返回

OpenClaw 源码解析(三):Agent——AI 的躯壳与灵魂

深入理解 OpenClaw 的 Agent 运行时,揭示 ACP 协议设计、Turn 执行流程、工具调用机制,以及 AI 如何从模型变成助手。

适用版本: OpenClaw v2026.3 阅读时间: 约 30 分钟 前置知识: 阅读前两篇文章,理解 Gateway 和消息流程 源码位置: src/agents/, src/acp/

开篇:Agent 是什么?

前两篇文章,我们了解了 Gateway 如何协调子系统、消息如何流转。今天,让我们进入最核心的问题:

Agent 是什么?它和 LLM 有什么区别?

LLM(Large Language Model)只是一个文本生成器——给它一段文本,它返回续写的文本。

Agent 则是 LLM 的"躯壳与灵魂":

  • 躯壳——工具、记忆、状态管理、多模态处理
  • 灵魂——规划、推理、自我反思、任务分解

用一个比喻:

LLM = 大脑(只有神经元)
Agent = 机器人(大脑 + 感知 + 行动 + 记忆)

本文将回答核心问题:

OpenClaw 如何让不同的 LLM 表现出一致的 Agent 行为?ACP 协议解决了什么问题?

Agent 架构概览

双模式运行时

OpenClaw 支持两种 Agent 运行模式:

flowchart TB
    subgraph Gateway["Gateway"]
        SM[Session Manager]
        AR[Agent Router]
    end

    subgraph Embedded["Embedded 模式<br/>(Pi Agent)"]
        PC[Pi Core]
        PA[Pi AI]
        PD[Pi Coding]
        MEMORY[(Memory)]
    end

    subgraph ACP["ACP 模式<br/>(独立进程)"]
        ASM[ACP Session Manager]
        BA[Backend Adapters]
        CL[Claude]
        GM[Gemini]
        OAI[OpenAI]
        CUS[Custom]
    end

    subgraph LLM["LLM Providers"]
        OPENAI[OpenAI]
        ANTHROPIC[Anthropic]
        GOOGLE[Google]
    end

    Gateway --> Embedded
    Gateway --> ACP
    Embedded --> LLM
    ACP --> LLM

    style Embedded fill:#e3f2fd
    style ACP fill:#fff3e0
模式 特点 适用场景
Embedded 与 Gateway 同进程,零通信开销 默认模式、高性能需求
ACP 独立进程,通过 RPC 通信 隔离性要求、自定义后端

ACP 协议:统一不同后端

ACP(Agent Communication Protocol)是 OpenClaw 定义的标准接口,让不同的 LLM 后端表现一致。

// src/acp/runtime/types.ts

/**
 * ACP Runtime 的核心接口
 * 任何 Agent 后端都必须实现这个接口
 */
export interface AcpRuntime {
  // 会话管理
  ensureSession(input: AcpRuntimeEnsureInput): Promise<AcpRuntimeHandle>;

  // 核心执行
  runTurn(input: AcpRuntimeTurnInput): AsyncIterable<AcpRuntimeEvent>;

  // 能力查询
  getCapabilities?(input: { handle?: AcpRuntimeHandle }): Promise<AcpRuntimeCapabilities>;

  // 状态查询
  getStatus?(input: { handle: AcpRuntimeHandle }): Promise<AcpRuntimeStatus>;

  // 控制
  setMode?(input: { handle: AcpRuntimeHandle; mode: string }): Promise<void>;
  setConfigOption?(input: { handle: AcpRuntimeHandle; key: string; value: string }): Promise<void>;

  // 中断
  cancel(input: { handle: AcpRuntimeHandle; reason?: string }): Promise<void>;
  close(input: { handle: AcpRuntimeHandle; reason: string }): Promise<void>;

  // 诊断
  doctor?(): Promise<AcpRuntimeDoctorReport>;
}

设计意图: 无论底层是 Claude、GPT-4、Gemini 还是自定义模型,上层代码只看到 runTurn() 返回的事件流。

Turn 执行:一次对话的完整生命周期

