에이전트 루프 (OpenClaw)
에이전트 루프란 에이전트가 실제로 실행되는 전체 과정을 말합니다. 입력 수신 -> 컨텍스트 조립 -> 모델 추론 -> 도구 실행 -> 스트리밍 응답 -> 영속화까지, 메시지를 행동과 최종 응답으로 변환하면서 세션 상태를 일관되게 유지하는 핵심 경로입니다.
OpenClaw에서 루프는 세션당 하나의 직렬 실행 단위로, 모델이 사고하고 도구를 호출하고 출력을 스트리밍하는 동안 생명주기 이벤트와 스트림 이벤트를 발생시킵니다. 이 문서에서는 이 루프가 처음부터 끝까지 어떻게 연결되는지 설명합니다.
진입점
- Gateway RPC:
agent및agent.wait. - CLI:
agent명령어.
동작 원리 (개괄)
agentRPC가 파라미터를 검증하고, 세션을 확인(sessionKey/sessionId)한 뒤, 세션 메타데이터를 저장하고 즉시{ runId, acceptedAt }을 반환합니다.agentCommand가 에이전트를 실행합니다:- 모델 및 thinking/verbose 기본값 확인
- 스킬 스냅샷 로드
runEmbeddedPiAgent(pi-agent-core 런타임) 호출- 임베디드 루프가 생명주기 이벤트를 발생시키지 않을 경우 lifecycle end/error를 직접 발생
runEmbeddedPiAgent:- 세션별 + 글로벌 큐를 통해 실행을 직렬화
- 모델 + 인증 프로필을 확인하고 pi 세션 구성
- pi 이벤트를 구독하여 assistant/tool 델타를 스트리밍
- 타임아웃 초과 시 실행 중단
- 페이로드 + 사용량 메타데이터 반환
subscribeEmbeddedPiSession이 pi-agent-core 이벤트를 OpenClawagent스트림에 연결합니다:- tool 이벤트 =>
stream: "tool" - assistant 델타 =>
stream: "assistant" - 생명주기 이벤트 =>
stream: "lifecycle"(phase: "start" | "end" | "error")
- tool 이벤트 =>
agent.wait는waitForAgentJob을 사용합니다:- 해당
runId의 lifecycle end/error를 대기 { status: ok|error|timeout, startedAt, endedAt, error? }반환
- 해당
큐잉 + 동시성
- 세션 키(세션 레인) 단위로 실행이 직렬화되며, 선택적으로 글로벌 레인도 거칩니다.
- 이를 통해 도구/세션 경합을 방지하고 세션 히스토리 일관성을 유지합니다.
- 메시징 채널은 이 레인 시스템에 연결되는 큐 모드(collect/steer/followup)를 선택할 수 있습니다. 명령어 큐를 참고하세요.
세션 + 워크스페이스 준비
- 워크스페이스가 확인되고 생성됩니다. 샌드박스 실행은 샌드박스 워크스페이스 루트로 리다이렉트될 수 있습니다.
- 스킬이 로드(또는 스냅샷에서 재사용)되어 환경 변수와 프롬프트에 주입됩니다.
- 부트스트랩/컨텍스트 파일이 확인되어 시스템 프롬프트 리포트에 주입됩니다.
- 세션 쓰기 잠금이 획득됩니다. 스트리밍 전에
SessionManager가 열리고 준비됩니다.
프롬프트 조립 + 시스템 프롬프트
- 시스템 프롬프트는 OpenClaw의 기본 프롬프트, 스킬 프롬프트, 부트스트랩 컨텍스트, 실행별 오버라이드로 구성됩니다.
- 모델별 제한 및 압축 예비 토큰이 적용됩니다.
- 모델에 전달되는 내용은 시스템 프롬프트를 참고하세요.
훅 포인트 (가로챌 수 있는 지점)
OpenClaw에는 두 가지 훅 시스템이 있습니다:
- 내부 훅 (Gateway 훅): 명령어와 생명주기 이벤트를 위한 이벤트 기반 스크립트.
- 플러그인 훅: 에이전트/도구 생명주기와 게이트웨이 파이프라인 내 확장 포인트.
내부 훅 (Gateway 훅)
agent:bootstrap: 시스템 프롬프트 확정 전 부트스트랩 파일을 구성하는 동안 실행됩니다. 부트스트랩 컨텍스트 파일을 추가/제거하는 데 사용합니다.- 명령어 훅:
/new,/reset,/stop등의 명령어 이벤트 (훅 문서 참고).
자세한 설정과 예시는 훅을 참고하세요.
플러그인 훅 (에이전트 + 게이트웨이 생명주기)
에이전트 루프 또는 게이트웨이 파이프라인 내에서 실행됩니다:
before_model_resolve: 세션 이전(messages없이) 실행되어 모델 확인 전에 프로바이더/모델을 결정적으로 오버라이드합니다.before_prompt_build: 세션 로드 후(messages와 함께) 실행되어 프롬프트 제출 전에prependContext,systemPrompt,prependSystemContext,appendSystemContext를 주입합니다. 턴별 동적 텍스트에는prependContext를, 시스템 프롬프트 영역에 위치해야 할 안정적 가이드에는 system-context 필드를 사용하세요.before_agent_start: 두 단계 중 하나에서 실행될 수 있는 레거시 호환 훅. 위의 명시적 훅을 사용하는 것을 권장합니다.agent_end: 완료 후 최종 메시지 목록과 실행 메타데이터를 검사합니다.before_compaction/after_compaction: 압축 사이클을 관찰하거나 주석을 달 수 있습니다.before_tool_call/after_tool_call: 도구 파라미터/결과를 가로챕니다.tool_result_persist: 도구 결과가 세션 트랜스크립트에 기록되기 전에 동기적으로 변환합니다.message_received/message_sending/message_sent: 인바운드 + 아웃바운드 메시지 훅.session_start/session_end: 세션 생명주기 경계.gateway_start/gateway_stop: 게이트웨이 생명주기 이벤트.
훅 API와 등록 방법은 플러그인을 참고하세요.
스트리밍 + 부분 응답
- pi-agent-core에서 assistant 델타가 스트리밍되어
assistant이벤트로 발생합니다. - 블록 스트리밍은
text_end또는message_end시점에 부분 응답을 내보낼 수 있습니다. - 추론 스트리밍은 별도 스트림 또는 블록 응답으로 내보낼 수 있습니다.
- 청킹과 블록 응답 동작은 스트리밍을 참고하세요.
도구 실행 + 메시징 도구
- tool start/update/end 이벤트가
tool스트림으로 발생합니다. - 도구 결과는 로깅/발생 전에 크기와 이미지 페이로드가 정리됩니다.
- 메시징 도구 전송은 중복 assistant 확인 메시지를 방지하기 위해 추적됩니다.
응답 형성 + 억제
- 최종 페이로드는 다음으로 구성됩니다:
- assistant 텍스트 (및 선택적 추론)
- 인라인 도구 요약 (verbose + 허용 시)
- 모델 오류 시 assistant 오류 텍스트
NO_REPLY는 무음 토큰으로 처리되어 발신 페이로드에서 필터링됩니다.- 메시징 도구 중복이 최종 페이로드 목록에서 제거됩니다.
- 렌더링 가능한 페이로드가 없고 도구에서 오류가 발생한 경우, 대체 도구 오류 응답이 발생합니다 (메시징 도구가 이미 사용자에게 보이는 응답을 보낸 경우는 제외).
압축 + 재시도
- 자동 압축은
compaction스트림 이벤트를 발생시키며 재시도를 유발할 수 있습니다. - 재시도 시 중복 출력을 방지하기 위해 인메모리 버퍼와 도구 요약이 초기화됩니다.
- 압축 파이프라인은 압축을 참고하세요.
이벤트 스트림 (현재)
lifecycle:subscribeEmbeddedPiSession에 의해 발생 (agentCommand에서 대체 수단으로도 발생)assistant: pi-agent-core에서 스트리밍되는 델타tool: pi-agent-core에서 스트리밍되는 도구 이벤트
채팅 채널 처리
- assistant 델타가 채팅
delta메시지로 버퍼링됩니다. - lifecycle end/error 시 채팅
final이 발생합니다.
타임아웃
agent.wait기본값: 30초 (대기만 해당).timeoutMs파라미터로 오버라이드 가능.- 에이전트 런타임:
agents.defaults.timeoutSeconds기본값 600초.runEmbeddedPiAgent중단 타이머에서 적용.
조기 종료될 수 있는 경우
- 에이전트 타임아웃 (중단)
- AbortSignal (취소)
- 게이트웨이 연결 해제 또는 RPC 타임아웃
agent.wait타임아웃 (대기 전용, 에이전트를 중단하지 않음)