본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 18. 19:45

에이전트 루프(Agent Loop) 이해하기: 도구를 사용하는 LLM 시스템의 실제 작동 방식

요약

LLM이 도구를 사용하여 작업을 수행할 때 필요한 '에이전트 루프(Agent Loop)'의 개념과 시스템 설계 방식을 설명합니다. 모델 단독의 추론을 넘어, 도구 실행과 결과 반영을 반복하는 하네스(Harness)의 역할과 상태 관리의 중요성을 다룹니다.

핵심 포인트

  • 에이전트 루프는 모델의 응답을 검사하고 도구를 실행하여 결과를 다시 컨텍스트에 추가하는 실행 사이클임
  • 모델은 시스템의 일부이며, 프롬프트 조립 및 도구 실행 등 오케스트레이션은 하네스(Harness)가 담당함
  • 효율적인 에이전트 설계를 위해 상태 관리, 프롬프트 제어, 캐싱, 승인 워크플로우가 필수적임

도구 호출 (tool-calling) 모델을 사용하여 구축하고 있다면, 가장 중요한 설계 결정은 종종 프롬프트가 아닙니다. 그것은 모델을 둘러싼 루프(loop)입니다.

LLM은 도구를 사용하고 싶다고 결정할 수는 있지만, 스스로 그 도구를 실행할 수는 없습니다. 주변 애플리케이션이나 SDK가 컨텍스트를 조립하고, 모델 응답을 검사하며, 도구를 실행하고, 결과를 추가하며, 최종 답변이 생성될 때까지 과정을 지속해야 합니다. 그 런타임 사이클이 바로 에이전트 루프 (agent loop) 입니다.

이 글은 에이전트 루프가 실제로 무엇인지, 모델이 어디에서 멈추고 하네스 (harness)가 어디서 시작되는지, 도구 호출이 단계별로 어떻게 작동하는지, 그리고 데모 단계를 넘어설 때 어떤 엔지니어링 트레이드오프 (tradeoffs)가 나타나는지를 설명합니다.

요약 (TL;DR)

  • 에이전트 루프는 모델이 컨텍스트를 검사하고, 도구를 요청하고, 결과를 관찰하며, 최종 답변에 도달할 때까지 계속할 수 있게 하는 실행 사이클입니다.
  • 모델은 시스템의 일부일 뿐입니다. 하네스 (harness) 또는 SDK가 프롬프트 조립, 도구 실행, 재시도 (retries), 승인 (approvals), 종료와 같은 오케스트레이션 (orchestration)을 담당합니다.
  • 상태 관리 (State management)는 프롬프팅만큼 중요합니다. 이전 도구 출력이나 대화의 연속성을 잃어버리면, 에이전트는 방금 무슨 일이 일어났는지 잊어버린 것처럼 행동할 것입니다.
  • 성능은 프롬프트 증가 제어, 안정적인 프롬프트 접두사 (prefixes), 캐싱 (caching), 그리고 제한된 도구 출력에 크게 좌우됩니다.
  • 안전한 에이전트 설계를 위해서는 검증 (validation), 부작용 (side effects)에 대한 승인 게이트 (approval gates), 그리고 동시성 (concurrency) 및 이력 전파 (history propagation)에 대한 명확한 규칙이 필요합니다.

에이전트 루프는 모델만이 아니라 시스템 그 자체입니다

핵심 문제는 간단합니다. 모델 외부의 무언가가 그 사이클을 관리하지 않는 한, 단발성 (one-shot) 모델 호출은 세상을 검사하고, 그에 따라 행동하며, 결과에 적응할 수 없습니다.

그것이 바로 하네스 (harness)의 역할입니다.

OpenAI의 Codex 아키텍처는 사용자 상호작용을 하나의 턴 (turn)으로 설명하지만, 단일 턴 내에는 모델 추론 (inference)과 도구 실행의 여러 내부 반복이 포함될 수 있습니다. OpenAI Agents SDK는 동일한 개념을 직접적으로 설명합니다: 에이전트를 호출하고, 최종 출력이 있는지 확인하며, 필요한 경우 핸드오프 (handoffs)를 처리하고, 그렇지 않으면 도구 호출을 실행하고 다시 실행합니다.

