Codex Skill 执行机制:从加载、选择到按需读取
本文按场景解释 Codex 如何“执行” skill。下面按真实使用场景展开。
Codex Skill 执行机制:从加载、选择到按需读取
本文按场景解释 Codex 如何“执行” skill。这里先澄清一个容易误解的点:
Codex 并没有一个独立的 skill 虚拟机。
SKILL.md 本身不是被运行的程序,而是模型可读的任务说明、流程约束和资源索引。
真正会被执行的是模型随后调用的普通工具,例如 shell、exec、apply_patch、MCP 工具,或者 skill/scripts/ 下的脚本。
所以“执行 skill”的完整链路其实是:
发现 skill -> 抽取元数据 -> 把可用 skill 列表注入给模型
-> 用户显式选择或模型语义判断需要使用某个 skill
-> 加载 SKILL.md 或由模型按路径读取 SKILL.md
-> 模型按照 SKILL.md 里的流程读取 references、运行 scripts、使用 assets 或调用工具
-> 结果进入普通会话历史和工具调用历史
下面按真实使用场景展开。
场景一:新会话启动,为什么模型只看到 skill 清单
用户进入一个仓库后说:
帮我分析这个项目,看看有哪些内置能力可以用。
Codex 不会一上来把所有 SKILL.md 全部塞进上下文。它先扫描 skill 元数据,然后只把“可用 skill 列表”注入到 developer role 中。这个列表通常长这样:
## Skills
A skill is a set of local instructions to follow that is stored in a `SKILL.md` file.
Below is the list of skills that can be used...
### Available skills
- imagegen: Generate or edit raster images... (file: /home/.../imagegen/SKILL.md)
- openai-docs: Use when the user asks how to build with OpenAI products... (file: /home/.../openai-docs/SKILL.md)
这一步由 Session::build_initial_context 调用 build_available_skills 完成,主要实现位置:
codex-rs/core/src/session/mod.rscodex-rs/core-skills/src/manager.rscodex-rs/core-skills/src/loader.rscodex-rs/core-skills/src/render.rs
模型看到的关键提示词
相关提示词 / Tool Description
英文原文:
A skill is a set of local instructions to follow that is stored in a
SKILL.mdfile. Below is the list of skills that can be used. Each entry includes a name, description, and file path so you can open the source for full instructions when using a specific skill.
中文对照:
skill 是一组存放在
SKILL.md文件里的本地指令。下面是当前会话可用的 skill 列表。每一项都包含名称、描述和文件路径,因此当你需要使用某个具体 skill 时,可以打开对应源码读取完整指令。
这段话的作用是:让模型先获得“可用能力目录”,但不立即消耗上下文加载所有 skill 正文。模型知道每个 skill 的名字、用途和 SKILL.md 路径。
紧接着 Codex 注入更重要的操作规则:
相关提示词 / Tool Description
英文原文:
- Discovery: The list above is the skills available in this session (name + description + file path). Skill bodies live on disk at the listed paths.
- Trigger rules: If the user names a skill (with
$SkillNameor plain text) OR the task clearly matches a skill’s description shown above, you must use that skill for that turn. Multiple mentions mean use them all. Do not carry skills across turns unless re-mentioned.- Missing/blocked: If a named skill isn’t in the list or the path can’t be read, say so briefly and continue with the best fallback.
- How to use a skill (progressive disclosure):
- After deciding to use a skill, open its
SKILL.md. Read only enough to follow the workflow.- When
SKILL.mdreferences relative paths (e.g.,scripts/foo.py), resolve them relative to the skill directory listed above first, and only consider other paths if needed.- If
SKILL.mdpoints to extra folders such asreferences/, load only the specific files needed for the request; don’t bulk-load everything.- If
scripts/exist, prefer running or patching them instead of retyping large code blocks.- If
assets/or templates exist, reuse them instead of recreating from scratch.
中文对照:
- 发现:上面的列表是当前会话可用的 skill,包括名称、描述和文件路径。skill 正文在这些路径上的磁盘文件里。
- 触发规则:如果用户点名某个 skill,比如
$SkillName或自然语言点名,或者当前任务明显匹配上面某个 skill 的描述,本轮必须使用该 skill。多个 skill 被提到时都要使用。除非再次提到,否则不要跨 turn 延续 skill。- 缺失或受阻:如果被点名的 skill 不在列表里,或者路径无法读取,简短说明后使用最佳降级方案继续。
- 如何使用 skill,采用渐进式披露:
- 决定使用某个 skill 后,打开它的
SKILL.md。只读取足够执行流程的内容。- 如果
SKILL.md引用了相对路径,例如scripts/foo.py,优先按 skill 目录解析这些路径。- 如果
SKILL.md指向references/等额外目录,只加载当前任务需要的具体文件,不要整目录批量加载。- 如果存在
scripts/,优先运行或修改脚本,而不是重新手写大段代码。- 如果存在
assets/或模板,复用它们,不要从零重建。
这段话的作用是:把 skill 系统设计成“先目录,后正文,再按需资源”的三层加载机制。模型不是凭空知道某个 skill 的完整流程,而是先看到元数据,再在需要时打开 SKILL.md。
Codex 如何找到这些 skill
SkillsManager 会从多个 root 收集 skill:
项目配置目录下的 skills/ 常见为 <repo>/.codex/skills/
仓库路径上的 .agents/skills/ 从 project root 到 cwd 逐级扫描
用户目录下的 $CODEX_HOME/skills/ 兼容旧位置
用户目录下的 $HOME/.agents/skills/ 用户安装 skill 的位置
系统缓存 $CODEX_HOME/skills/.system 内置 system skills
管理员配置 /etc/codex/skills admin-scoped skills
插件声明的 skill roots 来自 plugin capability
源码里的入口是 skill_roots 和 skill_roots_with_home_dir。它们按配置层、仓库路径和插件声明汇总 root,然后去重。
Codex 如何扫描 SKILL.md
扫描规则比较保守:
从 skill root 开始递归扫描
跳过以 "." 开头的目录
最大扫描深度 MAX_SCAN_DEPTH = 6
每个 root 最多扫描 MAX_SKILLS_DIRS_PER_ROOT = 2000 个目录
遇到名为 SKILL.md 的文件就尝试解析
parse_skill_file 会读取 SKILL.md 的 YAML frontmatter。最关键字段是:
---
name: scenario-tech-article-writer
description: Write Chinese technical implementation-analysis articles...
metadata:
short-description: Write scenario-first technical docs
---
name 和 description 是模型选择 skill 时最重要的可见信息。description 不能写成普通介绍,它必须说明什么时候应该使用这个 skill,因为它会出现在“Available skills”列表中,成为模型语义判断的依据。
场景二:用户显式选中 $skill,为什么完整 SKILL.md 会自动进入本轮
用户说:
使用 $scenario-tech-article-writer 写一篇文档。
或者 UI / App 把用户点击的 skill chip 作为结构化输入提交:
UserInput::Skill {
name: "scenario-tech-article-writer",
path: "/home/.../scenario-tech-article-writer/SKILL.md"
}
这是代码层面的显式注入路径。Codex 会在 run_turn 里调用 collect_explicit_skill_mentions。它能识别:
结构化 UserInput::Skill
$skill-name
[$skill-name](skill://absolute/path/to/SKILL.md)
[$skill-name](/absolute/path/to/SKILL.md)
对于 $skill-name 这种 plain mention,只有当 skill 名称唯一、没有被禁用、也不和 connector slug 冲突时,Codex 才会选中它。路径链接更可靠,因为它可以精确匹配 SKILL.md 路径。
如果用户只是自然语言说“使用 scenario-tech-article-writer 这个 skill”,但没有 $、skill 链接,也没有被 UI 转成 UserInput::Skill,那就不是这条 host 显式注入链路,而是下一节的模型语义选择链路。
显式注入时模型看到什么
当 collect_explicit_skill_mentions 成功选中 skill 后,build_skill_injections 会读取完整 SKILL.md,并把它包装成一个 user-role contextual fragment:
相关提示词 / Tool Description
英文原文:
<skill><name>{skill name}</name><path>{path to SKILL.md}</path>{contents of SKILL.md}</skill>
中文对照:
<skill><name>{skill 名称}</name><path>{SKILL.md 路径}</path>{SKILL.md 的完整内容}</skill>
这段包装的作用是:把“用户这轮明确选择的 skill 正文”放进模型上下文,让模型不需要再自己读文件。实现位置是 codex-rs/core/src/context/skill_instructions.rs。
注意这里的 role 是 user,而“Available skills”列表的 role 是 developer。也就是说:
developer role: 告诉模型有哪些 skill、如何使用 skill。
user role <skill>: 给模型本轮已经选中的 skill 正文。
显式注入发生在用户消息入库之前
run_turn 里的顺序大致是:
读取 turn_skills.outcome
解析用户 input 里的 skill mentions
处理 env_var / MCP skill 依赖
build_skill_injections 读取 SKILL.md
把 <skill> fragment 记录进 conversation items
再进入正常模型采样循环
所以当模型真正开始回答时,它已经能看到被显式选中的 skill 正文。
场景三:用户没写 $skill,模型怎么“自己选择”
用户说:
帮我写一篇场景化技术分析文档,解释 Codex 的 skill 执行机制。
用户没有写 $scenario-tech-article-writer,也没有通过 UI 结构化选中 skill。这时有一个容易混淆的问题:
如果模型发现应该用某个 skill,是不是一定会发起 toolcall 去加载 skill?
答案要分两条链路:
显式选择链路:host 在模型采样前读取 SKILL.md,并把 <skill> 注入上下文。
语义选择链路:模型根据 available skills 判断要用哪个 skill,然后自己用普通工具读取 SKILL.md。
用户没写 $skill 时,通常走第二条。Codex 不会在 Rust 代码里先跑一个语义分类器判断“这句话属于哪个 skill”,也不会在模型采样前自动把某个 SKILL.md 注入进去。真正驱动选择的是 developer prompt 中的 trigger rule:
相关提示词 / Tool Description
英文原文:
If the user names a skill (with
$SkillNameor plain text) OR the task clearly matches a skill’s description shown above, you must use that skill for that turn.
中文对照:
如果用户点名某个 skill,比如
$SkillName或自然语言点名,或者当前任务明显匹配上面某个 skill 的描述,本轮必须使用该 skill。
这段话的作用是:把“是否使用 skill”的语义判断交给模型。代码没有写死“技术文档请求 -> scenario-tech-article-writer”。代码只负责把 skill 的 name、description 和 path 给模型看;模型读到用户任务后,判断任务是否匹配某个描述。
模型一旦判断要用某个 skill,就继续遵守同一段 prompt 的渐进式披露规则:
相关提示词 / Tool Description
英文原文:
After deciding to use a skill, open its
SKILL.md. Read only enough to follow the workflow.
中文对照:
决定使用某个 skill 后,打开它的
SKILL.md。只读取足够执行流程的内容。
这段话的作用是:要求模型在语义选择 skill 后,不要只凭列表里的 description 工作,而要读取 skill 正文。也就是说,如果没有 pre-turn <skill> 注入,模型按规则应该发起一次普通 toolcall 来读取 SKILL.md。
也就是说,语义匹配路径通常长这样:
host 在 developer role 里注入 Available skills
模型看到 scenario-tech-article-writer 的 name、description、path
模型判断当前任务明显匹配这个 description
模型发送普通工具调用,例如 exec/shell 读取 /home/.../scenario-tech-article-writer/SKILL.md
工具返回 SKILL.md 内容
模型按 SKILL.md 的写作流程继续
这里没有一个特殊的 load_skill 工具。读取文件通常就是普通的文件读取或 shell 命令,例如:
sed -n '1,220p' /home/tlinux/.codex/skills/scenario-tech-article-writer/SKILL.md
所以你在 transcript 里看到的会是一次普通 toolcall,而不是“加载 skill”的专用事件。
那 MCP 依赖安装会不会自动发生
不会因为模型语义判断“我要用某个 skill”就一定自动发生。MCP 依赖安装挂在 pre-turn 的 mentioned_skills 上,而 mentioned_skills 来自 collect_explicit_skill_mentions 对用户输入的解析:
UserInput::Skill / $skill / skill 链接
-> mentioned_skills
-> resolve env_var dependencies
-> maybe_prompt_and_install_mcp_dependencies
-> build_skill_injections
-> 模型开始采样
语义选择路径发生在“模型开始采样之后”:
模型看到 Available skills
模型决定使用某个 skill
模型 toolcall 读取 SKILL.md
这时 pre-turn 依赖安装阶段已经过去了。即使该 skill 的 agents/openai.yaml 声明了 MCP server,语义选择本身也不会回头触发 maybe_prompt_and_install_mcp_dependencies。
因此要把三种提示分开看:
<skill> 注入:host 读 SKILL.md 后放进模型上下文,只发生在显式 mentioned skill 上。
普通 toolcall 读取 SKILL.md:模型语义选择 skill 后自己做,使用 shell/exec/文件读取工具。
MCP 依赖安装提示:host 对显式 selected skills 做 pre-turn 检查后弹出,不是模型随口生成的文本。
如果语义选择的 skill 后续需要某个 MCP 工具,模型只能按当前可见工具继续:已经安装并暴露就直接用;工具被延迟加载就按 tool description 使用 tool_search;如果是明确请求安装的 plugin/connector 且 request_plugin_install 可用,再按它的规则请求安装。普通 agents/openai.yaml 里声明的 MCP dependency,不会因为模型读了 SKILL.md 就自动写入配置。
场景四:SKILL.md 被打开后,references、scripts、assets 怎么用
假设 SKILL.md 里写:
For complex examples, read references/examples.md.
If generating the report repeatedly, run scripts/build_report.py.
Use assets/template.md as the output template.
模型不会自动把这些目录都加载进上下文。它会按 prompt 的渐进式披露规则处理。
相关提示词 / Tool Description
英文原文:
If
SKILL.mdpoints to extra folders such asreferences/, load only the specific files needed for the request; don’t bulk-load everything.
Ifscripts/exist, prefer running or patching them instead of retyping large code blocks.
Ifassets/or templates exist, reuse them instead of recreating from scratch.
中文对照:
如果
SKILL.md指向references/等额外目录,只加载当前请求需要的具体文件,不要整目录批量加载。
如果存在scripts/,优先运行或修改脚本,而不是重新手写大段代码。
如果存在assets/或模板,复用它们,不要从零重建。
这段话的作用是:控制 token 成本和执行可靠性。SKILL.md 是入口和导航;references/ 是按需知识;scripts/ 是可执行或可修改的确定性流程;assets/ 是输出资源,通常不需要读入模型上下文。
references 是按需读取,不是自动记忆
references/ 里的内容不会自动进入上下文。模型必须根据 SKILL.md 的导航和当前任务决定读取哪一个文件。
例如:
用户:请按我们公司的 SQL 指标口径写报表。
模型:打开 skill 的 SKILL.md。
SKILL.md:指标定义在 references/metrics.md。
模型:只读取 references/metrics.md,而不是读取整个 references/ 目录。
这就是 skill 的“二级上下文”。它既能让 skill 很强,又避免每次都把大量文档注入。
scripts 是普通工具执行,不是特权执行
如果 skill 里有:
scripts/rotate_pdf.py
scripts/generate_openai_yaml.py
模型运行它们时,本质上是普通 shell/exec 调用:
python3 /path/to/skill/scripts/generate_openai_yaml.py <args>
这条命令仍然受当前 turn 的 sandbox、approval policy、权限配置、网络配置约束。agents/openai.yaml 里的元数据不会给脚本额外提权。测试里也有专门覆盖:skill script execution is governed by the turn sandbox, not a removed skill approval gate。
assets 是输出材料,不是提示词主体
assets/ 常见用途:
图标
模板
字体
前端 boilerplate
示例文件
模型只有在需要复制、修改或引用这些文件时才会使用它们。它们通常不是为了“读进上下文”,而是为了参与最终产物。
场景五:agents/openai.yaml 到底参与了什么
一个 skill 目录可能是:
skill-name/
├── SKILL.md
├── agents/
│ └── openai.yaml
├── references/
├── scripts/
└── assets/
SKILL.md 是模型读的行为说明。agents/openai.yaml 是宿主产品、UI 和 harness 读取的元数据。它不会替代 SKILL.md,也不是 AGENTS.md。
相关提示词 / Tool Description
英文原文:
agents/openai.yamlis an extended, product-specific config intended for the machine/harness to read, not the agent. Other product-specific config can also live in theagents/folder.
中文对照:
agents/openai.yaml是扩展的、产品特定的配置,设计给机器或 harness 读取,而不是给 agent 直接读取。其他产品特定配置也可以放在agents/文件夹里。
这段话的作用是:明确 agents/ 不是 multi-agent 运行目录,也不是 AGENTS.md 项目规则目录。它是 skill 的产品元数据目录。
一个完整示例:
相关提示词 / Tool Description
英文原文:
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
中文对照:
interface:
display_name: "可选的用户可见名称"
short_description: "可选的用户可见简短描述"
icon_small: "./assets/small-400px.png"
icon_large: "./assets/large-logo.svg"
brand_color: "#3B82F6"
default_prompt: "调用该 skill 时可用的默认提示片段"
dependencies:
tools:
- type: "mcp"
value: "github"
description: "GitHub MCP server"
transport: "streamable_http"
url: "https://api.githubcopilot.com/mcp/"
policy:
allow_implicit_invocation: true
这段 YAML 的作用分三类:
interface: 给 UI、插件列表、skill chip、默认 prompt 使用。
dependencies: 声明 skill 依赖的工具,例如 MCP server 或 env var。
policy: 控制是否允许隐式出现在模型可见的 available skills 列表中。
openai.yaml 解析失败不会阻塞 SKILL.md
load_skill_metadata 会尝试读取 skill_dir/agents/openai.yaml。如果不存在、读失败或 YAML 无效,Codex 会 fail open:忽略这份可选元数据,但不阻止 SKILL.md 被加载。
这和 SKILL.md frontmatter 不同。SKILL.md 缺少 frontmatter、YAML 无效、缺少 name 或 description,会导致这个 skill 解析失败。
policy.allow_implicit_invocation 控制“默认出现在列表中”
policy.allow_implicit_invocation: false 的含义是:
这个 skill 默认不进入模型可见的 available skills 列表。
但用户显式通过 $skill 或结构化选择仍然可以使用它。
它适合不希望模型根据描述主动触发的 skill,例如危险、昂贵、内部测试或需要明确用户意图的 workflow。
场景六:skill 依赖 MCP 或环境变量时发生什么
用户说:
用 $openai-docs 帮我查最新 OpenAI API 文档。
openai-docs 的 agents/openai.yaml 可能声明:
dependencies:
tools:
- type: "mcp"
value: "openaiDeveloperDocs"
description: "OpenAI Developer Docs MCP server"
transport: "streamable_http"
url: "https://developers.openai.com/mcp"
当这个 skill 是本轮显式提到的 mentioned_skills 时,run_turn 会先处理依赖,再让模型采样。
MCP 依赖安装
MCP 依赖处理入口是 maybe_prompt_and_install_mcp_dependencies。它会检查:
当前客户端是否 first-party
Feature::SkillMcpDependencyInstall 是否开启
本轮是否有 mentioned_skills
这些 skill 是否声明了 type = "mcp" 的 dependencies.tools
对应 MCP server 是否已经安装
如果缺失,Codex 会发起用户确认:
相关提示词 / Tool Description
英文原文:
The following MCP servers are required by the selected skills but are not installed yet: {server_list}. Install them now?
中文对照:
选中的 skill 需要以下 MCP server,但它们尚未安装:{server_list}。现在安装吗?
这段话的作用是:把 skill 的外部工具依赖变成显式授权步骤。用户选择安装后,Codex 会把缺失 MCP server 写入全局配置,必要时执行 OAuth login,然后刷新 MCP server 列表。
注意,这个提示不是模型在回答里“写出来”的自然语言,也不是模型看到 SKILL.md 后发起的普通 toolcall。它是 host 在模型采样前检查显式 mentioned_skills 后,通过 request_user_input 这类用户确认机制发出的安装询问。
如果用户没有通过 $skill、skill 链接或结构化方式显式选择,而只是模型语义判断要用某个 skill,这条 pre-turn 依赖安装链路不会自动补触发。因为代码里的依赖安装输入是 mentioned_skills,它来自用户输入解析,而不是模型后续的语义判断。
env_var 依赖只保存在当前 session
skill 也可以声明:
dependencies:
tools:
- type: "env_var"
value: "GITHUB_TOKEN"
description: "GitHub API token with repo scopes"
当 Feature::SkillEnvVarDependencyPrompt 开启时,Codex 会检查本机环境变量。如果缺失,会通过 request_user_input 向用户请求 secret。代码里的提示说明这类值:
stored in memory for this session only
也就是只存当前 session 的 dependency env,不写入长期配置。
场景七:为什么读 SKILL.md 或运行 scripts 也会被记录为 skill 使用
用户没有写 $skill,但模型根据 available skills 列表自己执行:
sed -n '1,220p' /home/tlinux/.codex/skills/scenario-tech-article-writer/SKILL.md
或者运行:
python3 /home/tlinux/.codex/skills/skill-creator/scripts/generate_openai_yaml.py ...
这时并没有 pre-turn 的 <skill> 注入,但 Codex 仍然可以记录“这个 skill 被隐式使用过”。shell 和 unified exec handler 会调用 maybe_emit_implicit_skill_invocation,它再调用 detect_implicit_skill_invocation_for_command。
检测规则很具体:
如果命令是 cat/sed/head/tail/less/more/bat/awk 等读取器,
并且读取的是某个 SKILL.md,就认为该 skill 被隐式调用。
如果命令是 python/python3/bash/zsh/sh/node/deno/ruby/perl/pwsh 等 runner,
并且执行的是某个 skill/scripts/ 下的 .py/.sh/.js/.ts/.rb/.pl/.ps1,
也认为该 skill 被隐式调用。
这条链路主要用于 telemetry 和 analytics:
记录 skill name
记录 scope: repo/user/system/admin
记录 path
记录 invocation_type = Implicit
避免同一 turn 重复记录
它不会把 SKILL.md 自动注入给模型,也不会改变权限。它只是识别“模型已经通过文件读取或脚本执行实际使用了这个 skill”。
场景八:skill 如何被禁用、裁剪和治理
当 skill 很多时,Codex 需要避免 available skills 列表撑爆上下文。
元数据预算
build_available_skills 使用一个 skill metadata budget:
如果模型有 context_window,默认用 2% 作为 skill metadata budget。
否则使用 8000 characters 作为 fallback。
如果所有 skill 的完整描述放不下,Codex 会先保留每个 skill 的最小行:
- skill-name: (file: /path/to/SKILL.md)
然后在剩余预算中按字符分配 description。如果连最小行都放不下,就只能省略部分 skill,并向用户发 warning。
相关提示词 / Tool Description
英文原文:
Skill descriptions were shortened to fit the 2% skills context budget. Codex can still see every skill, but some descriptions are shorter. Disable unused skills or plugins to leave more room for the rest.
中文对照:
为了适配 2% 的 skill 上下文预算,skill 描述被缩短了。Codex 仍能看到每个 skill,但部分描述更短。可以禁用不用的 skill 或 plugin,为其他内容留下更多空间。
这段话的作用是:当描述被裁剪时提醒用户。裁剪不会改变磁盘上的 SKILL.md,只影响本轮模型看到的 available skills 列表。
如果最小信息也放不下,另一条 warning 是:
相关提示词 / Tool Description
英文原文:
Exceeded skills context budget. All skill descriptions were removed and {n} additional skills were not included in the model-visible skills list.
中文对照:
超出了 skill 上下文预算。所有 skill 描述都被移除,并且还有 {n} 个额外 skill 没有进入模型可见列表。
这段话的作用是:明确告诉用户有些 skill 对模型不可见,因此模型无法主动选择它们。用户仍可以通过显式路径或 $skill 使用没有被配置禁用的 skill。
路径别名
如果 skill 路径很长,Codex 会尝试构造 skill root alias:
### Skill roots
- `r0` = `/very/long/path/to/skills/root`
### Available skills
- demo-skill: ... (file: r0/demo/SKILL.md)
这不是另一个存储系统,只是为了节省 prompt token。
禁用规则
用户或 session config 可以通过 skills.config 按 name 或 path 禁用 skill。resolve_disabled_skill_paths 会把这些规则解析成 disabled_paths。
被禁用的 skill:
不会进入 available skills 列表
不会被 `$skill-name` plain mention 选中
不会进入隐式调用索引
如果只是 policy.allow_implicit_invocation: false,它不会出现在 available skills 列表,但仍可以被显式选择。
cache 只减少扫描成本,不减少 prompt 成本
SkillsManager 有两个 cache:
cache_by_config: 按 skill roots + config rules 缓存结果
cache_by_cwd: 按 cwd 缓存结果
这些 cache 避免每个 turn 都重复扫描磁盘。它们不等于“把 skill 压缩进长期记忆”,也不减少模型上下文 token。真正控制 token 的是 available skills 的 metadata budget,以及 SKILL.md 的按需加载策略。
一条完整链路:从用户请求到 skill 生效
以当前请求为例:
用户:使用 scenario-tech-article-writer skill 写一篇文档,详细介绍 Codex 如何执行 skill。
完整链路是:
1. 会话构造初始上下文
Codex 扫描各个 skills root,解析 SKILL.md frontmatter 和 agents/openai.yaml。
2. developer prompt 注入 available skills
模型看到 scenario-tech-article-writer 的 name、description、file path。
3. 用户点名 skill
如果输入被识别为结构化 skill 或 $scenario-tech-article-writer,host 会预先读取完整 SKILL.md 并注入 <skill> fragment。
如果只是自然语言点名,模型根据 trigger rule 自己打开 SKILL.md。
4. 模型读取 SKILL.md
它只读取足够执行工作流的内容;如果 SKILL.md 指向 references/,再读取具体需要的文件。
5. 模型执行普通工具
写文档时可能用 shell 查看源码,用 apply_patch 创建文件,用 rg 搜索引用。
如果 skill 要求运行脚本,脚本通过普通 shell/exec 执行。
6. 结果进入会话历史
工具调用、文件修改、模型回答都按普通 turn 流程记录。
7. 如果上下文过长
这不是 skill 系统单独处理,而是交给 Codex 的会话压缩、上下文管理和 rollout 持久化机制处理。
管理视角:设计优点和边界
Codex 的 skill 机制有几个明显取舍。
第一,它把“选择”交给模型,把“发现和注入”交给 host。host 只负责给出列表、解析显式 mentions、读取被显式选择的 SKILL.md;语义匹配主要靠模型读 description 判断。这让 skill 扩展很灵活,但也要求 description 写得非常准确。
第二,它用渐进式披露控制上下文。常驻 prompt 只放元数据,正文按需读取,references 更按需读取。这个设计能让 skill 数量增长,但不意味着可以无限增长。skill 太多时,available list 会裁剪;SKILL.md 太长时,读入正文仍会占用上下文。
第三,它没有给 skill 脚本特殊权限。脚本只是普通工具调用,仍受 turn sandbox 和 approval 控制。这避免了“安装一个 skill 就扩大权限”的风险。
第四,agents/openai.yaml 是 host 元数据,不是模型主提示词。它适合放 UI、默认 prompt、依赖、策略;真正改变模型行为的仍然是 SKILL.md body 和 available skills developer prompt。
第五,隐式调用统计不是自动加载。模型读取 SKILL.md 或运行 scripts/ 时,Codex 可以记录一次 implicit invocation;但这个记录不会反向把 skill 正文塞进上下文。
如果要进一步增强这个系统,常见方向是:
对 skill description 做检索排序,而不是只靠全量列表预算。
对大型 references 做 top-k retrieval,而不是让模型手动 rg。
对 skill 使用效果做质量评估,自动发现 stale skill。
对 dependencies 做更统一的生命周期管理。
对自然语言点名 skill 的 host-side 解析更强,减少模型手动打开文件的步骤。
但当前实现的核心思想已经很清楚:Codex skill 不是一个插件运行时,而是一个受 prompt 驱动、host 辅助加载、工具实际执行的分层上下文系统。
更多推荐



所有评论(0)