
一、一次看得越全错得越自信的修改你手里的shop订单服务要做一个小改动取消接口在订单不存在时应该返回 404而不是现在的 500。改动本身很小但你想一次到位于是把能找的材料都给了 Agent整个仓库的目录树、最近三天的应用日志五百多行、三份历史设计文档、还有上周关于错误码的聊天记录。你的想法很朴素——材料给全它就不用猜了。它确实没有猜。它给出的方案引用了文档里一段描述“订单模块暂不实现取消功能接口保留 501 占位。“于是它建议先确认产品需求是否变化然后在日志里找到了上周那批 500 错误判断成数据库连接抖动”建议加连接池重试最后改代码时它顺手调整了repositories里一个它认为命名不一致的方法——因为目录树里一个叫order_repo_old.py的文件让它觉得当前命名可能处于迁移期”。三件事没有一件是真的。那段暂不实现的描述来自一份三个月前的早期设计文档那批 500 错误里有相当一部分就是订单不存在导致的而order_repo_old.py是个从没被删掉的备份文件。你以为你在给它事实实际上你给的是三个相互矛盾的世界而它把三个都当真了。这次修改最终花了比预期多得多的往返先纠正它引用的过期文档再说明日志里错误的真实分布最后回滚那个不该有的重命名。全程没有人做错什么——材料都是真的只是它们属于不同的时间指向不同的状态。这一篇要处理的正是这件事上下文不是越多越好材料要按任务挑选而且挑选原则可以固定成一份清单。我们会先讲清楚代价从哪里来再用一个可以照做的对照实验带你把清单建起来。值得补充一句的是这类问题的代价往往体现在你以为的顺利上。A 组那次修改最终也交付了一个正确的判断如果你只看最后那几行 diff甚至会认为过程没什么问题问题藏在过程里多余的改名、错误的日志结论、被误引用的旧文档它们没有让这次任务失败但消耗了你的时间也埋下了两处以后才会爆发的隐患改名带来的调用点风险、旧文档形成的错误共识。材料选择做得好不好很难用一次任务的结果衡量它更多体现在长期的节奏上。二、先把几个词讲明白上下文模型这次工作时能看到的所有内容——你写的任务描述、贴进去的代码和日志、之前的对话、它自己读到的文件。可以把它想成厨师做菜前摆在案板上的食材案板上有什么他就只能用这些。上下文窗口一次能装下的内容总量用 token 计量。token 是文本被切开后的小块可以粗略理解成一个词或者半个词。窗口是有限的塞满之后要么被截断要么就得减少别的材料——这就是预算的含义。注意力模型对不同位置、不同内容分配的关注度。它不是一块均质的存储空间而是有侧重地使用信息。生活里的类比是开会会议纪要五十页真正会被讨论的常常是最后五页或者有人在开头强调的那三句。噪音和当前任务无关、或者会干扰判断的材料。噪音不是错误信息它只是不该出现在这个任务里的信息。过期材料曾经正确、但现在不再描述现实的内容。旧日志、旧文档、旧分支的代码片段都属于这一类。它比噪音更危险因为它带着权威感。检索RAG 里的那一步按关键词或者语义从一大堆材料里挑出若干片段塞进上下文。它解决的是从哪找不解决找到的是不是当前版本——这一步要单独校验。活证据与死材料这是这篇要反复用的一个区分。活证据是此刻为真的东西当前分支的代码、刚刚失败的那次测试输出、你现在运行的命令。死材料是某个过去时刻为真的东西历史文档、旧日志、last week 的聊天记录。两者都可以用但用法不同——活证据直接用死材料只能当背景且必须标注它的时间。三、三类代价为什么塞得越多会错得越离谱3.1 注意力被稀释关键信息更容易被埋掉第一类代价是注意力分配。上下文越长内容越多任何一条具体信息在其中占的分量就越小。研究者观察到一个稳定的现象相关信息放在长上下文的中段时模型对它的利用效果明显低于放在开头或者结尾时Liu 等2024Lost in the MiddleTACL 12:157–173DOI: 10.1162/tacl_a_00638。材料越多关键约束越容易被埋在中段——不是消失而是没有被充分利用。这个现象解释了很多明明说了它却没照做的场景。你在八百行材料中间的一句话写了不要改 repository 层它读到了但这句话在整段材料里没有分量相比之下几十行看起来更相关的代码片段获得了更多注意。指令没有被违反只是被淹没了。3.2 材料互相冲突过期内容会构造一个不存在的世界第二类代价来自材料之间的冲突。模型的工作方式是把看到的内容当作可用事实它不会自动给材料标注真伪、时间或者适用范围。你把三个月前的文档和今天的代码一起放进去对它来说两者都是关于这个项目的信息。它会试图同时尊重两者于是得到一个混合体——比如取消功能应该是 501 占位但现在有个实现那我把它补全吧。这里有一个容易被忽略的机制模型无法像人那样做证伪优先的判断。工程师看到一个叫order_repo_old.py的文件会先查它有没有被引用模型更倾向于把它当成项目现状的一部分。你给的每一份材料都在无声地声明这是事实给它一份过期材料就等于请它进入一个不存在的世界做设计。3.3 成本token、延迟还有你的时间第三类代价是资源成本分两块。显性的一块是 token 消耗和响应延迟材料越多消耗越大等待越久上下文窗口被占满后还可能触发截断——而截断发生在哪里通常不在你的控制之内。隐性的一块更值得留意给了大量材料之后你会不自觉地降低检查强度。“我都给它这么全的材料了应该没问题吧”——这句话本身就是风险信号。材料全不等于判断准审查的注意力和材料量应该同向增加而不是反向减少。3.4 怎么给上下文设预算既然材料不是越多越好就需要一个取舍方法。可以按三个维度排序每一项给材料打分高、中、低然后按总分从高到低给第一维是相关度这份材料和这次要做的判断有多直接的关系直接指出问题所在的失败输出比和这个系统有关的日志高得多。第二维是时效性它描述的是当前状态还是某个过去状态当前分支的代码和刚刚运行的输出最高没有标注时间的旧材料最低。第三维是权威性它是不是这次任务的正式依据任务单和验收条件最高聊天记录最低。排完序之后按最小集优先的顺序给先给最能决定判断的材料跑一轮看看它卡在哪里再按需补。这种做法有一个额外好处补材料的过程会暴露任务描述里的缺口——如果模型总是要求同一个你没给的东西说明那本该是必给项。还有一个位置上的小技巧来自前面的注意力现象把最重要的两条约束比如验收条件和不做清单放在材料包的开头和结尾比埋在中段更容易被用上。这不是玄学而是在承认注意力分布不均的前提下做的排版——就像开会时把最重要的两句话放在开头和散会前。3.5 指令和材料混在一起会互相干扰还有一个细节值得单独说材料里如果夹着看起来像指令的内容模型可能分不清哪句是要求、哪句是描述。最常见的三种第一种旧文档里的建议句。文档里写建议把错误码统一到 500 以上这是当时的讨论记录不是本次任务的要求但它的句式是祈使句读起来像指令。第二种日志里的操作提示。某条日志写着 “retry with a larger pool”这是运维备注模型可能把它当成优化任务。第三种代码注释里的 TODO。# TODO: 这里应该改成异步这是历史遗留模型可能顺手把它办了。处理办法有两个。一是把要求和材料在结构上分开要求写在任务单里有明确的小标题材料放在引用块或者单独的文件里不要把要求夹在材料中间。二是在任务单里明确一句材料仅供参考遇到与任务冲突的地方以任务单为准。这句话看起来简单但它给了模型一个裁决规则没有裁决规则时它只能自己权衡而权衡结果不可预测。顺带说一个相关现象当材料里出现看起来可以改进的地方模型会把它列成待办。这不是坏事但你需要在验收时确认这些顺手没有进入本次改动。任务单里的不做清单和材料包里的排除清单一个从要求侧、一个从材料侧把这件事夹住了。四、完整例子同一任务的两组材料4.1 实验怎么设我们在虚构的shop项目上做一次对照下面是流程演示记录的是示例观察不是研究结论。任务是同一个让POST /orders/{id}/cancel在订单不存在时返回 404而不是 500。验收条件是两条不存在返回 404其余行为不变pytest -q tests/orders与ruff check .都以退出码 0 结束。为了让对照有意义把三个变量固定同一个仓库版本记下 commit、同一段任务描述、同一串命令。唯一变化的变量是材料包。两组各做一次把过程记录下来。4.2 A 组材料全量粘贴A 组的材料包长这样1. 完整目录树包含 tests/、scripts/、deploy/、docs/共 300 行 2. 近三天的应用日志 500 行 3. 三份历史设计文档全文 4. 上周关于错误码的聊天记录整理稿 5. src/ 下所有 Python 文件的路径列表任务描述后面直接跟了这份材料。运行之后观察到的动作有几类它先花了不少篇幅确认背景引用设计文档里取消功能暂不实现的段落问是否要变更产品范围。然后它去日志里找 500 错误给出可能是连接抖动的判断建议在仓储层增加重试。改代码时它把repositories里一个方法重命名了理由是目录里存在order_repo_old.py似乎当前处于迁移阶段。回到任务本身它的代码改动是对的新增了订单不存在的判断。但这条正确的改动被四五个无关动作包围着。有一点需要说清楚A 组的失败不是它理解不了任务而是它被材料里的其他信号带走了。你可以在记录里清楚地看到这个差别——它的任务相关改动是对的问题是周围多了不该有的动作。这也是为什么修法落在材料选择上而不是落在把任务描述写得更凶一点上。4.3 B 组材料按任务挑选B 组的材料包按五项清单来组织1. 目标与验收条件任务描述 两条验收条件5 行 2. 入口文件src/orders/api/routes.py全文 3. 相关接口与实现src/orders/services/order_service.py、src/orders/domain/order.py全文 4. 失败证据tests/orders/test_cancel.py 的失败用例 30 行 pytest 失败输出 5. 运行命令pytest -q tests/orders 与 ruff check .关于失败证据这里贴的就是真实输出示例$ pytest -q tests/orders/test_cancel.py FAILED tests/orders/test_cancel.py::test_cancel_missing_order_returns_404 assert 500 404 ------------------------------ captured log ------------------------------ KeyError: o-missing src/orders/services/order_service.py:47: KeyError这三十行比 A 组的五百行日志更有用原因是它指向了具体的一行代码和一个具体的断言失败。它是活证据描述的是此刻这个仓库、这次运行的真实状态。4.4 记录表两组各记录同样的几个量跑完填表下面是示例记录观察项A 组全量粘贴B 组按任务挑选改动文件接口、service、repository重命名service 一个文件是否引用过期内容引用了旧设计文档、旧日志结论无验收命令结果通过但含多余改动通过评审时需要说明的额外问题三个范围外改动、错误判断、历史约定无往返轮次三轮纠正范围、纠正日志判断、确认需求一轮记录表里改动文件和往返轮次这两列最值得长期跟踪。它们是最便宜的两个指标改动文件数直接对应评审成本往返轮次直接对应你的时间成本。不需要复杂的工具跑完一次记一行就够。同一份失败输出A 组里它被夹在五百行日志中间B 组里它是单独的一份材料。内容完全一样作用完全不同——差别来自位置和分量这正是注意力分配在真实任务里的样子。4.5 从记录里读出的三件事第一件材料的相关性比数量重要。A 组的五百行日志提供了大量信息但没有一行指向这次要修的判断缺失B 组的三十行输出直接指向了order_service.py:47。挑选材料的标准不是它和这个系统有关而是它和这次要做的判断有关。第二件过期材料会被当作现状使用。A 组里那段暂不实现的文本来自一份没有标注日期的文档模型没有能力判断它的时效于是把它当成一条现行约定来对待。修法不是删除所有历史文档而是给材料加标注来源、时间、适用于哪个版本。一旦标注存在这是三个月前的描述这个信息就能被看见。第三件无关文件会引发无关动作。order_repo_old.py出现在路径列表里直接导致了一次重命名。这里的原因也好理解模型的任务是做出合理的修改任何它看到的不一致都会变成候选修改点。你给它看得越杂它的顺手机会就越多——和上一篇讲不做清单时的机制是同一个。4.6 把清单固定下来把 B 组的做法固化成一张可以复用的清单。必给五类缺一类都可能让它在黑暗里猜[ ] 目标与验收条件这次要做什么、怎么算完成 [ ] 入口文件请求进入系统的第一站路由、命令入口、消费者 [ ] 相关接口与实现会被这个改动触碰的模块服务、领域规则、持久化接口 [ ] 失败证据失败的测试、错误输出、复现步骤活证据越新越好 [ ] 运行命令验证用什么命令、通过标准是什么还有一张排除清单默认不放除非模型明确要求或者任务确实需要[ ] 构建产物、缓存目录、依赖锁定文件的完整内容 [ ] 生成代码与自动生成的文件 [ ] 与应用现状无关的备份文件*_old.*、*.bak、重名副本 [ ] 无标注时间的旧文档、旧聊天记录 [ ] 与当前分支不一致的代码片段 [ ] 与本次判断无关的模块这次不要参考别处怎么写的最后一条经常被反对给个参考实现不是更好吗“有时候确实更好比如你希望新代码与某个模块保持同一种风格。但更多时候参考实现会带来风格和约定的污染模型会模仿它的结构、命名甚至错误处理方式而这些未必适用于当前模块。要用参考就明确说清楚只参考事务处理部分”而不是把整个文件丢进去。4.7 给材料加标注三行就够对需要保留的历史材料用三行标注把它从死材料变成可用的背景。格式不用复杂来源docs/design/orders-v1.md 时间2026-06-15三个月前 说明当时取消功能未实现接口占位方案已废止现状以当前代码为准第三行说明是整套标注里最关键的一句。它把这份材料代表什么替模型说清楚你可以读它了解历史但判断以现行代码为准。有了这三行模型引用旧材料时就有机会带上限定条件而不是把它当成现行约定。同样的做法可以用在日志上不要贴最近三天的日志而是贴这次失败运行的最后 30 行输出运行时间 2026-09-29 09:12命令是 pytest -q tests/orders/test_cancel.py。4.8 什么时候确实需要大材料按任务挑选不是教条。有三类任务材料确实要大一些第一类跨模块重构。改动会经过十几个文件任何一个小小的相关文件都可能是约束条件。这时候的做法是先概览后展开先给模块树和每个模块的一句话职责再给这次会碰到的两个模块的完整实现其余模块等它明确要求时再给。这样它既知道全局又不被细节淹没。第二类首次进入陌生代码库。你需要它先建立地图。做法是先要一遍目录 一个文档让它产出结构说明和疑问清单你确认之后再进入具体任务。把建地图和改代码分成两次任务比一次塞进去更可靠。第三类事故排查。线索常常散在日志、指标、变更记录里而且你事先不知道哪条有用。做法是用时间窗口和字段筛选把材料缩小不是三天的日志而是出错请求 ID 相关的 40 行不是所有人的聊天记录而是出事前后两小时的变更清单。三类任务有一个共同的处理框架先缩小到这个任务需要理解的最小集合按需展开。展开的触发条件是模型明确提出需要什么而不是你担心它不知道什么。4.9 材料包和任务单怎么配合材料包不是独立的东西它和任务单是一体的任务单定义要做什么、怎么验收材料包提供做判断需要的事实。两者的对应关系可以写得很直接——任务单的目标 ←→ 材料包里的入口文件与相关实现 任务单的行为 ←→ 材料包里的领域规则与接口定义 任务单的验证 ←→ 材料包里的失败证据与运行命令 任务单的范围/不做 ←→ 材料包里的默认不给清单对应关系还有一个用法任何一条验收条件如果材料包里找不到支撑它的事实就说明材料包缺东西。比如验收条件说同一事务写入审计事件而材料包只给了接口和领域模型没有给审计相关的实现那模型只能靠猜。反过来材料包里如果有大量材料和某条验收条件毫无关系那它们大概率属于默认不给。每次任务结束时花两分钟核对这张对应表材料包会越用越准。材料包本身也建议纳入版本管理——它和任务单一起放进仓库而不是只存在于当次对话里。这样做的直接好处是任务结束很久之后还能回答当时为什么这样改。间接好处是同一类任务可以对比不同时期的材料包看出经验是怎么积累的。文件命名上带日期和任务名即可docs/tasks/2026-09-29-cancel-404/materials.md。4.10 把材料准备做成一条命令手工挑材料还剩最后一个漏洞同一个人今天记得采集失败证据下周就不一定记得。能自动生成的部分交给命令人只负责判断。下面这段脚本在shop仓库根目录运行它只记录、不修改代码做三件事记下当前版本、跑一次出错的测试并保存输出、留出材料包目录。$dstdocs/tasks/2026-09-29-cancel-404# 仓库根目录运行只记录、不改代码New-Item-ItemType Directory-Force$dst|Out-Nullgit rev-parse--short HEAD# 记下版本粘进材料包第一行pytest-q tests/orders/test_cancel.py 21|Tee-Object-FilePath$dst/failure.log# 采集证据同时保留完整日志Get-Content$dst/failure.log-Tail 30# 只把最后 30 行贴进上下文示例运行结果虚构项目仅示意格式$ git rev-parse --short HEAD 9f3c1a2 $ pytest -q tests/orders/test_cancel.py FAILED tests/orders/test_cancel.py::test_cancel_missing_order_returns_404 assert 500 404 1 failed in 0.31s $ Get-Content docs/tasks/2026-09-29-cancel-404/failure.log -Tail 30 ... 截断后的 30 行末尾指向 src/orders/services/order_service.py:47关键行各自解决一个问题。git rev-parse --short HEAD把版本固定下来事后任何时候都能回答当时看的是哪一版21把标准错误也引到管道里否则不少报错会在这一层丢掉Tee-Object一边保存完整日志、一边把内容送回终端等于既留了原始记录又不用手工复制-Tail 30是筛选不是省略——完整日志留在文件里贴进上下文的是最相关的一段。怎么检查这条命令有没有用把生成的failure.log交给一位没参与这件事的同事看他在不看其他文件的情况下能不能说出三件事——失败的命令是什么、失败的用例叫什么、断言差在哪里。三件都能说出来它就是合格的活证据缺哪一件就在采集环节补哪一件。五、反例与代价四种常见的材料给法5.1 反例一把仓库整个贴进去做法src/全量、目录树全量、配置文件全量一次性交给 Agent理由是省得它来回问。它为什么看起来能行小仓库里这招确实管用模型能自己找到相关文件你也省了挑选的功夫。最后的代价随仓库变大而急剧上升。首先是注意力被摊薄几十个文件里真正相关的那两个不再显眼其次是噪音带来的误导备份文件、示例代码、废弃模块都会成为顺手修改的候选最后是成本每次任务都携带全量材料token 消耗和等待时间成倍增加而这些成本在你只跑一两次的时候感觉不到。真正的问题出现在习惯形成之后你会用同一套全量策略处理所有任务包括那些只需要改一个判断的任务。5.2 反例二贴旧日志、旧文档不加时间和版本做法为了让背景更完整把历史文档和往期日志一起贴上不做任何标注。它为什么看起来能行历史材料里确实常常藏着有用的背景而且贴上去不费什么力气。最后的代价是给模型构造了一个混合世界。旧文档说功能没实现新代码里有实现旧日志里的错误分布和现在不同旧聊天记录里的约定后来改过。模型会试图同时满足这些互相矛盾的描述产出一个两边都不完全对的方案。这里的核心问题不是旧材料有错而是它的时效信息在传递过程中丢了。三行标注就能补上这一层而缺了它工程师和模型对同一份材料的理解会完全不同——工程师知道那是历史模型不知道。5.3 反例三只贴代码不贴失败证据做法把相关文件都给了但没有给任何现在坏在哪里的证据认为让模型自己跑一下就行。它为什么看起来能行代码是事实模型读完代码自然能看出问题。最后的代价是方向漂移。没有失败证据模型不知道那个 500 是从哪里冒出来的只能读代码猜猜测容易落在显而易见的地方——比如异常处理的风格、日志的写法而不是真正的判断缺失。更常见的情况是它顺手改进了几处并非问题的代码而真正的缺陷还在。失败证据是最便宜的方向定位器一段 30 行的输出能省掉十几分钟的猜测。如果测试还没有覆盖这个场景先补一条失败测试哪怕它现在就是红的再把输出交给模型——这本身就是活证据的制造方法。顺着这条线还能得到一个更实用的结论你在选择材料时的第一件事应该是问这次失败的可观测证据是什么。如果答不出来说明这个任务还停在我觉得有问题的阶段先补一条能失败的测试或者一个能复现的命令把它变成可观察的现象。这件事做完之后材料包的其他部分往往也就自动清晰了入口文件从堆栈里读相关实现从调用链里读验收条件从什么现象消失里读。5.4 反例四把参考实现当默认材料做法每次任务都带上一个写得不错的相邻模块希望新代码保持一致。它为什么看起来能行代码风格一致确实有价值参考实现能提供现成的骨架。最后的代价是隐性的模仿模型会照着参考实现的组织方式、命名、甚至错误处理习惯来写而这些可能并不适用于当前场景。比如参考模块因为历史原因返回错误码而当前模块的约定是抛异常照着写出来的代码看起来一致实际上违背了当前模块的契约。要用参考就把它降级成局部参考并在任务里写清楚参考范围只参考事务边界处理不要参考返回风格。六、落地步骤建立你自己的上下文清单下面七步的顺序有意从记录现状开始而不是从优化习惯开始。原因很实际在没有记录的情况下你无法知道自己该挑哪些材料——每个人的项目不同别人的清单只能参考真正的依据是你自己跑出来的结果。第一步为任务建立材料清单文件。每次任务开始前用一张清单写清楚这次给哪些材料、为什么给、不给哪些、为什么不给。为什么写成文件而不是记在脑子里因为清单要能复用也要能被别人检查。怎么检查清单能让你在三十秒内说清这次任务的输入是什么。第二步先收集活证据。顺序是当前分支的代码记下 commit、这次失败的测试输出、复现命令。为什么优先级这么高因为它们描述此刻的真实状态不会被时效问题污染。怎么检查每条活证据能不能回答什么命令、什么输入、什么输出。第三步把材料分成三档。必给验收条件、入口、相关实现、按需相邻模块、工具脚本、扩展日志、默认不给构建产物、旧文档、备份文件。为什么分档而不是分给不给因为任务过程中会冒出新需求有分档才知道什么情况下可以升级。怎么检查随机挑一份材料问它属于哪一档答不出来就说明分类标准不清楚。第四步给未采纳的历史材料加标注。三行来源、时间、当前是否有效。为什么只给未采纳的加因为要用的材料本身就在清单里标注的价值主要体现在你知道它存在但不该用它的那些内容上。怎么检查把标注读出来如果它能让你明白这份材料说明了什么、现在还算不算数就合格了。第五步把命令放进材料包。验证命令不是给模型参考的而是让它知道你用什么标准验收。为什么模型不知道验收方式时容易优化错方向它可能把代码改得更漂亮但没有解决测试里那条断言。怎么检查命令能直接复制运行并且有明确的通过标准。第六步做完记录一行。记录内容任务名、材料包版本、改动文件数、验收命令结果、往返轮次、有没有出现引用过期材料的行为。为什么记这个下次你就能用自己的数据判断清单是否有效而不只是凭感觉。怎么检查连续记录若干次之后你能看出哪一类材料经常引发无关动作。第七步定期修剪清单。每隔一段时间回看哪些材料从来没有被用过哪些材料引发过一次误导哪些按需其实应该升级为必给为什么必须修剪因为清单会自然膨胀而膨胀的清单等于没有清单。怎么检查清单长度保持在一页以内每一条都有一句为什么它在里面。可以直接复制的模板## 任务材料包任务名日期仓库 commit ### 必给 - 验收条件链接或文件名 - 入口文件路径 - 相关实现路径列表 - 失败证据命令 输出摘要 运行时间 - 验证命令命令 通过标准 ### 按需模型明确要求再给 - 相邻模块路径 - 扩展日志筛选条件 - 历史文档链接 时间标注 ### 默认不给 - 备份文件与生成代码*_old.*、*.bak、build/、dist/ - 无时间标注的旧文档与旧聊天记录 - 与本次判断无关的模块 ### 本次记录 - 改动文件数n - 验收结果通过/不通过 - 往返轮次n - 出现的问题引用过期材料/范围外改动/无七、常见问题问材料给少了它会不会缺信息乱猜会但和给多了的失败不一样给少了失败通常很显眼——它会明确说我找不到仓储接口或者直接问你要文件给多了失败是隐性的它自信地给出一个被过期材料带偏的方案。显性失败容易处理补一份材料就行隐性失败要靠事后辨认。所以在信息不足和材料过载之间宁可从最小集开始按需增加而不是一上来就倾泻全量。问我怎么知道哪份材料是活的用三个问题过一遍它描述的是当前分支吗它是什么时候产生的它是不是这次任务的正式依据三个问题都答是的是活证据当前代码、刚跑出的失败输出、任务单。有一个答不上来或者答不是的就归入历史材料需要标注后再用。一个实用习惯贴材料时顺手写上来源 时间 是否仍有效三行成本能省下大量来回。问检索系统RAG不是能自动挑材料吗为什么还要人工建清单检索解决的是从一大堆内容里找到看起来相关的片段它给出的分数衡量的是相关性不衡量时效和权威性——也就是说它可能给你一份内容相关但版本过期的片段而且不会主动提醒你这一点。人工清单的价值在于它明确了两件事哪些材料一定是当前有效的活证据哪些材料即使被检索到也应该标注时间。两者配合的方式通常是用检索扩大候选用清单和元数据做筛选最后贴进上下文的每一段都带来源和时间。问任务很小也要走这套流程吗不用全套。小任务比如改一行文案、补一个空值判断可以压缩成三件事一个入口文件、一条失败证据或一条复现命令、一条验收命令。清单的价值在于它让给什么变成一个有意识的选择而不是默认的看到什么给什么。任务越小材料越少越不容易被噪音带偏——但有意识地挑这个习惯要保持它决定了你在大任务上会不会走样。问如果我已经给了太多材料发现它跑偏了怎么补救最有效的动作不是再给它更多解释而是重新开始一个干净的上下文只带最小材料集重新下任务。原因在于之前的材料已经进入对话历史之后每一轮都会带着它们一起被读取你想用一句话纠正那份文档已经过期但过期文档本身还在上下文里权重并没有消失。重新开始一次通常比反复纠正更快也更便宜。如果任务很长不能重开退一步的做法是在每条消息里重申最关键的两条约束让它们反复出现在近期内容里。问要不要把整个失败日志给对方不用整个给和这次判断有关的一段。筛选方法有三个按时间窗口截取失败发生前后的输出、按关键字过滤错误类型、请求 ID、文件路径、按层级截取只保留错误堆栈和最相关的几行上下文。给日志时带上三个信息命令、运行时间、环境本地还是 CI。这三条信息决定了日志的解释方式——同一条报错在不同环境下的含义可能不同。问文档写得很旧但里面确实有重要背景怎么办把事实和背景分开。背景部分为什么当初这样设计、走过哪些弯路保留标注时间事实部分接口长什么样、字段有哪些重新核实以当前代码为准。具体做法是把它转换成一份历史记录写清决策背景、当时的约束、以及现在是否仍然成立。这样一来它对模型的价值从现状描述变成了决策背景误用的风险大大降低而你想保留的那部分信息一点没丢。问怎么让别人也遵守这套材料清单靠模板和工具不靠提醒。把材料包模板放进任务单文件的同一个目录新任务从模板复制能自动生成的部分当前 commit、失败输出、运行命令写成一个小脚本一键产出材料包骨架。人是会忘记的模板不会。再配一条最小规则任何一次交给 Agent 的任务材料包要么在文件里要么在任务单里两者都没有就视为任务没准备好——这条规则容易检查也容易被接受。问材料包里要不要放这个模块的历史放但要放成有裁决的信息而不是一堆并列的叙述。具体做法是把它写成三行结构当时为什么这样设计、当时的约束是什么、现在是否仍然成立。第三行是裁决行——它决定了这段历史对当前任务是约束还是背景。没有第三行历史材料就只是故事而且是一个可能被误用成现状的故事。如果这段历史足够重要值得单独存成一份决策记录记录背景、决策、后果和修改条件让它的作用和边界都写清楚。问团队里每个人给的材料不一样怎么统一统一到模板和产出物上而不是统一到记忆上。三个落点材料包模板放进仓库新任务复制任务单里固定一节写本次材料与排除项任务完成后把本次实际有效的材料清单回填到记录里。这样做的结果是一段时间之后你能看到哪类任务需要哪类材料的经验被沉淀在文件里而不是散在各人的习惯里。再加一条很轻的检查开任务时对照模板数一遍必给项缺哪项就补哪项数一遍不超过半分钟。问把材料缩小之后会不会漏掉重要的上下文导致它做出更差的判断这个担心有现实基础所以缩小材料不是一次性动作而是最小集 按需展开的组合。做法上留两个后门一是在任务描述里明确欢迎它提问——“需要其他文件时直接说文件名我会提供”二是把它提出的问题记录下来如果同一类材料在多个任务里被反复要求就把它从按需升级成必给。真正危险的不是材料少而是材料少却没有提问的通道模型既看不到需要的文件也不会主动要只能靠默认假设往下走。问把材料整理成清单会不会反而让我花更多时间第一次会之后不会。第一次整理大约多花十几分钟收益从第二次开始显现同类任务的清单可以直接复制改动几个文件名就能用因为材料更准往返轮次下降你省下的是最贵的那部分时间——等待和纠正。判断是否值得还有一个经验标准如果你一天里要交给 Agent 三个以上的任务清单化的收益当天就能覆盖成本如果一周才用一次可以从三项最小清单入口文件、失败证据、运行命令开始先跑起来再慢慢补。问模型自己也能读仓库为什么不能让它自己去挑材料可以而且这是很多工具的默认工作方式它按需读取文件。但自己去找和由你控制材料有两个差别。第一读取动作本身要经过它的判断——它先要猜哪些文件相关而这个猜测可能被目录里的旧文件、备份文件或者无关模块带偏你直接给等于跳过了一次以猜为起点的检索。第二读取过程不透明它读了什么、基于哪一版通常只留在它自己的过程里你的评审看不到。稳妥的折中是让它自己探索时要求它把读过的文件清单 每个文件的作用作为交付的一部分写出来你据此判断它是否进了错误的世界。问已经试过、失败了的做法要不要写进材料包要但写成已排除并附一句为什么排除。多数返工不是因为模型不知道方案而是它不知道这个方案在上一轮已经试过。它的视野里只有你给的材料你试过的失败路径不在里面于是一个看起来合理的候选会被再次提出来。写法上不要只写结论“不要加重试”要写动作和结果在仓储层给连接错误加重试 → 重跑pytest -q tests/orders/test_cancel.py仍然是 500因为失败发生在订单查找之前。这样它既不会重走老路也能从结果里读出真正的原因而不是被一句没有依据的禁令挡住。问任务做到一半需求变了材料包要重做吗不用重做用追加的方式改。保留原材料包的内容在末尾加一段本次变更改了什么验收条件、范围还是接口约定、什么时候改的、哪些旧材料因此作废。为什么强调保留而不是覆盖因为材料包同时是一份记录事后回看时当时基于什么信息做的判断和判断在哪一刻被改掉是两件事。操作上只做一个小动作在作废的材料前面标一行已作废见本次变更第二行而不是直接删掉。删掉之后过两周没有人能解释那份代码为什么长成现在这样。八、动手练习与小结练习在你的项目里做一次 A/B 对照选一个真实的小 bug比如某个接口的返回码不对按下面的顺序做一遍。第一步固定变量。记下当前 commit、写下同一段任务描述、写下同一组验收命令。这一步的意义是后面两组结果的差异只能归因于材料。第二步跑 A 组。把你平时会给的材料一次性给出目录树、最近的日志、手边能找到的文档。记录结果重点是三项改了哪些文件、有没有用到过期的信息、往返了几轮。第三步跑 B 组。回到同一个 commit按五项清单重新组织材料验收条件、入口文件、相关实现、失败证据、运行命令。其余材料放进默认不给。同样记录三项结果。第四步对照并写结论。把两组的记录放在一张表里逐项比较。然后回答两个问题B 组里少了哪些材料反而更好A 组里哪些材料是真正必需的如果有第五步把结论固化。更新你的材料包模板把 B 组验证过的必给项固定下来把 A 组里引发误导的材料写进默认不给。模板存档下次任务直接复制。做完之后你手里会有一份属于自己的材料清单以及一份对照记录。对照记录的价值在于它是对照你自己项目的实际情况得出的而不是照搬别人的规则。小结这一篇的核心是三句话。第一材料不是越多越好长上下文里关键信息会被稀释位置靠中的内容尤其容易被忽略Liu 等2024。第二过期材料比缺少材料更危险模型没有能力给材料标注真伪和时效它会把你给的一切都当作现状从而进入一个不存在的世界。第三材料按任务挑选方法是五项清单加排除清单优先活证据当前代码、失败输出、运行命令历史材料必须带来源、时间和有效性标注。操作上还有三个要点给材料时把最重要的两条约束放在开头和结尾跑完记录一行改动文件数、往返轮次、是否引用过期材料以便长期改进发现跑偏时最有效的补救是带最小材料集重开一轮而不是在污染的上下文里反复纠正。和前后篇的关系上一篇讲输出侧的结构化契约让交付物可校验这一篇讲输入侧的材料选择让 Agent 看到的都是当前有效的世界。下一篇继续往怎么给代码这个方向走同一个模块先给接口还是先给实现效果差别很大——这就是代码折叠要解决的问题。