首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >拆解 OpenClaw Agent Runtime:一个开源 AI Agent 执行引擎是怎么炼成的

拆解 OpenClaw Agent Runtime:一个开源 AI Agent 执行引擎是怎么炼成的

作者头像
唐国梁Tommy
发布2026-06-25 21:17:31
发布2026-06-25 21:17:31
1380
举报

从一条消息到一次完整的 AI 推理,中间到底发生了什么?本文以 OpenClaw 开源项目为蓝本,逐层拆解一个工业级 Agent Runtime 的内部运作机制。


为什么要关注 Agent Runtime?

如果说大语言模型是 AI Agent 的「大脑」,那么 Agent Runtime 就是它的「神经系统」——负责接收外部刺激、协调大脑思考、驱动肢体行动、并将结果反馈给外部世界。

市面上讨论 AI Agent 的文章很多,但大多停留在 Prompt 编排和工具调用层面。真正决定一个 Agent 是否能在生产环境中稳定运行的,是那些不那么"性感"但至关重要的工程问题:

  • 模型 API 挂了怎么办?
  • 对话历史超出上下文窗口了怎么处理?
  • 怎么防止 Agent 陷入工具调用死循环?
  • 多个 Agent 同时写同一个会话文件会不会冲突?
  • 如何在不牺牲安全的前提下让 Agent 执行代码?

OpenClaw 的 Agent Runtime 模块用约 150 个源文件、数万行 TypeScript 代码,给出了一套完整的答案。


一、全景:一条消息的旅程

在深入细节之前,先看一条用户消息在 OpenClaw 中的完整旅程:

代码语言:javascript
复制
用户在 Telegram 发送 "帮我写一个排序算法"
         │
         ▼
    消息渠道层(Telegram/Discord/Slack/...)
         │
         ▼
    Auto-Reply 分发器 ── 确定路由、加载配置
         │
         ▼
    Agent Runner ── 获取会话锁、刷新记忆
         │
         ▼
  ┌─ Agent Runtime 核心 ──────────────────┐
  │                                        │
  │  模型解析 → 认证链 → 上下文窗口检查     │
  │       │                                │
  │       ▼                                │
  │  构建系统提示词 + 工具集                 │
  │       │                                │
  │       ▼                                │
  │  调用 LLM 流式推理                      │
  │       │                                │
  │       ├── 文本流 → 分块 → 流式投递       │
  │       │                                │
  │       ├── 工具调用 → 策略检查 → 执行     │
  │       │              → 结果回传 LLM     │
  │       │                                │
  │       └── 上下文溢出 → 自动压缩          │
  │                                        │
  └────────────────────────────────────────┘
         │
         ▼
    回复投递 → Telegram 消息

看起来很直白?但每一个箭头背后都藏着大量的工程决策。接下来我们逐层拆解。


二、执行引擎:不只是"调一下 API"

Agent Runtime 的核心入口是一个名为 runEmbeddedPiAgent 的函数,它大约有 1,200 行代码。但它做的事情可以用一句话概括:

在一个带重试、带故障转移、带资源管理的循环中,反复尝试完成一次 LLM 推理。

重试循环:不是简单的 retry

很多项目的重试逻辑就是 for (let i = 0; i < 3; i++)。OpenClaw 的做法截然不同——重试次数是动态计算的:

代码语言:javascript
复制
最大重试次数 = min(160, max(32, 24 + 认证Profile数 × 8))

为什么?因为每个认证 Profile 代表一组独立的 API 凭证。如果你配置了 5 个 OpenAI API Key,系统就有 24 + 5×8 = 64 次尝试机会,可以在不同 Key 之间轮转,最大限度地利用所有可用资源。

错误不是"错误",是"分类信号"

当 LLM 调用失败时,系统不会无脑重试,而是先对错误进行分类:

错误类型

对应策略

余额不足(402)

切换到下一个认证 Profile

频率限制(429)

退避等待 + Profile 轮转

认证失败(401)

切换 Profile

