대화가 끝나면 채점이 시작된다 — 체크포인트 기반 피드백 설계
종료 버튼을 누르면 그때부터 진짜가 시작됩니다. 롤플레이 훈련 챗봇을 직접 만들면서 가장 오래 붙잡고 있던 부분은 AI 고객의 말투도, 화면 디자인도 아니었습니다. 대화가 끝난 다음 "그래서 이 사람은 잘한 건가, 못한 건가"를 어떻게 판정하느냐였습니다. 채점이 없으면 롤플레이는 그냥 심심풀이 대화로 끝납니다. 반대로 채점이 엉성하면 훈련하는 사람이 시스템을 신뢰하지 않게 되고, 결국 아무도 쓰지 않습니다. 이 글은 이 채점 로직을 어떤 의도로 설계했는지, 왜 "정답 하나"로 매기지 않기로 했는지를 코드 설계 관점에서 자세히 정리합니다.
[시리즈] S2S·LLM 음성 에이전트 엔지니어링 63편 · 현재 10-7편
← 이전: 10-6 퀴즈 풀 사전생성 / 다음 → 10-8 혼자 쓰는 챗봇의 현실
- 10-5 AI 고객 페르소나 프롬프트 엔지니어링
- 10-6 퀴즈 풀 사전생성
- 10-7 대화가 끝나면 채점한다 (현재 글)
- 10-8 혼자 쓰는 챗봇의 현실
- 11-1 KMS 프로젝트가 실사 이후로 밀리는 이유
전체 목차 펼치기 (63편)
Part 1 — 음성 AI가 느린 이유: 레이턴시 진단 (4편)
- 1-1 AI 보이스봇이 답답한 이유 — Cascaded 레이턴시
- 1-2 1초의 벽 — 지연이 UX를 결정하는 이유
- 1-3 지연 줄이기 — 스트리밍·청크로 TTFT 단축
- 1-4 RAG 병목과 오디오 버퍼링 제어
Part 2 — 텍스트를 넘어: End-to-End S2S의 원리 (4편)
- 2-1 End-to-End S2S 작동 원리
- 2-2 OpenAI Realtime API vs 오픈소스 S2S
- 2-3 음성 토큰(Audio Token)이란
- 2-4 감정·톤 조절이 CS를 바꾸는 이유
Part 3 — 실시간 대화와 에이전트화: 인터럽트·MCP·도구 (5편)
- 3-1 실시간 인터럽트(끼어들기) 감지
- 3-2 실시간 음성에 MCP가 필요한 이유
- 3-3 스트리밍 중 MCP 초고속 데이터 룩업
- 3-4 통화 중 외부 API 도구 호출
- 3-5 실시간 세션 관리 — 통화 맥락·고객 데이터
Part 4 — 인프라·세션·보안: 프로덕션 백엔드 (5편)
- 4-1 동적 컨텍스트 윈도우 관리
- 4-2 WebRTC·WebSocket 초저지연 음성
- 4-3 비동기 이벤트 루프와 동시 콜 처리
- 4-4 트래픽 스파이크를 견디는 확장성 설계
- 4-5 실시간 음성 보안 — 암호화·PII 마스킹
Part 5 — 운영·품질·평가: 에이전틱 워크플로우와 신뢰성 (7편)
- 5-1 에이전틱 워크플로우 — 응대를 넘어 완결로
- 5-2 상용화의 한계와 트러블슈팅
- 5-3 보이스 에이전트 평가(Eval) 설계
- 5-4 관측성(Observability) — 어디서 끊기나
- 5-5 가드레일과 환각 제어
- 5-6 상담사 전환(Handoff) 설계
- 5-7 프롬프트 A/B 테스트와 튜닝
Part 6 — 음성 경험 고도화·실전 통합: 한국어·UX·전화망·엣지 (5편)
- 6-1 한국어 음성 AI의 난관 — 존댓말·코드스위칭
- 6-2 턴테이킹과 시맨틱 VAD
- 6-3 보이스 페르소나 디자인
- 6-4 SIP·PSTN 전화망 연동
- 6-5 온디바이스·엣지 S2S와 프라이버시
Part 7 — S2S 도입 전략·구매 의사결정 (4편)
Part 8 — LLM 콜봇 PoC 현장 (6편)
- 8-1 LLM 콜봇 PoC — 검증의 갭
- 8-2 STT 정확도 93% 목표가 부족한 이유
- 8-3 금융 콜봇에서 소수점이 중요한 이유
- 8-4 TTFT 1.5초, 콜봇 스트리밍 파이프라인 설계
- 8-5 콜봇 SLM: 30B vs 70B 트레이드오프
- 8-6 PoC와 본사업 사이의 성능 괴리
Part 9 — 상담어시스트: 상담사 화면을 바꾸는 실시간 AI (7편)
- 9-1 상담어시스트란 무엇인가 — 실시간 STT가 상담사 화면을 바꾸는 구조
- 9-2 상담어시스트의 뼈대 — STT·인텐트·KMS 파이프라인
- 9-3 추천의 근거 — KMS·RAG 지식 그라운딩
- 9-4 통화 중 놓친 고지를 잡는 실시간 필수 안내 체크
- 9-5 AI가 상담 품질을 자동 채점하는 법 — AutoQA
- 9-6 신입 상담사에게 어시스트가 더 필요한 이유
- 9-7 온프레미스 상담어시스트 — GPU 제약과 모델 선택
Part 10 — 직접 만든 롤플레이 챗봇: RAG 에이전트 구축기 (8편)
- 10-1 왜 롤플레이 챗봇을 직접 만들었나
- 10-2 전체 아키텍처 한 장
- 10-3 RAG 파이프라인과 로컬 임베딩
- 10-4 멀티 LLM 백엔드 스위칭
- 10-5 AI 고객 페르소나 프롬프트 엔지니어링
- 10-6 퀴즈 풀 사전생성
- 10-7 대화가 끝나면 채점한다 (현재 글)
- 10-8 혼자 쓰는 챗봇의 현실
Part 11 — KMS 실무 — 지식관리시스템의 설계와 운영 현실 (8편)
왜 '정답 하나'로 채점할 수 없었나
처음에는 단순하게 생각했습니다. 모범답안을 하나 만들어 두고, 사용자의 답변이 그것과 얼마나 비슷한지를 재면 되지 않을까. 퀴즈라면 그게 맞습니다. "이 용어의 정의는?" 같은 질문은 정답이 하나이고, 맞았는지 틀렸는지가 명확합니다. 하지만 영업 대화는 그렇지 않았습니다.
가령 AI 고객이 "응답 속도가 실제로 견딜 만한가요?"라고 물었다고 합시다. 여기에 대한 좋은 답변은 여러 갈래입니다. 어떤 사람은 체감 지연을 숫자로 설명하고, 어떤 사람은 스트리밍 방식으로 첫 음절이 빨리 나오게 하는 구조를 설명하고, 또 어떤 사람은 실패 시 상담사로 넘기는 안전장치를 먼저 짚습니다. 세 답변 모두 훌륭할 수 있습니다. 순서도, 강조점도 사람마다 다릅니다. 여기에 "정답 문장 하나"를 놓고 유사도를 재면, 표현이 다르다는 이유로 좋은 답변이 감점됩니다. 그건 채점이 아니라 문체 검사입니다.
그래서 방향을 바꿨습니다. "이 답변이 모범답안과 얼마나 닮았나"가 아니라 "이 질문에서 반드시 짚었어야 할 것들을 짚었나"로 채점하기로 했습니다. 영업 대화에 유일한 정답은 없지만, 그 질문에 답하려면 빠뜨리면 안 되는 핵심 포인트는 존재합니다. 그 포인트들의 목록, 즉 체크포인트를 채점 기준으로 삼는 것입니다. 이 결정 하나가 이후 설계 전체의 뼈대가 됐습니다.
체크포인트 채점 구조 — 무엇을 입력하고 무엇을 판정하나
채점 함수는 매 턴마다 세 가지를 입력받습니다. 고객이 던진 질문, 사용자가 실제로 한 답변, 그리고 그 질문에 대응하는 체크포인트 목록입니다. 체크포인트 목록은 시나리오마다 미리 준비된 JSON으로, 각 항목은 식별자(id)·짧은 라벨(label)·구체 설명(content)을 가집니다. 예를 들어 "응답 속도" 질문에는 "체감 지연 수치", "스트리밍 구조", "실패 시 상담사 전환" 같은 체크포인트가 붙어 있습니다.
채점 LLM은 이 세 입력을 받아 체크포인트 하나하나에 대해 두 가지를 판정합니다.
[채점 흐름]
고객 질문 ┐
사용자 답변 ├─→ 채점 LLM (경량 호출)
체크포인트 ┘ │
▼
각 체크포인트마다 판정
├─ required : 이 질문의 핵심에 꼭 필요한가? (true/false)
└─ hit : 답변이 실제로 짚었는가? (true/false)
│
▼
필수 적중률 → score (0~100) + 서술형 코멘트
required는 "그 체크포인트가 이 질문의 핵심에 답하기 위해 꼭 필요한가"입니다. 있으면 좋지만 부가적인 것이라면 false입니다. hit는 "사용자의 답변이 그 포인트를 실제로 짚었는가"입니다. 두 판정을 분리한 게 핵심입니다. required는 질문의 성격이 정하는 것이고, hit는 답변이 정하는 것이라, 둘을 섞으면 안 되기 때문입니다. 같은 체크포인트라도 어떤 질문에서는 필수이고 다른 질문에서는 선택일 수 있습니다. 그래서 required 판정을 미리 고정해 두지 않고, 매번 질문의 의도를 기준으로 LLM이 다시 판단하게 했습니다.
출력은 순수 JSON 하나로 강제했습니다. 채점 결과가 뒤이어 점수 집계와 화면 표시로 흘러가야 하므로, 마크다운이나 설명문이 섞이면 파싱이 깨집니다. 실제 코드에서도 응답에서 코드블록을 벗겨내고 JSON만 뽑아내는 방어 로직을 두고, 파싱이 실패하면 점수 0의 안전 폴백을 반환하도록 했습니다. LLM 출력은 언제든 형식을 어길 수 있다는 전제로 만들어야 했습니다.
점수는 어떻게 나오나 — 필수 적중률이 중심
체크포인트별 required/hit이 정해지면 점수 산정은 원칙이 분명해집니다. 핵심은 필수 체크포인트를 얼마나 짚었는가입니다. 선택 체크포인트는 짚으면 소폭 가산하되, 놓쳐도 감점하지 않습니다. 필수가 아닌 것을 놓쳤다고 깎으면, 결국 "모든 걸 다 말해야 만점"이 되어 앞에서 버린 유사도 채점으로 되돌아가기 때문입니다.
구체적인 채점 지시는 이렇게 정리했습니다.
| 상황 | 점수 방향 |
|---|---|
| 필수 체크포인트를 모두 짚음 | 90~100점 |
| 필수 일부를 놓침 | 놓친 만큼 비례 감점 |
| 선택 체크포인트를 짚음 | 소폭 가산 (최대 100) |
| 선택 체크포인트를 놓침 | 감점 없음 |
이렇게 하면 점수의 의미가 사람에게 설명 가능해집니다. 70점이 나왔을 때 "왜 70점인가"를 물으면, "필수 세 개 중 하나를 놓쳤고 그게 이런 내용이었다"고 답할 수 있습니다. 숫자만 던지는 채점은 훈련하는 사람을 납득시키지 못합니다. 그래서 점수와 함께 각 체크포인트마다 서술형 코멘트를 2~3문장으로 붙이게 했습니다. 짚었으면 무엇을 잘했는지 인정하고, 놓쳤으면 무엇을 왜 말했어야 하는지를 체크포인트의 content를 근거로 구체적으로 설명하게 했습니다. 단답이나 키워드 나열은 금지했습니다. "미흡함" 같은 한 단어 코멘트는 아무것도 가르쳐 주지 못하니까요.
"모든 항목을 필수로 만들지 말라"는 지시가 왜 중요했나
이 설계에서 가장 취약했던 지점이 여기입니다. LLM에게 체크포인트마다 required를 판단하라고 시키면, 그냥 두면 거의 전부를 true로 찍는 경향이 있습니다. 모델 입장에서는 "다 중요해 보이니까 다 필수"라고 하는 게 안전하게 느껴지는 것입니다. 그런데 모든 항목이 필수가 되면, 조금이라도 덜 말한 사람은 전부 감점됩니다. 결과적으로 점수가 늘 낮게 깔리고, 짚어야 할 진짜 핵심과 부수적인 것이 구분되지 않습니다.
그래서 채점 프롬프트에 "한 질문에서 필수는 보통 2~4개입니다. 모든 항목을 필수로 만들지 마세요."라는 지시를 명시적으로 박아 넣었습니다. 이 한 줄이 없을 때와 있을 때의 채점 결과가 눈에 띄게 달랐습니다. 지시를 넣기 전에는 대부분의 답변이 60점대에 몰려 변별력이 없었는데, 넣은 뒤에는 정말 핵심을 짚은 답변과 곁가지만 말한 답변이 점수로 갈렸습니다.
이건 프롬프트 엔지니어링이라기보다 채점 철학을 문장으로 옮긴 것에 가깝습니다. 사람 코치도 "이 질문에서는 이거 두세 개만 제대로 말하면 합격"이라고 판단하지, 열 가지를 다 말하라고 요구하지 않습니다. 필수를 좁게 잡는 것이 오히려 공정한 채점이라는 원칙을, 모델이 스스로 발견하도록 두지 않고 지시로 강제한 셈입니다.
대화가 끝난 뒤 — 종합 등급과 코칭
턴 채점이 매 답변에 대한 즉석 판정이라면, 대화 전체가 끝난 뒤에는 종합 피드백이 나옵니다. 전체 대화를 한 번에 놓고 보면서 A부터 D까지 등급을 매기고, 무엇을 잘했고 어디가 약했는지를 상세하게 분석해 줍니다. 턴 채점이 "이 답변 이랬다"라면, 종합 피드백은 "이 대화 전체에서 당신의 패턴은 이랬다"에 가깝습니다. 예컨대 개별 답변은 무난했지만 전반적으로 고객의 우려를 되받아 정리해 주는 습관이 없었다든가 하는, 턴 단위로는 안 보이는 경향이 여기서 드러납니다.
코칭은 여기서 한 걸음 더 나갑니다. 시나리오마다 질문별 코칭 데이터가 준비되어 있는데, 이건 LLM이 매번 생성하는 게 아니라 정답참고서를 결정론적으로 파싱해 미리 만들어 둔 것입니다. LLM을 태우지 않으니 매번 같은 코칭이 안정적으로 나오고, 비용도 들지 않습니다. 훈련 중 오른쪽 패널에서 "이 질문에서는 이런 것들을 짚으면 좋다"는 힌트로 활용되고, 대화가 끝난 뒤 복기할 때 기준점이 됩니다.
중요한 원칙 하나. 이 점수와 등급은 본인만 봅니다. 관리자나 인사평가로 넘어가지 않습니다. 이건 기능이 아니라 설계 전제입니다. 점수가 공개되는 순간 사람들은 낮은 점수가 두려워 훈련 자체를 하지 않게 됩니다. 채점을 촘촘하게 만든 이유가 "잘 가르치기 위해서"이지 "줄 세우기 위해서"가 아니라는 걸, 데이터 흐름 자체로 못박아 둔 것입니다.
이 설계는 사람 코치를 얼마나 닮았고, 어디서 다른가
다 만들고 보니 이 채점 구조는 의외로 사람 코치가 하는 일을 그대로 옮긴 모양이 됐습니다. 좋은 코치는 답을 하나 정해 놓고 그대로 외웠는지 확인하지 않습니다. "이 질문이면 이건 꼭 말했어야지" 하는 핵심 몇 개를 머릿속에 두고, 상대가 그걸 짚었는지를 봅니다. required를 2~4개로 좁히고 나머지는 가산점으로 둔 것이, 바로 그 코치의 판단을 흉내 낸 것입니다. 놓친 부분을 그냥 "틀렸다"고 하지 않고 왜 그게 필요한지 설명하게 한 것도, 좋은 코치가 하는 피드백 방식입니다.
다른 점도 분명합니다. 사람 코치는 상대의 표정과 맥락, 그날의 컨디션까지 읽지만, 이 시스템은 텍스트에 적힌 것만 봅니다. 체크포인트에 없는 통찰을 사용자가 말했다면, 사람 코치는 감탄하겠지만 이 시스템은 그걸 온전히 인정하지 못합니다. 그래서 이 채점은 "사람 코치의 대체"가 아니라 "혼자서도 매일 반복할 수 있는 연습 파트너"로 자리를 잡았습니다. 코치는 하루에 한 번 붙기도 어렵지만, 이 챗봇은 언제든 붙어 열 번이고 돌릴 수 있습니다. 완벽한 심판이 되려 하지 않고, 성실한 연습 상대가 되는 쪽을 택한 것입니다.
자주 묻는 질문(FAQ)
Q1. 체크포인트는 누가 만드나요?
시나리오를 준비할 때 사람이 미리 정의합니다. 실제 미팅을 익명화·재구성한 시나리오마다, 각 핵심 질문에 대해 "이건 꼭 짚어야 한다"는 포인트들을 목록으로 붙여 둡니다. 채점 순간에 LLM이 즉석에서 만드는 게 아니라, 준비된 체크포인트 목록을 채점 기준으로 넣어 주는 구조입니다. 기준을 사람이 미리 통제하기 때문에 채점의 일관성이 유지됩니다.
Q2. required 판정을 AI가 어떻게 하나요?
채점 LLM이 매 턴 질문의 의도를 기준으로 판단합니다. 같은 체크포인트라도 어떤 질문에서는 핵심이라 필수(true)이고, 다른 질문에서는 있으면 좋은 정도라 선택(false)일 수 있어, required를 고정하지 않고 그때그때 다시 판정하게 했습니다. 다만 모델이 모든 걸 필수로 찍으려는 경향이 있어서, "필수는 보통 2~4개, 전부를 필수로 만들지 말라"는 지시를 프롬프트에 명시해 좁게 잡도록 강제했습니다.
Q3. 점수를 그대로 신뢰해도 되나요?
점수는 절대적 등수가 아니라 참고 신호로 보는 게 맞습니다. LLM 채점은 같은 답변도 호출마다 미세하게 흔들릴 수 있고, 체크포인트에 없는 좋은 답변은 온전히 반영되지 못합니다. 그래서 점수 숫자보다 함께 나오는 서술형 코멘트, 즉 "무엇을 왜 짚었어야 했는가"를 읽는 것이 훈련에 훨씬 유용합니다. 점수는 방향을 알려 주는 지표이지 성적표가 아닙니다.
Q4. 이 채점이 사람 코칭을 대체하나요?
대체를 목표로 만들지 않았습니다. 이 시스템은 텍스트에 적힌 것만 보고, 체크포인트 밖의 통찰은 인정하기 어렵습니다. 대신 사람 코치가 하기 힘든 것을 합니다. 언제든, 몇 번이든 반복해서 붙어 연습할 수 있다는 점입니다. 사람 코치의 깊이를 대신하는 게 아니라, 코치를 만나기 전까지 혼자 반복 연습하는 파트너로 설계했습니다. 참고로 이 글은 2026년 7월 시점에 필자가 직접 만든 훈련 챗봇의 설계 관점을 정리한 것으로, 코드에 등장하는 도메인 표현은 익명화해 옮겼고 회사·고객사·인물을 특정할 수 있는 정보는 담지 않았습니다.
댓글
댓글 쓰기