SWE-Touch:用户改过代码后,AI编程助手还能继续干活吗? 平时用 AI 编程助手改代码时我经常陷入一种很尴尬的流程Agent 改到一半我会忍不住自己上手微调几行逻辑比如改个参数默认值、补一个边界判断或者把函数签名调整一下。结果再让 Agent 继续干活时它就像短暂失忆了一样要么重复生成已经被我改掉的代码要么在我刚改过的地方继续“叠床架屋”。这种“用户中途触摸代码”的协作场景在真实开发里非常常见但在主流 Coding Agent 评测体系里却长期缺位。SWE-Touch 这个基准测试Benchmark正是冲着这个问题来的当用户已经亲手改过代码之后编码智能体还能不能保持正确的理解和判断本文会围绕 SWE-Touch 的评测思想展开先讲清楚它和传统编码智能体评测的差异再拆解真实协作中的挑战最后用一个最小可运行的 Python 示例演示一套简化版评测闭环。适合正在做 Coding Agent 应用开发、或者准备给团队接入 AI 编程助手的后端开发者阅读。1. 背景与核心概念从 SWE-bench 到 SWE-Touch1.1 编码智能体评测的主流范式先来回顾一下 Coding Agent 评测的主流做法。以大家熟悉的 SWE-bench 类基准测试为例它的评测流程大致是这样的给定一个真实 GitHub Issue再给一个完整代码仓库的固定快照让编码智能体独立完成问题定位、代码修复、生成补丁最后用仓库自带的测试集验证补丁是否让相关用例通过。这种“Issue → Patch → Test”的闭环设计优点是清晰、可复现、可横向比较。不同 Agent 面对同样的任务最后看通过率就能分出高下因此它很快成为编码智能体领域最常用的评测范式。但它隐含了一个很强的前提假设Agent 是在一份“静止的、无人打扰的代码”上工作的。任务一开始仓库状态就是最终状态Agent 只需要从零开始理解这份代码然后独立完成修改不需要考虑别人是不是已经动过代码。这个假设在大规模评测时是合理的因为它保证了所有 Agent 面对完全相同的起点。但放到真实开发环境里这个假设经常不成立。1.2 用户触摸代码真实协作中被低估的变量现实中的 AI 辅助编程从来不是“Agent 独自完成全部工作”的孤岛模式而是一种高度频繁的人机协作。用户会根据自己对业务逻辑的理解随时插入到代码修改过程中。常见的有三种情况用户先改Agent 后做用户已经手动实现了一部分功能剩下的交给 Agent 补齐。Agent 做到一半用户插进来Agent 正在生成代码或补丁的过程中用户自己改了相关文件Agent 需要基于新的状态继续。Agent 改完用户 reivew 后又改Agent 产出了修复补丁用户 review 时手动调整了实现方式或 API 名称后续 Agent 还要继续维护。这三种情况里代码状态已经不是“初始快照”而是被用户动过的“中间状态”。用户对代码的每一次修改都可能是新增约束、调整接口、修复一部分 bug也可能无意中留下新的问题。SWE-Touch 这个名字里“Touch”指的就是用户亲手触摸、修改代码这个动作。它把这类场景纳入了基准测试的核心设计考察 Agent 在用户已改过代码之后是否还能正确感知变更、理解用户意图并在此基础上继续高质量地完成编码任务。1.3 SWE-Touch 的核心评测视角从评测方法论上看SWE-Touch 与传统基准测试最大的区别在于它不再只关注“Agent 能否独立从零生成正确补丁”而是关注“Agent 能否在一个已经被用户修改过的代码状态下继续完成剩余工作”。这听起来只是一点任务构造差异实际上会引出一系列更复杂的评测维度变更感知Agent 能不能主动发现用户改过哪些文件而不是两眼一抹黑地基于旧理解输出代码。意图对齐用户手动改代码往往带有明确的业务意图Agent 能不能从改动中反推这些意图并保持对齐。冲突处理Agent 要补充的实现会不会和用户已经写好的部分产生冲突会不会把用户刚写的代码“反向改回去”。回归判断用户改过之后原本能通过的测试是否仍然安全Agent 有没有能力在不破坏用户修改的前提下完成剩余工作。换句话说SWE-Touch 想评测的不是“Agent 的代码能力”而是“Agent 在真实协作场景中的可持续工作能力”。2. 现实场景中的协作模式与挑战2.1 三种典型的用户触摸模式为了把问题讲清楚我们可以把用户触摸代码的行为归纳成三种典型模式。模式发生时机用户行为Agent 面临的典型任务先手触摸Agent 开始工作之前用户已手动改好一部分代码留下 TODO 或半成品理解已有改动补齐剩余逻辑中途插入Agent 工作过程中用户直接修改了 Agent 正在处理的文件重新读取最新状态避免重复或冲突后置修改Agent 产出补丁之后用户 review 并手动调整了 Agent 的改动基于新改动继续迭代不能回退用户调整在传统评测里这三种模式基本没有体现。任务一开始仓库就是“干净”的Agent 不会意识到中途会有人插手也不需要理解“用户意图”这种偏主观的变量。2.2 用户修改给 Agent 带来的四类困难当用户真的摸过代码之后Agent 拿到的不再是一个单纯的技术问题而是一个混合了“代码理解问题”和“协作对齐问题”的复杂任务。第一类是信息过时。真实项目里用户可能直接编辑文件也可能通过 IDE 重构、批量替换等方式改了多个文件。Agent 如果只依赖刚才上下文里的代码片段而不是重新读取当前文件内容就会基于过时信息生成代码。结果是代码合并后出现重复定义、接口错位甚至语法错误。第二类是隐含约束。用户手动改代码往往不是随便改的背后通常有业务约定。比如把某个参数默认值从False改成True可能意味着后续所有调用方都希望走四舍五入逻辑。Agent 如果看不见这个改动背后的意图就很难写出符合预期的实现。第三类是目标漂移。用户中途插入修改可能让原始任务的边界发生变化。比如原本只是让 Agent 修一个计算 bug用户顺手把函数签名改了Agent 再继续“修 bug”时必须先把签名调整考虑进去否则所有修法都是白做。第四类是变更回退风险。最糟糕的不是 Agent 不会改而是 Agent 生成的补丁把用户刚写好的代码又覆盖回去了。这种问题在自动化评测里很难自动发现因为测试可能照样通过但用户实际体验是灾难性的。2.3 为什么传统 benchmark 无法覆盖这些情况传统基准测试之所以没有覆盖这些情况根因在于它把“任务”定义得太线性了。任务只有一个起点、一个终点Agent 从头走到尾即可。真实开发中任务更像是“状态流”初始仓库状态 → 用户手动修改 → Agent 继续修改 → 用户 review 修改 → Agent 再次修改。每一步都可能产生新的状态Agent 必须随时响应状态变化。此外传统评测的判定标准通常只有“测试是否通过”它不太关心 Agent 是否破坏了用户已有的修改。SWE-Touch 这类基准测试的出现本质上是在推动评测标准从“结果正确性”转向“协作正确性”让 Benchmarking 更贴近真实工程实践。3. 环境准备与最小评测框架搭建理解了背景之后我们来动手搭一个最小评测框架。这个框架会模拟 SWE-Touch 的核心思路仓库处于“用户触摸后”的中间状态Agent 需要感知这个状态并完成剩余开发任务。3.1 运行环境建议本文的示例以常见的 Python 环境演示重点讲解评测闭环的设计思路不依赖特定云服务或复杂基础设施。需要注意具体版本需要根据你的项目实际情况调整。建议准备Python 3.10 或更高版本pytest 测试框架git 命令行工具一个终端或 IDE 内置终端。3.2 项目目录结构我们先创建一个名为swetouch-demo的目录模拟一个最小仓库。mkdir -p swetouch-demo/app swetouch-demo/tests cd swetouch-demo python -m venv .venv source .venv/bin/activate pip install pytest git initWindows 环境下虚拟环境激活命令稍有不同需要改为.venv\Scripts\activate最终目录结构如下swetouch-demo/ ├── app/ │ ├── __init__.py │ └── pricing.py ├── tests/ │ └── test_pricing.py └── eval_runner.py3.3 准备一个最小的示例仓库为了让示例足够聚焦我们模拟一个电商场景中的折扣计算函数。业务目标很简单给定商品原价和折扣比例计算折后价并支持一个“是否四舍五入到分”的开关。先创建app/__init__.py内容可以留空只是为了把app变成可导入的 Python 包touch app/__init__.py现在准备“用户触摸之后”的代码状态。4. 核心原理如何构造 SWE-Touch 风格评测任务在写代码之前先理解评测任务是怎么构造的。SWE-Touch 风格的评测任务本质上是一个带“中间状态”的状态机。4.1 任务状态流我们可以把一次评测任务拆成四个阶段初始仓库Start → 用户手动修改User Touch → Agent 生成补丁Agent Patch → 运行测试验证Test Result第一阶段是初始仓库对应传统基准里的原始代码状态。第二阶段会模拟用户对代码的手动修改这是 SWE-Touch 任务最核心的部分。第三阶段让 Agent 基于用户修改后的状态继续工作。第四阶段用测试集验证最终结果。需要特别强调的是用户手动修改不是简单地在代码里“埋一个 bug”而是模拟真实协作中的部分实现、接口调整或约束新增。用户的改动本身可能是有意义的开发进度Agent 不能无视它。4.2 评测指标设计在 SWE-Touch 风格的评测里指标设计比传统测试通过率更丰富一些。通常可以关注以下四类指标第一测试通过率。这是最基础的指标决定 Agent 的补丁是否让任务功能上正确。第二用户变更保持率。Agent 生成的补丁是否保留用户手动修改的部分有没有出现“把用户代码改回去”的情况。第三迭代效率。Agent 是花了一步就理解了用户改动还是反复生成大量无效补丁后才摸清状态。第四变更定位能力。Agent 能否准确识别用户改过的文件而不是在无关文件里做无用功。在本文的最小示例中我们主要以测试通过率作为可验证指标其余指标可以在真实评测平台中扩展实现。4.3 构造任务时的注意事项构造这类评测任务时有几个细节容易踩坑。一是用户修改不能太随意。用户的改动要有合理性比如补充了部分参数校验、预留了接口而不是毫无逻辑地删代码。二是测试用例要区分“原有约束”和“用户新增约束”。最好用注释或显式标记说明哪些测试是用户触摸之后新增的这样 Agent 能更清楚用户改了什么。三是必须提供显式的“当前状态”。真实开发中用户改了代码一般会留下工作区变更Agent 可以通过git diff感知差异。评测框架也应该把这种感知能力纳入考量。5. 模拟实战用 Python 实现一个简化版 SWE-Touch接下来进入完整实战环节。我们会手动构建一个“用户触摸后”的代码状态并写一个评测脚本模拟 Agent 从当前状态继续完成任务的完整流程。5.1 定义“用户已触摸”的代码状态先创建app/pricing.py。这个文件是用户手动修改后的版本也是 Agent 开始工作前看到的起点。# 文件路径swetouch-demo/app/pricing.py # 当前状态用户手动修改后的版本Agent 看到的起点 def calculate_discount(price: float, discount: float, round_result: bool True) - float: 计算折后价格。 参数说明 price : 商品原价必须大于等于 0 discount : 折扣比例范围 0 ~ 100 round_result : 是否将最终结果四舍五入到两位小数 if price 0: raise ValueError(price 不能为负数) if discount 0 or discount 100: raise ValueError(discount 必须在 [0, 100] 区间) result price * (1 - discount / 100) # TODO(agent): 请根据 round_result 参数决定是否对结果四舍五入 # 用户已经完成了参数校验和基础折扣计算剩余逻辑由 Agent 补充。 return result注意这个代码是“半成品”。用户已经完成了参数校验和基础折扣计算但round_result参数还没有生效。Agent 的任务就是读取这个函数理解用户已经完成的部分然后补齐剩余逻辑。这里面没有埋所谓的低质量 bug反而更贴近真实协作用户做了一部分剩下的交给 Agent。5.2 加入用户补充的测试用例接着创建测试文件tests/test_pricing.py。其中前两个用例是原有约束后两个用例是用户触摸后新增的约束。# 文件路径swetouch-demo/tests/test_pricing.py import pytest from app.pricing import calculate_discount def test_normal_discount(): 基础折扣场景。 assert calculate_discount(100, 20) 80.0 assert calculate_discount(100, 0) 100.0 def test_full_discount(): 100% 折扣时价格应为 0。 assert calculate_discount(100, 100) 0.0 def test_round_result_true(): 用户补充用例默认对结果四舍五入到分。 assert calculate_discount(99.99, 10, round_resultTrue) 89.99 def test_round_result_false(): 用户补充用例关闭四舍五入时保留原始精度。 assert calculate_discount(99.99, 10, round_resultFalse) 89.991这里有两个非常关键的细节。第一test_round_result_true和test_round_result_false是用户触摸之后新增的用例它们明确了用户对round_result参数的约束。第二如果 Agent 没有感知到用户已经新增了这些约束直接把函数按旧逻辑写死就无法通过全部测试。5.3 编写评测脚本接下来创建eval_runner.py这是整个评测闭环的入口。它会模拟一个 benchmark 系统应用 Agent 提交的补丁然后运行测试集根据结果判定任务是否成功。# 文件路径swetouch-demo/eval_runner.py 简化版 SWE-Touch 评测脚本。 它演示了 benchmark 的核心闭环 1. 仓库处于“用户触摸后”的中间状态 2. Agent 提交一个补丁文件 3. 评测系统应用补丁并运行测试 4. 根据测试结果判定任务是否成功。 import argparse import subprocess from pathlib import Path REPO_DIR Path(__file__).resolve().parent TEST_CMD [python, -m, pytest, tests/, -q] def apply_patch(patch_path: Path) - None: 把 Agent 输出的 patch 应用到仓库。 result subprocess.run( [git, apply, str(patch_path)], cwdREPO_DIR, capture_outputTrue, textTrue, ) if result.returncode ! 0: raise RuntimeError( f应用 patch 失败stderr:\n{result.stderr} ) print(f 已应用 patch: {patch_path.name}) def run_tests() - bool: 运行单元测试返回是否全部通过。 result subprocess.run( TEST_CMD, cwdREPO_DIR, capture_outputTrue, textTrue, ) print(result.stdout) if result.stderr: print(result.stderr) return result.returncode 0 def main() - None: parser argparse.ArgumentParser(descriptionSWE-Touch 简化评测脚本) parser.add_argument( --patch, typePath, defaultPath(agent.patch), helpAgent 生成的 patch 文件默认使用当前目录下的 agent.patch ) args parser.parse_args() if not args.patch.exists(): raise FileNotFoundError(f找不到 patch 文件: {args.patch}) print( 步骤 1: 应用 Agent patch) apply_patch(args.patch) print( 步骤 2: 运行测试集) passed run_tests() print(f 任务结果: {PASSED if passed else FAILED}) if not passed: raise SystemExit(1) if __name__ __main__: main()这个脚本虽然简单但已经具备了一个 benchmark 评测器的基本骨架接收补丁、应用补丁、执行验证、输出结果。真实评测平台会在此基础上增加沙箱隔离、超时控制、多任务批量执行等能力。5.4 运行与验证先不应用任何补丁直接运行测试能够看到当前“用户触摸后”的状态并不能通过全部用例。cd swetouch-demo python -m pytest tests/ -q预期输出大概是这样..FF FAILURES ___________ test_round_result_true ____________ ... ___________ test_round_result_false ____________ ... 2 failed, 2 passed in 0.05s两个原有用例通过两个用户新增用例失败。这说明 Agent 必须继续工作补齐round_result的处理逻辑。现在模拟 Agent 的工作成果。创建一个补丁文件agent.patchdiff --git a/app/pricing.py b/app/pricing.py --- a/app/pricing.py b/app/pricing.py -13,6 13,8 def calculate_discount(price: float, discount: float, round_result: bool True) result price * (1 - discount / 100) - # TODO(agent): 请根据 round_result 参数决定是否对结果四舍五入 - # 用户已经完成了参数校验和基础折扣计算剩余逻辑由 Agent 补充。 - return result if round_result: result round(result, 2) return result然后运行评测脚本python eval_runner.py --patch agent.patch预期输出 步骤 1: 应用 Agent patch 已应用 patch: agent.patch 步骤 2: 运行测试集 .... [100%] 4 passed in 0.02s 任务结果: PASSED到这里一个简化版的 SWE-Touch 评测闭环就跑通了。5.5 从模拟到真实 Benchmark需要提醒的是上面这个示例是教学级模拟目的是帮助你理解 SWE-Touch 的评测思想。真实的 SWE-Touch 基准测试会复杂得多主要体现在几个方面。任务规模更大。真实基准会准备大量真实仓库、真实 Issue 和真实用户修改形成完整的任务集而不是单独一个函数。用户修改更贴近真实历史。真实用户修改可能涉及多个文件、重构、注释调整、测试补充等Agent 需要依赖工具感知变更而不只是读一个文件。评测流程更工程化。包括 Docker 沙箱、资源限制、超时控制、防止 Agent 作弊、统一补丁校验、多轮交互日志记录等。不过把最小闭环跑通之后再去阅读真实基准的评测代码和任务构造逻辑会轻松很多。6. 常见问题与排查思路在搭建和运行这类评测闭环时比较容易遇到一些共性问题。这里整理成一份排查清单。问题现象常见原因解决思路应用 patch 失败报patch does not apply仓库状态和 patch 基准不一致或 Agent 基于旧状态生成补丁确认仓库处于用户触摸后的状态要求 Agent 先查看git diff再生成补丁测试结果不稳定同一补丁时而过时而不通过测试用例存在随机性或依赖外部服务在评测逻辑中固定随机种子、隔离网络、使用沙箱环境Agent 生成的补丁把用户修改覆盖了Agent 没有感知用户改动基于旧代码上下文输出在提示词中强制 Agent 先读取当前文件再输出补丁评测时增加“用户变更保持率”指标评测时仓库状态被污染上一次测试的补丁没有回滚在评测脚本执行前重置仓库回到“用户触摸后”的状态不同 Agent 结果无法横向对比评测基准不统一、测试集不一致固定同一份 task 集和测试集统一超时和资源限制Agent 反复尝试但一直不通过用户新增约束没有被 Agent 理解检查用户改动是否足够清晰真实场景中可要求 Agent 先输出对用户改动的理解在这类问题里最容易被忽视的是“仓库状态被污染”。尤其是本地手工实验时上一次git apply的补丁如果没回滚下一次评测结果就会失真。建议在评测脚本里增加一个 reset 步骤每次都从干净的“用户触摸状态”出发。7. 最佳实践与工程建议7.1 对 Coding Agent 开发者的建议如果你在开发自己的 Coding AgentSWE-Touch 的核心思想可以直接落到产品设计里。让 Agent 具备“先读差异再动手”的习惯。当 Agent 进入一个仓库时首先应该执行git diff、git status之类的能力明确当前工作区有哪些用户改动再基于最新状态规划修改方案。给 Agent 提供“用户改动摘要”的接口。对于已有的代码改动可以通过工具或者预处理的变更摘要把用户修改的文件、函数、约束条件注入到上下文中。这能显著降低 Agent 对用户意图的误解。在评测链路中加入“用户改动保持检查”。简单做法是在评测脚本中先保存用户改动文件的内容摘要Agent 输出补丁后检查这些文件的核心改动是否仍然存在。如果被 Agent 反向回退即便测试通过也应判定为失败或降权。7.2 对 Benchmark 使用者的建议如果你正在用 SWE-Touch 或类似基准评估编码智能体建议不要只看整体通过率重点关注 Agent 在“用户触摸后”的稳定性。具体来说可以按维度拆分统计用户先手修改场景下的通过率、Agent 中途被插入修改时的通过率、Agent 修改后用户再 review 的通过率。三种场景的难度和风险完全不同混在一起看容易掩盖问题。同时尽量让 Agent 在评测中拥有与真实开发一致的工具权限。如果 Agent 没有读取git diff的通道那么在 SWE-Touch 任务里天然处于劣势这种劣势不能完全代表模型能力。7.3 对将 Agent 落地到真实项目的团队对真实项目团队来说SWE-Touch 提醒我们的其实是工程协作设计问题。团队在引入 AI 编程助手时应该为“人机协作改码”设定清晰的秩序。一方面尽量让 AI 和用户的改动范围解耦。比如约定 AI 优先生成新文件或新增函数用户手工维护核心业务逻辑减少同一区域的直接冲突。另一方面建立代码变更的强制 review 机制。Agent 产生的 diff必须经过git diff检视后再入库不要让 Agent 直接提交。这样即使 Agent 基于过时信息输出了补丁也能在合并之前被拦截。在配置 Agent 的权限时遵循最小权限原则也是必要的。不要让 Agent 直接改动 git 历史、强制推送或批量替换文件所有高风险操作都应该限制在测试环境或者经过人工确认后执行。8. 总结与下一步学习方向这篇文章从一个真实协作痛点出发介绍了 SWE-Touch 这种基准测试的核心思想编码智能体不应该只会在干净仓库里完成 Issue 修复更应该能在用户已经触摸过代码之后继续稳定工作。我们搭建了一个最小可运行的评测闭环模拟了“用户手动修改代码 → Agent 继续补齐逻辑 → 测试验证结果”的完整流程。虽然示例规模很小但评测框架的四个核心阶段——初始状态、用户触摸、Agent 补丁、测试验证——已经完整呈现。接下来如果你对这个方向感兴趣可以沿着两条线继续深入。一条是在真实任务集上跑 SWE-Touch观察不同 Coding Agent 在用户修改场景下的稳定性差异另一条是改进自己的 Agent 产品让它具备“感知变更、尊重用户改动、规避冲突”的协作能力。最后留一个实践题目给你在这个示例仓库里如果用户触摸后的代码不是留下 TODO而是把round_result的处理逻辑写反了Agent 应该怎样才能在不破坏用户意图的前提下完成任务建议自己动手跑一遍会很有收获。如果你的工作流里也经常出现“AI 改到一半、你又手动改了几行”的情况欢迎在评论区分享你的场景和踩坑经历。