永久拒绝(403)

标记该 Profile 不可用,跳过

超时(408)

直接重试

模型不存在(404)

回退到默认模型

这套机制意味着:即使你的主力 API Key 被限流了,系统会自动切换到备用 Key 继续工作,而不是直接报错。


三、认证体系:六层 Fallback,永不断线

模型认证是 Agent 能否正常工作的前提。OpenClaw 设计了一个六层优先级的认证解析链:

代码语言:javascript
复制
第 1 层:显式指定的 Profile ID
    ↓ 未找到
第 2 层:配置文件中的认证覆盖
    ↓ 未找到
第 3 层:Auth Profile Store(本地存储的 Profile 列表)
    ↓ 未找到
第 4 层:环境变量(如 OPENAI_API_KEY)
    ↓ 未找到
第 5 层:配置文件中的自定义 API Key
    ↓ 未找到
第 6 层:AWS SDK 默认凭证链(仅 Bedrock)

同时支持四种认证模式:标准 API Key、OAuth Token、特殊 Token、以及 AWS 凭证链。这意味着无论你是用 Anthropic 的 API Key,还是通过 GitHub Copilot 的 OAuth,还是 AWS Bedrock 的 IAM 角色,都能无缝接入。


四、工具系统:十步管线,九层策略

工具(Tools)是 Agent 与外部世界交互的通道。OpenClaw 的工具系统不是简单的"注册一个函数",而是一条精密的工业管线。

十步工具构建管线

从"定义一个工具"到"Agent 可以调用它",要经过十个步骤:

代码语言:javascript
复制
① 解析工具策略配置
② 创建基础工具(文件读写、编辑)
③ 创建 OpenClaw 专有工具(浏览器、消息、定时任务等)
④ 创建命令执行工具(Bash/Exec)
⑤ 应用 Owner-Only 授权过滤
⑥ 应用消息渠道策略(如语音渠道禁用 TTS)
⑦ 应用多层策略管线过滤
⑧ 规范化工具 Schema(适配不同 LLM 的 API 格式)
⑨ 包装 Before-Call 钩子(循环检测)
⑩ 包装 AbortSignal 处理器(超时取消)

九层策略过滤

一个工具能否被 Agent 使用,要通过九层策略的层层审查:

代码语言:javascript
复制
全局 Profile 策略 → Provider Profile 策略
    → 全局 Allow 策略 → 全局 Provider 策略
        → Agent 策略 → Agent Provider 策略
            → 群组策略 → 沙箱策略 → 子代理策略

为什么要这么复杂?因为不同场景对工具的需求完全不同:

  • • 在私聊中,Agent 可能需要全部工具
  • • 在群聊中,你可能只想让它回复消息,不要执行代码
  • • 在沙箱中,Agent 不应该能访问网关配置
  • • 子代理不应该能再生成子代理(防止无限嵌套)

子代理的深度感知策略尤其值得一提:

系统维护了两个黑名单——"始终禁止"和"叶子节点禁止"。当子代理的嵌套深度达到上限时,会自动禁用 sessions_spawn(生成新子代理)工具,从架构层面杜绝了 Agent 递归爆炸的风险。

循环检测

Agent 有时候会陷入工具调用循环——反复用相同参数调用同一个工具。OpenClaw 的循环检测器会追踪每个工具调用的签名:

  • • 第 10 次重复:发出警告
  • • 第 20 次重复:再次警告
  • • 第 30 次重复:强化警告

追踪按 10 次调用分桶,最多记录 256 个不同签名,在检测精度和内存开销之间取得平衡。

OpenClaw 内置了哪些工具?

类别

工具

能力

文件操作

read, write, edit

读写编辑文件

代码执行

exec, process

运行命令、管理进程

浏览器

browser

Puppeteer 自动化

消息

message, tts

跨渠道发送消息、语音合成

Web

web_search, web_fetch

搜索和抓取网页

会话

sessions_list/spawn/send

管理会话、生成子代理

自动化

cron

定时任务

