학습 자료

예시로 가르친다 — few-shot


Article

8강에서 구조화된 지시로 메모 정리 비서를 만들었다. 분류 기준이 흔들리던 문제, 팁이 따라붙던 문제는 잡혔다. 오늘은 규칙 하나를 더 얹는다, 할 일 내용을 8자 이내로 짧게 줄여라. 문장으로 못 박으면 될 것 같은데, 실제로 돌려보면 얘기가 다르다.

규칙을 문장으로 추가해본다

my-ai-assistant 폴더에 no-examples.ts 를 만든다. 8강의 index.ts<output_format> 규칙 하나만 추가했다.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const SYSTEM_PROMPT = `<role>
너는 메모 정리 비서다. 사용자가 두서없이 적은 메모에서 할 일을 뽑아 목록으로 만든다.
</role>

<task>
입력 메모에서 "해야 할 일"을 모두 찾아낸다. 마감이 있으면 그대로 살리고, 없으면 "미정"으로 표시한다.
</task>

<output_format>
- 마크다운, 이모지, 헤더, 굵은 글씨를 쓰지 않는다. 순수 텍스트 줄만 출력한다.
- 할 일 한 줄은 반드시 이 형식이다: "- [마감기한] 할 일 내용"
- 할 일 내용은 8자 이내로 짧게 압축한다. 조사와 불필요한 수식어는 뺀다.
- 마감이 급한 순서로 정렬한다. 마감이 없는 항목은 맨 뒤에 둔다.
- 목록 앞뒤로 인사말, 설명, 팁, 요약을 절대 덧붙이지 않는다. 목록 줄만 출력한다.
</output_format>`;

async function organize(note: string) {
  const response = await client.messages.create({
    model: "claude-haiku-4-5",
    max_tokens: 300,
    system: SYSTEM_PROMPT,
    messages: [{ role: "user", content: note }],
  });

  const text = response.content[0].type === "text" ? response.content[0].text : "";
  console.log(`\n--- 입력 ---\n${note}`);
  console.log(`--- 출력 ---\n${text}`);
}

await organize(
  "내일까지 3분기 마케팅 예산안 초안을 작성해서 팀장님한테 검토받아야 하고, 이번 주 금요일에는 신규 입사자 온보딩 자료도 준비해야 함. 시간 날 때 회사 근처 도서관에 반납할 책도 챙기기.",
);
await organize(
  "이번 주 안에 치과 예약을 다시 잡아야 하고, 프로젝트 문서 최종 리뷰는 오늘 중으로 끝내야 함. 엄마 생신 선물로 뭘 살지 다음 달 초까지 정해야 함.",
);

전보다 메모를 좀 더 복잡하게(문장을 길게) 만들었다. 실행한다.

npx tsx --env-file=.env no-examples.ts
터미널 — npx tsx --env-file=.env no-examples.ts
  • --- 입력 ---
  • 내일까지 3분기 마케팅 예산안 초안을 작성해서 팀장님한테 검토받아야 하고, 이번 주 금요일에는 신규 입사자 온보딩 자료도 준비해야 함. 시간 날 때 회사 근처 도서관에 반납할 책도 챙기기.
  • --- 출력 ---
  • - [내일] 3분기 마케팅 예산안 초안
  • - [금요일] 신규 입사자 온보딩 자료
  • - [미정] 도서관에 책 반납
  • --- 입력 ---
  • 이번 주 안에 치과 예약을 다시 잡아야 하고, 프로젝트 문서 최종 리뷰는 오늘 중으로 끝내야 함. 엄마 생신 선물로 뭘 살지 다음 달 초까지 정해야 함.
  • --- 출력 ---
  • - [오늘] 문서 최종 리뷰
  • - [이번 주] 치과 예약
  • - [다음 달 초] 생신 선물 결정

글자 수를 실제로 세어보면 규칙이 얼마나 안 지켜졌는지 드러난다.

no-examples.ts — 할 일 내용 글자 수 (규칙: 8자 이내)
3분기 마케팅 예산안 초안14자초과
신규 입사자 온보딩 자료13자초과
도서관에 책 반납9자초과
문서 최종 리뷰8자통과
치과 예약5자통과
생신 선물 결정8자통과

