
OODER 技术博客 · Agent Engineering
——OODER Agent / SuperAgent 架构升级的技术原理分析
2026-11-05 · 深度技术原理分析 · 约 9000 字
摘要:当 Agent 从“会调用预置工具”走向“能为自己制造工具”,系统设计的重心就从 API 编排转移到能力治理。本文以 OODER Agent / SuperAgent 的架构升级为背景,讨论 Agent 自主造工具的真实需求、理论脉络、关键难点与工程实现,并给出一条可验证、可审批、可审计、可回滚的声明式工具构建路径。文中的截图均来自真实工具面或真实会话,而非示意图。 关键词:LLM Agent;工具制造;能力缺口;声明式工具;自进化;SuperAgent;A2A
过去一年,Agent 工程的主线从“单轮问答 + 固定函数列表”逐步转向“多轮任务执行 + 多执行体协作”。OODER 的这次升级,核心变化可以概括为三层:
tools_load 按需装载。工具面不再由某个场景一次性写死,而是由能力注册表、技能中心和动态注册器共同供给。这套架构解决的是“已有能力如何被调度”的问题,但没有自动解决另一个更底层的问题:当能力根本不存在时,Agent 应该怎么办?
OODER 的工具面并不小。下图来自真实的“工具目录”页面:272 个工具、48 个分类。但同一个页面上,写工具(可执行外部副作用的工具)数量为 0,危险级别工具为 3。