可视化

canvas, image

画布渲染、图像处理

基础设施

gateway, nodes

网关和节点管理

同时通过插件系统支持无限扩展——任何第三方都可以编写插件注册新工具。


五、流式响应:从 Token 到消息的精密管线

在 ChatGPT 时代,用户已经习惯了"打字机效果"——文字一个个蹦出来。但要在一个多渠道、多工具的 Agent 系统中实现可靠的流式响应,远比想象中复杂。

流式状态机

OpenClaw 的流式订阅引擎(pi-embedded-subscribe.ts)大约有 2,000 行代码,核心是一个精密的状态机:

代码语言:javascript
复制
LLM Token 流
    │
    ▼
增量缓冲(deltaBuffer)── 累积原始 Token
    │
    ▼
块级缓冲(blockBuffer)── 识别代码块、思维块边界
    │
    ▼
Block Chunker ── 按段落/换行/句子智能分割
    │              (不会打断 Markdown 代码块)
    ▼
Block Reply Pipeline ── 去重 + 排队 + 超时保护
    │
    ▼
Reply Dispatcher ── 序列化投递 + 人工延迟注入
    │
    ▼
消息渠道 ── Telegram/Discord/Slack/...

三重去重机制

流式系统最怕的问题是重复发送。OpenClaw 设计了三重去重:

  1. 1. Payload 指纹去重:对每个消息块计算指纹(text + mediaList + replyToId),已发送的指纹不会再发
  2. 2. 消息工具去重:如果 Agent 通过 Message Tool 主动发了一条消息,流式管线会检测并跳过相同内容
  3. 3. Pipeline 状态追踪sentKeys(已发送)、pendingKeys(发送中)、bufferedKeys(缓冲中)三组状态互斥

智能分块

Block Chunker 不是简单地按固定长度切割文本,而是:

  • • 优先在段落边界(\n\n)处分割
  • • 其次在换行处分割
  • • 最后在句子边界分割
  • • 但绝不会打断 Markdown 代码块

这确保了用户看到的每一条消息都是语义完整的。

拟人化延迟

在消息块之间,系统会注入 800-2500 毫秒的随机延迟,模拟人类打字的节奏。这不是性能问题,而是刻意的 UX 设计——避免瞬间刷出一大堆消息吓到用户。


六、会话管理:为并发而生

分布式文件锁

当多个 Agent 或多个请求同时操作同一个会话时,如何保证数据一致性?OpenClaw 实现了一套基于文件的分布式锁:

  • • 锁文件:.jsonl.lock,包含 PID 和时间戳
  • • 支持可重入(同进程多次获取,引用计数)
  • • 指数退避重试(50ms → 1000ms)
  • • 过期锁自动回收(30 分钟阈值 + PID 存活检测)
  • • 看门狗线程(60 秒间隔扫描超时锁)
  • • 进程退出和信号处理器保证清理

这套机制确保了即使在多 Agent 并发场景下,会话文件也不会出现数据损坏。

自动压缩:不让上下文窗口溢出

随着对话的进行,会话历史会越来越长,终将超出模型的上下文窗口。OpenClaw 的自动压缩系统会在溢出前触发:

代码语言:javascript
复制
检测到上下文接近窗口限制
    │
    ▼
是否最近已压缩过?── 是 → 跳过
    │ 否
    ▼
计算可压缩条目数 ── 不足 → 跳过
    │ 足够
    ▼
调用 LLM 生成历史摘要
    │
    ▼
用摘要替换原始历史
    │
    ▼
记录压缩诊断日志

压缩操作有 300 秒的硬超时保护,避免压缩过程本身成为瓶颈。

每次压缩都会产出详细的诊断信息,包括压缩前的消息数、文本字符数、工具结果字符数、估计 Token 数等,方便事后分析。


七、沙箱隔离:让 Agent 安全地"动手"

Agent 需要执行代码、读写文件,这意味着它有能力搞破坏。OpenClaw 的沙箱系统在「让 Agent 有用」和「让 Agent 安全」之间找到了平衡。

