乐于分享
好东西不私藏

OpenClaw 中 AGENTS.md 文件,一行尽量不超过 240 个字符,因为有特殊截断规则.

OpenClaw 中 AGENTS.md 文件,一行尽量不超过 240 个字符,因为有特殊截断规则.

大家好, 上篇内容和大家聊了 MEMORY.md在记忆系统中的流程, 以及它的截断规则。 这次我们继续补充一下上次的一些细节。

我们上次聊过, workspace 跟目录中会有下面几个 bootstrap 文件:AGENTS.md,SOUL.md,TOOLS.md,IDENTITY.md,USER.md,HEARTBEAT.md,BOOTSTRAP.md,MEMORY.md

也说过有一个长度限制规则,总长度 60000个字符, 单个文件 20000 个字符。

如果超过长度,内容就会被截断。 具体细节上篇文章中有过介绍

为什么你的 OpenClaw 总是记不住? 记忆系统探索之 MEMORY.md

但是这次要和大家聊的是一个例外, 就是 AGENTS.md 这个文件的截断规则,和上面列出的几个其他文件不太一样。

简单来说, 其他几个文件, 如果遇到超过默认字符上限, 需要截断的情况,规则是文件开头留一部分,然后结尾留一部分,中间部分截掉。

AGENTS.md 的截断规则,也有留头尾,去掉中间的逻辑。 但是它还多了一个保留关键内容的流程。

具体是这样,下面是它的三个分配常量值:

const AGENTS_POLICY_DIGEST_RATIO = 0.35;const AGENTS_POLICY_HEAD_RATIO = 0.45;const AGENTS_POLICY_TAIL_RATIO = 0.15;

也就是:

头部:45%规则摘要:35%尾部:15%提示和换行预留:约 5%

当 maxChars = 20,000

headChars    = 9,000digestBudget = 7,000tailChars    = 3,000

这里边的 digestBudget, 就是和其他文件不同的一点。 假设超过默认 20000 字符长度限制, 其中 7000个字符,要留给 digestBudget。

240个字符限制

下面我们来聊聊标题中数说的 240字符问题,AGENTS.md ,发生截断的时候, 会进入这样一个特殊为他处理的子程序,先把每一行做标准化,这里面就会把每行最大限制到 240字符。

从完整文件中查找规则候选行

等价于:

const candidates = content  .split(/\r?\n/u)  .map((line, index) => ({    index,    line: normalizePolicyDigestLine(line),  }))  .filter(({ line }) => {    return line.length > 0 && isPolicyDigestCandidate(line);  });

这里扫描的是完整 AGENTS.md,包括最终不会出现在头部和尾部的中间区域。

每个候选行保留:

index:原始行号line:标准化后的文本

标准化每一行

逻辑等价于:

let normalized = line.trim();normalized = normalized.replace(/\s+/gu, " ");if (normalized.length > 240{  normalized = utf16SafePrefix(normalized, 239+ "";}

具体规则:

  1. 删除行首和行尾空白。
  2. 连续空格、Tab 等压缩成一个空格。
  3. 单行最多 240 个字符。
  4. 超长行保留前 239 个字符,再添加 

例如:

-   Never      commit   secrets

会变为:

- Never commit secrets

候选行匹配

对所有的行做了标准化之后,就会进入候选行匹配, 这里的意思是那些行有资格被当作重要的内容,有两种主要类别:

第一类:Markdown 结构行。

const markdownRule =  /^(?:#{1,6}|\s*[-*+]|\s*\d+[.)])\s+\S/u.test(line);

可以匹配:

# Heading## Heading- Rule* Rule+ Rule1. Rule2) Rule

第二类:包含规则关键词的普通行。

等价关键词集合:

const candidateKeywords = [  "AGENTS.md",  "scoped",  "required",  "must",  "never",  "do not",  "before subtree",  "read scoped",  "owner",  "security",  "secret",  "credential",  "test",  "validation",  "command",  "commit",  "push",  "github",  "pr",];

匹配大小写不敏感。

具体调用代码:

return markdownRule || containsCandidateKeyword(line);

高优先级规则

上面两条规则,会把特殊 markdown 标题语法作为重要内容, 也会把包含上述关键字的行作为重要内容。

除此之外,还有一个高优先级关键字规则, 就是上述关键字列表的一个子集:

const highPriorityKeywords = [  "AGENTS.md",  "scoped",  "required",  "must",  "never",  "do not",  "before subtree",  "read scoped",  "security",  "secret",  "credential",];

这些内容优先于 testcommitpushgithub 等普通候选。

选取顺序

接着会先从 highPriorityKeywords 这个匹配行中优先选择, 如果都选完, 还有可以用的字符配额, 再去从普通匹配行中选取。只要知道这点 highPriorityKeywords 中关键字匹配到的行, 会优先占用 AGENTS_POLICY_DIGEST_RATIO 的字符配额。

篇幅原因这个过程就不展开了。

总结

总之前面说这这么多, 主要是给大家展示 AGENTS.md 特殊截断规则的一些具体过程,让大家有一个实际的理解。

我们的标题已经把最核心要表达的事情说了, 尽量每行不要超过 240 字符,特别是中间位置的内容。

解释一下,一旦 AGENTS.md 超过 20000 个字符的上限,哪怕只多了 1 个字符,也会走到截断流程, 这时候文件内容的 前 45% 和 后 15% 还会原样保留, 但是中间那 35% 的内容, 就一定会变成标准化后,也就是 240 字符以后都别截掉的样子。 一旦这件事情发生,而你这里面很多行都超过 240 字符的话,就会损失很多语义内容。

然后大家是不是还会有一个发现, candidateKeywords 的列表是英文关键词。 如果你是用英语之外的语言写的 AGENTS.md, 在关键字匹配这个流程上,你的内容基本不会被匹配到。 因为这个阶段没有到达语言模型的参与,无法理解语义,只能用程序的快速字符串匹配。

当然,匹配规则不只有关键字, 还有 markdown 语法元素。 其实从这个匹配规则上,大家也能更了解 AGENTS.md 这个文件的优化的写法怎么来写。

这次我们就先聊这么多, 希望对你有帮助。