SWE-Touch:当用户中途修改代码,编码智能体还能跟上吗?

SWE-Touch:当用户中途修改代码,编码智能体还能跟上吗? 如果你用过编码智能体大概遇到过这样一个场景你让 AI 修复一个函数它先给出方案你顺手把函数后半段按自己的思路重写了然后让它继续处理下一步。结果它要么像没看到你的修改一样继续按旧逻辑补全要么直接把你刚刚手工调整过的代码又“优化”回原来的样子。这种体验非常常见但现有的大多数编码智能体评测并不关心这件事。这正是 SWE-Touch 这个基准让人感兴趣的地方。它把“用户会在中途触碰代码”这件事变成了一个可以被重复测量、被比较、被研究的评估场景。它的核心信号很清楚真正决定编码智能体生产效率的不是单次独立解题能力而是当用户半路插改之后它还能不能保持正确的上下文、调整计划、继续把任务做对。这篇文章会从研究背景、任务设计、自建测试、团队选型、问题排查和未来影响几个层面展开。没有官方榜单和完整论文细节也没关系我们可以从这类基准的通用设计逻辑和真实工程经验里反推出它到底在测什么以及我们自己能用它学到什么。1. 为什么需要一个新的交互式编码智能体基准1.1 旧基准的典型假设有手有脚从头做到尾过去两年代码智能体评测最常被提及的是 SWE-bench 这类任务。它的做法大致是给定一个真实仓库、一个 issue 描述以及一些失败测试让智能体自己完成定位、修改、运行测试、生成 patch 的整个过程。评估指标很清晰就是最终能不能让原本失败的测试通过。这类基准非常有价值它让“代码智能体能不能独立解决一个真实问题”第一次有了可复现的标尺。但它有一个隐性假设用户不在中途干预问题从起点到终点都由智能体独立完成。你可以把这个过程想象成一场开卷考试。题目印在卷子上标准答案在测试用例里考生独立完成。可真实软件开发并不是考试更像两个人在同一张工作台上轮流操作。你刚改完一个变量命名拿起手边的新需求转过头发现智能体已经在你改过的代码上继续长出了一大段逻辑。这种场景在旧基准里根本没有被充分覆盖。1.2 真实开发不是“一次性任务”而是“边做边改”实际开发中的编码智能体使用方式很少是“把整个 issue 丢给它等一个最终 patch”。更常见的是这样一个函数写到一半你发现参数类型不合适先改成更通用的接口。agent 生成了一段实现你审阅时觉得某个分支逻辑有问题手工重写了那段分支然后继续要求它补错误处理。你重命名了一个类把调用点都改好了然后让 agent 继续完成某个相关模块。甚至只是在一个注释里补了一句“这里的价格必须保留两位小数”这个注释对模型来说就是一堵墙后面所有代码都不能越过它。这些动作都可以称作“用户触碰代码”。它不像直接提需求那样明确也不像传统 code review 那样发生在任务完成之后而是发生在任务执行过程中。用户不是旁观者而是参与者。对于编码智能体来说它必须能够感知用户刚刚做了什么、理解这个动作背后的意图并把这种理解综合进自己的后续计划。如果智能体做不到就会出现典型的“协作短路”它还在按最初生成的计划推进但用户的世界已经变了。最后的输出要么是覆盖用户修改要么是生成一份逻辑上已经和仓库状态脱节的代码。1.3 为什么这个问题长期被忽略一个原因是评估成本。要模拟“用户触碰代码”需要定义用户行为的分布。是手工改动一行还是重写一个文件改动后要不要继续多轮交互每次改动如何影响“正确答案”的判断这些问题都比传统 benchmark 复杂得多。另一个原因是可复现性。标准的自动评测希望尽量减少随机干预而用户修改本质上是一种“不可控介入”。为了做评测就必须把这种介入也变成一个标准化的动作比如预先生成一系列 diff在某个固定时间点或某个 agent 执行步骤后注入。设计成本高评分规则也模糊。但从工程经验看真正决定智能体能不能被放进团队工作流里的恰恰是这种“临时插一脚”的鲁棒性。一个 agent 如果能在用户改完代码后快速调整方向它带来的效率增益远大于一个只擅长从头写到尾的 agent。因为真实项目永远在变化没有哪个任务会安安静静等你跑完。2. SWE-Touch 到底在测什么一次“用户改代码”之后发生了什么2.1 用户修改是干扰、约束还是线索不同用户触碰代码的方式传递的信息是不同的。它可能是干扰比如用户只是做个局部重构不希望 agent 继续碰这个区域也可能是约束比如用户通过手工修改表达“这条业务规则不能依赖外部配置”还可能是一个线索暗示接下来的所有生成都应该围绕这个新方向展开。智能体最大的挑战不是识别这些修改的字面 diff而是推断它们传递的意图。一个改参数类型的动作可能意味着后续所有涉及这个函数的调用点都要跟着变一个在返回值前添加的断言可能意味着后续的错误处理必须更严格一个把列表改为元组的操作可能是在提醒你这些值不允许被修改。SWE-Touch 这类基准之所以值得关注就是因为它把这种“模糊但真实”的场景固化成可重复的实验。它要求智能体不是被动地接受文本变化而是主动理解用户行为背后的意图并把新意图贯穿到后续代码里。2.2 对编码智能体的关键能力要求如果只看最终测试是否通过很难区分一个 agent 是真理解了还是碰巧蒙对了。所以 SWE-Touch 这类交互基准考察的其实是几项更底层的能力Diff 感知能力。智能体能不能在海量上下文里注意到那几行用户改动。很多模型不是不聪明是根本没发现你改过代码因为它的上下文窗口里塞满了历史对话和旧版文件内容。意图推断能力。看到用户把 list 改成 tuple它能不能判断出这是一种不可变性约束而不是一个随意的类型变换。这需要模型具备一定的代码推理能力而不只是模式匹配。计划更新能力。agent 早期生成的计划往往是按最初状态设计的一旦用户改动发生旧计划可能会把后续任务带偏。它必须有一个重新评估的触发机制而不是机械地执行 todolist 里的下一步。风险控制能力。面对用户刚改过的代码它至少要克制住“优化”的冲动。最危险的行为不是生成速度慢而是自作主张把用户的手动改动“修正”回它自认为更好的版本。这些能力在传统 benchmark 里很容易被忽略因为旧基准只看结果 patch不看过程中的协作质量。SWE-Touch 把注意力拉回了过程这会让研究者重新思考模型该往哪个方向优化。2.3 构造任务时最难的环节如何定义“用户触碰”真正让这类基准落地的难点并不是让 agent 跑起来而是设计“用户触碰”这一动作本身。首先是触碰粒度。用户可能只改一个变量名也可能重写半个函数还可能跨文件调整接口。粒度过小agent 可能根本不需要改变行为粒度过大任务又变成了另一个独立的编程任务。其次是触碰时机。是在 agent 一开始行动前就给出修改还是在它已经完成了早期计划、生成了部分代码、跑到中途时才插入时机不同挑战完全不同。中途插入更贴近真实但也更难评估。最后是正确性定义。传统 benchmark 有测试作为通关标准但用户改完代码后最终“正确”的答案未必只有一个。只要满足了用户新增的约束、保留了用户改动、原有测试继续通过就应该算正确。这种更宽松的评估标准对自动化打分提出了更高要求。所以SWE-Touch 表面上是给编码智能体出题实际上是在给整个评测体系设置一个更贴近现实的难度模式。3. 在还没有官方完整榜单前如何用同样思路自建交互测试3.1 先想清楚要验证什么从需求变成可执行假设即使官方完整榜单还没公布你也能用同样的思路给自己团队用的编码智能体做一次“交互稳定性测试”。关键不是复刻一个完整 benchmark而是从你自己的真实工作流里提取几个最容易翻车的场景。我一般会先列一个清单每个场景包含一个初始任务、一次用户修改、一个后续请求。不用复杂关键是用户修改要出现在 agent 工作流程的中途。比如场景 A让 agent 实现一个订单金额计算函数等它生成第一版后手工把折扣参数从浮点数改成 Decimal然后要求它继续补充边界测试。场景 B让 agent 重构一个用户类在它刚改完文件结构后手工调换两个方法的位置并给其中一个方法改名再让它完成相关调用点的更新。场景 C让 agent 修复一个偶发空指针在它提出方案后手工在入口处增加一层 null 检查然后让它继续处理日志记录和异常包装。这些场景的共同点是用户修改不是一次完整指令而是一个半路插入的动作。智能体必须自己去发现并在后续行为里体现出来。3.2 最小实现脚本化跑一个“动手脚本”自建交互测试不需要太重最基础版本只需要一个小示例仓库、一个可重复的 diff和一个用来注入 diff 的脚本。大致的执行顺序是准备一个固定版本的示例仓库记录起始 commit。给编码智能体一个初始任务让它开始执行。当它执行到某个约定阶段比如生成了第一版代码或运行到第 N 步时用脚本把预先写好的 diff 静默应用到工作区。不额外提示让 agent 继续执行原任务。记录最终 patch、测试结果和 agent 行为轨迹。这里的关键点在于diff 要预先写好注入过程要可复现而且不要在注入后向 agent 明说“我已经改了代码”。你模拟的就是现实中的隐形协作——用户默默调整了代码agent 应该自己发现并适应而不是靠人类告知。一个简化版的脚本流程可以长这样# 示例在 agent 执行中途注入用户修改 git checkout -b touch-test origin/main # 运行 agent 并让它生成中间步骤等待某个标记文件出现 # 在标记文件出现后应用预定义的修改 git apply --whitespacenowarn fixtures/user_touch.diff # 然后让 agent 继续实际落地时你会需要一些参数控制超时时间、最大迭代步数、是否允许 agent 自行运行测试、上下文窗口大小、模型名称等。建议先跑小样本每次只测一个场景不要一上来就并发跑十个任务。因为交互基准最怕的不是跑得慢而是结果不稳定你不知道失败是模型能力问题还是测试脚本注入时机偏差。3.3 评估指标不只看测试通过率传统 benchmark 里最关键的数字是测试通过率。但在交互场景里还要额外关注几件事用户改动保留率agent 最终生成的代码里有没有把你手工修改过的内容改回去。首次引用步数agent 在多少步内开始正确引用你改过的代码如果一次都没引用说明它根本没感知到变化。错误方向浪费步数agent 是先按旧逻辑绕了一大圈最后才回到正轨还是一开始就转向新约束。覆盖风险最终 patch 里是否包含与用户改动直接冲突的、不必要的回滚型修改。这些指标不必全部自动化可以分两类。一类用于快速筛选比如测试通过率和用户改动保留率另一类用于人工审查比如“它是否理解了你把参数改为 Decimal 的真实意图”。小规模人工审核仍然不可替代因为在交互任务里很多“正确”不是非黑即白。3.4 需要注意的边界自建交互测试有一个明显的边界它最多只能模拟你设计出来的那几种“用户触碰”。真实用户的行为分布远比脚本丰富有时候一个毫无逻辑的 micro-diff可能比精心设计的场景更容易让 agent 崩溃。另外不要期待 agent 对所有手工修改都有正确反应。如果你的修改本身存在歧义agent 不一定会按你的隐藏意图走。这时候问题未必在 agent而在于用户改动是否需要更明确地表达意图。所以自建测试的定位应该是“回归测试”不是“能力绝对证明”。它的价值在于当新的模型版本发布或者你的 prompt 策略调整之后你有办法快速确认“在用户中途修改代码的场景下它的表现没有变差”。4. 从基准到团队协作判断编码智能体的五个维度4.1 感知能力用户改过的代码是否真的进入了上下文最先要考察的是agent 有没有意识到代码变了。很多失败不是推理能力差而是上下文管理有问题。它可能只把用户修改当成普通文本没有和当前任务产生关联。判断方法很简单你手工改动某个函数后再让 agent 继续相关任务看它的第一轮反馈里有没有提到你刚改过的东西。如果完全没有说明它可能还在用旧版本模型回答。此时不要急着让它继续先手动把 diff 贴进会话或者要求它先读取最新文件内容。4.2 意图推断能力能不能理解你为什么要改代码修改本身是一份高度压缩的反馈。用户把参数改为不可变类型往往不只是想换个类型而是在给后续实现加上不可变性约束。agent 如果只是机械地照抄新类型但后续生成里仍然时不时把改过的值重新赋值说明它没有理解意图。面对这种情况一个更稳妥的使用方式是在用户改动的同时用一句简短的话说明意图。不要假设一个 agent 总能从 diff 里准确推断出隐含需求。好的协作不是测试 agent 的读心术而是给它的推断提供必要上下文。4.3 计划更新能力旧计划会不会把路带偏很多 agent 会先生成一个“计划列表”然后逐项执行。问题在于如果用户中途改了代码旧计划里没有被标成“已完成”的步骤可能已经失效但 agent 仍然按部就班地执行。判断标准是它在收到新状态后有没有重新读取相关文件、更新计划还是继续做计划里那些不太相关的改动。如果它还在改一个你已经不关心的问题那说明计划更新机制失效了。这种场景下更有效的做法不是强行打断它而是把旧计划删除重新让它基于当前代码生成一份新计划。4.4 风险控制能力会不会覆盖你的改动这是最危险的一类错误。用户手动改好的代码被 agent 在后续“优化”中覆盖成另一种实现。尤其当用户改动没有伴随测试更新时agent 很容易把它当成一个可以被改进的临时状态。所以审阅最终 diff 时一定要重点检查用户修改过的关键行看它们有没有被改回或者被包裹进一个更大逻辑里。有些 agent 不是故意覆盖而是它生成代码时会使用一个较大范围的 apply model导致“顺带”重写了相邻代码。这时候应该要求 agent 使用更小的编辑单位或者限定只修改与任务相关的文件。4.5 验证能力能不能围绕“触碰点”写断言一个真正融入协作的 agent不会只满足于让现有测试通过。它会在用户改动附近补上新的测试用例用来验证用户加的约束确实被后续代码遵守。这听起来要求很高但实际上很多基础场景是可以做到的。我通常建议团队在这一项上不要求一步到位而是先要求 agent 在用户改动后的注释或提交信息里明确总结“我理解到的用户约束是 X”。如果它复述都错了后面的代码自然不可靠。4.6 一个可复用框架用户小步修改、继续执行、验证、复盘把上面五个维度浓缩成日常使用流就是四步用户小步修改只做可解释的、聚焦的单点代码改动。继续执行让 agent 继续原任务观察第一轮反馈。验证检查测试、diff、用户改动保留情况。复盘把失败案例整理成固定的“交互回归测试”样本。这套流程不需要特别复杂的工具核心是把“用户触碰”这件事从偶发事件变成一种有规律的检查项。5. 排查链路用户改完代码后 agent 为什么开始“发疯”5.1 先看现象当 agent 在用户修改代码后表现异常先别急着换模型。你首先要做的是把现象分类。常见的异常大致有几种完全忽略用户改动继续按旧逻辑生成。覆盖用户改动把代码“优化”回旧版本。报错找不着文件或反复执行同一段正确代码。开始修改无关文件偏离任务主线。生成内容与当前工作区完全脱节像是在回答一个不存在的问题。不同现象背后的原因完全不同。比如忽略改动通常是上下文没更新覆盖改动通常是工具链里的编辑逻辑太粗糙反复执行通常是计划状态没有失效处理。5.2 按输入、上下文、计划、工具、环境五层排查我从工程经验里总结出一个排查顺序基本可以覆盖大多数场景。第一层输入。先确认用户改动的代码是否真的进入了 agent 的输入范围。如果 agent 是通过文件路径读取代码那要看它是否访问了最新文件如果它只依赖对话历史里的旧版本内容那再怎么调参数也没用。第二层上下文。检查上下文里有没有包含 diff 信息。很多 agent 支持 tools比如git diff或view_file但它可能没有主动调用。你可以在提示里要求它先查看git diff再复述发生了什么。第三层计划。查看 agent 生成的 plan 是否已经过期。如果一个早期的 plan 仍然把“修改函数 A”作为下一步但函数 A 已经被用户改好了它当然会继续输出冲突代码。这时候应该让 plan 状态失效重新规划。第四层工具。工具链的问题也很常见。比如文件保存时机、语言服务器的索引缓存、终端里旧进程占用端口、测试命令缓存等都会导致 agent 看到旧状态。更隐蔽的是agent 调用write_file时使用“全量覆盖”模式把用户改动一起覆盖掉。第五层环境。最后检查依赖版本、运行权限、模型上下文窗口上限。如果输入太长工具输出可能被截断用户改动的代码可能就在被截断的那部分里。5.3 一个推荐的排查顺序如果出现上述问题我会按这个顺序操作先把 agent 最近的改动暂时撤销回到用户手工修改后的状态。手动运行一次测试确认不借助 agent 时基线是好的。在 prompt 里显式要求 agent 先运行git diff并复述用户改动内容。限制它的编辑范围比如只允许修改指定文件避免泛化覆盖。尝试在小实验里复现如果小实验失败就缩小问题到一个函数。记录完整日志输入、prompt、上下文长度、调用工具顺序、修改文件列表。把这套顺序做成团队内的检查清单比让每个人遇到问题都从零开始猜要高效得多。6. 这类基准会怎样改变编码智能体的演进方向6.1 从“解题正确率”到“协作质量”SWE-Touch 如果真能成为广泛使用的基准最直接的影响是研究者的优化目标会从单一答案正确率转向多轮交互中的稳定性。过去大家更关心 pass1也就是一次生成能不能做对现在更值得关心的是在用户不断参与修改的过程中模型能不能持续保持一致性。这会改变模型训练、prompt 工程和产品设计的方向。比如模型需要更强的 diff 理解能力而不是只理解自然语言指令agent 产品需要更精确的编辑行为而不是每次都大段重写代码评测系统也需要追踪 trace而不是只看最终 patch。6.2 对开源工具链和评测框架的影响一旦交互稳定性变成重要指标相关的工程基础设施会跟着变化。你会需要更细粒度的 agent 运行日志需要能回放每一次工具调用的调试工具也需要能对比不同模型在同一用户修改下的行为差异。从团队选型角度看以后评估编码智能体不能只看它在干净仓库里的表现更要看它在“已经被人改得乱七八糟”的仓库里还能不能维护住正确方向。企业采购或引入开源 agent 时也会把“用户介入后的失败率”当作一个核心指标。6.3 对个人开发者的启示即使是个人开发者短期内也能从这套思路里受益。不用等官方榜单你可以先把自己最常遇到的“人机协作翻车点”沉淀成一个小的测试集。每当你切换模型版本、调整系统提示词或者更换 agent 工具时先跑一遍这个测试集用不了多少时间但能避免在真实项目里踩坑。这些测试集的价值会随着时间积累。一开始可能只有两三个场景三个月后可能覆盖你工作中最典型的二十种改动模式。到那时候你对编码智能体的判断就不需要依赖别人发布的“平均分”而是基于你自己项目里的真实表现。说到底SWE-Touch 真正想回答的问题并不是“哪个模型更能写代码”而是“当你已经动手改过代码之后它还能不能跟上你的思路”。这个问题比任何一个单次通过率都更能决定编码智能体能不能成为你的长期协作伙伴。下次再有人问你这个 agent 好不好用你可以反过来想一下我改一半它能接住吗这或许比所有基准分数都更有意义。