图 1:真实工具目录截图(OODER 管理控制台)。工具数量并不等于能力覆盖:大量工具集中在读、检索、编排和设计域,真正能触达业务系统的写工具仍然稀缺。
这张图揭示了三个结构性瓶颈:
/api/。平台不可能为每个租户、每个版本、每个边缘接口预置一个 Java 工具。在一次真实会话里,用户要求“把集团资金管理驾驶舱生成图片,用钉钉发给张海艳”。当时工具面既没有图片导出,也没有媒体上传,模型只能回答“我没有这个能力”。这个回答在语义上没有错,但在产品上是失败的:
这类事件反复出现后,团队把它定义为能力缺口(capability gap):Agent 在完成任务时,发现“当前工具面无法覆盖目标动作”的状态。能力缺口不是系统异常,而是 Agent 与环境之间的正常摩擦;关键在于,系统能否把摩擦转化为可运营的需求,并进一步转化为可用的工具。
这就是“自主造工具”的迫切性:它不是让模型随意写代码,而是让 Agent 在受控边界内,把“缺失的动作”表达成一份可校验、可审批、可执行的工具声明。
“Agent 造工具”并不是一个新奇概念。过去三年,研究社区已经从不同角度逼近这个问题。
研究方向 | 代表工作 | 核心思想 | 对本实践的启示 |
|---|---|---|---|
自监督工具调用 | Toolformer | 让模型自己学习“何时调用、调用什么、传什么参数” | 工具调用决策应由模型自主完成,而不是靠外部硬编码 |
大规模 API 调用 | ToolLLM、Gorilla | 用检索增强和指令微调,让模型掌握成千上万个 API | 工具目录、检索和 schema 是基础设施,不是附属品 |
工具制造者/使用者分离 | LATM(LLMs As Tool Makers) | 一个模型造工具,另一个模型用工具 | 生成与使用应解耦,生成侧需要独立的质量门禁 |
抽象工具创建 | CREATOR | 把“抽象工具创建”和“具体决策执行”分开 | 工具声明应描述契约,执行时才绑定具体参数 |
开放式技能获取 | Voyager | 自动课程 + 技能库 + 自验证,持续积累可复用技能 | 工具需要可复用、可验证、可淘汰,而不是一次性脚本 |
从代码仓库生成工具 | ToolMaker | 从论文/代码仓库自动生成 LLM 可用工具,并闭环自纠正 | “生成 → 自测 → 纠错”必须成为同一条链路 |
程序性记忆 | Agent Workflow Memory | 从历史轨迹归纳可复用工作流 | 一次成功经验应沉淀为可检索的程序性资产 |
自进化 Agent | Self-Evolving Agents 系列综述 | 从模型、记忆、工具、架构四个维度持续演化 | 工具是自进化的核心维度,但必须与治理同步演化 |
这些工作共同指向一个结论:工具不再只是“外部函数的列表”,而是 Agent 可以学习、创建、验证和积累的知识对象。
但学术工作与工程落地之间仍有一段距离。LATM/CREATOR 关注“能不能造出来”,Voyager 关注“能不能在开放环境里持续积累”,ToolMaker 关注“能不能从代码仓库自动生成”。而企业级 Agent 还要回答四个工程问题:
本文的实践定位是:不追求“模型自由写代码”,而是把工具制造收敛为一份可治理的声明(declaration)。模型负责“表达意图与契约”,平台负责“校验、授权、注册、执行与审计”。这与 CREATOR 的“抽象工具创建 / 具体执行分离”一脉相承,但把“审批与租户”纳入了工具对象本身。
设 Agent 当前工具面为 \(T\),用户任务需要的动作集合为 \(A\)。若存在 \(a \in A\),使得 \(T\) 中没有任何工具能在当前会话的权限、租户和网络边界内完成 \(a\),则称系统存在能力缺口:
\[ Gap = \{ a \in A \mid \nexists t \in T,\ allowed(t, a, tenant, risk) \} \]
能力缺口有三个特征:
OODER 把“造工具”拆成五段,而不是一次“让模型写个函数”:
tool_gap_report 把缺口结构化上报;tool_register(dryRun=true) 生成声明并校验;tools_load 后调用;
图 2:五段闭环。真正困难的不在“生成”,而在生成之后的校验、授权、执行和审计。
把这条链路放进 OODER SuperAgent 的整体架构,可以看到三个层次:
tools_load;
图 3:制造层不是独立服务,而是嵌在 SuperAgent 的工具面与执行面之间;治理层横向贯穿。
最直接的做法,是让模型在声明里自己填 risk: READ | WRITE | DANGER。但我们在审计中确认,这种做法不可接受:
DELETE 声明成 READ;POST 声明成 READ;tool_test “试跑”,绕过审批;READ,从而接管别人的工具。因此,风险必须由服务端推导,声明只能升高、不能降低:
HTTP 方法/目标 | 服务端推导风险 |
|---|---|
GET / HEAD | READ |
POST / PUT / PATCH | WRITE |
DELETE | DANGER |
命中 /api/studio、/api/chat、/api/org、/actuator 等敏感前缀 | 至少 DANGER |
这条规则把“模型自报风险”从安全边界降级为“提示信息”。审批、能力授权、执行确认都以服务端推导结果为准。
如果每个工具都要人工审批,Agent 就失去了“自主”的意义;如果完全不审批,工具面就会变成模型可以随意扩张的攻击面。OODER 的折中是:
这套规则的关键不是“审批”,而是审批对象是一份带内容指纹的声明,而不是一句自然语言描述。
动态工具要进入 tools_load,就必须进入 ToolEngine 的注册表。但注册表是全局的:
weather_query,会不会互相覆盖?tools_index?demo_tool,租户工具还能不能叫 demo_tool?OODER 的解法是把“工具身份”拆成三个名字:
名字 | 用途 | 示例 |
|---|---|---|
基 id | 业务语义、声明文件、人读 | demo_tool |
qualified id | 审批、删除、后台运营 | tenant-a:demo_tool |
runtimeName | ToolEngine 注册键、tools_load、LLM 调用 | t-tenant-a-demo_tool |
基 id 只允许 [a-z0-9_],不含 -;运行时名以 t- 开头。这样租户工具的运行时名不可能与全局/存量工具重名。文件键也使用运行时名,因此两个租户的同名声明落在不同文件。执行时再校验 def.tenantId 与当前会话租户一致。

