본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 30. 22:34

BoxAgnts 소개 (6) — 에이전트의 멀티턴 대화 (Multi-Turn Conversation) 및 도구/기술 호출 (Tool/Skill

요약

BoxAgnts 프레임워크에서 에이전트의 멀티턴 대화와 도구 호출이 이루어지는 내부 설계 및 구현 과정을 분석합니다. 에이전트의 역할 정의, 시스템 프롬프트 주입 방식, 그리고 핵심 함수인 run_query_loop의 구조를 다룹니다.

핵심 포인트

  • 에이전트의 정체성을 부여하는 역할(Role) 정의 및 권한 설정 방식
  • 단계별 최적화를 위한 모델 및 최대 턴 수 재정의 기능
  • 대화 기록, 도구 실행, 컨텍스트 관리를 포함한 복잡한 상호작용 흐름
  • run_query_loop 함수를 통한 에이전트 추론 루프의 핵심 설계

만약 여러분이 ChatGPT와만 대화를 나눠봤다면, AI 에이전트(AI Agent)란 단순히 "API에 프롬프트(Prompt)를 보내고 응답을 표시하는 것"이라고 생각할 수도 있습니다.

현실은 훨씬 더 복잡합니다. 다음은 BoxAgnts에서의 완전한 에이전트 상호작용 흐름입니다:

사용자 입력: "config.toml 파일을 읽고 포트를 9090으로 변경하는 것을 도와줘"

1. 사용자 메시지가 대화 기록(Conversation history)에 추가됨
...

이 프로세스에는 3번의 API 호출, 2번의 도구 실행(Tool execution), 스트리밍 푸시(Streaming push), 그리고 컨텍스트 관리(Context management)가 포함됩니다. 이 글에서는 각 연결 단계의 설계와 구현을 분석합니다.

에이전트 정의: 에이전트에게 "정체성" 부여하기

추론 루프(Reasoning loop)를 시작하기 전에, 에이전트의 "역할(Role)"을 정의해야 합니다. BoxAgnts에는 세 가지 에이전트가 사전 설치되어 있습니다:

// boxagnts-workspace/src/config.rs
pub struct AgentDefinition {
    pub description: "Option<String>,    // Description"
...

사전 설치된 세 가지 에이전트 역할:

에이전트 (Agent)권한 (Permission)프롬프트 특성 (Prompt Characteristics)사용 사례 (Use Cases)
build전체 (full)"당신은 빌드 에이전트입니다. 구현에 집중하세요..."코딩, 파일 수정
...

에이전트 프롬프트가 주입되는 방식

에이전트 정의의 prompt 필드는 쿼리 루프(Query loop)가 시작될 때 시스템 프롬프트(System prompt)의 맨 앞부분에 주입됩니다:

// boxagnts-query/src/query.rs
if let Some(ref agent) = config.agent_definition {
    if let Some(ref agent_prompt) = agent.prompt {
...

또한, 에이전트는 모델(Model)과 최대 턴 수(Max turns)를 재정의(Override)할 수 있습니다:

let effective_model = if let Some(ref agent) = config.agent_definition {
    agent.model.clone().unwrap_or_else(|| config.model.clone())
} else {
...

이는 사용자가 에이전트 정의를 사용하여 "동일한 세션의 서로 다른 단계에서 서로 다른 모델과 역할을 구현"할 수 있음을 의미합니다. 예를 들어, 계획 단계(Planning phase)에서는 읽기 전용의 느리게 생각하는 모델(Slow-thinking model)을 사용하고, 실행 단계(Execution phase)에서는 모든 권한을 가진 빠른 모델(Fast model)을 사용하는 식입니다.

run_query_loop: 에이전트의 핵심

run_query_loop()boxagnts-query 크레이트(Crate)에 위치한 BoxAgnts의 가장 핵심적인 함수입니다:

pub async fn run_query_loop(
    client: &AnthropicClient,        // API 클라이언트
    messages: &mut Vec<Message>,     // 대화 기록 (가변 참조)
...

이 함수 시그니처(Signature) 자체가 하나의 설계 문서 역할을 합니다. 각 매개변수는 설계상의 결정 사항을 담고 있습니다:

매개변수설계 의도
client단일 진입점이지만, 내부적으로 ProviderRegistry를 통해 20개 이상의 모델을 전환함
...

메인 루프의 5단계 리듬 (The Five-Step Rhythm of the Main Loop)

┌─────────────────────────────────────────────┐
│                  loop {                       │
│                                               │
...

시스템 프롬프트 구성: 에이전트의 "세계관" (System Prompt Construction: The Agent's "Worldview")

각 API 호출 전에, BoxAgnts는 완전한 시스템 프롬프트 (System Prompt)를 구축합니다:

fn build_system_prompt(config: &QueryConfig) -> SystemPrompt {
    let opts = SystemPromptOptions {
        custom_system_prompt: config.system_prompt.clone(),     // 사용자 정의
...

시스템 프롬프트 구조는 계층적입니다:

┌──────────────────────────────────────┐
│ 에이전트 역할 정의 (build/plan/explore) │  ← AgentDefinition.prompt
├──────────────────────────────────────┤
...

--- Above cached, below not cached --- 구분자는 영리한 설계입니다. Anthropic API는 프롬프트 캐싱 (Prompt Caching)을 지원하며, 위쪽 부분을 캐싱함으로써 API 호출당 토큰 비용을 크게 절감할 수 있습니다.

max_tokens 복구: 에이전트의 "중단점부터 재개" (max_tokens Recovery: The Agent's "Resume from Breakpoint")

AI의 응답이 max_tokens 제한에 도달하면, 모델은 출력 중간에 끊기게 됩니다. 일반적인 API 호출은 여기서 종료되지만, 에이전트는 멈출 수 없습니다.

BoxAgnts의 해결책은 영리합니다:

// boxagnts-query/src/query.rs
const MAX_TOKENS_RECOVERY_LIMIT: u32 = 3;

...

stop_reason == "max_tokens"가 감지되었을 때:

  1. 부분적인 응답을 대화의 어시스턴트 메시지 (Assistant Message)로 추가합니다.
  2. 특수한 사용자 메시지 (MAX_TOKENS_RECOVERY_MSG)를 덧붙입니다.
  3. 루프를 계속 진행합니다. 그러면 모델은 끊긴 지점부터 생성을 계속하게 됩니다.

프롬프트의 세부 사항인 "사과하지 말 것, 요약하지 말 것(no apology, no recap)"은 주목할 가치가 있습니다. 왜냐하면 LLM이 중단된 후 보이는 본능적인 반응은 "죄송합니다, 대화가 중단되었습니다. 다시 시작하겠습니다..."이기 때문입니다. 이는 무익한 출력을 초래합니다. 이 프롬프트는 그러한 패턴을 직접적으로 금지합니다.

auto_compact: 컨텍스트가 너무 길어질 때

LLM의 컨텍스트 창(Context Window)은 유한합니다. 대화가 길어지고 도구 결과가 쌓임에 따라, 더 이상 내용이 들어가지 않는 시점이 찾아옵니다.

BoxAgnts의 대응책은 자동 압축(Automatic Compaction)입니다. 트리거 조건은 토큰 추정치가 컨텍스트 창의 90%에 도달했을 때입니다:

// boxagnts-query/src/compact.rs
const AUTOCOMPACT_TRIGGER_FRACTION: f64 = 0.90;
const WARNING_PCT: f64 = 0.80;   // 80%에서 경고
...

핵심 압축 전략은 다른 LLM을 호출하여 대화 기록을 "요약(Summarize)"하는 것입니다:

Original conversation (potentially thousands of messages)
      │
      ▼
...

압축 프롬프트에는 핵심적인 설계인 NO_TOOLS_PREAMBLE이 포함되어 있습니다:

CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.
- Do NOT use Read, Bash, Grep, Glob, Edit, Write, or ANY other tool.
- You already have all the context you need in the conversation above.
...

만약 압축을 수행하는 LLM이 도구를 호출하려고 시도하면, 압축 작업 전체가 낭비됩니다. 이 서문(Preamble)은 그러한 메타 재귀(Meta-recursion)를 방지합니다.

도구 실행: AI의 결정에서 실행 결과까지

LLM이 stop_reason == "tool_use"를 반환하면, 대화는 도구 실행 단계로 진입합니다:

┌──────────────────────────────────────────────┐
│  Phase 1: Sequential PreToolUse preprocessing │
│  (Each tool block processed sequentially,     │
...

핵심 설계 포인트는 도구 결과가 사용자 메시지(User Message) 형식으로 주입된다는 점입니다. 이는 LLM의 메시지 역할 의미론(Message Role Semantics)을 활용합니다. 즉, 어시스턴트(Assistant)가 도구 호출을 시작했고, 사용자(User, 즉 사용자를 대신하여 동작하는 시스템)가 도구 결과를 반환한 것입니다. 모델은 이를 "사용자가 당신의 요청에 응답했다"라고 이해하며 자연스럽게 다음 추론 단계로 진행합니다.

execute_tool: 도구 호출 (Tool Dispatch)의 핵심

// boxagnts-query/src/lib.rs
async fn execute_tool(
    name: &str,
...

매우 단순한 구현 방식인 선형 탐색 (Linear Search)을 사용합니다. tools 벡터는 보통 십여 개의 요소만 포함하므로, 선형 탐색의 오버헤드는 무시할 수 있는 수준입니다. 단순함은 복잡함보다 더 신뢰할 수 있습니다.

관리형 에이전트 모드 (Managed Agent Mode): 매니저-실행자 (Manager-Executor) 아키텍처

작업의 복잡도가 단일 에이전트 (Agent)의 역량을 초과할 때, BoxAgnts는 관리형 에이전트 (Managed Agent) 모드를 제공합니다:

                    ┌──────────────────┐
                    │  Manager Agent   │
                    │  (Strong model    │
...

매니저 (Manager)의 시스템 프롬프트 (System Prompt)에는 관리형 모드 지침이 주입됩니다:

pub fn managed_agent_system_prompt(config: &ManagedAgentConfig) -> String {
    format!(r#"
## Managed Agent Mode
...

매니저는 도구를 직접 실행하지 않습니다. 오직 계획을 세우고, 할당하며, 결과를 종합(Synthesize)할 뿐입니다. 실행자 (Executor)는 전체 도구 세트를 갖춘 일반적인 에이전트 인스턴스입니다. 이 패턴은 "사고 (Thinking)"와 "실행 (Execution)"을 분리하며, 두 가지 모두 단일 에이전트의 컨텍스트 비대화 (Context Bloat)를 방지하고 진정한 병렬 처리 (Parallel Processing)를 가능하게 합니다.

기술 시스템 (Skill System): 에이전트에게 "전문 기술" 가르치기

도구 (Tools)가 파일을 읽고, 쓰고, 명령을 실행하는 에이전트의 "손"이라면, 기술 (Skills)은 코드 리뷰 방법론, CSS 리팩토링 가이드라인, 프론트엔드 컴포넌트 템플릿과 같은 에이전트의 "전문 지식"입니다.

기술 파일 형식 (Skill File Format)

기술 (Skill)은 단순히 SKILL.md 파일입니다:

app/extensions/skills/
├── code-review/SKILL.md
├── css-refactor-advisor/SKILL.md
...

SkillTool 구현

pub struct SkillTool;

#[async_trait]
...

이중 계층 기술 검색 경로 (Dual-Layer Skill Search Paths)

기술 검색은 워크스페이스 (Workspace) 디렉토리를 우선적으로 탐색한 다음, 앱 확장 (App Extensions) 디렉토리를 탐색합니다:

async fn skill_search_dirs(ctx: &ToolContext) -> Vec<PathBuf> {
    let mut dirs = vec![
        ctx.get_workspace_extensions_dir().await.join("skills")  // Project-level
...

This means you can define project-specific Skills under your project directory (e.g., "Understand this project's build system") while also using global Skills (e.g., "Universal code review standards"). Project-level Skills take priority over global Skills.

$ARGUMENTS Placeholder

The most critical mechanism in Skill templates is $ARGUMENTS:

# Code Review Skill Template

Please review: $ARGUMENTS
...

When the AI calls with args: "src/main.rs", $ARGUMENTS is replaced with src/main.rs. This turns Skills from "static knowledge" into "parameterized tools."

Streaming Push: Letting Users See the Agent "Think"

The entire query loop pushes status in real-time through the event_tx channel:

pub enum QueryEvent {
    Token { text: String },                    // Per-token push
    ToolStart { tool_name, tool_id, input },   // Tool start
...

These events are pushed to the Dashboard frontend in real-time via WebSocket, allowing users to see every decision the Agent makes — not facing a black box.

Summary

An AI Agent's multi-turn conversation is a complex control system:

System Prompt → API Call → Stream Parse → Tool Detection → Tool Execution → Result Injection → Call Again
     ↑                                                                         │
     └───────────────── Loop until end_turn ───────────────────────────────────┘

The robustness of this loop depends on:

MechanismProblem Solved
Agent definition systemMulti-role, multi-model switching
...

Related Resources

AI 자동 생성 콘텐츠

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

원문 바로가기
2

댓글

0