首页
/ openinterpreter Skills 体系中的 agents/openai.yaml:interface、dependencies、policy 字段全解与源码级校验规则

openinterpreter Skills 体系中的 agents/openai.yaml:interface、dependencies、policy 字段全解与源码级校验规则

2026-09-06 16:12:14作者:裘晴惠Vivianne

本篇基于仓库中 skill-creator 技能自带的参考文档 openai_yaml.md,完整讲解技能目录下 agents/openai.yaml 这一“面向机器/harness 而非面向 Agent”的产品级配置文件的三大块字段(interfacedependenciespolicy)的语义、约束与写法规范,并结合 codex-rs/skills 的 Rust 解析源码与仓库内真实技能样例,说明每个字段在校验失败时会发生什么、以及如何在创建技能时用配套脚本确定性地生成该文件。读完你可以独立为任意技能编写、审查和调试 openai.yaml,并准确预判哪些字段会被运行时静默忽略。

openai.yaml 的角色定位:写给 harness 看的扩展配置

原文档开头给出了一句话定位:

agents/openai.yaml is an extended, product-specific config intended for the machine/harness to read, not the agent. Other product-specific config can also live in the agents/ folder.

也就是说,它和每个技能必需的 SKILL.md 分工完全不同:

  • SKILL.md 的 frontmatter(name + description)是技能触发的唯一依据,由模型读取用于决定是否激活技能;其解析与长度约束实现在 parser.rs(例如 name 最长 64 字符、description 必填)。
  • agents/openai.yaml 则是可选的 UI 元数据与策略声明,供界面(技能列表、chips、默认提示词)和运行框架读取,正文内容不进入模型上下文。skill-creator 技能的 SKILL.md 也把 agents/ 描述为 "UI metadata for skill lists and chips",并要求"生成取值前先阅读 references/openai_yaml.md 并遵循其中的描述与约束"。

从源码结构看,这份文件的解析入口是 interface.rs 中的 SkillInterfaceFile 结构体,它用 serde 从 agents/openai.yaml 反序列化出 interface 子树;而 dependenciespolicy 子树对应的数据结构则定义在 model.rs

完整配置示例(可直接复制)

原文档给出的完整示例如下,它覆盖了当前文档支持的全部字段,可直接作为编写新技能时的模板:

interface:
  display_name: "Optional user-facing name"
  short_description: "Optional user-facing description"
  icon_small: "./assets/small-400px.png"
  icon_large: "./assets/large-logo.svg"
  brand_color: "#3B82F6"
  default_prompt: "Optional surrounding prompt to use the skill with"

dependencies:
  tools:
    - type: "mcp"
      value: "github"
      description: "GitHub MCP server"
      transport: "streamable_http"
      url: "https://api.githubcopilot.com/mcp/"

policy:
  allow_implicit_invocation: true

三个顶层键全部是可选的。仓库内现有样例也印证了这一点:skill-creator 自己的 openai.yaml 只写了 interface 的四个字段,没有任何 dependenciespolicy

interface:面向 UI 的展示与调用元数据

字段语义总表

字段 语义 约束(文档 + 源码)
interface.display_name 人类可读标题,显示在 UI 的技能列表和 chips 中 字符串加引号;超过 64 字符会被忽略(见下节)
interface.short_description 人类可读的简短 UI 描述,供快速扫读 文档建议 25–64 字符;源码硬上限 1024 字符
interface.icon_small 小图标资源路径,相对于技能目录 必须落在技能目录的 assets/ 下;建议写成 ./assets/...
interface.icon_large 大 logo 资源路径,相对于技能目录 同上
interface.brand_color 用于 UI 强调色(如徽章)的十六进制颜色 必须是 #RRGGBB 格式,否则被忽略
interface.default_prompt 调用该技能时插入的默认提示词片段 建议为一句话,且必须显式以 $skill-name 形式提及技能

其中 default_prompt 的写法要求最容易被忽略:文档明确要求"生成一个有帮助的、简短(通常一句话)的示例起始提示词,且必须显式地以 $skill-name 提及该技能",并给出示范句式 "Use $skill-name-here to draft a concise weekly status update."。仓库中两个系统技能的真实写法完全遵循这一规范,例如 imagegen 的 openai.yaml 中:

default_prompt: "Use $imagegen to make or edit an image for this project."

源码中的实际校验规则:逐字段容错而非整体失败