图 4:qualified id、runtimeName、fileKey 三层映射,保证“同名不同租户”可共存且可审计。
声明式工具本质上是“让模型指定一个 HTTP 请求”。如果不加约束,它就是一个 SSRF 入口。OODER 在注册期和执行期做双重校验:
..、//、反斜杠、%2e、%2f、%5c 等路径穿越/编码变体;80,443,5332,8000-8999,9000-9999;/api/studio/、/api/chat/、/api/org/、/api/v1/auth/、/actuator;${secret:ooder.tool.secret.*},缺失即失败,不再静默替换为空串;这些约束的目标不是“让工具更难用”,而是让“模型犯错”变成“可诊断的失败”,而不是“不可见的越权”。
工具造出来之后,最危险的场景不是“调用失败”,而是“调用成功但没人知道它做了什么”。OODER 的审计记录包含:
actor:谁创建/审批/调用;conversationId:哪个会话;paramsHash:参数指纹,不落明文;contentHash:声明定义指纹,审批后若文件被改动,执行直接拒绝;httpStatus、elapsedMs、truncated、risk、tenantId。当审计文件或缺口文件超过阈值时,系统自动归档,避免无限增长。工具修订时先下线旧版本,防止“文件里是新 risk、内存里是旧实现”的授权错配。
OODER 有多个场景(通用对话、意图分发、BPM、RAD、页面调试、技能中心等),其中不少场景覆写了 getAvailableTools 和 buildSystemPrompt。如果只在基类里补平台工具包,覆写场景就会拿不到 tool_register / tool_gap_report。
工程上的解法不是逐个场景加代码,而是:
effectiveTools(context);appendPlatformToolPacks 在最后统一补平台工具包;appendPlatformProtocols 在提示词末尾按标记幂等追加协议;一次“造工具”的真实链路如下:
用户提出目标
→ 模型检索工具面(tools_index / tools_find / tools_load)
→ 发现缺口:tool_gap_report(intent, neededAction, missing, alternatives)
→ 平台落库 + SSE 缺口卡(gapId)
→ 模型生成声明:tool_register(definition, dryRun=true)
→ 校验 URL / schema / 密钥引用 / 风险
→ tool_register(definition, dryRun=false, confirm=true)
→ 服务端推导 risk:READ 直接 ACTIVE;WRITE/DANGER → PENDING
→ 管理员审批:tool_register_approve(qualifiedId)
→ ToolEngine 热注册
→ tools_load(names=[runtimeName])
→ 真实 HTTP 调用 → 审计 → 回写缺口 resolved在真实会话里,工具调用的密度远比“单次函数调用”高。下图来自一次资金流水分析任务:同一轮里连续出现 20 多次工具调用,涵盖工具装载、流水查询、实例列表、图表渲染等,单次耗时从 1ms 到 119ms。

图 5:真实工具链截图。工具面不足时,模型会在“检索—重试—再检索”中消耗轮次;这正是能力缺口需要被结构化的原因。
tool_gap_report 不是“报错日志”,而是一份需求契约:
{
"intent": "把资金驾驶舱生成图片并用钉钉发给张海艳",
"neededAction": "渲染 PNG + 上传媒体 + 发送工作通知",
"missing": [
{"kind": "media", "name": "dashboard_image_render", "reason": "无图片导出工具"},
{"kind": "tool", "name": "dingtalk_send_image", "reason": "无媒体上传能力"}
],
"alternatives": [
{"tool": "render_chart", "label": "先渲染图表", "note": "不能直接生成 PNG"}
],
"impact": "无法按时发送日报",
"evidence": "工具返回 SKILL_NOT_WIRED"
}平台把这个对象落库为 gaps.jsonl,并通过 SSE 推送 capability_gap 事件,前端渲染缺口卡。缺口卡的价值在于:用户能立刻看到“缺什么”,研发能按 gapId 追到“用户原话 + 需要的动作 + 期望参数”。

