2장. 예시와 구조화

학습 목표

  • 예시가 의도한 규칙과 우연한 패턴을 함께 가르친다는 점을 설명하고, 우연한 패턴을 찾아 없앤다.
  • few-shot 예시를 관련성·다양성·형식 일관성 기준으로 구성하고, 예시와 평가 데이터를 분리한다.
  • XML 태그로 지시·맥락·예시·입력의 경계를 나눈다.
  • 출력을 받는 쪽(사람, 시스템, 음성)에 맞는 형식을 고르고, 데이터 사전과 결측 표현을 정한다.
  • 기계가 읽을 출력에 지시, 예시, 구조화 출력 중 알맞은 방법을 고르고, 형식 준수와 내용 정확성을 따로 검사한다.
  • 프리필에 기대던 프롬프트를 최신 모델에 맞는 방법으로 옮긴다.

들어가며

한 통신 판매 회사가 상품 문의를 “배송, 교환, 결제, 기타” 넷으로 나누는 프롬프트를 만들었습니다. 담당자는 예시를 네 개 넣었는데, 우연히 네 예시 모두 “안녕하세요”로 시작하는 정중한 문장이었습니다. 운영을 시작하자 인사 없이 짧게 쓴 문의가 “기타”로 몰렸고, 급한 사정을 적은 문의 수십 건이 하루 넘게 방치되었습니다. 담당자가 원인을 찾은 것은 “기타” 담당자가 일이 늘었다고 항의한 지 일주일이 지나서였습니다. 모델은 담당자가 가르치려 한 분류 기준과 함께 “정중한 문장이어야 정식 문의”라는, 아무도 의도하지 않은 규칙까지 배운 것입니다. 편향을 일으킨 것은 담당자가 쓴 지시가 아니라 담당자가 고른 예시였습니다. 예시는 가장 강력한 지시이면서 가장 통제하기 어려운 지시입니다.

이 장은 좋은 예시의 조건과 다양성 설계, 경계 사례, 편향을 줄이는 절차, 예시와 평가 데이터의 분리에서 시작합니다. 이어서 지시와 자료의 경계를 긋는 태그, 받는 쪽에 맞는 형식, 데이터 사전과 결측 표현, 구조화 출력의 보장 범위와 한계, 프리필의 대안, 근거 필드의 설계를 봅니다. 깊이 읽기에서는 사고 기능이 있는 모델에 방법을 보여 주는 예시와 표시 환경에 따른 서식 문제를 다룹니다.

핵심 개념

예시는 재단사에게 건네는 견본 옷이다

재단사에게 “깔끔한 셔츠”라고 말하는 것보다 견본 셔츠 몇 벌을 건네는 편이 훨씬 정확합니다. 다만 견본이 모두 흰색 반팔이면 재단사는 손님이 흰색 반팔만 원한다고 오해할 수 있습니다. few-shot 예시(입력과 원하는 출력의 짝을 몇 개 보여 주는 방식)도 같습니다. Anthropic 가이드는 예시를 출력의 형식, 어조, 구조를 조정하는 가장 믿을 만한 방법의 하나로 꼽습니다. 그러나 모델은 예시에 숨은 의도하지 않은 패턴까지 함께 배웁니다.

예시를 넣기 전에 “이 예시 묶음이 가르치는 것”을 두 칸으로 나눠 적어 보면 위험이 보입니다.

가르치려는 것 우연히 가르칠 수 있는 것
분류 기준(어떤 문의가 교환인가) 문장 길이, 인사말 유무, 존댓말 여부
출력 형식(라벨 한 단어) 특정 라벨의 빈도(넷 중 셋이 배송)
어조(담백한 설명) 예시에 반복된 표현, 고유명사, 숫자 크기

오른쪽 칸에 적힌 것이 예시 사이에서 고르게 섞여 있지 않다면, 모델은 그것을 규칙으로 받아들일 수 있습니다.

좋은 예시의 조건

조건 뜻 근거
관련성 실제로 들어올 입력과 닮은 예시 Anthropic 가이드
다양성 경계 사례를 포함하고, 의도하지 않은 패턴을 배우지 않을 만큼 서로 다름 Anthropic 가이드
구조 <example>로 감싸고 여러 개는 <examples>로 묶어 지시와 구분 Anthropic 가이드
형식 일관성 구분자, 태그, 줄바꿈까지 모든 예시가 같은 구조 Gemini 가이드