三种隔离级别

模式

说明

off

不使用沙箱(完全信任)

non-main

仅非主 Agent 使用沙箱

all

所有 Agent 都在沙箱中运行

容器化隔离

沙箱基于 Docker 容器,提供多维度的安全隔离:

代码语言:javascript
复制
安全维度:
├── 能力限制:capDrop: ["ALL"](丢弃所有 Linux Capabilities)
├── 网络隔离:禁止 host 网络模式
├── 文件系统:工作空间访问控制(none/只读/读写)
├── 进程限制:pidsLimit 防止 Fork 炸弹
├── 内存限制:memory + memorySwap 上限
├── CPU 限制:cpus 配额
├── 安全策略:seccomp + apparmor(禁止 unconfined)
└── 工具限制:沙箱内的工具白名单/黑名单

容器生命周期管理

代码语言:javascript
复制
三种容器复用策略:
├── session:每个会话一个容器(最安全)
├── agent:每个 Agent 一个容器(平衡)
└── shared:所有 Agent 共享容器(最省资源)

自动清理:
├── 空闲超时:默认 24 小时
└── 最大存活:默认 7 天

Schema 层面的安全硬编码

某些危险配置在 Schema 验证层就被拦截了,代码都写不出来:

  • • 网络模式 "host" → 验证直接拒绝
  • • Seccomp "unconfined" → 验证直接拒绝
  • • AppArmor "unconfined" → 验证直接拒绝
  • • Bind Mount 非绝对路径 → 验证直接拒绝

这是"安全左移"理念的典型实践——在配置解析阶段就阻止危险操作,而不是等到运行时才检查。


八、系统提示词:Agent 的"人格说明书"

系统提示词决定了 Agent "是谁"、"能做什么"、"该怎么做"。OpenClaw 的系统提示词不是一段静态文本,而是根据运行时上下文动态组装的:

代码语言:javascript
复制
系统提示词 =
    运行时信息(宿主/OS/架构/模型/Provider)
  + 工具目录(每个工具的名称和功能摘要)
  + 工作空间注释(项目结构、约定)
  + 技能指引(可用的 Skills)
  + 记忆部分(带引用模式)
  + Owner 身份(谁是管理员)
  + 推理指引(思维深度配置)
  + 消息渠道指引(当前渠道支持的操作)
  + 沙箱信息(容器环境元数据)
  + 时间上下文(用户时区和当前时间)

这种动态组装确保了 Agent 在不同场景下都能获得最相关的上下文,同时避免了静态提示词的膨胀问题。


九、插件与扩展:开放的工具生态

除了内置工具,OpenClaw 还提供了完整的插件系统:

插件工具工厂

代码语言:javascript
复制
// 每个插件导出一个工具工厂函数
type PluginToolFactory = (context) => Tool | Tool[] | null;

// 上下文包含了 Agent 运行时的关键信息
context = {
  config,          // 全局配置
  workspaceDir,    // 工作空间
  agentId,         // 当前 Agent
  sessionKey,      // 当前会话
  messageChannel,  // 消息渠道
  sandboxed,       // 是否在沙箱中
};

工具名冲突解决

当插件工具与核心工具同名时,系统会自动检测并记录冲突,核心工具优先。

可选插件

通过 optional: true 标记的插件工具,只有在白名单中明确列出时才会加载,避免不必要的工具膨胀。


十、并发管理:多 Agent 协作的基石

在真实场景中,一个 OpenClaw 实例可能同时运行多个 Agent,每个 Agent 可能生成子代理。并发管理至关重要。

并发限制

代码语言:javascript
复制
每个 Agent 并行调用上限:4
子代理生成并行上限:8
子代理嵌套深度上限:1(可配置,防止无限递归)

Lane 队列隔离

为防止死锁,Agent Runtime 使用命名 Lane 隔离执行:

  • • 每个会话有独立的 Lane:session:{sessionId}
  • • 压缩操作跳过队列重入,避免"压缩等待自己完成"的死锁