文档只给出了"字段描述",而字段写错时运行时到底怎么处理,则由 interface.rsresolve_skill_interface 决定。结合源码与测试 interface_tests.rs,可归纳出以下可验证的规则:

  1. 空白规范化:所有字符串字段(display_nameshort_descriptiondefault_prompt)会先经 resolve_strsplit_whitespace().join(" ") 处理,即 " Demo skill " 会被规范化为 "Demo skill"(测试 resolves_local_interface_fields_and_assets 中有此断言)。
  2. 长度上限display_name 超过 64 字符(MAX_NAME_LEN)或 short_description/default_prompt 超过 1024 字符(MAX_DESCRIPTION_LEN,见 interface.rs#L10-L11)时,该字段被丢弃并记录 tracing::warn!,而不是让整个文件解析失败。测试 drops_invalid_fields_without_discarding_valid_interface_fields 明确验证了"坏字段单独丢弃、好字段保留"的行为。
  3. brand_color 严格校验resolve_color_strinterface.rs#L180-L197)要求值恰为 7 个字节且形如 # + 6 位十六进制(即 #RRGGBB),blue 这类颜色名会被忽略并告警。
  4. short_description 的 25–64 字符只是 UI 建议:它不是硬校验,硬校验是 1024 上限;真正强制 25–64 区间的是生成脚本(见"实践建议"一节)。

图标路径解析:必须锚定在 assets/

icon_small/icon_large 的解析规则是这份文档中最"隐蔽"的约束,完整逻辑在 resolve_asset_pathinterface.rs#L77-L122):

  • 路径必须相对于技能目录;绝对路径会被忽略并告警(测试 rejects_absolute_asset_paths 覆盖)。
  • 路径组件会被归一化(./ 前缀被剥掉),归一化后第一段必须是 assets,否则会收到 "icon path must be under assets/" 的告警并被丢弃。这也解释了为什么文档建议"默认使用 ./assets/,把图标放在技能的 assets/ 文件夹里"。
  • .. 的路径在普通技能(SkillInterfaceAssetPolicy::LocalOnly)中一律被拒绝;只有当技能属于某个插件、且运行时以 PluginShared 策略解析时,.. 才被允许——但归一化后仍必须落在插件根目录的 assets/ 之内(resolve_plugin_shared_asset_pathinterface.rs#L124-L148;正反用例见 interface_tests.rs#L118-L165)。
  • 全部字段都被判无效(或本来就为空)时,resolve_skill_interface 返回 None,即该技能没有 interface 元数据,UI 侧回退到基于 SKILL.md 的展示。

dependencies.tools:声明 MCP 依赖

文档对 dependencies.tools[] 各字段的定义是:

  • type:依赖类别,目前仅支持 mcp("Only mcp is supported for now");
  • value:工具或依赖的标识符;
  • description:人类可读的依赖说明;
  • transport:当 typemcp 时的连接类型,示例中使用 "streamable_http"
  • url:当 typemcp 时的 MCP 服务器 URL。

对照 model.rs,运行时结构 SkillDependencies { tools: Vec<SkillToolDependency> } 中的 SkillToolDependency 还包含一个 command 可选字段,与 transport/url 并列。从源码结构看,这是为命令式(本地命令)依赖预留的字段位,但文档口径明确当前仅 mcp 类别受支持,因此在 openai.yaml 中手写依赖时,仍应以文档示例的 type: "mcp" + transport + url 组合为准。

dependencies 整体也是可选的:仓库中 skill-creator、imagegen、openai-docs 等系统技能的 openai.yaml 均未声明依赖,对应 model_tests.rsdependencies: None 的常见形态。

policy.allow_implicit_invocation:控制技能是否默认注入上下文

policy.allow_implicit_invocation 是文档中唯一的策略字段,语义为:

  • 设为 false 时,该技能默认不会被注入到模型上下文,但仍可通过 $skill 显式调用;
  • 默认为 true(不写 policy 或留空即视为允许隐式调用)。

源码层面这一默认值由 SkillMetadata::allows_implicit_invocation 实现(model.rs#L22-L36):policy.allow_implicit_invocationOption<bool>,取值时 unwrap_or(true)

仓库中有一个现成的 false 用法样例——review-agent 技能的 openai.yaml

interface:
  display_name: "Review Agent"
  short_description: "Find actionable bugs in code changes"
  default_prompt: "Use $review-agent to review the requested code changes and return actionable findings."
policy:
  allow_implicit_invocation: false

这是一个典型场景:代码评审技能不希望每次普通对话都被动注入,只应在用户明确 $review-agent 时激活。

补充一点源码事实:SkillPolicy 结构体(model.rs#L62-L68)中还解析了一个 products 产品限定字段,但源码中的 TODO 注释表明目前只做了解析与存储,尚未在技能选择/注入环节强制执行,且该字段未出现在参考文档中,编写时不建议依赖它。

顶层书写规范:引号与键名

文档"Top-level constraints"给出三条全局规则,写 YAML 时应逐条遵守:

  1. 所有字符串值必须加引号(Quote all string values)。
  2. 键名保持不加引号(Keep keys unquoted)。
  3. interface.default_prompt:基于该技能生成一句简短(通常一句话)的示例起始提示词,且必须显式以 $skill-name 提及技能,例如 "Use $skill-name-here to draft a concise weekly status update."。

之所以强制加引号,与技能生态的现实有关:parser.rsSKILL.md frontmatter 专门做了"修复式"解析来兼容第三方技能中未加引号的散文化描述;而 openai.yaml 作为机器读取的配置文件,规范写法可以避免依赖这类容错逻辑。

解析链路:这份文件如何被读入与消费

把文档字段与源码串起来,一条完整的消费链路是:

  1. 嵌入与安装:系统技能(含本文引用的 skill-creator 等样例)通过 include_dir! 编译进二进制,启动时由 install_system_skills 写入 CODEX_HOME/skills/.systemlib.rs#L49-L95),因此 agents/openai.yaml 会随技能一起落盘。
  2. 反序列化interface 子树 → SkillInterfaceFile(serde Deserialize);dependenciespolicySkillDependenciesSkillPolicymodel.rs)。
  3. 逐字段校验与路径解析resolve_skill_interface 对每个字段独立校验,坏字段告警丢弃(前文已述),图标路径归一化为绝对路径后写入 SkillInterface
  4. 消费SkillMetadata 聚合 name/description/interface/dependencies/policy(model.rs#L6-L20),allows_implicit_invocation 决定技能是否参与默认上下文注入,interface 供 UI 展示层使用。

仓库内真实样例对照

以下样例均在 codex-rs/skills/src/assets/samples 下,可对照字段用法:

技能 文件 用到的字段 说明
skill-creator agents/openai.yaml display_nameshort_descriptionicon_smallicon_large 最小形态:无 default_prompt、无 policy
imagegen agents/openai.yaml interface 全五字段 default_prompt 用 "Use $imagegen to ..." 规范句式
openai-docs agents/openai.yaml interface 全五字段 展示了较长的 default_prompt 写法
review-agent agents/openai.yaml interface + policy 唯一使用 allow_implicit_invocation: false 的样例

可以看出,文档示例中的 dependencies 块在内置样例里尚未被使用,它更多面向需要声明 MCP 服务器依赖的第三方技能。

实践建议:用配套脚本确定性生成 openai.yaml

skill-creator 技能明确要求:display_nameshort_descriptiondefault_prompt 应由 Agent 读完技能内容后生成,再作为 --interface key=value 参数传给脚本确定性生成,而不是手写 YAML。对应 SKILL.md 中的流程:

# 初始化技能时一并生成(含 agents/openai.yaml)
scripts/init_skill.py my-skill --path "${CODEX_HOME:-$HOME/.codex}/skills" \
    --interface display_name="My Skill" \
    --interface short_description="One line within 25 to 64 chars" \
    --interface default_prompt="Use $my-skill to ..."

# 或对已有技能目录单独(重新)生成
scripts/generate_openai_yaml.py <path/to/skill-folder> --interface key=value

生成脚本 generate_openai_yaml.py 值得细看两点:

  • 它只接受白名单内的 interface 键(ALLOWED_INTERFACE_KEYSdisplay_nameshort_descriptionicon_smallicon_largebrand_colordefault_prompt,见 generate_openai_yaml.py#L40-L47),与文档字段一一对应;
  • 当没有显式传入 short_description 时,脚本会按 25–64 字符区间自动伸缩兜底文案(generate_openai_yaml.py#L74-L101)——这正是文档"25–64 chars"建议在工具链中的落地位置。

配套约定还包括:

  • 图标等其他可选字段:SKILL.md 要求"仅当用户显式提供时才写入 icons、brand color",避免臆造资产路径导致图标解析告警;
  • 更新时保持同步:修改 SKILL.md 后应校验 agents/openai.yaml 是否仍然匹配,过期则重新生成;
  • 验证:整个技能目录可用 skill-creator 自带的 scripts/quick_validate.py 做基础校验(frontmatter 格式、必填字段、命名规则),openai.yaml 本身则依赖上文所述的运行时逐字段校验与 tracing::warn! 日志来暴露问题——调试图标不显示、颜色不生效时,优先检查告警日志中 "ignoring interface.xxx" 的条目,按提示修正格式即可。

小结

agents/openai.yaml 是技能体系中唯一"面向机器与 UI"的配置文件:interface 决定技能在列表、chips 中如何展示以及调用时插入什么默认提示词;dependencies.tools 用于声明(当前仅支持的)MCP 依赖;policy.allow_implicit_invocation 控制技能是否默认注入上下文。它的字段约束既有文档层的书写规范(值加引号、键不加引号、$skill-name 句式),也有源码层的硬性校验(64/1024 字符上限、#RRGGBB 颜色格式、assets/ 路径锚定、逐字段容错丢弃)。理解了 openai_yaml.mdinterface.rsmodel.rs 两侧的对应关系,就能保证写出的 openai.yaml 既符合文档规范,又不会在运行时被静默忽略。

登录后查看全文
热门项目推荐
相关项目推荐