
这个系列写到第四篇前几篇文章我一直在和同一个问题较劲我把开发任务的执行规范写成一整套SKILL文档丢给AI让它照着生成代码结果它经常像没看过一样怎么写都跑偏。所谓SKILL你可以理解成一套用来约束AI行为的任务规范现在社区里叫Agent Skill、Codex Skill的本质上都是同一个东西。我试过把规则写得更具体试过把SKILL拆成若干小模块试过换模型、换会话、换措辞效果都很有限。直到我把SKILL的写法彻底改成“框架细节”两层结构才第一次看到AI老老实实按流程走完。这篇文章就是这次改造与验证的全程记录包含AI反复不执行的那五轮完整调试过程以及最后被我验证有效的修复思路。如果你正在用AI生成代码并且被“它就是不按我说的做”气到想摔键盘这篇应该能帮你少熬几个夜。1. 为什么我要把SKILL从“一段话”改成“框架细节”两件套1.1 前三次尝试留下的教训AI不是不听话是没拿到可执行的边界前几篇的试验里我的SKILL结构通常是一段任务背景、三段功能需求、一段注意事项。自己读起来逻辑通顺但AI执行起来完全不是一回事。我让它“用标准库实现”它擅自引第三方依赖我规定“函数名统一动词开头”它开局就定义了一个叫data()的函数我强调“先写设计再写代码”它直接吐出一大坨没有注释的代码。最令我崩溃的是我把它违规的地方指出来它道完歉之后下一轮依然违规。那几天我一度怀疑是模型能力上限直到我做了一次最基础的变量控制实验才意识到问题出在SKILL的“表达方式”而不是模型的“执行能力”。为什么会这样简单说模型生成代码的时候它首先在做一个“概率选择题”。训练数据里大量优秀代码的样子是“import完之后直接写逻辑”所以当它生成完import部分下一段最可能的token就是代码主体而不是我写在SKILL里的“请先输出执行清单”。我的规则不是被无视了而是在概率竞争里输给了模型的代码先验。这给我的启发是写SKILL不是一个写文档的任务而是一个设计“概率轨道”的任务。只把要求写清楚是不够的还要让它出现在模型最可能做选择的位置上并用可预测的方式拦住自由发挥。1.2 “框架细节”的核心思想先让AI看到全局地图再让它无法自由发挥所谓“框架细节”就是把原来的长段落SKILL拆成物理上完全独立的两层。框架层解决“这个任务是什么、覆盖哪些环节、按什么顺序推进、怎样才算完成”细节层解决“具体用到哪些API、变量怎么命名、哪些边界情况必须处理、哪些写法绝对禁止”。两层分开之后我还固定了一份声明如果框架层和细节层出现任何冲突一律以细节层为准如果细节层与模型自身经验冲突以细节层为准。这条优先级声明看似废话其实非常关键它给模型一个“不要自由发挥”的依据。没有这句声明时模型会自动选择它觉得更“合理”的那条指令而它的“合理”往往就是它训练数据里的主流写法。我拿实习生来类比你给新人一份“项目说明”和一份“编码规范”前者讲清楚背景和目标后者规定具体的变量命名、目录结构、禁止写法。新人去看这两个文档时的心理过程完全不同看项目说明时他在建立宏观认知看编码规范时他在记忆硬性约束。如果你把两份内容混在一起新人大概率只记住他最后看到的那部分。模型也一样混排的SKILL会让所有规则争夺有限的注意力而被抢夺的对象恰好是“不要用某个API”这类最关键的东西。1.3 这次验证的目标不是生成一个能跑的脚本而是让AI严格按规范执行为了验证“框架细节”是否真的有效我特意选了一个极小的任务用Python标准库实现一个目录归档脚本。之所以选这么简单的任务是因为任何主流模型靠直觉都能写好如果这种任务都会失败那失败原因只能是“没有执行SKILL”而不是能力不足。验证目标定得很死第一AI是否先输出它要遵守的执行框架第二代码是否完整实现细节层里规定的4个函数和3条边界规则第三是否没有引入任何第三方依赖。三个条件全部满足才算通过。下面五轮对话记录了我从失败到稳定通过的全过程这里面包含的坑比我自己手写十次这个脚本都多。2. 改造后的SKILL文档长什么样一份可复用的示例2.1 框架层任务目标、输入输出、执行步骤、验收标准下面是我在验证中使用的一版SKILL编号PY-ARCHIVE v0.3先看框架层SKILL-PY-ARCHIVE v0.3框架层 任务实现一个命令行目录归档脚本。 输入命令行参数 src源目录路径、dst目标目录路径。 输出将 src 下所有文件按扩展名归档到 dst 的子目录并在控制台打印统计摘要。 执行步骤 1. 先输出你准备遵守的执行清单逐条引用细节层中的强制规则最多3行。 2. 再输出完整代码代码必须放在单个 python 代码块内。 3. 最后输出自检结果逐项核对细节层规则标注“通过/不通过”。 验收标准 - 代码可以直接运行不需要额外安装依赖。 - 隐藏文件与隐藏目录被忽略。 - 同名冲突时自动追加数字后缀。 - 执行清单、代码、自检结果三部分严格按顺序出现。框架层最重要的不是措辞而是“验收标准”的写法。每个标准必须能被检查最好是能被脚本或肉眼直接对照的比如“严格按顺序出现”、“不需要额外安装依赖”而不是“代码质量要高”这种抽象表述。模型对抽象表述只有一个模糊模拟对可检查的对比项才会真正约束生成。我后来把所有“应该”“需要”全部改成了“必须”“禁止”“严格”效果差距非常大。2.2 细节层代码结构、命名规范、边界处理、负面清单再看细节层SKILL-PY-ARCHIVE v0.3细节层 语言与依赖 - 仅使用 Python 3.9 标准库。 - 禁止 import shutil。 模块划分 - 必须定义以下4个函数 1. scan_files(src) - list[Path] 2. move_file(file, dst) - Path 3. generate_report(stats) - None 4. main(src, dst) - None 命名规范 - 函数名一律为动词开头scan、move、generate、main都是动词。 - 变量名一律 snake_case。 边界规则 - 跳过以 . 开头的文件与目录隐藏文件。 - 目标子目录不存在时自动创建。 - 文件名冲突时自动追加 _1、_2 后缀。 输出格式 - 统计摘要直接使用 print 输出不写日志文件。 负面清单 - 不要使用 os.walk。 - 不要使用 shutil.move。 - 不要使用多线程。这里给模型的关键信息不是风格建议而是“可路障”。特别要说负面清单LLM对“不要使用xx”这类约束往往比正面描述敏感得多因为它的预训练语料里有大量“不要在Python中使用xx”的问答。如果你说“使用标准库实现”它可能觉得pathlib、os、shutil都是标准库但如果你说“禁止import shutil”它每生成一行代码都要绕开shutil路障生效得非常明显。2.3 为什么要把“禁忌”写进负面清单这一栏我用一张表格展示平时容易写“空话”的地方和具体的负面清单写法这是我从这次验证中总结的对比常见的含糊写法模型容易产生的行为改成负面/可验证写法请使用干净的路径处理方式import shutil、混用os.path禁止import shutil仅用pathlib.Path函数划分要合理只写一个main或随意拆函数必须定义scan_files/move_file/generate_report/main处理可能的异常情况忽略或只try-except最外层跳过隐藏文件目标目录不存在时自动创建冲突自动加后缀不要输出无关内容在代码前加大量解释输出顺序严格为执行清单、代码块、自检结果表格的右侧每一项都对应一个自动化检查或肉眼检查条件。我自己做验证时第一件事写了个grep命令扫代码块看是否出现shutil、os.walk看是否包含“startswith(.)”来处理隐藏文件。如果SKILL里的每条规则都能落成检查命令AI执行率会明显上升因为“能不能被验证”本身也是它生成时的一个约束力。3. 调试实录AI五轮不执行的完整过程3.1 第一轮AI跳过了框架中的执行步骤直接写代码我先把v0.2版SKILL也就是还没做最后修复的版本整篇发给模型然后附上一句“请按SKILL生成代码”。模型回复得很快但直接跳过了框架层规定的执行步骤第一步没有输出执行清单直接给了一段完整代码。更关键的是代码里用了shutil.move函数划分只有两个大函数scan_files里也没有做隐藏文件过滤。我让它“按SKILL重新执行”它说了一遍抱歉然后重新输出的代码依然没有遵守边界规则。这时候我判断是“模型没有读取长上下文”于是做了一次精简。这里补充一个真实的排查细节第一轮失败后我把AI生成的代码保存下来写了个bash脚本做静态检查grep -n import ai_output.py grep -n shutil\|os.walk ai_output.py grep -n def ai_output.py grep -n startswith(\.) ai_output.py前三项全中招最后一项直接没有匹配。这让我确定了具体的偏差方向模型不是没理解任务而是在执行步骤上选了它最熟悉的“直接写代码”路径。3.2 第二轮强制“先出设计”后AI输出了一套假清单第二轮的修复方法是加强约束语气我把框架层的执行步骤从“建议先输出执行清单”改成了“如果不先输出执行清单这个任务就是失败的”。模型这次确实先输出了一份执行清单但问题变得更加隐蔽它列的清单里写着“将使用shutil模块完成移动”而细节层负面清单明确禁止shutil。也就是说它只是在编一份“看起来像计划”的文本计划的内容依然是它的默认写法完全没有把细节层的强制规则读进去。这个现象让我意识到只是让模型“先声明计划”没有用除非声明的内容可以用某种方式校验。模型并不真正理解“执行清单”是后续动作的契约它只是把它当作一段“对问题的计划式回答”来生成。这也解释了为什么很多论文里推荐让模型复述问题它不是让模型想清楚而是把它自己生成的内容作为后续token选择的上下文提高规则在概率分布里的权重。但如果复述的内容本身就是错的那它只会把错误也叫得更响。3.3 第三轮换会话、精简SKILL长度结果仍然不执行第二轮之后我做了两件事一是新建对话排除历史上下文干扰二是把SKILL从接近1500字压缩到800字以内删除功能背景、删除示例片段只保留规则和验收标准。这次模型生成的代码确实能运行了但规范层面还是违规它没有定义move_file和generate_report两个函数而是把逻辑全部塞进main命名也乱出现了file_processor这种名词开头函数。更让我意外的是即便把规则放到离输出最近的位置它依然会“先输出代码再考虑规则”。这一轮的证据很重要它排除了“上下文太长导致注意力衰减”这个假设。压缩后的800字SKILL长度远远没有超过常见的上下文窗口但该违背还是违背。我当时的判断是问题不在长度也不在语气而在SKILL内部存在某种让模型无所适从的冲突或者它根本没把细节层视为必须在生成过程中遵守的硬性约束。于是下一轮我进入消融实验。3.4 第四轮消融实验定位到SKILL内部指令冲突消融实验的思路很简单把框架层和细节层拆开分别发给模型。我开了两个新会话会话A只发框架层加任务描述不发细节层会话B只发细节层加任务描述不发框架层。结果是这样的会话A只有框架层模型老老实实输出了执行清单、代码、自检结构顺序完全达标但它用来实现move_file的代码还是shutil.move因为框架层没禁止shutil。会话B只有细节层代码完全遵守了负面清单用了pathlib四个函数齐全隐藏文件也过滤了但它没有先输出执行清单因为框架层不在场模型觉得直接给代码才是正常回答。这个结果的对照一下就让我锁定了根因单独的每一层都能被模型接受说明模型完全理解规则、也有能力执行合在一起后反而行为不稳定说明两层之间存在隐性指令冲突。我回到完整SKILL里逐句排查最终找到了那句话——细节层的输出格式里写着“代码是重点不要输出多余解释”。这句话在v0.2里是我为了控制AI废话而加的但它恰好压过了框架层的“先输出执行清单”。模型面对两个靠近的指令时更倾向于执行看起来像“最终要求”的那一个而“不要输出多余解释”就像一个音量更大的命令把框架层的步骤要求整个盖住了。3.5 第五轮修复冲突并加“复述约束”后行为终于符合预期第五轮的修复分两步。第一步是删除“不要输出多余解释”这句话把三段式输出顺序直接写进输出格式要求让框架层和细节层的指令一致。第二步是在执行步骤1里增加了一个“复述约束”的动作必须逐条引用细节层中的强制规则。这样模型生成代码之前会先把规则文本作为它自己的输出生成一遍等于在它的上文里主动注入了一堆和自己接下来的代码直接相关的约束会显著抬高规则token在后续生成中的概率。修复后的版本就是我在第二章展示的v0.3。我连续做了五轮测试每次都开新对话结果五次全部通过执行清单逐条对应细节层规则代码里没有shutil和os.walk四个函数齐全隐藏文件过滤逻辑存在自检结果全部标注通过。到这里我在第一章定的三个验证目标全部命中才确定“框架细节”这套结构本身是对的之前所有失败都出在我自己埋下的指令冲突与含糊写法上。4. 从“不执行”到“稳定执行”的关键转折4.1 定位根因的排查链路复盘把五轮调试串起来看其实是一条标准的问题排查链路轮次观察到的现象我当时的假设采用的验证手段结论1跳过步骤直接输出代码模型没读完长上下文静态检查代码规则没有成为约束2输出了与规则相悖的执行清单加强语气能提高约束力对比清单与代码内容语气无效需要可校验内容3精简上下文后仍然违规上下文过长导致遗忘压缩SKILL长度长度不是主因4单层各自通过、合体失败可能是指令冲突消融实验拆分变量确认冲突在细节层“不要输出多余解释”5修复冲突后全部通过冲突已解除、规则权重提高5次独立会话复测框架细节结构可行排查的关键不是“看现象猜原因”而是每一步都要用一个可重复的验证来排除假设。特别是在第4轮如果不做消融实验我可能还会在“语气不够强硬”这个方向上浪费很长时间。4.2 两版SKILL的差异对比与执行率变化v0.2和v0.3的执行差异可以从一份表格看得很明显维度v0.2失败版v0.3修复版输出结构只要求“先设计再代码”但细节层有“不要输出多余解释”明确的“执行清单-代码-自检”三段顺序优先级声明无框架与细节冲突以细节为准负面清单藏在正文段落里独立成节使用“禁止import shutil”这类可检查描述复述约束无执行清单要求逐条引用细节层强制规则5次独立测试通过率1/55/5执行率的提升并不是模型突然变聪明了而是我把轨道铺得更窄了。v0.2更像一个“建议包”v0.3更像一个“检查表加禁止路障”。这也是为什么很多实际工程里把系统提示词写成一堆“请尽量”“请务必”没有用真正起作用的是能被校验的命令和明确的优先级。4.3 “复述约束”为什么有效让约束参与next-token决策最后解释一下为什么让模型复述约束会有这么大用。LLM生成每个token时都会基于当前已生成的全部上文计算下一个token的概率分布。规则写在我的提示词里距离当前生成位置可能已经隔了几百甚至上千个token它的概率贡献被稀释得很厉害。而“复述约束”让模型自己先把规则输出一遍等于把规则文本拉到了离后续生成最近的上文里规则相关的token在当前概率计算中的权重就会明显上升。这就像一个实习生出门干活前我让他把“不能用这个扳手、必须按这三步走”背一遍他再去操作时这段话储存在他工作记忆最表层能实时影响动作。但要注意复述只解决“规则参与概率计算”的问题不解决“规则内容错误”的问题。如果SKILL本身有漏洞复述只会让漏洞被放大。所以它必须和“规则可验证”配合使用先保证每条规则是对的、无冲突的再让模型复述它。两个条件缺一个都会继续翻车。5. 这套方法迁移到日常AI协作的几个经验5.1 把抽象规则翻译成可自动检查的动作我后来接手的所有AI生成代码类任务都会先在SKILL里过一遍“每条规则能不能写成一个grep、一个AST检查或者一个人眼就能核对的事实”。比如“处理边界情况”这个说法会被拆成三个具体动作隐藏文件跳过、目录不存在时创建、冲突时加后缀。“代码质量要高”这种话会被直接删掉换成“禁止把逻辑全部堆进main函数”。模型不是不理解抽象概念而是抽象概念在生成代码时没有足够的约束力只有当它落到“某个符号是否出现”“某个函数是否存在”这个级别它才能真正影响生成结果。这条原则同样适用于代码评审里的检查清单。5.2 用消融实验区分“模型不懂”和“指令无效”很多人在调AI时遇到不执行就拼命改措辞改了十几版反而越改越乱。更高效的方式是先做消融实验把一个SKILL拆成几部分分别单独测试。如果单独给某一层时模型表现良好说明模型理解了这个部分的要求合在一起表现失常说明是组合方式出了问题大概率存在指令冲突或优先级不明。如果单独给某一层时模型也表现很差再去检查是不是词汇太抽象、缺例子、或者部分规则超出模型能力。这套方法和传统软件开发里的二分定位很像只要每次只改一个变量很快就能把问题缩小到很小范围。5.3 在边界位置埋“保底校验”还有一个小技巧把最重要的约束放进“自检步骤”里重复一遍。比如我要求模型在输出结束时逐项检查隐藏文件是否处理、是否有shutil、函数是否齐全。这不是我多写几行字的问题而是让同一个关键约束在输出流程里出现了至少两次一次在规则正文一次在自检动作。模型对重复出现的关键信息会更敏感而且自检步骤会强制它在结束前再次把注意力拉回规则让它有机会发现并修正前面的错误。我在实际使用中看到过很多次模型在自检步骤里主动改掉了它之前代码里的违规项相当于在一步里完成了自我修正。5.4 一段实际项目中的使用体会这套方法从那次目录归档脚本验证开始已经被我搬到好几个实际任务里了。比如给遗留代码库写迁移脚本、自动生成接口文档、按团队规范生成单元测试都适用。刚开始写一份合格的框架细节SKILL会花掉我比直接手写代码更长的时间但一旦SKILL结构稳定后面每一次生成都在复用同一套约束返工次数会降得很低。我的体会是最终决定AI协作效率的不是模型多聪明而是我能不能把任务边界设计到“模型根本没有多少自由发挥空间”的程度。如果你的AI也一直不听话先别急着换模型回去看看SKILL里是不是也埋了类似“不要输出多余解释”这种和主线矛盾的命令把那句话改掉可能比再花一晚上调提示词有效得多。