什么是 Turn?

Turn 是 Agent 执行的基本单位——一个"回合":

用户发送消息 → Agent 处理 → Agent 回复

一次 Turn 可能包含:

  • 多次 LLM 调用(如果需要工具调用)
  • 多个流式事件
  • 工具执行结果

Turn 执行流程

sequenceDiagram
    autonumber
    participant User as 用户
    participant Agent as Agent Runtime
    participant LLM as LLM Provider
    participant Tools as Tool Executor

    User->>Agent: runTurn(message)

    Note over Agent: 1. 构建提示词
    Agent->>Agent: buildPrompt(message, transcript)

    Note over Agent: 2. 调用 LLM
    Agent->>LLM: streamCompletion(prompt)

    loop 流式输出
        LLM-->>Agent: text_delta
        Agent-->>User: event: text_delta
    end

    alt 需要工具调用
        LLM-->>Agent: tool_call
        Agent-->>User: event: tool_call

        Note over Tools: 3. 执行工具
        Agent->>Tools: execute(tool_name, params)
        Tools-->>Agent: result
        Agent-->>User: event: tool_result

        Note over Agent: 4. 继续生成
        Agent->>LLM: continue(tool_result)

        loop 流式输出
            LLM-->>Agent: text_delta
            Agent-->>User: event: text_delta
        end
    end

    Note over Agent: 5. 完成
    LLM-->>Agent: done
    Agent-->>User: event: done
    Agent-->>Agent: saveTranscript()

Turn 输入输出

// 输入
interface AcpRuntimeTurnInput {
  handle: AcpRuntimeHandle;     // 会话句柄
  text: string;                 // 用户消息
  attachments?: Attachment[];   // 附件(图片、文件等)
  mode: "prompt" | "steer";     // 模式:对话 or 引导
  requestId: string;            // 请求 ID
  signal?: AbortSignal;         // 中断信号
}

// 输出(事件流)
type AcpRuntimeEvent =
  | { type: "text_delta"; text: string; stream?: "output" | "thought" }
  | { type: "status"; text: string; used?: number; size?: number }
  | { type: "tool_call"; name: string; args: Record<string, unknown>; id: string }
  | { type: "tool_result"; id: string; result: string }
  | { type: "usage_update"; input: number; output: number }
  | { type: "done"; stopReason: string }
  | { type: "error"; message: string; code?: string; retryable?: boolean };

事件流示例

用户: "今天北京天气怎么样?"

事件序列:
1. { type: "status", text: "Thinking..." }
2. { type: "tool_call", name: "weather.get", args: {city: "北京"}, id: "tc_1" }
3. { type: "tool_result", id: "tc_1", result: '{"temp":"15-25°C","condition":"晴"}' }
4. { type: "text_delta", text: "北京今天" }
5. { type: "text_delta", text: "天气晴朗" }
6. { type: "text_delta", text: ",气温" }
7. { type: "text_delta", text: "15-25°C。" }
8. { type: "usage_update", input: 150, output: 25 }
9. { type: "done", stopReason: "end_turn" }

工具调用:Agent 的手脚

问题:LLM 无法直接操作世界

LLM 只能生成文本,不能:

  • 查询数据库
  • 调用 API
  • 读写文件
  • 执行代码

解决方案:工具调用协议

flowchart TB
    subgraph LLM["LLM"]
        DECIDE["决定调用工具"]
    end

    subgraph Agent["Agent Runtime"]
        PARSE["解析工具调用"]
        EXEC["执行工具"]
        FORMAT["格式化结果"]
    end

    subgraph Tools["工具系统"]
        T1["weather.get"]
        T2["web.search"]
        T3["fs.read"]
        T4["code.execute"]
    end

    LLM --> |tool_call| Agent
    Agent --> PARSE
    PARSE --> EXEC
    EXEC --> T1
    EXEC --> T2
    EXEC --> T3
    EXEC --> T4
    T1 --> |result| FORMAT
    T2 --> |result| FORMAT
    T3 --> |result| FORMAT
    T4 --> |result| FORMAT
    FORMAT --> |tool_result| LLM

