[AI] 피드백 루프 구축: 사용자의 '좋아요/싫어요'를 모델 개선에 활용하기

모델 품질을 올리고 싶다고 해서 곧바로 파인튜닝부터 떠올릴 필요는 없습니다. 실제로는 사용자의 좋아요, 싫어요, 재시도, 수정 요청 같은 신호를 어떻게 모으고 해석하느냐가 먼저입니다. 피드백 루프는 기능 하나가 아니라, 서비스 운영과 모델 개선을 연결하는 설계라고 보는 편이 맞습니다.

피드백 루프란 무엇인가: 좋아요/싫어요가 모델 개선으로 이어지는 구조

피드백 루프는 사용자의 반응을 수집하고, 그 반응을 해석 가능한 데이터로 바꾼 뒤, 평가와 개선에 다시 연결하는 흐름입니다. 여기서 중요한 점은 좋아요/싫어요 버튼 자체가 아니라, 그 신호가 어떤 맥락에서 발생했는지까지 함께 보는 것입니다.

인간 피드백을 학습에 활용하는 방식 자체는 새로운 개념이 아닙니다. OpenAI는 사람의 선호 비교와 시범 데이터를 이용해 모델을 정렬하는 RLHF 방식을 소개했고, Google Cloud도 인간이 학습·평가·운영에 참여하는 HITL 구조를 핵심 개념으로 설명합니다. 즉, 사용자 반응을 모델 개선에 연결하는 발상은 이미 검증된 방향이라고 이해하면 됩니다. 

 

왜 단순한 좋아요/싫어요 집계만으로는 부족한가

처음에는 좋아요 수가 많으면 좋은 응답, 싫어요 수가 많으면 나쁜 응답이라고 생각하기 쉽습니다. 그런데 실무에서는 그렇게 단순하게 해석하면 금방 한계가 드러납니다.

같은 싫어요라도 의미가 다릅니다

사용자가 싫어요를 누른 이유는 여러 가지입니다. 사실 오류일 수도 있고, 말투가 거슬렸을 수도 있고, 답은 맞지만 너무 장황했을 수도 있습니다. 안전 정책 때문에 거절한 응답을 사용자가 불만족스럽게 느낀 경우도 있습니다. 이 차이를 구분하지 않으면 개선 방향이 흐려집니다.

무응답 데이터도 중요한 신호입니다

좋아요/싫어요를 누르지 않았다고 해서 중립이라고 보기는 어렵습니다. 답변 직후 이탈했는지, 다시 질문했는지, 직접 고쳐서 복사했는지, 같은 질문을 조금 바꿔 다시 던졌는지까지 함께 봐야 합니다. 협업할 때도 이 지점이 자주 빠집니다. 버튼 이벤트만 저장해 두고 실제 행동 로그를 놓치면, 모델보다 UX 문제를 모델 문제로 오해하는 경우가 생깁니다.

 

피드백 루프의 핵심 단계

피드백 루프는 보통 네 단계로 나눠서 설계합니다. 수집, 해석, 평가, 반영입니다. 이 네 단계를 분리해 두면 시스템이 커져도 유지보수가 한결 수월합니다.

1. 수집: 어떤 맥락에서 반응이 나왔는지 저장합니다

좋아요/싫어요만 저장하지 말고, 최소한 프롬프트 버전, 모델 버전, 응답 ID, 세션 ID, 응답 길이, 재시도 여부, 후속 질문 여부 정도는 같이 남기는 편이 좋습니다. 그래야 나중에 “특정 프롬프트 버전에서만 싫어요가 늘었다” 같은 분석이 가능합니다.

type FeedbackEvent = {
  feedbackId: string;
  sessionId: string;
  responseId: string;
  promptVersion: string;
  modelVersion: string;
  reaction: 'like' | 'dislike' | 'retry' | 'edited_copy';
  reasonCode?: 'incorrect' | 'unsafe' | 'too_long' | 'tone' | 'other';
  userComment?: string;
  createdAt: string;
};

여기서 reasonCode를 너무 촘촘하게 잡을 필요는 없습니다. 처음부터 분류 체계를 크게 벌리면 운영자가도 헷갈리고, 사용자도 누르기 귀찮아집니다. 초반에는 4~6개 정도의 거친 카테고리로 시작하는 편이 낫습니다.

2. 해석: 이벤트를 학습 가능한 레코드로 바꿉니다

