[LLM 앱 실전] Day 4: 에이전트 - 스스로 계획하고 행동하는 루프
이 글은 AI(Claude)의 도움을 받아 작성하고, 작성자가 검토·편집했습니다.
서론: 한 번의 응답에서 자율적 작업으로
Day 3에서 모델이 도구 하나를 호출하는 법을 배웠다. 에이전트는 그것을 루프로 확장한다. 목표를 받으면 스스로 계획을 세우고, 도구를 쓰고, 결과를 관찰하고, 다음 행동을 정하기를 — 목표를 달성할 때까지 반복한다. “리서치 후 보고서 작성”, “버그 찾아 수정” 같은 다단계 작업이 가능해진다. 하지만 자율성은 통제와 비용의 새 문제를 부른다.
1. 에이전트의 핵심 루프: ReAct
에이전트의 가장 기본 패턴은 추론(Reason)과 행동(Act)의 반복이다.
1
2
3
4
5
6
7
8
목표 입력
↓
┌─> [Thought] 무엇을 해야 하나? (추론 - Transformer Day 4의 CoT)
│ [Action] 도구 호출 (Day 3)
│ [Observation] 도구 결과 관찰
└── 목표 달성? No → 루프 반복 / Yes → 종료
↓
최종 답변
1
2
3
4
5
6
7
8
9
예: "최근 출시된 우리 경쟁사 제품 3개를 표로 정리해줘"
Thought: 경쟁사 정보를 검색해야겠다
Action: web_search("경쟁사 신제품 2026")
Observation: [검색 결과...]
Thought: 제품 3개를 찾았다. 각 가격을 확인하자
Action: web_search("제품A 가격")
... 반복 ...
Thought: 충분한 정보를 모았다. 표로 정리하자
→ 최종 답변
2. 최소 에이전트 구현
에이전트는 본질적으로 Day 3의 도구 루프에 “종료 조건”과 “반복”을 더한 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def run_agent(goal, max_steps=10):
messages = [
{"role": "system", "content":
"너는 목표를 달성하는 에이전트다. 도구를 사용해 단계적으로 일하고, "
"목표를 달성하면 최종 답을 텍스트로 반환하라."},
{"role": "user", "content": goal},
]
for step in range(max_steps): # 무한 루프 방지 상한 (필수!)
resp = client.chat.completions.create(
model="...", messages=messages, tools=tools)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls:
return msg.content # 도구 호출 없음 → 작업 완료
for call in msg.tool_calls: # 도구 실행 (Day 3)
result = dispatch(call.function.name,
json.loads(call.function.arguments))
messages.append({"role": "tool", "tool_call_id": call.id,
"content": json.dumps(result)})
return "최대 단계 초과" # 안전장치
max_steps는 선택이 아니라 필수다. 에이전트가 무한 루프에 빠지면 비용이 폭주한다.
3. 계획 수립: 큰 목표를 쪼개기
복잡한 작업은 즉흥적으로 풀기보다 먼저 계획을 세우게 하면 안정적이다.
1
2
3
4
5
6
7
Plan-and-Execute 패턴:
1. 플래너: 목표를 하위 작업 목록으로 분해
2. 실행자: 각 하위 작업을 순서대로 (또는 병렬로) 수행
3. 재계획: 중간 결과에 따라 계획 수정
장점: 전체 그림을 먼저 잡아 표류(곁길로 새기) 방지
단점: 초기 계획이 틀리면 비효율 → 재계획 능력 필요
4. 메모리: 컨텍스트를 넘어 기억하기
에이전트는 긴 작업 중 컨텍스트 한계(Day 1)에 부딪힌다. 메모리 계층으로 해결한다.
1
2
3
4
5
6
7
8
단기 메모리: 현재 대화/작업의 메시지 (컨텍스트 윈도우)
→ 길어지면 요약해 압축 (Day 1)
장기 메모리: 벡터DB에 과거 상호작용·지식 저장 (Day 2 RAG와 동일 인프라)
→ 필요할 때 검색해 컨텍스트로 불러옴
작업 메모리: 현재 계획·진행 상태를 구조화해 외부에 저장
→ 스크래치패드, 할 일 목록
메모리는 결국 “무엇을 컨텍스트에 넣을지”의 문제다. RAG가 지식 검색이라면, 에이전트 메모리는 자기 경험의 검색이다.
5. 멀티 에이전트: 역할 분담
하나의 에이전트로 모든 걸 하기보다, 전문화된 여러 에이전트를 협업시키는 패턴이 있다.
1
2
3
4
5
6
7
8
9
오케스트레이터-워커:
조정자 에이전트가 작업을 나눠 전문 워커에게 분배
예: [조정자] → [리서처][작성자][검증자]
토론/검증:
한 에이전트가 작업, 다른 에이전트가 비평 → 품질 향상
주의: 멀티 에이전트는 강력하지만 복잡도·비용·지연이 곱으로 증가
→ 단일 에이전트로 충분하면 그것을 택한다 (대규모 시스템의 "필요할 때만")
6. 에이전트의 현실: 신뢰성 문제
에이전트는 매력적이지만, 프로덕션에서는 신뢰성이 가장 큰 도전이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
주요 실패 모드:
- 누적 오류: 단계마다 작은 실수가 쌓여 결과가 크게 빗나감
- 무한 루프 / 표류: 같은 행동 반복, 목표에서 벗어남
- 비용 폭주: 자율 루프가 예상보다 많은 API 호출
- 환각 행동: 없는 도구를 부르거나 잘못된 인자
대응:
- 단계 수·비용·시간 상한 (서킷브레이커 — gRPC Day 4)
- 중요 행동에 인간 승인(human-in-the-loop)
- 각 단계 로깅·추적 (관측성 — 대규모 시스템 Day 5)
- 좁은 도구·명확한 종료 조건
- 평가로 신뢰성 측정 (→ Day 5)
원칙: 자율성은 정도의 문제다. 완전 자율보다, 통제된 자율 + 인간 개입이 실용적.
7. Day 4 체크리스트
- 에이전트가 추론-행동-관찰(ReAct) 루프로 자율 작업함을 이해했다.
- 도구 루프에 종료 조건과 단계 상한을 더해 에이전트를 구현했다.
- Plan-and-Execute로 복잡한 목표를 분해하는 패턴을 파악했다.
- 단기·장기·작업 메모리로 컨텍스트 한계를 넘는 법을 익혔다.
- 멀티 에이전트의 가치와 비용, 그리고 신뢰성 문제·대응책을 이해했다.
다음 편 예고
프롬프트·RAG·도구·에이전트로 LLM 앱을 만들었다. 그런데 “이게 잘 작동하는가”를 어떻게 알까? 마지막 Day 5(시리즈 마무리)에서는 평가와 가드레일 — LLM 앱의 품질을 측정하고 프로덕션에서 안전하게 운영하는 법을 다룬다.