图 6:真实会话截图(浅色界面)。工具卡展示工具名、执行状态与任务步骤;当工具不存在时,同一位置会变为“能力缺口卡”。
一份最小的工具声明如下:
{
"id": "weather_query",
"displayName": "天气查询",
"description": "查询指定城市当前天气",
"method": "GET",
"url": "http://127.0.0.1:9004/api/weather/current",
"query": {"city": "{city}"},
"risk": "READ",
"params": [
{"name": "city", "type": "string", "required": true, "description": "城市名"}
]
}模型第一次调用 tool_register(definition, dryRun=true),平台只做校验和预览,不落盘;第二次带 dryRun=false + confirm=true 才真正写入。这个过程强制模型“先想清楚契约,再申请落地”。
服务端拿到声明后,不直接信任 risk,而是计算 effectiveRisk:
GET / HEAD → READ
POST / PUT / PATCH → WRITE
DELETE → DANGER
命中敏感目标(/api/studio 等) → 至少 DANGER
最终 risk = max(声明 risk, 推导 risk)WRITE/DANGER 声明落盘为 PENDING,不注册进工具面。管理员在审批台看到的是:
qualifiedId(tenant:id)runtimeName(t-<ns>-<id>)审批通过时,平台写入 approvedAt、approvedBy、contentHash,然后热注册。执行时重新计算 contentHash,如果不一致,直接拒绝执行——这防止“审批后声明文件被替换”。
注册器不覆盖核心工具,也不允许同名声明被非 owner 修订。对于租户工具:
t-<tenantNs>-<id>.jsont-<tenantNs>-<id><tenant>:<id>查询工具面时,ToolCatalogCapability 会把动态工具并入候选集,但按当前会话租户过滤;执行时,DeclarativeToolUnit 再校验一次租户。这样“索引不可见”和“直接按名字调用”两条路径都被堵住。
除了 URL 与密钥,OODER 还做了三件事:
BodyHandlers.ofInputStream() 流式读取,超过 64KB 立即截断;JSON 响应不会因为“解析成功”就整包进入 LLM 上下文。audit.jsonl 超 10MB、gaps.jsonl 超 20MB 自动归档;审计字段包含 actor、paramsHash、contentHash。在 8014 的实测中,一次完整闭环如下:
weather_query 缺口 → 看板“待补齐” +1;gapId 创建草稿 → PENDING,不在工具索引;stage=applied,工具索引可见;tools_load 调用 → CALL httpStatus=200 / 12ms;resolved=True,resolvedByTool=weather_query。
图 7:真实工具卡详情截图(结果数据已脱敏)。工具名、参数结构与执行状态可追溯;这正是“造工具”之后必须保留的证据链。
这个闭环说明:自主造工具不是“模型写一段代码就完事”,而是“缺口—声明—审批—执行—审计—闭环”的系统工程。
声明式工具如果只落在本地 data/tool-decls/,它仍然是一个“单机工具”。OODER 的第二步,是把工具声明接入技能中心(Skill Center),让它成为可发现、可安装、可授权、可审核的跨节点能力资产。
技能中心的完整管理流程可以概括为六段:
SkillCarrierRegistrar 遍历能力载体,把 @CapabilityDeclaration 与 CapabilityUnitPort 注册到 SkillRegistrationTable;CANDIDATE / IN_REVIEW,审核通过后变为 LISTED,驳回则回到 DRAFT;下面两张截图来自真实的技能中心页面(已裁剪并脱敏,保留流程与状态,去掉租户、账号和统计数字):

图 8:技能市场截图。每张卡展示技能 id、版本、能力标签、菜单数与安装状态;“未安装”是租户级状态,不是技能不存在。

图 9:技能审核台截图。候选技能在这里完成契约校验与人工审核;通过后状态变为 LISTED,租户才可安装。
这两个页面回答了一个关键问题:自主造工具不是“造完就能用”,而是“造完要能被分发、被安装、被授权、被审核”。 技能中心承担的就是“能力契约的分发与审核平面”,而不是简单的文件仓库。
技能中心与自主造工具的关系可以概括为:
tool_register(本地声明)
→ SkillRegistrationTable(统一真源)
→ SC 上行(roster / scene / summary / skills)
→ 技能市场(目录可见)
→ 租户安装 + 授权(可用)
→ 运行 / 撤销(生命周期)工具不是“注册成功就结束”。它需要一条完整的生命周期,才能在长期运行中保持可治理。

