에이전트 루프
Revka가 에이전트 턴을 실행하는 방식: 툴 반복 횟수, 병렬 툴 실행, 컨텍스트 압축, 히스토리 관리.
채널, 대시보드 채팅, /webhook 엔드포인트, 크론 잡, 또는 revka agent를 통해 Revka가 처리하는 모든 메시지는 동일한 툴 사용 에이전트 루프를 거칩니다. LLM이 추론하고, 툴 호출을 발행하고, 결과를 읽고, 다시 추론하며, 작업이 완료되거나 제한에 도달할 때까지 이 과정을 반복합니다. 이 페이지에서는 해당 루프의 경계와 조정 방식을 설명합니다. 반복 가능한 최대 횟수, 툴이 병렬로 실행되는 조건, Revka가 컨텍스트 윈도우 초과를 방지하는 방법, 그리고 시간이 지남에 따라 대화 히스토리를 정리하는 방식을 다룹니다.
에이전트 동작을 조정해야 할 때 이 페이지를 참고하세요. 장시간 실행 작업 확장, 멀티 툴 턴 속도 향상, 대용량 툴 출력의 토큰 비용 절감, 또는 소규모 컨텍스트 로컬 모델 실행 등이 해당됩니다. 아래의 모든 설정 키는 ~/.revka/config.toml의 [agent] 섹션에 있습니다. 전반적인 아키텍처는 Revka 동작 원리를, 각 툴 호출에 적용되는 정책 검사는 자율성 수준 및 승인을 참고하세요.
턴 실행 방식
섹션 제목: “턴 실행 방식”-
수신(Ingress). 메시지가 채널, WebSocket(
/ws/chat), SSE, 웹훅, 또는 CLI를 통해 루프로 진입합니다. -
추론 및 툴 호출. LLM이 추론을 수행하고 0개 이상의 툴 호출을 생성합니다. 각 툴 호출은 실행 전에 보안 정책을 통해 검사됩니다.
-
실행(Execute). 독립적인 툴 호출이 실행됩니다.
parallel_tools = true이고 승인 게이팅이 필요한 호출이 없을 경우 동시에 실행됩니다. 결과는 완료 순서와 관계없이 안정적인 순서로 반환됩니다. -
반복(Iterate). 툴 결과가 프롬프트로 다시 전달되고 LLM이 재추론합니다. 각 사이클은 하나의 *툴 반복(tool iteration)*으로 계산됩니다.
-
종료(Stop). 루프는 LLM이 툴 호출 없이 최종 답변을 반환하거나,
max_tool_iterations에 도달했을 때 종료됩니다. 응답은 요청이 들어온 인터페이스로 스트리밍됩니다.
반복 사이에 Revka는 컨텍스트 윈도우를 투명하게 관리합니다. 툴 스키마를 압축하고, 과도하게 큰 툴 결과를 트리밍하며, 누적 토큰 수가 임계값을 초과하면 이전 히스토리를 압축합니다. 이 모든 과정은 에이전트나 사용자의 개입 없이 자동으로 이루어지며, 기본값은 1M 토큰 컨텍스트 모델에 맞게 조정되어 있습니다.
오케스트레이션 설정 ([agent])
섹션 제목: “오케스트레이션 설정 ([agent])”핵심 루프 설정입니다. 모든 키는 선택 사항이며, 지정하지 않으면 표시된 기본값으로 동작합니다.
[agent]max_tool_iterations = 60parallel_tools = truemax_context_tokens = 1050000max_history_messages = 1000keep_tool_context_turns = 2max_tool_result_chars = 50000context_window_safety_ratio = 0.95| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
max_tool_iterations | int | 60 | CLI, 게이트웨이, 채널 전반에서 사용자 메시지당 최대 툴 호출 루프 횟수. 0은 60으로 대체됩니다. |
parallel_tools | bool | true | 하나의 반복 내에서 독립적인 툴 호출을 동시에 실행합니다. |
max_context_tokens | int | 1050000 | 루프 수준의 컨텍스트 트리밍 및 압축에 사용되는 토큰 예산. |
max_history_messages | int | 1000 | 세션당 보존되는 최대 대화 히스토리 메시지 수. |
keep_tool_context_turns | int | 2 | 채널 히스토리에서 전체 툴 호출/결과 메시지를 보존하는 최근 턴 수. |
max_tool_result_chars | int | 50000 | 중간 트리밍 전 단일 툴 결과에 보존되는 최대 문자 수. |
context_window_safety_ratio | float | 0.95 | Revka가 오류를 발생시키기 전까지 허용되는 모델 컨텍스트 윈도우의 비율. 최대 1.0으로 제한되며, <= 0이면 0.95로 대체됩니다. |
tool_call_dedup_exempt | [string] | [] | 한 턴 내에서 동일한 인자로 반복 호출이 허용되는 툴 이름 목록. 중복 호출 억제를 우회합니다. |
compact_context | bool | true | 압축된 부트스트랩 프롬프트를 사용합니다(더 작은 RAG 및 부트스트랩 예산). 13B 이하 소규모 모델을 위한 옵션입니다. |
툴 반복 횟수
섹션 제목: “툴 반복 횟수”max_tool_iterations는 단일 메시지가 수행할 수 있는 추론-툴호출 사이클의 최대 횟수를 제한합니다. 단순 Q&A는 하나의 반복만 사용할 수도 있으며, 파일을 읽고 빌드를 실행하고 결과를 보고하는 다단계 작업은 여러 반복을 사용합니다. 채널 메시지에서 한도를 초과하면 런타임이 다음을 반환합니다:
Agent exceeded maximum tool iterations (60)깊이 있는 자율 작업에서는 값을 높이고, 신뢰할 수 없는 입력에서 빠르게 실패하고 비용을 제한하려면 낮추세요. 채널 메시지 타임아웃 예산은 이 값에 비례하여 조정됩니다. 구체적으로는 message_timeout_secs * min(max_tool_iterations, message_timeout_scale_max)이므로, 반복 한도를 높이면 실제 실행 시간도 늘어납니다([pacing] message_timeout_scale_max 한도까지, 기본값 4).
병렬 툴
섹션 제목: “병렬 툴”parallel_tools = true(기본값)로 설정하면, Revka는 하나의 반복 내에서 독립적인 툴 호출을 순차적으로 처리하는 대신 동시에 실행합니다. 예를 들어, 세 파일을 한꺼번에 읽거나 두 URL을 병렬로 가져올 수 있습니다. 결과는 원래 순서로 재조합되므로 LLM은 안정적이고 결정론적인 결과 목록을 확인합니다.
승인 게이팅이 필요한 호출은 병렬 처리되지 않으며, 일반적인 감독 승인 경로를 통해 실행됩니다. parallel_tools = false로 설정하면 엄격하게 순차 실행이 강제되며, 툴이 취약한 외부 상태를 공유하는 경우에 간혹 유용합니다.
컨텍스트 압축
섹션 제목: “컨텍스트 압축”Revka는 결정론적이고 LLM 호출이 없는 압축 레이어와 이전 히스토리에 대한 선택적 요약 단계를 조합하여 프롬프트를 모델의 컨텍스트 윈도우 안에 유지합니다. [agent.context_compression] 아래에서 설정합니다.
[agent.context_compression]enabled = truethreshold_ratio = 0.5protect_first_n = 3protect_last_n = 4max_passes = 3compact_tool_schemas = trueterse_internal_outputs = true| 키 | 기본값 | 설명 |
|---|---|---|
enabled | true | 자동 컨텍스트 압축을 활성화합니다. |
threshold_ratio | 0.5 | 압축 패스를 트리거하는 컨텍스트 윈도우 비율. |
protect_first_n | 3 | 히스토리 시작 부분에서 보호되는 메시지 수(작업 프레이밍). |
protect_last_n | 4 | 압축에서 보호되는 최근 메시지 수. |
max_passes | 3 | 오류 발생 전 최대 압축 패스 횟수. |
summary_max_chars | 4000 | 저장된 압축 요약에 보존되는 최대 문자 수. |
source_max_chars | 50000 | 요약기에 전달되는 트랜스크립트 텍스트의 안전 상한값. |
timeout_secs | 60 | 요약 프로바이더 호출의 타임아웃. |
live_tool_result_max_chars | 12000 | 콘텐츠 인식 압축 전 라이브 툴 결과에 보존되는 최대 문자 수. |
tool_result_retrim_chars | 2000 | 빠른 트리밍 중 이전 툴 결과에 보존되는 최대 문자 수. |
input_max_chars | 24000 | 콘텐츠 인식 압축 전 단일 대용량 사용자 입력에 보존되는 최대 문자 수. |
compact_tool_schemas | true | 각 LLM 호출 전 네이티브 툴 설명과 JSON 스키마 메타데이터를 단축합니다. |
compact_system_tool_docs | true | 스키마가 별도로 전송될 때 시스템 프롬프트에 압축된 툴 문서를 렌더링합니다. |
tool_description_max_chars | 180 | 스키마 압축 후 툴 설명당 최대 문자 수. |
schema_description_max_chars | 120 | 압축 후 JSON 스키마 description당 최대 문자 수. |
terse_internal_outputs | true | 내부 오퍼레이터/에이전트 핸드오프에 간결한 출력 계약을 사용합니다. |
tool_result_trim_exempt | [string] | [] — 툴 결과 트리밍에서 제외되는 툴 이름 목록. |
네 가지 콘텐츠 인식 축
섹션 제목: “네 가지 콘텐츠 인식 축”콘텐츠 인식 레이어는 결정론적으로 동작하며, LLM 호출이나 토큰 비용이 발생하지 않습니다. 토큰 소모가 많은 네 가지 축에 유형별 축소를 적용합니다:
| 축 | 출처 | 축소 결과 |
|---|---|---|
| 대용량 붙여넣기 입력 | 큰 사용자 메시지 | 구조화된 데이터의 경우 스키마 및 샘플로, 그 외에는 제한된 텍스트로 |
| CLI / 셸 출력 | shell 및 명령 툴 결과 | 실패 라인과 출력 끝부분 |
| 일반 툴 출력 | 대용량 툴 결과(JSON, diff 등) | JSON → 스키마 + 샘플; diff → 파일/헝크/변경 요약 |
| 코드 검색 출력 | content_search, semantic_code_search | 파일별 그룹화된 히트 결과 |
시맨틱 코드 검색의 경우, semantic_code_search는 Semble이 설치되어 있으면 이를 사용하고, 없으면 제한된 로컬 ripgrep으로 대체하며, 마지막으로 내장 리터럴 스캔으로 폴백합니다. 따라서 아무것도 설치되지 않은 환경에서도 코드 검색을 사용할 수 있습니다. 전체 툴 카탈로그는 툴 개요를 참고하세요.
스키마 및 핸드오프 압축
섹션 제목: “스키마 및 핸드오프 압축”두 가지 추가 축소 기법으로 모든 호출에서 공통으로 사용되는 기본 컨텍스트를 줄입니다:
- 툴 스키마 압축 (
compact_tool_schemas)은 각 프로바이더 호출 전에 네이티브 툴 설명과 JSON 스키마 메타데이터를 트리밍하며, 프로바이더의 툴 인터페이스를 통해 이미 제공된 파라미터 스키마는 시스템 프롬프트에서 생략됩니다. - 간결한 내부 출력 (
terse_internal_outputs)은 오퍼레이터 및 서브에이전트 프롬프트에 간결한 핸드오프 계약을 적용합니다. Python 오퍼레이터 측을 비활성화하려면REVKA_TERSE_INTERNAL_OUTPUTS=0으로 설정하세요.
압축 예산에 대한 기타 환경 변수 재정의:
REVKA_AGENT_RESULT_MAX_CHARS(오퍼레이터 측 에이전트 last_message 예산),
REVKA_WORKFLOW_SKILL_MAX_CHARS, REVKA_WORKFLOW_SKILL_CONTEXT_MODE
(pointer로 설정하면 kref/경로만 전송, full로 설정하면 레거시 전체 인라인 스킬 컨텍스트로 복원).
히스토리 정리(Pruning)
섹션 제목: “히스토리 정리(Pruning)”턴별 압축과는 별개로, [agent.history_pruning]은 메시지 목록 자체에 대한 토큰 효율화 패스입니다. 기본적으로 비활성화되어 있으며, 장기 세션 또는 소규모 컨텍스트 모델에서는 활성화하세요.
[agent.history_pruning]enabled = falsemax_tokens = 8192keep_recent = 4collapse_tool_results = true| 키 | 기본값 | 설명 |
|---|---|---|
enabled | false | 히스토리 정리를 활성화합니다. |
max_tokens | 8192 | 메시지 히스토리의 최대 추정 토큰 수. |
keep_recent | 4 | 그대로 보존할 가장 최근 메시지 수. |
collapse_tool_results | true | 이전 어시스턴트 툴 호출/결과 쌍을 짧은 요약으로 접습니다. |
시스템 메시지와 keep_recent 개의 최근 메시지는 항상 보호됩니다. 활성화되면 정리는 먼저 이전 툴 호출/결과 쌍을 축약한 다음, 추정 토큰 합계가 max_tokens 이하가 될 때까지 이전 메시지를 삭제합니다.
최상위 [agent] 테이블의 keep_tool_context_turns(기본값 2)는 채널 히스토리에서 전체 툴 호출 및 툴 결과 메시지를 보존하는 최근 턴 수를 제어합니다. 이보다 오래된 턴은 대화 텍스트는 유지하되 상세한 툴 페이로드는 제거됩니다.
툴 필터링 (tool_filter_groups)
섹션 제목: “툴 필터링 (tool_filter_groups)”많은 외부 MCP 서버를 연결하면 매 턴마다 모든 툴 스키마를 전송하는 것은 비용이 큽니다. tool_filter_groups는 턴별로 LLM에 전송되는 MCP 툴 스키마를 제한합니다. 내장(비 MCP) 툴은 항상 그대로 전달되며, 목록이 비어 있으면 기능이 비활성화되어 모든 툴이 통과합니다(하위 호환 기본값).
각 그룹은 다음 테이블 형태입니다:
| 필드 | 타입 | 용도 |
|---|---|---|
mode | "always" | "dynamic" | always: 무조건 툴을 포함합니다. dynamic: 마지막 사용자 메시지에 키워드가 포함될 때만 포함합니다. |
tools | [string] | 툴 이름 패턴. 단일 * 와일드카드 지원(접두사, 접미사, 인픽스), 예: "mcp_vikunja_*". |
keywords | [string] | dynamic 모드 전용. 마지막 사용자 메시지와 대소문자 구분 없이 매칭되는 서브스트링. |
[agent]# Vikunja task-management MCP tools are always available.[[agent.tool_filter_groups]]mode = "always"tools = ["mcp_vikunja_*"]
# Browser MCP tools are only included when the user mentions browsing.[[agent.tool_filter_groups]]mode = "dynamic"tools = ["mcp_browser_*"]keywords = ["browse", "navigate", "open url", "screenshot"]조정 레시피
섹션 제목: “조정 레시피”| 목표 | 변경 사항 |
|---|---|
| 더 긴 자율 작업 | max_tool_iterations 증가; [pacing] message_timeout_scale_max 증가. |
| 멀티 툴 턴 속도 향상 | parallel_tools = true 유지(기본값). |
| 대용량 출력의 토큰 비용 절감 | max_tool_result_chars 및 live_tool_result_max_chars 감소; tool_filter_groups 활성화. |
| 소규모 컨텍스트 / 로컬 모델 | compact_context = true 설정, [agent.history_pruning] 활성화, [agent.model_context_windows] 설정, [pacing] 조정. |
| 무한 루프 제어 | max_tool_iterations 감소; 긴급 중지 참고. |
느린 로컬 LLM 배포(Ollama, llama.cpp, vLLM)의 경우, 커스텀 프로바이더 및 로컬 LLM에서 설명하는 [pacing] 제어(스텝 타임아웃 및 루프 감지)와 함께 사용하세요.
관련 페이지
섹션 제목: “관련 페이지”- 자율성 수준 및 승인 — 모든 툴 호출에 적용되는 정책 검사.
- 세션 및 대화 상태 — 히스토리의 범위 설정 및 지속 방식.
- 에이전트, 팀 및 스웜 — 루프 상위의 멀티 에이전트 오케스트레이션.
- 설정: 프로바이더, 에이전트 및 라우팅 — 전체
[agent]설정 레퍼런스. - 툴 개요 — 호출 가능한 툴 카탈로그.