工具定义

// src/agents/tools/types.ts
interface AgentTool {
  // 元信息
  name: string;                    // 工具名称
  description: string;             // 工具描述(LLM 会看到)
  inputSchema: JSONSchema;         // 输入参数 Schema

  // 执行函数
  handler: (params: Record<string, unknown>, ctx: ToolContext) => Promise<ToolResult>;
}

interface ToolContext {
  sessionKey: string;              // 当前会话
  agentId: string;                 // Agent ID
  sandboxed: boolean;              // 是否在沙箱中
  abortSignal: AbortSignal;        // 中断信号
  cwd?: string;                    // 工作目录
}

interface ToolResult {
  content: string | ContentBlock[];
  isError?: boolean;               // 是否错误
}

工具注册机制

// src/agents/tools/registry.ts
export class ToolRegistry {
  private tools = new Map<string, AgentTool>();

  register(tool: AgentTool): void {
    if (this.tools.has(tool.name)) {
      throw new Error(`Tool ${tool.name} already registered`);
    }
    this.tools.set(tool.name, tool);
  }

  get(name: string): AgentTool | undefined {
    return this.tools.get(name);
  }

  // 生成 LLM 能理解的工具列表
  toOpenAITools(): OpenAI.Chat.ChatCompletionTool[] {
    return Array.from(this.tools.values()).map(tool => ({
      type: "function",
      function: {
        name: tool.name,
        description: tool.description,
        parameters: tool.inputSchema,
      },
    }));
  }
}

// 内置工具注册
const registry = new ToolRegistry();

registry.register({
  name: "sessions.list",
  description: "List all available sessions",
  inputSchema: { type: "object", properties: {} },
  handler: async (_, ctx) => {
    const sessions = await listSessions();
    return { content: JSON.stringify(sessions) };
  },
});

registry.register({
  name: "sessions.send",
  description: "Send a message to a session",
  inputSchema: {
    type: "object",
    properties: {
      sessionKey: { type: "string", description: "Target session key" },
      text: { type: "string", description: "Message text" },
    },
    required: ["sessionKey", "text"],
  },
  handler: async (params, ctx) => {
    const { sessionKey, text } = params as { sessionKey: string; text: string };
    await sendMessage(sessionKey, text);
    return { content: "Message sent" };
  },
});

工具执行流程

// src/agents/tools/executor.ts
async function executeToolCall(
  call: ToolCall,
  registry: ToolRegistry,
  ctx: ToolContext
): Promise<ToolResult> {
  const tool = registry.get(call.name);

  if (!tool) {
    return {
      content: `Unknown tool: ${call.name}`,
      isError: true,
    };
  }

  // 1. 验证参数
  const validation = validateInput(tool.inputSchema, call.args);
  if (!validation.valid) {
    return {
      content: `Invalid arguments: ${validation.errors.join(", ")}`,
      isError: true,
    };
  }

  // 2. 检查权限(沙箱模式)
  if (ctx.sandboxed && !isToolAllowedInSandbox(call.name)) {
    return {
      content: `Tool ${call.name} is not allowed in sandbox mode`,
      isError: true,
    };
  }

  // 3. 执行工具
  try {
    const result = await tool.handler(call.args, ctx);
    return result;
  } catch (err) {
    return {
      content: `Tool execution failed: ${err instanceof Error ? err.message : String(err)}`,
      isError: true,
    };
  }
}

沙箱安全

// 沙箱模式下的工具白名单
const SANDBOX_ALLOWED_TOOLS = new Set([
  // 只读工具
  "sessions.list",
  "sessions.get",
  "config.get",

  // 受限的文件操作
  "fs.read",
  "fs.readdir",

  // 安全的网络请求
  "web.fetch",  // 只允许 GET
]);

function isToolAllowedInSandbox(toolName: string): boolean {
  return SANDBOX_ALLOWED_TOOLS.has(toolName);
}

Subagent:任务分解与协作