개수에 대해서는 벤더마다 강조점이 다릅니다. Anthropic은 3~5개를 권하고, 모델에게 예시의 관련성과 다양성을 평가하게 하거나 예시를 더 만들게 할 수 있다고 덧붙입니다. Gemini 가이드는 예시를 항상 넣으라고 권하면서도 너무 많으면 응답이 예시에 지나치게 맞춰지는 과적합이 생길 수 있다고 경고합니다. OpenAI의 추론 모델 모범 사례는 먼저 예시 없이(zero-shot) 시도하라고 합니다. 반대로 긴 컨텍스트에 예시를 수백 개 넣는 방식(many-shot)이 특정 작업에서 미세 조정 모델과 비슷한 성능을 냈다는 Google 문서의 설명도 있습니다. 정리하면 “내용은 다르게, 형식은 똑같이, 개수는 실험으로”입니다. 예시를 조금씩 늘리며 같은 평가 세트로 재고, 점수가 멈추거나 출력이 예시 문장을 닮아 가면 멈춥니다.

다양성을 설계하는 표

“다양하게”는 1장에서 본 판정할 수 없는 표현입니다. 예시를 고를 때는 다양성을 축으로 나눠 표를 채웁니다.

축 점검 질문
라벨 모든 라벨이 최소 한 번씩 나오는가. 실제 비율과 크게 어긋나지 않는가
길이 짧은 입력과 긴 입력이 섞였는가
문체 정중한 글, 짧은 메모, 오탈자가 있는 글이 섞였는가
경계 두 라벨 사이에 걸친 입력이 있는가
예외 정보가 빠진 입력, 관련 없는 입력이 있는가
순서 같은 라벨이 연달아 나오지 않는가. 마지막 예시가 특정 라벨로 고정되지 않았는가

표의 빈칸이 곧 다음에 찾아야 할 예시입니다. 실제 로그에서 빈칸에 맞는 입력을 찾되, 개인정보는 지우고 넣습니다.

경계 사례와 대조 쌍

쉬운 예시는 모델도 이미 맞힙니다. 판단 기준을 가르치는 것은 헷갈리는 예시입니다. “상자는 찌그러졌는데 제품은 아직 열어 보지 않았다”는 배송 문제일까요, 교환 요청일까요? 이런 경계 사례에 정답을 붙여 보여 주면 모델은 두 범주를 가르는 선이 어디인지 배웁니다.

경계를 더 선명하게 하려면 대조 쌍을 씁니다. 거의 같은 두 입력이 작은 차이 하나 때문에 다른 라벨을 받는 짝입니다.

<examples>
  <example>
    <input>받은 신발 한 짝 굽이 떨어져 있어요. 같은 사이즈로 바꿔 주세요.</input>
    <label>교환</label>
  </example>
  <example>
    <input>받은 신발 한 짝 굽이 떨어져 있어요. 그냥 돈으로 돌려받고 싶어요.</input>
    <label>환불</label>
  </example>
</examples>

잘못된 출력을 예로 보여 주는 방법은 조심해야 합니다. 잘못된 형식을 길게 보여 주면 그 형식이 컨텍스트에 강하게 남아 오히려 따라 할 수 있습니다. 오답 예시가 꼭 필요하다면 짧게, “이렇게 하지 않는다”는 표시와 이유를 붙이고, 바로 뒤에 올바른 예시를 둡니다. 기본은 원하는 결과를 보여 주는 것입니다.

예시 편향을 줄이는 절차

예시 편향은 예시 묶음의 치우침이 모델 판단을 기울이는 현상입니다. 흔한 유형은 셋입니다. 특정 라벨이 많아 그 라벨로 쏠리는 경우, 예시의 순서나 마지막 예시가 결과를 끌어당기는 경우, 예시의 문구를 그대로 베끼는 경우입니다. 다음 절차로 진단하고 줄입니다.

  1. 증상을 수치로 확인한다. 라벨별 정답률과 출력 라벨 분포를 실제 분포와 비교한다. 특정 라벨이 실제보다 많이 나오면 쏠림이다.
  2. 예시를 다양성 표에 대 본다. 쏠린 라벨이 예시에서도 많은지, 문체나 길이가 한쪽으로 몰렸는지 본다.
  3. 한 번에 하나만 바꾼다. 라벨 균형 맞추기, 순서 섞기, 문체 섞기 중 하나를 바꾸고 같은 평가 세트로 다시 잰다.
  4. 베끼기를 확인한다. 생성 작업이라면 출력과 예시의 문장 겹침을 센다. 겹치면 예시의 표현을 서로 다르게 만들고, “예시는 구성과 어조를 보여 주기 위한 것이며 문장을 옮겨 쓰지 않는다”고 이유와 함께 적는다.
  5. 규칙으로 메우지 않는다. Anthropic 컨텍스트 엔지니어링 글의 조언처럼 긴 예외 목록보다 대표적인 예시 묶음을 먼저 고른다.

