Skip to content

04.2 注意力机制自白

指令为什么会失效、位置为什么携带权重、以及你的指令在和什么东西竞争。

读完你能做什么:诊断"它为什么不听话",并用位置和结构而非更多措辞来解决问题。

⚠️ 同 04.1 的认识论声明:这是工程化心智模型,不是权重级的精确描述。


一、你的指令在和谁竞争

当你写下一条指令,它不是被放进一个"指令寄存器"。它只是上下文中的一段文本,和其他所有内容平等地参与注意力计算。

它的竞争对手包括:

text
你的指令:「回答不超过 5 句」
      ↓ 竞争
┌────────────────────────────────────────┐
│ · 系统提示词里关于"提供有帮助回答"的倾向    │
│ · 我自己前面 20 轮的长回答(自我示范)      │
│ · CLAUDE.md 里可能存在的相反规定           │
│ · 当前问题本身的复杂度(复杂问题倾向长回答) │
│ · 训练分布中"详细回答=好回答"的先验         │
└────────────────────────────────────────┘

你的指令能不能赢,取决于它的"注意力份额"。 而份额受三个因素影响:位置、重复次数、结构显著性。


二、指令稀释:一个可量化的直觉

2.1 现象

同样一条「回答不超过 5 句」:

上下文总长遵守率(主观观察)
500 token很高
5,000 token
50,000 token中等,开始漂移
150,000 token低,基本失效

2.2 机制

注意力权重经过 softmax 归一化,总和为 1。上下文中有 N 个位置时,平均每个位置的权重是 1/N。

你的指令占 20 个 token。在 500 token 的上下文里,它占 4%;在 50,000 token 里,它占 0.04%。

这不是比喻,这是字面意义上的稀释。

2.3 三个抵消手段

手段 1:提升到不会被稀释的层级

系统提示词和 CLAUDE.md每次会话开头重新注入。它们的相对位置永远靠前,且在 /compact 后会被重新读取(项目根目录的 CLAUDE.md)。

bash
claude --append-system-prompt "所有回答控制在 5 句以内。禁止开场白和总结段。"

手段 2:重复(末尾重申)

text
{……长提示词……}

再次确认:回答不超过 5 句。

重复 = 两份注意力份额,且第二份在最高权重位。

手段 3:减少竞争者

清理上下文比加强指令更有效。见 03.4


三、自我示范效应:最强也最隐蔽的干扰源

这是我想特别强调的一点,因为它常常被忽略。

3.1 现象

text
第 1 轮:你说「简洁一点」
第 2-4 轮:我遵守了,回答很短
第 5 轮:问题稍微复杂,我写长了一点
第 6 轮:你没纠正
第 7-10 轮:我的回答越来越长
第 15 轮:完全恢复到默认的啰嗦程度

3.2 机制

在第 15 轮生成时,我的上下文里有:

  • 1 条「要简洁」的指令(在第 1 轮,已被稀释)
  • 10 条我自己写的长回答(分布在整个上下文中,且靠近末尾的权重高)

那 10 条长回答构成了一组强有力的 few-shot 示例,示范的正是"这里的回答应该长这样"。

它们的总注意力份额,远超那一条早期指令。

3.3 这解释了几个常见困惑

困惑解释
「我说了好几遍它还是不改」你说 3 遍,但它自己示范了 20 遍
「越到后面越不听话」自我示范的样本量随轮次线性增长
「重开一个对话就好了」因为清空了所有自我示范
「有时候纠正一次就好了」因为纠正发生得早,坏示范还没积累

3.4 对策:早纠正、硬删除

对策 A:第一次偏离就纠正

不要想着"这次算了,下次再说"。第一个坏示范的成本远低于第十个。

对策 B:用 [Edit] (编辑) 物理删除坏示范

在网页/客户端中,回到偏离开始的那条你的消息,点 [Edit] (编辑) 重新提交 —— 该消息之后的所有内容(包括我的坏示范)会被丢弃。

在 Claude Code 中:

text
> /rewind

对策 C:主动注入好示范

text
> 从现在开始,你的回答格式必须像这样:

  【结论】一句话
  【依据】不超过 3 条,每条一行
  【风险】有就写,没有就写"无"

  确认后,用这个格式重新回答上一个问题。

用一个明确的好示范覆盖掉之前的坏示范。


四、位置权重的实战应用

4.1 一个精确的心智模型

想象上下文是一条时间线,而"注意力预算"是一条曲线:

text
权重

 │ ██                                          ████
 │ ████                                      ██████
 │ ██████                                  ████████
 │ ████████                            ████████████
 │ ██████████                      ████████████████
 │ ████████████████████████████████████████████████
 └──────────────────────────────────────────────────→
   开头        ← ← 衰减区 → →              末尾
   ↑                  ↑                     ↑
 系统提示词        长文档中段            当前问题
 长文档开头        历史对话中段          最后的约束