问题:复杂任务需要专业化

当用户说"帮我开发一个完整的 Web 应用"时,单个 Agent 难以处理:

  • 需要架构设计
  • 需要前端开发
  • 需要后端开发
  • 需要测试

解决方案:Subagent 机制

flowchart TB
    subgraph Main["Main Agent"]
        PLAN["分析任务"]
        DELEGATE["委派给子 Agent"]
        COLLECT["收集结果"]
    end

    subgraph Subagents["子 Agent 池"]
        ARCH["architect<br/>架构设计"]
        FRONT["frontend<br/>前端开发"]
        BACK["backend<br/>后端开发"]
        TEST["tester<br/>测试"]
    end

    TASK["任务: 开发 Web 应用"] --> PLAN
    PLAN --> DELEGATE

    DELEGATE --> |"设计架构"| ARCH
    DELEGATE --> |"实现前端"| FRONT
    DELEGATE --> |"实现后端"| BACK
    DELEGATE --> |"编写测试"| TEST

    ARCH --> COLLECT
    FRONT --> COLLECT
    BACK --> COLLECT
    TEST --> COLLECT

    COLLECT --> RESULT["完成的应用"]

Spawn 参数

// src/agents/acp-spawn.ts
interface SpawnAcpParams {
  task: string;                    // 任务描述
  agentId?: string;                // 目标 Agent ID
  mode?: "run" | "session";        // 运行模式
  thread?: boolean;                // 是否绑定线程
  sandbox?: "inherit" | "require"; // 沙箱模式
  streamTo?: "parent";             // 流式输出目标
}

interface SpawnAcpResult {
  status: "accepted" | "forbidden" | "error";
  childSessionKey?: string;        // 子会话键
  runId?: string;                  // 运行 ID
  streamLogPath?: string;          // 流日志路径
  error?: string;
}

Spawn 实现

export async function spawnAcpDirect(
  params: SpawnAcpParams,
  ctx: SpawnAcpContext
): Promise<SpawnAcpResult> {
  const cfg = loadConfig();

  // 1. 策略检查
  if (!isAcpEnabledByPolicy(cfg)) {
    return { status: "forbidden", error: "ACP is disabled by policy" };
  }

  // 2. 解析目标 Agent
  const agentResult = resolveTargetAcpAgentId({
    requestedAgentId: params.agentId,
    cfg,
  });

  if (!agentResult.ok) {
    return { status: "error", error: agentResult.error };
  }

  // 3. 生成子会话键
  const childSessionKey = generateChildSessionKey({
    parentSessionKey: ctx.agentSessionKey,
    agentId: agentResult.agentId,
  });

  // 4. 创建子会话
  const handle = await getAcpSessionManager().getOrCreateSession({
    sessionKey: childSessionKey,
    agent: agentResult.agentId,
    mode: params.mode === "session" ? "persistent" : "oneshot",
    cwd: params.sandbox === "require" ? createSandboxDir() : undefined,
  });

  // 5. 启动流式中继(如果需要)
  if (params.streamTo === "parent") {
    await startAcpSpawnParentStreamRelay({
      handle,
      parentSessionKey: ctx.agentSessionKey,
    });
  }

  // 6. 执行初始 Turn
  await runInitialTurn({ handle, task: params.task });

  return {
    status: "accepted",
    childSessionKey,
    mode: params.mode ?? "run",
  };
}

Agent 配置示例

# ~/.openclaw/openclaw.yaml
agents:
  defaults:
    model: gpt-4
    provider: openai

  list:
    - id: main
      name: General Assistant
      default: true

    - id: architect
      name: System Architect
      model: claude-opus-4-6
      provider: anthropic
      systemPrompt: |
        You are a system architect. Your job is to:
        1. Analyze requirements
        2. Design system architecture
        3. Define APIs and data models
        Output structured architecture documents.

    - id: coder
      name: Code Implementer
      model: claude-sonnet-4-6
      provider: anthropic
      systemPrompt: |
        You are a code implementer. Your job is to:
        1. Take architecture documents
        2. Implement the code
        3. Write unit tests
        Follow clean code principles.

    - id: reviewer
      name: Code Reviewer
      model: claude-sonnet-4-6
      provider: anthropic
      systemPrompt: |
        You are a code reviewer. Your job is to:
        1. Review code for bugs and issues
        2. Check for security vulnerabilities
        3. Suggest improvements
        Be thorough but constructive.

