模型集成与选择
简介
本文聚焦于“模型集成与选择”的完整实现,覆盖以下关键主题:
- 模型目录管理:本地与远程模型目录的加载、缓存与回退策略
- 能力检测与兼容性验证:基于目录条目的输入类型、推理能力与上下文窗口等属性进行校验
- 模型选择算法:别名解析、默认模型推断、允许列表与白名单控制
- 负载均衡与性能评估:通过基准脚本与使用聚合统计进行评估
- 配置合并与认证管理:提供者配置合并、密钥与基础 URL 的保留策略、认证存储与发现
- 动态切换机制:会话级模型覆盖、回调数据构建与 UI 展示
- 故障转移策略、降级处理与错误恢复:失败原因分类、超时识别与错误包装
- 模型发现机制、自动配置与版本管理:PI SDK 发现、合成回退、版本兼容
- 模型集成指南、自定义模型添加与性能监控技巧
模型集成与选择
围绕模型集成与选择的关键模块分布如下:
- 选择与解析:model-selection.ts(模型引用解析、别名索引、默认模型推断)
- 目录与发现:model-catalog.ts(目录加载、PI SDK 发现、合成回退)、pi-model-discovery.ts(认证与模型注册表发现)
- 配置与合并:models-config.merge.ts(提供者与模型字段合并、密钥与基础 URL 保留)、models-config.plan.ts(生成 models.json 计划)
- 列表与可用性:commands/models/list.rows.ts、list.registry.ts(模型行构建、可用性判断、过滤)
- 会话与覆盖:gateway/sessions-patch.ts(会话模型覆盖、允许模型解析)
- 媒体理解:media-understanding/resolve.ts(按能力筛选媒体理解模型)
- 性能与监控:scripts/bench-model.ts(基准测试)、usage-aggregates.ts 与 usage-render-overview.ts(使用统计与可视化)
graph TB
subgraph "模型选择与目录"
MSel["model-selection.ts"]
MCat["model-catalog.ts"]
PIdx["pi-model-discovery.ts"]
end
subgraph "配置与合并"
Mrg["models-config.merge.ts"]
Plan["models-config.plan.ts"]
end
subgraph "命令行与可用性"
LRows["commands/models/list.rows.ts"]
LReg["commands/models/list.registry.ts"]
end
subgraph "运行时集成"
Sess["gateway/sessions-patch.ts"]
Media["media-understanding/resolve.ts"]
end
subgraph "性能与监控"
Bench["scripts/bench-model.ts"]
Usage["usage-aggregates.ts"]
UIV["ui/views/usage-render-overview.ts"]
end
MSel --> MCat
MCat --> PIdx
Mrg --> Plan
LRows --> LReg
Sess --> MSel
Media --> MSel
Bench --> MSel
Usage --> UIV
核心组件
- 模型选择与解析:负责模型引用字符串解析、别名索引、默认模型推断、允许列表与白名单控制、思考级别与推理默认值解析。
- 模型目录与发现:负责从 PI SDK 加载模型目录、合并配置化模型、应用合成回退、支持图像/文档输入能力查询。
- 配置合并与计划:负责隐式与显式提供者配置合并、密钥与基础 URL 的保留策略、生成 models.json 写入计划。
- 列表与可用性:负责模型行构建、可用性判断(优先模型级,其次提供者级认证启发式)、过滤与展示。
- 会话与覆盖:负责会话级模型覆盖、允许模型解析、默认模型回退。
- 媒体理解:根据能力筛选媒体理解模型,支持共享与能力配置两种来源。
- 性能与监控:基准脚本用于评估延迟与用量,使用聚合与 UI 视图用于成本、吞吐、错误率与缓存命中率等指标。
架构总览
模型集成与选择的整体流程包括:配置加载与隐式/显式提供者合并、模型目录加载与可用性探测、模型选择与会话覆盖、能力筛选与兼容性验证、故障转移与降级、性能评估与监控。
sequenceDiagram
participant CLI as "命令行/工具"
participant Plan as "配置计划(models-config.plan)"
participant Merge as "配置合并(models-config.merge)"
participant Catalog as "模型目录(model-catalog)"
participant Sel as "模型选择(model-selection)"
participant Reg as "注册表(list.registry)"
participant Rows as "模型行(list.rows)"
participant Sess as "会话覆盖(sessions-patch)"
CLI->>Plan : 生成models.json计划
Plan->>Merge : 合并隐式/显式提供者
Merge-->>Plan : 返回合并后的提供者
CLI->>Catalog : 加载模型目录(含PI发现/回退)
Catalog-->>CLI : 返回目录与可用性
CLI->>Sel : 解析默认/允许列表/别名
Sel-->>CLI : 返回最终模型引用
CLI->>Reg : 获取可用模型集合
Reg-->>CLI : 返回可用键集
CLI->>Rows : 构建模型行(含标签/别名/可用性)
Rows-->>CLI : 返回行集合
CLI->>Sess : 应用会话模型覆盖
Sess-->>CLI : 返回覆盖结果
详细组件分析
组件A:模型选择与解析(model-selection)
- 关键职责
- 解析模型引用字符串(provider/model 或别名),标准化提供者 ID 与模型 ID
- 构建别名索引,支持按别名解析
- 默认模型推断:优先代理覆盖,其次配置默认,最后回退到硬编码默认
- 允许列表与白名单:允许任意或受控集合,合成未在目录中的条目
- 思考级别与推理默认值:基于模型目录与配置综合判定
- 数据结构与复杂度
- 别名索引:Map 查询 O(1),构建 O(N)
- 允许集合:Set 查询 O(1),构建 O(M)
- 依赖关系
- 依赖模型目录条目以判定允许性与合成条目
- 依赖代理作用域与默认配置
- 错误处理
- 对空引用、无效引用返回错误;对不可解析引用给出警告并回退
flowchart TD
Start(["入口: 解析模型引用"]) --> Parse["解析字符串为provider/model或别名"]
Parse --> HasAlias{"是否别名?"}
HasAlias --> |是| AliasLookup["别名索引查找"]
HasAlias --> |否| Normalize["标准化provider/model"]
AliasLookup --> Found{"找到别名?"}
Found --> |是| ReturnRef["返回模型引用"]
Found --> |否| Normalize
Normalize --> BuildAllow["构建允许集合(含默认)"]
BuildAllow --> Allowed{"在允许集合内?"}
Allowed --> |是| ReturnRef
Allowed --> |否| Error["返回错误: 不被允许"]
组件B:模型目录与发现(model-catalog + pi-model-discovery)
- 关键职责
- 通过 PI SDK 动态导入模型注册表,加载模型目录
- 合并配置化提供者模型(非 PI 原生提供者)
- 应用合成回退:当目录缺失时,基于模板 ID 推导
- 提供能力查询:图像/文档输入、推理能力、上下文窗口
- 缓存与容错
- 目录加载结果缓存,失败不污染缓存,避免安装过程临时失败导致的持续失败
- 依赖关系
- 依赖认证存储与模型注册表类
- 依赖配置以决定是否合并配置化模型
sequenceDiagram
participant Cat as "model-catalog"
participant PIdx as "pi-model-discovery"
participant FS as "文件系统"
participant Reg as "模型注册表"
Cat->>FS : 确保models.json存在
Cat->>PIdx : discoverAuthStorage(agentDir)
PIdx-->>Cat : 返回认证存储
Cat->>PIdx : discoverModels(authStorage, agentDir)
PIdx-->>Cat : 返回注册表实例
Cat->>Reg : getAll()/getAvailable()
Reg-->>Cat : 返回模型条目
Cat->>Cat : 合并配置化模型/应用合成回退
Cat-->>Cat : 缓存结果(可选)
组件C:配置合并与计划(models-config.merge + models-config.plan)
- 关键职责
- 合并隐式与显式提供者配置,优先显式,保留隐式模型字段(如上下文窗口、推理标记)
- 保留现有密钥与基础 URL,避免覆盖由 secret-ref 管理的凭据
- 生成 models.json 写入计划(跳过/无操作/写入)
- 复杂度
- 合并提供者:O(P)(P 为提供者数量)
- 保留策略:O(P)(逐提供者检查)
flowchart TD
Start(["开始: 合并提供者"]) --> Implicit["读取隐式提供者"]
Implicit --> Explicit["读取显式提供者"]
Explicit --> Merge["逐提供者合并模型字段"]
Merge --> Preserve["保留现有密钥/基础URL(条件)"]
Preserve --> Plan["生成models.json计划"]
Plan --> End(["结束"])
组件D:列表与可用性(list.rows + list.registry)
- 关键职责
- 加载模型注册表与可用模型集合
- 构建模型行:标签、别名、可用性、本地标识
- 可用性优先使用模型级 getAvailable(),否则回退到提供者级认证启发式
- 过滤与排序
- 支持按提供者与本地过滤,按提供者与 ID 排序
flowchart TD
Load(["加载注册表"]) --> GetAll["getAll()"]
GetAll --> GetAvail["getAvailable()"]
GetAvail --> AvailKeys["构建可用键集"]
AvailKeys --> ToRow["构建模型行(含标签/别名/可用性)"]
ToRow --> Filter["按提供者/本地过滤"]
Filter --> Sort["排序输出"]
组件E:会话与覆盖(sessions-patch)
- 关键职责
- 会话 patch 中的 model 字段支持 null(重置为默认)、未提供(保持不变)、字符串(解析为允许模型)
- 解析允许模型引用,若目录不可用则返回 UNAVAILABLE 错误
- 将解析结果应用到会话条目,并标记是否为默认模型
sequenceDiagram
participant Sess as "会话"
participant Patch as "patch.model"
participant Cat as "模型目录"
participant Sel as "模型选择"
Sess->>Patch : 读取model字段
alt null
Patch-->>Sess : 应用默认模型(标记为默认)
else 未提供
Patch-->>Sess : 保持原模型
else 字符串
Patch->>Cat : 加载目录(若需要)
Patch->>Sel : 解析允许模型引用
Sel-->>Patch : 返回引用或错误
Patch-->>Sess : 应用覆盖(标记默认/非默认)
end
组件F:媒体理解模型筛选(media-understanding/resolve)
- 关键职责
- 合并能力配置与共享模型配置
- 若共享模型未声明能力,则尝试从提供者注册表解析能力
- 仅保留具备指定能力的模型条目
组件G:故障转移与错误恢复(failover-error)
- 关键职责
- 将通用错误归类为故障转移原因(超时、配额、鉴权、格式、模型不存在等)
- 提供错误描述与状态码映射
- 将错误转换为 FailoverError 以便上层统一处理
flowchart TD
Err(["输入错误"]) --> Classify["按HTTP状态/错误码/消息分类"]
Classify --> Timeout{"是否超时?"}
Timeout --> |是| Mark["标记为timeout"]
Timeout --> |否| Other["其他原因分类"]
Mark --> Wrap["包装为FailoverError"]
Other --> Wrap
Wrap --> Out(["输出FailoverError"])
组件H:性能评估与监控(bench-model + usage-aggregates + usage-render-overview)
- 关键职责
- 基准脚本:多次运行取中位数,统计耗时与用量
- 使用聚合:按渠道、每日、模型维度聚合成本、延迟、错误率
- UI 视图:展示吞吐、错误率、缓存命中率等指标
依赖关系分析
- 组件耦合
- model-selection 依赖 model-catalog 以进行允许性与合成条目判定
- list.rows/list.registry 依赖 model-catalog 与 PI SDK 注册表
- sessions-patch 依赖 model-selection 与 model-catalog
- failover-error 为上层统一错误处理提供抽象
- 外部依赖
- PI SDK:认证存储与模型注册表发现
- 文件系统:models.json 与认证存储文件
graph LR
MCat["model-catalog.ts"] --> MSel["model-selection.ts"]
PIdx["pi-model-discovery.ts"] --> MCat
LReg["list.registry.ts"] --> LRows["list.rows.ts"]
MCat --> LReg
MSel --> Sess["sessions-patch.ts"]
MCat --> Sess
MSel --> Media["media-understanding/resolve.ts"]
Bench["bench-model.ts"] --> MSel
Usage["usage-aggregates.ts"] --> UIV["usage-render-overview.ts"]
性能考量
- 目录加载缓存:避免重复动态导入与文件系统访问
- 合并策略:优先显式配置,减少回退路径
- 可用性探测:优先模型级可用性,必要时回退至认证启发式
- 基准测试:多轮运行取中位数,降低异常波动影响
- 监控指标:吞吐、错误率、缓存命中率、平均时延,辅助定位瓶颈
认证与权限管理
认证与权限管理相关代码主要分布在以下模块:
- 认证档案与存储:src/agents/auth-profiles/*
- 认证健康检查:src/agents/auth-health.ts
- OAuth 实现与刷新:src/agents/auth-profiles/oauth.ts
- 令牌有效期与资格评估:src/agents/auth-profiles/credential-state.ts
- 配置与密钥管理:src/secrets/*
- 文档与概念说明:docs/concepts/oauth.md、docs/gateway/authentication.md
- 系统服务与监控脚本:scripts/systemd/*、scripts/auth-monitor.sh
- 扩展插件 OAuth:extensions/*/oauth.ts
graph TB
subgraph "认证核心"
A["auth-profiles/types.ts<br/>类型定义"]
B["auth-profiles/store.ts<br/>存储加载/合并/保存"]
C["auth-profiles/oauth.ts<br/>OAuth解析/刷新/故障转移"]
D["auth-profiles/credential-state.ts<br/>令牌有效期/资格评估"]
E["auth-health.ts<br/>健康检查汇总"]
end
subgraph "配置与密钥"
F["secrets/configure.ts<br/>密钥配置解析"]
G["secrets/configure-plan.ts<br/>配置变更计划"]
H["secrets/credential-matrix.ts<br/>凭证矩阵"]
end
subgraph "文档与脚本"
I["docs/concepts/oauth.md"]
J["docs/gateway/authentication.md"]
K["scripts/systemd/*.service/*.timer"]
L["scripts/auth-monitor.sh"]
end
A --> B --> C --> D
C --> E
F --> G --> H
I --> C
J --> C
K --> L
核心组件
- 认证档案类型与使用统计:定义 api_key、token、oauth 三种凭证类型,以及每档案的使用统计(冷却、禁用、失败计数等),用于轮转与故障转移。
- 存储加载/合并/保存:支持主代理与子代理的认证档案合并;兼容旧版 auth.json 迁移;写入时对明文敏感字段进行清理。
- OAuth 解析与刷新:统一解析并生成可用的 API Key;在过期时加锁刷新;针对特定提供商提供专用刷新逻辑;失败时执行多级故障转移(主代理继承、备用档案、提示诊断)。
- 令牌有效期与资格评估:判断 access/token/expires 的有效性;为健康检查与轮转提供依据。
- 健康检查汇总:按档案与提供商聚合状态(ok/expiring/expired/missing/static),并格式化剩余时间。
- 配置与密钥管理:解析 SecretRef(env/file/exec)、构建配置变更计划、生成严格用户提供的凭证矩阵,确保只纳入不可运行时生成或轮换的凭证。
架构总览
认证系统围绕“认证档案存储”和“凭证解析/刷新”两条主线展开,并通过“健康检查”和“配置计划”实现可观测性与可维护性。
sequenceDiagram
participant Caller as "调用方"
participant Store as "认证存储<br/>store.ts"
participant OAuth as "OAuth解析/刷新<br/>oauth.ts"
participant Provider as "提供商刷新器<br/>provider refreshers"
participant Health as "健康检查<br/>auth-health.ts"
Caller->>Store : 加载/合并认证档案
Store-->>Caller : 返回合并后的档案
Caller->>OAuth : 解析指定档案的API Key
OAuth->>OAuth : 检查有效期/兼容性
alt 已过期
OAuth->>Provider : 刷新令牌(带文件锁)
Provider-->>OAuth : 新令牌/凭证
OAuth->>Store : 写回新凭证
end
OAuth-->>Caller : 返回可用API Key
Caller->>Health : 生成健康摘要
Health-->>Caller : 汇总状态与剩余时间
详细组件分析
组件A:认证档案与存储(合并、迁移、持久化)
- 加载与合并:支持主代理与子代理的档案合并;若子代理无档案则从主代理继承;运行时可合并多个代理快照。
- 兼容与迁移:自动识别并迁移旧版 auth.json;将外部 CLI 凭证同步到当前存储;删除迁移后遗留的旧文件。
- 安全写入:保存时对明文密钥进行清理,仅保留引用(keyRef/tokenRef),避免明文泄露。
- 文件锁保护:所有写操作使用文件锁,重试策略避免并发冲突。
flowchart TD
Start(["开始"]) --> Load["加载auth-profiles.json"]
Load --> Exists{"存在?"}
Exists --> |否| Legacy["尝试加载auth.json(旧版)"]
Exists --> |是| Merge["合并主/子代理档案"]
Legacy --> ApplyLegacy["应用旧版条目到新格式"]
ApplyLegacy --> Merge
Merge --> Sync["同步外部CLI凭证"]
Sync --> Save{"是否需要写入?"}
Save --> |是| Clean["清理明文密钥"]
Clean --> Persist["保存到磁盘(带文件锁)"]
Save --> |否| End(["结束"])
Persist --> End
组件B:OAuth 解析、刷新与故障转移
- 模式兼容:允许 token 与 oauth 在某些场景互换(Bearer 场景)。
- 解析流程:先检查本地有效期,未过期直接返回;过期则加锁刷新。
- 提供商专用刷新:针对 chutes、qwen-portal 等提供专用刷新逻辑;通用提供商通过统一接口刷新。
- 故障转移:
- 若刷新失败且存在较新的主代理凭证,则采用主代理凭证;
- 尝试备用档案(基于默认档案修复建议);
- 若仍失败,尝试从主代理复制新鲜凭证到当前代理;
- 特定提供商(如 openai-codex)在特定错误条件下使用缓存的 access token 作为回退;
- 最终抛出带诊断提示的错误信息。
sequenceDiagram
participant API as "调用方"
participant OA as "OAuth解析<br/>oauth.ts"
participant Lock as "文件锁"
participant Prov as "提供商刷新器"
participant Main as "主代理存储"
API->>OA : 解析档案API Key
OA->>OA : 检查有效期
alt 未过期
OA-->>API : 直接返回
else 已过期
OA->>Lock : 获取文件锁
Lock-->>OA : 成功
OA->>Prov : 刷新令牌
alt 刷新成功
Prov-->>OA : 新凭证
OA->>OA : 写回存储
OA-->>API : 返回新API Key
else 失败
OA->>Main : 检查主代理是否有更新凭证
alt 主代理有更新
Main-->>OA : 返回新凭证
OA-->>API : 返回新API Key
else 回退策略
OA-->>API : 抛出错误(含诊断提示)
end
end
end
组件C:令牌有效期与资格评估
- 令牌状态:缺失、有效、已过期、无效(非数值/非正数)。
- 资格评估:对 api_key/token/oauth 分别校验是否存在有效凭据;对 token 还需检查 expires 字段有效性与是否过期。
flowchart TD
S(["开始"]) --> Type{"凭证类型?"}
Type --> |api_key| CheckAK["校验key或keyRef是否存在"]
Type --> |token| CheckTok["校验token或tokenRef<br/>并检查expires"]
Type --> |oauth| CheckOauth["校验access或refresh是否存在"]
CheckAK --> AKOK{"有效?"}
CheckTok --> TokOK{"有效?"}
CheckOauth --> OauthOK{"有效?"}
AKOK --> |是| OK["返回可用"]
AKOK --> |否| Err["返回不可用及原因"]
TokOK --> |是| OK
TokOK --> |否| Err
OauthOK --> |是| OK
OauthOK --> |否| Err
组件D:认证健康检查与状态监控
- 按档案与提供商聚合状态,区分 ok/expiring/expired/missing/static。
- 对 OAuth 与 token:当存在有效 refresh_token 时,即使 access 过期也不警告,因为会自动续期。
- 支持自定义告警阈值(默认 24 小时),并提供短格式剩余时间展示。
flowchart TD
HStart(["开始"]) --> Build["构建档案健康列表"]
Build --> Group["按提供商分组"]
Group --> Status["计算提供商状态"]
Status --> Warn{"是否接近过期?"}
Warn --> |是| Expiring["标记为即将过期"]
Warn --> |否| Ok["标记为正常"]
Expiring --> HEnd(["输出汇总"])
Ok --> HEnd
组件E:API 密钥轮换与实时认证键处理
- 轮换顺序(网关环境变量):OPENCLAW_LIVE__KEY > _API_KEYS > _API_KEY > API_KEY*。
- 仅在速率限制类错误(如 429、rate_limit、quota、resource exhausted)时进行轮换。
- 合法性与去重:轮换前对密钥列表去重,最终失败返回最后一次尝试的错误。
组件F:认证配置合并、优先级排序与故障恢复
- 合并策略:主代理与子代理档案合并,后者覆盖前者同名项;版本取较大者。
- 优先级排序:支持 per-agent 的 auth.order 覆盖全局配置,按 provider 分组的 profileId 列表决定首选顺序。
- 故障恢复:当某档案不可用时,系统尝试备用档案或从主代理继承;若仍失败,输出诊断提示并抛错。
组件G:安全策略、令牌管理与访问控制
- 凭证表面:严格限定“用户直接提供”的凭证,不包含运行时生成或轮换的凭证;生成严格凭证矩阵,标注排除项。
- 权限审计:对凭据目录进行权限检查(可写/可读),给出修复建议(POSIX 权限模式 0700)。
- 机密输入:支持 env/file/exec 三类 SecretRef;在保存时清理明文,仅保留引用。
依赖关系分析
- 类型依赖:types.ts 为其他模块提供统一的数据结构;store.ts 依赖 types.ts;oauth.ts 依赖 store.ts 与 credential-state.ts。
- 外部集成:oauth.ts 依赖 @mariozechner/pi-ai 的 OAuth 提供商能力;针对特定提供商(如 qwen-portal、chutes)有专用刷新器。
- 配置与密钥:configure.ts 与 configure-plan.ts 依赖 secrets 解析与凭证矩阵,确保变更可控与可审计。
graph LR
Types["types.ts"] --> Store["store.ts"]
Store --> OAuth["oauth.ts"]
State["credential-state.ts"] --> OAuth
OAuth --> Health["auth-health.ts"]
SecCfg["secrets/configure.ts"] --> Plan["secrets/configure-plan.ts"]
Plan --> Matrix["secrets/credential-matrix.ts"]
性能考量
- 文件锁与重试:写操作采用指数回退与最大超时,降低并发写入冲突概率。
- 运行时快照:支持多代理运行时快照合并,减少重复 IO。
- 健康检查:按提供商聚合状态,避免对每个档案单独检查带来的开销。
- 轮换策略:仅在速率限制错误时切换密钥,避免不必要的网络往返。
沙箱与安全机制
围绕“沙箱与安全”的关键模块分布于 agents/sandbox 及其子模块,配合配置校验、路径与媒体处理、工具策略与文件系统策略等模块协同工作,形成从配置到运行时的完整安全闭环。
graph TB
subgraph "沙箱核心"
A["validate-sandbox-security.ts<br/>安全校验与拒绝列表"]
B["host-paths.ts<br/>主机路径归一化/解析"]
C["constants.ts<br/>默认镜像/前缀/端口/注册表路径"]
D["network-mode.ts<br/>网络模式阻断判定"]
E["bind-spec.ts<br/>绑定规范解析"]
F["docker.ts<br/>构建创建参数/执行docker"]
G["sandbox-paths.ts<br/>沙箱路径解析/边界检查"]
H["sandbox-media-paths.ts<br/>媒体路径解析/桥接"]
I["sandbox-tool-policy.ts<br/>工具策略合并"]
J["tool-fs-policy.ts<br/>工具文件系统策略"]
end
subgraph "配置与测试"
K["zod-schema.agent-runtime.ts<br/>Zod配置校验"]
L["config.sandbox-docker.test.ts<br/>配置测试"]
M["sandbox-create-args.test.ts<br/>创建参数测试"]
N["sandbox-paths.test.ts<br/>路径测试"]
O["sandbox-media-paths.test.ts<br/>媒体路径测试"]
P["sandbox-tool-policy.test.ts<br/>工具策略测试"]
Q["tool-fs-policy.test.ts<br/>工具FS策略测试"]
R["validate-sandbox-security.test.ts<br/>安全校验测试"]
end
A --> F
B --> A
C --> F
D --> A
E --> A
G --> H
I --> J
K --> A
K --> F
L --> K
M --> F
N --> G
O --> H
P --> I
Q --> J
R --> A
核心组件
- 安全校验与拒绝列表:对绑定挂载、网络模式、安全配置(seccomp/AppArmor)进行严格校验,阻止高危配置。
- 主机路径处理:路径归一化、通过现有祖先解析以规避符号链接逃逸。
- 常量与默认值:默认镜像、容器前缀、工作目录、浏览器专用网络与端口、注册表路径等。
- 网络模式阻断:禁止 host 模式与容器命名空间加入,确保网络隔离。
- 绑定规范解析:解析 host:container[:options] 规范,支持 Windows 驱动器前缀。
- Docker 创建参数构建:将安全校验结果与资源限制、能力(drop/no-new-privileges)、安全选项(seccomp/apparmor)、DNS/hosts 等注入到 docker create 参数。
- 路径与媒体策略:路径边界检查、相对路径展开、file:// 与 http:// 处理、临时媒体目录白名单。
- 工具策略与文件系统策略:允许/拒绝工具集合的合并与生效;工具仅限工作区访问的策略解析。
架构总览
下图展示沙箱创建与安全校验在运行时的关键交互流程。
sequenceDiagram
participant Caller as "调用方"
participant Builder as "buildSandboxCreateArgs"
participant Validator as "validateSandboxSecurity"
participant Docker as "execDocker"
participant FS as "宿主机文件系统"
Caller->>Builder : 提供SandboxDockerConfig与上下文
Builder->>Validator : 传入binds/network/seccomp/apparmor等
Validator-->>Builder : 返回校验结果或抛出错误
Builder->>Docker : 生成docker create参数并执行
Docker->>FS : 写入标签/挂载/安全选项
Docker-->>Caller : 返回容器名/状态
详细组件分析
安全校验与拒绝列表
- 目标:阻止危险的 Docker 配置,包括系统路径暴露、保留容器目标路径、非绝对源路径、host 网络、容器命名空间加入、禁用 seccomp/AppArmor 等。
- 关键点:
- BLOCKED_HOST_PATHS:禁止挂载 /etc、/proc、/sys、/dev、/root、/boot、常见 Docker 套接字路径等。
- BLOCKED_SECCOMP_PROFILES/BLOCKED_APPARMOR_PROFILES:禁用 unconfined。
- RESERVED_CONTAINER_TARGET_PATHS:禁止覆盖 /workspace 与代理工作区挂载点。
- getBlockedBindReason/getOutsideAllowedRootsReason/getReservedTargetReason:三类拒绝原因。
- enforceSourcePathPolicy:结合 allowedRoots 与 allowSourcesOutsideAllowedRoots 进行策略判断。
- validateNetworkMode:阻断 host 与 container:*(除非显式允许)。
- validateSeccompProfile/validateApparmorProfile:阻断禁用配置。
flowchart TD
Start(["进入 validateBindMounts"]) --> CheckEmpty{"binds为空?"}
CheckEmpty --> |是| EndOK["返回"]
CheckEmpty --> |否| Loop["遍历每个bind"]
Loop --> FastCheck["字符串级阻断检查<br/>getBlockedBindReason"]
FastCheck --> Blocked{"被拒绝?"}
Blocked --> |是| ThrowFast["抛出错误"]
Blocked --> |否| Reserved{"允许保留目标?"}
Reserved --> |否| CheckReserved["getReservedTargetReason"]
CheckReserved --> ReservedBlocked{"命中保留目标?"}
ReservedBlocked --> |是| ThrowReserved["抛出错误"]
ReservedBlocked --> |否| Normalize["normalizeHostPath"]
ReservedBlocked --> |是| Normalize
Normalize --> Policy["enforceSourcePathPolicy"]
Policy --> Ancestor["通过现有祖先解析<br/>resolveSandboxHostPathViaExistingAncestor"]
Ancestor --> Policy2["再次 enforceSourcePathPolicy"]
Policy2 --> Next["下一个bind"]
Next --> Loop
Loop --> EndOK
主机路径处理与符号链接硬防
- 归一化:POSIX 路径规范化(.、..、//、尾部斜杠),Windows 前缀剥离与 UNC 规范化。
- 解析:通过现有祖先解析,即使最终叶子不存在也能正确识别真实父链,防止符号链接逃逸。
flowchart TD
A["输入原始路径"] --> B["stripWindowsNamespacePrefix"]
B --> C["posix.normalize + 去除尾斜杠"]
C --> D{"是否为空?"}
D --> |是| E["返回'/'"]
D --> |否| F["返回规范化路径"]
常量与默认值
- 默认镜像、容器前缀、工作目录、空闲/最大存活时间。
- 默认工具允许/拒绝清单(如 exec、process、read/write/edit、apply_patch、image、会话相关工具等)。
- 浏览器沙箱镜像与通用镜像、浏览器网络与端口、自动启动超时。
- 代理工作区挂载点、状态目录与注册表路径。
网络模式阻断
- 归一化网络模式后,阻断 host 与 container:*(除非允许容器命名空间加入)。
- isDangerousNetworkMode 提供快速判定。
绑定规范解析
- 支持 host:container[:options],兼容 Windows 驱动器前缀与 UNC。
- 用于解析源/目标路径与可选挂载选项。
Docker 创建参数构建与执行
- 构建阶段:
- 先执行 validateSandboxSecurity,再拼装标签、只读根文件系统、tmpfs、网络、用户、环境变量(含敏感项阻断/告警)、能力 drop、no-new-privileges、seccomp/apparmor、DNS/hosts、PID/内存/CPU/ulimit、binds。
- 自动追加工作区挂载与自定义 binds。
- 执行阶段:
- 确保镜像存在,创建容器并启动;可选执行 setupCommand。
- 注册表更新与热容器窗口提示。
sequenceDiagram
participant Cfg as "SandboxDockerConfig"
participant Args as "buildSandboxCreateArgs"
participant Sec as "validateSandboxSecurity"
participant Exec as "execDocker"
participant Reg as "注册表"
Cfg->>Args : 传入配置与上下文
Args->>Sec : 安全校验
Sec-->>Args : 通过或抛错
Args->>Exec : docker create + start
Exec-->>Reg : 更新容器信息
Reg-->>Args : 返回容器名
沙箱路径管理
- 输入路径解析:支持
、/ 前缀展开、相对路径转绝对、Unicode 空格规范化。 - 边界检查:assertSandboxPath 确保相对路径不逃逸沙箱根,使用路径别名守卫避免符号/硬链接逃逸。
- 媒体路径处理:
- 不支持 data: URL;file:// URL 与 http:// URL 分别处理。
- 将容器内 /workspace 映射回宿主机工作区或临时媒体目录(受控白名单)。
- 临时媒体目录必须位于 OpenClaw 临时目录内且不逃逸。
flowchart TD
S["输入媒体路径"] --> T{"是否为file://或http://?"}
T --> |http://| U["直接返回URL"]
T --> |file://| V["尝试映射容器/workspace"]
V --> W{"映射成功?"}
W --> |是| X["返回映射后的宿主机路径"]
W --> |否| Y["fileURLToPath转换"]
Y --> Z["映射容器/workspace或临时目录"]
T --> |都不是| Z
Z --> A{"是否在临时目录?"}
A --> |是| B["校验不逃逸临时根"]
A --> |否| C["assertSandboxPath校验"]
B --> D["返回宿主机路径"]
C --> D
工具策略与文件系统策略
- 工具策略:
- pickSandboxToolPolicy 合并 allow/alsoAllow/deny,支持通配符与 apply_patch 特例。
- 文件系统策略:
- resolveEffectiveToolFsWorkspaceOnly 基于全局与代理配置解析 workspaceOnly 策略,强制工具仅访问工作区。
依赖关系分析
- validateSandboxSecurity 依赖:
- bind-spec:解析绑定规范
- host-paths:路径归一化与祖先解析
- network-mode:网络模式阻断
- constants:代理工作区挂载常量
- docker.ts 依赖:
- validateSandboxSecurity:运行时安全校验
- constants:默认镜像/前缀/注册表路径
- sanitize-env-vars:环境变量阻断/告警
- sandbox-paths 与 sandbox-media-paths 依赖:
- path-alias-guards/path-guards:边界与别名检查
- tmp-openclaw-dir:临时目录解析
graph LR
VS["validate-sandbox-security.ts"] --> BS["bind-spec.ts"]
VS --> HP["host-paths.ts"]
VS --> NM["network-mode.ts"]
VS --> CT["constants.ts"]
DK["docker.ts"] --> VS
DK --> CT
DK --> EV["sanitize-env-vars.js"]
SP["sandbox-paths.ts"] --> PG["path-guards.js"]
SP --> PA["path-alias-guards.js"]
SP --> TMP["tmp-openclaw-dir.js"]
SMP["sandbox-media-paths.ts"] --> SP
性能考量
- 路径解析与边界检查为纯字符串与少量文件系统 I/O,开销较低。
- 安全校验在创建前集中执行,避免运行期反复校验。
- 通过只读根文件系统、tmpfs、ulimit、CPU/内存限制降低容器资源占用风险。
- 热容器窗口(最近使用)提示减少频繁重建带来的开销。
AI 代理系统
OpenClaw 采用“网关控制平面 + 多通道接入 + 代理运行时”的分层架构:
- 网关(Gateway)作为统一控制平面,承载会话、路由、事件与工具调用编排;
- 代理运行时以 Pi 代理为核心,支持嵌入式运行、工具流式与块流式输出;
- 通过插件化渠道适配器连接 WhatsApp、Telegram、Discord、iMessage 等消息平台;
- 提供 CLI、Web 控制台与移动端节点,形成完整的本地优先、自托管智能体生态。
graph TB
subgraph "客户端与入口"
UI["Web 控制台"]
CLI["命令行(openclaw ...)"]
Nodes["iOS/Android 节点"]
end
subgraph "网关控制平面"
GW["Gateway WebSocket 控制面"]
Sessions["会话与路由"]
Tools["工具与动作编排"]
end
subgraph "代理运行时"
Pi["Pi 代理(嵌入式)"]
Streams["工具流式/块流式输出"]
end
subgraph "渠道适配"
WA["WhatsApp 插件"]
TG["Telegram 插件"]
DC["Discord 插件"]
IM["iMessage/BlueBubbles 插件"]
end
UI --> GW
CLI --> GW
Nodes --> GW
GW --> Sessions
GW --> Tools
GW --> Pi
Pi --> Streams
Tools --> WA
Tools --> TG
Tools --> DC
Tools --> IM
核心组件
- 代理运行时与生命周期
- 嵌入式 Pi 代理运行器负责执行推理、工具调度、流式输出与运行状态管理。
- 关键导出包括运行控制(启动/队列/中止/等待结束)、历史限制与会话车道解析、沙箱信息构建、系统提示覆盖与工具拆分等。
- 消息与工具
- 统一的消息工具识别与发送判定逻辑,支持核心消息工具与各渠道插件的动作提取。
- 块级回复载荷结构用于组织文本、媒体、语音与回执标记。
- 认证与凭据
- 将认证档案转换为 Pi 代理可用的 API Key 或 OAuth 凭据映射,并进行相等性比较。
- 辅助与错误分类
- 错误分类与降级策略、图像与转录内容清洗、Turn 序列校验、思维层级降级等。
- 运行时环境
- 标准 I/O 输出与退出行为封装,便于测试与非退出模式使用。
架构总览
下图展示从消息入口到代理执行、工具调用与响应返回的端到端流程,强调会话与上下文在代理运行时中的作用。
sequenceDiagram
participant User as "用户"
participant Channel as "渠道插件(如 Telegram)"
participant GW as "网关控制平面"
participant Runner as "Pi 代理运行器"
participant Tools as "工具/动作编排"
participant Out as "外部服务/渠道"
User->>Channel : 发送消息
Channel->>GW : 解析并转发消息事件
GW->>Runner : 触发会话上下文加载与推理
Runner->>Runner : 工具调用计划与流式/块式生成
Runner->>Tools : 执行具体工具(消息发送/节点动作/浏览器控制等)
Tools->>Out : 调用外部接口或设备能力
Out-->>Tools : 返回结果
Tools-->>Runner : 工具执行结果
Runner-->>GW : 流式/块式输出与最终回复
GW-->>Channel : 将回复投递至对应渠道
Channel-->>User : 展示最终消息
详细组件分析
代理运行时与生命周期
- 运行器职责
- 启动/排队/中止/等待嵌入式 Pi 代理运行,维护运行元数据与结果。
- 历史回合限制与会话车道解析,确保上下文规模可控与并发会话隔离。
- 沙箱信息构建与系统提示覆盖,满足不同场景下的安全与提示一致性。
- 工具拆分与额外参数应用,提升跨模型兼容性与运行稳定性。
- 生命周期管理
- 通过运行状态查询与等待结束,实现对长尾任务的可观测与可中断。
- 结合会话修剪与紧凑化策略,降低上下文开销并维持长期对话质量。
flowchart TD
Start(["开始运行"]) --> Load["加载会话上下文<br/>解析历史限制/车道"]
Load --> Plan["生成工具调用计划"]
Plan --> Stream{"是否需要流式输出?"}
Stream --> |是| Chunk["块流式/工具流式输出"]
Stream --> |否| Final["生成最终回复"]
Chunk --> Monitor["监控运行状态/队列"]
Final --> Monitor
Monitor --> Done(["结束/等待下一轮"])
会话管理与上下文保持
- 会话键与历史限制
- 支持基于会话键的历史回合裁剪,兼顾 DM 与群组场景的差异化上限。
- 上下文紧凑化
- 提供紧凑化能力以减少上下文长度,缓解超限风险并保持语义连贯。
- 会话车道
- 会话车道解析用于区分不同运行路径或优先级,保障资源分配与隔离。
工具流式传输与块流式处理
- 工具与消息工具识别
- 统一识别核心消息工具与各渠道插件的动作,确保发送类工具被正确提取与执行。
- 块级回复载荷
- 文本、媒体 URL、音频转语音、推理标记、回执标识与回复目标等字段构成块级输出的基础结构。
- 流式输出
- 在工具执行与模型生成过程中,按块推送中间结果,提升交互体验与可观测性。
classDiagram
class MessagingToolSend {
+tool : string
+provider : string
+accountId? : string
+to? : string
+threadId? : string
}
class BlockReplyPayload {
+text? : string
+mediaUrls? : string[]
+audioAsVoice? : boolean
+isReasoning? : boolean
+replyToId? : string
+replyToTag? : boolean
+replyToCurrent? : boolean
}
MessagingToolSend <.. BlockReplyPayload : "组合/传递"
代理配置、模型选择与认证轮换
- 模型选择
- 通过标准化的提供方 ID 归一化与凭据映射,支持多提供商与多模型的灵活切换。
- 认证轮换
- 将认证档案转换为 API Key 或 OAuth 凭据,自动处理过期与刷新条件,保证连续可用性。
- 故障转移策略
- 错误分类与降级策略(如速率限制、计费错误、上下文溢出、超时等),结合备用凭据与备用模型实现自动切换。
flowchart TD
A["输入认证档案"] --> B["归一化提供方ID"]
B --> C{"类型判断(API Key/Token/OAuth)"}
C --> |API Key| D["直接映射"]
C --> |Token| E["检查过期/转换为API Key"]
C --> |OAuth| F["提取访问/刷新/过期时间"]
D --> G["凭据映射完成"]
E --> G
F --> G
G --> H["错误分类与降级策略"]
H --> I["故障转移/重试/备用凭据"]
代理沙箱机制、安全隔离与权限控制
- 沙箱模式
- 非主会话(群组/频道)默认启用容器化沙箱,限制工具集与文件系统访问,仅允许必要工具(如会话列表/历史/发送等)。
- 权限控制
- macOS 节点通过网关协议暴露能力与权限映射,本地动作需遵循 TCC 状态;可按会话启用/禁用“提升权限”模式并持久化。
- 安全建议
- 默认仅主会话拥有主机执行权限;群组/频道会话置于沙箱内运行,避免越权操作。
代理生命周期管理、状态持久化与性能优化
- 生命周期
- 运行器提供运行状态查询、队列注入、中止与结束等待,便于长任务与并发场景的精细化控制。
- 状态持久化
- macOS 场景下,会话的思考级别、详细程度、模型、发送策略与群组激活等可通过会话补丁持久化。
- 性能优化
- 历史回合裁剪、上下文紧凑化、Turn 序列校验与图像/转录内容清洗,降低计算与存储压力。
- 思维层级降级与工具拆分提升跨模型兼容性与稳定性。
多代理路由、会话隔离与资源管理
- 多代理路由
- 支持按发送者、工作区与代理维度进行会话隔离与路由,实现多代理协作与资源隔离。
- 会话隔离
- 不同会话拥有独立上下文与工具执行边界,避免相互干扰。
- 资源管理
- 通过会话车道、历史限制与沙箱策略,平衡并发度与资源占用。
依赖关系分析
- 运行时 I/O
- 运行时封装了日志输出与进程退出,支持测试环境下的非退出模式,便于单元测试与集成测试。
- 代理运行器
- 导出运行控制、历史限制、车道解析、沙箱信息、系统提示覆盖、工具拆分与类型定义,形成代理执行的统一入口。
- 消息与工具
- 消息工具识别与发送判定依赖渠道插件的动作提取能力,形成“核心工具 + 插件动作”的扩展模型。
- 辅助与错误分类
- 错误分类与降级策略贯穿代理执行链路,配合凭据映射与 Turn 校验,提升鲁棒性。
graph LR
RT["runtime.ts"] --> ER["pi-embedded-runner.ts"]
ER --> EM["pi-embedded-messaging.ts"]
ER --> EP["pi-embedded-payloads.ts"]
ER --> EH["pi-embedded-helpers.ts"]
EH --> AC["pi-auth-credentials.ts"]
性能考量
- 上下文规模控制
- 使用历史回合裁剪与上下文紧凑化,避免超限导致的失败与延迟。
- 流式输出
- 工具流式与块流式输出缩短首包延迟,改善用户体验。
- Turn 校验与内容清洗
- 对 Turn 序列与图像/媒体内容进行清洗与降级,减少无效负载与错误重试。
- 思维层级降级
- 在高负载或不稳定网络下自动降级思维层级,维持稳定响应。
Pi 嵌入式运行时
Pi 嵌入式运行时位于 src/agents 下,核心入口为 pi-embedded.ts,实际运行逻辑集中在 pi-embedded-runner 子目录;配套的订阅、工具、扩展、系统提示、历史限制、沙箱信息、会话缓存、压缩安全护栏与上下文修剪等模块共同构成完整的嵌入式运行时。
graph TB
A["pi-embedded.ts<br/>导出运行与状态查询接口"] --> B["pi-embedded-runner.ts<br/>再导出运行器子模块"]
B --> C["run.ts<br/>runEmbeddedPiAgent 主入口"]
C --> D["run/attempt.ts<br/>单次尝试与会话初始化"]
C --> E["subscribeEmbeddedPiSession<br/>事件订阅与流式处理"]
C --> F["compact.ts<br/>手动/自动压缩"]
C --> G["model.ts<br/>模型解析与鉴权"]
C --> H["system-prompt.ts<br/>系统提示构建"]
C --> I["tool-split.ts<br/>工具拆分策略"]
C --> J["history.ts<br/>历史限制"]
C --> K["google.ts<br/>Google/Gemini 兼容处理"]
C --> L["sandbox-info.ts<br/>沙箱信息"]
C --> M["session-manager-cache.ts<br/>会话缓存"]
C --> N["extensions.ts<br/>扩展加载"]
C --> O["compaction-safety-timeout.ts<br/>压缩安全超时"]
C --> P["payloads.ts<br/>响应负载构建"]
C --> Q["block-chunker.ts<br/>块级流式分块"]
C --> R["messaging.ts<br/>消息发送追踪"]
C --> S["helpers.ts<br/>错误分类与校验"]
核心组件
- 运行器入口与状态查询
- 导出 runEmbeddedPiAgent、queueEmbeddedPiMessage、waitForEmbeddedPiRunEnd、isEmbeddedPiRunActive、isEmbeddedPiRunStreaming、abortEmbeddedPiRun、compactEmbeddedPiSession、resolveEmbeddedSessionLane 等接口,统一对外暴露嵌入式运行时能力。
- 运行时类型与元数据
- EmbeddedPiRunMeta/EmbeddedPiRunResult/EmbeddedPiCompactResult 等类型定义运行元信息、运行结果与压缩结果。
- 会话与订阅
- subscribeEmbeddedPiSession 订阅 AgentSession 事件,驱动流式文本、思考、工具执行、回合与自动压缩等事件的回调处理。
- 工具与系统提示
- createOpenClawCodingTools 构建工具集;splitSdkTools 将工具全部归入 customTools;system-prompt 构建动态系统提示。
- 历史与上下文
- history 限制 DM 与群组历史;context-engine 类型定义上下文组装与压缩结果;session-manager-cache 缓存会话以提升性能。
- 扩展与兼容
- extensions 加载压缩安全护栏与上下文修剪扩展;google 处理 Gemini 转写顺序与工具 schema;compaction-safety-timeout 保护压缩过程。
- 消息与块级流式
- block-chunker 将流式文本切分为块;payloads 负责从运行结果构建响应负载;messaging 追踪消息发送目标与媒体。
架构总览
Pi 嵌入式运行时采用“直接 SDK 引入 + 事件驱动”的架构:通过 createAgentSession 创建会话,随后订阅 AgentSession 事件,结合系统提示、工具链、历史限制与扩展,完成一次完整的嵌入式运行周期。运行器还提供队列消息、等待运行结束、主动中断、会话压缩等运行期能力。
sequenceDiagram
participant Caller as "调用方"
participant Runner as "运行器<br/>runEmbeddedPiAgent"
participant Session as "AgentSession"
participant Sub as "订阅器<br/>subscribeEmbeddedPiSession"
participant Tools as "工具集"
participant Ext as "扩展"
participant Store as "会话存储"
Caller->>Runner : "传入参数与回调"
Runner->>Session : "创建会话(createAgentSession)"
Runner->>Sub : "订阅事件(流式文本/思考/工具/回合/压缩)"
Runner->>Session : "prompt(有效提示)"
Session-->>Sub : "事件(message/tool/turn/compaction)"
Sub-->>Caller : "onBlockReply/onPartialReply/..."
Runner->>Tools : "执行工具调用"
Tools-->>Session : "返回工具结果"
Runner->>Ext : "应用扩展(压缩/修剪)"
Runner->>Store : "持久化会话(缓存/修复)"
Runner-->>Caller : "返回运行结果与元数据"
详细组件分析
运行器初始化与会话生命周期
- 初始化阶段
- 解析模型与鉴权、准备沙箱上下文、构建系统提示、加载扩展、预热会话缓存、修复会话文件、应用转录策略与工具允许列表。
- 会话创建
- 使用 DefaultResourceLoader 注册扩展工厂并 reload;通过 createAgentSession 创建会话,应用系统提示覆盖。
- 生命周期事件
- 订阅 message/tool/turn/agent/compaction 等事件,驱动流式输出与工具执行。
flowchart TD
Start(["开始"]) --> ResolveModel["解析模型与鉴权"]
ResolveModel --> Sandbox["解析沙箱上下文"]
Sandbox --> SysPrompt["构建系统提示"]
SysPrompt --> Ext["加载扩展工厂并reload"]
Ext --> Session["创建AgentSession"]
Session --> ApplyPrompt["应用系统提示覆盖"]
ApplyPrompt --> WarmCache["预热会话缓存/修复会话"]
WarmCache --> Ready(["就绪"])
Ready --> Prompt["prompt(有效提示)"]
Prompt --> Events["事件驱动(流式/工具/回合/压缩)"]
Events --> End(["结束/返回结果"])
会话订阅与消息处理
- 订阅器职责
- 接收 AgentSession 事件,将流式文本与思考内容按块分发给 onBlockReply/onPartialReply;处理工具执行、回合与自动压缩事件。
- 块级流式分块
- EmbeddedBlockChunker 将连续流式片段聚合成块,剥离思考标签,提取最终内容与回复指令(媒体、语音、回复ID)。
- 消息发送追踪
- pi-embedded-messaging 记录通过消息工具发送成功的文本、媒体与目标,用于抑制确认文本与统计。
sequenceDiagram
participant Sub as "订阅器"
participant Chunk as "块分块器"
participant Handler as "回调(onBlockReply/onPartialReply)"
participant Msg as "消息追踪"
Sub->>Chunk : "接收流式文本"
Chunk-->>Handler : "块级文本/媒体/指令"
Handler-->>Msg : "记录发送成功项"
Handler-->>Sub : "触发回调"
历史记录管理与上下文保持
- 历史限制
- 根据会话键与配置决定 DM 与群组的历史轮次限制,减少上下文开销。
- 历史清洗与配对修复
- 在截断后重新修复 tool_use 与 tool_result 的配对关系,保证上下文一致性。
- 上下文引擎
- context-engine/types 定义上下文组装、压缩与引导结果的数据结构,支撑运行期上下文度量与报告。
flowchart TD
Load["读取会话消息"] --> Sanitize["历史清洗(Gemini/Anthropic校验)"]
Sanitize --> Truncate["按渠道类型截断历史轮次"]
Truncate --> Repair["修复tool_use/tool_result配对"]
Repair --> Apply["应用到会话消息"]
Apply --> Report["生成上下文度量与报告"]
嵌入式工具定义与消息提供者策略
- 工具拆分策略
- splitSdkTools 将所有工具放入 customTools,确保 OpenClaw 的策略过滤、沙箱集成与扩展工具集一致。
- 工具定义适配
- 将 AgentTool 的 execute 签名适配为 ToolDefinition,保证与 pi-coding-agent 的调用约定一致。
- 消息提供者策略
- 根据通道能力与配置,注入 inlineButtons、反应指导、消息动作提示等,影响系统提示与行为。
classDiagram
class ToolSplit {
+splitSdkTools(options) : {builtInTools, customTools}
}
class Adapter {
+toToolDefinitions(tools) : ToolDefinition[]
}
class ProviderPolicy {
+channelCapabilities
+inlineButtons
+reactionGuidance
+messageToolHints
}
ToolSplit --> Adapter : "转换为ToolDefinition"
ProviderPolicy --> ToolSplit : "影响工具允许列表"
模型兼容性与提供商特定处理
- 模型解析与鉴权
- resolveModel 通过 ModelRegistry 与 AuthStorage 获取模型与密钥;针对 GitHub Copilot 等特殊场景进行令牌转换。
- 提供商特定处理
- Google/Gemini:turn ordering 修复、工具 schema 清理、历史清洗;Anthropic:拒绝文本清理、回合校验;OpenAI:apply_patch 工具与思考级别降级。
- 流式参数与 Ollama
- extra-params 提供提供商特定流式参数;Ollama 通过自定义流函数注册,确保本地模型兼容。
flowchart TD
Resolve["resolveModel"] --> Auth["鉴权存储(setRuntimeApiKey)"]
Auth --> Provider["提供商特定处理"]
Provider --> Google["Google/Gemini: turn/ordering/schema"]
Provider --> Anthropic["Anthropic: 拒绝/回合校验"]
Provider --> OpenAI["OpenAI: apply_patch/降级"]
Provider --> Ollama["Ollama: 自定义流函数注册"]
嵌入式运行时配置与运行期能力
- 运行期状态查询
- isEmbeddedPiRunActive/isEmbeddedPiRunStreaming 查询运行状态;queueEmbeddedPiMessage 向正在流式的运行追加消息;waitForEmbeddedPiRunEnd 等待运行结束。
- 会话与命令通道
- resolveEmbeddedSessionLane/全局 lanes 控制并发与优先级,避免死锁。
- 压缩与安全护栏
- compactEmbeddedPiSessionDirect 执行手动/自动压缩;compaction-safety-timeout 保护压缩过程;compaction-safeguard 与 context-pruning 扩展提供额外保障。
sequenceDiagram
participant API as "外部API"
participant Runs as "运行状态管理"
participant Lane as "命令通道"
participant Comp as "压缩"
API->>Runs : "queueEmbeddedPiMessage"
Runs-->>API : "是否入队成功"
API->>Lane : "resolveEmbeddedSessionLane"
Lane-->>API : "分配会话/全局通道"
API->>Comp : "compactEmbeddedPiSession"
Comp-->>API : "压缩结果与原因"
助手身份、历史与上下文保持
- 助手身份
- UI 层提供默认名称与头像,normalizeAssistantIdentity 统一输入,确保跨渠道一致性。
- 历史与上下文
- 通过历史限制、转录策略与上下文引擎,维持合理的上下文窗口与历史长度,避免溢出。
节点订阅与网关集成
- 节点订阅管理
- server-node-subscriptions 提供节点到会话的订阅映射,支持向指定会话广播事件;gateway-misc.test 展示事件路由与取消订阅行为。
- 会话事件分发
- 通过 sendToSession/sendToAllSubscribed 将运行期事件推送到已订阅节点,便于网关侧统一消费。
sequenceDiagram
participant Manager as "节点订阅管理器"
participant NodeA as "节点A"
participant NodeB as "节点B"
Manager->>NodeA : "订阅会话(main)"
Manager->>NodeB : "订阅会话(main)"
Manager->>Manager : "sendToSession('main', 'chat', payload)"
Manager-->>NodeA : "事件(chat)"
Manager-->>NodeB : "事件(chat)"
Manager->>NodeA : "unsubscribeAll(nodeA)"
Manager->>Manager : "sendToSession('main','tick',...)"
Manager-->>NodeB : "事件(tick)"
开发指南、自定义实现与调试技巧
- 开发指南
- 使用 runEmbeddedPiAgent 作为统一入口;通过 onBlockReply/onPartialReply 获取流式输出;必要时使用 queueEmbeddedPiMessage 追加用户消息。
- 自定义实现
- 工具:通过 createOpenClawCodingTools 注入自定义工具;使用 tool-split 与 policy 控制可用工具集合。
- 提示:通过 system-prompt 构建动态系统提示,注入渠道能力、反应指导、消息动作提示与沙箱信息。
- 扩展:通过 extensions 加载压缩安全护栏与上下文修剪扩展,增强稳定性与性能。
- 调试技巧
- 启用日志与诊断:logger 提供子系统日志;compaction-diag 输出压缩前后的消息统计与贡献者分析。
- 错误分类:helpers 提供上下文溢出、压缩失败、鉴权失败、限流等错误分类,辅助快速定位问题。
- 等待运行结束:waitForEmbeddedPiRunEnd 提供超时控制,避免阻塞。
依赖关系分析
Pi 嵌入式运行时依赖 pi-* 生态包(pi-agent-core、pi-ai、pi-coding-agent、pi-tui),并通过 OpenClaw 的工具、系统提示、历史限制、扩展与会话管理形成闭环。
graph TB
OpenClaw["OpenClaw 运行时"] --> PiCore["@mariozechner/pi-agent-core"]
OpenClaw --> PiAI["@mariozechner/pi-ai"]
OpenClaw --> PiCoding["@mariozechner/pi-coding-agent"]
OpenClaw --> PiTUI["@mariozechner/pi-tui"]
OpenClaw --> Tools["OpenClaw 工具集"]
OpenClaw --> Prompt["系统提示构建"]
OpenClaw --> History["历史限制/清洗"]
OpenClaw --> Ext["Pi 扩展(压缩/修剪)"]
OpenClaw --> Session["会话缓存/修复"]
性能考量
- 会话缓存与预热
- session-manager-cache 预热会话文件,减少重复解析成本;session-manager-init 确保会话头存在。
- 历史限制与上下文修剪
- history 限制 DM 与群组历史轮次;context-pruning 基于缓存 TTL 实现上下文修剪,降低上下文窗口压力。
- 压缩安全护栏
- compaction-safety-timeout 限制压缩耗时;compaction-safeguard 与 context-pruning 扩展在压缩过程中提供额外保护。
- 工具与沙箱
- splitSdkTools 将工具全部进入 customTools,便于统一策略与沙箱控制,减少不必要的内置工具开销。