ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI Agent Harness Engineering 在软件开发中的应用:自动编码与 Bug 修复

AI Agent Harness Engineering 在软件开发中的应用:自动编码与 Bug 修复 1. 从一次真实的 Bug 修复说起AI Agent Harness Engineering 到底是什么先说一个我上周遇到的场景。团队里一个跑了半年的订单服务突然在凌晨报KeyError: discount_rule日志只留下一行堆栈复现路径不明。按老办法得先翻代码定位字段来源再查上游数据变更最后写补丁、跑回归——一套下来两三个小时。这次我换了个思路把仓库挂给一个带 Harness 层的 Agent让它自己读堆栈、搜代码、改文件、跑测试我只需要在关键节点点确认。结果 18 分钟出补丁测试全绿。这就是AI Agent Harness Engineering想解决的问题。它不是再训一个更强的模型而是在模型外面搭一层工程骨架把模型调用、工具执行、结果校验三件事编排成一条可观测、可回滚的流水线。你可以把它理解成给大模型配了一个项目经理 质检员 操作台模型负责想Harness 负责让它想得靠谱、做得可查、错了能退。它适合谁三类人最该关注。第一类是中小团队的技术负责人没有资源自建 Agent 平台但想让 AI 真正进 CI 而不是停在聊天框第二类是一线开发天天被重复 Bug 和样板代码消耗想把手动流程自动化第三类是平台/DevOps 工程师需要一套统一入口管理模型 Key、限流、审计。核心检索词就三个AI Agent、Harness Engineering、自动编码与 Bug 修复。为什么单纯调 API 不够因为真实开发任务是多步、有状态、要验证的。你让模型修这个 Bug它可能改错文件、引入新依赖、或者改对了但没跑测试。Harness 层的价值就在于把任务拆成读上下文 → 定位 → 改 → 验证 → 回滚的固定环节每一步都有输入输出记录模型只是其中一个可替换的零件。下面我从落地路径讲起给出能直接抄的配置和验证步骤。2. 前置准备用 TaoToken 统一 Key 与 API 通道让 Harness 只认一个出口搭 Harness 层第一个坑往往不是模型能力而是通道管理。你可能有 OpenAI 的 Key、有 Anthropic 的 Key、有某个国产模型的 KeyHarness 里每接一个工具就要写一套鉴权逻辑改起来要命。我的做法是让 Harness 只面向一个统一的 Base URL 和一个 Key模型切换在网关侧完成。TaoToken 在这里扮演的就是这个统一出口。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 这个不带 UTM配置里就填它。它的作用是把你对多个模型的调用收敛成一套 OpenAI 兼容协议Harness 层不用关心背后是哪个模型。具体怎么接分三步。第一步拿 Key。进控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在 API Keys 页面创建一个新 Key命名建议带上用途比如harness-dev、harness-ci方便后面按环境隔离和审计。创建后立刻复制页面刷新就看不到了。第二步确认模型 ID。不同模型在网关里的标识不一样去模型对话页 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 能看到当前可用的模型列表和对应的 ID 字符串。Harness 配置里的model字段就填这个 ID别自己猜。第三步把 Base URL 和 Key 写进环境变量而不是硬编码。这是 Harness 可回滚的前提——配置和代码分离出问题改环境变量重启即可。# .env 文件不要提交到 git TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_API_KEYsk-你的key HARNESS_MODEL_ID你从模型列表页复制的ID这里有个关键点Harness 层要做的第一件事是通道健康检查而不是直接跑任务。启动时先发一个最小请求确认 Key 有效、模型可达否则整个流水线不该启动。这个检查我放在下一节的配置里。另外提醒一句Key 的权限要最小化。CI 环境用的 Key 和本地开发用的 Key 分开建万一泄露可以单独吊销不影响其他环境。TaoToken 的 API Keys 页面支持多 Key 管理这点对团队协作很实用。3. 可复制配置一份 Harness 层的 Agent 编排模板这一节是全文最该抄的部分。我给出一个JSON 配置 Python 编排骨架的组合路径和字段名都按真实可跑的标准写。核心思路Harness 不直接写业务逻辑它读配置、按阶段调度、记录每步结果。先看配置文件harness.config.json放在项目根目录{ harness_version: 1.0, channel: { base_url: https://taotoken.net/api, api_key_env: TAOTOKEN_API_KEY, model_id: 你从模型列表页复制的ID, timeout_seconds: 60, max_retries: 2 }, pipeline: { stages: [locate, patch, verify, rollback_check], workspace: ./repo, artifact_dir: ./.harness/artifacts, max_iterations: 5 }, tools: { read_file: { enabled: true, max_bytes: 200000 }, search_code: { enabled: true, engine: ripgrep }, apply_patch: { enabled: true, require_confirm: true }, run_tests: { enabled: true, command: python -m pytest -q } }, guardrails: { forbidden_paths: [.git, node_modules, .env], max_files_per_patch: 3, require_test_pass: true } }字段说明几个容易踩坑的。require_confirm: true表示改文件前要人工确认生产环境建议开本地调试可以关。max_files_per_patch: 3是防止模型一次改太多文件导致回滚困难。forbidden_paths必须包含.env否则模型可能把你的 Key 读进上下文。再看编排骨架harness.py这是 Harness 层的核心负责按阶段调度import json, os, subprocess from pathlib import Path from openai import OpenAI class Harness: def __init__(self, config_pathharness.config.json): self.cfg json.loads(Path(config_path).read_text()) ch self.cfg[channel] self.client OpenAI( base_urlch[base_url], api_keyos.environ[ch[api_key_env]], timeoutch[timeout_seconds], ) self.model ch[model_id] self.artifacts Path(self.cfg[pipeline][artifact_dir]) self.artifacts.mkdir(parentsTrue, exist_okTrue) def health_check(self): 通道健康检查失败则整个流水线不启动 resp self.client.chat.completions.create( modelself.model, messages[{role: user, content: reply with OK}], max_tokens5, ) return OK in resp.choices[0].message.content def call_model(self, system, user, stage): 统一模型调用入口记录每次请求到 artifacts resp self.client.chat.completions.create( modelself.model, messages[ {role: system, content: system}, {role: user, content: user}, ], temperature0.2, ) content resp.choices[0].message.content (self.artifacts / f{stage}.json).write_text( json.dumps({stage: stage, output: content}, ensure_asciiFalse, indent2) ) return content def run_stage(self, stage, system, user): 每个阶段独立执行失败可单独重试 print(f[harness] stage{stage} start) out self.call_model(system, user, stage) print(f[harness] stage{stage} done, {len(out)} chars) return out def run_tests(self): cmd self.cfg[tools][run_tests][command] r subprocess.run(cmd, shellTrue, capture_outputTrue, textTrue, cwdself.cfg[pipeline][workspace]) return r.returncode 0, r.stdout r.stderr这份骨架的关键设计是每个 stage 的输出都落盘到artifacts。这样出问题时你能回看模型在定位阶段到底看到了什么、在打补丁阶段生成了什么而不是两眼一抹黑。这就是可观测的落地方式——不是加日志而是把中间产物结构化保存。temperature0.2是刻意调低的。自动编码和 Bug 修复要的是稳定复现不是创意温度高了同一个 Bug 每次改法都不一样没法做回归。4. 验证请求跑通一次自动 Bug 修复的完整流程配置写好了得验证它真能跑。我设计一个最小可复现的 Bug 场景一个计算折扣的函数当discount_rule字段缺失时抛KeyError。你可以在本地建个repo/目录放两个文件。repo/order.pydef calc_price(order): base order[amount] rule order[discount_rule] return base * (1 - rule[rate])repo/test_order.pyfrom order import calc_price def test_calc_price_with_rule(): assert calc_price({amount: 100, discount_rule: {rate: 0.1}}) 90 def test_calc_price_without_rule(): assert calc_price({amount: 100}) 100跑pytest会看到第二个用例失败报KeyError: discount_rule。现在让 Harness 走一遍四阶段流水线。阶段一locate把堆栈和仓库文件列表喂给模型让它输出可疑文件与行号。系统提示词写死只输出 JSON包含 file 和 line 字段。阶段二patch把定位到的文件内容 失败测试喂进去要求输出 unified diff 格式的补丁。这里必须约束输出格式否则模型会给你一段散文。阶段三verifyHarness 应用补丁后自动跑pytest把结果回传。如果失败把失败输出作为新输入回到阶段二最多迭代max_iterations次。阶段四rollback_check如果迭代超限仍失败用git checkout还原所有改动并记录失败原因到 artifacts。调用代码h Harness() assert h.health_check(), 通道不通检查 Key 和 Base URL locate_out h.run_stage( locate, system你是代码定位助手只输出JSON: {\file\:..., \line\:...}, userf堆栈: KeyError: discount_rule\n文件列表: order.py, test_order.py, ) patch_out h.run_stage( patch, system你是补丁生成器只输出 unified diff不要解释, userf定位结果: {locate_out}\n失败测试: test_calc_price_without_rule, ) # 应用补丁生产环境需人工确认 Path(repo/patch.diff).write_text(patch_out) subprocess.run(git apply patch.diff, shellTrue, cwdrepo) ok, log h.run_tests() print(测试通过 if ok else f测试失败:\n{log})实测下来这个场景模型一次就能改对——把order[discount_rule]改成order.get(discount_rule, {rate: 0})。但重点不是它改对了而是每一步都有记录、失败能回滚、测试是硬门槛。你可以打开.harness/artifacts/locate.json看到模型当时的判断依据这在排查为什么它改错了时非常有用。验证成功的标志有三个health_check返回 True、pytest退出码为 0、artifacts目录下四个阶段的 JSON 都存在。缺任何一个说明流水线没跑完整。5. 常见报错排查401、local proxy failed、reading choices、OAuthHarness 层跑起来后报错基本集中在通道和解析两类。我把踩过的坑按真实报错信息列出来。401 Unauthorized / invalid api key九成是 Key 没读到或读错。先确认环境变量名和配置里的api_key_env一致再确认 Key 没有多余空格。如果你用的是 CI检查 Secret 是否注入到了正确的 job。还有一种情况是 Key 被吊销了去 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 看状态。local proxy failed / connection refused这个报错通常出现在你本地配了某个转发工具但没启动。Harness 层不需要任何本地转发base_url直接填https://taotoken.net/api即可。如果你之前为了别的用途设过HTTP_PROXY环境变量记得在跑 Harness 前 unset否则请求会被劫持到不存在的本地端口。Error reading choices / choices KeyError模型返回了非预期结构常见于两种情况。一是model_id填错了网关返回的是错误对象而不是标准 completion二是触发了内容过滤返回体里没有choices字段。排查方法把artifacts里对应阶段的原始响应打出来看别只看异常。修复就是核对模型 ID并给call_model加一层结构校验。OAuth / token expired如果你用的是 Claude Code 或 Codex 这类带 OAuth 的客户端报这个说明登录态过期了。但注意Harness 层走的是 API Key 模式不涉及 OAuth。如果你在 Harness 里嵌了这类客户端要么改用 API Key要么单独维护它的登录态。混用是排查噩梦。这里补一个三件套的完整写法凡是接入类配置都按这个来Base URL Key Model ID缺一不可。# 以 Codex 的 auth.json 风格为例字段名按实际客户端调整 [model_providers.taotoken] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY model 你从模型列表页复制的ID如果你用的是 Cline 或带 MCP 的客户端配置里同样要写全这三项MCP server 的env段里注入 KeybaseUrl填 TaoToken 的 API 地址。CC Switch 这类切换工具也是同理切换的是这三件套的组合不是只换 Key。排障的通用原则先看 artifacts 里的原始请求和响应再看异常信息。异常信息往往只告诉你失败了原始数据才告诉你为什么失败。6. 把 Harness 接进日常从单次修复到可回滚流水线单次跑通只是起点。真正让 AI Agent Harness Engineering 产生价值是把它接进日常开发流。我的做法是三个层次递进。第一层本地预检。在提交前跑一次 Harness 的locate patch让它对改动的文件做一次自检输出潜在问题。这一步不自动改代码只给建议成本低、风险小。第二层CI 里的自动修复。把 Harness 挂到 CI 的失败 job 上测试挂了自动触发定位和补丁生成生成的结果作为 PR 评论贴出来人工确认后再合并。这样既享受了自动化又保留了人工闸门。配置上把require_confirm设为 truemax_files_per_patch压到 2。第三层长期编码与 Agent 编排。当你的 Harness 稳定跑了几十次修复后可以开始让它承担更长的任务链比如根据 issue 描述生成实现 测试 文档。这类长链路对通道稳定性和额度要求更高适合用 Coding Plan 这类面向持续编码的方案入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它的价值在于把模型调用从按次计费变成可持续供给适合 Agent 高频调用的场景。几个实用技巧。给每个 stage 设超时别让一个卡住的请求拖垮整条流水线。artifacts 定期清理不然跑几百次后目录会很大。失败案例单独归档这些是最有价值的训练素材能帮你反推提示词哪里需要收紧。最后说个我自己的判断Harness 层的成熟度不取决于你用了多强的模型而取决于你的校验环节有多硬。测试通过就是通过回滚就是回滚没有中间地带。把这条守住模型换哪个都能用守不住再强的模型也只是个会写代码的赌徒。
返回列表