Pi Agent:嵌入式运行时

为什么需要 Pi Agent?

ACP 模式虽然灵活,但需要额外的进程通信开销。对于大多数场景,嵌入式运行时更高效。

Pi Agent 架构

flowchart TB
    subgraph PiCore["Pi Agent Core"]
        PM[Prompt Manager]
        TC[Tool Coordinator]
        MM[Memory Manager]
        ST[Stream Transformer]
    end

    subgraph PiAI["Pi AI"]
        CL[Claude Backend]
        OAI[OpenAI Backend]
        GM[Gemini Backend]
    end

    subgraph PiCoding["Pi Coding Agent"]
        FS[File System]
        CODE[Code Execution]
        LINT[Linter/Formatter]
    end

    Gateway --> PiCore
    PiCore --> PiAI
    PiCore --> PiCoding
    PiAI --> LLM["LLM APIs"]

Pi Agent 依赖

// 基于 @mariozechner/pi-* 包
import { PiAgentCore } from "@mariozechner/pi-agent-core";
import { PiAI } from "@mariozechner/pi-ai";
import { PiCodingAgent } from "@mariozechner/pi-coding-agent";

// 创建 Pi Agent
const agent = new PiAgentCore({
  provider: "openai",
  model: "gpt-4",

  // 工具配置
  tools: loadTools(),

  // 记忆配置
  memory: {
    type: "sliding_window",
    maxTokens: 4000,
  },

  // 系统提示词
  systemPrompt: buildSystemPrompt(),
});

// 执行 Turn
for await (const event of agent.runTurn({ message: "Hello" })) {
  handleEvent(event);
}

实战演练:自定义 Agent

场景:创建一个代码审查 Agent

# ~/.openclaw/openclaw.yaml
agents:
  list:
    - id: code-reviewer
      name: Code Reviewer
      model: claude-sonnet-4-6
      provider: anthropic
      systemPrompt: |
        You are a senior code reviewer. When reviewing code:

        1. **Correctness**: Does the code do what it's supposed to do?
        2. **Security**: Are there any vulnerabilities?
        3. **Performance**: Are there any obvious bottlenecks?
        4. **Maintainability**: Is the code readable and well-organized?
        5. **Testing**: Are edge cases covered?

        Format your review as:
        ## Summary
        [Brief summary]

        ## Issues
        - [SEVERITY] Description

        ## Suggestions
        - [Improvement suggestions]

        Use severity: CRITICAL, HIGH, MEDIUM, LOW, INFO

测试 Agent

# 通过 CLI 测试
openclaw agent chat --agent code-reviewer

# 通过 WebSocket 测试
wscat -c "ws://127.0.0.1:18789" -H "Authorization: Bearer $TOKEN"
> {"kind":"request","id":"test","method":"message.send","params":{"sessionKey":"main:code-reviewer","text":"Review this code:\n```python\ndef calc(a,b):\n  return a+b\n```"}}

< {"kind":"event","event":"agent","payload":{"type":"text_delta","text":"## Summary\nThis is a simple addition function..."}}

调试 Agent 行为

# 启用 Agent 调试日志
LOG_LEVEL=debug LOG_INCLUDE="agent,acp" openclaw gateway start

# 输出示例
[DEBUG] agent: Creating session for agent: code-reviewer
[DEBUG] agent: Loading tools: sessions.list, sessions.get, fs.read, fs.write
[DEBUG] acp: Starting turn, sessionKey=main:code-reviewer
[DEBUG] acp: Prompt tokens: 450
[DEBUG] acp: LLM response: text_delta "## Summary"
[DEBUG] acp: LLM response: text_delta "This is a..."
[DEBUG] acp: Turn complete, total tokens: 520

