OpenHuman Skill Creator 智能体深度解析:面向 Node 运行时的 SKILL 创作、代码路径与验证指南
【免费下载链接】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 仓库内置的 Skill Creator 系统提示词(src/openhuman/agent/registry/agents/skill_creator/prompt.md)为主体,结合其 agent.toml、prompt.rs、node_exec.rs 与 skills 子系统 等源码,为你还原这个“技能创作智能体”的完整职责、运行时规则、底层执行链路与验证闭环。读完本文,你将掌握 OpenHuman 中 SKILL.md 技能包与 Node 支撑代码的正确创作姿势,理解
node_exec/npm_exec/javascript控制器三类真实执行面的用法,以及如何通过定向测试保证技能可运行、可被编排器调用。
一、Skill Creator 是谁:定位与职责边界
Skill Creator 是 OpenHuman 仓库中的一个内置(built-in)智能体,核心职责是创建或更新 OpenHuman 技能(skills)以及支撑它们的 JavaScript 代码。它既不是泛泛的“写代码助手”,也不是只管文档的“提示词写手”,而是一个横跨三层交付物的专项角色:
SKILL.md技能包及相关捆绑资源(bundled resources);- 需要在 Node.js 下运行的 JavaScript / TypeScript 文件;
- 仓库接线(repo wiring):让编排器(orchestrator)或其他智能体能够使用新能力;
- 定向测试或验证命令:证明技能/代码确实可用。
这四类交付物在 prompt.md 的 "What You Build" 一节中被明确列出,缺一不可——写一个只有说明没有可执行后端的SKILL.md,或者写一段没人调用得上的 Node 脚本,都不算完成任务。
从注册表配置看,该智能体的系统身份信息也很清晰(agent.toml):
| 字段 | 值 | 含义 |
|---|---|---|
id | skill_creator | 注册表内唯一标识 |
display_name | Skill Creator | 面向用户/日志的展示名 |
delegate_name | create_skill | 被编排器委托调用时的名称 |
when_to_use | JavaScript skill/runtime specialist | 编排器选择该智能体的触发条件描述 |
temperature | 0.3 | 偏保守采样,减少创作中的随机发散 |
max_iterations | 10 | 单次会话最大迭代轮数 |
iteration_policy | extended | 允许更长的迭代执行策略 |
max_result_chars | 16000 | 单次返回结果上限 |
sandbox_mode | sandboxed | 默认在沙箱模式下执行 |
omit_identity/omit_memory_context | true | 省略身份与记忆上下文,聚焦任务本身 |
omit_safety_preamble | false | 仍保留安全前导说明 |
此外还为其注入了 17 个具名工具([tools] named段):shell、file_read、file_write、git_operations、node_exec、npm_exec、python_exec、grep、glob、list、edit、apply_patch、todowrite、plan_exit、web_fetch、lsp、update_memory_md。这份工具清单本身就是创作技能的最小工作台:读写文件 + 搜索浏览 + 执行验证(Node/npm/Python/shell)+ 代码编辑(edit/apply_patch/lsp)+ 计划与收尾(todowrite/plan_exit)。
二、运行时规则:QuickJS 退役后的真实执行面
提示词开篇就定下了一条硬性红线:
Do not assume QuickJS exists.The old embedded QuickJS runtime is gone.
这意味着旧的嵌入式 QuickJS 运行时已从仓库移除,Skill Creator 必须面向当前仓库真实的执行面来创作技能,而非假设某个历史运行时仍然可用。仓库确实用测试固化了这一约束——prompt_tests.rs 中的build_returns_nonempty_body明确断言生成的提示词正文包含字符串"Do not assume QuickJS exists.",防止未来有人误删这条关键规则。
与之配套的,是提示词给出的三个真实执行目标:
node_exec:一次性 JS 执行(inline 代码或脚本文件);npm_exec:包/脚本工作流(依赖安装、npm run类任务);javascript控制器:当核心需要暴露工具列表(tool listing)或具名工具分发(named tool dispatch)时使用。
这三者在源码中都有对应的实现落点:node_exec与npm_exec都是系统工具层(src/openhuman/tools/impl/system/mod.rs 中的pub use node_exec::NodeExecTool;/pub use npm_exec::NpmExecTool;),而javascript则是核心对外暴露的一等语言槽位(src/openhuman/runtime/javascript/README.md),详见下文第四节。
提示词还特别强调了SKILL.md的定位:先把它当作元数据/指令(metadata/instructions),而不是可执行行为本身。如果用户要的是可执行行为,就必须同时新增或更新真正运行它的 Node 支撑代码路径。这一原则与 skills 子系统的实现一致——skills/README.md 明确写着技能通过run_skill在隔离 worker 中执行,“技能正文不再被拼接进聊天轮次”,说明执行与说明在架构上是解耦的。
三、工作风格:先看模式,再做小步组合
提示词的 "Working Style" 一节给出了四条创作方法论,直接决定了技能代码在仓库中的演进方式:
- 先检查既有模式,再发明新范式(Inspect existing patterns before inventing a new one);
- 偏好小而可组合的改动,而非新建一套并行框架(Prefer small, composable changes over a new parallel framework);
- 新增 JS 执行能力时,走既有的 agent 与 tool 表面接进编排器/子智能体,而不是隐藏的旁路(wire it to orchestrator/subagents through the existing agent and tool surfaces instead of hidden side paths);
- 命名与仓库现有的
javascript、tools、agent 定义保持一致; - 行为变化时补充或更新测试。
从仓库结构可以印证这套原则的落地:技能与工具相关的命名确实高度统一——运行时模块统一叫javascript(src/openhuman/runtime/javascript/mod.rs),工具实现集中在 src/openhuman/tools/impl/system/,内置智能体则统一登记在 src/openhuman/agent/registry/agents/(同目录下还有code_executor、tool_maker等兄弟智能体,分工定位各异)。Skill Creator 的任务边界正是“沿着这套既有表面做增量”,而不是另起炉灶。
四、node_exec/npm_exec/javascript控制器:三类执行面的源码级剖析
4.1node_exec:受管的 Node.js 执行工具
node_exec的实现位于 src/openhuman/tools/impl/system/node_exec.rs,文档注释给出了两种输入模式:
| 模式 | 参数 | 最终调用形态 |
|---|---|---|
| Inline 代码 | inline_code: "console.log(1+1)" | node -e '<code>' |
| 脚本路径 | script_path: "scripts/run.js"+args | node <path> <args...> |
两条约束值得创作者注意:
inline_code与script_path必须二选一(Exactly one of inline_code / script_path must be supplied),两者同时提供或都缺失都会直接返回错误;- 脚本必须位于工作区内:
script_path以工作区为根解析,绝对路径、..逃逸、Windows 盘符前缀都会被拒绝(见resolve_script_path实现,node_exec.rs)。
node_exec的参数 schema(可从工具的parameters_schema中看到)完整字段如下:
{ "inline_code": "JavaScript source passed to `node -e`. Mutually exclusive with script_path.", "script_path": "Path (relative to workspace) to a .js/.mjs/.cjs file. Mutually exclusive with inline_code.", "args": "Positional arguments appended after the script. Ignored for inline_code.", "timeout_secs": "Optional wall-clock timeout (seconds) before the process is killed." }超时策略是 Skill Creator 需要特别记住的一条设计:node_exec默认无超时,因为它要跑合法的长任务(bundler、solver、测试运行),不能被默认上限硬杀(注释中引用了 issue #4023);只有显式传入timeout_secs时才启用截止时间,且上限封顶为NODE_TIMEOUT_MAX_SECS = 1800秒(node_exec.rs)。node_timeout_policy与测试(node_exec_tests.rs)共同验证了这一行为:不传或传0⇒ToolTimeout::Unbounded,传99999⇒ 被钳制到 1800s。
安全模型是另一层硬约束:
- 任意 JS 执行属于
Write权限桶(external_effect_with_args返回gate_decision(CommandClass::Write) == GateDecision::Prompt),在 ask-before-edit 模式下会走人工审批闸门; - 只读模式下直接拒绝执行(
[policy-blocked] Action blocked: the agent is in read-only mode and cannot execute code.)——注释指出这修复了历史上node -e绕过自治检查的问题; - 执行前还有跨 profile 命令扫描(
check_cross_profile_command)与速率限制(is_rate_limited/record_action)两道闸; - 子进程环境使用白名单(
SAFE_ENV_VARS,node_exec.rs)并env_clear()后重建,保证密钥不会泄漏进 Node 子进程;PATH会被前置受管 Node 的 bin 目录; - stdout/stderr 各有1MB 上限(
MAX_OUTPUT_BYTES = 1_048_576),超出部分截断并追加... [stdout truncated at 1MB]提示。
Node 运行时从哪来:node_exec不假设系统已装 Node,而是通过NodeBootstrap解析——首次调用时解析,若PATH上没有兼容的node,会下载并解压一份受管(managed)Node.js 发行版,后续调用复用缓存安装(见 node_exec.rs 模块注释)。这套解析/下载/解压逻辑集中在 src/openhuman/runtime/node/,node_exec、npm_exec、shell都通过openhuman::runtime::javascript::NodeBootstrap复用(见 runtime/javascript/README.md 的 "Used by" 一节)。
两条进阶执行路径(源码注释均有标注):
- 沙箱路径:当智能体的
sandbox_mode为Sandboxed时(Skill Creator 默认正是sandboxed),执行会被路由到沙箱后端(Docker / OS 级cwd_jail/ 文档化的 noop),与ShellTool获得相同的隔离保证;沙箱路径必须有有限截止时间,未显式指定时用 24h 的“有效无界”上限兜底。 - 运行时池(runtime pool):inline 代码在启用池时会被路由到一组常驻的
nodeworker(issue #5106),一个 fleet 只付一份解释器开销;process.chdir相关的代码会自动降级走旧式逐次 spawn(因为 Node 禁止在worker_threads内chdir),池饱和时返回可重试的繁忙错误,post-dispatch 失败则绝不重试以避免重复执行。
最后,工具描述中有一条对创作者至关重要的使用提醒:只有程序的 stdout/stderr 会被捕获返回——你不console.log的值对智能体不可见,退出码为 0 但不打印任何内容的脚本会返回空结果。因此创作 JS 技能时,务必显式打印所需输出,例如console.log(JSON.stringify(result))。
4.2npm_exec:包与脚本工作流
npm_exec与node_exec是兄弟工具(同在 src/openhuman/tools/impl/system/mod.rs 中导出),面向包/脚本类工作流,与node_exec共享同样的安全闸门、环境清洁策略以及NodeBootstrap的运行时解析(runtime/javascript/README.md 确认npm_exec.rs同样 importNodeBootstrap)。当技能需要安装依赖或运行 npm 脚本时,Skill Creator 应优先选择它,而不是用shell裸拼命令。
4.3javascript控制器:核心层的工具列表与具名分发
javascript是核心对外暴露的一等语言槽位,但它在架构上是一个纯重导出门面(rename-only facade):crate::openhuman::runtime::javascript表面不拥有任何逻辑,全部pub use自runtime_node(runtime/javascript/README.md),这样未来若出现 Python/Ruby 或另一个 JS 后端,无需改动调用方即可替换实现。
该门面暴露两个 RPC 方法(runtime/node/schemas.rs 定义,经门面以all_javascript_*名称接入src/core/all.rs):
| 方法 | 输入 | 输出 |
|---|---|---|
javascript.list_tools | 无 | tools:工具元数据数组(name、description、category、permission_level、scope、supports_markdown、parameters) |
javascript.execute_tool | tool_name(必填)、args(可选,默认{})、prefer_markdown(可选 bool) | tool_name、elapsed_ms(u64)、result(MCP 风格 ToolResult:{content, is_error, markdownFormatted?}) |
实现上(runtime_node/rpc.rs/ops.rs):处理器通过config::rpc::load_config_with_timeout加载配置、用tools::all_tools_with_runtime构建完整工具集,然后按精确名称列出或分发工具;每次execute_tool都会重建整个工具集(没有持久工具缓存),分发结果以RpcOutcome(CLI 兼容 JSON)返回,并在执行前后通过全局事件总线发布ToolExecutionStarted/ToolExecutionCompleted事件(session_id为字面量"javascript")。
对 Skill Creator 而言,这条路径意味着:当技能需要让核心以“工具”形态暴露 JS 能力(工具列表 + 具名分发)时,接javascript控制器;当只是跑一段一次性脚本或一个技能测试时,用node_exec/npm_exec。
五、SKILL.md 规范:技能子系统的元数据契约
既然 Skill Creator 的交付物之一是SKILL.md技能包,就有必要理解仓库对技能格式的既有约定。skills/README.md 说明:技能是 agentskills.io 风格的一个目录,包含带 YAML frontmatter 和 Markdown 指令的SKILL.md。子系统负责:
- 发现与解析:扫描技能目录并解析 frontmatter 与指令正文;
- 作用域解析:
SkillScope枚举区分User/Project/Legacy三种发现作用域,名字冲突时决定优先级; - 信任标记强制(trust-marker enforcement)与资源读取;
- 安装 / 卸载:通过 RPC
skills.{skills_list, skills_read_resource, skills_create, skills_install_from_url, skills_uninstall}暴露; - 执行:
run_skill在隔离 worker中执行,技能正文不再拼接进聊天轮次;技能以紧凑的## Installed Skills目录形式呈现给智能体。
资源边界上,单个资源的 RPC 载荷上限为MAX_SKILL_RESOURCE_BYTES = 128 * 1024(128KB,skills/ops.rs)。因此 Skill Creator 创作的技能包应保持资源精简,避免把大体积二进制捆进技能目录。
六、验证要求与输出契约:可证明地工作,而非声称工作
提示词的 "Validation" 与 "Output Contract" 两节,构成了 Skill Creator 的完成标准:
验证(Validation)
- 每次编辑后运行定向检查;
- 对技能:验证
SKILL.md的形态(shape)以及任何你触碰过的运行时代码路径; - 对 JavaScript:执行最窄的有用命令——
node_exec、npm_exec或项目测试命令——并在停止前修复失败。
这条“先跑最窄命令再收工”的纪律与node_exec的实现哲学完全一致:默认无超时是为了长任务能跑完,1MB 输出上限是为了结果可回传,退出码 + 双流回显(node_exec.rs)是为了让智能体能就地诊断失败而不是盲目重跑(注释引用 issue #4095)。
输出契约(Output Contract),收尾时三件事必须交代:
- 返回你改了什么(Return what you changed);
- 说明编排器或其他智能体应如何调用它(State how the orchestrator or another agent is expected to invoke it);
- 明确指出端到端执行还缺什么(Call out anything still missing from full end-to-end execution)。
七、系统提示词是怎么组装出来的:prompt.rs 源码视角
Skill Creator 的最终提示词并非只有 prompt.md 一份静态文本,而是由 prompt.rs 的build(&ctx)在运行时按固定顺序拼装:
ARCHETYPE:include_str!("prompt.md")将 prompt.md 的正文编译进二进制,作为提示词骨架;- 用户文件段(
render_user_files):若上下文携带用户文件则追加; - 工具段(
render_tools):渲染可见工具列表; - 安全段(
render_safety):追加安全前导说明——与agent.toml中omit_safety_preamble = false呼应; - 工作区段(
render_workspace):追加工作区上下文。
也就是说,你读到的 prompt.md 只是“骨架”,实际运行时的提示词是骨架 + 用户文件 + 工具清单 + 安全说明 + 工作区上下文的组合。这也是为什么agent.toml中omit_identity = true/omit_memory_context = true会影响最终提示词形态——Skill Creator 被刻意设计为“轻身份、重任务”的专项角色。
八、测试闭环:规则如何被固化
Skill Creator 相关的测试覆盖了两个层面:
- 提示词层面:
build_returns_nonempty_body(prompt_tests.rs)验证build()产出的提示词非空且包含"Do not assume QuickJS exists.",防止运行时规则被意外删改; - 执行工具层面:
node_exec_tests.rs(src/openhuman/tools/impl/system/node_exec_tests.rs)以单元测试固化shell_quote的单引号转义与元字符中和、node_timeout_policy的无界默认与 1800s 钳制、process.chdir片段走旧式 spawn 的降级逻辑、resolve_script_path对空路径/绝对路径/逃逸路径的拒绝。
这两层测试分别对应提示词中“Add or update tests when behavior changes”和“For JavaScript: execute the narrowest useful … test command”的要求——规则不是口头约定,而是被测试钉死的实现事实。
九、实践速览:创作一个技能的最小闭环
综合以上全部约束,Skill Creator(以及人工开发者)创作一个带可执行行为的技能,可以遵循如下最小闭环:
- 观察:先浏览 src/openhuman/skills/ 与 src/openhuman/tools/impl/system/ 的既有模式,确认命名与结构;
- 写元数据:创建含 YAML frontmatter 的
SKILL.md,内容先行,声明技能意图与调用方式; - 写执行代码:新增 Node.js 支撑脚本(
.js/.mjs/.cjs,置于工作区内),并在脚本中显式console.log需要回传的结果; - 接线:若需被编排器或其他智能体调用,走既有 agent/tool 表面接入(必要时接
javascript控制器的工具列表/具名分发);不要发明隐藏旁路; - 验证:用
node_exec(inline 或 script_path)或npm_exec执行最窄命令,必要时给长任务显式传timeout_secs(上限 1800s); - 收尾:按输出契约汇报改动清单、调用方式与尚缺的端到端环节,并补上相应测试。
这套闭环既是对 prompt.md 六节内容的完整落地,也是仓库源码(prompt.rs、node_exec.rs、skills/README.md、runtime/javascript/README.md)所支撑的、可验证可追溯的创作流程。对想在 OpenHuman 上扩展能力的开发者来说,Skill Creator 的规则集本身就是一份“如何正确地给这个系统加新技能”的权威范本。
【免费下载链接】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),仅供参考