6개 중 3개가 규칙을 어겼다. "3분기 마케팅 예산안 초안"은 14자로, 8자 기준의 거의 두 배다.

예시 몇 개를 먼저 보여준다

이럴 때 쓰는 게 few-shot이다. 규칙을 문장으로 설명하는 대신, "이렇게 압축한다"는 예시 대화를 실제 질문 앞에 몇 개 놔둔다. 사람도 "짧게 써"보다 "이 정도로 짧게 써"라며 예시를 보여주면 훨씬 빨리 감을 잡는데, 모델도 마찬가지다.

규칙을 설명하는 것 vs 예시로 보여주는 것
  1. 지시문 (zero-shot)"8자 이내로 압축해라", 기준을 말로 설명한다
  2. 예시 대화 (few-shot)실제 입력→출력 쌍을 몇 개 먼저 보여준다
  3. 진짜 질문예시 뒤에 이어붙이면, 모델이 그 압축 폭을 그대로 흉내 낸다
few-shot 은 새 기능이 아니다. messages 배열에 예시용 user·assistant 쌍을 실제 대화처럼 미리 넣어두는 것뿐이다.

index.ts 를 만든다. no-examples.ts 와 시스템 프롬프트는 똑같고, messages 배열 앞에 예시 두 쌍을 추가한다.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const SYSTEM_PROMPT = `<role>
너는 메모 정리 비서다. 사용자가 두서없이 적은 메모에서 할 일을 뽑아 목록으로 만든다.
</role>

<task>
입력 메모에서 "해야 할 일"을 모두 찾아낸다. 마감이 있으면 그대로 살리고, 없으면 "미정"으로 표시한다.
</task>

<output_format>
- 마크다운, 이모지, 헤더, 굵은 글씨를 쓰지 않는다. 순수 텍스트 줄만 출력한다.
- 할 일 한 줄은 반드시 이 형식이다: "- [마감기한] 할 일 내용"
- 할 일 내용은 8자 이내로 짧게 압축한다. 조사와 불필요한 수식어는 뺀다.
- 마감이 급한 순서로 정렬한다. 마감이 없는 항목은 맨 뒤에 둔다.
- 목록 앞뒤로 인사말, 설명, 팁, 요약을 절대 덧붙이지 않는다. 목록 줄만 출력한다.
</output_format>`;

// 실제 압축 폭을 예시 두 개로 보여준다. 규칙은 이미 system 에 있으니, 여기서는 "이 정도로 줄인다"는 감각만 심는다.
const FEW_SHOT: Anthropic.MessageParam[] = [
  {
    role: "user",
    content:
      "내일까지 부서 워크샵 장소를 예약해야 하고, 다다음 주 화요일에 있을 신입사원 환영회 준비물도 미리 챙겨놔야 함.",
  },
  {
    role: "assistant",
    content: "- [내일] 워크샵 예약\n- [다다음 주 화요일] 환영회 준비물",
  },
  {
    role: "user",
    content:
      "이번 주 목요일까지 계약서 최종본에 서명해서 법무팀에 보내야 함. 사무실 정수기 필터도 갈아야 하는데 날짜는 상관없음.",
  },
  {
    role: "assistant",
    content: "- [이번 주 목요일] 계약서 서명\n- [미정] 정수기 필터 교체",
  },
];

async function organize(note: string) {
  const response = await client.messages.create({
    model: "claude-haiku-4-5",
    max_tokens: 300,
    system: SYSTEM_PROMPT,
    messages: [...FEW_SHOT, { role: "user", content: note }],
  });

  const text = response.content[0].type === "text" ? response.content[0].text : "";
  console.log(`\n--- 입력 ---\n${note}`);
  console.log(`--- 출력 ---\n${text}`);
}

await organize(
  "내일까지 3분기 마케팅 예산안 초안을 작성해서 팀장님한테 검토받아야 하고, 이번 주 금요일에는 신규 입사자 온보딩 자료도 준비해야 함. 시간 날 때 회사 근처 도서관에 반납할 책도 챙기기.",
);
await organize(
  "이번 주 안에 치과 예약을 다시 잡아야 하고, 프로젝트 문서 최종 리뷰는 오늘 중으로 끝내야 함. 엄마 생신 선물로 뭘 살지 다음 달 초까지 정해야 함.",
);