常见陷阱

陷阱 1:工具调用超时

症状:

[ERROR] Tool execution timed out after 30000ms
[ERROR] Turn aborted: tool_timeout

原因: 工具执行时间超过了默认的超时限制(30秒),导致 Turn 被中断。

错误代码:

// 工具执行没有设置合理的超时
async function handler(params, ctx) {
  const result = await fetch('https://slow-api.example.com/data');
  // 如果 API 响应慢,会触发超时
  return { content: await result.text() };
}

正确代码:

// 正确写法:使用 AbortSignal 控制超时
async function handler(params, ctx) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 25000); // 25秒超时,留缓冲

  try {
    const result = await fetch('https://slow-api.example.com/data', {
      signal: ctx.abortSignal || controller.signal,
    });
    return { content: await result.text() };
  } finally {
    clearTimeout(timeoutId);
  }
}

调试方法:

# 查看工具执行详情
LOG_LEVEL=debug LOG_INCLUDE="tools,executor" openclaw gateway start

# 输出示例
[DEBUG] tools: Executing tool: weather.get
[DEBUG] tools: Tool params: {"city":"北京"}
[DEBUG] tools: Tool execution started at 2026-03-14T10:30:00.000Z
[DEBUG] tools: Tool execution timed out after 30000ms

源码位置: src/agents/tools/executor.ts


陷阱 2:Subagent 权限拒绝

症状:

{
  "type": "tool_result",
  "id": "tc_spawn",
  "result": "{\"status\":\"forbidden\",\"error\":\"ACP is disabled by policy\"}"
}

原因: Subagent 的 spawn 请求被策略拦截,可能是因为:

  1. 配置中禁用了 ACP
  2. 目标 Agent 不在允许列表中
  3. 沙箱模式不兼容

错误配置:

# ~/.openclaw/openclaw.yaml
# 问题:禁用了 ACP 但尝试使用 Subagent
acp:
  enabled: false

正确配置:

# ~/.openclaw/openclaw.yaml
acp:
  enabled: true

  # 配置允许的 Agent
  agents:
    allowed:
      - main
      - architect
      - coder

  # 沙箱策略
  sandbox:
    mode: optional  # inherit | require | optional

调试方法:

# 检查 ACP 配置
openclaw config get acp

# 输出
acp.enabled: true
acp.agents.allowed: ["main", "architect", "coder"]

# 查看 spawn 请求日志
LOG_LEVEL=debug LOG_INCLUDE="spawn,acp" openclaw gateway start

# 输出示例
[DEBUG] spawn: Spawn request: agent=architect, mode=run
[DEBUG] spawn: Checking policy...
[DEBUG] spawn: Policy check passed
[DEBUG] spawn: Creating child session: main:architect:spawn_abc123

源码位置: src/agents/acp-spawn.ts


陷阱 3:工具参数验证失败

症状:

{
  "type": "tool_result",
  "id": "tc_123",
  "result": "Invalid arguments: sessionKey is required, text is required",
  "isError": true
}

原因: LLM 生成的工具调用参数不符合 JSON Schema 定义,导致验证失败。

错误代码:

// Schema 定义不清晰,LLM 容易误解
registry.register({
  name: "sessions.send",
  description: "Send a message",  // 描述太简略
  inputSchema: {
    type: "object",
    properties: {
      sessionKey: { type: "string" },  // 缺少描述
      text: { type: "string" },         // 缺少描述
    },
    required: ["sessionKey", "text"],
  },
  handler: async (params, ctx) => { ... },
});

正确代码:

// 清晰的 Schema 定义
registry.register({
  name: "sessions.send",
  description: "Send a message to a specific session. Use this to communicate with other sessions.",
  inputSchema: {
    type: "object",
    properties: {
      sessionKey: {
        type: "string",
        description: "The target session key, format: 'channel:identifier' (e.g., 'whatsapp:+1234567890')"
      },
      text: {
        type: "string",
        description: "The message text to send"
      },
    },
    required: ["sessionKey", "text"],
  },
  handler: async (params, ctx) => { ... },
});