좋아요/싫어요 이벤트는 그대로는 학습 데이터가 아닙니다. 프롬프트, 모델 응답, 사용자 반응, 보조 설명을 묶어 하나의 평가 단위로 재구성해야 합니다. 이 과정이 빠지면 데이터는 쌓이는데 개선에는 잘 연결되지 않습니다.

예를 들어 싫어요를 받은 응답을 바로 “나쁜 답변”으로 저장하기보다, 동일 질문에서 더 나은 대안 응답이 있었는지와 함께 쌍(pair) 형태로 만드는 방식이 유용합니다. RLHF와 선호 학습 계열 접근도 결국 이런 비교 구조를 많이 활용합니다. OpenAI의 InstructGPT 설명에서도 사람 평가자가 여러 출력 결과를 순위화해 학습에 반영하는 방식이 소개됩니다. 

3. 평가: 모델 개선 후보가 실제로 나아졌는지 검증합니다

이 단계가 빠지면 피드백 루프가 아니라 피드백 수집 시스템에 머물게 됩니다. 개선안이 생기면 기존 프롬프트나 모델과 비교 평가를 해야 합니다. 자동 평가와 사람 평가를 함께 두는 구성이 많이 쓰입니다.

Google Cloud의 생성형 AI 평가 문서도 테스트 기반 평가와 루브릭 평가를 제공하고 있습니다. 실무에서도 비슷합니다. 형식 오류나 금칙어 누락처럼 기계적으로 확인 가능한 항목은 자동 평가로 돌리고, 정확성·도움됨·말투 적절성 같은 부분은 표본을 뽑아 사람이 다시 보는 편입니다.

4. 반영: 프롬프트, 정책, 데이터, 모델 중 무엇을 바꿀지 결정합니다

사용자 피드백이 쌓였다고 해서 항상 모델 재학습으로 가는 것은 아닙니다. 이 부분은 자주 오해합니다. 실제로는 아래 순서로 보는 편이 더 효율적입니다.

1) 프롬프트 수정으로 해결 가능한가
2) 출력 후처리 정책으로 해결 가능한가
3) 검색/RAG 근거 품질 문제인가
4) 평가 기준이 잘못된 것인가
5) 그래도 남는 문제만 학습 데이터로 올릴 것인가

이 순서가 중요한 이유는, 대부분의 초기 문제는 프롬프트와 UX에서 먼저 잡히기 때문입니다. 모델 자체를 건드리는 일은 가장 나중으로 미루는 편이 운영상 안전합니다.

실무에서 자주 쓰는 피드백 루프 설계 방식

피드백 루프를 너무 크게 시작하면 팀이 금방 지칩니다. 처음에는 분석 가능한 최소 구조로 출발하는 것이 좋습니다. 제가 추천하는 초기 구성은 다음과 같습니다.

단계 1: 버튼 + 사유 선택 + 자유 입력

좋아요/싫어요 버튼만 두지 말고, 싫어요를 눌렀을 때 짧은 사유를 선택하게 하면 품질이 훨씬 좋아집니다. 다만 장문의 서술을 강제하면 응답률이 떨어집니다. 선택형 사유와 선택적 자유 입력 조합이 가장 무난합니다.

단계 2: 주간 단위 집계 대시보드

이벤트 원본을 그대로 보지 말고, promptVersion·modelVersion·reasonCode 기준으로 묶어서 봐야 합니다. 그래야 “새 프롬프트 이후 too_long이 늘었다”처럼 바로 액션으로 연결되는 신호가 보입니다.

단계 3: 표본 검수 큐

싫어요가 많이 찍힌 사례만 보는 것은 위험합니다. 좋아요를 많이 받은 응답도 함께 봐야 합니다. 좋은 사례를 모아야 어떤 패턴을 유지해야 하는지가 보이기 때문입니다. OpenAI의 과거 인간 피드백 연구에서도 선호 데이터를 통해 더 바람직한 출력을 학습시키는 흐름이 강조됩니다.

단계 4: 변경 이력 관리

피드백 루프는 모델 팀만의 일이 아닙니다. 프롬프트를 누가 언제 바꿨는지, 안전 정책을 어떻게 수정했는지, RAG 인덱스를 언제 갱신했는지까지 변경 이력이 남아야 원인을 추적할 수 있습니다. 팀 협업 관점에서는 이 부분이 생각보다 더 중요합니다.

좋아요/싫어요 데이터를 볼 때 주의할 점

피드백 루프는 데이터가 많다고 자동으로 좋아지지 않습니다. 오히려 해석을 잘못하면 잘못된 방향으로 최적화될 수 있습니다.