바뀐 건 한 곳이다. messages: [{ role: "user", content: note }] 대신 messages: [...FEW_SHOT, { role: "user", content: note }] 를 보냈다. 모델 입장에서는 이게 실제 대화 기록인지 예시인지 구분하지 않는다. 그냥 앞에 그런 대화가 있었던 것처럼 받아들이고, 그 패턴을 이어간다.

다시 실행하면

같은 두 메모, 같은 규칙이다. 예시만 앞에 붙었다.

npx tsx --env-file=.env index.ts
터미널 — npx tsx --env-file=.env index.ts
  • --- 입력 ---
  • 내일까지 3분기 마케팅 예산안 초안을 작성해서 팀장님한테 검토받아야 하고, 이번 주 금요일에는 신규 입사자 온보딩 자료도 준비해야 함. 시간 날 때 회사 근처 도서관에 반납할 책도 챙기기.
  • --- 출력 ---
  • - [내일] 마케팅 예산안 초안
  • - [이번 주 금요일] 온보딩 자료 준비
  • - [미정] 도서관 반납
  • --- 입력 ---
  • 이번 주 안에 치과 예약을 다시 잡아야 하고, 프로젝트 문서 최종 리뷰는 오늘 중으로 끝내야 함. 엄마 생신 선물로 뭘 살지 다음 달 초까지 정해야 함.
  • --- 출력 ---
  • - [오늘] 문서 최종 리뷰
  • - [이번 주 안에] 치과 예약
  • - [다음 달 초] 생신 선물 구매

글자 수를 다시 잰다.

index.ts(few-shot) — 할 일 내용 글자 수 (규칙: 8자 이내)
마케팅 예산안 초안10자초과
온보딩 자료 준비9자초과
도서관 반납6자통과
문서 최종 리뷰8자통과
치과 예약5자통과
생신 선물 구매8자통과
no-examples.ts vs index.ts — 최악 위반 사례 글자 수
no-examples · 3분기 마케팅 예산안 초안14자
index.ts · 마케팅 예산안 초안10자
"3분기"라는 부가 정보까지 쳐내면서 14자에서 10자로 줄었다. 기준(8자)에는 여전히 못 미치지만, 압축 폭 자체가 커졌다.

통과 개수는 3/6에서 4/6으로 늘었고, 가장 심하게 어겼던 항목도 14자에서 10자로 줄었다. 예시 두 개를 보여준 것만으로 압축 강도가 눈에 띄게 세졌다.

그런데 완벽하진 않다

"마케팅 예산안 초안"(10자), "온보딩 자료 준비"(9자)는 여전히 8자를 넘겼다. few-shot 이 방향은 잡아줬지만 규칙을 100% 강제하지는 못했다.

정리하면

문장으로 아무리 강조해도 모델이 감을 못 잡는 규칙이 있다. 그럴 때는 규칙을 설명하는 대신, 원하는 입력→출력 쌍을 messages 배열 앞에 예시로 놓는다. 완벽하진 않아도 지시문만 쓸 때보다 훨씬 규칙에 가까워진다.

다시 짚어보기
  1. 01

    문장으로 규칙을 추가했지만 절반이 어겨졌다

    8자 압축 규칙을 문장으로 추가했더니, 6개 중 3개가 기준을 넘겼다.

  2. 02

    예시 두 쌍을 messages 앞에 추가했다

    user·assistant 예시 대화를 실제 질문 앞에 붙여, 원하는 압축 폭을 직접 보여줬다.

    npx tsx --env-file=.env index.ts
  3. 03

    글자 수로 개선 폭을 직접 쟀다

    통과 항목이 3/6에서 4/6으로 늘었고, 최악의 위반도 14자에서 10자로 줄었다. 완벽하진 않다는 것도 함께 확인했다.

프롬프트만으로는 규칙을 100% 강제할 수 없다는 걸 오늘 눈으로 봤다. 다음 강의에서는 접근을 바꾼다. 텍스트 형식을 요구하는 대신, JSON 으로 답을 받아 프로그램이 직접 다루기 쉬운 구조로 바꾼다. 그리고 11강에서 그 JSON 이 깨져 나올 때를 대비해 검증까지 마치면, Course A 의 결과물인 CLI 어시스턴트가 완성된다.

예시로 가르친다 — few-shot — 디코드랩(DCODELAB)