Agent 运行机制

📚 学习路径:本文档是架构文档的第 6 部分。建议按顺序阅读:

前言

Agent 是 OpenClaw 的核心处理引擎,负责组装上下文、调用 AI 模型、执行工具操作。本文档将深入解析 Agent 的运行机制、故障转移策略以及核心设计。

通过阅读本文档,你将能够:

  • 理解 Agent Loop 的执行流程
  • 掌握上下文组装和模型调用机制
  • 了解故障转移和容错策略
  • 理解工具调用和流式处理

一、Agent 概述

1.1 Agent 的作用

Agent 是真正干活的核心引擎,负责:

  • 组装上下文:加载会话历史、系统提示词、记忆检索
  • 调用 AI 模型:与 AI 模型交互,获取回复
  • 执行工具:执行命令行、浏览器、文件操作等工具
  • 保存状态:保存会话状态到磁盘

1.2 Agent 框架

OpenClaw 支持调用已有的 CLI Agent(如 Claude Code),但默认情况下使用基于 Pi-Agent 框架的嵌入式 Agent 运行时。

Pi-Agent 框架的优势

特性说明
高扩展性满足 OpenClaw 定制化需求
大模型支持支持多种大模型供应商
Session 管理完善的会话管理机制
工具定制灵活的工具定制化能力
流式输出支持流式响应输出
消息订阅支持事件订阅机制

1.3 Agent 架构

外部系统

支撑系统

🤖 Agent 运行时

上下文组装

模型调用

工具执行

状态保存

并发控制

会话管理

记忆检索

安全沙箱

AI 模型 API

命令行

浏览器

文件系统


二、Agent Loop 执行流程

2.1 执行流程概览

存储 工具执行 AI 模型 上下文组装 Agent Gateway 存储 工具执行 AI 模型 上下文组装 Agent Gateway 分发消息 加载上下文 读取会话历史 检索记忆 完整上下文 调用模型 流式响应 检测工具调用 执行工具 工具结果 继续生成 最终回复 发送回复 保存状态

2.2 详细步骤

步骤 1:消息接收

  • 接收来自 Gateway 的消息
  • 解析消息内容和元数据
  • 确定会话标识(Session Key)

步骤 2:上下文组装

  • 加载会话历史(从 .jsonl 文件)
  • 组装系统提示词(AGENTS.md、SOUL.md 等)
  • 记忆检索(搜索相关历史记忆)
  • 工具注册(准备可用的工具列表)

步骤 3:模型调用

  • 调用 AI 模型获取回复
  • 流式接收响应
  • 实时检测工具调用

步骤 4:工具执行

  • 如果 AI 需要调用工具,执行工具
  • 返回工具结果给 AI
  • AI 继续生成最终回复

步骤 5:回复发送

  • 将 AI 回复发送回渠道
  • 格式化输出内容
  • 处理流式输出

步骤 6:状态保存

  • 保存会话状态到磁盘
  • 更新记忆索引
  • 记录使用统计

三、上下文组装

3.1 上下文组件

代码位置src/agents/context.ts

export async function buildAgentContext(
  route: RouteDecision,
  config: OpenClawConfig,
): Promise<AgentContext> {
  // 1. 加载会话历史
  const sessionHistory = await loadSessionHistory(route.sessionKey);

  // 2. 组装系统提示词
  const systemPrompt = await buildSystemPrompt(config);

  // 3. 记忆检索
  const memories = await searchMemory(route.sessionKey, route.content);

  // 4. 工具注册
  const tools = await registerTools(config.tools);

  return {
    sessionHistory,
    systemPrompt,
    memories,
    tools,
    // ... 更多上下文信息
  };
}

3.2 会话历史加载

代码位置src/agents/session-loader.ts

export async function loadSessionHistory(
  sessionKey: string,
): Promise<SessionMessage[]> {
  // 1. 确定会话文件路径
  const sessionPath = resolveSessionFilePath(sessionKey);

  // 2. 读取 JSONL 文件
  const lines = await fs.readFile(sessionPath, 'utf-8');

  // 3. 解析每一行
  const messages = lines
    .split('\n')
    .filter(line => line.trim())
    .map(line => JSON.parse(line));

  // 4. 返回消息列表
  return messages;
}

存储格式

~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl

JSONL 格式示例

{"role": "user", "content": "你好", "timestamp": "2024-01-01T12:00:00Z"}
{"role": "assistant", "content": "你好!有什么可以帮助你的?", "timestamp": "2024-01-01T12:00:01Z"}
{"role": "user", "content": "帮我查一下天气", "timestamp": "2024-01-01T12:00:02Z"}

3.3 系统提示词组装

代码位置src/agents/prompt-builder.ts