실질적인 멘탈 모델(mental model)은 다음과 같습니다:

  1. 입력 상태(input state)를 구축합니다.
  2. 모델을 호출합니다.
  3. 응답을 검사합니다.
  4. 모델이 도구(tools)를 요청했다면, 이를 검증하고 실행합니다.
  5. 도구 실행 결과(tool results)를 다시 컨텍스트(context)에 추가합니다.
  6. 모델을 다시 호출합니다.
  7. 모델이 최종 답변을 반환할 때만 중단합니다.

이는 모델 단독이 아니라, 하네스(harness)가 다음과 같은 작업들을 책임진다는 것을 의미합니다:

  • 프롬프트 조립 (Prompt assembly)
  • 메시지 이력 관리 (Message history management)
  • 도구 스키마 등록 (Tool schema registration)
  • 도구 실행 (Tool execution)
  • 검증 및 에러 처리 (Validation and error handling)
  • 재시도 로직 (Retry logic)
  • 승인 워크플로우 (Approval workflows)
  • 상태 지속성 (State persistence)
  • 루프 종료 (Loop termination)

이것이 바로 동일한 모델을 사용하는 두 시스템이 매우 다르게 동작할 수 있는 이유입니다. 각 시스템의 하네스가 컨텍스트, 도구 순서, 절단(truncation), 승인 및 지속 여부에 대해 서로 다른 결정을 내릴 수 있기 때문입니다.

단일 턴(Single Turn)에 포함되는 요소

루프가 실행되기 전에, 시스템은 모델이 무엇을 보게 될지를 정의해야 합니다.

입력 상태 (The input state)

일반적인 턴에는 다음이 포함됩니다:

  • 시스템 또는 개발자 지침 (System or developer instructions)
  • 도구 정의 또는 스키마 (Tool definitions or schemas)
  • 이전 메시지들 (Previous messages)
  • 이전 도구 호출 결과 (Previous tool-call results)
  • 현재 사용자 요청 (The current user request)
  • 때로는 환경 상태(environment state), 세션 메타데이터(session metadata), 또는 숨겨진 런타임 지침(hidden runtime instructions)

이것이 중요한 이유는 후속 추론(follow-up reasoning)이 이전의 관찰(observations)이 존재하는지에 달려 있기 때문입니다. 만약 모델이 한 번의 반복(iteration)에서 도구를 요청했는데 그 결과가 올바르게 다시 추가되지 않는다면, 다음 반복은 해당 작업 위에서 진행될 수 없습니다.

내부 루프 vs 외부 루프 (Inner loop vs outer loop)

고려해야 할 루프는 실제로 두 가지가 있습니다:

  • 내부 루프 (Inner loop): 단일 사용자 턴 내에서의 모델 추론(model inference) 및 도구 실행(tool execution)
  • 외부 루프 (Outer loop): 사용자의 후속 질문을 포함하는 더 넓은 범위의 멀티 턴(multi-turn) 대화

이러한 구분은 Codex 스타일의 아키텍처에서 명확하게 나타납니다. 사용자는 한 번 질문을 하지만, 에이전트는 답변하기 전에 내부적으로 여러 번의 도구 단계를 수행할 수 있습니다. 그 후 다음 사용자 메시지가 도착하면, 전체 대화 스레드는 그 축적된 상태로부터 계속됩니다.

그렇기 때문에 상태 연속성 (state continuity)은 선택 사항이 아닙니다. 상태 연속성이 없다면, 외부 루프 (outer loop)는 깨지게 되고 내부 루프 (inner loop)는 현실에 대한 불완전한 관점에서 추론을 시작하게 됩니다.

모델이 텍스트와 도구 호출 (Tool Call) 사이에서 결정하는 방식

하네스 (harness)가 현재 턴의 상태를 제공하면, 모델은 결정 경계 (decision boundary)에 놓이게 됩니다: 즉시 답변할 것인지, 아니면 하나 이상의 도구를 요청할 것인지 결정해야 합니다.

도구 호출 (Tool calling)이 작동하는 이유는 모델에게 구조화된 도구 정의 (structured tool definitions)가 제공되기 때문입니다. 모델은 자연어만을 생성하는 대신, 어떤 도구를 사용하고 싶은지, 그리고 어떤 인자 (arguments)를 전달하고 싶은지를 나타내는 구조화된 요청을 방출 (emit)할 수 있습니다.

이 시점에서 모델은 사실상 애플리케이션에 제어권을 다시 양도하는 것입니다.

