OpenClaw Agent Loop 机制源码深度分析
基于源码的全面解析,帮助你深入理解 OpenClaw 的 Agent 循环执行机制
目录
概述
OpenClaw 的 Agent Loop(代理循环) 是系统的核心执行引擎,负责接收消息、构建上下文、调用 LLM、执行工具、处理响应,形成一个完整的对话循环。
核心特性
支持功能
流式响应
上下文窗口管理
工具策略控制
错误恢复
Agent Loop
是
否
接收消息
构建上下文
调用 LLM
有工具调用?
执行工具
返回结果
压缩上下文
循环流程
有
无
是
否
开始
接收消息
构建系统提示词
加载会话历史
调用 LLM
工具调用?
执行工具
生成回复
压缩会话
继续?
结束
架构设计
模块结构
src/agents/pi-embedded-runner/
├── run.ts # 主运行入口
├── run/
│ ├── params.ts # 运行参数
│ ├── attempt.ts # 单次执行尝试
│ ├── payloads.ts # 载荷构建
│ └── images.ts # 图片处理
├── compact.ts # 会话压缩
├── runs.ts # 运行状态管理
├── history.ts # 历史管理
├── lanes.ts # 执行队列通道
├── system-prompt.ts # 系统提示词构建
├── tool-split.ts # 工具拆分
├── tool-result-truncation.ts # 工具结果截断
├── types.ts # 类型定义
└── utils.ts # 工具函数
核心类型定义
typescript
// types.ts
export type EmbeddedPiRunResult = {
success: boolean;
reply?: string;
usage?: Usage;
error?: string;
};
export type EmbeddedPiAgentMeta = {
runId: string;
sessionId: string;
provider: string;
modelId: string;
thinkLevel: ThinkLevel;
};
// 运行状态
export type EmbeddedPiRunStatus =
| { status: "idle" }
| { status: "streaming" }
| { status: "compacting" }
| { status: "completed" }
| { status: "error"; error: string };
核心组件
运行器入口
文件 : run.ts
主入口函数,处理整个运行生命周期。
typescript
export async function runEmbeddedPiAgent(
params: RunEmbeddedPiAgentParams,
): Promise<EmbeddedPiRunResult> {
const sessionLane = resolveSessionLane(params.sessionKey || params.sessionId);
return enqueueSession(() =>
enqueueGlobal(async () => {
// 1. 准备工作区
const workspaceResolution = resolveRunWorkspaceDir({...});
const resolvedWorkspace = workspaceResolution.workspaceDir;
// 2. 解析模型配置
const { model, error, authStorage } = resolveModel(
provider, modelId, agentDir, params.config
);
if (!model) {
throw new Error(error ?? `Unknown model: ${provider}/${modelId}`);
}
// 3. 检查上下文窗口
const ctxInfo = resolveContextWindowInfo({...});
const ctxGuard = evaluateContextWindowGuard({...});
// 4. 执行循环
const result = await runEmbeddedAttempt({
...params,
model,
authStorage,
workspaceDir: resolvedWorkspace,
sessionId: redactedSessionId,
});
return result;
})
);
}
参数定义:
typescript
type RunEmbeddedPiAgentParams = {
message: string; // 用户消息
sessionId: string; // 会话 ID
sessionKey?: string; // 会话 Key
agentId?: string; // Agent ID
provider?: string; // 模型提供商
model?: string; // 模型名称
workspaceDir?: string; // 工作区目录
config?: OpenClawConfig; // 配置
messageChannel?: string; // 消息通道
messageProvider?: string; // 消息提供商
// ... 更多参数
};
执行尝试
文件 : run/attempt.ts
单个执行尝试,包含完整的 LLM 调用和工具执行循环。
typescript
export async function runEmbeddedAttempt(
params: EmbeddedRunAttemptParams,
): Promise<EmbeddedRunAttemptResult> {
const workspace = resolveUserPath(params.workspaceDir);
// 1. 解析沙箱配置
const sandbox = await resolveSandboxContext({
config: params.config,
sessionKey: params.sessionKey || params.sessionId,
workspaceDir: workspace,
});
// 2. 加载 Skills
const skillEntries = loadWorkspaceSkillEntries(workspace);
const skillsPrompt = resolveSkillsPromptForRun({...});
// 3. 构建系统提示词
const { systemPrompt, snapshot } = buildEmbeddedSystemPrompt({...});
// 4. 准备会话管理器
const sessionManager = await prepareSessionManagerForRun({
sessionId: params.sessionId,
sessionKey: params.sessionKey,
systemPrompt,
workspaceDir: workspace,
config: params.config,
});
// 5. 构建工具定义
const tools = await toClientToolDefinitions({
config: params.config,
sessionManager,
sandbox,
});
// 6. 注册运行状态
const handle = registerRun({
sessionId: params.sessionId,
sessionManager,
});
try {
// 7. 发送用户消息
await sessionManager.appendUserMessage(params.message);
// 8. 执行主循环
while (true) {
// 调用 LLM
const response = await sessionManager.complete({
model: params.modelId,
tools,
thinking: params.thinkLevel,
});
// 检查是否有工具调用
if (response.tool_calls?.length > 0) {
// 执行工具
for (const toolCall of response.tool_calls) {
const result = await executeTool(toolCall);
await sessionManager.appendToolResult(toolCall.id, toolCall.name, result);
}
continue; // 继续循环
}
// 没有工具调用,返回结果
return {
success: true,
reply: response.content,
usage: response.usage,
};
}
} finally {
unregisterRun(params.sessionId);
}
}