
“openJiuwen 论文面向长程编码智能体的动态 harness 达到 SWE-bench Verified 82.6%”——很多关注编码智能体Coding Agent方向的开发者最近都看过这个标题。SWE-bench Verified 是目前衡量大模型真实代码修复能力最受认可的基准之一能在这个榜单上做到 82.6%说明这套方案不是简单堆算力而是在“智能体如何与外部工具、测试环境、上下文管理和验证流程交互”这件事上做了系统的工程优化。而这套交互机制就是标题里反复提到的harness。这篇博客会拆开讲三件事第一SWE-bench Verified 到底评估的是什么为什么不能只盯着模型能力第二openJiuwen 提出的“动态 harness”相比传统固定工作流解决了什么核心问题第三这种设计思路能迁移到哪些真实业务场景以及想复现或借鉴这套方案需要准备哪些环境、注意哪些坑。1. 先理解 SWE-bench Verified 在测什么为什么拿高分不容易1.1 SWE-bench 的核心评估机制SWE-bench含 Verified 子集是一个面向真实代码仓库的基准测试集合。它从 GitHub 上大量 Python 开源仓库里收集真实 issue每个问题包含一份 Issue 描述、对应的代码仓库快照以及一组用于验证修复是否正确的测试用例。评估流程可以简化为三个阶段给智能体一份 Issue 描述。智能体在仓库环境中完成代码修改可以调用文件读取、搜索、命令执行等工具。系统在修改后的代码上运行预先准备的测试用例只有通过全部或者指定数量的测试才算修复成功。SWE-bench Verified 是被人工筛选过的子集去掉了描述含糊、测试不稳定、复现困难的样本评估结果更可靠。它的难度主要体现在几个地方问题往往深埋在大型仓库中需要跨文件定位。Issue 描述不一定给出精确复现步骤需要理解业务逻辑。修改代码后不仅要保证目标测试通过还不能破坏已有行为。这四个字连起来的场景是长程 代码任务 工具调用 结果验证每一环都会影响最终分数。1.2 分数模型能力 x 框架能力 x 验证能力传统思路会认为SWE-bench 分数主要看模型本身强不强。实际并不是。面对一个真实仓库的复杂 issue模型必须经历一个很长的决策序列先探索代码结构再定位可疑模块尝试修改运行测试看到失败后再调整。这个序列里的每一环都依赖 harness如何把 Issue 内容转换成智能体的初始上下文。允许智能体执行什么命令读取哪些文件。如何判断一次修改是否值得继续深入而不是盲目重试。最终用哪些测试命令和哪些测试用例来判分。如果把模型看成“大脑”harness 就是“手、眼睛和判断执行结果的神经系统”。同一套模型配不同 harness分数差距会非常明显。openJiuwen 拿到 82.6%很大一部分工作就集中在优化这套神经系统。2. 传统 Harness 为什么成了长程编码智能体的瓶颈2.1 固定式 Harness 的典型工作流目前大多数编码智能体系统harness 采用固定的线性或近似线性流程启动一个沙箱容器拉取代码。给智能体一段 system prompt 和 issue 描述。智能体进入循环读文件、搜索、改文件、执行命令。循环次数达到上限或智能体主动提交后停止。在干净容器里重新应用 patch跑官方测试。这一步本身没有错但它在长任务场景下会暴露出四个问题。2.2 问题一上下文无限膨胀长程任务里智能体要读很多文件、执行很多命令。每一个动作的结果都会拼接进对话历史。当上下文窗口被日志、文件内容、测试输出塞满时智能体对关键信息的感知会变差甚至直接丢失最初的 issue 目标。固定 harness 通常只是简单截断或压缩历史这种方式容易丢失中间发现的关键线索。2.3 问题二工具粒度不匹配一个真实仓库中直接让智能体去读整个文件可能消耗大量 token而且低效。人类开发者定位问题时会先用 grep、git blame、测试套件结果来缩小范围再精读局部代码。传统 harness 如果没有内置这类“检索-精读”机制智能体会浪费大量动作在无关文件上。2.4 问题三验证反馈不及时固定 harness 通常在智能体提交 patch 后才执行全套测试。如果测试运行时间很长智能体要等很久才知道改错了而且错误信息往往堆在一个巨大的输出里智能体很难定位。2.5 问题四策略固定无法适配问题类型有些 issue 适合先写复现测试再改代码有些 issue 适合先搜索所有相关调用点改完再统一验证有些 issue 则只需要修一个配置项。固定 harness 对所有问题都用同一套流程天然不是最优策略。openJiuwen 的“动态 harness”核心就是针对这四类问题做设计。3. 动态 Harness 的设计核心让智能体参与工作流决策3.1 从静态工具链到动态执行策略动态 harness 的核心思路是不再把所有工具、所有上下文、所有验证方式在开始时一次性固定下来而是根据任务进展、中间结果和失败原因在运行过程中动态调整智能体的工作方式。它主要解决四个关键决策点上下文管理策略动态化当对话历史过长时harness 不是简单丢弃旧信息而是把关键结论提炼成结构化记忆例如“已经确认崩溃发生在 StorageService 的 load 方法原因是 NullPointerException”。工具暴露范围动态化前期提供更宽松的探索工具例如全局搜索、git 历史查询、测试过滤定位到具体模块后再让智能体集中精读局部文件和运行局部测试。验证策略动态化如果某个修改可能只影响一个子模块harness 会先运行该模块的快速测试通过后再运行全量回归。这种方式把验证反馈从“分钟级”压缩到“秒级”。策略切换动态化当智能体在某条路径上反复失败时harness 会提示或强制切换思路比如从“直接改代码”切换到“先写最小复现测试”或者从“修改实现”切换到“修改调用方”。3.2 动态 Harness 的抽象工作流程下面用一个简化的流程描述动态 harness 的执行模型。1. 任务输入阶段 - 接收 issue 描述 - 解析仓库结构识别语言、构建工具、测试框架 - 生成初始工作区 2. 规划阶段 - 根据 issue 生成候选探索策略 - 按类型分配策略优先级是否需要复现测试 - 初始化结构化任务记忆 3. 执行-反馈循环 - 智能体选择一个动作搜索、读文件、写文件、执行命令 - 动作结果进入解析器抽取出结构化的反馈摘要 - 摘要写入任务记忆原始输出按需截断保存 - 根据反馈判断是否需要切换策略 - 重复直到提交 patch 4. 验证阶段 - 对最终 patch 做静态检查 - 运行最小相关测试集 - 运行全量测试集 - 输出分数和失败原因这段流程里最关键的差异在第 3 步动态 harness 不是为了“记录”动作而是为了“理解”动作结果并基于理解调整后续流程。3.3 动态记忆的结构化设计结构化的任务记忆是动态 harness 的基础设施。它通常包含以下几类信息记忆类型内容示例作用任务目标Issue 希望修复的错误现象防止智能体在长链路中偏离问题关键线索崩溃栈顶、错误关键字、相关方法名支撑后续检索和定位已验证事实某测试在修改前已失败避免重复验证提高动作有效性未验证假设怀疑某个配置字段导致问题指导下一步实验策略状态当前处于“复现-修复-回归”哪个阶段支撑动态切换判断有了这套记忆智能体即使上下文窗口有限也能随时回看最关键的中间结论而不是靠长对话里的模糊印象。4. 落地一个简化版动态 Harness环境准备与最小实现4.1 环境准备想在自己的项目里复现或验证这套思路不需要完整复制 openJiuwen 论文里的系统。下面给出一套可运行的最小组件方案用于理解动态 harness 的骨架。推荐环境组件推荐选择说明语言Python 3.11生态成熟适合编写 Agent 编排代码代码智能体框架LangGraph 或自研状态机负责管理执行循环与状态迁移沙箱Docker隔离代码执行环境代码检索ripgrep / tree-sitter快速定位符号、调用关系测试命令pytest作为验证反馈来源模型 API支持 function calling 的模型保证智能体能按结构化方式选择工具首次运行前建议在 Linux 或 macOS 环境操作Windows 需要处理 Docker 和 shell 兼容问题。4.2 定义工具集合先定义一个简化工具集合。动态 harness 和普通 Agent 最大的区别在于工具不只是被调用它们的结果还会被结构化解析。# tools.py import subprocess import json from dataclasses import dataclass dataclass class ToolResult: status: str # success / error summary: str # 结构化摘要 raw_output: str # 原始输出 metadata: dict # 额外信息如耗时、退出码 def run_shell(command: str, cwd: str, timeout: int 30) - ToolResult: 执行 shell 命令并结构化返回结果 try: proc subprocess.run( command, shellTrue, cwdcwd, capture_outputTrue, textTrue, timeouttimeout, ) summary_lines proc.stdout.strip().split(\n) return ToolResult( statussuccess, summaryfexit_code{proc.returncode}, output_lines{len(summary_lines)}, last_line{summary_lines[-1] if summary_lines else }, raw_outputproc.stdout proc.stderr, metadata{exit_code: proc.returncode}, ) except subprocess.TimeoutExpired as exc: return ToolResult( statuserror, summaryfcommand timeout after {timeout}s, raw_outputstr(exc), metadata{timeout: True}, ) def grep_symbol(pattern: str, repo_path: str) - ToolResult: 用 ripgrep 搜索符号并返回文件-行号-代码片段摘要 cmd frg -n {pattern} {repo_path} result run_shell(cmd, repo_path) # 进一步解析输出把匹配行整理成结构化片段 snippets [] for line in result.raw_output.splitlines()[:50]: snippets.append(line) result.summary ffound {len(snippets)} matches result.metadata[snippets] snippets return result关键点在于ToolResult的summary字段。它不保存完整长文本只保存可支持决策的摘要。在长任务里智能体看到的不是 2000 行测试日志而是一句“有 15 个测试失败其中 3 个集中在 storage.py”。4.3 实现动态上下文管理动态 harness 的第二个核心组件是上下文管理器。它维护上面提到的任务记忆并负责决定哪些信息进入模型上下文。# memory.py class TaskMemory: def __init__(self): self.goal self.findings [] # 结构化的已验证事实 self.hypotheses [] # 未验证假设 self.strategy explore # 当前策略: explore/fix/verify self.command_history [] def add_finding(self, text: str, source: str): self.findings.append({text: text, source: source, verified: False}) # 控制最多保留最新 20 条关键结论 self.findings self.findings[-20:] def switch_strategy(self, new_strategy: str): 根据执行反馈动态切换策略 old self.strategy self.strategy new_strategy return fstrategy switched from {old} to {new_strategy} def compact_history(self, full_history: list, max_items: int 6) - list: 将完整动作历史压缩为最近 摘要形式。 这是动态 harness 与固定 context 窗口的主要区别。 recent full_history[-max_items:] compact_prompt ( 以下是截至目前的已确认事实\n \n.join(f- {f[text]} for f in self.findings) \n\n以下是最近的执行历史更早的历史已压缩\n ) return compact_prompt, recent当对话历史超出 Window 限制时harness 不是简单删除旧消息而是把旧消息中已经提炼进findings的结论保留下来再配合最近的原始历史一起送入模型。这样既控制 token 成本又不会丢失关键中间结论。4.4 实现动态验证动态验证是这套 harness 对得分提升最直接的贡献。它让智能体可以在提交最终 patch 前用低成本测试快速试错。# verifier.py import pytest def select_quick_tests(repo_path: str, changed_files: list) - list: 根据修改文件与测试文件的对应关系选择最小相关测试集。 这里用简单的文件路径包含关系模拟实际项目可用覆盖率数据或调用图。 quick_tests [] for changed in changed_files: module_base changed.split(/)[-1].replace(.py, ) # 简化映射假设 test_module.py 是相关测试 test_file ftest_{module_base}.py quick_tests.append(test_file) # 去重并限制数量 return list(set(quick_tests))[:5] def run_tests(repo_path: str, tests: list) - dict: 运行 pytest 并返回结构化结果 if not tests: return {passed: 0, failed: 0, message: no quick tests matched} result {} cmd [pytest, -q] tests # 这里省略实际 subprocess 调用代码 return result这个模块在生产系统里会做得更精细对 Python 项目可以用pytest --collect-only收集用例再用覆盖率工具或静态调用分析建立“文件改动影响哪些测试”的映射。只要能比全量测试更快就能大幅提升智能体的试错效率。4.5 动态策略切换的判定规则动态 harness 的“动态”体现在策略切换上。一个简单的判定规则如下def decide_strategy(memory: TaskMemory, last_result: ToolResult) - str: 根据最近一次工具结果和记忆状态决定下一步策略。 返回 explore / reproduce / fix / verify 之一。 # 如果还没有定位到根本原因且探索轮次已经很多先切到复现模式 if memory.strategy explore and len(memory.command_history) 8: if len(memory.hypotheses) 0: return reproduce # 如果已经找到可疑代码并做了修改但测试仍然失败切回修复模式 if memory.strategy verify and last_result.status error: return fix # 如果已经完成修改切到验证模式 if memory.strategy fix: return verify # 默认继续探索 return memory.strategy这只是最简策略。真实论文中的策略切换会参考更多信号比如测试失败增量、修改文件数量、循环次数、错误类型等。但核心逻辑一致让执行路径不是预先写死的而是由中间结果动态生成。5. 动态 Harness 的关键参数与优化方向5.1 需要重点调优的参数参数含义默认参考值调大影响调小影响max_steps单任务最大执行步数40-60更多探索空间成本上升容易探索不足history_window最近原始历史保留条数6-10 条上下文更完整token 成本上升丢失近期细节findings_limit结构化记忆最大条数15-30 条结论覆盖广容易信息过载关键结论可能被挤出quick_test_threshold快速测试最大数量5-10 个反馈更充分耗时上升反馈不充分max_retry_same_strategy同策略最大连续失败次数3 次更耐心尝试过早切换策略调优建议先固定模型和 max_steps单独调 history_window观察修复成功率变化再调 findings_limit找一个能覆盖关键线索又不撑爆上下文的值。不要同时调太多参数否则无法定位是哪一项带来的提升。5.2 动态 Harness 对模型能力的依赖边界动态 harness 能提升分数的前提是模型具备基本的长程推理和工具调用能力。如果模型连“读完文件后判断下一处代码位置”这种基础能力都不具备harness 再动态也补不上。参考能力分界模型每次工具调用都能正确理解结果成功率 90% 以上动态 harness 收益明显主要体现在减少无效动作和更早发现问题。模型经常误解命令行输出、无法理解测试失败原因动态 harness 只能解决上下文管理和策略切换无法根治模型理解缺陷。对于第二类情况应该优先换更强模型或者做更细粒度的输出解析而不是继续堆 harness 复杂度。6. 运行验证用最小 Demo 观察动态行为6.1 准备一个故意设坑的最小仓库为了验证动态 harness 是否真的在运行可以准备一个故意带 bug 的小项目。这个项目不要大但要包含跨文件定位的要素。demo_repo/ ├── main.py ├── services/ │ ├── __init__.py │ └── order.py └── tests/ ├── __init__.py └── test_order.pyorder.py中故意引入一个错误某个函数引用了不存在的参数名或者错误地使用了None。# services/order.py def calculate_total(price, quantity, discount_rate0.1): # 故意写错应该是 discount_rate * price写成 discount_rate * quantity discount discount_rate * quantity return price * quantity - discounttest_order.py中写一个期望discount discount_rate * price的测试用例。# tests/test_order.py def test_calculate_total(): from services.order import calculate_total assert calculate_total(100, 3, 0.1) 270 # 正确是 100*3 - 100*3*0.1 270把 discount 计算改成discount discount_rate * quantity后quantity3, price100时折扣是 0.3 元总价变成 299.7测试失败。这个问题需要智能体看到测试期望和实现不一致才能定位。6.2 观察动态策略切换运行一个简化 Agent 循环在日志里打印decide_strategy的输出。预期会看到策略序列[1] strategyexplore, actiongrep_symbol(discount_rate) [2] strategyexplore, actionread_file(order.py) [3] strategyreproduce, actionrun_shell(pytest tests/test_order.py -q) [4] strategyfix, actionedit_file(order.py, line 5) [5] strategyverify, actionrun_shell(pytest tests/test_order.py -q)如果日志显示智能体第一轮修改后没有立刻验证还在反复搜索说明策略切换逻辑太保守如果还没定位到问题就进入 fix 阶段说明策略切换太激进。两种都要调阈值。6.3 验证三项关键结果一个合格的动态 harness 运行结束后应该能验证三件事验证项判断标准是否复现原始问题初始测试确实失败是否定位到根因修改位置与测试失败点逻辑一致是否通过回归修改后相关测试全部通过且没有破坏其它测试如果这三项都满足说明动态 harness 的“探索-复现-修复-验证”闭环已经跑通。7. 常见问题与排错路径7.1 上下文压缩后智能体“失忆”现象任务中途智能体不再引用早期发现而是反复搜索同一处代码。排查步骤检查 findings 中是否记录了初始 issue 目标。检查 compact_history 是否把早期关键结论截掉了。检查模型是否只看到了 recent history而最近的 recent 里又没有关键结论。处理建议在 compact 提示词中固定保留“任务目标”和“最近 3 条已验证事实”这两个字段不允许被压缩掉。7.2 策略切换过于频繁现象智能体在 explore 和 fix 之间来回跳动作碎片化严重。可能原因失败重试次数设置过小。工具返回的 summary 信息不足以支撑“确定根因”的判断。处理建议增加max_retry_same_strategy到 4-5 次同时检查 tool result 的 summary 是否真的包含足够的失败原因比如是否解析了 pytest 的断言错误行。7.3 快速测试结果与全量测试不一致现象快速测试通过但全量测试失败。可能原因文件到测试的映射关系过于粗糙。改动对其它模块产生了间接影响没有覆盖到。处理建议先用静态分析建立更完整的“文件影响测试”关系快速测试只用于中间过程提交前的全量回归绝不能省略。7.4 工具调用超时被误判为失败现象某些命令比如全量测试、安装依赖执行时间远超 timeout被 harness 判定为错误导致错误策略切换。处理建议不要让“超时”和“逻辑失败”共用同一个 status。建议在 metadata 中区分error_typetimeout/assertion/infra策略切换逻辑要忽略 timeout只对 assertion 失败做反应。7.5 动态 Harness 在真实业务中的适配要点场景适配建议自研代码库先用文件路径映射建立快速测试表再逐步引入覆盖率优化旧系统改造优先做探索工具和上下文管理策略切换先保守生产环境缺陷修复动态 harness 只建议在预发环境试跑经验证后再自动执行算法题/竞赛题动态 harness 优势不明显因为问题规模小、验证即时8. 从 82.6% 到工程落地下一步该怎么练openJiuwen 的 82.6% 不是一篇论文的终点而是给工程社区留下的一个重要信号编码智能体的上限不只是模型参数的堆积更是工程编排能力的体现。如果你想亲手验证这条路推荐按三个阶段推进。8.1 阶段一复现固定 Harness 基线先不要上动态策略把最朴素的探索-修改-验证循环跑通。这一步的目标是稳定获得一个基线分数。工具不复杂一个 Docker 容器、一个支持 function calling 的模型、一套 sysprompt 和测试脚本。8.2 阶段二加结构化记忆与上下文压缩在固定 harness 上只做一项改动引入结构化 findings把每个工具结果压缩成摘要。观察两个指标每任务平均 token 消耗是否下降修复成功率是否稳定。不要同时改工具、策略和记忆否则无法判断哪个改动有效。8.3 阶段三加动态策略切换在记忆机制稳定后再加入策略切换。先做最简单的二态切换探索 8 轮后如果还没有复现问题强制切到复现模式复现成功后再进入修复模式。等二态切换稳定后再扩展三态、四态。这三个阶段走完你就能理解 openJiuwen 论文里最核心的工程价值它不是给模型灌更多规则而是给智能体一套能在长任务中保持目标感、控制上下文成本、快速获得验证反馈的执行框架。8.4 论文复现时最需要保存的中间数据如果你打算写实验总结或继续做研究以下数据一定要在每次运行后落盘每个任务的完整动作轨迹。每次工具调用的 summary 和原始输出。策略切换时间和原因。最终 patch 与 diff。快速测试与全量测试结果对比。有了这些数据你才能复盘智能体在哪一步浪费了动作在哪一步漏掉了关键线索也才能在下一个版本里做有针对性的优化。动态 harness 会是未来编码智能体工程化的核心拼图之一。它不降低对模型能力的要求但能把同一条模型能力变成更高的任务成功率、更少的 token 消耗和更稳定的执行过程。站在工程角度这比单纯追逐下一个更大参数的模型更有复利价值。