SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-26

编码代理为什么会忽略您的指令?

指令文件写着“停止”,代理却继续执行?了解规则未进入上下文、与代码冲突或距当前内容过远的原因,并在重写规则前完成诊断。

为什么编码代理会忽略您的指令

编码代理会因4个原因忽略您的指令,但原因不是您不够礼貌。规则根本没有进入上下文窗口。规则过于模糊,无法据此检查某个操作。上下文中的其他内容与规则冲突,通常是代理刚刚读取的代码与规则冲突。或者,规则仍然已加载,但位于当前轮次之前很远的位置,代理会优先依据附近的内容工作。

每个原因都有对应的解决方法,因此首先要区分它们。使用大写字母或 IMPORTANT 一词不能诊断问题。下面以 Claude Code 为例说明这些机制,因为截至 August 2026,其加载和压缩行为已有详细文档记录。其他工具的具体细节不同,但总体行为相同。

先说明两个术语。上下文窗口是模型在某一轮看到的文本块,包括系统提示、您的指令文件、对话内容,以及代理读取过的每个文件。harness 是模型周围的程序,负责从磁盘读取文件并组装这个文本块。本文中几乎所有抱怨,实际针对的都是 harness,而不是模型。

您的指令文件是消息,不是设置

指令文件不是配置。运行时不会读取 CLAUDE.md 并强制执行它。运行框架会从磁盘读取该文件,再将文本粘贴到对话中。在 Claude Code 中,这些内容会作为位于系统提示之后的用户消息传递,因此模型看到这些规则的方式,与看到您输入的其他内容相同。

这会带来一个令人不适的结果。您的规则会与窗口中的其他文本处于同等位置并相互竞争。规则是一项声明。代理刚刚打开的文件则是证据。两者不一致时,证据往往会胜出,而且不会触发任何错误,因为从模型的角度看,并没有发生异常。

官方文档对此说明得很清楚:指令文件会作为上下文处理,而不是作为强制执行的配置。无论模型如何决定,如果您都要阻止某项操作,就需要使用 hook,而不是写一句话。请记住这一点。本文末尾的大多数修复方案,都是将这一原则应用到具体场景中。

加载哪些指令文件,以及何时加载

Claude Code 会从启动目录开始,沿目录树逐级向上查找。从文件系统根目录到工作目录之间的每个 CLAUDE.md 和 CLAUDE.local.md,都会在启动时完整加载。它们会按此顺序拼接,因此距离启动目录最近的文件最后读取;在同一目录中,.local 文件会追加在主文件之后。

工作目录下方的子目录中的文件加载方式不同。它们不会在启动时加载,而是在代理读取该目录中的文件时加载。.claude/rules/ 中带有 paths: frontmatter 字段的路径作用域规则也是如此:只有读取匹配文件时才会进入上下文,而不是在每轮对话中加载。

这一差异解释了大量已报告的失败案例。您将规则放在 packages/api/CLAUDE.md 中,询问有关 API 的问题,但代理从未打开 packages/api/ 下的任何文件,因此直接给出了答案。规则并不是被忽略了,而是从未进入上下文。如果您的仓库将指导内容拆分到 monorepo 中每个包的指令文件,每次都应先检查这一点。

还有一个加载陷阱,也是“代理忽略了我的指令”最常见的原因:Claude Code 读取 CLAUDE.md,而不是 AGENTS.md。如果仓库统一使用 AGENTS.md,但没有 CLAUDE.md,Claude Code 将没有任何内容可加载。受支持的衔接方式是使用 CLAUDE.md,其第一行写入 @AGENTS.md,这样启动时会导入该文件;下面还可以添加 Claude 专用说明。如果没有额外内容,也可以使用符号链接。至于该文件本身应包含哪些内容,则是另一个问题,详见将代理指令与人工文档分开。

在重写前确认文件已加载

在确认代理能够看到该文件之前,不要修改其中的措辞。需要进行两项检查,先执行成本较低的检查。

在会话中运行 /context。它会按类别显示当前窗口的内容,其中 Memory files 列出实际加载的每个指令文件。文件不在该列表中,就表示它没有进入对话,因此你在其中写入的任何内容都不会生效。/memory 列出文件位置并打开文件进行编辑,包括尚不存在的文件。

如需更确切的结果,请记录加载事件。每当 CLAUDE.md 或规则文件进入上下文时,InstructionsLoaded hook 事件都会触发;其匹配器会说明加载原因:session_start、nested_traversal、path_glob_match、include 或 compact。将以下内容写入 .claude/settings.json:

{
  "hooks": {
    "InstructionsLoaded": [
      {
        "matcher": "nested_traversal",
        "hooks": [
          {
            "type": "command",
            "command": "cat >> /tmp/instructions-loaded.log"
          }
        ]
      }
    ]
  }
}

