☰
AI Agent Harness Engineering 实战:用 Devin 思路搭建可复现的软件开发工作流
2026/9/26 10:23:53 网站建设 项目流程

1. 为什么“会写代码”不等于“能交付”:我踩过的 Agent 工作流坑

AI Agent 在软件开发里的讨论,最近几乎被 Devin 式演示刷屏:读需求、拆任务、开终端、跑测试、提 PR,看起来像一个能独立干活的实习生。但真正把 AI Agent 接进日常开发后,你会发现一个尴尬的事实——模型能写出漂亮的函数,却经常在“任务边界、工具调用顺序、结果校验”这三件事上翻车。Harness Engineering 要解决的正是这个问题:它不是让模型更聪明,而是给 Agent 套上一副“工程约束框架”,让它的每一步都可观测、可复现、可回滚。

我试过让一个 Agent 直接改一个 FastAPI 项目:它先删了requirements.txt里的alembic,又自己写了个create_all建表脚本,最后跑测试时因为数据库迁移状态不一致直接卡死。问题不在模型能力,而在于我没有给它定义“允许改哪些文件、必须按什么顺序调用工具、什么算任务完成”。这就是 Harness 的价值:把 Devin 演示里那些看起来自然的动作,拆成可配置的规则和检查点。

这篇内容适合三类人:正在用 Cursor / Claude Code / 自建 Agent 做开发的工程师;想把“AI 写代码”升级成“AI 交付功能”的团队;以及被 Agent 乱改代码、乱装依赖折磨过的朋友。下面我会给出可复制的 Agent 配置骨架(settings.json/config.toml),并用 TaoToken 统一 Key 通道接入模型,最后跑一轮端到端验证,让你在本地复现一个可观测、可回滚的 Agent 开发流程。

2. TaoToken 前置:统一 Key 与 API 通道,让 Agent 配置不再散落

Harness Engineering 的第一原则是“配置集中”。如果 Agent 的模型调用散落在.env、IDE 插件、终端脚本里,你根本无法复现一次失败的任务。我的做法是把所有模型请求收敛到一个统一通道:TaoToken。它提供兼容 OpenAI 风格的 API,Agent 的settings.json和config.toml只需要指向同一个base_url,换模型时改一个字段即可。

官网入口在这里:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,注册后在控制台创建 Key。API 根地址是 https://taotoken.net/api ,注意这个地址不带任何查询参数,Agent 配置里直接写它。

你需要提前准备三样东西:一个 TaoToken API Key、一个本地 Git 仓库(建议新建一个空仓库做实验)、以及 Python 3.11+ 和 Node 18+ 环境。Key 的创建入口在控制台的 API Keys 页面:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。拿到 Key 后不要写进代码,放进系统环境变量:

export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

注意:环境变量名建议统一用TAOTOKEN_前缀,这样 Agent 的多个工具(终端、IDE 插件、测试脚本)都能读到同一份配置,避免出现“IDE 里能跑、终端里 401”的经典问题。

如果你只是想先验证模型通道是否通,可以直接用模型对话页面发一条消息:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。确认返回正常后,再进入下面的 Agent 配置环节。长期做编码和 Agent 任务的话,Coding Plan 会更划算,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。

3. 可复制的 Agent 配置骨架:settings.json 与 config.toml

Harness 的核心是把“任务拆解、工具调用、结果校验”写成声明式配置。下面这套骨架我用了几个月,结构上分三层:模型通道、工具白名单、校验钩子。先看settings.json,它负责 Agent 的运行时行为:

{ "agent": { "name": "harness-dev-agent", "max_steps": 40, "task_decomposition": { "enabled": true, "max_subtasks": 12, "require_plan_approval": false }, "tools": { "allow": ["read_file", "write_file", "run_shell", "run_tests", "git_diff"], "deny": ["rm_rf", "curl_external", "pip_install_global"], "shell_timeout_sec": 120 }, "checkpoints": { "before_write": ["git_stash_snapshot"], "after_step": ["run_lint", "git_diff_summary"], "on_failure": ["rollback_to_snapshot"] } }, "model": { "provider": "openai-compatible", "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "model": "claude-sonnet-4-20250514", "temperature": 0.2, "max_tokens": 8192 } }

几个关键点值得展开。max_steps是硬约束,防止 Agent 陷入无限循环;tools.deny里我特意禁掉了全局 pip 安装和外部 curl,因为这两类操作最容易污染环境且难以回滚;checkpoints.before_write会在每次写文件前自动打一个 git stash 快照,出问题一条命令就能回退。

再看config.toml,它负责工具链和校验规则,和settings.json配合使用:

[workspace] root = "." ignore = [".git", "node_modules", "__pycache__", ".venv"] [validation] lint_cmd = "ruff check ." test_cmd = "pytest -q --maxfail=1" typecheck_cmd = "mypy app --ignore-missing-imports" require_all_pass = true [validation.retry] max_retries = 2 backoff_sec = 3 [observability] log_dir = ".agent/logs" trace_file = ".agent/trace.jsonl" record_tool_calls = true [rollback] strategy = "git_stash" snapshot_prefix = "agent-snapshot"

require_all_pass = true是 Harness 里最有用的一条:Agent 不能自己说“我改完了”,必须 lint、test、typecheck 全绿才算完成。trace_file会把每次工具调用和模型输出写成 JSONL,方便事后复盘。rollback.strategy用 git stash 而不是硬重置,保留现场的同时能快速恢复。

提示:如果你的项目用pnpm或uv,把lint_cmd/test_cmd换成对应命令即可,Harness 不绑定具体工具链,只要求命令有明确的退出码。

4. 端到端验证:从任务下发到结果校验跑一轮

配置写好后,用一个真实小任务验证整条链路。我在空仓库里放了一个有 bug 的 FastAPI 接口:/users/{id}在用户不存在时返回 500 而不是 404。任务描述直接写进task.md:

# Task 修复 GET /users/{id} 在用户不存在时返回 500 的问题。 要求: 1. 不存在时返回 404,body 为 {"detail": "user not found"} 2. 补充一个 pytest 用例覆盖该场景 3. 不得修改数据库 schema

启动 Agent 的命令如下,注意--config同时加载两个配置文件:

python -m harness_agent run \ --task task.md \ --settings settings.json \ --config config.toml \ --workspace . \ --dry-run false

Agent 的执行链路会按 Harness 规则展开:先读task.md并拆成 3 个子任务(定位接口、修改逻辑、补测试),然后调用read_file读取路由文件,调用write_file修改异常处理,调用run_tests执行 pytest。每一步之后都会触发after_step里的 lint 和 diff 摘要。实测下来,一次成功的运行日志大致长这样:

[step 1] read_file app/routes/users.py -> ok [step 2] plan: 3 subtasks generated [step 3] write_file app/routes/users.py -> snapshot agent-snapshot-001 [step 4] run_shell ruff check . -> exit 0 [step 5] run_tests pytest -q -> 4 passed [step 6] git_diff_summary -> 2 files changed, +18 -3 [step 7] validation: lint=pass test=pass typecheck=pass [result] task completed, trace saved to .agent/trace.jsonl

验证是否真的修好了,不要只看 Agent 的结论,自己跑一遍:

pytest -q curl -s http://127.0.0.1:8000/users/9999 | jq .

预期返回{"detail": "user not found"}且 HTTP 状态码为 404。如果 Agent 中途失败,Harness 会按on_failure触发回滚,你可以用git stash list看到快照,用git stash apply stash@{0}恢复现场。这一步是 Harness 和普通“让 AI 改代码”最大的区别:失败不是灾难,而是一次可回放的实验。

5. 本篇常见错排查:401、工具越权与校验假通过

第一个高频问题是 401。Agent 报AuthenticationError时,先确认TAOTOKEN_API_KEY在当前 shell 里可见:echo $TAOTOKEN_API_KEY | head -c 8。如果 IDE 里正常、终端里失败,多半是环境变量没继承。另一个常见原因是base_url写成了带路径的地址,正确写法是https://taotoken.net/api,不要在后面拼/v1或加查询参数。

第二个问题是工具越权。Agent 试图执行pip install或访问外部网络时会被tools.deny拦截,日志里会出现tool_denied。这不是 bug,而是 Harness 在保护你的环境。如果确实需要装依赖,正确做法是把它写进任务的前置条件,由你手动执行,而不是放开 Agent 的权限。

第三个问题最隐蔽:校验假通过。有些项目的pytest在没有测试文件时也会返回 0,导致 Agent 误以为测试通过。解决办法是在config.toml里加一条test_cmd = "pytest -q --maxfail=1 --co -q && pytest -q",或者直接在 CI 里要求测试数量大于 0。Harness 的require_all_pass只认退出码,所以命令本身必须足够严格。

第四个问题是回滚失败。如果git_stash_snapshot报not a git repository,说明工作目录没有初始化 git。Harness 的快照依赖 git,所以实验前务必git init && git add -A && git commit -m "baseline"。没有 baseline,回滚就无从谈起。

6. 把 Harness 接进你的日常:从模型对话到 Coding Plan

跑通上面这一轮后,你会得到一个可观测、可回滚的 Agent 开发流程。接下来可以按需扩展:把settings.json里的model换成更强的模型做复杂重构,或者把validation接到 CI 上,让 Agent 的每次提交都自动过一遍流水线。模型通道始终走 TaoToken,换模型只改一个字段,不用重新配 Key。

如果你还在选模型阶段,可以先用模型对话页面快速对比不同模型在同一个任务上的表现:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。确认模型后,把 Key 和base_url填进settings.json即可。接入文档里有完整的参数说明和示例:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。

长期做编码和 Agent 任务的话,Coding Plan 比按量调用更稳定,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。如果你用的是 Claude Code 这类终端 Agent,可以参考 Anthropic 兼容接入说明:https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claude_code&utm_campaign=rewrite ,把ANTHROPIC_BASE_URL指向 TaoToken 的 API 地址即可复用同一套 Key。

最后留一个我自己的习惯:每次 Agent 任务结束后,翻一遍.agent/trace.jsonl,看看它在哪一步犹豫、哪一步重试。Harness 的价值不只是让 Agent 跑起来,而是让你看清它为什么跑偏。把这份 trace 当成代码 review 的一部分,你的 Agent 工作流会越来越稳。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询