사용자 만족과 정답률은 항상 같지 않습니다

짧고 자신감 있게 말한 응답이 더 많은 좋아요를 받을 수 있습니다. 그런데 그 답이 더 정확하다는 뜻은 아닙니다. 반대로 신중하게 제한을 설명한 답변은 사실 맞아도 만족도가 낮게 나올 수 있습니다. 따라서 만족도 지표와 품질 지표를 분리해서 봐야 합니다.

침묵한 사용자 데이터를 과소평가하면 안 됩니다

버튼을 누른 사람은 원래 적극적인 사용자일 가능성이 큽니다. 그래서 버튼 클릭 데이터만 믿으면 전체 사용자 경험을 과장해서 보게 됩니다. 복사 후 수정, 즉시 재질문, 세션 종료 같은 행동 로그를 함께 넣는 이유가 바로 여기에 있습니다.

개인정보와 학습 사용 정책은 분리해서 다뤄야 합니다

사용자 피드백을 개선에 활용하려면 데이터 저장 범위와 사용 목적을 분명히 해야 합니다. OpenAI 도움말도 서비스와 설정에 따라 데이터가 모델 개선에 사용되는 방식이 다를 수 있다고 설명합니다. 따라서 제품을 설계할 때는 “피드백 수집”과 “학습 반영”을 같은 기능으로 취급하지 말고, 동의와 보관 정책을 분리해서 설계하는 편이 맞습니다.

TypeScript 기준으로 보는 간단한 구현 예시

백엔드에서는 보통 이벤트 저장 API, 집계 배치, 검수 큐 생성기 정도로 나누어 구현합니다. 처음부터 복잡한 파이프라인을 만들기보다, 수집과 집계를 안정적으로 분리하는 것이 우선입니다.

import { Body, Controller, Post } from '@nestjs/common';

type FeedbackRequest = {
  responseId: string;
  reaction: 'like' | 'dislike';
  reasonCode?: 'incorrect' | 'unsafe' | 'too_long' | 'tone' | 'other';
  userComment?: string;
};

@Controller('/feedback')
export class FeedbackController {
  @Post()
  async create(@Body() body: FeedbackRequest) {
    // 1. 응답 메타데이터 조회
    // 2. 세션/프롬프트/모델 버전 조합
    // 3. 이벤트 저장
    // 4. 분석 큐로 비동기 발행
    return { ok: true };
  }
}

이 구현에서 중요한 것은 API 코드보다 저장 모델입니다. responseId 하나만 저장하면 나중에 맥락 복원이 어렵습니다. 반대로 모든 원문을 중복 저장하면 관리가 번거로워집니다. 보통은 응답 원문은 응답 저장소에서 참조하고, 피드백 이벤트에는 식별자와 분석용 메타데이터만 남기는 구성이 깔끔합니다.

피드백 루프를 도입할 때 추천하는 운영 순서

이 주제는 설계를 크게 벌리기 쉽지만, 실제로는 작은 루프를 빨리 닫는 편이 더 효과적입니다. 저는 보통 아래 순서를 권합니다.

1주차: 버튼/사유/API 저장
2주차: 집계 쿼리와 대시보드
3주차: 표본 검수 프로세스
4주차: 프롬프트 개선 실험
그 이후: 평가셋 고도화, 선호 데이터셋 구축, 학습 반영 검토

이 흐름의 장점은 팀이 중간 결과를 빨리 볼 수 있다는 점입니다. 피드백 루프는 결국 반복 구조입니다. 수집만 하고 끝나면 의미가 없고, 학습만 강조하면 운영이 불안정해집니다. 작은 개선을 자주 검증하는 구조가 더 오래 갑니다.

피드백 루프와 모델 개선을 어떻게 연결해야 하는가

정리하면, 사용자의 좋아요/싫어요는 그 자체로 답이 아니라 출발점입니다. 피드백 루프의 핵심은 반응을 모으는 것이 아니라, 반응을 맥락화하고 평가 가능한 형태로 바꾸고, 실제 변경으로 연결하는 데 있습니다.

좋은 피드백 루프는 세 가지 특징이 있습니다. 왜 그런 반응이 나왔는지 설명 가능한 데이터가 남고, 변경 전후를 비교할 평가 체계가 있으며, 프롬프트·정책·데이터·모델 중 어디를 바꿔야 하는지 구분할 수 있습니다. 이 정도 구조만 갖춰도 좋아요/싫어요 버튼은 단순한 UI가 아니라 모델 개선의 입력 채널이 됩니다.