给弱模型一本说明书:把文档规范做成单文件 Skill,也终于分清了 Skill 和 MCP
1. 弱模型写文档为什么总翻车从一份规范说起我手里那份资料编写规范最早是给团队新人看的。标题怎么写、段落怎么分、列表什么时候用、表格分隔行长什么样、代码块标什么语言、术语大小写怎么统一、版本号用三段还是四段、单位前面要不要空格零零总总几十条。人读一遍能记住大概真到写的时候还是靠翻文档翻完还容易漏。后来这份规范要交给一个本地部署的 Qwen 模型用问题就放大了。这个模型能力不算强长提示词里靠后的规则经常被忽略跨文件的引用基本不认遇到“适当处理”“保持一致”这种词就开始自由发挥。我把整份规范粘进 Prompt输出确实比不粘强一点但每次结果都不一样同一个表格这次分隔行对了下次又错了同一个术语这次大写下次小写。这不是规范不够多的问题是规范没有变成模型能执行的步骤。人看规范是“理解意图”模型看规范需要的是“判断条件 动作 验收标准”。比如“表格写规范一些”对人是一句话对模型是一团模糊。我后来把它拆成表头两端保留空格、分隔行用| --- | --- |、空单元格填-、整列都是-时删掉该列、复杂类型里的竖线写成\|。拆到这个粒度模型才不再猜“规范”是什么意思。所以这篇要讲的事情很具体把一份文档规范做成一个单文件 Skill用SKILL.md承载规则配合 Codex 的加载机制和 Prompt 的任务边界让弱模型也能稳定执行。同时把 Skill 和 MCP 的职责边界讲清楚这两个东西经常被混在一起说实际解决的是完全不同层面的问题。如果你也在做类似的事比如让模型按团队规范写接口文档、按模板生成周报、按固定格式整理测试用例这套思路可以直接搬。核心不是让规范更长而是把自然语言规范翻译成可重复执行的工作说明。2. Skill 和 MCP 到底谁管什么先把职责边界钉死在动手写SKILL.md之前得先把 Skill 和 MCP 的关系理清楚不然很容易写成四不像。我一开始也犯过这个错想着“既然要读文件那是不是得挂个 MCP”结果发现根本不需要。Skill 是给模型的一套可重复使用的任务说明和工作流程。它回答的是“这件事该怎么做”。一个 Skill 目录至少包含SKILL.md文件里要有name和description两个字段还可以按需加脚本、参考资料、资源文件。Codex 的加载机制是渐进式披露先看到 Skill 的名称、描述和路径判断这个任务要不要用它决定用了才加载完整指令。这个设计对弱模型特别友好因为不会一上来就把几千字规则全塞进上下文。MCP 全称 Model Context Protocol是 AI 应用和外部系统交换上下文与能力的协议。它回答的是“模型能连接什么、调用什么”。MCP 采用 Host—Client—Server 架构Host 是协调连接的 AI 应用Host 为每个 Server 创建对应的 ClientClient 维护连接Server 提供上下文或能力。MCP Server 暴露三类核心能力Tools 是可执行函数比如文件操作、API 调用、数据库查询Resources 是供应用读取的上下文数据比如文件内容、数据库记录、接口响应Prompts 是可复用的交互模板。把两者放一起对比会更清楚对比项SkillMCP核心作用告诉模型如何完成任务连接模型与外部数据和工具解决的问题流程、规范、经验复用外部能力接入主要内容指令、规则、流程、示例、可选脚本Tools、Resources、Prompts 等协议能力是否需要外部服务通常不需要通常需要 MCP Server 或对应连接是否直接提供业务数据通常不提供可以提供是否定义工作步骤是主要用途不是核心职责典型例子文档规范 SkillGitHub、数据库或文件 MCP Server一句话概括Skill 解决“怎么做”MCP 解决“可以连接什么、调用什么”。这个概括方便理解但现实系统里边界会有交叉比如 MCP Server 也能提供 PromptsSkill 也能声明工具依赖。不过主要关注点不同前者偏工作方法后者偏标准化连接。判断该用哪个先问两个问题任务的方法是否需要复用任务是否需要连接外部世界前者决定要不要 Skill后者决定要不要 MCP。如果只是让模型按规范改一篇文档不需要外部数据那就纯 Skill。如果要从知识库读接口定义再按规范生成文档那就是 Skill 定方法、MCP 取数据两者配合。这里要强调一点Skill 不是新模型不会改变 Qwen 的参数规模也不等于微调、知识库或插件更不会自动让弱模型变强。它主要解决“模型应按什么流程和规范做事”。最终效果仍受模型能力、上下文长度和运行平台支持程度影响。MCP 同理它不会自动提高模型能力只是给模型接上了外部的手和眼。3. 单文件 SKILL.md 的目录结构与字段模板现在进入动手环节。我最终选择只保留一个SKILL.md不拆scripts/、references/、assets/。原因很现实使用场景是受限的内部开发环境本地模型能力有限我不希望它跨多个文件查找规则也不想为复制、路径和加载顺序增加新的失败点。单文件方案的优势是复制一个文件就能用排查问题只有一个入口规则不会因为漏加载某个 reference 而失效。这是针对当前环境的工程取舍不是所有项目的最佳实践。先看目录结构。Codex 的 Skill 一般放在项目或用户级目录下我用的路径是.agents/ └── skills/ └── document-writing-spec/ └── SKILL.md如果你的 Codex 版本用的是.codex/skills/把路径换掉即可SKILL.md内容不变。关键是SKILL.md的头部字段这是触发和加载的依据--- name: document-writing-spec description: 根据本地资料编写规范对文档进行新建、改写、补全、格式化和规范检查。适用于 Markdown 技术文档、接口说明、测试用例和团队内部资料。 ---name是 Skill 的唯一标识用短横线连接的小写英文。description不只是简介它是触发边界。Codex 可以被显式要求使用某个 Skill也可以根据description隐式匹配。所以描述必须清楚说明它做什么而不是只写一个宽泛名称。我一开始写的是“文档处理”结果模型经常在无关任务上误触发改成上面这版之后准确多了。正文部分我按“入口—执行—规则—兜底—验收”组织一共十九个章节。顺序很重要弱模型如果先看到几百条格式细节却不知道当前任务是什么很容易局部执行。先确定任务再加载约束能降低把“检查”误做成“重写”、把“格式化”误做成“润色”的概率。章节骨架大致是这样## 使用范围 ## 不适用范围 ## 输入内容 ## 规则优先级 ## 固定执行流程 ## 内容规则 ## 结构规则 ## Markdown 规则 ## 标题规则 ## 列表规则 ## 表格规则 ## 图片规则 ## 链接规则 ## 代码规则 ## 标点与空格规则 ## 单位与版本号规则 ## 术语规则 ## 禁止事项 ## 信息不足与规则冲突处理 ## 正反例 ## 输出要求 ## 最终自检规则优先级从高到低是用户当前任务中的明确要求、强制规则、特殊场景规则、通用规则、推荐规则、模型默认写作习惯。这个顺序解决的是冲突问题。比如用户只要求检查问题时模型不应该因为“完整输出更好看”就重写全文。规范要求三段式版本号、输入却是四段式时模型需要识别冲突而不是静默选一个自己喜欢的。固定执行流程是判断任务类型、提取用户要求、识别文档和读者、检查信息完整性、处理冲突、确定结构、编写或修改、应用格式、统一术语和标点、检查禁止事项、静默自检、输出结果。流程的目标是减少漏项不是要求模型展示内部推理。文件里明确要求执行过程保持静默只输出最终文档或必要问题。规则等级用明确词语划分“必须”代表验收条件“禁止”和“不得”代表越界条件“优先”和“建议”允许在不冲突时采用。相比之下“适当”“视情况”“酌情”把判断责任重新丢给了模型模型越弱越容易产生不一致结果。禁止事项单独集中一章包括不得虚构事实、数据、接口、参数、路径和引用不得改变原文含义不得删除关键条件不得混用名称不得使用裸链接、错误标题层级和未经评审的网页图片。这组负面约束对技术资料特别重要一个“更通顺”的参数名如果并不存在就是错误一个看似合理但来源不明的接口字段就是幻觉。最后是 29 项静默自检从用户要求、事实完整性、标题层级一直检查到表格、代码块、链接、图片、单位、术语、个人信息和无关解释。每一项都能回答“是”或“否”比“整体检查一下质量”更容易执行。它不能保证百分之百正确但给模型建立了明确的完成条件也让失败样例更容易定位到具体规则。4. Codex 侧加载与触发配置让 Skill 真正被调用文件写好了接下来要让它被 Codex 正确加载和触发。这一步不做SKILL.md就是躺在磁盘上的死文件。先说加载路径。Codex 会扫描约定目录下的 Skill我实测下来项目级放在.agents/skills/下最稳用户级可以放在~/.agents/skills/。目录名要和name字段一致也就是document-writing-spec。放好之后可以用一条命令确认 Codex 是否识别到codex skills list如果输出里能看到document-writing-spec和它的 description说明加载成功。看不到的话先检查目录层级是不是多套了一层比如.agents/skills/document-writing-spec/document-writing-spec/SKILL.md这种就是错的。触发方式有两种。显式触发是在 Prompt 里直接点名使用 document-writing-spec Skill 对 test.md 执行仅格式规范化。 只修正格式问题不润色、不扩写、不缩写、不改变原文含义不修改代码、参数、路径和专有名词。 直接修改 test.md完成后列出修复的格式问题。隐式触发是 Codex 根据description自动匹配。比如你说“帮我按团队规范检查这篇接口文档的格式”它可能自动挂上这个 Skill。隐式触发方便但不完全可控重要任务建议显式点名。这里有个关键点Skill 负责稳定流程Prompt 负责本次任务边界。两者分工要清楚。我前面提到当前SKILL.md虽然把“格式化”列为任务类型但没有单独定义“仅格式规范化”模式它的边界分散在“必须保留关键信息”“禁止改变原意”“禁止混用名称”“用户只要求指出问题时不得重写”等规则中。所以真实测试里我仍会在 Prompt 里补一层限制只修正排版不润色、不扩写、不缩写、不重构不修改接口、参数、路径、代码和专有名词。这不是否定 Skill而是让本次任务边界更精确。后续版本可以考虑把“仅格式规范化”提升为独立模式。如果你用的是 Cline 或带 MCP 的编辑器Skill 和 MCP 的配置是分开的。Skill 走文件系统加载MCP 走cline_mcp_settings.json之类的配置文件。两者不要混在一个配置里。比如 Cline 的 MCP 配置长这样{ mcpServers: { filesystem: { command: npx, args: [-y, modelcontextprotocol/server-filesystem, /path/to/docs] } } }而 Skill 不需要写进这个文件它只需要放在 Codex 能扫描到的 skills 目录。这一点很多人会搞混以为 Skill 也要注册到 MCP 配置里其实完全不用。再说模型接入。Codex 本身要连模型才能跑我用 TaoToken 统一了 Key 和 API 通道这样换模型不用改一堆配置。Base URL 填https://taotoken.net/apiKey 在控制台生成Model ID 按你实际用的填。三件套缺一不可# ~/.codex/config.toml model claude-sonnet-4-5 model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEYKey 通过环境变量注入不要硬编码在配置文件里export TAOTOKEN_API_KEYsk-你的key如果你用的是auth.json方式结构类似{ provider: taotoken, base_url: https://taotoken.net/api, api_key: sk-你的key, model: claude-sonnet-4-5 }配置完可以用一条最小请求验证通道是否通curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: 回复 ok}] }返回里有choices字段且内容是ok说明 Key 和通道都正常。这一步过了再回去跑 Skill能排除掉一半“看起来是 Skill 不生效其实是模型没连上”的问题。5. 验证请求与常见报错排查配置好之后怎么确认 Skill 真的在起作用我的做法是准备一篇故意写坏的 Markdown保留原始版本然后跑一遍对比。测试文档test.md里故意埋这些问题标题跳级从#直接到###、列表符号混用-和*交替、表格分隔行写成|--|--|、代码块没标语言、中英文之间缺空格、术语大小写不一致。然后执行使用 document-writing-spec Skill 对 test.md 执行仅格式规范化。 只修正格式问题不润色、不扩写、不缩写、不改变原文含义不修改代码、参数、路径和专有名词。 直接修改 test.md完成后列出修复的格式问题。执行完用git diff看变化而不是只看最终文档“好像更整齐”。重点检查四件事正文语义有没有变、标题列表表格代码块问题有没有遗漏、接口参数路径代码专有名词有没有被擅自改、相同输入多次执行结果是否基本稳定。diff 里每一处变化都应该能对应到 Skill 或本次 Prompt 的明确规则对不上的就是模型自由发挥需要回去补规则。下面是我踩过的几个真实报错按出现频率排401 Unauthorized。这个最常见八成是 Key 没注入或写错了。先确认环境变量在当前 shell 里生效echo $TAOTOKEN_API_KEY如果输出为空说明export没在当前会话执行或者写进了.bashrc但没source。注意 Codex 启动的进程可能不继承你交互 shell 的环境变量必要时在启动脚本里显式导出。local proxy failed / connection refused。这个报错通常出现在 Base URL 写错或本地有残留代理配置时。检查config.toml里的base_url是不是https://taotoken.net/api注意结尾不要多加/v1路径拼接由客户端处理。另外确认系统环境里没有指向本地的HTTP_PROXY、HTTPS_PROXY有的话先清掉unset HTTP_PROXY HTTPS_PROXY ALL_PROXYreading choices: unexpected end of JSON input。这个报错说明请求发出去了但返回体不完整常见原因是流式响应被中途截断或者模型名写错导致服务端返回了非预期结构。先确认model字段是服务端支持的 ID再用非流式方式发一次最小请求验证。如果最小请求正常那就是流式解析的问题检查客户端版本。OAuth / token expired。如果你用的是带 OAuth 的客户端token 过期后会报这个。重新走一遍授权流程或者改用 API Key 方式接入。用 TaoToken 的 Key 方式就不涉及 OAuth 刷新省掉这类问题。Skill 没被触发。表现是模型完全没按规范来输出和裸模型一样。先跑codex skills list确认 Skill 被识别再检查description是不是太宽泛导致没匹配上或者太窄导致该触发时没触发。显式点名是最稳的验证方式如果显式点名都不生效那就是路径或字段格式问题。规则冲突导致输出摇摆。同一个输入两次执行结果不同通常是规则优先级没写清楚或者存在两条互相矛盾的规则。回去检查“必须”和“建议”有没有混用特殊场景规则和通用规则有没有重叠。把冲突项按优先级排一遍再重复测试。排查的核心思路是分层先确认模型通道通curl 最小请求再确认 Skill 被加载skills list再确认触发方式显式点名最后才怀疑规则本身。跳过前面几步直接改SKILL.md往往是在错误的地方使劲。6. 把通道和规范都固定下来这套东西跑通之后我最大的感受是对弱模型来说明确比聪明更重要。Skill 的价值不在于把提示词写得更长而在于把任务边界、规则优先级、执行流程和检查标准写清楚。单文件方案是针对受限环境的取舍它牺牲了一部分渐进式拆分和资源复用能力换取更低的加载复杂度和更直接的排障路径。当规范继续扩大、模型能力提高或平台支持更多能力时这个 Skill 还可以演进补上独立的“仅格式规范化”模式拆出模板和参考资料或者用脚本完成需要确定性的检查。但那是后面的事先把当前这版跑稳。通道侧我用 TaoToken 统一了 Key 和 API 地址Codex、Cline 这些客户端都指向同一个 Base URL换模型只改model字段不用每个客户端重新配一遍。Key 在控制台生成接入文档里有各客户端的配置示例。如果你要长期跑编码或 Agent 任务Coding Plan 比按量更划算只是验证模型效果的话模型对话页面直接试就行。Skill 和 MCP 解决的是两个层面的问题。一个可靠的 Agent 系统既需要清晰的做事方法也需要可信的外部能力。前者减少随意发挥后者减少脱离事实。把SKILL.md写扎实把通道配稳定剩下的就是拿真实样例反复回归让规则在 diff 里一点点收敛。