커스텀 도구 (custom tools)를 사용할 때는 클라이언트 하네스 (client harness)가 제어권을 넘겨받아 도구를 실행하고 결과를 반환해야 합니다. 호스팅된 도구 (hosted tools)를 사용할 때는 이러한 오케스트레이션 (orchestration)의 더 많은 부분이 API 자체 내부에서 수행될 수 있습니다.

이는 중요한 아키텍처 설계 선택 사항입니다:

도구 유형실행 오케스트레이션 주체주요 트레이드오프 (tradeoff)
호스팅된 도구 (Hosted tool)API/런타임이 루프의 더 많은 부분을 처리더 단순한 오케스트레이션, 직접적인 제어권 감소
...

클라이언트 측 오케스트레이션의 장점은 제어권입니다. 그 대가는 이제 실패 모드 (failure modes)에 대한 책임이 사용자에게 있다는 점입니다.

실제 도구 실행 메커니즘

모델이 도구 요청을 방출하면, 하네스는 단순히 이를 실행하는 것 이상의 작업을 수행해야 합니다.

실행 전 검증 (Validate before execution)

안전한 하네스는 다음 사항들을 검증해야 합니다:

  • 도구 이름 (Tool name)
  • 인자 구조 (Argument structure)
  • 인자 유형 (Argument types)
  • 권한 규칙 (Permission rules)
  • 도구가 읽기 전용 (read-only)인지 또는 상태를 변경 (mutating)하는지 여부

이는 단순히 보안 문제일 뿐만 아니라 품질 문제이기도 합니다. 만약 모델이 잘못된 인자로 도구를 요청할 경우, 명시적인 도구 에러를 반환하는 것은 모델이 다음 루프 반복에서 스스로 수정할 수 있는 충분한 신호를 제공하는 경우가 많습니다.

올바른 형식으로 관찰 결과 (observation) 반환

모델은 행동-관찰 사이클 (action-observation cycle)을 종결짓는 구조화된 관찰 결과 (structured observation)를 필요로 합니다.

최소한의 패턴은 다음과 같습니다:

