페이지 목차
이 페이지에서 검색
멀티 에이전트
이 페이지에 묻기
멀티 에이전트 · 현재 차시와 목차 본문에서만 찾아 답합니다. 답을 지어내지 않고 해당하는 대목을 그대로 보여 주며, 여기에 없으면 없다고 알려 드립니다.
생성형 AI가 아니라 이 페이지 본문을 찾아 그대로 보여 주는 방식입니다. 외부로 나가는 요청이 없습니다.
MULTI · AGENT
멀티 에이전트
생성 수정
도구 실행·검색·기억·그래프 흐름·전문 에이전트의 협업을 구성하고 권한·평가·사람의 확인으로 통제합니다.
26개 문서 · 2일차 · 10 / 26
9차시 · 에이전트 루프 직접 구현
지도 위치 : 2일차 · README 4장의 ② 행동 층 — 도구를 한 번 부르던 앱이 스스로 반복 하기 시작하는 자리 | 이전: 8차시 보안 — 안전한 도구 실행 | 다음: 10차시 루프 제어와 가드레일 키워드 : Agent Loop, ReAct 패턴
이 차시를 다 읽으면
- 에이전트 루프를 유와 종차로 정의하고, 앞에서 배운 "도구 한 번 호출"(5차시)과 누가 흐름을 정하는가 축으로 가를 수 있다.
- ReAct(생각 → 행동 → 관찰의 반복)를 그림으로 그리고, 오피스봇 질문 하나에 대입할 수 있다.
- 수동 루프 코드에서 멈추는 조건 두 가지 (
stop_reason,MAX_STEPS)를 찾아 짚을 수 있다. - API는 무상태인데 루프가 앞 단계 결과를 "기억"하는 이유를 축 ⑦로 설명할 수 있다.
- 루프 로그를 읽고 "몇 번 돌았나, 무엇을 불렀나, 왜 멈췄나"를 말할 수 있다.
0. 이 차시의 판별 축
| # | 축 | 왼쪽 (0) | 오른쪽 (1) | 이 축으로 갈리는 것 | 큰 축 (README 5장) |
|---|---|---|---|---|---|
| 1 | ⭐ 누가 흐름을 정하는가 | 코드 — 미리 짠 순서대로 도구를 부름 | 모델 — 결과를 보고 다음 행동을 정함 | 워크플로우 ↔ 에이전트 루프 | 중심 축 (README 5.2), 부모 ⑦ |
| 2 | 무상태 ↔ 상태 | API 호출 한 번은 이전을 모름 | messages 리스트에 관찰이 쌓임 | 루프가 앞 단계를 "기억"하는 방식 | ⑦ 무상태 ↔ 상태 |
| 3 | 한 번 ↔ 반복 | 도구 호출 1회 → 답 | 목표에 닿을 때까지 여러 바퀴 | 도구를 쓰는 앱 ↔ 에이전트 | 이 차시의 축 |
| 4 | 누가 멈추는가 | 모델 — 답을 냄(end_turn) | 코드 — 상한에 닿으면 끊음(MAX_STEPS) | 정상 종료 ↔ 강제 종료 | 부탁 ↔ 강제 (10차시에서 확장) |
이 차시의 질문 — 직원이 "다음 주 월~수 휴가 쓸 수 있어?"라고 물으면 잔여 연차 조회 와 휴가 규정 확인 이 둘 다 필요합니다. 앞에서 배운 도구 호출(5차시)은 "요청 → 실행 → 결과 → 답"의 한 바퀴였고, 다중 도구 라우팅(7차시)은 여러 도구 중 하나를 고르는 일이었습니다. 이번 차시는 한 바퀴를 여러 번 돌리고, 몇 바퀴를 돌지 모델이 정하게 합니다. 1일차가 대부분 중심 축의 왼쪽(코드가 흐름을 정함)이었다면, 이 차시에서 처음으로 오른쪽 으로 건너갑니다.
1. ⭐ 누가 흐름을 정하는가 — 한 번에서 반복으로
1.1 앞에서 배운 한 바퀴 (5차시 회수)
짧게 다시 짚습니다. 앱이 tools=[...](도구 선언: 이름 · 설명 · 인자 형식)를 붙여 모델을 부르면, 모델은 답 대신 "이 도구를 이 인자로 불러 달라"는 tool_use 블록 을 낼 수 있습니다. 이때 stop_reason은 "tool_use"입니다. ⭐ 모델은 실행하지 않고 요청만 합니다. 앱이 함수를 실행해 그 결과를 tool_result로 돌려주고 다시 부르면, 모델이 결과를 읽고 답합니다.
| 질문 | 필요한 도구 호출 | 한 바퀴로 끝나는가 |
|---|---|---|
| "올해 연차 며칠 남았어?" | 잔여 조회 1번 | ⭕ |
| "다음 주 월~수 휴가 쓸 수 있어?" | 잔여 조회 → (결과를 보고) 규정 확인 → 답 | ❌ 두 번째 호출이 첫 결과에 따라 달라짐 |
| "IT 티켓 상태 보고, 아직 미처리면 새로 접수해 줘" | 조회 → (미처리면) 접수 | ❌ 다음 행동이 관찰에 달려 있음 |
⭐ 아래 두 줄이 핵심입니다. 다음에 무엇을 할지가 앞 결과를 봐야 정해지면 , 순서를 미리 코드로 짤 수 없습니다. 그 판단을 모델에게 넘기는 구조가 에이전트 루프입니다.
1.2 정의와 경계
에이전트 루프 (Agent Loop) — [LLM 응용의 실행 구조]인데, [ 모델의 응답이 도구 요청인 동안 "호출 → 실행 → 결과 돌려주기"를 반복하고, 모델이 답을 내거나 코드가 정한 상한에 닿으면 멈춘다 ]는 점에서 코드가 정한 순서대로 도구를 부르는 워크플로우와 구별된다.
| 워크플로우 (코드가 정함) | 에이전트 루프 (모델이 정함) | |
|---|---|---|
| 다음 행동 | 개발자가 짠 if · 순서 | 모델이 직전 관찰을 보고 결정 |
| 도구 호출 횟수 | 미리 정해짐 | 실행해 봐야 앎 (0번일 수도, 6번일 수도) |
| 예측 · 시험 | 쉬움 | 어려움 — 같은 질문에 경로가 달라질 수 있음 |
| 비용 · 맞는 일 | 고정에 가까움 · 순서가 늘 같은 일 | 바퀴 수만큼 늘어남 (10차시) · 순서를 미리 정할 수 없는 일 |
1.3 반례 — 이건 아직 에이전트 루프가 아닙니다
| 대상 | 왜 아닌가 |
|---|---|
| 도구 목록을 준 한 번의 호출 | 반복이 없음. 5차시의 한 바퀴 |
| 코드가 도구 셋을 정해진 순서로 부르고 마지막에 LLM이 요약 | 반복은 있지만 순서를 코드가 정함 . 워크플로우 |
| 응답이 깨졌을 때 같은 요청을 다시 보내는 재시도 | 반복이지만 관찰을 보고 다음 행동을 고르지 않음 |
한 응답 안에 tool_use가 셋 (병렬 도구 호출) | 한 바퀴 안에서 여럿을 동시에 요청한 것. 바퀴 수는 1 |
💡 비유(기억 보조용): 체크리스트를 위에서부터 그대로 따르는 신입 ↔ 서류를 하나 확인할 때마다 다음에 어디를 볼지 스스로 정하는 담당자. 다만 이 담당자에게는 "최대 여덟 군데까지만 확인"이라는 규칙을 회사(코드)가 걸어 둡니다(5절).
2. ReAct 패턴 — 생각 · 행동 · 관찰
2.1 정의
ReAct (Reason + Act) — [에이전트 루프의 설계 패턴]인데, [ 생각(Reason) → 행동(Act, 도구 호출) → 관찰(Observation, 도구 결과)을 한 바퀴로 삼고, 관찰을 다음 생각의 재료로 쓴다 ]는 점에서 생각만 길게 하고 한 번에 답하는 방식이나, 생각 없이 도구만 연달아 부르는 방식과 구별된다.
┌─▶ 생각 "잔여부터 봐야겠다" ─▶ 행동 tool_use: 잔여 조회 ─▶ 관찰 tool_result: "5일 남음" ─┐
└──────────────────────────────── 관찰을 들고 다시 생각 ◀────────────────────────────────┘
│ 더 할 일이 없다고 판단하면
▼
답 (stop_reason = end_turn)
2.2 Claude API에서는 어디에 해당하는가
ReAct가 처음 나왔을 때는 프롬프트에 "Thought: … Action: … Observation: …" 형식을 글로 쓰게 했습니다. 지금은 API의 도구 호출 구조가 그 자리를 대신합니다.
| ReAct의 칸 | Claude API에서의 모습 | 누가 만드나 |
|---|---|---|
| 생각 | 모델 내부의 생각(thinking) · 설명 text 블록 | 모델 |
| 행동 | tool_use 블록 (name, input) | 모델이 요청 |
| 관찰 | tool_result 블록 | ⭐ 앱이 실행해서 돌려줌 |
| 답 | stop_reason == "end_turn"인 응답의 text 블록 | 모델 |
💡 최신 Claude 모델은 적응형 생각(adaptive thinking)이 기본으로 켜져 있어 "단계적으로 생각해"라고 따로 부탁할 필요가 줄었습니다. 그래서 응답 content에는 text · tool_use 외에 생각 블록이 섞여 올 수 있습니다. ⚠️ 이 때문에 루프는 응답을 골라 담지 않고 response.content를 통째로 다음 요청에 넣습니다(3.1).
3. 직접 구현 — 수동 루프
3.1 루프 골격
import anthropic
client = anthropic.Anthropic() # 키는 환경변수 ANTHROPIC_API_KEY에서 자동으로 읽음
MAX_STEPS = 8
messages = [{"role": "user", "content": "다음 주 월~수 휴가 쓸 수 있어?"}]
for step in range(MAX_STEPS):
response = client.messages.create(
model="claude-opus-5-5", max_tokens=16000,
system=SYSTEM_PROMPT, tools=tools, messages=messages,
)
if response.stop_reason != "tool_use":
break # 모델이 더 부를 도구가 없다 → 루프 끝
messages.append({"role": "assistant", "content": response.content})
results = []
for block in response.content:
if block.type == "tool_use":
content, is_error = run_tool(block.name, block.input)
results.append({"type": "tool_result", "tool_use_id": block.id,
"content": content, "is_error": is_error})
messages.append({"role": "user", "content": results})
else:
print("MAX_STEPS 도달 — 답을 내지 못하고 코드가 멈춤") # 강제 종료
🔍 읽는 포인트
for step in range(MAX_STEPS)— ⭐ 반복 상한 . 모델이 멈추지 않아도 코드가 여덟 바퀴에서 끊습니다.while True로 쓰지 않습니다. 맨 아래else:는break없이 끝까지 돌았을 때, 즉 "상한에 닿았다"는 뜻입니다.if response.stop_reason != "tool_use": break— 모델이 도구를 더 요청하지 않으면 나갑니다. 다만 이 줄은 정상 답(end_turn)과 잘림(max_tokens) · 거절(refusal)을 구별하지 않습니다 → 5절에서 나눕니다.messages.append(... response.content)— 모델의 요청을 먼저 , 그 뒤에tool_result를 넣습니다. 둘은tool_use_id로 묶인 짝 입니다.- 안쪽
for block— 한 응답에tool_use가 여럿이면 결과를 모두 한 user 메시지에 담습니다.
3.2 도구 실행부 — 1일차의 안전 장치가 그대로 들어가는 자리
TOOL_FUNCS = {"get_leave_balance": get_leave_balance,
"get_leave_policy": get_leave_policy}
def run_tool(name, args):
func = TOOL_FUNCS.get(name)
if func is None:
return f"오류: 알 수 없는 도구 {name}", True
try:
return func(employee_id=session.employee_id, **args), False # 신원은 로그인 세션에서
except Exception as e:
return f"오류: {e}", True # 실패도 결과로 돌려줌
🔍 읽는 포인트
TOOL_FUNCS.get(name)— 모델이 없는 도구 이름을 지어내도 실행되지 않습니다. 허용 도구 목록 입니다(10차시에서 가드레일로 다시 봄).employee_id=session.employee_id— 앞에서 배운 권한 경계 (8차시): 누구의 데이터인지는 모델이 준 인자가 아니라 로그인 세션 에서 가져옵니다.return ..., True— 실패를 예외로 터뜨리지 않고is_error가 붙은 결과로 돌려줍니다. 모델이 읽고 다른 방법을 고를 기회 가 되며, 이것도 관찰의 하나입니다.- ⭐ 루프는 새 안전 장치를 만들지 않습니다. 1일차의 권한 검사 · 마스킹 · 예외 처리가
run_tool안에서 매 바퀴 똑같이 돌 뿐입니다.
4. 축 ⑦ — messages가 쌓이며 상태가 된다
4.1 API는 기억하지 않는다
앞에서 배운 대로(2차시) LLM API는 무상태 입니다. 두 번째 호출은 첫 번째 호출을 모릅니다. 그런데 루프의 3바퀴째에 모델은 1바퀴째 결과("5일 남음")를 압니다. 이유는 하나입니다 — 앱이 매번 지금까지의 messages 전체를 다시 보내기 때문입니다.
1바퀴 보냄: [user 질문]
받음: assistant [생각, tool_use 잔여조회]
2바퀴 보냄: [user 질문, assistant tool_use, user tool_result "5일"]
받음: assistant [생각, tool_use 규정확인]
3바퀴 보냄: [user 질문, assistant tool_use, user tool_result "5일",
assistant tool_use, user tool_result "3일 전까지 신청"]
받음: assistant [text 답] → stop_reason = end_turn
| 무엇이 상태를 들고 있나 | 어디에 있나 | 언제 사라지나 |
|---|---|---|
messages 리스트 | 앱의 메모리 (축 ①) | 루프 · 요청이 끝나면 |
| 대화 이력 · 세션 저장소 | 메모리 또는 DB | 16차시에서 설계 |
⚠️ 두 가지가 따라옵니다.
- 매 바퀴 입력 토큰이 늘어납니다. 3바퀴째는 1 · 2바퀴의 내용을 다시 보냅니다. 바퀴가 늘수록 비용은 더하기가 아니라 누적의 누적 으로 늘어납니다 → 10차시의 비용 상한.
tool_use와tool_result의 짝이 깨지면 400 에러 가 납니다. 이력을 잘라 줄일 때 이 짝을 같이 다뤄야 합니다 → 16차시.
앞으로 다시 만납니다 — 16차시(멀티턴 대화)에서 이
messages를 요청을 넘어 세션 단위로 저장하고, 18차시(그래프 워크플로우)에서는 같은 생각을 그래프의 State 라는 이름으로 다시 만납니다.
5. 멈춤 조건 — 누가 멈추는가
5.1 모델이 멈추는 경우 — stop_reason 읽기
stop_reason | 뜻 | 루프가 할 일 |
|---|---|---|
tool_use | 도구를 요청함 | 실행하고 한 바퀴 더 |
end_turn | 답을 다 씀 | ⭕ 정상 종료. text 블록을 답으로 |
max_tokens | 출력이 max_tokens에서 잘림 | ⚠️ 답이 중간에 끊김. 그대로 보여 주지 말 것 |
refusal | 안전상 거절 | ⚠️ content를 읽기 전에 확인하고 거절 안내로 |
pause_turn · stop_sequence | 긴 작업의 일시 멈춤 · 지정한 멈춤 문자열 | 용도에 따라 처리 (세부는 공식 문서 확인) |
5.2 코드가 멈추는 경우 — 상한
모델이 "이제 답하겠다"고 판단해 주기를 기대 하는 것은 부탁입니다. 같은 도구를 계속 부르거나, 결과가 계속 실패해 헛도는 경우는 언제든 생깁니다. 그래서 MAX_STEPS로 강제 합니다. README 6장의 문장 2(모델은 판단하고, 코드는 지킨다)가 루프에서 처음 나타나는 자리입니다.
💡 MAX_STEPS 값은 "평소 가장 긴 정상 경로 + 여유"로 잡습니다. 오피스봇의 휴가 질문은 보통 2~3바퀴이므로 8이면 넉넉합니다. 상한에 닿았을 때 사용자에게 보여 줄 문장("확인이 길어져 담당자에게 넘깁니다" 등)도 미리 정해 둡니다.
앞으로 다시 만납니다 — 10차시에서 멈춤 조건이 넷으로 늘어납니다: 최대 반복, 토큰 · 비용 누적 상한, 같은 호출 반복 감지, 시간 제한.
6. 오피스봇 적용 — "다음 주 휴가 가능해?"
6.1 한 질문의 세 바퀴
도구는 둘입니다. get_leave_balance(year) — 잔여 연차 조회(6차시에서 만든 것), get_leave_policy(topic) — 휴가 규정 조회(지금은 고정된 규정 문구를 돌려주는 가짜 함수, 12~14차시에서 문서 검색으로 바뀜).
| 바퀴 | 생각 (모델) | 행동 (tool_use) | 관찰 (tool_result) |
|---|---|---|---|
| 1 | 3일을 쓰려면 잔여부터 봐야 한다 | get_leave_balance({"year": 2026}) | "남은 연차: 5일" |
| 2 | 일수는 충분. 신청 기한 규정이 있을 것이다 | get_leave_policy({"topic": "연차 신청 기한"}) | "연차는 사용 3일 전까지 신청" |
| 3 | 둘 다 확인됨. 답할 수 있다 | (없음) → end_turn | — |
최종 답(예시): "남은 연차가 5일이라 월~수 3일은 쓸 수 있습니다. 다만 규정상 사용 3일 전까지 신청해야 하니, 이번 주 목요일까지 신청하세요."
⚠️ 같은 질문이라도 모델은 순서를 바꾸거나(규정 먼저), 2바퀴에 두 도구를 한꺼번에 요청할 수도 있습니다. 경로가 고정되지 않는 것이 에이전트 루프의 본성입니다. 그래서 "어떤 경로든 답이 맞고 상한 안에서 끝나는가 "를 검사합니다.
6.2 루프 로그를 사람이 읽는 법
[REQ-7c21] step=1 stop=tool_use tool=get_leave_balance input={"year":2026} → "남은 연차: 5일" in=1,240 out=88
[REQ-7c21] step=2 stop=tool_use tool=get_leave_policy input={"topic":"연차 신청 기한"} → "3일 전까지 신청" in=1,410 out=95
[REQ-7c21] step=3 stop=end_turn 답=212자 in=1,690 out=240
[REQ-7c21] 종료=정상(end_turn) 바퀴=3 누적 in=4,340 out=423
(예시 — 실측 아님)
🔍 읽는 포인트 — 코드를 몰라도 이 네 줄은 읽을 수 있어야 합니다.
| 볼 것 | 정상 신호 | 이상 신호 |
|---|---|---|
종료= · 바퀴 수 | 정상(end_turn), 질문 난이도에 맞음 (2~3) | MAX_STEPS · max_tokens · refusal, 단순 질문에 6바퀴 이상 |
tool= · input= · → 결과 | 질문과 관련된 도구, 질문에 있는 값, 결과에 값이 있음 | 같은 도구 · 같은 인자가 연속, 오류:인데 같은 호출 반복 → 헛돎 |
in= | 바퀴마다 조금씩 증가 | 한 바퀴에 크게 뜀 (긴 도구 결과가 들어옴) |
⭐ 요청 ID(REQ-7c21)로 한 질문의 모든 바퀴를 묶어 둡니다. 로그에 직원 정보가 찍히므로 앞에서 배운 마스킹 (8차시: 외부로 나가거나 기록되기 전에 주민번호 · 전화번호 등을 가리는 것)을 로그에도 적용합니다.
7. 이런 도우미도 있다 — Tool Runner
SDK에는 위 루프를 대신 돌려 주는 Tool Runner (베타)가 있습니다. 함수에 데코레이터를 붙이면 도구 선언을 만들어 주고, 호출 → 실행 → 결과 돌려주기를 알아서 반복합니다.
from anthropic import beta_tool
@beta_tool
def get_leave_balance(year: int) -> str:
"""직원의 남은 연차 일수를 조회한다. 휴가 잔여를 물을 때 사용."""
runner = client.beta.messages.tool_runner(
model="claude-opus-5-5", max_tokens=16000,
tools=[get_leave_balance], messages=messages,
)
for message in runner: # 바퀴마다 모델의 응답이 하나씩 나옴
...
🔍 읽는 포인트 : @beta_tool이 함수의 이름 · 설명(docstring) · 인자 타입으로 도구 선언을 만들고, for message in runner가 3.1의 루프를 대신합니다. 베타 기능이라 이름 · 옵션이 바뀔 수 있으니 공식 문서 확인 .
⭐ 도우미는 코드가 짧은 대신 루프 안을 감춥니다. 직접 구현을 먼저 하는 이유는, 감춰진 루프 안에서 무엇을 어디에 끼워야 하는지 (10차시의 비용 상한 · 반복 감지 같은 가드레일)를 알기 위해서입니다.
앞으로 다시 만납니다 — 11차시에서 같은 루프를 LangChain 프레임워크로 옮기며 "직접 구현 ↔ 프레임워크: 무엇을 얻고 잃나"를 다시 비교합니다.
8. 실습 — 맡기고 검수하기
지시
오피스봇에 에이전트 루프를 직접 구현해줘. (Tool Runner·프레임워크 쓰지 말고 messages.create로 직접)
- 참고: Claude API 공식 문서의 tool use 페이지 (최신 SDK 기준으로 확인하고, 확인한 문서 주소를 보고에 적을 것)
- 도구 2개: get_leave_balance(year) — 가짜 DB(직원 3명), get_leave_policy(topic) — 고정 규정 문구 3개
- 직원 신원은 함수 인자가 아니라 session 객체에서 가져올 것 (모델이 준 사번은 무시)
- MAX_STEPS = 8. stop_reason을 end_turn / max_tokens / refusal / 상한 도달로 나눠 처리
- 도구 실패는 is_error=True 인 tool_result로. 바퀴마다 [요청ID, step, stop_reason, 도구, 입력, 결과 앞 50자, input/output 토큰] 한 줄 로그
- API 키는 환경변수로만 (코드·로그에 키 금지)
테스트 질문: ① "안녕" ② "올해 연차 며칠 남았어?" ③ "다음 주 월~수 휴가 쓸 수 있어?"
④ get_leave_policy가 항상 오류를 내게 바꾼 뒤 ③ ⑤ MAX_STEPS=1로 바꾼 뒤 ③
추측하지 말고 실행 출력 원문을 붙여.
보고 형식: [질문 | 바퀴 수 | 부른 도구 순서 | 종료 이유 | 누적 토큰 | 최종 답 요약] 표
받을 증거
- 질문 ①~⑤의 루프 로그 원문 과 위 형식의 표, ⑤에서 상한 도달로 코드가 멈췄다는 로그 줄, 참고한 공식 문서 주소
내가 직접 확인할 것
| 볼 것 | 이걸로 아는 것 |
|---|---|
| ①의 바퀴 수가 1이고 도구 호출이 0번인가 | 루프가 필요 없을 때 도구를 남발하지 않는가 (1.2) |
| ③의 로그에 도구 두 개가 나뉘어 또는 함께 나타나는가 | 모델이 관찰을 보고 다음 행동을 정했는가 (2절, 6.1) |
③의 in= 숫자가 바퀴마다 늘어나는가 | messages 누적 = 상태 (4.1) |
| ④에서 모델이 오류를 숨기지 않고 "규정을 확인하지 못했다"고 말하는가 | is_error 관찰이 전달됐는가 (3.2) |
| ⑤에서 사용자에게 보이는 문장이 정해 둔 안내인가 | 강제 종료 처리 (5.2) |
부록 A. 스스로 확인하기
| # | 질문 | 답이 있는 곳 |
|---|---|---|
| 1 | 에이전트 루프를 유와 종차로 정의하면? 워크플로우와 무엇으로 갈리나? | 1.2 |
| 2 | ReAct의 생각 · 행동 · 관찰은 Claude API의 어떤 블록에 해당하나? | 2.2 |
| 3 | 응답을 골라 담지 않고 response.content를 통째로 넣는 이유는? | 2.2, 3.1 |
| 4 | 수동 루프의 멈춤 조건 두 가지는? | 3.1, 5절 |
| 5 | 무상태 API에서 루프가 앞 결과를 아는 이유는? | 4.1 |
| 6 | 루프 로그에서 헛돎을 알아보는 신호는? | 6.2 |
| 7 | Tool Runner가 있는데도 직접 구현을 먼저 하는 이유는? | 7절 |
부록 B. 자주 하는 실수
| 실수 | 바로잡기 |
|---|---|
while True로 루프를 돌림 | ❌ 모델이 멈춰 주길 기대하는 것은 부탁. ⭕ MAX_STEPS로 강제 |
stop_reason != "tool_use"면 무조건 정상 답으로 처리 | ⚠️ max_tokens(잘림) · refusal(거절)을 나눠 처리 |
| 응답에서 text 블록만 골라 assistant 메시지에 넣음 | ❌ tool_use · 생각 블록이 빠져 짝이 깨짐. ⭕ response.content 통째로 |
| 도구 실패를 예외로 터뜨려 루프가 죽음 | ⭕ is_error: True 결과로 돌려줘 모델이 대응하게 |
| "루프를 쓰면 더 똑똑해진다" | ⚠️ 한 바퀴로 되는 질문에 루프는 비용만 늘림 (README 문장 1) |
부록 C. NotebookLM 복습 프롬프트
이 9차시 노트만 근거로 6문제를 내줘. 비전공자 기준으로.
"누가 흐름을 정하는가(워크플로우 ↔ 에이전트 루프)", "ReAct의 세 칸", "messages 누적이 곧 상태", "멈춤 조건 두 가지"는 반드시 포함해줘.
답은 내가 답한 다음에 채점하고, 틀린 이유를 노트의 절 번호를 근거로 설명해줘.
LangTailor