图 10:工具从 DRAFT/PENDING/ACTIVE/DEPRECATED 到 RETIRED 的状态流转;修订会回到 PENDING 重新审批。
状态 | 含义 | 进入条件 | 退出条件 |
|---|---|---|---|
DRAFT | 可选草稿 | 看板“补工具”生成 | 提交审核 / 删除 |
PENDING | 待批,不注册、不可调用 | WRITE/DANGER 声明、同名修订 | 管理员通过 / 驳回 |
ACTIVE | 已审批、已热注册 | 管理员通过、READ 直生效 | 停用 / 修订 / 删除 |
REJECTED | 已驳回,不注册 | 管理员驳回 | 修改后重新提交 |
DEPRECATED | 停用,不接受新调用 | 运维主动停用 | 删除 / 归档 |
RETIRED | 退役,归档留痕 | 删除 / 过期 / 上游失效 | 只读审计 |
生命周期的四个关键设计:
contentHash 在审批时写入,执行前重算,不一致直接拒绝;audit.jsonl 与缺口记录仍然保留,便于追责与复盘。“让模型造工具”本质上是在给模型增加一个写请求的能力。因此,安全设计不能只在执行阶段做,而要贯穿生命周期。
攻击面 | 典型风险 | 控制措施 |
|---|---|---|
工具投毒 | 模型在 description 中写入提示注入,影响其他用户 | owner/租户隔离、审批、描述限长、工具面按租户过滤 |
风险降级 | 把 DELETE/POST 声明成 READ | 服务端按 method + 目标推导 effectiveRisk,声明只能升高 |
审批绕过 | 用 tool_test 试跑 PENDING 工具 | 仅 ACTIVE 可自测;非 READ 自测需管理员;审批凭证 + contentHash |
SSRF / 路径穿越 | /api/../admin、任意端口、云元数据地址 | 路径规范化、编码变体拒绝、端口白名单、敏感前缀黑名单、元数据地址拒绝 |
密钥外带 | ${secret:任意系统属性} 被写入请求头 | 只允许 ooder.tool.secret.*,缺失 fail-closed,审计不落密钥值 |
租户逃逸 | 直接按运行时名调用其它租户工具 | runtimeName = t-<tenant>-<id>;执行时校验 def.tenantId;目录按租户过滤 |
资源耗尽 | 大响应、无限声明、注册洪水 | 响应 64KB 流式截断、单用户声明上限、注册限流、文件归档 |
核心工具被顶替 | 声明与核心工具同名 | 运行时名冲突检查;永不覆盖核心工具;只注销本注册器注册的工具 |
审计缺失 | 不知道谁创建/审批/调用 | actor、conversationId、paramsHash、contentHash、状态与耗时全部落盘 |
把这张表压缩成一句话:
自主造工具的安全边界,不是“模型会不会写坏代码”,而是“平台能不能在每个阶段说不”。
具体来说,平台在五个位置保留“说不”的能力:
这也是 OODER 与“让模型自由写脚本”的根本区别:不是不给模型能力,而是给能力加上可验证、可审批、可回滚的边界。
本轮改造的验证口径不是“代码看起来对”,而是“编译 + 单测 + 关键路径可复现”:
验证项 | 结果 |
|---|---|
mvn -o -DskipTests compile | BUILD SUCCESS |
mvn -o -Ptests test | 318 passed, 0 failed, 0 skipped |
声明式工具安全用例 | 风险推导、URL 穿越、审批指纹、密钥命名空间、租户命名空间均通过 |
沙箱工具风险分级 | sandbox_agent_load/run/execute 等提升为 DANGER |
缺口看板 | 仅管理员可访问 |
历史测试编译错误 | 已修复(TenantFilter 构造注入、A2A 过期用例替换) |
上述结果覆盖编译、全量单测与安全用例回归;关键路径已在工程环境完成实现与回归验证,后续按灰度节奏推进生产验证。
OODER 的声明式工具只覆盖 HTTP 工具。它不解决“需要写一段本地算法”的场景。后者应该走沙箱代码生成与编译链路,且需要更严格的 DANGER 审批。两条链路的边界要清晰:HTTP 契约用声明,复杂逻辑用沙箱代码,二者都走治理面。
tool_test 能证明“HTTP 通”,不能证明“业务语义对”。一个返回 200 但字段为空的接口,工具测试也会通过。因此:
httpStatus/data/elapsedMs;上游 API 会改字段、改鉴权、改限流。声明式工具需要:
目前没有公开 benchmark 能覆盖“企业内网 API + 多租户 + 审批 + 沙箱”的组合。OODER 的做法是用真实缺口、真实会话、真实审批记录做“运营式评测”。这比合成数据集更接近生产,但样本量小、可重复性弱,需要长期积累。
自主造工具的目标不是“让 Agent 无限扩张工具面”,而是“让 Agent 在边界内补齐能力”。因此,以下原则应长期保留:
OODER SuperAgent 的这次升级,表面上解决的是“多执行体调度”和“工具按需装载”,本质上解决的是“Agent 如何面对自身能力边界”的问题。
从 Toolformer 到 LATM、CREATOR、Voyager、ToolMaker,再到 Self-Evolving Agents 综述,研究社区已经证明:工具可以成为 Agent 学习、创造和积累的对象。但企业级落地还需要另一套东西——声明化、风险推导、审批、租户命名空间、审计与配额。
一句话总结:
会调用工具的 Agent 是“执行者”;能为自己制造工具、并且知道何时不该制造工具的 Agent,才是“可运营的智能体”。
OODER 的实践把“造工具”从一次性的代码生成,变成了一个可治理的运行时能力。这条路径还远未完成,但它至少让“能力缺口”从一句“我没有这个能力”,变成了一个可以被审批、被执行、被审计、被关闭的工程对象。
本文基于 OODER Agent / SuperAgent 的工程实践与 2026-11-04/05 的审计记录整理。文中截图来自真实工具目录、真实会话与真实工具卡;涉及内网地址、账号与业务数据均已脱敏或未展示。
本文基于 OODER Agent / SuperAgent 工程实践与 2026-11-04/05 审计记录整理。截图来自真实工具目录、真实会话与真实工具卡;内网地址、账号与业务数据均已脱敏或未展示。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。