export async function buildSystemPrompt(
  config: OpenClawConfig,
): Promise<string> {
  const parts: string[] = [];

  // 1. 基础系统提示词
  parts.push(config.systemPrompt || DEFAULT_SYSTEM_PROMPT);

  // 2. AGENTS.md 文件内容
  const agentsContent = await readAgentsFile();
  if (agentsContent) {
    parts.push(agentsContent);
  }

  // 3. SOUL.md 文件内容
  const soulContent = await readSoulFile();
  if (soulContent) {
    parts.push(soulContent);
  }

  // 4. 工具描述
  const toolsDescription = buildToolsDescription(config.tools);
  if (toolsDescription) {
    parts.push(toolsDescription);
  }

  // 5. 合并所有部分
  return parts.join('\n\n');
}

提示词文件位置

  • ~/.openclaw/agents/<agentId>/AGENTS.md - Agent 行为描述
  • ~/.openclaw/agents/<agentId>/SOUL.md - Agent 个性描述

3.4 记忆检索

代码位置src/agents/memory-search.ts

export async function searchMemory(
  sessionKey: string,
  query: string,
): Promise<MemoryResult[]> {
  // 1. 向量搜索
  const vectorResults = await vectorSearch(query);

  // 2. 关键词搜索
  const keywordResults = await keywordSearch(query);

  // 3. 结果融合
  const mergedResults = mergeHybridResults(
    vectorResults,
    keywordResults,
    alpha = 0.7, // 向量搜索权重
  );

  // 4. 返回前 N 个结果
  return mergedResults.slice(0, MAX_MEMORY_RESULTS);
}

混合检索

  • 向量搜索:基于语义相似度
  • 关键词搜索:基于 BM25 算法
  • 结果融合:加权合并两种搜索结果

3.5 工具注册

代码位置src/agents/pi-tools.ts

export async function registerTools(
  config: ToolConfig[],
): Promise<Tool[]> {
  const tools: Tool[] = [];

  // 1. 内置工具
  tools.push(...BUILTIN_TOOLS);

  // 2. 自定义工具
  for (const toolConfig of config) {
    const tool = await loadCustomTool(toolConfig);
    tools.push(tool);
  }

  // 3. 过滤不可用工具
  const availableTools = tools.filter(tool => tool.isAvailable());

  return availableTools;
}

内置工具

  • exec - 命令行执行
  • browser - 浏览器操作
  • file_read - 文件读取
  • file_write - 文件写入
  • memory_search - 记忆搜索

四、模型调用

4.1 流式调用

代码位置src/agents/openai-ws-connection.ts

export async function* streamChatCompletion(
  params: ChatCompletionParams,
): AsyncGenerator<StreamChunk> {
  const stream = await openai.chat.completions.create({
    model: params.model,
    messages: params.messages,
    tools: params.tools,
    stream: true,  // 启用流式
  });

  for await (const chunk of stream) {
    const content = chunk.choices[0]?.delta?.content;
    const toolCall = chunk.choices[0]?.delta?.tool_calls;

    // 实时处理每个 chunk
    if (content) {
      yield { type: 'content', data: content };
    }
    if (toolCall) {
      yield { type: 'tool_call', data: toolCall };
    }
  }
}

4.2 工具调用检测

代码位置src/agents/pi-embedded-runner/attempt.ts

async function* processStream(stream: AsyncIterable<StreamChunk>) {
  const toolCallBuffer: ToolCall[] = [];

  for await (const chunk of stream) {
    if (chunk.type === 'content') {
      // 普通内容,直接转发给用户
      yield { type: 'content', data: chunk.data };
    }
    else if (chunk.type === 'tool_call') {
      // 检测到工具调用,但不阻塞
      toolCallBuffer.push(chunk.data);

      // 异步启动工具执行
      executeToolAsync(chunk.data).then(result => {
        // 工具完成后,通过回调注入结果
        injectToolResult(result);
      });
    }
  }
}

4.3 模型配置

代码位置src/agents/model-resolver.ts

export function resolveModel(
  provider: string,
  modelId: string,
  agentDir: string,
  config: OpenClawConfig,
): ModelInfo {
  // 1. 查找模型配置
  const modelConfig = config.models?.[modelId];

  // 2. 解析上下文窗口
  const contextWindow = modelConfig?.contextWindow || DEFAULT_CONTEXT_WINDOW;

  // 3. 解析支持的特性
  const features = modelConfig?.features || {};

  return {
    id: modelId,
    provider,
    contextWindow,
    features,
    // ... 更多模型信息
  };
}

五、工具执行

5.1 工具执行流程

沙箱 工具执行器 Agent AI 模型 沙箱 工具执行器 Agent AI 模型 function_call: exec 解析工具参数 创建沙箱环境 沙箱就绪 执行工具 运行命令 工具结果 注入结果到上下文 继续生成

5.2 工具执行器