response = client.responses.create(
    input=initial_question,
    **MODEL_DEFAULTS,
...

핵심적인 세부 사항은 단순히 루프(loop) 그 자체만이 아닙니다. 다음 요청이 이전 응답으로부터 계속되며, 하네스(harness)에 의해 생성된 도구 출력(tool outputs)을 포함한다는 점입니다.

더 명시적인 관찰(observation) 페이로드는 다음과 같습니다:

context.append({
    "type": "function_call_output",
    "call_id": tool_call.call_id,
...

해당 function_call_output 항목은 모델이 이제 컨텍스트(context)에서 사용할 수 있게 된 도구 결과(tool result)를 바탕으로 추론을 계속할 수 있게 해주는 관찰(observation)입니다.

상태 관리 패턴 (State Management Patterns): 많은 에이전트가 실패하는 지점

에이전트를 망가뜨리는 가장 쉬운 방법 중 하나는 상태 연속성(state continuity)을 잃는 것입니다.

일반적인 상태 전략 (Common state strategies)

현재 OpenAI 툴링에는 몇 가지 패턴이 있습니다:

  • 클라이언트가 관리하는 전체 히스토리 재생 (Full history replay)
  • 서버 관리형 연속성을 위한 previous_response_id
  • 대화 연속성을 위한 conversation_id
  • SDK 관리형 세션 지속성 (SDK-managed session persistence)

각 접근 방식에는 트레이드오프(tradeoffs)가 존재합니다.

전체 재생(Full replay) vs 서버 관리형 연속성(server-managed continuation)

전체 재생(Full replay) 방식에서는 클라이언트가 매번 이전의 모든 메시지와 도구 결과(tool results)를 전송합니다. 이는 추론하기는 간단하지만, 페이로드(payload) 크기가 빠르게 증가합니다.

서버 관리형 연속성(server-managed continuation) 방식에서는 클라이언트가 previous_response_id와 같은 연속성 식별자와 함께 새로운 입력을 보낼 수 있습니다. 이는 페이로드 크기를 줄이고 히스토리 관리의 일부를 오프로드(offload)합니다.

Agents SDK의 이 예시는 응답 체이닝(response chaining)을 보여줍니다:

from agents import Agent, Runner

async def main():
...

이는 편리하지만, 여전히 일관된 상태 전략을 선택해야 합니다.

호환되지 않는 모드를 혼합하지 마세요

Agents SDK 문서는 동일한 실행 경로(run path)에서 세션 지속성(session persistence)을 conversation_id, previous_response_id, 또는 auto_previous_response_id와 결합하는 것에 대해 명시적으로 경고합니다.

이는 실질적인 설계 규칙입니다: 호출 흐름(call flow)당 하나의 연속성 모델을 선택하세요.

만약 이들을 혼합하면, 모델이 실제로 어떤 상태를 보고 있는지 더 이상 명확하지 않기 때문에 디버깅이 훨씬 어려워집니다.

프롬프트 증가, 캐싱, 그리고 안정적인 접두사(Stable Prefixes)가 중요한 이유

루프가 지속됨에 따라 컨텍스트(Context)가 성장합니다.

모든 새로운 모델 호출에는 이전의 지침(Instructions), 도구 스키마(Tool schemas), 사용자 메시지, 그리고 도구 출력(Tool outputs)이 포함될 수 있습니다. 만약 단순히 모든 것을 영원히 계속 추가하기만 한다면, 대화의 수명 동안 전송되는 바이트(Bytes)의 수가 빠르게 증가할 수 있습니다.

Codex가 프롬프트 접두사(Prompt prefixes)를 강조하는 이유

Codex 아키텍처 논의는 유용한 원칙을 강조합니다: 가능한 한 오래된 프롬프트 콘텐츠를 새로운 프롬프트의 정확한 접두사(Prefix)로 유지하는 것입니다. 이는 프롬프트 캐시(Prompt-cache) 재사용성을 향상시킵니다.

실질적인 관점에서, 안정적인 순서(Stable ordering)는 다음 항목들에 대해 중요합니다:

  • 시스템 지침 (System instructions)
  • 도구 정의 (Tool definitions)
  • 환경 메타데이터 (Environment metadata)
  • 이전 메시지 (Prior messages)

만약 호출 사이에 이들의 순서가 바뀐다면, 캐싱 가능성(Cacheability)이 떨어집니다. 동일한 문제가 재현성(Reproducibility)에도 영향을 미칩니다. 심지어 도구 정의의 순서 버그조차 캐시 미스(Cache misses)와 일관되지 않은 동작을 유발할 수 있습니다.

압축 전략 (Compaction strategies)

프로덕션 하네스(Production harness)는 보통 다음과 같은 요소들의 조합이 필요합니다:

  • 장황한 도구 출력(Tool output)의 절단 (Truncating)
  • 오래된 이력의 요약 (Summarizing)
  • 정적인 지침을 안정적으로 유지하고 앞부분에 배치
  • 셸(Shell) 또는 검색(Retrieval) 출력의 제한 (Bounding)
  • 가장 관련성이 높은 관찰(Observations)만을 그대로 보존

이는 출력이 매우 빠르게 노이즈(Noisy)로 변할 수 있는 셸, 검색, 또는 컴퓨터 사용(Computer-use) 작업에서 더욱 중요합니다.

목표는 단순히 비용을 낮추는 것이 아닙니다. 모델을 위한 사용 가능한 추론 기질(Reasoning substrate)을 유지하는 것입니다.

루프에서의 안전성과 제어 (Safety and Control in the Loop)

도구가 강력해질수록 하네스(Harness)의 중요성은 커집니다.

승인 게이트(Approval gates)와 부작용 (Side effects)

읽기 전용(Read-only) 도구 호출은 부작용(Side-effectful)이 있는 작업과는 다릅니다.

예를 들어:

  • 문서를 가져오는 것은 상대적으로 위험도가 낮습니다.
  • 이메일을 보내거나, 파일을 편집하거나, 배포를 실행하는 것은 위험도가 높습니다.

상태를 변경하는 작업(Mutating actions)은 종종 다음과 같아야 합니다:

  • 병렬로 실행하는 대신 직렬화(Serialized)되어야 함
  • 승인 게이트(Approval-gated)를 거쳐야 함
  • 가능한 경우 샌드박스(Sandboxed) 처리되어야 함
  • 감사 가능성(Auditability)을 위해 충분한 메타데이터와 함께 로그가 기록되어야 함

이것이 에이전트 프레임워크(Agent frameworks)가 동시성 설정(Concurrency settings)과 승인 워크플로(Approval workflows)를 노출하는 이유 중 하나입니다.

의도가 아닌 인자(Arguments)를 검증하라

모델로부터 생성되었다는 이유만으로 도구 요청(tool request)이 올바르다고 안전하게 가정할 수는 없습니다. 실행하기 전에 인자(arguments)를 검증하고, 무언가 잘못되었을 경우 구조화된 오류 피드백(structured error feedback)을 반환하세요.

이를 통해 루프가 잘못된 동작을 조용히 수행하지 않고도 복구할 기회를 얻을 수 있습니다.

추론 모델(Reasoning models)에 과도한 프롬프트를 제공하지 마세요

OpenAI의 추론 모델을 위한 함수 호출(function-calling) 가이드라인에 따르면, 모든 함수 호출 전에 "더 많이 생각하라"와 같은 추가적인 프롬프트를 강제해서는 안 된다고 명시되어 있습니다. 추론 모델은 이미 내부적인 추론을 수행하고 있으며, 과도한 프롬프트는 성능을 저하시킬 수 있습니다.

이는 프롬프트의 장황함(verbosity)보다 하네스(harness)의 품질이 더 중요한 경우가 많다는 유용한 상기 사항입니다.

멀티 에이전트 확장 및 트레이드오프(Tradeoffs)

단일 에이전트 루프가 작동하기 시작하면, 팀들은 종종 핸드오프(handoffs)나 에이전트를 도구로 사용하는 패턴(agent-as-tool patterns)을 추가합니다.

개념적으로 루프는 동일하게 유지됩니다:

  1. 하나의 에이전트를 호출합니다.
  2. 에이전트가 최종 출력(final output), 도구 요청(tool request), 또는 핸드오프(handoff)를 생성했는지 감지합니다.
  3. 그에 따라 실행 경로를 라우팅(route)합니다.
  4. 종료될 때까지 계속합니다.

Agents SDK는 그 의미를 명확하게 요약합니다:

에이전트는 최종 출력이 생성될 때까지 루프 내에서 실행됩니다. 루프는 다음과 같이 작동합니다:

1. 에이전트가 주어진 입력과 함께 호출됩니다.
...

까다로운 부분은 핸드오프라는 개념 자체가 아니라, 히스토리 전파(history propagation)입니다.

최근 커뮤니티의 논의를 보면, 한 에이전트가 다른 에이전트의 도구로 노출될 때 개발자들이 얼마나 많은 히스토리가 자동으로 전달되는지 확신하지 못하는 경우가 많습니다. 실제로 이는 프레임워크가 명시적으로 보장하지 않는 한, 모든 관련 컨텍스트(context)가 핸드오프를 따라온다고 가정해서는 안 된다는 것을 의미합니다.

멀티 에이전트 시스템의 경우, 암시적 상속(implicit inheritance)보다는 명시적인 컨텍스트 구성(explicit context composition)이 더 안전한 경우가 많습니다.

일반적인 실패 모드 및 디버깅 전략

대부분의 에이전트 버그는 지나고 나면 명백해 보입니다.

실패 모드 1: 연속성 상실(losing continuity)

증상:

  • 에이전트가 같은 말을 반복함
  • 이전의 도구 결과(tool results)를 잊어버림
  • MCP 도구 탐색(tool discovery)이 계속해서 다시 발생함

previous_response_id, conversation_id 또는 전체 메시지 기록(full message history)을 올바르게 전달하고 있는지 확인하세요.

실패 모드 2: 컨텍스트 범람 (context flooding)

증상:

  • 길고 품질이 낮은 응답
  • 부적절한 도구 선택 (poor tool selection)
  • 모델이 관련 사실을 놓침

도구 출력(tool output)이 너무 장황하지 않은지 확인하세요. 출력 크기를 제한하고, 로그를 요약하며, 유용한 관찰 결과(observations)만 유지하세요.

실패 모드 3: 불안정한 프롬프트 구성 (unstable prompt construction)

증상:

  • 캐시 미스 (Cache misses)
  • 유사한 실행 간의 일관성 없는 동작
  • 예상보다 높은 토큰 사용량

지시 사항(instructions), 도구 스키마(tool schemas), 그리고 환경 메타데이터(environment metadata)의 순서를 확인하세요.

실패 모드 4: 안전하지 않은 도구 실행 (unsafe tool execution)

증상:

  • 잘못된 API 호출 (invalid API calls)
  • 의도치 않은 부작용 (accidental side effects)
  • 재현하기 어려운 실패

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0