OpenHuman Tool Maker 子代理深度解析:Self-Healing Polyfill 的设计、配置与源码实现
【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman
OpenHuman 是一个面向 Mac、Windows 和 Linux 的开源个人 AI,其核心特色之一是内置多子代理(sub-agent)编排架构。当编排过程中的某个子代理发现主机环境缺少某个必需命令时,系统并不会直接失败——而是会触发一个名为Tool Maker的内置代理,让它编写一个轻量 polyfill 脚本来补齐缺失功能,实现"自愈"(self-healing)。本文以仓库中的 tool_maker 系统提示词 为骨架,结合 agent.toml、prompt.rs 及对应测试,完整讲解这个自愈代理的职责边界、配置语义、提示词组装原理与实战约束,帮助读者理解 OpenHuman 多代理体系中"窄职责、可移植、快速失败"的子代理设计范式。
一、为什么需要 Tool Maker:缺失命令场景与自愈定位
在 OpenHuman 的多代理编排体系中,一个任务会被拆解给多个专职子代理执行(参考 planner 提示词 中列出的code_executor、integrations_agent、researcher、critic等)。这些子代理运行在真实主机上,依赖宿主环境提供的命令与运行时。然而用户的机器千差万别:某些工具链、CLI 命令或脚本解释器可能并未安装。
Tool Maker 正是为应对这一场景而生的"最后手段"代理。根据其系统提示词的定义:
You are theTool Makeragent. You have a single, narrow job: when another sub-agent reports that a required command is missing on the host, write a small polyfill script that provides the missing functionality.
(你是 Tool Maker 代理。你只有一个单一而狭窄的职责:当另一个子代理报告主机上缺少某个必需命令时,编写一个提供缺失功能的小型 polyfill 脚本。)
这里有两个值得注意的关键点:
- 它是被其他子代理"报告"而触发的——Tool Maker 本身不主动探测环境,而是响应上游的缺失命令反馈,属于典型的响应式(reactive)自愈设计。
- 它只做"补脚本"这一件事——不负责环境修复、系统安装或长期维护,交付物就是一段可运行的 polyfill 脚本及其调用说明。
这一自愈定位在 agent.toml 的when_to_use字段中也有明确声明:
when_to_use = "Self-healer — writes a polyfill script when a required command is missing on the host. Very narrow scope; max 2 iterations."二、Capabilities:只暴露"写文件"与"执行命令"两类能力
prompt.md 的 Capabilities 部分极其克制,仅声明两种能力:
- Write files(写文件):产出 polyfill 脚本本身;
- Execute shell commands(执行 shell 命令):用于验证脚本确实能运行。
这与 agent.toml 的[tools]配置严格对应,工具白名单为:
[tools] named = ["file_write", "shell", "node_exec", "npm_exec", "python_exec"]从源码结构看,这种"工具白名单 + 提示词能力描述"的双重约束,意味着该代理在运行时既受到提示词的语义引导,也受到注册层的工具可见性限制(render_tools会基于可见工具集合渲染工具列表,见下文 prompt.rs 分析)。值得注意的是,工具列表里同时包含node_exec、npm_exec与python_exec,与提示词中"优先可移植运行时"的规则互为印证——它允许 polyfill 选择 Node 或 Python 实现,而不只局限于 shell。
三、Rules 全解:五条铁律背后的工程意图
prompt.md 的 Rules 部分是全篇的核心约束,共五条,逐条解读如下:
1. Narrow scope — 最多 2 次迭代,写、验、停
You get at most 2 iterations. Write the script, verify it runs, stop.
Tool Maker 是典型的"窄范围"代理:至多 2 轮迭代。第一轮写脚本并自测,若失败则只有一次修正机会,之后必须停下并输出结论。
这条规则在 agent.toml 中由max_iterations = 2硬性落地,并被 loader 测试 专门断言:
#[test] fn tool_maker_is_sandboxed_with_max_2_iterations() { let def = find("tool_maker"); assert_eq!(def.sandbox_mode, SandboxMode::Sandboxed); assert_eq!(def.max_iterations, 2); assert!(!def.omit_safety_preamble); ... }从迭代上限的对比可以看出 OpenHuman 对子代理"按需分配预算"的设计思路:code_executor(代码仓储任务)拥有max_iterations = 10且启用iteration_policy = "extended",context_scout为 8 次,而 Tool Maker 只有 2 次——因为补一个脚本本就不该是一个大工程,迭代上限本身就迫使代理保持交付物的小巧与聚焦。
2. Prefer portable shell — 可移植性优先
POSIX
sh/ Python 3 / Node are usually available; avoid exotic runtimes.
polyfill 的意义在于"在任何缺少命令的主机上补齐功能",因此实现本身必须运行在几乎处处可用的运行时上:POSIXsh、Python 3、Node。这条规则直接抑制了"为了写 polyfill 而引入另一个更冷门依赖"的荒谬循环——禁止使用 exotic(小众/异构)运行时。
这与工具白名单高度自洽:既然python_exec、node_exec、npm_exec都已被授予,代理完全可以在 Python 3 或 Node 中编写更健壮的实现,而不必受限于纯 shell 的脆弱语法。
3. Fail fast — 无法干净实现就明确上报
If you can't polyfill the command cleanly, report that clearly instead of half-implementing it.
这是对"诚实性"的硬性要求:如果某个命令的行为过于复杂、依赖系统级能力或无法在沙箱内干净复刻,宁可明确报告失败,也不要交付一个半成品脚本。这与整篇文章"自愈但不僭越"的边界哲学一致——polyfill 只解决"可被脚本干净替代"的命令,绝不假装解决系统级问题。
4. No destructive commands — 安全红线
Never
rm -rf, modify system files, or escalate privileges.
三条明确禁区:
- 禁止
rm -rf等破坏性删除; - 禁止修改系统文件;
- 禁止权限提升(escalate privileges)。
值得注意的是,尽管该代理被配置为沙箱模式(见下文 sandbox_mode 分析),提示词中依然内嵌了完整的安全边界描述。这与 prompt.rs 顶部的模块注释相互印证:
Returns the fully-assembled system prompt, including the standard
## Safetyblock (this agent hasomit_safety_preamble = false— it executes code or external actions and needs the guard rails inlined).
也就是说,正因为 Tool Maker会执行代码或外部动作,它的配置刻意保持omit_safety_preamble = false,让标准 Safety 段落内联进最终系统提示词——这是"会动手的代理必须戴好安全绳"的典型体现。
5. Report clearly — 交付物必须可被直接调用
State exactly where you wrote the polyfill and how the caller should invoke it.
polyfill 写完之后,调用链并没有结束:上游子代理还要依赖这个脚本继续工作。因此提示词要求 Tool Maker 在最终报告中明确说明:
- polyfill 脚本写在了哪里(确切路径);
- 调用方应该如何调用它(命令格式、参数约定)。
这条规则保证了"自愈闭环"可被机械式消费:上游拿到路径与调用方式后即可无缝接管,不需要再猜测脚本用法。
四、agent.toml 逐字段解析:窄范围代理的配置语义
agent.toml 是该代理的注册定义,全部字段如下:
id = "tool_maker" display_name = "Tool Maker" when_to_use = "Self-healer — writes a polyfill script when a required command is missing on the host. Very narrow scope; max 2 iterations." temperature = 0.4 max_iterations = 2 sandbox_mode = "sandboxed" omit_identity = true omit_memory_context = true omit_safety_preamble = false [model] hint = "coding" [tools] named = ["file_write", "shell", "node_exec", "npm_exec", "python_exec"]逐字段语义说明:
| 字段 | 值 | 含义 |
|---|---|---|
id/display_name | tool_maker/Tool Maker | 注册 ID 与展示名,被 loader.rs 作为内置代理加载 |
when_to_use | 自愈器描述 | 供编排层/规划层判断何时选用该代理 |
temperature | 0.4 | 相对低温度,追求输出确定性,减少脚本生成的随机波动 |
max_iterations | 2 | 迭代预算硬上限,与提示词"at most 2 iterations"一致 |
sandbox_mode | sandboxed | 在沙箱中执行,降低脚本对宿主环境的破坏风险 |
omit_identity | true | 不注入用户身份上下文,保持职责纯净 |
omit_memory_context | true | 不注入记忆上下文,避免无关信息干扰窄任务 |
omit_safety_preamble | false | 保留标准 Safety 段(因为它会执行代码,需要护栏) |
[model] hint | coding | 模型选择倾向编码类模型 |
[tools] named | 五个工具 | 工具白名单:写文件、执行 shell/Node/npm/Python |
这套配置组合勾勒出一个典型的"工具型子代理"画像:低温度 + 极窄迭代预算 + 沙箱隔离 + 无身份无记忆 + 保留安全前言。对比同目录下其他代理可以更直观地看到差异:
archivist(归档员)为只读背景任务:sandbox_mode = "none"、omit_safety_preamble = true、max_iterations = 3,且带background = true;critic(代码评审)为只读代理:sandbox_mode = "read_only",同样省略安全前言;code_executor会写会跑代码,因此与 Tool Maker 一样是sandbox_mode = "sandboxed"且omit_safety_preamble = false,但迭代上限放宽到 10 并启用iteration_policy = "extended"。
可见"是否执行代码/外部动作"直接决定了sandbox_mode与omit_safety_preamble的取值——这是 OpenHuman 子代理安全模型里一条清晰可循的规律。
五、提示词如何被组装:prompt.rs 的渲染管线
Tool Maker 的系统提示词并不是运行时逐字读入的,而是由 prompt.rs 中的build函数在运行时动态组装。核心代码逻辑为:
const ARCHETYPE: &str = include_str!("prompt.md"); pub fn build(ctx: &PromptContext<'_>) -> Result<String> { let mut out = String::with_capacity(4096); out.push_str(ARCHETYPE.trim_end()); out.push_str("\n\n"); // 1. 用户文件上下文(若存在) let user_files = render_user_files(ctx)?; // 2. 可见工具列表 let tools = render_tools(ctx)?; // 3. 标准 Safety 段(omit_safety_preamble = false,必然注入) let safety = render_safety(); // 4. 工作区信息 let workspace = render_workspace(ctx)?; ... Ok(out) }值得注意的实现细节:
include_str!("prompt.md"):提示词源文件在编译期被嵌入二进制,运行时零 IO 读取,避免提示词文件缺失或被篡改的风险;- 组装顺序固定:
prompt.md 正文 → 用户文件 → 工具列表 → Safety 段 → 工作区,其中 Safety 段通过render_safety()无条件追加(因为omit_safety_preamble = false); - 上下文按需渲染:
render_user_files、render_workspace会根据PromptContext决定是否输出内容——配合omit_identity = true/omit_memory_context = true,最终提示词中不会出现身份与记忆相关段落。
同时,prompt_tests.rs 中的build_returns_nonempty_body测试构造了一个最小化的PromptContext(空工具集、空可见工具名、ToolCallFormat::PFormat),断言build输出非空——这是对提示词渲染管线的基本回归保护,确保即便在无工具、无上下文的极端情况下,系统提示词仍能完整生成。
六、注册与编排位置:它处在代理生态的哪个环节
从源码结构看,Tool Maker 的注册路径清晰:
- 模块挂载点:registry/agents/mod.rs 中的
pub mod tool_maker; - 内置代理注册:loader.rs 中将其注册为
BuiltinAgent { id: "tool_maker", toml: include_str!("tool_maker/agent.toml"), prompt_fn: super::tool_maker::prompt::build, graph_fn: None }——agent.toml同样通过include_str!编译期嵌入; - 编排层的认知:planner 提示词 将
tool_maker描述为 "Writes polyfill scripts. Rarely needed in planning.",并明确提示规划阶段通常不需要它——这进一步印证了它"响应式、事后补救"的定位,只在其他子代理报缺失命令时才被拉起。
也就是说,在 OpenHuman 的多代理拓扑中,Tool Maker 是编排链路末端的"补丁生产单元":planner规划 → 各执行型子代理执行 → 遇到缺失命令 → 上报 →tool_maker补脚本 → 执行继续。它很少进入规划视野,却是保证"环境不完整也能继续干活"的关键兜底。
七、实战要点总结:如何用好 Tool Maker 这个自愈单元
基于上述提示词与配置分析,可以归纳出在 OpenHuman 体系内使用/理解 Tool Maker 的几个要点:
- 触发方式:无需显式请求,由子代理在执行过程中发现命令缺失后触发其补脚本能力;若你在编排层规划,参考 planner 提示词 的约定,正常规划流程几乎不需要主动委派给它。
- 交付物预期:一段可移植的 polyfill 脚本(优先 POSIX
sh/ Python 3 / Node 实现)+ 明确的位置与调用方式报告;不期望它做系统安装或权限操作。 - 质量与安全边界:它被沙箱隔离、迭代预算仅 2 次、温度 0.4、保留完整 Safety 段——任何"破坏性操作、系统文件修改、权限提升"都在红线之外;无法干净实现时,它会明确失败而非交付半成品。
- 可验证性:若需验证该代理配置是否如期加载,可参考 loader 测试(断言沙箱模式、迭代上限与安全前言保留)以及 prompt 渲染测试(断言提示词组装非空),它们在 CI 中守护了 Tool Maker 的核心行为契约。
综上,Tool Maker 是 OpenHuman 子代理体系中一个教科书式的"窄职责自愈单元":提示词划定职责与红线,TOML 把约束落成运行时事实(2 次迭代、沙箱、低温度、工具白名单),Rust 组装层在编译期嵌入提示词并在运行时拼接 Safety 与工具上下文,测试则锁住关键行为。理解它的设计,也就理解了这个项目在"代理自治"与"安全可控"之间取得平衡的微观样本。
【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考