多 Agent 安全规范

OpenClaw 在配置文件(CLAUDE.md)中明确了多 Agent 场景下的安全规范:

  • • 不要创建/应用/删除 git stash(其他 Agent 可能在用)
  • • 不要切换分支(除非显式要求)
  • • 不要修改 git worktree(除非显式要求)
  • • 看到不认识的文件,继续工作,只提交自己的变更
  • git pull --rebase 时不要丢弃其他 Agent 的工作

十一、从架构中学到的设计原则

回顾整个 Agent Runtime 的架构,可以提炼出几个值得借鉴的设计原则:

1. 多层策略叠加 > 单一权限检查

工具系统的九层策略管线看似复杂,但它解决了一个真实问题:不同维度的权限需求互相正交。全局策略、Agent 策略、群组策略、沙箱策略各管一面,互不干扰。

2. 优雅降级 > 快速失败

认证 Profile 轮转、模型回退、错误分类驱动恢复——系统的每一层都在努力"找到一条能走通的路",而不是遇到第一个错误就放弃。

3. 安全左移 > 运行时检查

沙箱的危险配置在 Schema 验证阶段就被拦截,而不是等到 Docker 容器启动后才报错。这大幅减少了安全漏洞的攻击面。

4. 流式优先 > 批量响应

从 LLM Token 到用户看到消息,全链路流式传输,配合智能分块和去重,既保证了响应速度,又避免了消息碎片化。

5. 可观测性内建 > 事后补日志

压缩诊断、Token 用量追踪、工具调用循环检测——关键运行数据在架构设计阶段就被考虑到,而不是出问题后才想起加日志。


结语

OpenClaw 的 Agent Runtime 模块展示了一个工业级 AI Agent 执行引擎应该长什么样。它不是一个简单的"LLM API 调用封装",而是一套涵盖了认证管理、故障转移、工具管控、安全隔离、流式传输、并发控制、会话持久化等方方面面的完整运行时系统。

对于正在构建 AI Agent 产品的团队来说,OpenClaw 的设计提供了大量可借鉴的工程实践。即使不直接使用 OpenClaw,理解它的架构决策也能帮助你避开很多"踩过的坑"。

毕竟,让 Agent 写出正确的代码只是开始,让它在生产环境中安全、稳定、高效地运行,才是真正的挑战。


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 唐国梁TGLTommy 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么要关注 Agent Runtime?
  • 一、全景:一条消息的旅程
  • 二、执行引擎:不只是"调一下 API"
    • 重试循环:不是简单的 retry
    • 错误不是"错误",是"分类信号"
  • 三、认证体系:六层 Fallback,永不断线
  • 四、工具系统:十步管线,九层策略
    • 十步工具构建管线
    • 九层策略过滤
    • 循环检测
    • OpenClaw 内置了哪些工具?
  • 五、流式响应:从 Token 到消息的精密管线
    • 流式状态机
    • 三重去重机制
    • 智能分块
    • 拟人化延迟
  • 六、会话管理:为并发而生
    • 分布式文件锁
    • 自动压缩:不让上下文窗口溢出
  • 七、沙箱隔离:让 Agent 安全地"动手"
    • 三种隔离级别
    • 容器化隔离
    • 容器生命周期管理
    • Schema 层面的安全硬编码
  • 八、系统提示词:Agent 的"人格说明书"
  • 九、插件与扩展:开放的工具生态
    • 插件工具工厂
    • 工具名冲突解决
    • 可选插件
  • 十、并发管理:多 Agent 协作的基石
    • 并发限制
    • Lane 队列隔离
    • 多 Agent 安全规范
  • 十一、从架构中学到的设计原则
    • 1. 多层策略叠加 > 单一权限检查
    • 2. 优雅降级 > 快速失败
    • 3. 安全左移 > 运行时检查
    • 4. 流式优先 > 批量响应
    • 5. 可观测性内建 > 事后补日志
  • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档