예시와 평가 데이터를 섞지 않는다

예시를 고르는 원천과 평가 세트를 만드는 원천이 같은 로그일 때가 많습니다. 이때 예시로 쓴 입력이 평가 세트에 남아 있으면, 모델은 정답을 본 문제를 다시 푸는 셈이 되어 점수가 실제보다 높게 나옵니다. 순서는 이렇습니다. 먼저 평가용 입력을 따로 떼어 잠가 두고, 남은 입력에서 다양성 표를 채울 예시를 고릅니다. 예시를 바꿀 때마다 평가용 입력과 겹치지 않는지 확인합니다. 5장에서 이 원칙을 “개선용 세트와 확인용 세트의 분리”로 다시 다룹니다.

XML 태그로 경계를 긋는다

프롬프트에 지시, 참고 자료, 예시, 사용자 입력이 섞이면 모델이 참고 자료 속 문장을 지시로 오해할 수 있습니다. Anthropic 가이드는 내용의 종류마다 <instructions>, <context>, <input> 같은 태그로 감싸면 오해가 줄어든다고 설명합니다. 태그는 서류철의 색인지 같은 역할을 합니다.

<instructions>
견적 요청 메일을 읽고 요청 품목과 희망 납기를 뽑는다.
</instructions>
<price_policy>
견적 유효 기간은 발행일로부터 30일이다.
</price_policy>
<email>
{{CUSTOMER_EMAIL}}
</email>

태그를 쓸 때의 원칙은 단순합니다.

  • 태그 이름은 정해진 것이 없습니다. 담긴 내용이 무엇인지 드러나는 이름을 고르고, 한 번 정한 이름은 끝까지 바꾸지 않습니다.
  • 계층이 있는 내용은 중첩합니다. 문서 여러 건이라면 <documents> 안에 <document index="1">을 두고, OpenAI 가이드처럼 XML 속성으로 메타데이터를 붙여 지시에서 가리킬 수도 있습니다.
  • 태그가 하는 일은 경계 표시까지입니다. 출력 형식은 따로 정해야 하고, 태그가 보안 장벽 노릇을 하지도 않습니다. 외부 자료에 </email> 같은 문자열이 섞여 경계를 깨뜨릴 수 있다면 3장에서 다룰 것처럼 JSON으로 감싸 넣는 편이 안전합니다.
  • OpenAI와 Anthropic 모두 Markdown 제목도 구획 표시 수단으로 언급합니다. 한 프롬프트 안에서는 한 방식으로 통일합니다.

받는 쪽에 맞는 형식을 고른다

형식을 정할 때 가장 먼저 물을 것은 “이 출력을 누가 받는가”입니다.

받는 쪽 알맞은 형식 주의할 점
사람이 화면에서 읽음 문단, 필요할 때만 표와 목록 표시 환경이 마크다운을 그리는지 확인
사람이 인쇄물로 읽음 제목이 있는 문단, 표 링크 대신 출처 이름
음성으로 읽힘 짧은 평서문 기호, 괄호, 약어, 표 금지 이유 명시
시스템이 파싱함 JSON 등 스키마가 정해진 형식 구조화 출력으로 강제, 사람이 읽을 설명과 분리
스프레드시트로 붙임 CSV 또는 탭 구분 쉼표·줄바꿈·따옴표가 든 값의 처리 규칙

사람이 읽을 설명과 시스템이 읽을 데이터를 함께 받아야 한다면, 설명은 정해진 태그에, 데이터는 별도 필드에 두거나 호출을 나눕니다. 설명 문장이 데이터 사이에 끼면 파서가 깨집니다.

데이터 사전과 결측 표현

필드 이름만 정하고 의미를 정하지 않으면 같은 필드를 사람마다, 요청마다 다르게 채웁니다. 스키마를 쓰기 전에 데이터 사전을 먼저 만듭니다.