该 hook 会将载荷以 JSON 形式通过标准输入接收,因此 cat 会追加完整记录。工作期间使用 tail -f /tmp/instructions-loaded.log 监控该记录。系统会忽略此事件的退出状态,因此该 hook 只能进行观察,不能阻止加载。如果在预期加载嵌套文件的会话中,日志始终没有出现该文件,请停止改写。问题出在文件位置。

长时间会话如何影响规则

这里有两种不同的影响,需要分别应对。

距离。 第 1 轮中声明的规则到了第 90 轮仍在上下文窗口中,但此时它要与最近 90 轮、且更具体地针对当前任务的文本竞争。无法通过配置消除这种影响,但可以对其进行测量。在新会话中执行相同的任务。如果规则在新会话中有效,却在长会话进行到较深阶段后失效,那么原因就是距离。

压缩。 上下文窗口填满后,运行框架会汇总截至当前的对话,并从该摘要继续。能够保留下来的内容取决于摘要器认为哪些内容重要,而这不一定与您认为重要的内容相同。Claude Code 会按机制说明具体结果,差异很大。项目根目录中的 CLAUDE.md 和未限定范围的规则会在压缩后从磁盘重新注入。自动记忆会从磁盘重新注入。带有 paths: frontmatter 的规则会丢失,直到再次读取匹配的文件。子目录中的嵌套 CLAUDE.md 文件会丢失,直到再次读取该子目录中的文件。

根据该表对指令排序后,脆弱性顺序就很清楚了。只在聊天中输入的规则是会话中最脆弱的内容:只有摘要碰巧保留它时,规则才能继续存在。packages/api/CLAUDE.md 中的规则次之,因为它只加载过一次,之后可能被摘要省略,并且只有在该目录中再次读取时才会恢复。项目根目录文件中的规则最持久,因为每次都会从磁盘重新读取。

因此,如果某条指令必须在整个会话期间生效,就应将其放入项目根目录文件,并且不使用 paths: frontmatter。其他选择都存在取舍,应有意识地决定。管理上下文窗口中保留的内容介绍了带 focus 参数的 /compact,以及无关任务之间的 /clear;这两者都会改变摘要器决定保留哪些规则的频率。

为何周边代码比规则更有说服力

这是人们最常描述、却最少诊断的问题。您的文件规定数据库访问必须经过仓储层。代理却编写了一个直接调用 ORM(对象关系映射器)的处理程序。问题不是代理在风格上忽略了您的要求,而是现有证据占了上风。

规则描述的是一种偏好。代码展示的是一种实际做法。当代理打开即将编辑的模块中的 3 个文件,而这 3 个文件都直接调用 ORM 时,当前上下文一侧只有一句抽象规则,另一侧则有 3 个具体、近期且与任务匹配的示例。复制本地模式通常是正确行为。这里只是因为您知道上下文不知道的信息,所以这种做法才是错误的:这些文件属于旧代码。

因此,应将这点写入规则。明确说明自身反例的规则,才能经受真实代码仓库的检验。只陈述偏好的规则做不到这一点。

新的数据库访问必须经过 app/repositories/。app/legacy/ 下的文件仍会直接调用 ORM。这是旧代码,不是应遵循的模式。不要复制它。

第二句话才是关键。它会在代理发现这些文件之前,告诉代理将要看到什么,以及应如何理解这些内容。同样的修复方式适用于任何明显与代码仓库矛盾的规则:历史提交并未遵循的提交格式、半数测试套件都未采用的测试布局、仅适用于新代码的导入约定。只要代码与文件中的规则不一致,就应在文件中明确说明这种不一致。

无法检查的规则也就无法执行

“编写整洁的代码。”“不要过度设计。”“保持简单。”“迁移时要谨慎。”这些要求都无法针对某个具体操作进行测试,无论由代理执行还是由您检查都一样。如果代理拿到一条无法用来检查自身输出的规则,它只能猜测;而您只能凭感觉评判这个猜测。

对文件中的每一行都应用以下测试。写出一条 shell 命令,使规则被违反时命令以非零状态退出。如果无法写出这条命令,规则就不可检查。比较以下示例:

  • 不可检查:“保持函数简短。”可检查:“超过 60 行的函数上方必须有注释,说明函数为何需要这么长。”
  • 不可检查:“测试你的修改。”可检查:“运行 npm test,并在将任务标记为完成前粘贴失败计数。”
  • 不可检查:“保持文件井然有序。”可检查:“HTTP 处理程序位于 src/api/handlers/。该目录中不得放置其他内容。”
  • 不可检查:“正确格式化代码。”可检查:“.ts 文件使用 2 个空格缩进。”

“不要过度设计”是人们最先放弃的一条要求,因为修复方式不是把句子写得更短,而是写得更长:明确说明可行的最小修改实际包含哪些内容,为代理提供可以用来检查自身 diff 的标准。

