ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

SWE-Touch:当用户“触碰”代码,AI编程助手还能干完活吗?

SWE-Touch:当用户“触碰”代码,AI编程助手还能干完活吗? 先丢一个真实场景你正在用 Claude Code、Codex、OpenCode 这类 AI 编程助手改代码。它在终端里不停输出 diff你一边看一遍皱眉——中间忍不住打断它“这个变量名别改”“这里逻辑不对”“先等等我自己补两行”。然后你手动改了文件再让它继续。这段听起来很普通的开发过程恰恰是现在绝大多数 coding agent 评测基准没有覆盖的盲区。SWE-Touch 这篇工作要研究的问题就是当用户在 Agent 干活的过程中“触碰”代码时Agent 还能不能保持高质量地完成任务。它和现有基准最大的区别是把评测从“让 Agent 独自进考场”变成了“让 Agent 和用户坐在同一张工位上协作”。这篇文章我会先讲清楚 SWE-Touch 到底在测什么再从推演的角度分析它的评测设计最后给出一套最小化的“用户触碰”评测流程帮助你在本地验证自己常用的 coding agent 是否具备应对真实交互场景的能力。1. SWE-Touch 到底在测什么1.1 一个被忽略的真实场景先做一个简单对比。绝大多数 coding agent 基准的评测方式是给 Agent 一段 issue 描述让它自己读仓库、定位问题、生成补丁最后跑测试看通过率。整个过程像一个“封闭考试”——题目发下来Agent 独立答题交卷后判分。但真实开发完全不是这样。真实开发中用户会做很多基准测试没有考虑的动作中途打断 Agent要求换一种实现方案。自己手动改掉 Agent 刚生成的部分代码。在 Agent 阅读代码的间隙往文件里添加注释或新函数。对 Agent 的中间产物提出修改意见。甚至会在 Agent 生成完补丁后自己又补了几个测试用例。这些动作都属于“用户触碰代码”。SWE-Touch 从标题来看正是把这种“被用户触碰过的工作区”作为评测的起点和过程变量。换句话说SWE-bench 这类基准回答的是“Agent 能不能独立修好一个 issue”而 SWE-Touch 回答的是“Agent 能不能在用户一直在改代码的情况下仍然把活干完”。1.2 从问题到判断评测范式切换我读完标题和可用背景材料后最核心的判断是SWE-Touch 并不是又一个“刷分榜单”而是把 coding agent 评测从“单机模式”切换到“联机模式”。为什么这个切换很重要因为当前很多 coding agent 的能力展示都是在“没有用户干预”的理想条件下得到的。可一旦用户真正上场Agent 面对的工作区是动态变化的它之前读过的文件可能已经被用户改了它准备修改的函数可能已经被用户重写了它以为的“目标代码”可能已经不存在了。这时Agent 会表现出三类典型问题上下文过期Agent 拿着旧的工作区快照做决策改出来的补丁和用户最新代码冲突。意图分裂User touch 引入了新约束Agent 没有把用户意图和原始 issue 合并理解导致只解决了其中一半。覆盖用户改动Agent 按照旧计划执行把用户手动补充的代码又改回去了。SWE-Touch 的意义在于它把这些过去被 benchmark 忽略的失败模式正式变成了可评测、可量化的指标。2. 从 SWE-bench 到 SWE-TouchCoding Agent 评测范式的变化2.1 先理解 SWE-bench 的思路要理解 SWE-Touch必须先理解 SWE-bench 的评测范式。SWE-bench 是软件工程领域很有代表性的 benchmark。它从真实开源仓库中收集 issue让模型在给定的 base commit 上生成修复补丁然后用仓库自带的测试用例来判分。如果一个补丁能让相关测试从失败变通过就算答对。这套设计的优点是客观、可复现、贴近真实代码。它把 AI 编程任务的评估从“聊天式问答”推进到了“真实代码修复”是 coding agent 评测的重要基础。但它也带着一个很强的前提假设Agent 是任务唯一的执行者用户全程不参与代码修改。这个假设对科研评测来说很干净但对真实工程来说并不成立。实际开发中代码库永远处于“被人类编辑”的状态。Agent 不是在空白的工位上做题而是进入一个随时可能被用户改动的活跃工作区。2.2 SWE-Touch 的“Touch”指什么从命名看SWE-Touch 延续了 SWE-bench 的命名风格而 Touch 这个单词带有双重含义。第一层含义是物理动作用户“触碰”代码即在代码上进行手动修改、插入注释、补充测试、重构局部实现等操作。第二层含义是状态提示被触碰后的代码和 Agent 最初看到的代码已经不同了。Agent 必须感知到这种变化并据此调整后续动作。如果把 SWE-bench 比作“闭卷考试”那么 SWE-Touch 更像“开卷考试而且试卷会在答题过程中被考官不断改题”。2.3 一张表对比两种评测下表对比的是两类评测范式的核心差异具体实现细节可能因版本而异但代表了设计思路的关键转变。对比维度SWE-bench 类基准SWE-Touch 类交互式基准任务形态单轮给 issue输出最终补丁多轮工作区随用户触碰动态变化用户角色不在场不干预在场可能随时修改代码评测重点最终补丁能否通过测试面临用户修改后是否保持正确并保留用户意图上下文状态静态Agent 读取的内容相对稳定动态Agent 读取的内容可能已经过期典型失败模式没修好 issue修好了 issue但覆盖了用户的手改代码这份对比揭示了一个关键问题过去我们评测的是 Agent 的“代码能力”SWE-Touch 试图评测的是 Agent 的“协作能力”。这两种能力并不等价。3. SWE-Touch 的评测设计分析与推断由于公开材料有限这一节我会基于标题、SWE-bench 已知设计思路以及 coding agent 现有评测实践做合理推断。以下内容不是论文原始实现而是帮助理解评测思路的框架。3.1 可能的用户触碰类型从真实开发场景出发用户触碰代码的方式可以归纳为几类评论式触碰用户在 Agent 工作过程中追加文字说明比如“这个异常只发生在 session 过期之后”“不要改动认证模块以外的部分”。这类触碰不改变代码但改变了任务约束。局部修改式触碰用户手动修改某个文件的部分代码比如补齐判空、调整变量名、重写某个分支逻辑。这类触碰直接改变工作区Agent 必须基于新代码继续工作。新增测试式触碰用户添加新的测试用例或修改测试配置。这会改变“通过”的定义Agent 需要关注新测试带来的约束。重构式触碰用户对代码结构进行较大调整例如抽取函数、改变类名、移动文件。这类触碰对 Agent 的上下文同步能力要求最高。撤销式触碰用户把 Agent 刚生成的补丁整体或部分撤销要求 Agent 换一种方案重新实现。这五类触碰的“破坏力”是递增的。评论式触碰最容易处理因为它不改代码重构式触碰最难处理因为它会同时破坏 Agent 对代码结构和语义的理解。3.2 评测流程从静态到动态传统 SWE-bench 的评测流程是线性的读取 issue → 读取仓库 → 生成补丁 → 运行测试 → 判定通过/失败SWE-Touch 类基准的评测流程更像是带分支的循环读取 issue → 读取仓库 → Agent 开始工作 → 在某个 step 注入用户触碰 → 用户触碰改变工作区 → Agent 继续工作 → 再次注入触碰 → ... → 运行测试 → 判定通过/失败 → 额外检查用户改动是否被保留这里最核心的变化是“注入时机”。用户触碰不是随机发生的而是和 Agent 的进度相关。比如在 Agent 刚读完文件时注入评论、在 Agent 生成第一版补丁后注入修改这些不同时机会产生完全不同的效果。更复杂的评测还可能设置“触碰的回声”用户修改过某段代码Agent 后续生成补丁时如果又改了这一区域就会被判定为“覆盖用户改动”即使最终测试通过也要扣分。3.3 评测指标会有什么变化传统基准最常用的是 pass1、passk 这类指标只看最终补丁是否通过测试。SWE-Touch 类基准需要增加几类指标才能刻画交互能力用户意图保持率最终代码中用户手动新增或修改的内容是否仍然存在。触碰感知率用户触碰发生后Agent 是否在后续步骤中主动提及或适应了这种变化。回归破坏率Agent 在修复过程中是否引入了新的失败测试。协作效率完成同一任务有用户触碰和无用户触碰时步数和 token 消耗的差异。这些指标组合起来才能回答一个完整的问题Agent 在用户触碰代码的干扰下是变得更快了还是被带偏了。4. 为什么这类基准对开发者真正重要4.1 谁最应该关注 SWE-Touch从实际收益来看以下几类读者最应该关注 SWE-Touch 这类工作第一类是正在把 coding agent 引入日常开发的个人开发者。如果你只是让 Agent 做一些“一次性问答”式的任务基准差异对你的影响不大。但如果你像我一样习惯让 Agent 直接改本地仓库代码那么它的“触碰鲁棒性”就直接决定了你的体验。第二类是在团队里推动 AI 辅助开发的工程负责人。引入 coding agent 不是装一个 CLI 那么简单而是要把它嵌入到团队的代码评审、CI/CD 和协作流程里。你需要知道当团队成员在 Agent 干活时手动改了文件Agent 会不会把同事的修复“顶掉”。第三类是研究 LLM Agent 评测方向的学生和研究者。SWE-Touch 提供了一个研究“交互式代码生成评测”的切口。反过来说如果你完全不用 coding agent或者只是拿 Agent 问概念问题那这篇工作的实际价值就不大。它不是给“AI 聊天玩具”做的基准而是给“AI 写代码同事”做的压力测试。4.2 它解决的真实痛点很多人在使用 coding agent 时有一个隐约的感受为什么 Agent 单独做题时很厉害一放进我的真实项目就频繁翻车过去我们很难把这个感受讲清楚。你可以怀疑是自己的 prompt 写得不好也可以怀疑是模型版本不够新但很难定位到“评测范式”这个层面。SWE-Touch 指出了一条新的解释路径现有基准没有覆盖“用户触碰”这个关键变量所以 Agent 的交互能力一直是被高估的。在典型开源 benchmark 上分数很高的模型遇到用户手改代码后可能仍然表现出非常幼稚的行为。比如明明用户已经在文件顶部添加了一条注释说明实现方向Agent 还是会按照旧计划把相关代码全部重写。这个痛点的本质是“评测维度与使用场景错配”。SWE-Touch 试图把评测维度拉回到真实使用场景这是一个该被认真对待的方向。4.3 不要神化 benchmark 分数这里也需要泼一点冷水。任何一个 benchmark 都有边界SWE-Touch 也不例外。它模拟的“用户触碰”再多也不可能覆盖真实协作中的人类情感、沟通语气、隐性知识等因素。比如用户说“这里有点问题”真实人类同事能根据上下文、语气、项目背景判断出具体指哪里但 Agent 只能从字面理解。这类“只能意会”的协作信号是任何 benchmark 都难以完全构造的。所以SWE-Touch 的价值不是给出一个“最终答案”而是提供一个更接近真实的“模拟考试”。它能帮你筛掉那些“考试型选手”但它不能替你判断哪个 Agent 最适合你的团队。5. 环境准备与前置条件看完概念分析后我们进入实践环节。为了让你理解 SWE-Touch 的评测思路我会构造一个最小化的“用户触碰”评测流程。它不是 SWE-Touch 的官方实现而是帮助你跑通思想的最小示例。5.1 本地评测需要什么运行下面的示例你需要准备以下环境Python 3.10 或更高版本。Git用于管理被测仓库的版本状态。一个可调用的 coding agent CLI例如 Claude Code、Codex、OpenCode 或 Kimi Code。如果使用云端模型 API需要提前配置好对应的认证环境变量。测试仓库建议使用小型项目避免大仓库导致的上下文超长和调试困难。版本方面不需要太纠结示例代码使用标准库和通用 CLI 调用方式基本不依赖特定版本。如果你的 Agent CLI 命令名不同替换agent_cmd即可。5.2 安全提醒评测也要守边界在开始前必须强调评测 coding agent 时它可能会执行命令、修改文件。请始终在隔离的测试仓库中进行不要直接指向生产代码。权限方面遵循最小权限原则。给 Agent 配置的 API key 应该只具备必要的模型调用权限不要使用拥有云平台管理权限的高危凭证。评测代码如果涉及 API key建议通过环境变量注入并确认它没有被提交到 Git 仓库。6. 动手复现一个最小化的“用户触碰”评测流程6.1 第一步定义评测任务格式SWE-Touch 类评测的核心是“任务描述 用户触碰序列”。下面是一个 JSON 定义示例展示了如何描述一次带有用户触碰的评测任务。// 文件路径/tmp/swe-touch-demo/task.json { task_id: demo-001, repo_path: /tmp/swe-touch-demo/repo, agent_cmd: claude-code, problem_statement: 修复登录接口在 session 过期后偶发空指针的问题不要改动认证模块之外的代码, expected_patch: /tmp/swe-touch-demo/expected_patch.diff, user_touches: [ { step: 0, type: comment, content: 注意空指针只在 session 过期之后出现先做判空再取值 }, { step: 2, type: partial_edit, file: src/main/java/com/example/AuthService.java, content: 在 getUserProfile 方法中补充 Optional 判空逻辑你只需要处理异常分支 } ] }这里需要解释几个字段的含义step表示在第几步注入用户触碰。第 0 步意味着任务刚开始就追加了评论。type用户触碰类型示例中定义了comment和partial_edit两种。filecontent描述用户手动修改了哪个文件、改了什么内容。expected_patch最终补丁的正确参考用于判断 Agent 是否修好了 issue。6.2 第二步编写评测 Harness下面是一个 Python 评测脚本的核心逻辑。它模拟了“在 Agent 工作过程中注入用户触碰然后检查结果”的流程。# 文件路径/tmp/swe-touch-demo/eval_harness.py import json import subprocess import sys from pathlib import Path def apply_user_touch(touch, repo_path): 根据用户触碰定义在指定 step 前修改工作区。 touch_type touch[type] if touch_type partial_edit: file_path Path(repo_path) / touch[file] if not file_path.exists(): raise FileNotFoundError(f用户要修改的文件不存在: {file_path}) # 简化处理在文件末尾追加用户意图标记模拟手动改动 with file_path.open(a, encodingutf-8) as f: f.write(f\n# USER_TOUCH: {touch[content]}\n) print(f[harness] step{touch[step]} 注入用户修改: {touch[file]}) elif touch_type comment: print(f[harness] step{touch[step]} 注入用户评论: {touch[content]}) else: print(f[harness] step{touch[step]} 未知触碰类型: {touch_type}) def run_agent(agent_cmd, repo_path, problem_statement): 调用外部 coding agent CLI这里只做最小封装。 # 实际使用时你可能需要根据 CLI 的具体参数调整 cmd [agent_cmd, --repo, repo_path, --prompt, problem_statement] result subprocess.run(cmd, capture_outputTrue, textTrue, timeout600) return result.stdout def evaluate(repo_path, expected_patch): 判断最终补丁是否命中预期以及用户改动是否被保留。 diff subprocess.run( [git, diff], cwdrepo_path, capture_outputTrue, textTrue ).stdout expected Path(expected_patch).read_text(encodingutf-8).strip() user_marks subprocess.run( [git, grep, -n, USER_TOUCH], cwdrepo_path, capture_outputTrue, textTrue ).stdout return { passes_expected_patch: expected in diff, keeps_user_touch: USER_TOUCH in user_marks, diff_length: len(diff), } def main(): task_file sys.argv[1] task json.loads(Path(task_file).read_text(encodingutf-8)) print(f[task] {task[task_id]}: {task[problem_statement]}) for touch in task[user_touches]: apply_user_touch(touch, task[repo_path]) output run_agent(task[agent_cmd], task[repo_path], task[problem_statement]) print(output) report evaluate(task[repo_path], task[expected_patch]) print(f[result] {report}) if __name__ __main__: main()这个脚本只做了最简化的事情先把用户触碰应用到工作区再让 Agent 去解决一个带额外约束的 issue最后检查两个点——修复是否命中预期以及用户触碰的标记是否被保留。在实际项目中你会希望把“触碰”放在 Agent 执行过程中的不同 step而不是全部放在最开始。这需要 agent CLI 支持交互回调或者你在调用 Agent 和检查结果之间多次交替执行。这里给出的是基础骨架便于理解。6.3 第三步运行评测脚本确定被测仓库的基线状态后执行下面的命令。# 进入评测目录 cd /tmp/swe-touch-demo # 准备被测仓库假设 repo 目录已经存在并且处于干净的基线状态 git clone your-repo /tmp/swe-touch-demo/repo # 准备预期补丁 cp expected_patch.diff /tmp/swe-touch-demo/ # 运行评测 python eval_harness.py /tmp/swe-touch-demo/task.json如果一切正常你会看到类似下面的输出结构。[task] demo-001: 修复登录接口在 session 过期后偶发空指针... [harness] step0 注入用户评论: 注意空指针只在 session 过期之后出现... [harness] step2 注入用户修改: src/main/java/com/example/AuthService.java [agent] 正在分析代码... [agent] 已生成补丁变更 3 个文件 [result] {passes_expected_patch: True, keeps_user_touch: True, diff_length: 420}6.4 关键逻辑解释这里的passes_expected_patch检查的是最终补丁是否与预期修复一致。keeps_user_touch检查的是用户在文件中留下的USER_TOUCH标记是否仍然存在。为什么用标记文件来检查因为在真实场景中用户手写的代码不会自动带着“这是用户写的”这样的标记。所以在最小示例里我用追加注释的方式模拟用户改动并把这个注释作为“用户意图保留”的代理指标。实际评测 SWE-Touch 时会做更精细的处理比如通过 diff 行号定位用户的修改区域检查 Agent 的最终补丁是否触碰了这些区域。但核心思想是一致的既要看 Agent 有没有完成任务也要看它有没有破坏用户已有的修改。7. 运行结果与效果验证7.1 如何判断评测是否有效拿到输出后你需要分三步判断。第一步看passes_expected_patch是否为 True。如果为 False说明 Agent 没有正确解决 issue这是最直接的失败。第二步看keeps_user_touch是否为 True。如果为 False说明 Agent 虽然可能修好了 issue但把用户手动添加的代码或注释覆盖了。在真实项目中这种“好心办坏事”同样危险。第三步看diff_length。一个过大的 diff 往往意味着 Agent 做了大量无关修改。你可以继续执行下面的命令检查改动范围。# 查看改动的文件列表和统计 git diff --stat # 查看关键文件的具体改动 git diff src/main/java/com/example/AuthService.java # 查看评测过程中的提交记录 git log --oneline -5从上面的命令中你应该能看到 Agent 到底动了哪些文件。如果它修改了用户明确要求不要动的模块即使测试通过这种修改也需要被标记为风险行为。7.2 如果失败第一步应该看哪里评测运行失败时按顺序排查往往最有效率。第一优先看 stderr。我的示例脚本把 Agent 的 stdout 打印出来但很多 CLI 会把错误信息写到 stderr。你可以在run_agent函数中补充打印result.stderr或者直接修改命令行加上--verbose参数。第二优先看工作区状态。Agent 执行完已经退出但工作区保留着最后的文件状态。在评测目录里手动执行git status和git diff --stat可以快速判断问题出在“Agent 没干活”还是“Agent 干了太多的活”。第三优先看用户触碰是否真的生效。如果apply_user_touch匹配的文件路径不对FileNotFoundError会直接中断脚本。这通常说明你的user_touches定义和仓库实际路径不一致需要调整 JSON 配置。8. 常见问题与排查思路在评测和实际使用 coding agent 的过程中有一批问题出现频率很高。这里整理成表格方便你直接对照排查。问题现象可能原因排查方式解决方案Agent 把我手动改的代码又改回去了Agent 上下文过期没有感知到用户改动查看 Agent 日志中实际读取的文件版本用户修改后用 git commit 保存基线或在 prompt 中明确告知“不要改动某区域”Agent 单轮任务分数高交互式评测分数低评测维度不同交互场景暴露了上下文同步短板对比不同 user_touch 类型下的得分差异针对特定触碰类型调整 prompt增加约束文件本地评测结果每次不一样模型非确定性或多轮状态污染固定 seed重复运行多次增加重试采样按多次结果取统计值Agent 生成大量无关 diff缺少操作边界约束执行 git diff --stat 查看改动范围在 AGENTS.md 或 CLAUDE.md 中明确文件白名单和禁止区域脚本报 API 认证错误环境变量未配置或密钥过期检查进程环境变量配置正确的 API key使用最小权限绝不要提交到 git评测时 Agent 读取不到用户修改用户的修改发生在 Agent 读取文件之后调整触碰注入时机将部分触碰放在 Agent 执行中间步而不是全部放在任务开始前这些问题的共同点是多数不是因为模型“不会写代码”而是因为模型“没有协作意识”。SWE-Touch 类基准最擅长暴露的就是这一类问题。9. 工程实践建议让人机协作真正落地9.1 把用户触碰显式化在真实项目中用户不要默默修改代码然后期待 Agent 自己发现。更稳妥的做法是每次手动修改后用 git commit 提交一个基线或者在给 Agent 的下一轮 prompt 中主动说明“我在某个文件里改了某个函数”。显式化的好处是减少 Agent 的猜测成本。Agent 不需要从 diff 中推断用户意图而是直接收到明确的指令。这是提升人机协作效率成本最低的方式。9.2 给 Agent 划定操作边界使用 coding agent 时最好通过项目级约束文件限制它的操作范围。很多 agent CLI 支持类似AGENTS.md这样的规则文件你可以在里面写清楚哪些目录是 Agent 可以修改的。哪些文件只读不允许改动。哪些操作必须先向用户确认。测试命令和代码风格约定。设置操作边界不是“限制 Agent 能力”而是“减少误伤概率”。一个不知道边界在哪的 Agent在用户触碰代码后容易把不该动的地方也改了。9.3 把交互鲁棒性纳入选型标准当你评估一个 coding agent 是否适合团队时不要只看它在公开 benchmark 上的分数更要看它在“用户触碰场景”下的表现。你可以用本文的最小示例把几个候选 Agent 在相同任务、相同用户触碰序列下跑一遍。重点关注两点用户改动保留率以及新增回归失败率。这两个指标能更真实地反映“团队里实际用的效果”。9.4 安全与权限的最小化让 Agent 直接操作代码库会带来新的安全风险。工程上建议遵循几个原则API key 使用最小权限并通过环境变量注入不写入代码仓库。评测和生产环境隔离Agent 执行命令前先确认目标仓库路径。重要变更先让 Agent 生成补丁由人工 review 后再应用而不是让 Agent 直接构建、发布。操作可回滚每次 Agent 执行前后都保留 git 基线。SWE-Touch 这类基准评测的是能力而工程落地还需要配套的安全和协作机制。只有把能力和机制结合起来coding agent 才真正值得进入生产环境。9.5 团队协作的流程建议最后给团队一个简单的流程建议。当多人同时在一个仓库里使用 coding agent 时建议约定以下规则一个时间点只能有一个 Agent 在工作区执行写操作。Agent 开始工作前先确认当前工作区是干净的或已提交到临时分支。用户手动修改代码时优先通过提交新 commit 而不是修改 Agent 正在操作的未提交内容。每次 Agent 完成任务后运行全量测试并人工 review diff 中是否包含非预期改动。这套规则可以显著降低“用户触碰”与“Agent 修改”之间的冲突概率让协作更接近理想状态。回到开头的问题。下次你在评估某个 coding agent 时别只问它的 benchmark 分数有多高要问一个更实际的问题当我自己也在改代码随时会打断它、纠正它、推翻它的时候它还能不能把活干完这才是 SWE-Touch 这类交互式基准真正想回答的问题也是 AI 编程助手走向真实工程协作所必须迈过的一道门槛。如果你正在设计自己的 agent 评测流程建议直接参考本文的最小示例把用户触碰纳入评测维度。这样的评估结果才更接近你真正会在日常开发中感受到的体验。
返回列表