调试方法:

# 启用详细日志查看验证错误
LOG_LEVEL=debug LOG_INCLUDE="tools,validation" openclaw gateway start

# 输出示例
[DEBUG] tools: Validating params for tool: sessions.send
[DEBUG] tools: Schema: {"type":"object","properties":{...}}
[DEBUG] tools: Input: {"sessionKey":123}  // 类型错误
[DEBUG] tools: Validation failed: sessionKey must be string

源码位置: src/agents/tools/executor.ts


陷阱 4:沙箱模式工具被阻止

症状:

{
  "type": "tool_result",
  "id": "tc_fs_write",
  "result": "Tool fs.write is not allowed in sandbox mode",
  "isError": true
}

原因: 当前会话运行在沙箱模式下,某些危险工具被禁止使用。

错误代码:

// 尝试在沙箱中执行受限操作
await ctx.executeTool("fs.write", {
  path: "/etc/passwd",
  content: "..."
});

正确代码:

// 检查沙箱状态后再执行
if (ctx.sandboxed) {
  // 使用沙箱允许的替代方案
  const sandboxPath = path.join(ctx.cwd || "/tmp/sandbox", "output.txt");
  await ctx.executeTool("fs.write", { path: sandboxPath, content: "..." });
} else {
  // 非沙箱模式可以访问完整文件系统
  await ctx.executeTool("fs.write", { path: targetPath, content: "..." });
}

调试方法:

# 查看当前会话的沙箱状态
openclaw session get <sessionKey> --json | jq '.sandboxed'

# 查看沙箱允许的工具列表
openclaw config get sandbox.allowedTools

# 输出
["sessions.list", "sessions.get", "fs.read", "fs.readdir", "web.fetch"]

源码位置: src/agents/tools/executor.ts


设计启示:Agent 模式的权衡

当前设计的优势

设计 优势
ACP 协议 统一不同后端,支持自定义 Agent
流式事件 实时反馈,支持中断
工具系统 可扩展,支持沙箱隔离
Subagent 任务分解,专业化处理

当前设计的劣势

问题 原因 可能的解决方案
工具调用延迟 需要等待 LLM 决定 → 执行 → 继续 并行工具调用
记忆管理 上下文窗口有限 向量数据库 + RAG
Agent 切换 需要 NLP 解析意图 显式 @mention 或命令

与其他 Agent 框架对比

特性 OpenClaw LangChain AutoGPT CrewAI
运行时模式 Embedded + ACP 链式调用 循环执行 多 Agent
工具系统 插件 + 沙箱 Python 函数 自定义 角色-任务
流式支持 ✅ 原生 ⚠️ 部分 ⚠️ 部分
多渠道 ✅ 20+
状态持久化 ✅ SQLite ⚠️ 可选 ⚠️ JSON ⚠️ 可选

小结

Agent 是 OpenClaw 的核心,它让 LLM 从"文本生成器"变成"智能助手":

组件 职责 关键概念
ACP 协议 统一后端接口 AcpRuntime 接口
Turn 执行 一次对话的处理 事件流 + 工具调用
工具系统 扩展 Agent 能力 工具注册 + 沙箱隔离
Subagent 任务分解 Spawn 机制
Pi Agent 嵌入式运行时 零通信开销

关键源码文件

文件 职责
src/acp/runtime/types.ts ACP 协议类型定义
src/acp/control-plane/manager.ts ACP Session 管理
src/agents/tools/registry.ts 工具注册表
src/agents/tools/executor.ts 工具执行器
src/agents/acp-spawn.ts Subagent Spawn

在下一篇文章中,我们将进入 扩展点——如何开发自己的 Channel Plugin、工具和钩子,打造属于你的 OpenClaw。


系列索引: OpenClaw 源码解析:目录索引

上一篇: OpenClaw 源码解析(二):消息的一生 下一篇: OpenClaw 源码解析(四):扩展点