필드 업무상 의미 타입·단위 허용 값 없을 때
requested_items 고객이 견적을 원한 품목 문자열 배열 품목 코드표에 있는 코드 빈 배열 []
due_date 고객이 희망한 납기 날짜(YYYY-MM-DD) 오늘 이후 null
urgency 메일에 드러난 긴급도 문자열 high, normal 판단 불가면 unknown

특히 “없음”을 하나로 뭉뚱그리지 않는 것이 중요합니다. 원문에 정보가 없는 경우, 항목 자체가 해당하지 않는 경우, 근거가 부족해 판단할 수 없는 경우는 후속 업무에서 의미가 다릅니다. 셋을 다른 값으로 정하고, 지시와 스키마 설명에 함께 적습니다. 필수 문자열 필드만 두면 모델은 정보가 없어도 그럴듯한 값을 채워 넣으려 합니다. 값이 없을 수 있는 필드는 null을 허용하도록 스키마를 짜야 합니다.

구조화 출력: 형식을 강제하는 기능

출력 형식을 고정하는 방법은 세 단계가 있습니다.

방법 보장 수준 어울리는 상황
지시문으로 형식 요청 대체로 따르지만 보장 없음 사람이 읽는 출력
예시로 형식 시연 일관성이 높아짐 문체와 구성까지 맞춰야 할 때
구조화 출력(JSON 스키마) 스키마 준수를 강제 시스템이 바로 읽고 저장하는 출력

OpenAI 문서는 JSON 모드와 구조화 출력을 구분합니다. 둘 다 유효한 JSON을 만들지만 스키마 준수까지 보장하는 것은 구조화 출력뿐이며, 가능하면 구조화 출력을 쓰라고 권합니다. 벤더별 요구 사항은 조금씩 다릅니다.

벤더 설정 알아 둘 점
OpenAI Responses API의 text.format에 json_schema와 strict: true, 또는 함수 호출의 strict 모드 모든 필드를 required로 두고, 선택 필드는 null과의 유니언으로 표현하며, 모든 객체에 additionalProperties: false가 필요하다. 출력은 스키마의 키 순서를 따른다
Anthropic output_config.format(JSON 출력)과 도구 정의의 strict: true 제약된 디코딩으로 스키마를 따른다. minimum·maximum·minLength·maxLength 같은 일부 제약은 지원하지 않아 API에 직접 보내면 400 오류가 나고, 대부분의 SDK 도우미는 이를 설명문으로 옮겨 보내고, 응답을 검증하는 도우미는 원래 제약으로 다시 확인한다. 필수 속성이 먼저, 선택 속성이 나중에 나온다
Google 응답을 JSON으로 지정하고 스키마 제공 JSON 스키마의 일부만 지원한다. 출력이 문법적으로 맞아도 값은 애플리케이션에서 항상 검증하라고 안내한다

분류 작업이라면 허용 라벨을 enum으로 정의합니다. Anthropic 문서는 분류에 enum 필드를 가진 도구나 구조화 출력을 쓰라고 권하면서, enum 값의 대소문자는 보장되지 않으니 대소문자를 무시하고 비교하고 대소문자만 다른 값을 두지 말라고 안내합니다.

형식 준수와 내용 정확성은 다르다

구조화 출력이 보장하는 것은 모양입니다. 내용이 맞는지는 보장하지 않습니다. OpenAI 문서는 구조화 출력도 실수를 담을 수 있다고 명시하고, 지시를 다듬거나 예시를 주거나 작업을 단순한 하위 작업으로 나누라고 권합니다. 그래서 기계가 읽을 출력은 네 단계로 검사합니다.

  1. 문법: JSON으로 파싱되는가.
  2. 스키마: 필드, 타입, enum이 맞는가. 지원되지 않아 강제할 수 없었던 제약(최댓값, 길이)은 여기서 코드로 확인한다.
  3. 업무 규칙: 납기가 오늘 이후인가, 품목 코드가 코드표에 있는가.
  4. 원문 대조: 값이 원문에 실제로 있는가. 표본을 뽑아 사람이 확인하거나 원문 문자열 검색으로 확인한다.

주의

구조화 출력도 예외가 있습니다. 모델이 안전상의 이유로 요청을 거절하거나 출력 한도에 걸려 잘리면 결과가 스키마와 맞지 않을 수 있습니다. Anthropic은 이 경우 stop_reason이 refusal 또는 max_tokens로 오고, OpenAI는 refusal 필드나 incomplete 상태로 알려 줍니다. 파싱 전에 중단 사유부터 확인합니다.