大小问题只是换了一种形式。Claude Code 的指南建议每个指令文件少于 200 行,并明确指出,文件越长,遵循程度越低。700 行的文件并不会让指令更严格。它只是包含 700 行更容易互相矛盾的陈述,而且每一轮都会占用窗口,这会直接反映在您的 token 使用量中。将文件组织为按标题划分的规则,便于读者快速查找;相关方法见编写代理可以执行的指令文件。更好的做法是删去描述性内容,而不是指令性内容:处理程序和模型所在位置的目录说明属于结构信息,代理可以根据需要从解析后的仓库地图中查询,无需每一轮都将其保留在窗口中。

十分钟内诊断问题

按以下顺序执行。直接跳到最后一步,最终只会得到一份充满强调规则、但仍然无法生效的长文件。

  1. 确认规则已加载。 执行 /context,查看 Memory 文件列表。如果文件不在列表中,请修正位置,然后停止。此列表中的其他步骤暂时都不适用。
  2. 在新会话中复现。 启动新会话,并给出应触发该规则的最小任务。在新会话中生效,但在长会话中失败,通常说明上下文距离过长或发生了压缩。在新会话中也失败,则问题出在规则本身。
  3. 移除竞争规则。 在现有代码已经遵循该规则的目录中,要求执行同一项更改。如果合规性恢复,说明周围代码中的其他内容压过了你的规则。
  4. 搜索冲突。 两个文件针对同一行为提供不同指导,是已知的失败原因:模型可能任意选择其中一个,而且不会告知你它这样做了。
  5. 让规则可检查,然后重新测试。 使用具体路径和条件重写规则。如果合规性大幅提高,说明原因是措辞不明确。

第 4 步只需执行一条命令。搜索所有指令来源中的相关主题,不要只搜索你正在编辑的文件:

grep -rni "migration" --include="CLAUDE.md" --include="CLAUDE.local.md" .
grep -rni "migration" .claude/rules/ ~/.claude/CLAUDE.md ~/.claude/rules/ 2>/dev/null

如果两个文件中的相关内容互相矛盾,这就是问题所在。删除其中一份。不要尝试用更强的措辞为它们排序,因为没有可供申诉的排序引擎。

最有作用的修复方法,按优先级排列

下面每一步的作用都比上一步更强,但设置成本也更高。如果规则只需简单改写就能解决,请从顶部开始。如果某条规则重要到不能接受偶尔遗漏,应立即下移到更强的措施。

  1. 让规则具体明确。 指定路径、命令或条件。像前文所示,补充代理在仓库中会找到的反面证据。这不需要额外成本,却能解决相当多的问题。
  2. 将规则移到更接近其约束对象的位置。 可以使用嵌套的 CLAUDE.md、.claude/rules/ 中按路径限定的规则,或直接写在文件顶部的注释。这样,规则会与其约束的代码在同一次读取中被加载。需要接受这一取舍:以这种方式加载的内容会在下一次压缩时被移除,并在下一次匹配读取时重新出现。
  3. 将强制执行移入 hook。 文字说明只是要求,hook 才能作出决定。hook 会在固定的生命周期事件中作为代码运行,无论模型得出什么结论,都会执行相应规则。
  4. 将规则交给确定性工具,并删除文字说明。 例如格式化、导入顺序、行长度、禁止导入项和提交消息格式。可以使用 ruff format、prettier --write、eslint 或 pre-commit hook。格式化工具每次都能正确执行,而且不消耗 token。文字说明大多数时候是正确的,但每轮都会消耗 token。

完整说明第 3 步。假设代理绝不能编辑迁移文件。将以下内容放入 .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-migrations.sh"
          }
        ]
      }
    ]
  }
}

再将以下内容放入 .claude/hooks/guard-migrations.sh:

#!/usr/bin/env bash
set -euo pipefail

path=$(jq -r '.tool_input.file_path // empty')

