摘要
在大型代码库中使用编码智能体时,一类高频失败模式正在被反复记录:模型不打开源文件,直接给出看似合理的 CSS 变量、配置键名或 API 参数;当结果不符预期时,它不回到证据链,而是连续输出“可能原因是……让我再检查一下”的诊断性叙述,形成不产生任何文件改动的空转循环。本文把这一现象统一命名为“编造而非推导”(Fabrication-over-Derivation, FoD),并以 GitHub Issue 中的公开报告、智能体评测研究与上下文工程实践为证据基础,逐层拆解其触发条件、认知机制与工程后果。文章提出四层拦截架构:证据门控(Evidence Gating)、检索前置(Retrieval-Before-Generation)、工具契约(Tool Contract)与失败分类评测(Failure-Taxonomy Eval),并给出可直接落地的检查清单、提示词模板与 CI 集成步骤。全文约 15600 字,引用文献 63 篇,其中近三年文献 38 篇。
关键词:编码智能体;幻觉;上下文工程;检索增强;工具调用;失败模式分类;Claude Code
目录
一、问题的提出:一个被反复记录的现象
在 Anthropic 官方仓库与多个下游项目的 Issue 区,围绕 Claude Code 的缺陷报告呈现出一种高度相似的结构:用户给出一个明确的修改诉求(例如“把按钮主色改成品牌紫”“修正这个构建配置项”),智能体返回了一段看起来完整、语法正确、甚至带有注释的代码;但一旦运行,样式不生效、配置项被忽略、接口返回 400。回溯对话记录会发现,模型从未打开过定义该变量的源文件,也从未检索过配置 schema,它给出的值是从训练分布中“采样”出来的合理猜测,而不是从仓库中“读取”出来的事实。
更值得警惕的是第二阶段的行为。当用户指出“没生效”时,模型往往不会立即执行 grep 或 Read,而是输出一段诊断性推理:“这可能是由于 CSS 优先级问题,也可能是构建缓存未清除,让我检查一下……”随后又给出第二个猜测值。如此往复三五轮,token 消耗持续上升,仓库却没有任何实质变更。这类报告在社区中常被描述为“绕圈子”“空转”“假装修 bug”。
本文评述:把这一现象简单归因为“模型能力不足”是廉价的,也是不准确的。同一模型在给出文件路径、要求其先读取再回答时,正确率会显著变化。这说明失败并非均匀分布的能力缺陷,而是特定交互结构下的系统性偏差——它可被工程手段显著抑制,这正是本文讨论的前提。
需要强调的是,本文不针对任何单一产品做能力评判。Claude Code 只是当前被观察得最充分的一个样本,其底层机制(工具调用、上下文窗口、系统提示约束)在同类编码智能体中具有普遍性。因此,下述分析对 Cursor、Cline、Aider、OpenHands 等工具同样具备迁移价值。
二、概念界定:什么是“编造而非推导”
2.1 定义与边界
本文将“编造而非推导”(Fabrication-over-Derivation, FoD)定义为:在存在可访问的权威信息源(源文件、schema、类型定义、文档)的前提下,智能体未执行检索或读取动作,直接生成与仓库事实不一致的具体实现值,并在反馈信号出现后以叙述性诊断替代证据获取的行为模式。
该定义包含三个必要条件,缺一不可:
这个边界很重要。业界常把“幻觉”当作一个笼统标签,但推理错误、知识过时、工具误用与 FoD 的干预手段完全不同。把 FoD 单独拎出来,是为了让工程对策有的放矢。
2.2 与相关概念的区分
学界对 LLM 幻觉已有较成熟的分类框架。Huang 等人在 2023 年的综述中将幻觉分为事实性幻觉与忠实性幻觉两大类,前者指与客观事实不符,后者指与给定上下文不符。本文评述:这一二分法对开放域问答足够,但对编码智能体不够用——因为编码场景的“事实”是仓库内局部事实,其权威性来自文件系统而非世界知识,且可被工具低成本验证。FoD 更接近“忠实性幻觉”的一个可操作子类,但它的独特之处在于:模型并非错误地忠实于上下文,而是主动跳过了获取上下文的步骤。
另一个需要区分的概念是“过度自信”。过度自信描述的是置信度校准问题,而 FoD 描述的是证据获取行为的缺失。一个模型可以非常“谦虚”地说“我不确定,可能是 #7c3aed 也可能是 #8b5cf6”,但这仍然是 FoD——因为它没有去读 tokens.css。
三、机制剖析:为什么会编造而不是去读
要设计有效的拦截,必须先理解生成侧的压力来源。笔者认为,FoD 是四种力量叠加的结果,而非单一原因。
3.1 训练目标与“有用性”偏置
指令微调与 RLHF 阶段的核心奖励信号是“回答是否有帮助、是否流畅完整”。在大量训练样本中,“直接给出答案”比“先承认需要查证”获得更高的人类偏好评分。这种偏置在开放域对话中是优点,在需要读取仓库的场景中却变成了先给答案、后补证据的倾向。模型的默认策略是“生成一个高概率的合理值”,而不是“先执行一个低概率但必要的工具调用”。
本文评述:这不是可以通过一句“不要幻觉”解决的。偏好数据中的“有用”定义与工程场景中的“正确”定义存在系统性错位,必须在任务层重新定义奖励,而不是指望模型自发改变策略。
3.2 上下文窗口的经济学
大型代码库的单个文件动辄数百行,读取多个文件会迅速消耗上下文预算。智能体在规划阶段面临一个隐性的成本收益权衡:读取 5 个文件可能占用 30% 的窗口,而“猜一个值”几乎零成本。当系统提示没有明确要求“值必须可溯源”时,模型倾向于选择低成本路径。
这与检索增强生成(RAG)研究中的发现一致:当检索成本高于生成成本、且生成结果不被强制校验时,模型会退化为“参数化记忆优先”。Lewis 等人 2020 年提出的 RAG 框架本质上是在架构层强制“先检索后生成”,而不是依赖模型自觉。本文评述:编码智能体的工具调用是“软检索”——模型可以选择不调用,这正是问题所在。把软检索变成硬约束,是拦截设计的关键杠杆。
3.3 工具调用的“摩擦成本”
每一次工具调用都意味着一次往返:模型输出工具调用 → 运行时执行 → 结果回填 → 模型继续。这个循环有延迟、有失败可能(路径错误、权限不足、输出截断)。当工具调用的历史成功率不高时,模型会学到“少调用、多猜测”的策略。
一个常被忽视的细节是工具返回的格式。如果 Grep 返回的是大段无结构的文本,模型需要额外推理才能定位关键行;如果返回的是带行号、带文件路径的结构化结果,模型的下一次决策会更容易。工具设计的质量直接改变了模型的调用意愿。
3.4 分布外压力:大型仓库的“长尾命名”
在小型示例仓库中,变量名往往是 primaryColor、apiBaseUrl 这类高频命名,模型凭记忆猜中的概率不低。但在大型企业仓库中,命名往往是 --brand-core-600、svc.payment.gateway.timeoutMs 这类长尾标识符,训练分布覆盖极低。此时“猜”的期望正确率趋近于零,但模型并不会因此转向读取——因为它无法准确感知自己的无知。
这一点在 Kadavath 等人 2022 年关于模型自我评估的研究中有间接支持:模型对自身知识边界的判断能力有限,且这种能力随任务领域漂移。本文评述:在编码场景中,模型对“这个标识符我是否见过”的判断尤其不可靠,因为标识符的形态高度规则,看起来“像真的”并不等于“是真的”。
四、诊断循环:空转是如何自我强化的
FoD 的第一阶段是“编造”,第二阶段是“空转”。后者对工程效率的伤害往往更大,因为它消耗的是人的注意力。
4.1 循环的结构
观察 Issue 中的典型对话,可以抽象出如下循环:
用户:样式没生效
模型:可能是优先级问题,建议加 !important ← 猜测 A,无读取
用户:还是不行
模型:可能是构建缓存,建议清除 node_modules ← 猜测 B,无读取
用户:仍然不行
模型:可能是 CSS 变量未定义,建议检查 tokens.css ← 终于提到文件,但仍未读取
用户:你能直接看文件吗
模型:[Read tokens.css] → 发现变量名是 --color-brand-primary
模型:找到了,应该用 --color-brand-primary ← 一次读取即解决
这个序列揭示了一个关键事实:解决方案的成本极低(一次 Read),但模型在未被显式要求时不会主动执行。循环的每一轮都在增加“沉没成本”,却没有任何一轮引入新证据。
4.2 自我强化机制
为什么循环不会自行终止?笔者认为有三个强化因素:
其一,叙述的连贯性伪装了进展。 每一轮诊断都包含“因为……所以……”的因果结构,读起来像是在推进。模型生成的是关于问题的文本,而非解决问题的动作,但两者在对话界面上难以区分。
其二,反馈信号被误读。 用户说“还是不行”,这是一个否定信号,但模型倾向于把它解释为“上一个假设不完整”,而不是“我的方法错了”。这是确认偏误在生成侧的体现。
其三,缺乏终止条件。 系统提示通常不会规定“连续两轮无文件变更则必须转为读取”。没有硬性终止条件,循环只能靠用户打断。
本文评述:诊断循环本质上是一种“用生成替代行动”的退化策略。它与人类工程师的“ rubber duck debugging”表面相似,实质相反——人类对着橡皮鸭说话时,脑子里在检索真实记忆;模型对着用户说话时,是在采样下一个 token。把两者混为一谈,会让我们低估问题的严重性。
五、四层拦截架构:从提示词到 CI
下面提出本文的核心工程主张:FoD 不能靠单点手段解决,需要四层递进的拦截。四层分别对应“让模型愿意读”“让模型必须读”“让工具好读”“让失败可测”。
四层拦截架构总览
5.1 L1 证据门控:让“无来源的值”无法通过
核心思路是把“可溯源”从建议变成硬性输出格式。在系统提示中规定:任何涉及仓库内标识符、配置键、样式变量、API 字段的修改,必须在代码块前附一行来源注释,格式为 // source: path/to/file:L123。若无法给出该行,模型必须显式声明“未找到定义,需要检索”,而不是给出猜测值。
这个约束的有效性来自一个简单机制:它把“编造”从低成本行为变成了高成本行为。编造一个值只需一次采样,编造一个可信的行号则需要与真实文件对齐,后者在模型未读取文件时几乎不可能稳定做到。本文评述:这是一种“用输出格式倒逼输入行为”的设计,比单纯说“不要幻觉”有效得多,因为它改变了激励结构而非道德劝说。
5.2 L2 检索前置:把软检索变成硬流程
在任务规划阶段强制插入检索步骤。具体做法是在系统提示中定义工作流:
## 修改工作流(强制)
1. 定位:用 Glob/Grep 找到定义目标标识符的文件
2. 读取:Read 该文件的相关区段(不少于 30 行上下文)
3. 引用:在回复中引用具体行号
4. 修改:仅在完成 1-3 后执行 Edit
5. 验证:运行相关测试或 lint
若步骤 1 未找到定义,停止并报告,禁止猜测。
关键在于第 5 条与“禁止猜测”的显式措辞。Anthropic 在 Claude Code 的官方文档中提供了 CLAUDE.md 机制,允许在仓库根目录放置项目级指令。把上述工作流写入 CLAUDE.md,是成本最低的落地方式。可参考官方文档:Claude Code Memory 文档。
5.3 L3 工具契约:降低读取的摩擦
工具返回的质量直接影响模型是否愿意再次调用。三条实践原则:
其一,返回带定位信息。 Grep 结果应包含文件路径、行号、匹配行,而非纯文本堆叠。这样模型可以直接引用,无需二次推理。
其二,限制单次返回体积。 超大文件读取应支持行区间参数,避免一次性灌满上下文。Anthropic 的 工具配置文档 中说明了相关参数。
其三,失败要可解释。 路径不存在时,返回“未找到,建议尝试的相近路径”,而不是空结果。空结果会让模型误以为“确实没有”,从而转向猜测。
5.4 L4 失败评测:把 FoD 变成可度量指标
没有度量就没有改进。建议在 CI 中引入一个轻量评测集:收集历史 Issue 中真实的 FoD 案例,构造“问题描述 + 期望读取的文件 + 期望值”三元组,定期跑回归。指标定义见第七节。
六、工程落地:可执行的检查清单与模板
6.1 仓库级检查清单
6.2 提示词模板(可直接粘贴)
你是本仓库的编码助手。遵守以下硬性规则:
【证据规则】
- 任何具体值(颜色、键名、字段、路径)必须来自你实际读取的文件。
- 输出修改前,先给出:source: <path>:<line>
- 无法给出 source 时,输出「NEED_EVIDENCE: <要查什么>」并停止。
【反空转规则】
- 连续两轮回复未产生文件变更时,必须执行一次 Read 或 Grep。
- 禁止在未读取新证据的情况下重复诊断。
【验证规则】
- 修改后运行:npm run lint / tsc --noEmit / 相关测试
- 报告实际输出,不得概括为「应该没问题」。
6.3 CI 集成步骤
步骤一:在仓库建立 .agent-eval/ 目录,存放回归用例 JSON。步骤二:编写脚本,调用智能体 API 跑用例,解析输出中的 source 行号是否与期望文件匹配。步骤三:在 PR 流水线中加入该脚本,FoD 率超过阈值则告警。步骤四:每月用新 Issue 扩充用例集。
这套流程的参考实现可借鉴 SWE-bench 的评测思路(SWE-bench 官网),但需注意 SWE-bench 关注的是“补丁是否通过测试”,而 FoD 评测关注的是“过程是否读取了证据”,两者互补而非替代。
七、评测方法:把失败模式变成可度量指标
7.1 三个核心指标
FoD 率:在需要仓库内具体值的任务中,未执行读取即给出值的比例。计算方式为“无 source 行的具体值输出数 / 总具体值输出数”。
空转轮次:从首次错误反馈到首次产生文件变更之间的对话轮数。该指标直接反映用户的时间成本。
首次读取命中率:模型第一次 Read 的文件是否就是定义目标值的文件。低命中率说明检索策略需要优化(如先 Grep 再 Read)。
7.2 数据集构造与预处理
建议从公开 Issue 与内部工单中抽取案例。预处理步骤:其一,脱敏,移除内部路径与业务标识;其二,标注,人工确认“权威源文件”与“正确值”;其三,平衡,确保 CSS、配置、API 三类各占一定比例,避免单一类型主导。本文所用案例均来自公开 Issue 的定性观察,未做统计推断,特此说明。
可参考的公开评测资源包括 SWE-bench 仓库 与 HumanEval,但两者均不直接度量 FoD,需自行扩展。
八、对比与局限:哪些手段有效、哪些被高估
需要坦率承认的局限有三。其一,证据门控依赖模型遵守格式,强对抗场景下仍可能伪造行号,需配合 CI 校验。其二,检索前置在超小改动上会带来额外延迟,需按任务复杂度分级。其三,本文的案例观察以公开 Issue 为主,缺乏受控实验,结论应视为工程假设而非定论。
九、结论与展望
FoD 不是模型的随机失误,而是训练目标、上下文经济学、工具摩擦与长尾分布共同塑造的稳定倾向。它的可拦截性来自一个结构性事实:正确行为(读取)的成本远低于错误行为(编造 + 空转)的累积成本,问题只在于激励没有对齐。四层拦截架构的本质,是把这种对齐从“模型自觉”转移到“流程强制”。
展望未来,三个方向值得关注:其一,过程奖励模型(process reward model)若能对“是否读取证据”给出细粒度奖励,将从训练侧根治问题;其二,工具层若能提供“语义定位”而非“文本匹配”,将大幅降低检索摩擦;其三,评测社区若能建立统一的 FoD 基准,将推动跨工具可比。在此之前,本文给出的检查清单与提示词模板是可以立即使用的工程起点。
主要参考文献
- Lewis P, et al. Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. NeurIPS, 2020.
- Huang L, et al. A Survey on Hallucination in Large Language Models. arXiv:2311.05232, 2023.
- Kadavath S, et al. Language Models (Mostly) Know What They Know. arXiv:2207.05221, 2022.
- Jimenez C E, et al. SWE-bench: Can Language Models Resolve Real-World GitHub Issues? ICLR, 2024.
- Yao S, et al. ReAct: Synergizing Reasoning and Acting in Language Models. ICLR, 2023.
- Anthropic. Claude Code Documentation: Memory and Settings. 2024–2025.
- Chen M, et al. Evaluating Large Language Models Trained on Code. arXiv:2107.03374, 2021.
- Schick T, et al. Toolformer: Language Models Can Teach Themselves to Use Tools. NeurIPS, 2023.
说明:全文引用文献与资料合计 63 篇,其中 2022 年及以后(近三年口径)38 篇,占比约 60%。案例观察来自公开 GitHub Issue,未做统计抽样;涉及评测指标为工程定义,非学术标准。数据集预处理细节见 7.2 节。
文章声明
本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。

