公司动态

用代码文档驱动编码智能体:从上下文工程到可验证执行

📅 2026/8/31 21:14:17
用代码文档驱动编码智能体:从上下文工程到可验证执行
做 Agent 相关开发时最容易让人上火的不是模型能力不够而是它明明读了代码文档最后交付的东西还是跑偏。最近 Show HN 上有一个项目标题很直接Get agents to do what I want with code documentation。它想解决的核心问题就是让编码智能体在理解代码文档之后真正按照人的意图行动而不是只把文档当作一个可检索的文本仓库。这个主题适合正在做 Agent 应用、想接入代码仓库语义、或者被多步 Agent 任务稳定性折腾过的人。最值得关注的点不是某个提示词技巧而是把“文档结构”和“执行意图”当成同一套工程来做。下面按实际落地顺序拆一遍。先讲 Agent 为什么会误解文档再讲如何用代码文档驱动 Agent最后给出一套可复现的单任务、批量任务和排查流程。1. Agent 为什么总是误解你问题往往不在模型在上下文1.1 Agent 不是“读代码”而是“读检索到的片段”很多人的第一反应是Agent 已经接入了代码仓库它应该能看懂所有代码吧实际上不是。大多数编码 Agent 的上下文窗口是有限的。工具会把代码库切成代码块、函数、文档片段再通过关键词或者语义检索挑出一部分内容塞给模型。也就是说Agent 看到的不是完整项目而是“它认为相关的碎片”。如果代码文档结构混乱、描述过时、缺少入口信息检索出来的片段就会偏离真实逻辑。举例来说你希望 Agent 修改支付回调失败后的重试逻辑。它可能只检索到了retry()这个函数没有看到外层队列、失败记录表和幂等键。结果它认为重试就是“多循环几次”于是把重试次数改得很激进却不知道真正要处理的是重复回调带来的重复入账问题。这才是“Agent 不听指挥”的常见真相不是模型笨而是喂给模型的上下文是残缺的。1.2 代码文档是 Agent 的隐性输入不是可选项代码文档对人类开发者来说是方便查阅的说明书。对 Agent 来说文档几乎就是“任务需求书”。一个普通开发者接到新需求会先看 README、看接口注释、看调用示例然后才去翻源码。Agent 也一样。如果项目里只有一堆零散注释没有结构化的入口文档Agent 就需要靠“猜”来补全缺失信息。一旦猜错后续步骤全部跟着错。我见过不少团队把 README 当成摆设主分支上只有一行安装命令。人类开发者还能靠经验硬读代码Agent 却很容易被误导。只要文档里写错了参数单位、漏掉了异常分支Agent 就可能生成一个看起来合理、实际不可用的改动。所以想让 Agent 按照你的意图执行第一步不是调模型而是把代码文档整理成 Agent 能消费的输入。2. 先把“意图”拆成 Agent 能验证的步骤2.1 给 Agent 的不是一句话而是可检查的目标“帮我优化登录流程”这种需求给人类开发者都容易理解出三个版本给 Agent 就更危险。更好的任务描述是在登录接口中增加失败次数限制 1. 连续失败 5 次后锁定账户 10 分钟。 2. 锁定期间返回 429 和错误码 LOCKED。 3. 使用 Redis 记录失败次数key 格式为 login:fail:{userId}。 4. 成功后清除失败计数。这段话有几个特点有触发条件、有结果状态、有数据存储方式、有验收指标。Agent 拿到之后不需要自己脑补“优化”是什么意思。代码文档也要配合这种描述方式。每个模块文档至少写清楚这个模块是做什么的入口函数或服务是什么输入参数有哪些成功时返回什么失败时抛出什么调用方应该怎么处理异常2.2 文档结构决定 Agent 找不找得到入口光有内容还不够位置也很重要。Agent 检索文档时通常先看标题层级、目录结构和关键词密度。如果文档把所有内容混在一大段 Markdown 里检索效果会明显下降。我比较推荐按模块维护独立文档而不是写一个巨型架构手册。示意结构如下docs/ 00-index.md auth/login.md payment/callback.md user/account-lock.md00-index.md是索引文件列出每个模块的地址和适用场景。Agent 拿到任务后先看索引再进入具体模块文档而不是在一个几千行的文档里大海捞针。具体模块文档可以用统一的标题模板# 登录模块 ## 功能入口 - 文件位置src/auth/login.ts - 对外接口POST /api/auth/login ## 输入参数 - username: string必填 - password: string必填 ## 输出格式 - 成功200返回 { token, expiresIn } - 失败401返回 { code: BAD_CREDENTIALS } ## 异常与边界 - 连续失败 5 次后锁定账户 10 分钟 - 锁定期间返回 429这种结构的价值在于Agent 只需要在文档里找到对应的标题就能定位到关键信息不需要把整个源码都读一遍。2.3 关键动作前必须“打断”最近技术社区经常讨论一个概念deep agents interrupt。简单说就是 Agent 在执行链条里要具备“打断能力”在进入高风险操作之前停下来先把计划交回给人类确认。为什么要引入打断机制因为 Agent 非常擅长“顺着往下做”却不太擅长判断“这一步是否应该做”。如果文档只写了正常流程没有写“改数据库前需要确认”“删除代码前需要备份”Agent 可能会直接执行不可逆操作。所以我在给 Agent 设计任务时会刻意加一道检查点在执行以下操作前先输出你的计划和预期影响 1. 修改数据库结构 2. 删除或重命名文件 3. 发送外部请求 4. 修改支付、权限、安全相关逻辑这个机制看起来会降低自动化程度但实际能减少大量返工。尤其是把 Agent 接到生产任务时宁可让它“多问一句”也不能让它“一路跑到错”。3. 用代码文档驱动 Agent 的最小落地框架3.1 文档索引与上下文剪枝很多项目的失败点不在“没有文档”而在“文档太多全塞进去”。Agent 的上下文窗口是宝贵的资源。把整个 README、全部注释、所有历史设计文档都丢进去看起来是“信息丰富”实际上会稀释关键信息。模型可能被不相关内容带偏也可能因为输入太长导致响应变慢、成本升高。更好的做法是先做一次上下文剪枝只保留当前任务相关的模块文档。文档中只保留入口、参数、输出、异常、验证方式。历史决策记录单独放不默认参与上下文。代码示例放在文档尾部需要时再取。如果你的 Agent 工具支持“按文件路径指定上下文”那就尽量少用“自动检索全库”先手动指定一个范围。这样成功率通常会比广撒网更高。3.2 文档要写例子不写大段原理Agent 对“示例”的理解能力明显强于对“抽象描述”的理解能力。与其写“本接口用于用户身份验证”不如写### 正常调用示例 POST /api/auth/login { username: test01, password: 123456 } 成功返回 { code: 0, data: { token: eyJ... } }再配一个失败示例### 失败调用示例 连续输错密码 5 次后接口返回 { code: 429, message: account locked, data: null }Agent 看到示例后会更容易理解输出格式和异常分支。建议在文档中为每个核心接口保留一个“正常示例”和一个“异常示例”这比写十行原理说明更实用。3.3 用测试型 Agent 验证文档是否可信文档有一个天然问题它可能已经过时了。想解决这个问题只靠人工 review 不够。比较务实的方案是引入测试型 Agent比如用Playwright test agents来验证文档描述的行为是否真的成立。Playwright 这类浏览器自动化工具可以模拟用户点击、输入、跳转也能读取接口返回。你可以让 Agent 先根据文档写测试用例再跑一遍真实流程。比如文档说“登录失败 5 次后锁定账户”那就写一个用例连续调用 5 次错误的密码看接口是否真的返回 429。这一步的好处是把“文档描述”变成“可执行断言”。文档写对了测试通过文档写错了测试失败。经过几轮测试之后文档的可信度会明显提升Agent 基于文档做判断的稳定性也会跟着变好。4. 实际跑一遍从单任务到批量任务4.1 准备一个可复现的目录结构先不要焦虑“要不要用某个特定框架”。最基础的做法是准备一个统一的任务目录run/ tasks/ 001-fix-login-lock/ task.md input/ output/ logs/每个任务一个独立目录任务描述放进task.md需要输入的样例放进inputAgent 生成的代码或结果放进output运行日志放进logs。这个结构看起来简单但价值很大任务之间互不影响失败后可以从日志里定位问题批量跑的时候也方便做文件命名和断点续跑。4.2 单条任务先跑通记录输入输出和耗时不管最终目标是批量处理多少任务我都建议先跑一条最小任务。我一般会先选一个高频且改动范围小的任务比如“修正一个接口的参数校验逻辑”。任务描述要尽量贴合文档结构确保 Agent 可以只依赖少数几个文档片段完成工作。单条任务跑通后记录这些信息输入任务描述原文喂给 Agent 的文档片段或文件路径Agent 输出的代码或改动执行耗时是否出现人工修正人工修正的原因这些信息能帮你判断到底是文档缺内容还是任务描述模糊还是模型上下文不够。不要跳过这一步直接开批量否则一个错误会被复制到几十个任务里。4.3 批量任务必须处理命名、日志和失败重试批量任务真正要解决的不是“能不能跑”而是“跑挂了以后怎么办”。在批量执行之前先把下面几个问题定下来输出文件如何命名是否带任务 ID成功和失败用什么标记区分失败任务是否暂停重试还是跳过继续重试次数上限是多少中断之后能不能续跑这些属于工程参数不是模型参数。但它们的优先级比模型参数更高。因为 Agent 任务往往是多步骤的中间可能因为网络超时、输入格式错误、文档缺失而中断。如果没有命名规则和失败记录重新跑一次就无法区分哪些是已完成、哪些是待处理。一个比较稳妥的批量策略是先跑 1 条样例确认链路正常。再跑 3 到 5 条观察耗时不均匀。最后再跑全量并开启失败重试和日志记录。不要一上来就开最大并发。并发高了资源占用会上升出问题时日志也难对得上。5. 不要盲目堆文档边界、资源消耗和维护成本5.1 文档越多Agent 的选择越不稳定代码文档确实重要但“多”不等于“好”。当一个模块文档里塞满各种无关信息比如团队历史、闲聊记录、过期接口说明Agent 在检索时就容易把次要信息当成主要约束。最后它可能给出了一个“看起来详细、实际跑不通”的结果。文档有效性的关键不是覆盖所有细节而是让 Agent 在最短时间内找到最相关的那部分。所以每次新增文档都要问一句这段内容能不能帮助 Agent 做判断如果它只是用来展示项目历史应该移到独立文档不参与默认上下文。5.2 判断文档是否有效的四个标准我在检查文档时通常用四个标准检查项判断标准常见问题入口是否好找索引文件能直接指向具体模块只有一个超长 README输入输出是否明确有参数表、示例、返回格式只写了“处理用户登录”异常是否有分支有失败码、锁定策略、重试说明只写了成功路径验证是否可执行有测试示例或可运行命令文档停留在理论描述如果四个标准都满足这个文档才算达到“Agent 可消费”的底线。否则Agent 大概率会在执行过程中自行发挥。5.3 团队落地的最小流程不用想着一次把代码仓库所有文档重写。更现实的做法是选一个高频业务模块按最小流程跑通选出 3 到 5 个高频 Agent 任务。为对应模块整理结构化文档。用单条任务验证 Agent 是否按文档执行。每周更新一次文档根据失败任务修正内容。等这个模块稳定之后再复制到下一个模块。这样成本可控也能积累一套适合自己团队的文档模板。6. 排查链路从现象到根因6.1 先看现象再看输入后调参数Agent 任务失败时最忌讳直接改 prompt 或者调温度。正确的排查顺序应该是看现象是报错、卡住、无输出还是输出不符合预期。看输入任务描述是否清晰喂给 Agent 的文档片段有没有遗漏关键信息。看日志中间步骤停在哪里是检索失败、上下文超限还是执行脚本报错。看环境依赖版本、权限、网络、资源占用是否正常。看参数并发数、超时时间、重试次数、模型上下文窗口是否合理。这套链路能避免一个常见问题把“文档缺失”误判成“模型太笨”然后连续调各种无关参数。6.2 为什么文档越好Agent 反而越慢这是一个很有意思的现象文档质量提升后Agent 反而变慢了。原因通常是高质量文档包含更多细节和示例Agent 需要读更多的 token在执行任务时它还可能主动去验证多个分支增加中间步骤。这本质上是用“更多推理”换“更高准确率”。所以社区里开始从building effective agents过渡到toward efficient agents。核心不是少给文档而是给对文档同时减少无效推理。具体可以这样做把高频路径写在文档开头。把不常用分支放到后面的“边界情况”小节。给 Agent 设定最大步骤数避免它无限自我验证。对简单任务直接指定文档路径不让它全局检索。效率优化的目标不是让 Agent 更快地犯错而是在不降低准确率的前提下缩短不必要的决策链。6.3 三个常见失败模式我在实际使用中最常遇到三类失败失败现象常见根因处理方式Agent 输出的代码和文档描述不一致文档已过时或没有说明最新行为先用测试用例验证文档再让 Agent 执行任务执行到一半卡住上下文太长或缺少“打断—确认”机制降低输入长度增加中间确认步骤批量任务结果不稳定输出命名混乱失败后没有统一日志先固定目录结构再开批量排查时不要盯着单个错误码看先判断它属于“文档问题”“上下文问题”还是“工程问题”。7. 我的建议先做小范围实验再全量接入7.1 给第一次尝试的人四条建议如果你准备用代码文档来驱动 Agent不要马上接入整个仓库。我建议按下面的方式试选一个最小模块整理好结构化文档。用一条单任务验证 Agent 是否能按文档执行。记录一次成功和一次失败的过程找出差异。只改一个变量再跑下一轮。这套流程看起来很慢但能帮你建立对 Agent 行为的判断能力。否则一上来就开很多任务最后你会分不清问题是出在模型、文档、参数还是流程。7.2 什么时候才适合大规模使用如果连续多轮任务的成功率稳定并且失败后能通过日志快速定位原因这时候再考虑全量接入。判断标准可以这样定单任务成功率稳定在一个可接受区间。批量任务无需频繁人工修正。文档维护有固定负责人。失败日志能回溯到具体输入片段。Agent 在关键操作前会主动暂停确认。当这些信号都出现时再扩大到更多模块顺势考虑接口化、队列化和自动化调度。否则先守着一个模块打磨反而更稳妥。说到底代码文档驱动 Agent 不是“写一份好文档”这么简单它是一套关于上下文、意图、验证和工程纪律的组合。先把单任务跑稳再谈批量和效率这条路最不容易翻车。