페이지 목차
이 페이지에서 검색
멀티 에이전트
이 페이지에 묻기
멀티 에이전트 · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.
생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.
MULTI · AGENT
멀티 에이전트
생성 수정
도구 실행·검색·기억·그래프 흐름·전문 에이전트의 협업을 구성하고 권한·평가·사람의 확인으로 통제합니다.
26개 문서 · 1일차 · 8 / 26
7차시 · 다중 도구 라우팅
지도 위치 : 1일차 · README 4장 ② 행동 층 — 도구가 여럿일 때 어느 것을 고르는가 | 이전: 6차시 데이터 조회 도구 구현 | 다음: 8차시 보안 — 안전한 도구 실행 키워드 : 도구 라우팅, 컨텍스트 비용, 디버깅
이 차시를 다 읽으면
- 도구가 늘면 생기는 세 문제( 설명 겹침 · 선택 오류 · 컨텍스트 비용 )를 말할 수 있다.
- 라우팅의 두 방식( 모델이 고름 ↔ 분류기가 먼저 좁힘 )을 "누가 흐름을 정하는가" 축으로 비교할 수 있다.
- 질문-기대 도구 평가셋 으로 도구 선택 정확도를 재는 표를 만들 수 있다.
- 선택 오류를 줄이는 네 수단(설명 다듬기 · 이름 구분 · 도구 묶음 줄이기 · 의도별 도구 세트)과 프롬프트 캐싱을 적용할 수 있다.
- 요청 · 응답 로그의
tool_use기록으로 어떤 도구를 왜 골랐는지 추적할 수 있다.
0. 이 차시의 판별 축
| # | 축 | 왼쪽 (0) | 오른쪽 (1) | 이 축으로 갈리는 것 | 큰 축 (README 5장) |
|---|---|---|---|---|---|
| 1 | ⭐ 하나 ↔ 여럿 | 도구 몇 개 (한 묶음) | 도구 수십 개 | 선택 정확도와 토큰이 어떻게 변하는가 | ⑤ 하나 ↔ 여럿 |
| 2 | ⭐ 한 건의 비용 ↔ 전체 비용 | 호출 한 번의 도구 정의 토큰 | 모든 요청 × 도구 정의 토큰 | 도구 정의가 왜 비용인가 | 5.4 파생 축 (부모 ⑤) |
| 3 | 누가 흐름을 정하는가 | 분류기 + 코드가 도구 후보를 좁힘 | 모델이 전체 목록에서 고름 | 라우팅 방식 | 5.2 중심 축 |
| 4 | 증거 ↔ 주장 | 평가셋으로 잰 선택 정확도 | "잘 고르는 것 같다" | 개선을 무엇으로 아는가 | 5.4 파생 축 (부모 ⑧) |
이 차시의 질문은 "도구가 두 개에서 열 개, 스무 개로 늘어도 모델이 맞는 도구를 고르게 하려면?" 입니다. 앞에서 조회 도구 두 개를 만들었습니다(6차시). 오피스봇이 자라면 휴가 · 티켓 · 장비 · 회의실 · 사내 연락처 도구가 계속 붙습니다. 그때 생기는 문제를 측정하고 고칩니다.
1. 도구가 늘면 생기는 문제
1.1 정의
도구 라우팅 — [도구 호출 설계]인데, [ 여러 도구 중 이번 요청에 맞는 도구(또는 도구 없음)를 고르는 과정 ]이라는 점에서 고른 도구를 실제로 실행하는 단계와 구별된다.
1.2 세 문제
| 문제 | 무엇이 일어나나 | 오피스봇 예 |
|---|---|---|
| 설명 겹침 | 두 도구의 설명이 비슷해 모델이 헷갈림 | get_ticket_status(티켓 상태)와 get_it_notice(IT 공지) — "메일이 안 돼요"에 어느 쪽? |
| 선택 오류 | 엉뚱한 도구, 필요 없는 호출, 필요한데 안 부름 | "연차 규정 알려줘"에 get_leave_balance(잔여 조회) 호출 |
| 컨텍스트 비용 | 도구 정의 전체가 매 요청의 입력 토큰 이 됨 | 도구 20개 × 정의 수백 토큰 = 질문마다 수천 토큰 |
컨텍스트 — [모델 입력]인데, [ 이번 호출에 함께 보내는 모든 것(시스템 프롬프트 · 도구 정의 · 대화 · 도구 결과) ]이라는 점에서 모델이 학습으로 가진 지식과 구별된다.
1.3 선택 오류의 네 종류
| 종류 | 예 | 원인 후보 |
|---|---|---|
| 오선택 | 규정 질문에 잔여 조회 도구 | 설명 겹침, 이름이 비슷 |
| 불필요 호출 | "고마워"에 도구 호출 | 설명에 "언제 쓰지 말지"가 없음 |
| 누락 | 잔여를 물었는데 도구 없이 숫자를 답함 (환각) | 설명이 약함, 프롬프트에 "추측 금지"가 없음 |
| 인자 오류 | 도구는 맞는데 year를 잘못 채움 | 인자 설명 부족 (6차시 검증이 잡음) |
1.4 컨텍스트 비용 재기
tokens_2 = client.messages.count_tokens(model=MODEL, tools=TOOLS[:2], messages=msgs).input_tokens
tokens_20 = client.messages.count_tokens(model=MODEL, tools=TOOLS, messages=msgs).input_tokens
print("도구 2개:", tokens_2, "/ 도구 20개:", tokens_20)
🔍 읽는 포인트 : 같은 질문, 도구 목록만 다르게 해서 입력 토큰을 셉니다(2차시의 count_tokens). 차이가 질문마다 붙는 도구 정의 비용 입니다. 앞에서 본 "곱하기 건수"가 여기서도 적용됩니다. 9차시 에이전트 루프는 한 질문에 여러 번 호출하므로 곱하기 반복 횟수 까지 붙습니다.
2. 라우팅의 두 방식 — 누가 흐름을 정하는가
(A) 모델이 고름 (B) 분류기가 먼저 좁힘
질문 ─▶ 모델 + 도구 20개 전부 질문 ─▶ 분류기(4차시) ─▶ intent="휴가조회"
│ 모델이 하나 고름 │ 코드가 도구 세트 선택
▼ ▼
tool_use 모델 + 휴가 도구 3개만 ─▶ tool_use
| (A) 모델이 고름 | (B) 분류기가 먼저 좁힘 | |
|---|---|---|
| 누가 흐름을 정하나 | 모델 | 코드 (분류 결과로) → 좁힌 범위 안에서 모델 |
| 도구 정의 토큰 | 매번 전체 | 의도별 몇 개 |
| 선택 오류 | 도구가 많을수록 늘기 쉬움 | 후보가 적어 줄기 쉬움 |
| 약점 | 비용 · 헷갈림 | 분류가 틀리면 맞는 도구가 후보에 없음 . 분류 호출 비용이 추가됨 |
| 복합 요청 ("연차랑 티켓 둘 다") | 한 번에 여러 도구 가능 | 한 의도로 좁히면 놓침 → 20차시에서 분해 |
⭐ 정답은 하나가 아닙니다. 도구가 몇 개뿐이면 (A)로 충분하고, 늘어나면 (B)를 검토합니다 — 1차시 문장 1 "충분하면 멈춘다"가 여기에도 적용됩니다. 어느 쪽이 나은지는 3절의 평가셋으로 잰 뒤 정합니다.
💡 (B)의 약점 대비 — 분류가 low이거나 기타면 넓은 도구 세트 를 주는 식으로 섞을 수 있습니다(4차시 3.2).
앞으로 다시 만납니다 — (B)는 19차시에서 그래프의 조건 분기 로, 22차시에서 관리 에이전트가 전문 에이전트를 고르는 오케스트레이션 으로 다시 나옵니다. 도구 대신 에이전트를 고를 뿐 같은 질문입니다.
3. 도구 선택 정확도 측정
3.1 평가셋 — 1차시 평가셋에 열 추가
번호 | 질문 | 기대 도구 | 기대 인자 | 비고
101 | 올해 연차 며칠 남았지? | get_leave_balance | year=2026 |
102 | 연차는 몇 년차부터 늘어나요? | (도구 없음 → 규정 검색) | | 오선택 유도
103 | 내가 올린 장애 처리됐어? | get_ticket_status | status_filter=전체 |
104 | 처리 중인 티켓만 보여줘 | get_ticket_status | status_filter=처리중 |
105 | 고마워요 | (도구 없음) | | 불필요 호출 유도
106 | 연차 남은 거랑 티켓 상태 둘 다 | get_leave_balance + get_ticket_status | | 병렬
(예시 형식입니다.) ⭐ "도구 없음"이 정답인 문항 을 꼭 넣습니다. 이것이 없으면 불필요 호출을 잴 수 없습니다.
3.2 결과표
| 구성 | 문항 수 | 정답 도구 | 오선택 | 불필요 호출 | 누락 | 인자 오류 | 평균 입력 토큰 |
|---|---|---|---|---|---|---|---|
| (A) 도구 전체 | ___ | ___ | ___ | ___ | ___ | ___ | ___ |
| (A) + 설명 다듬기 | ___ | ___ | ___ | ___ | ___ | ___ | ___ |
| (B) 의도별 도구 세트 | ___ | ___ | ___ | ___ | ___ | ___ | ___ |
(빈칸 양식입니다. 실측 값을 채워 쓰세요.)
도구 선택 정확도 = 정답 도구 ÷ 전체 문항. 확률론(3차시) 때문에 같은 구성을 2~3회 돌려 흔들림도 봅니다.
⚠️ 도구 선택만 맞고 최종 답이 틀릴 수도 있습니다(도구 결과를 무시하고 답함). 선택 정확도와 답의 정확도는 따로 셉니다.
4. 개선 수단
4.1 네 수단
| 수단 | 하는 일 | 잡는 오류 |
|---|---|---|
| 설명 다듬기 | "언제 쓰는가 / 언제 쓰지 않는가 / 비슷한 도구와의 차이"를 설명에 | 오선택, 불필요 호출 |
| 이름 구분 | get_info, get_data 대신 get_leave_balance, get_ticket_status처럼 동사 + 대상 | 오선택 |
| 도구 묶음 줄이기 | 비슷한 도구 여러 개를 인자 하나(enum)로 합침 — 단, 읽기 · 쓰기는 합치지 않음 (6차시) | 설명 겹침, 토큰 |
| 의도별 도구 세트 | 분류 결과로 후보를 좁힘 (2절의 B) | 오선택, 토큰 |
# 설명 다듬기 — 비슷한 도구와의 차이를 적음
"description": "현재 사용자의 남은 연차 일수를 숫자로 조회한다. "
"'며칠 남았어' 같은 잔여 질문에만 사용. "
"연차가 생기는 기준 · 규정 질문에는 사용하지 않는다(규정 검색이 담당)."
# 의도별 도구 세트
TOOLSETS = {
"휴가조회": [LEAVE_BALANCE, LEAVE_HISTORY],
"IT장애": [TICKET_STATUS, IT_NOTICE],
"기타": ALL_READ_TOOLS, # 분류가 애매하면 넓게
}
tools = TOOLSETS.get(intent.intent, ALL_READ_TOOLS)
🔍 읽는 포인트 : 위는 설명의 마지막 문장 (쓰지 말 때와 담당자), 아래는 TOOLSETS 딕셔너리 — 의도 이름이 열쇠, 도구 목록이 값. 모르는 의도면 넓은 세트로 갑니다.
4.2 ⚠️ 한 번에 하나씩
설명을 고치면서 이름도 바꾸고 세트도 나누면, 점수가 올라도 무엇 덕분인지 모릅니다. 3차시에서 프롬프트를 고칠 때와 같은 규칙입니다. 결과표(3.2)에 한 줄씩 추가합니다.
4.3 프롬프트 캐싱으로 도구 정의 비용 줄이기
요청의 앞부분은 도구 정의 → 시스템 프롬프트 → 대화 순서로 놓입니다. 도구 정의와 시스템 프롬프트가 요청마다 같다면 캐싱으로 재사용할 수 있습니다(2차시).
response = client.messages.create(
model=MODEL, max_tokens=16000,
tools=tools, system=SYSTEM_PROMPT, messages=messages,
cache_control={"type": "ephemeral"},
)
log.info("cache_read=%s input=%s",
response.usage.cache_read_input_tokens, response.usage.input_tokens)
🔍 읽는 포인트 : 두 번째 요청부터 cache_read가 0보다 크면 도구 정의 부분을 캐시에서 읽은 것입니다.
| 주의 | 이유 |
|---|---|
| 도구 목록의 순서 · 내용이 매번 같아야 | 한 글자라도 바뀌면 그 뒤가 전부 캐시 무효 |
| (B) 의도별 세트를 쓰면 | 세트마다 앞부분이 달라 캐시가 세트 수만큼 따로 생김. 세트를 너무 잘게 나누면 캐시 효과가 줄어듦 |
| 짧은 정의는 캐시 대상이 아닐 수 있음 | 최소 길이와 할인율은 공식 문서 확인 |
⭐ (A)와 (B)의 비용 비교는 캐싱까지 켠 상태에서 해야 공정합니다. 3.2 결과표의 "평균 입력 토큰" 옆에 cache_read 평균을 함께 적으세요.
5. 디버깅 — 어떤 도구를 왜 골랐나
5.1 남길 로그
[REQ-7c21] user=E1024 intent=휴가조회(high) toolset=휴가조회[2]
[REQ-7c21] step=1 stop_reason=tool_use tool=get_leave_balance input={"year": 2026}
[REQ-7c21] step=1 result_len=48 is_error=false
[REQ-7c21] step=2 stop_reason=end_turn answer_len=31 in=1830 out=42 cache_read=1610
🔍 읽는 포인트 : 같은 요청 ID (REQ-7c21)로 한 질문이 거친 단계를 묶습니다. 볼 칸은 intent, toolset, tool, input, stop_reason — "어떤 후보를 줬고, 무엇을 골랐고, 어떤 인자를 채웠는가".
5.2 오류를 거꾸로 따라가기
| 증상 | 로그에서 볼 곳 | 고칠 곳 |
|---|---|---|
| 엉뚱한 도구 | toolset에 맞는 도구가 있었는가 | 없었다면 분류(4차시), 있었다면 설명(4.1) |
| 도구를 안 부르고 숫자를 답함 | stop_reason=end_turn이 step=1에 | 설명 · 시스템 프롬프트의 "추측 금지" |
| 인자 오류 | input 값과 6차시 검증 결과 | 인자 description |
| 토큰이 많음 | in, cache_read | 도구 세트 크기, 캐싱 |
💡 모델이 도구 호출 전에 짧은 text 블록으로 이유를 남기는 경우도 있습니다. 로그에 함께 남기면 단서가 됩니다. 단, 3차시의 판단 근거 필드와 마찬가지로 증명이 아니라 단서 입니다.
⚠️ 로그에는 질문 원문과 도구 결과가 남습니다. 개인정보가 함께 남으므로 마스킹 이 필요합니다(8차시).
앞으로 다시 만납니다 — 11차시에서 이 로그를 직접 쓰는 대신 트레이싱 도구 가 단계별로 기록하게 합니다.
6. 실습 — 맡기고 검수하기
지시
오피스봇 읽기 도구를 6개로 늘리고(휴가 잔여, 휴가 사용 이력, 티켓 상태, IT 공지, 회의실 조회, 사내 연락처),
도구 선택 정확도를 두 방식으로 비교해줘.
참고 공식 문서: Anthropic Tool use 문서(도구 설명 작성 권장사항), 토큰 세기, 프롬프트 캐싱
목표:
1. eval/tool_eval_v0.csv: [번호 | 질문 | 기대 도구(없음 포함) | 기대 인자] 30문항.
"도구 없음" 5문항, 비슷한 도구 사이 헷갈리는 질문 5문항, 둘 이상 필요한 질문 3문항 포함
2. 구성 A(도구 6개 전부), 구성 B(4차시 분류기 → 의도별 도구 세트) 각각 실행, 각 2회
3. 결과표: [구성 | 정답 도구 | 오선택 | 불필요 호출 | 누락 | 인자 오류 | 평균 입력 토큰 | 평균 cache_read]
4. 모든 호출을 요청 ID로 묶은 로그로 남길 것 (intent, toolset, tool, input, stop_reason, usage)
5. 오선택 문항마다 [질문 | 기대 | 실제 | 그때 후보 도구 목록]
제약: 도구 설명을 고치는 것은 이번 실습 범위가 아님 — 먼저 현재 상태를 잴 것. tool_choice 강제 금지.
추측하지 말고 실행 명령과 실행 출력 원문을 붙여.
보고 형식: 위 결과표 + 오선택 표 + 로그 원문 10줄
받을 증거
- 결과표와 오선택 문항 표
- 요청 ID로 묶인 로그 원문 일부
내가 직접 확인할 것
| 볼 것 | 이걸로 아는 것 |
|---|---|
| "도구 없음" 문항에서 불필요 호출이 몇 건인가 | 1.3 — 설명에 "쓰지 말 때"가 필요한가 |
| 구성 B의 오선택 중 후보 목록에 정답이 없던 건수 | 2 — 분류가 틀려서 생긴 오류인가 |
구성 A와 B의 평균 입력 토큰 차이, cache_read 차이 | 1.4, 4.3 — 비용 비교가 공정한가 |
| 같은 구성 2회의 점수 차이 vs A·B 차이 | 3.2 — 개선이 우연보다 큰가 |
| 오선택 한 건을 골라 로그만 보고 원인을 내가 설명할 수 있는가 | 5.2 — 디버깅이 가능한 로그인가 |
부록 A. 스스로 확인하기
| # | 질문 | 답이 있는 곳 |
|---|---|---|
| 1 | 도구가 늘면 생기는 세 문제는? | 1.2 |
| 2 | 선택 오류의 네 종류는? | 1.3 |
| 3 | 도구 정의가 왜 매 요청의 비용인가? 어떻게 재나? | 1.2, 1.4 |
| 4 | 라우팅 두 방식을 "누가 흐름을 정하는가"로 비교하면? | 2 |
| 5 | 분류기로 좁히는 방식의 약점과 대비책은? | 2 |
| 6 | 도구 선택 평가셋에 "도구 없음" 문항이 필요한 이유는? | 3.1 |
| 7 | 개선 네 수단과, 한 번에 하나씩 바꾸는 이유는? | 4.1, 4.2 |
| 8 | 의도별 도구 세트와 프롬프트 캐싱이 부딪히는 지점은? | 4.3 |
| 9 | 엉뚱한 도구를 골랐을 때 로그에서 먼저 볼 곳은? | 5.2 |
부록 B. 자주 하는 실수
| 실수 | 바로잡기 |
|---|---|
| 도구를 일단 다 붙여 둠 | ⚠️ 정의 토큰이 매 요청 비용. 선택 오류도 늘기 쉬움 (1.2) |
get_info, get_data 같은 이름 | ❌ 동사 + 대상으로 구분 (4.1) |
| "도구 없음" 문항 없는 평가셋 | ❌ 불필요 호출을 못 잼 (3.1) |
| 도구 선택이 맞으면 답도 맞다고 봄 | ⚠️ 따로 셈 (3.2) |
| 설명 · 이름 · 세트를 한꺼번에 변경 | ⚠️ 무엇이 효과였는지 모름 (4.2) |
| 도구 목록 순서를 요청마다 바꿈 | ❌ 캐시가 깨짐 (4.3) |
| 로그에 요청 ID가 없음 | ❌ 한 질문의 단계를 묶어 볼 수 없음 (5.1) |
부록 C. NotebookLM 복습 프롬프트
이 7차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"도구가 늘면 생기는 세 문제", "모델이 고름과 분류기가 좁힘의 비교", "도구 선택 평가셋과 도구 없음 문항", "의도별 도구 세트와 캐싱의 충돌", "로그로 원인 찾기"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.
LangTailor