关于 writing-for-agents
为编写 Agent 会读取的技能、项目指引和文档提供结构设计参考,面向技能作者与文档维护者。内容聚焦上下文指针、信息层级、步骤标准和精简方法。
主要功能
- 01上下文指针的触发设计
- 02信息层级与渐进披露
- 03步骤完成标准设计
- 04文档拆分与并置原则
- 05冗余和过时内容修剪
适用场景
- 01编写 Agent 技能文档
- 02整理 AGENTS.md 或 CLAUDE.md
- 03优化 Agent 可读取的项目说明
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ overextended/ skills --skill writing-for-agents安装后在 Claude Code 中输入/writing-for-agents确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CREDITS.mdSKILL-MECHANICS.mdagents/openai.yaml详细介绍
面向 Agent 编写文档
本文档是编写任何 Agent 会读取的文档的参考:技能、AGENTS.md / CLAUDE.md,或通过指针引用的文档。打包方式各不相同,但写作原则相同:每次运行时,Agent 执行的都是相同的_流程_,而不是生成相同的输出,因此同一组方法能让每份文档都更可预测。
如果你要编写的是技能,请阅读 SKILL-MECHANICS.md,了解 frontmatter、调用方式选择和路由技能。
上下文指针
上下文指针是 Agent 上下文中的一条引用,用于指明某份不在当前上下文中的材料,并编码访问该材料的条件。技能的描述就是一个例子;AGENTS.md 中指向某份文档的行也是同一种对象。决定 Agent 何时访问材料以及访问是否可靠的,是指针的_措辞_,而不是目标文档。必需的目标若被措辞含糊的指针引用,就会造成方差问题:应先改进措辞,只有改进无效时才将材料内联。
指针有两个作用:说明材料是什么,并列出应触发访问的分支(分支是文档处理的一个独立情形,因此不同运行会沿不同路径处理文档)。始终加载的指针,每个词每一轮都会产生开销,因此比正文更需要精简:
- 将最关键的词放在前面:指针的触发作用体现在开头。
- 每个分支只用一个触发条件。 用同义词指称同一个分支,只是把一个分支写了两遍;应合并,只保留真正不同的分支。
- 删去正文中已有的信息。
两种开销
你添加的每份文档和每个指针,都会消耗以下两种预算之一:
- 上下文开销是 Agent 窗口中始终加载的材料所产生的成本:一行
AGENTS.md、一段技能描述,以及每轮都留在上下文中的任何内容。无论是否触发,都会消耗令牌和注意力。 - 认知开销是人类需要承担的成本:有哪些文档,以及何时该查阅每份文档。人类就是索引。这不是需要最小化的成本,而是发挥人类自主性的代价;应在需要人类判断的地方投入,在不需要的地方则予以消除。
只有通过指针才能访问的材料,不产生上下文开销,但要付出指针自身那一行的代价;完全没有指针的材料,则完全依赖认知开销。
信息层级
一份文档由两类内容构成:步骤(Agent 按顺序执行的操作)和参考内容(按需查阅的定义、规则和事实)。两者可以自由组合:全部是步骤(例如一份菜谱)、全部是参考内容(例如一份评审规则,即本技能),或二者兼有。核心决策在于每一部分应放在信息层级的哪一层。这是一个按 Agent 即时需要程度排序的阶梯:
- 文件内步骤是首要层级:Agent 按顺序执行的操作。
- 文件内参考内容按需查阅。它常常是一组扁平的同级内容(例如评审的每条规则都位于同一层),这是一种合理的安排,而非坏味道。
- 外置参考内容被移到一个单独的文件中,通过上下文指针引用,仅在指针触发时加载。它的范围从同一文件夹中的同级文件,到可以存放于任何位置、且任何文档都可以指向的完全外部参考资料。
下放的内容过少,顶层会变得臃肿;下放过多,则会隐藏 Agent 真正需要的材料。这种张力正是整个决策的核心。
渐进式披露是沿阶梯向下的操作(将内容移出主文件,置于指针之后),使顶层保持清晰可读。它主要不是为了节省 token,而是为了保护这一层级结构。分支是检验披露是否得当的最佳方式:每个分支都需要的内容应内联,只有部分分支会用到的内容则放在指针之后。当文档包含步骤时,若将本应外置的文件内参考内容留在其中,就会淹没这些步骤,使 Agent 对它们的关注变成一场碰运气的赌博。这是一个影响方差的杠杆,而不仅仅是可读性的问题。
共置是文件内部的配套原则:阶梯决定一项内容_位于多深_,共置则决定它到达后_与哪些内容相邻_。将某个概念的定义、规则和注意事项放在同一标题之下,而非分散各处,使读者阅读其中一部分时,其相关内容也随之而来。判断标准是:文档应读起来像是专为 Agent 撰写的说明文档。分组后的内容读起来如此,分散的内容则不然。(这与重复不同:重复是将同一含义在两处重复出现;分散则是将同一含义碎片化到多处。)
冗长是这里的失败模式:文档本身过长,即便每一行都有效且各不相同。注意力会被多余的内容稀释,而每多一行,就多一处需要保持相关性。解决办法同样是借助阶梯:将参考内容放到指针之后,并按分支或顺序拆分,使每条路径只承载其所需的内容。
步骤与完成标准
每个步骤都以完成标准结束,即告诉 Agent 工作已完成的条件。有两个属性使其成为一个杠杆:
- 清晰度:Agent 能否判断已完成还是未完成?一个模糊的边界(例如“达到理解”)会引发过早完成:在步骤真正完成之前就结束它,注意力滑向已经完成。其后仍待执行的可见步骤(即完成后步骤)提供拉力,而完成标准的清晰度则构成阻力。应按以下顺序应对:首先收紧边界(局部且成本低);只有当它本质上无法消除模糊,_并且_你观察到了急于收尾的现象时,才通过拆分序列来隐藏后续步骤。隐藏只有在真实的上下文边界(交接或子 Agent 派发)之上才有效;内联调用会让后续步骤留在上下文中,什么也清除不了。
- 要求强度:标准要求多少工作量。“所有已修改的模型都已核对”会迫使工作彻底,而“产出一份变更清单”则不会。要求强度驱动额外工作(Agent 在工作过程中进行的深入挖掘,潜藏于措辞之中,而非单独作为一个步骤写出)。它并不局限于步骤:“所有规则均已应用”同样约束一组扁平的参考内容,正如“所有步骤均已完成”约束一个序列。这也是为什么全部由参考内容构成的文档仍然带有穷尽性的要求。
最强的完成标准既可检查,又具有穷尽性。
何时拆分
将一份文档拆成两份,会占用两种负载中的一种,因此只有当拆分的收益足以抵偿代价时才拆分:
-
按顺序拆分:当一连串步骤中,后续步骤容易诱使 Agent 草率完成前面的步骤时,就将其拆分。把这些后续步骤移出视野,能促使 Agent 在当前任务上投入更多实际工作。反过来也要注意:若把多个序列合并,每个步骤都会暴露在其后续步骤之下,容易引发过早完成。
-
按调用方式拆分(针对 skill):参见
SKILL-MECHANICS.md。
引导词
引导词是一个已存在于模型预训练中的紧凑概念,Agent 在执行文档时会以它进行思考(lesson、fog of war、tracer bullets)。以词元而非句子的形式反复出现时,它会累积出一个分布式的定义,用最少的词元锚定一整片行为区域,并调用模型已掌握的先验知识。自创词汇同样可行,但前提是要清晰定义;而自造的词无法调用任何先验,你需要用定义词元来补偿预训练词汇免费提供的内容。因此应优先使用现成的词。
引导词会在两处起锚定作用。在正文中,它作用于_执行_:每当该词出现,Agent 都会调用同一套行为模式;在扁平的参考材料中,它会把注意力聚焦到某一类需要留意的事物上。在指针中,它作用于_调用_:当同一个词同时出现在你的提示词、文档和代码库中时,Agent 会把这种共享语言与材料关联起来,从而更可靠地找到所需内容。
要主动寻找可用引导词进行重构的机会。例如,一个三元组在三处被完整写出,或一个指针花一句话去指代某个概念,这些都是适合压缩为单一词元的段落:
- "快速、确定性强、低开销" → tight(一个 tight 循环)。
- "一个你相信的循环" → red,将模糊的门禁转化为二元可观测状态(循环在缺陷处变为 red,否则不会)。
这样你能获得两方面的收益:词元更少,同时为 Agent 的思考提供了更清晰的挂钩。假设每份文档都存在引导词可以替代的重复表述,并去把它们找出来。
否定是与这一杠杆相对的失败模式:以禁止来引导行为,会把被禁止的行为带入上下文,反而使其更容易被调用。不要想象一头大象,结果满脑子都是大象。否定只是一个较弱的修饰语,会被强激活的概念压过,禁令反而被理解为去做这件事的指令。应当使用正向提示:直接描述目标行为(例如"编写单行注释"),使被禁止的行为根本不被提及。只有当某条约束无法用正向措辞表达、必须作为硬性护栏时,禁止才值得保留;即便如此,也应搭配正向目标,使注意力落在该做什么上。
精简
- 每种含义都应只有一个唯一事实来源:即一个权威位置,这样要改变行为时只需修改一处。重复(同一种含义出现在多个位置)会增加维护成本和令牌消耗,还会让这种含义在优先级阶梯上的显著程度超过其实际排名。(有意重复令牌的开头词,其作用恰好相反:它重复的是令牌,而不是含义。)
- 环境也是事实来源(
fxmanifest.lua、package.json脚本、配置文件、server.cfg中的 convar、目录布局、--help输出),而重复陈述这些信息的文档就是缓存:一份查找结果的副本,只有在查找成本高时,才值得占用负载。缓存 Agent 无法通过查找找到的内容:未写明的约定、某项选择背后的原因、配置文件不会说明的陷阱。把只需查阅一个文件或运行一条命令就能找到的信息留给环境,这样它们就不会过时。 - 逐行检查相关性:这一行是否仍与文档的作用有关?一行内容可能因为从未与任务相关(只是说明性内容,或应该披露的分支),也可能因为其描述的行为或世界发生变化而过时,从而失去相关性。文档越短,就越容易保持相关性。如果没有精简的习惯,最终往往会堆积沉积物:过时的层层内容,因为添加让人觉得稳妥、删除却让人担心出错,直到你不得不一路挖到文档核心,才能找到仍然有效的内容。
- 逐句查找无效指令:如果模型默认就会遵守某条指令,那么写出来也只是增加负载,毫无作用。判断标准(它是否会改变相对于默认行为的表现?)取决于模型,而非读者:两个人若对某条指令是否无效意见不一,实际上是对默认行为意见不一,应通过运行文档来解决,而不是争论。若某句话未通过测试,就删除整句话,而不是只删减几个词。此测试也适用于开头词:如果一个词弱到无法胜过默认行为(例如 Agent 本来就相当认真,却仍用 be thorough),那它就是无效指令;正确做法是换成更有力的词(relentless),而不是改用另一种技巧。