▶️15

[영상] ReAct 패턴과 루프 비용 줄이기

Day 3: ReAct 에이전트

학습 목표
  • ReAct 패턴의 Thought-Action-Observation 루프 구조를 설명한다
  • 루프 회차가 늘 때 토큰이 어디서 불어나는지 messages 구조로 짚는다
  • 도구 결과 캐싱과 프롬프트 캐싱이 서로 다른 것임을 구분한다
  • 루프 무한 반복을 막는 Max Step과 중복 호출 차단을 구현한다

영상 핵심 정리 — ReAct 패턴과 루프 비용

ReAct는 2022년 Google이 발표한 Agent 설계 패턴으로, LLM이 '생각하고 → 행동하고 → 결과를 관찰하고 → 다시 생각하는' 루프를 반복하여 복잡한 태스크를 완수한다.


1. ReAct 루프 구조

Goal: 라인 2의 불량률이 어제보다 2% 상승한 원인을 찾아라

Thought 1: 라인 2 센서 데이터를 먼저 조회해야 한다
Action 1:  get_sensor_data(line=2, period='24h')
Observation 1: 온도 87°C (임계 85°C 초과), 진동 정상

Thought 2: 온도 이상이 원인일 수 있다. 냉각 시스템 상태 확인이 필요하다
Action 2:  get_cooling_system_status(line=2)
Observation 2: 냉각수 유량 15% 감소

Thought 3: 냉각수 유량 감소 → 온도 상승 → 불량률 증가 연결이 확인됐다
Action 3:  create_maintenance_ticket(issue='냉각수 유량 저하', priority='HIGH')
Answer:    냉각 시스템 이상으로 인한 열 변형이 불량률 상승 원인

2. 비용은 어디서 늘어나는가

비용 요인왜 늘어나는가줄이는 방법
루프 반복회차마다 messages 전체를 다시 보낸다. n회를 돌면 보낸 토큰의 합이 대략 n의 제곱에 비례한다Max Step 제한, 중복 호출 차단
Tool 결과 누적결과 문자열이 길수록 이후 모든 회차에 그대로 실려 간다결과를 요약해 반환, 오래된 결과 잘라내기
System Prompt 반복매 회차 앞에 똑같이 붙는다프롬프트 캐싱(공급자 기능)
불필요한 Tool 호출회차 자체가 늘어난다프롬프트에 행동 순서·금지 규칙 명시

Day 1의 Agent 실행 파이프라인 해부에서 messages 배열이 회차마다 어떻게 길어지는지 봤다. 그 그림이 이 표의 첫 줄이다. 절감 폭은 대화 길이와 Tool 결과 크기에 따라 달라지므로, "몇 % 줄었다"는 자기 워크로드에서 재기 전에는 말할 수 없다.

3. 두 캐싱은 다른 것이다

무엇을 저장하나누가 하나이 주차에서
프롬프트 캐싱매 요청 앞에 똑같이 붙는 프롬프트 접두부LLM 공급자다루지 않는다
도구 결과 캐싱Tool이 돌려준 문자열우리 코드(ToolCache)Day 2·3·4

이름이 비슷해 같은 것으로 배우기 쉽다. Day 4의 ToolCache는 MES를 다시 부르지 않게 할 뿐, 모델에 보내는 토큰을 줄여 주지 않는다. 캐시에서 꺼낸 결과도 messages에는 그대로 실린다.

4. 무한 루프 방지

MAX_STEPS = 10
for step in range(MAX_STEPS):
    response = llm_call(messages)
    message = response.choices[0].message
    if not message.tool_calls:      # 모델이 더 부를 도구가 없다 -> 최종 답변
        break
    if is_duplicate_action(message, history):  # 같은 (도구, 인자)의 되풀이
        break
    # Tool 실행 후 결과를 messages에 추가
else:
    return 'Max step 초과: 수동 검토 필요'

finish_reason을 쓰고 싶다면 위치는 response.choices[0].finish_reason이고, 도구를 부른 턴에서는 값이 'tool_calls', 최종 답변 턴에서는 'stop'이다. 판정 기준이 둘로 갈리면 헷갈리므로 이 주차는 tool_calls 유무 하나로 통일한다.

그리고 루프가 끝난 것이 질문이 풀렸다는 뜻은 아니다. 모델이 더 부르지 않기로 했을 뿐이다. 목표 달성 여부를 따로 확인하는 분기는 Week 5의 LangGraph에서 다룬다.

5. 비용은 재야 안다

response = client.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
u = response.usage
print(u.prompt_tokens, u.completion_tokens)

# gpt-4o-mini 공개 단가(2026-07 확인): 100만 토큰당 입력 $0.15 / 출력 $0.60
cost = u.prompt_tokens / 1_000_000 * 0.15 + u.completion_tokens / 1_000_000 * 0.60

루프 회차마다 이 값을 더하면 질문 하나의 비용이 나온다. 단가는 바뀌므로 공급자 가격표를 확인하고 쓴다.

함정 주의: ReAct 루프에서 Observation이 모호하면 LLM이 같은 Action을 반복하는 '무한 루프'에 빠진다. 각 Tool의 반환값은 '다음 행동을 결정하기에 충분한 정보'를 포함해야 하며, 오류 발생 시도 오류 코드+설명을 명확히 반환해야 한다.


다음 task와의 연결

'ReAct 루프: Thought-Action-Observation' 읽기 자료에서 ReAct를 LangGraph로 구현하는 방법과 각 단계를 시각화하여 디버깅하는 기법을 학습한다.

AI로 학습하기 — 꿀팁
ReAct 루프 토큰 비용 직접 계산AI 학습 팁

루프 회차가 늘 때 토큰이 어떻게 불어나는지 계산으로 확인하고, 본인 코드에서 response.usage로 실제 값과 맞춰 보세요.

ReAct 루프를 10회 도는 에이전트에서, 회차마다 messages 전체를 다시 보낼 때 누적 입력 토큰이 어떻게 늘어나는지 계산식으로 보여줘. system 500토큰, 질문 50토큰, 회차마다 assistant 80 + tool 결과 300토큰이 쌓인다고 가정해줘. 그다음 (1) 오래된 tool 결과를 잘라낼 때, (2) 결과를 요약해 반환할 때 각각 누적 토큰이 어떻게 달라지는지 같은 가정으로 비교해줘.
이 팁이 도움이 됐나요?
핵심 포인트
  • ReAct = Reasoning + Acting: 추론(Thought)과 행동(Action)을 교차 반복하여 목표에 도달한다
  • 루프는 회차마다 messages 전체를 다시 보낸다. n회를 돌면 보낸 토큰의 합이 대략 n의 제곱에 비례해 늘어난다
  • 히스토리를 자르거나 요약하면 회차가 늘어도 토큰이 선형에 가깝게 유지된다. 절감 폭은 대화 길이와 Tool 결과 크기에 달렸으므로 response.usage로 직접 재야 안다
  • Max Step(예: 10회) 제한과 같은 (도구, 인자)의 되풀이 감지로 무한 반복을 막는다
용어