很多人对 Agent 的印象就是:"写一段 Prompt,调一次模型,拿回一段文本"。但在 OpenClaw 里,一次 Agent 执行是一条完整的链路:Gateway 负责接入,Session 负责状态锁定,Agent Runtime 驱动模型循环,Tool Runtime 执行工具动作,Audit 和 Task 分别做审计和任务追踪。
本文先按官方的分层设计,说明这条链路和理论上的执行时序;然后通过一次 "只读一个本地文件" 的实验(Mission 011)给出真实证据;最后总结 OpenClaw 的运行时设计。
1. Provider / Model / Agent Runtime / Channel 是四个不同层次
初学者最容易把 "Provider"、"Model"、"Runtime" 混为一谈,因为它们都出现在模型配置附近。官方把它们明确拆成不同的层(来源: Agent runtimes):
| 层次 | 职责 | 示例 |
|---|---|---|
| Provider | 认证、模型发现、请求传输 | deepseek-official、anthropic、openai |
| Model | 当前 Agent Turn 选定的具体模型 | deepseek-v4-flash、claude-opus |
| Agent Runtime | 驱动模型循环、处理 Tool Call、交回完成的 Turn | openclaw(内嵌)、codex、claude-cli |
| Channel | 消息进出 OpenClaw 的位置 | CLI、Slack、Telegram |
说明:一个 Agent Runtime 独占一个"已准备好的模型循环"——接收 Prompt、驱动模型输出、处理原生 Tool Call,再把完成的 Turn 交还给 OpenClaw。提供某个 Runtime 具体实现的代码,官方称为 harness(如
openclaw、codex内置Runtime)。
因此 deepseek-official/deepseek-v4-flash 只描述了 Provider 与 Model,它并不"运行" Agent;真正持有工具循环的是 Agent Runtime。本实验用的是内嵌 openclaw runtime——官方的 auto 策略在没有插件 harness 认领该 Provider/Model 时,会回退到这个内置运行时(Runtime selection)。
从源码结构也能看出这条运行时边界(来源:Agent runtime architecture):
| 模块 | 主要职责 |
|---|---|
src/agents/embedded-agent-runner/ | 内置 attempt loop、Provider 流适配、Compaction、模型选择、Session 接线 |
src/agents/runtime/ | 对 @openclaw/agent-core 的门面与本地代理工具 |
packages/agent-core/ | 可复用的 Agent core、消息、工具与 Session 契约 |
src/agents/sessions/ | Session 持久化、资源发现、Prompt、Skills |
src/agents/agent-tools*.ts | Tool 定义、参数 Schema、Tool Policy、调用前后适配 |
src/agents/agent-hooks/ | Compaction safeguard、Context pruning |
src/llm/ | Provider 注册、模型传输与流式实现 |
Agent 循环和工具执行都在 OpenClaw 这一侧;Provider 只负责模型通信。这也决定了后面所有证据的归属——工具不是模型自己调用,是运行时替它执行的。
2. 理论时序:一次 Run 是按 Session 串行的闭环
官方定义(转述):Agent Loop 是一次按 Session 串行的运行,把一条消息变成一系列动作与一个回复,依次经过接入、Context 组装、模型推理、Tool 执行、流式输出与持久化。入口有两个:Gateway RPC(
agent/agent.wait)与 CLI(openclaw agent)。(来源: Agent loop)
sequenceDiagram
autonumber
participant C as CLI / Channel / Cron
participant G as Gateway
participant T as Task Ledger
participant S as Session Store
participant R as Agent Runtime
participant P as Model Provider
participant X as Tool Runtime
participant A as Audit Ledger
C->>G: 提交消息与 sessionKey
G->>S: 解析或创建 Session
G->>T: 为可追踪运行创建 Task
G->>R: 启动 Agent Run
R->>S: 获取 Session 写锁
R->>R: 加载 Workspace / Skills / Tool Schema
R->>R: 组装 System Prompt 与 Context
R->>P: Model Request #1
P-->>R: Tool Call (stopReason=toolUse)
R->>A: tool_action.started
R->>X: 执行 Tool
X-->>R: Tool Result
R->>A: tool_action.finished
R->>P: Model Request #2 + Tool Result
P-->>R: Final Answer (stopReason=stop)
R->>S: 持久化消息、Usage 与运行状态
R->>A: agent_run.finished
R->>T: 更新 Task 终态
G-->>C: 返回最终结果
三个设计要点:
- 串行与加锁:Run 通过"每个 Session 一个队列 + 一个全局队列"保证串行执行,避免 Tool 和 Transcript 的竞争。Transcript 写入额外受一把基于文件的 Session 写锁保护(进程感知,默认超时 60 秒,非可重入)。
- System Prompt 每 Run 重建:模型接收的不只是用户消息,还有 Tool Schema、Skills 元数据、Workspace 引导文件、运行时信息与对话历史。
- Tool Call 会触发一个完整的执行环路:只要模型返回 Tool Call,运行时就必须执行对应的工具,然后把工具的返回结果注入下一次模型请求。由此得到本文核心命题:
一次 Agent Run ≠ 一次模型请求
3. 实验设计:用最小动作暴露完整链路
实验任务极简:
让 Agent 读取一个本地 Markdown 文件,返回文件中预先嵌入的唯一标识(Marker),并返回文件前三行。
/root/openclaw/lab/runtime-anatomy-mission-011/input/runtime-sample.md
Prompt 中没有写入 Marker 的实际值,所以只要 Agent 返回了正确的 Marker,就证明它确实读到了文件——这是验证工具是否真实执行的锚点。
运行环境:
| 字段 | 实际值 |
|---|---|
| OpenClaw | v2026.7.1-2 |
| Agent | main |
| Provider / Model | deepseek-official / deepseek-v4-flash |
| Agent Runtime | 内嵌(embedded,auto 策略,未走 ACP 远程 Runtime) |
| Tool | read |
| Session Key | agent:main:mission011-20260724-135327 |
| Session ID | d1ca7f12-ca11-438d-98f8-91ecaf632511 |
| 成功 Run ID | d996b4e1-305b-4791-bc7a-c60bcb07fee8 |
本次实验将从五个数据来源采集证据:
- Agent 结果:
agent-result.json - 会话记录:Session JSONL Transcript
- 审计事件:
audit-run.json/audit-tools.json - 运行时日志:Gateway / systemd 日志
- 任务状态:
tasks-after.json
4. 实验结果:模型 → Tool → 模型 的两阶段闭环
成功 Run 由两次模型请求构成,中间夹一次本地读文件:
| 阶段 | Input Tokens | Output Tokens | Stop Reason | 作用 |
|---|---|---|---|---|
| Model Request #1 | 251 | 63 | toolUse | 生成 read Tool Call |
| Model Request #2 | 164 | 65 | stop | 依据 Tool Result 产出最终回答 |
Tool 调用参数与执行结果:
{ "path": "/root/openclaw/lab/runtime-anatomy-mission-011/input/runtime-sample.md" }
| 指标 | 结果 |
|---|---|
| 调用次数 / 状态 | 1 次 / succeeded |
| Tool 耗时(Audit) | 约 5 ms |
| Run 总耗时 | 5,020 ms(durationMs: 5020) |
实际循环:
sequenceDiagram
autonumber
participant R as Embedded Agent Runtime
participant D as deepseek-v4-flash
participant X as read Tool
participant S as Session / Transcript
R->>D: Request #1
D-->>R: stopReason=toolUse · read(path)
R->>X: 读取 runtime-sample.md
X-->>R: 文件正文与 Marker
R->>S: 记录 Tool Call / Tool Result
R->>D: Request #2 + Tool Result
D-->>R: stopReason=stop · 最终回答
R->>S: 持久化 Assistant 消息与 Usage
两个可以直接读出来的结论:
其一,延迟由模型与运行时主导,而非本地 Tool。 read 仅约 5 ms,占 Run 总时长的千分之一;5.02 s 中绝大部分是两次模型请求与运行时处理。对本地工具做性能优化收益极低。
其二,Tool Result 是第二阶段的模型输入。 Request #2 的 input(164)小于 Request #1(251),却已携带 Tool Result,说明注入 Tool Result 的同时,前序 Context 经过了运行时侧的裁剪/重组,而非简单累加。
5. Prompt 成本主要来自系统层
用户请求很短,但模型实际看到的输入是官方定义的一组固定内容拼接而成:基础 Prompt + Skills Prompt + Bootstrap Context + 每轮覆盖项,并在提交前强制执行模型上限与 Compaction 预留(来源:System prompt)。
从 agent-result.json 可以看到本次 Prompt 的组成:
| 组成 | 数量 |
|---|---|
| Workspace 文件 | 7 |
| Skill 条目 | 20 |
| Tool Schema | 23 |
| System Prompt 总字符 | 32,255 |
仅 Tool Schema 一项就占了 12,978 字符(约四成) ,其余部分(基础 Prompt / Workspace / Skills / 历史)合计 19,277 字符。
这里引出两条工程含义:
- 短消息不代表低 Context 成本。 用户消息很短,但系统层组成的 Prompt 可能远大于用户输入。
- Tool 数量增长会同时抬高文本说明与 JSON Schema 两项开销。 每增加一个 Tool,都要付出双倍代价。
值得注意的是,可用 Tool 数量本身受 Tool Policy 动态裁剪:Gateway 日志显示 cron、gateway、nodes 三个 Tool 被策略移除后才进入 Schema 组装。因此"23 个 Tool Schema"是策略过滤后的结果,而非 Agent 全量工具集。
本次 Context Budget 为 64,000 tokens、预留 24,000 tokens,报告 shouldCompact: false——没有证据表明该成功 Run 触发了 Compaction。
6. runtime=cli 与 Agent Runtime 是两个维度
本次实验的 openclaw agent 命令在前台 Shell 中执行,同步等待结果,但 tasks-after.json 中仍然生成了 Task 记录:
{
"runtime": "cli",
"runId": "d996b4e1-305b-4791-bc7a-c60bcb07fee8",
"status": "succeeded",
"terminalSummary": "completed"
}
这里需要区分两个 runtime 的含义:
- Agent Runtime:执行模型循环的后端,本次使用的是 OpenClaw 内置运行时(embedded runtime);
- Task runtime:Task 的来源类型,本次的来源是 CLI。
换句话说:Task 的 runtime: "cli",并不等于 Agent 用了 CLI 作为后端运行时。两者是完全不同的维度。
在 OpenClaw 的 Task 设计里,通过 Gateway 派发的 CLI 命令、Cron 任务、Subagent、ACP 请求,都会被统一纳入 Task 记录。Task 只记录工作的生命周期,不决定谁来调度,更不代表使用了哪种 Agent Runtime。本次前台 CLI 执行也进入了 Task 表,说明 Task 系统的入口比"只记后台任务"更宽。
7. 四类标识,四种作用域
| 标识 | 作用域 |
|---|---|
| Session Key | 应用层会话路由键 |
| Session ID | Session Store 内部标识(UUID) |
| Run ID | 一次 Agent 执行实例 |
| Task ID | Task Ledger 中的一条工作记录 |
这四种标识是从属关系,不是同义词:
Session Key ──映射──> Session ID
│
├──包含多次──> Run ID
│
└──关联多条──> Task ID
Task ID ──可关联──> Run ID
在本次实验中,同一个 Session 内先出现一次被中止的 Run(aborted),紧接着又成功完成了一个 Run。这说明 失败的是某一次执行实例,Session 本身不受影响,仍然可以继续使用。而 Task 为可追踪的执行过程附加了独立的生命周期:
queued → running → succeeded / failed / timed_out / cancelled / lost
8. 可观测性:五个数据面各覆盖一部分事实
| 数据源 | 保存内容 | 含正文 | 主要用途 |
|---|---|---|---|
| Session | 会话状态、模型与 Usage 元数据 | 是 | 恢复与管理会话 |
| Transcript | 用户/Assistant 消息、Tool Call、Tool Result | 是 | 重放具体交互 |
| Audit | Run 与 Tool Action 的元数据事件 | 否 | 审计顺序、状态、耗时 |
| Gateway Logs | Provider、策略、网络与运行时诊断 | 有限 | 故障定位 |
| Tasks | 可追踪工作的生命周期 | 有限 | 查询运行状态与来源 |
Audit 只保存元数据,这不是本次实验偶然观察到的情况,而是官方明确的设计:Gateway 把生命周期和工具的起止事件记录到审计日志中,只保存来源和结果码,不复制 Prompt、消息、工具参数、工具结果或原始错误(来源: Agent loop · Audit projection)。本次实验所有 Audit 事件的 redaction 都是 metadata_only,与这个设计一致。
因此,观察一次调用的完整链路,不能只看单一数据源:
Task → 任务是否完成
Audit → Run 和 Tool 的执行过程
Transcript → 交换了什么内容
Logs → 运行时为什么失败
结论:OpenClaw 是一个 Agent Runtime,不是模型 API 的封装
本次实验验证了 OpenClaw 内置 Runtime 的几个核心设计要点:
- Runtime 与 Provider 分层——Provider 负责模型通信,Agent Runtime 负责 Prompt、模型循环与 Tool 接线。
- 一次 Run 可含多次模型请求——本次成功 Run 由
toolUse与stop两个模型阶段组成。 - Tool 由 OpenClaw 执行——模型只产出结构化 Tool Call,本地文件读取由 Tool Runtime 完成。
- Tool Result 反哺为下一阶段输入——Tool Call 把 Agent 从单次生成变为闭环执行。
- Prompt 成本集中在系统层——Workspace、Skills 与 Tool Schema 可远大于用户消息,且受 Tool Policy 动态裁剪。
- Task 来源与 Agent Runtime 正交——
runtime=cli只标注 Task 入口,不代表使用 CLI backend。 - Session / Run / Task 生命周期不同——Session 持续存在,Run 是一次执行,Task 是一条可追踪的记录。失败只影响执行实例,Session 和 Task 仍然可用。
- 审计需要多个数据源——Task、Audit、Transcript、Logs 各自记录一部分事实,只看任何一个都不足以复现全貌。
综合来看,OpenClaw 在 Provider 之上自行提供了运行循环、状态管理、工具执行、任务追踪与审计能力——它是一个完整的 Agent Runtime,而非模型 API 的薄封装。理解它的关键,是始终区分"哪一层在做事、哪一份记录能证明它"。
OpenClaw 官方扩展阅读(简体中文)
- Agent runtime architecture · 智能体运行时架构 — 源码模块划分、运行时边界与 Harness 选择。
- Agent loop · 智能体循环 — 从 Gateway RPC 到 Context 组装、推理、Tool 执行与持久化的完整流程,含队列、写锁与超时。
- Agent runtimes · 智能体运行时 — Provider、Model、Agent Runtime、Channel 的分层与
auto选择规则。 - System prompt · 系统提示词 — System Prompt 的构建层次、固定区段与运行时注入。
- Context · 上下文 — Context 组成、Workspace 注入、Skills 与 Tool Schema 开销。
- Tasks · 后台任务 — Task Ledger 与 CLI/Cron/Subagent/ACP 的创建条件与生命周期。
- Audit · 审计记录 — Audit Ledger 的数据范围、隐私边界与查询方式。
- Sessions · 会话 — Session Store 的查询语义及其与在线状态的区别。