Post

[LLM 앱 실전] Day 4: 에이전트 - 스스로 계획하고 행동하는 루프

[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 체크리스트

  1. 에이전트가 추론-행동-관찰(ReAct) 루프로 자율 작업함을 이해했다.
  2. 도구 루프에 종료 조건과 단계 상한을 더해 에이전트를 구현했다.
  3. Plan-and-Execute로 복잡한 목표를 분해하는 패턴을 파악했다.
  4. 단기·장기·작업 메모리로 컨텍스트 한계를 넘는 법을 익혔다.
  5. 멀티 에이전트의 가치와 비용, 그리고 신뢰성 문제·대응책을 이해했다.

다음 편 예고

프롬프트·RAG·도구·에이전트로 LLM 앱을 만들었다. 그런데 “이게 잘 작동하는가”를 어떻게 알까? 마지막 Day 5(시리즈 마무리)에서는 평가와 가드레일 — LLM 앱의 품질을 측정하고 프로덕션에서 안전하게 운영하는 법을 다룬다.

This post is licensed under CC BY 4.0 by the author.