代码位置src/agents/bash-tools.ts

export async function executeTool(
  toolCall: ToolCall,
  sandbox: Sandbox,
): Promise<ToolResult> {
  // 1. 解析工具参数
  const { command, args } = parseToolCall(toolCall);

  // 2. 在沙箱中执行
  const result = await sandbox.exec(command, args);

  // 3. 格式化结果
  return {
    success: result.exitCode === 0,
    output: result.stdout,
    error: result.stderr,
    exitCode: result.exitCode,
  };
}

5.3 沙箱隔离

代码位置src/agents/sandbox.ts

export class Sandbox {
  constructor(private config: SandboxConfig) {
    // 初始化沙箱环境
  }

  async exec(command: string, args: string[]): Promise<ExecResult> {
    // 1. 验证命令安全性
    if (!this.isCommandSafe(command)) {
      throw new Error('Command not allowed');
    }

    // 2. 限制资源使用
    const limits = this.config.limits;
    const options = {
      timeout: limits.timeout,
      maxMemory: limits.maxMemory,
    };

    // 3. 执行命令
    const result = await this.runCommand(command, args, options);

    return result;
  }

  private isCommandSafe(command: string): boolean {
    // 检查命令是否在白名单中
    return ALLOWED_COMMANDS.includes(command);
  }
}

沙箱限制

限制类型说明默认值
超时命令执行超时时间30 秒
内存最大内存使用512 MB
CPUCPU 使用限制50%
网络网络访问限制禁止(主会话除外)

六、故障转移机制

6.1 故障转移策略

为了能 24×7 持续运行,不能因为一些异常就停止。OpenClaw 实现了完整的故障转移机制:

开始执行

API Key 有效?

切换到下一个 Key

执行 AI 调用

上下文溢出?

压缩历史消息

思考级别不支持?

降级到基本模式

成功返回

6.2 Auth Profile 轮换

当一个 API Key 遇到速率限制或认证失败时,自动切换到下一个可用的 Profile。

代码位置src/agents/pi-embedded-runner/run.ts

const profileOrder = resolveAuthProfileOrder({
  cfg: params.config,
  store: authStore,
  provider,
  preferredProfile: preferredProfileId,
});

// 主执行循环,支持故障转移
while (true) {
  const attempt = await runEmbeddedAttempt({
    sessionId: params.sessionId,
    sessionKey: params.sessionKey,
    // ... 大量参数
  });

  // 处理认证/速率限制故障转移
  if (shouldRotate) {
    const rotated = await advanceAuthProfile();
    if (rotated) continue;
  }

  return {
    payloads: payloads.length ? payloads : undefined,
    meta: {
      durationMs: Date.now() - started,
      agentMeta,
      aborted,
      systemPromptReport: attempt.systemPromptReport,
    },
  };
}

6.3 上下文溢出自动压缩

当会话过长时,自动压缩历史消息。

if (isContextOverflowError(errorText)) {
  if (!overflowCompactionAttempted) {
    const compactResult = await compactEmbeddedPiSessionDirect({
      sessionId: params.sessionId,
      sessionKey: params.sessionKey,
      // ...
    });
    if (compactResult.compacted) {
      continue; // 使用压缩后的会话重试
    }
  }
}

6.4 思考级别降级

当模型不支持扩展思考模式时,自动降级到基本模式。

代码位置src/agents/pi-embedded-runner/run.ts

const { model, error, authStorage, modelRegistry } = resolveModel(
  provider,
  modelId,
  agentDir,
  params.config,
);

const ctxInfo = resolveContextWindowInfo({
  cfg: params.config,
  provider,
  modelId,
  modelContextWindow: model.contextWindow,
  defaultTokens: DEFAULT_CONTEXT_TOKENS,
});

七、核心代码文件索引

文件路径功能重要性
src/agents/pi-tools.ts工具定义和创建⭐⭐⭐⭐⭐
src/agents/context.ts上下文管理⭐⭐⭐⭐⭐
src/agents/pi-embedded-runner/run.tsAgent 运行器⭐⭐⭐⭐⭐
src/agents/session-loader.ts会话加载⭐⭐⭐⭐
src/agents/prompt-builder.ts提示词构建⭐⭐⭐⭐
src/agents/memory-search.ts记忆检索⭐⭐⭐⭐
src/agents/openai-ws-connection.tsOpenAI 连接⭐⭐⭐⭐
src/agents/model-resolver.ts模型解析⭐⭐⭐⭐
src/agents/bash-tools.tsBash 工具⭐⭐⭐
src/agents/sandbox.ts沙箱隔离⭐⭐⭐

八、下一步

恭喜你完成了 Agent 运行机制的学习!接下来建议:


通过理解 Agent 的工作原理,你已经掌握了 OpenClaw 的核心处理引擎!

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