프리필의 원리와 대안

프리필(prefill)은 assistant 메시지의 앞부분을 미리 채워 두고 모델이 그 뒤를 잇게 하는 기법입니다. 예를 들어 마지막 assistant 메시지를 {로 채우면 모델은 JSON의 나머지를 이어 씁니다. 모델이 다음 글자를 예측하며 글을 쓴다는 성질을 이용해 첫 단추를 고정하는 방법이었습니다.

Anthropic 문서에 따르면 Claude 4.6 모델부터(그리고 Claude Mythos Preview에서) 마지막 assistant 턴의 프리필은 더 이상 지원되지 않으며, 그런 요청은 400 오류를 반환합니다. 이전 모델은 여전히 프리필을 지원하고, 대화 중간에 assistant 메시지를 넣는 것은 영향을 받지 않습니다. 문서는 모델의 지시 이행 능력이 좋아져 대부분의 용도에 프리필이 필요 없어졌다고 설명하고, 용도별 이전 경로를 제시합니다.

프리필의 용도 대신 쓸 방법
JSON·분류 형식 고정 구조화 출력, enum 필드를 가진 도구. 먼저 형식을 따르라고 요청해 보고 재시도와 함께 쓰는 방법도 있다
서두 문구 없애기 “서두 없이 바로 답하라”는 시스템 지시, 태그 안에 출력, 구조화 출력이나 도구 호출. 가끔 남는 서두는 후처리로 지운다
불필요한 거절 피하기 사용자 메시지 안의 분명한 지시로 충분하다
중단된 응답 이어 쓰기 사용자 메시지에 이전 응답의 끝부분을 넣고 이어서 쓰라고 요청하거나, 요청을 다시 보낸다
긴 대화에서 맥락 상기 상기할 내용을 사용자 턴에 넣거나, 도구나 컨텍스트 압축 단계에서 넣는다

모델을 바꿀 때 가장 먼저 점검할 항목이 프리필입니다. 오류가 나는 곳이 분명하기 때문에 찾기는 쉽지만, 프리필이 하던 일을 무엇으로 대신할지는 위 표처럼 용도별로 따로 정해야 합니다.

근거 필드는 짧은 설명으로

판정 결과와 함께 근거를 받고 싶을 때가 많습니다. 이때 두 가지를 설계합니다. 첫째는 필드의 순서입니다. 모델은 앞에서부터 쓰므로, 근거를 먼저 쓰고 판정을 나중에 쓰게 하면 판정이 근거에 기대게 됩니다. OpenAI 구조화 출력은 스키마의 키 순서를 따르고, Anthropic은 필수 속성을 먼저 내놓으므로, 순서를 지키려면 모든 속성을 필수로 두거나 재정렬을 고려해 파싱합니다.

둘째는 근거 필드에 무엇을 요구하느냐입니다. 사고 기능이 있는 최신 Claude 모델에서는 reasoning, thinking, trace 같은 필드에 단계별 사고 과정을 쓰라고 요구하면 reasoning_extraction 범주의 거절이 돌아올 수 있습니다. 공식 문서는 대신 짧은 설명이나 결과를 뒷받침하는 증거를 요구하라고 안내합니다. 필드 이름도 evidence, explanation처럼 무엇을 원하는지 드러나게 짓습니다. 4장에서 이 주제를 다시 다룹니다.

깊이 읽기

사고 기능이 있는 모델에는 방법을 보여 준다

사고(thinking) 기능이 있는 모델에서도 예시는 효과가 있습니다. Anthropic 문서는 풀이 예시가 모델이 비슷한 문제를 사고 블록 안에서 접근하는 방식을 형성한다고 설명하고, 각 예시를 “문제, 적용할 방법, 기대하는 답”으로 제시하라고 권합니다. 입력과 답만 보여 주는 예시는 답의 모양만 가르치지만, 방법까지 보여 주는 예시는 회사 고유의 계산 규칙처럼 모델이 일반 지식으로 알 수 없는 절차를 가르칩니다.

예시 형태 가르치는 것 위험
입력 → 답 답의 형식과 크기 예시 답과 비슷한 숫자를 내는 쏠림
입력 → 방법 → 답 적용할 규칙과 순서 예시가 길어져 토큰이 늘어남

방법을 보여 주더라도 최종 답은 정해진 필드나 태그에서만 뽑도록 지시하면, 설명과 답이 섞여 파싱이 깨지는 일을 막을 수 있습니다.

표시 환경이 서식을 결정한다

모델의 기본 서식이 표시 환경과 맞지 않으면 사용자는 기호를 그대로 보게 됩니다. 마크다운을 그리지 못하는 화면에 별표와 샵이 찍히는 것이 대표적입니다. Anthropic 문서는 최신 모델이 수학 표현에 LaTeX를 기본으로 쓴다고 밝히고, 평문이 필요할 때 LaTeX나 MathJax 대신 /, *, ^ 같은 기호만으로 수식을 표기하게 하는 예시 문구를 제공합니다.

서식 문제를 고칠 때는 1장의 원칙이 그대로 적용됩니다.

  1. 금지 대신 원하는 서식을 말한다. “마크다운 금지”보다 “매끄러운 문단으로”.
  2. 이유를 붙인다. “이 화면은 서식을 그리지 못해 별표가 글자로 찍힌다.”
  3. 프롬프트의 서식을 원하는 출력에 맞춘다. 평문 출력을 원하면 프롬프트에서도 제목과 글머리표를 걷어낸다.
  4. 후처리는 최후 수단으로 둔다. 정규식으로 기호를 지우면 의도한 기호(수식의 곱셈 기호 등)까지 지울 수 있다.

실무 장면

해오름의원: 접수 메모를 차트 입력란으로

지역 병원 ‘해오름의원’은 간호사가 접수 창구에서 적은 메모에서 증상, 발생 시점, 복용 약을 뽑아 전자차트 입력란에 미리 채우려 한다. 처음 프롬프트는 “다음 메모에서 정보를 JSON으로 뽑아 줘”와 예시 두 개였다. 운영해 보니 가끔 onset 필드 이름이 start_date로 바뀌고, 복용 약이 없을 때는 필드가 통째로 빠졌다. 메모에 시점이 “며칠 전부터”라고만 적힌 경우에는 구체적인 날짜가 지어져 들어왔다.

정보팀 서 주임은 원인을 세 갈래로 나눴다. 첫째, 예시 두 개가 모두 복용 약이 있고 시점이 분명한 메모라서 “없는 경우”와 “모호한 경우”의 모양을 보여 주지 못했다. 둘째, 지시와 예시만으로는 필드 이름과 존재 여부를 보장할 수 없다. 셋째, onset이 필수 날짜 필드라서 모델이 값을 비워 둘 방법이 없었다.

서 주임은 먼저 데이터 사전을 만들었다. onset은 “환자가 말한 증상 시작 시점”이고, 메모에 날짜가 있으면 날짜, “사흘 전”처럼 상대 표현만 있으면 원문 표현을 onset_text에 그대로 담고 onset은 null로 둔다. 복용 약은 “없다고 말함”(빈 배열)과 “메모에 언급 없음”(null)을 구분했다. 간호사가 다음 문진에서 물어야 할 대상이 바로 후자이기 때문이다.

그다음 예시를 다양성 표에 맞춰 네 개로 늘렸다. 약이 없다고 말한 메모, 약에 대한 언급이 없는 메모, 시점이 상대 표현인 메모, 증상이 여러 개인 메모다. 네 예시 모두 같은 태그와 같은 필드 순서를 쓴다. 메모 원문은 <memo> 태그로 감싸 지시와 분리했다. 차트 입력은 시스템이 바로 읽으므로 구조화 출력으로 스키마를 강제하고, onset은 날짜 또는 null을 허용하도록 바꿨다.

팀원 한 명은 날짜를 못 뽑으면 접수일을 넣자고 제안했지만, 서 주임은 버렸다. 접수일은 증상 시작일이 아니고, 그럴듯한 값이 채워져 있으면 의사가 확인 없이 지나칠 수 있었다. 마지막으로 중단 사유를 먼저 확인해 정상 종료일 때만 차트에 채우고, 하루 표본 열 건은 간호사가 원문과 대조하게 했다. 이후 필드 이름이 바뀌거나 빠지는 일은 사라졌고, 지어낸 날짜도 표본에서 나오지 않았다. 예시는 판단 경계를, 스키마는 모양을, 데이터 사전은 의미를 맡도록 역할을 나눈 것이 핵심이었다.

모퉁이오피스: 시설 민원 분류의 쏠림 잡기

공유 오피스 운영사 ‘모퉁이오피스’는 입주사가 앱으로 보내는 시설 민원을 “설비 고장, 청결, 소음, 출입·보안, 기타” 다섯 라벨로 분류해 담당 팀에 자동 배정한다. 시범 운영 2주 동안 담당 팀장들의 불만이 쌓였다. 설비팀에는 엉뚱한 민원이 몰렸고, 소음 민원은 자꾸 “기타”로 빠졌다.

운영 기획 담당 차 매니저는 사람이 다시 분류한 400건과 모델의 분류를 비교했다. 모델은 실제보다 훨씬 자주 “설비 고장”을 골랐다. 예시를 다양성 표에 대 보니 원인이 보였다. 예시 다섯 개 가운데 셋이 설비 고장이었고, 다섯 개 모두 긴 존댓말 문장이었으며, 마지막 예시도 설비 고장이었다. 반면 실제 민원은 “3층 회의실 옆 너무 시끄러움”처럼 짧은 글이 절반을 넘었다.

차 매니저는 고치기 전에 400건 가운데 150건을 평가용으로 떼어 잠갔다. 남은 250건에서 다양성 표의 빈칸을 채우는 예시를 골랐다. 라벨마다 하나 이상, 짧은 글과 긴 글, 그리고 경계 사례 둘을 넣었다. 하나는 “에어컨 소리가 너무 커서 통화를 못 하겠다”로, 소음처럼 보이지만 원인이 장비라 설비 고장이다. 다른 하나는 “복도에서 계속 큰 소리로 통화하는 사람이 있다”로 소음이다. 두 예시에는 라벨과 함께 “원인이 장비면 설비 고장”이라는 짧은 이유를 붙였다. 예시 순서도 라벨이 연달아 나오지 않게 섞었다.

출력은 배정 시스템이 바로 읽으므로 구조화 출력으로 label을 enum으로 강제하고, 담당 팀장이 볼 수 있게 evidence 필드에 판단 근거가 된 민원 속 표현을 짧게 옮기게 했다. 사고 과정을 적는 필드는 만들지 않았다.

검토 회의에서 “라벨마다 예외 규칙을 덧붙이자”는 의견이 나왔지만, 차 매니저는 먼저 예시 구성만 바꾼 버전을 평가하기로 했다. 규칙과 예시를 한꺼번에 바꾸면 무엇이 효과를 냈는지 알 수 없기 때문이다. 잠가 둔 150건으로 비교하자 소음 민원의 정답률이 크게 올랐고 설비 고장 쏠림이 줄었다. 남은 오류는 대부분 “기타”와 다른 라벨의 경계였고, 차 매니저는 그 유형만 골라 다음 수정 대상으로 기록했다.

자주 틀리는 지점

  • 예시는 많을수록 좋다. 같은 유형을 늘리면 쏠림만 강해지고, 너무 많으면 과적합됩니다. 개수는 실험으로 정합니다.
  • 예시만 좋으면 평가도 믿을 수 있다. 예시로 쓴 입력이 평가 세트에 섞이면 점수가 부풀어 보입니다. 평가용 입력을 먼저 떼어 둡니다.
  • 입력에 태그를 쓰면 출력도 구조화된다. 출력 형식은 따로 지정해야 하고, 기계가 읽을 출력은 스키마로 강제합니다.
  • JSON 모드면 필드도 지켜진다. JSON 모드는 문법만 보장합니다. 필드와 타입은 구조화 출력이 보장합니다.
  • 스키마를 지키면 값도 맞다. 구조화 출력은 모양을 보장할 뿐 내용을 보장하지 않습니다. 업무 규칙과 원문 대조는 따로 검사합니다.
  • 필수 필드로 두면 빠짐이 없어진다. 정보가 없는데 필수로 두면 그럴듯한 값이 지어집니다. 없을 수 있는 값에는 null을 허용합니다.
  • 프리필은 어디서나 통한다. 최신 Claude 모델에서는 400 오류가 납니다. 용도별 대안으로 옮깁니다.

한눈에 정리

주제 기억할 것
예시의 힘과 위험 형식·어조·경계를 가장 확실히 가르치지만 우연한 패턴도 가르친다
좋은 예시 관련성·다양성·구조, 형식은 모두 같게. 개수는 실험으로
편향 줄이기 수치로 확인 → 다양성 표 → 하나씩 바꾸기 → 베끼기 확인
데이터 분리 평가용 입력을 먼저 떼고 남은 것에서 예시를 고른다
태그 일관되고 설명적인 이름, 계층은 중첩. 경계 표시이지 보안 장벽이 아니다
데이터 사전 의미·타입·허용 값·결측 규칙. 없음/해당 없음/판단 불가를 구분
구조화 출력 스키마 준수를 강제. 벤더별 제약이 다르고 거절·잘림은 예외
4단 검사 문법 → 스키마 → 업무 규칙 → 원문 대조
프리필 Claude 4.6 이후 400 오류. 구조화 출력, 직접 지시, 태그로 대체

공식 문서로 확인하기

셀프 체크

2-1. 예시가 “가르치려는 것”과 “우연히 가르칠 수 있는 것”을 각각 두 가지씩 들라.

2-2. 예시를 고를 원천과 평가 세트를 만들 원천이 같은 로그 하나뿐이다. 작업 순서를 어떻게 잡아야 하는지 쓰고, 순서를 거꾸로 하면 어떤 문제가 생기는지 설명하라.

2-3. “아래 행사 문의에 답장 초안을 써라. 비가 오면 행사는 실내 체육관으로 옮긴다. 문의: …”를 지시·정책·입력이 나뉘도록 태그로 다시 써 보라.

2-4. 같은 판매 실적 데이터를 (가) 임원 보고용 화면, (나) 매장 안내 방송, (다) 재고 시스템 적재용으로 내보낸다. 각각에 알맞은 형식과 한 가지 주의점을 쓰라.

2-5. 출장비 정산서에서 “동행자 이름 목록”(문자열 배열)을 뽑는 필드가 있다. 동행자가 없다고 적힌 경우, 동행 여부가 아예 적혀 있지 않은 경우, 글씨가 번져 읽을 수 없는 경우를 각각 어떤 값으로 표현할지 정하고 이유를 쓰라.

2-6. 구조화 출력을 켰는데도 응답이 스키마와 맞지 않을 수 있는 경우 두 가지와, 파싱 전에 확인할 것을 쓰라.

2-7. 마지막 assistant 메시지를 미리 채워 두던 프롬프트 세 개가 있다. 용도는 각각 (가) 라벨 하나만 출력하게 하기, (나) 응답 첫머리의 인사말 없애기, (다) 끊긴 긴 글 이어 쓰기다. 최신 Claude 모델로 옮길 때 각각 무엇으로 대신할지 쓰라.

실습 과제

실습

예시 구성 비교 실험 (45분)

  1. 문의나 의견을 세 유형으로 분류하는 프롬프트를 만든다.
  2. 직접 만든 테스트 입력 20개(경계 사례 6개 포함)를 먼저 따로 적어 둔다. 이 20개는 예시로 쓰지 않는다.
  3. 버전 A는 예시 없이, 버전 B는 한 유형만 담은 예시 3개, 버전 C는 세 유형과 경계 사례를 섞고 문체와 길이도 섞은 예시 4~5개로 만든다.
  4. 세 버전에 테스트 입력 20개를 넣고, 버전별 전체 정답 개수, 경계 사례 정답 개수, 출력 라벨 분포를 표로 정리한다.

완료 기준: 표에서 버전 B의 라벨 쏠림과 버전 C의 경계 사례 정답 개수를 확인하고, 결과가 예상과 다르다면 그 이유를 한 줄로 적으면 완료다.

실습

데이터 사전과 스키마 설계 (40분)

  1. 영수증, 신청서, 이메일 가운데 하나를 골라 뽑을 필드 다섯 개를 정한다.
  2. 필드마다 업무상 의미, 타입·단위, 허용 값, 없을 때의 값을 데이터 사전 표로 쓴다. 없음·해당 없음·판단 불가 중 둘 이상을 구분한다.
  3. 데이터 사전을 JSON 스키마로 옮긴다. 분류 필드는 enum으로, 없을 수 있는 필드는 null을 허용하게 한다.
  4. 정보가 일부 빠진 입력 세 개를 포함해 입력 다섯 개로 결과를 받고, 4단 검사(문법, 스키마, 업무 규칙, 원문 대조)를 직접 해 본다.

완료 기준: 다섯 결과 모두 4단 검사 결과가 표로 남아 있고, 정보가 빠진 세 입력에서 지어낸 값이 하나도 없으면 완료다.