case "$path" in
  */migrations/*)
    echo "Files under migrations/ are written by hand. Stop and ask first." >&2
    exit 2
    ;;
esac

exit 0

运行 chmod +x .claude/hooks/guard-migrations.sh,然后启动新会话,并要求代理编辑 migrations/ 下的文件。编辑会被拒绝,您的消息会返回拒绝原因。在 PreToolUse 中返回退出状态 2 会在工具调用执行前将其阻止,stderr 文本会作为阻止消息传递给模型。${CLAUDE_PROJECT_DIR} 会解析为项目根目录,因此无论代理当前位于哪个目录,hook 都能正常工作。代理不必同意这条规则,也不必记住这条规则,当前上下文中也不必仍然包含这条规则。编辑不会发生。

如果只是禁止某项操作,不包含任何逻辑,那么在设置中使用 permissions.deny 也能实现相同效果,并且无需维护脚本;权限模式决定哪些操作可以在不先询问您的情况下运行。如果某条指令确实必须放在系统提示词层级,而不能放在用户消息中,--append-system-prompt 可以将其放在那里。不过,每次调用都必须传入该指令,因此它更适合脚本,而不是交互式操作。

无法仅靠指令消除的问题

明确哪些部分由您负责。放置位置、措辞、文件之间的冲突以及文件大小,都是作者的问题,也应由作者修复。其余部分属于模型行为,改进措辞无法消除这些问题。

同意不等于遵守。 代理会确认一条规则,正确复述规则,然后在两次工具调用后违反它。确认本身没有成本,也不能预测后续行为。不要把确认当作修复,也不要把它计为测试。

有些习惯会持续出现。 添加注释、加入防御性错误处理、编写结束总结、运行显而易见的下一条命令。这些行为在规则禁止时仍会回来,只是发生率降低,而不是降为 0。您可以测量自己的发生率:在全新的会话中运行同一任务 10 次,然后统计违规次数。如果该数字必须为 0,就不应再把这条规则放在提示中。任务尚未完成一部分却声称任务已完成,也是同一种习惯。修复方式应采用结构化方案,而不是继续增加文字:unlazy 技能会用深度树和门控文件替代这句话,代理必须清除这些检查项后才能声称任务完成。

当前会话本身会成为示例。 如果代理在第 12 轮违反了规则,而您没有处理,这次违规就会作为示例留在上下文中,而且比规则新得多。发现违规后应立即纠正。未纠正的违规会为当前会话的其余部分提供错误示范。

指令文件不是安全边界。 它只能影响行为,不能强制执行规则。任何遗漏代价高的事项,例如凭据或破坏性命令,都应交给权限或钩子处理。让代理无法接触机密对数据也适用同一原则:不要要求代理不要读取某个文件,而应确保该文件不可读。

简而言之:证明文件已加载,使规则可检查,将规则放在其所约束对象的旁边;当遗漏率仍然重要时,就不要再依赖文字。代理无法忽略的规则,是一条从未要求代理遵守的规则。

FAQ

为什么 Claude Code 会忽略我的 CLAUDE.md?

先确认它是否已加载,不要直接假设它被忽略了。运行 /context,查看 Memory files 列表;其中没有列出的文件不会进入当前对话。指令文件会在系统提示之后作为用户消息传入,并被视为上下文,而不是强制配置,因此无法保证严格遵守。实际情况通常有以下4种之一:文件位于代理从未读取的子目录中;两个文件内容冲突,模型任意选择了其中一个;规则过于模糊,无法据此检查具体操作;或者周围代码展示了与规则相反的做法。

在会话中途编辑指令文件会产生什么影响?

对已经进入当前对话的副本没有影响。工作目录上级的文件会在启动时完整加载,因此模型持有的是启动时的文件内容。要加载编辑后的内容,请启动新会话,或让代理使用常规文件工具读取该文件,这会将当前版本作为新消息放入对话。压缩上下文后,项目根目录文件会从磁盘重新读取,因此新版本也会在此时进入对话。

根目录中的 CLAUDE.md 与嵌套文件冲突时,哪个文件优先?

不能可靠地认为任何一个文件优先。已发现的文件会按从文件系统根目录到工作目录的顺序串联到上下文中,而不是互相覆盖,因此距离工作目录最近的文件只是最后读取。系统没有用于解决冲突的优先级引擎,Claude Code 文档也说明,冲突规则可能会被任意处理。应将嵌套文件写成补充规则,并明确说明其适用路径;不要试图通过提高优先级来压过冲突规则,而应直接删除冲突内容。

我的指令能在 /compact 后保留吗?

这取决于它们的加载方式。项目根目录中的 CLAUDE.md、未限定范围的规则和自动记忆会在压缩上下文后从磁盘重新注入。带有 paths: frontmatter 的规则,以及子目录中的嵌套 CLAUDE.md 文件,在再次读取匹配文件前会丢失。仅在聊天中输入的内容,只有在摘要器恰好保留它时才能继续存在。如果某条规则必须在整个会话中生效,应将它放在项目根目录文件中,并且不要使用 paths: frontmatter。

什么时候应将规则改为 hook,而不是继续写成说明文字?

当检查是确定性的,并且遗漏检查的代价高于编写一个小脚本的代价时,就应使用 hook。文件路径限制、提交前必须运行的命令,以及禁止调用的工具都属于这种情况。退出状态为 2 的 PreToolUse hook 会直接阻止工具调用,并将 stderr 文本作为原因返回给模型,因此无论该规则是否仍在上下文中,它都能生效。凡是格式化工具或 linter 可以判断的内容,都应交由相应工具负责,并从指令文件中完全删除。