4.2 一张"该放哪"的对照表

内容类型最佳位置理由
长参考资料上下文开头后续所有 token 都会参照它;且不占用末尾的黄金位
角色/人格设定系统提示词不随轮次衰减
项目常驻规则CLAUDE.md每次会话重新注入,/compact 后重新读取
本轮的任务最后直接影响下一个生成的 token
输出格式规范倒数第二紧邻生成位置
最不能违反的那一条最后一行单条最高权重位
次要背景中段反正权重低,放低重要度内容

4.3 一个实际的布局

text
<!-- 开头:长资料 -->
<codebase_context>
{相关文件内容}
</codebase_context>

<!-- 中段:次要信息,放在这里损失最小 -->
<background>
项目历史、团队情况等次要背景
</background>

<!-- 靠后:核心指令 -->
<task>
重构 ReconciliationService,抽出渠道适配层。
</task>

<constraints>
- 不修改 src/legacy/
- 保持 IPaymentCallback 接口签名不变
- 金额一律 BigDecimal
</constraints>

<output_format>
先给方案,我确认后再写代码。
</output_format>

<!-- 最后一行:最关键的一条 -->
最重要:IPaymentCallback 的接口签名绝对不能改,有 3 个外部系统依赖它。

五、结构显著性:为什么 XML 标签有效

5.1 三个叠加的原因

原因 1:边界确定性

<constraints>...</constraints> 有明确的开始和结束。当我需要"回忆约束是什么"时,这是一个定义清晰的区域。而如果约束散落在一段散文里,我需要在整段文本中做软性判断"哪些句子是约束"。

原因 2:标签名是零成本的元信息

<constraints> 这个词本身就在告诉我"接下来是约束"。这比读完内容再推断它是约束,路径短得多。

原因 3:块内独立性

分块之后,<context> 里的内容和 <output_format> 里的内容在表示空间中的相互干扰降低了。混在一起时,"背景信息"可能被误当成"输出要求"的一部分。

5.2 一个可以自己观察的现象

试试这两个提示词,观察差异:

text
版本 A:
我在做一个数据分析,数据是 CSV 格式,有 10 万行,包含用户 ID、时间戳、
金额三列,我需要按用户聚合计算月度消费,输出要是 JSON,另外要过滤掉
金额为负的记录,还有时间戳是 Unix 秒级的需要转换。
text
版本 B:
<data_schema>
CSV,10 万行
列:user_id, timestamp (Unix 秒级), amount
</data_schema>

<task>
按用户聚合,计算月度消费总额。
</task>

<preprocessing>
- 过滤 amount < 0 的记录
- timestamp 转换为日期
</preprocessing>

<output_format>
JSON
</output_format>

字数几乎一样,但版本 B 里"过滤负数"这条约束被遗漏的概率明显更低 —— 它有自己的容器。


六、一个反直觉的建议:少即是多

很多人在效果不好时的第一反应是加更多说明。这经常适得其反。

6.1 为什么加说明可能有害

text
你的提示词从 200 token 加到 800 token
  → 每条指令的注意力份额从 1/200 降到 1/800
  → 原本有效的那条关键指令,现在被自己新加的话稀释了

6.2 正确的诊断顺序

效果不好时,按这个顺序检查:

text
1. 上下文是不是被污染了?(有矛盾信息、坏示范)
   → 清理,不是加说明

2. 关键约束是不是在中段?
   → 移到末尾

3. 约束本身是不是可验证的?
   → 「要简洁」改成「不超过 5 句」

4. 是不是任务太多混在一起?
   → 拆分

5. 以上都没问题,才考虑加说明

80% 的"它不听话",根因在第 1-4 步,而不是"说得不够清楚"。


七、Hack 清单

把这一章的机制转化成可执行的动作:

#动作针对的机制
1最关键的约束写在提示词最后一行因果邻近效应
2长文档放前面,问题放后面位置权重
3关键约束在开头和末尾各写一次重复=加权
4用 XML 标签给每类内容独立容器结构显著性
5看到第一次偏离立刻纠正抑制自我示范积累
6偏离已积累时用 [Edit] / /rewind 物理删除移除坏示范
7常驻规则提升到 CLAUDE.md / 系统提示词免于稀释
8长会话中定期重置锚点(重申约束)恢复权重
9效果不好时先清理,后补充避免自我稀释
10必须保证的规则用 hook 而非提示词概率 → 确定性

延伸阅读

基于 VitePress 构建 · 内容采用原作者授权