适用场景
手上有一个边界清晰、结果能自动验证的真实任务——比如"给现有服务加一个分页参数""把这个模块的测试补到能覆盖异常分支""复现并修掉一个稳定出现的 bug"——而且仓库已经在 Git 里,测试能用一条命令跑通。这种情况下可以把任务写成一张"任务单"交给结对智能体,让它在隔离的工作区里改代码、跑测试、提交,你只负责下单、审阅关键节点、必要时回滚。
反过来,需求还没想清楚、验收标准说不出来、或者代码跑不起来也测不了的任务,不适合交给它——智能体会很努力地改,但你没法判断改得对不对,审阅成本会高过自己动手。
顺带说清分工:同类工具大致分三类。命令行里"边聊边改"的助手(如 Claude Code 这类),适合你已经知道要改哪个文件、需要短回合反复确认的活;长时间自主执行的结对智能体(本文的 Duet),适合给一张任务单让它自己跑测试迭代,你在检查点审阅;偏方案讨论、任务拆解、文档产出的工具(如 Muse 这类),适合在动手之前把任务想清楚。具体能力边界与入口命令以各自官方文档为准,这里给的是分工思路,不是功能承诺。
环境与前置条件
- 操作系统:macOS 或 Linux。Windows 建议在 WSL2 里操作,避免路径与换行符问题。
- Git:需要支持
git worktree的版本(2.x 均可),这是隔离工作区的基础。 - 运行时:按你项目自身的语言栈准备(Node、Python、Go 等),版本以项目
package.json/pyproject.toml/go.mod的要求为准;智能体客户端自身的运行时要看官方文档。 - 内存:8 GB 起步,16 GB 更从容——智能体会同时跑测试、跑 lint、读文件。
- 磁盘:预留 5~10 GB。多个工作区各装一份依赖,
node_modules这类目录很容易翻倍。 - 网络:能访问模型 API。公司网络需要走代理的,提前准备好
HTTPS_PROXY/NO_PROXY和内部 CA 证书路径。 - 凭证:一个 Anthropic API Key,在控制台创建,建议单独建一把给自动任务用,方便单独吊销。资费标准以官方页面为准。
- 仓库状态:主分支干净、能跑通测试、有明确的验收命令(
make test、npm test、pytest之类)。
一句提醒:本文按官方文档的通用流程组织,客户端安装命令、配置字段名、模型标识这类细节,以官方文档当前版本为准;如果字段名和下文示意不一致,按文档映射过去即可,流程本身不变。
分步骤部署
第 1 步:开一个隔离工作区
不要让它在你正在写代码的目录里动手。用 git worktree 开一份独立副本,主工作区不受影响:
```bash
cd /path/to/your-repo
git worktree add ../duet-task -b duet/task-001
cd ../duet-task
```
duet-task 是一个新分支、新目录,和主工作区共享同一个 .git。成功标志:目录里文件齐全,并且 git status 显示干净:
```bash
git status --short # 无输出
```
顺手把凭据文件挡在版本库外:
```bash
printf '\n.env\n.duet/\n' >> .gitignore
```
第 2 步:写任务单
结对智能体失败,多半不是模型不行,而是任务单太糊。在仓库根目录建一个 TASK.md,把"做什么、能改哪、怎么算做完"写死:
```markdown
任务:为 /api/orders 增加分页
目标
列表接口支持 page / page_size 两个查询参数,默认每页 20 条,上限 100。
允许修改
- src/api/**
- tests/api/**
不允许修改
- 数据库迁移脚本、CI 配置、依赖清单
- 需要新增依赖时,先停下来问我,不要自己装
验收命令
- make test
- make lint
完成定义
- 新增测试覆盖:空结果、页码越界、page_size 超上限
- 两条验收命令退出码均为 0
- 提交信息沿用仓库现有风格,一个提交只做一件事
```
"不允许修改"这一节价值很高。范围越窄,diff 越好读,返工越少。
第 3 步:配置凭证
只走环境变量,不写进仓库:
```bash
export ANTHROPIC_API_KEY="sk-ant-..."
```
检查一下确实生效(只打印前几位,避免截图泄露整把 key):
```bash
echo "${ANTHROPIC_API_KEY:0:8}"
```
如果客户端支持配置文件,放在用户目录下,权限收紧:
```yaml
~/.config/<客户端目录>/config.yaml(字段名以官方文档为准)
workspace: /abs/path/to/duet-task
approval: ask # 每次写文件/执行命令前先问你
max_turns: 30 # 单次任务的最大回合数,防止跑飞
log: ~/.local/state/duet/session.log
```
approval: ask 是新手期的安全绳。跑顺几次之后再考虑放宽。
第 4 步:安装客户端并做健康检查
按官方文档给出的安装方式安装(包管理器、官方脚本或容器镜像均可),版本以官方文档当前版本为准。装完先做一次版本查询,能打印出版本号就说明可执行文件在 PATH 里:
```bash
<客户端命令> --version
```
再确认配置能被读到(大多数客户端都有类似 config show / doctor 的子命令,具体名字看文档)。
第 5 步:先做只读验证,再谈写
第一次会话不要让它改代码。在 duet-task 目录里启动客户端,只问一个问题:
> 不要修改任何文件。请告诉我:这个仓库的测试命令是什么、主要源码在哪个目录、有没有代码风格检查。
成功标志有两个:回答内容和仓库实际情况一致;git status --short 仍然没有输出。
```bash
git status --short # 无输出 = 它确实没动文件
```
这一步能提前暴露权限、网络、代理、密钥四类问题,比改到一半报错省事得多。
第 6 步:正式下单
把任务单交给它,并且明确要求"先给计划、别急着改":
> 阅读 TASK.md。先不要修改文件,给我一份执行计划:打算改哪几个文件、每个文件改什么、准备跑哪些命令验证。我确认后再开始。
拿到计划后逐条对一遍:有没有超出"允许修改"的目录、有没有打算动依赖、验收命令是否被漏掉。这一步花三分钟,后面能省半小时。
计划没问题就回一句"按计划执行"。如果客户端支持自动批准某类操作,这个阶段仍然建议保持逐次确认。
第 7 步:过程审阅
每完成一个小步骤就停下来看一眼,不要等它全跑完。三种粒度从粗到细:
```bash
git status --short # 动了哪些文件
git diff --stat # 每个文件改了多少行
git diff # 具体改了什么
make test # 验收命令自己跑一遍,别只听它说
```
要求它每轮汇报四件事:改了哪些文件、为什么这么改、跑了什么命令、命令输出是什么。汇报和 git diff 对不上,就是危险信号——先回滚再排查,不要一边怀疑一边继续往下跑。
每通过一个小步骤就提交一次,提交点就是你的回滚点:
```bash
git add -A
git commit -m "feat(orders): add pagination params"
```
第 8 步:验收与合并
完整跑一遍任务单里的验收命令,两条都过再谈合并:
```bash
make test && make lint
```
回主工作区合并前先同步主干,避免冲突留到最后:
```bash
cd /path/to/your-repo
git fetch origin
git merge --no-ff duet/task-001
```
合并后删掉临时工作区:
```bash
git worktree remove ../duet-task
git branch -d duet/task-001
```
第 9 步:演练一次回滚
回滚能力要在需要之前就验证过。三种粒度的命令记牢:
```bash
只撤掉某个文件的改动
git checkout -- src/api/orders.py
回到某个提交(会丢弃之后的改动,先确认 diff)
git log --oneline
git reset --hard <commit-hash>
整个工作区不要了
git worktree remove ../duet-task --force
git branch -D duet/task-001
```
reset --hard 之前先 git stash 或 git diff > backup.patch 留一手。
验证部署是否成功
三步全部通过,才算跑通闭环:
1. 只读验证——让智能体回答仓库结构问题,然后:
```bash
git status --short
```
预期:无任何输出。
2. 写入验证——让它做一处一行改动,比如给某个函数补一句注释或改一个变量名,然后:
```bash
git diff
```
预期:只出现你指定的那个文件的改动,行数在个位数。如果 diff 里冒出格式化工具重排的全文件改动,说明仓库没配好格式化钩子,先修这个再继续。
3. 回滚验证——
```bash
git checkout -- <那个文件>
git status --short
```
预期:无输出,文件内容回到改动前。这一步过了,说明你的"审阅—回滚"链路是通的。
再补一条:跑一次完整验收命令 make test,退出码为 0,echo $? 打印 0。
常见报错与解决
401 Unauthorized / invalid x-api-key
→ 密钥没设、拼错,或 shell 里残留了旧的导出值。
```bash
echo "${ANTHROPIC_API_KEY:0:8}" # 确认前缀对不对
unset ANTHROPIC_API_KEY
export ANTHROPIC_API_KEY="sk-ant-..."
```
注意 .env 里如果还有一份旧值,会被再次覆盖,一并检查。
SSL certificate problem / 连接超时
→ 公司代理或自签 CA 没被客户端识别。
```bash
export HTTPS_PROXY="http://proxy.example.com:8080"
export NO_PROXY="localhost,127.0.0.1,.internal"
export NODE_EXTRA_CA_CERTS="/path/to/ca-bundle.crt" # Node 系
export REQUESTS_CA_BUNDLE="/path/to/ca-bundle.crt" # Python 系
```
改完重开一个终端再试。
429 Too Many Requests / overloaded
→ 并发太高或额度用尽。先降并发(把客户端配置里的并行任务数调到 1),把一次大任务拆成两三个小任务重试;同时去控制台看用量,确认不是额度问题。
fatal: 'duet/task-001' is already checked out at ...
→ 同一个分支被两个工作区同时占用。
```bash
git worktree list
git worktree remove ../duet-task --force
git worktree add ../duet-task -b duet/task-002
```
智能体改了"不允许修改"的文件
→ 任务单里的范围没写死,或它把依赖清单当成了顺手要改的东西。
```bash
git checkout -- package.json package-lock.json
git diff --stat
```
回滚后在 TASK.md 里把禁改目录逐条列出来,并补一句"需要变更范围时先停下来询问"。
磁盘写满 / 依赖装了两三遍
→ 多个工作区各有一份 node_modules 或虚拟环境。
```bash
du -sh ../duet-task/node_modules
git worktree list
git worktree remove ../duet-task # 用完即删,别攒
```
后续维护
备份。代码本身走远端仓库,要额外备份的是"任务档案":把每张 TASK.md 和最终 diff 一起归档,出问题时能复盘"当时是怎么判断的":
```bash
mkdir -p tasks/archive
cp TASK.md "tasks/archive/$(date +%Y%m%d)-pagination.md"
git diff main...duet/task-001 > "tasks/archive/$(date +%Y%m%d)-pagination.patch"
```
升级。客户端升级前,先在一次性工作区里跑一遍本文的"三步验证",通过再升级主环境。项目依赖用 lockfile 锁住,别让智能体顺手 update。升级后重跑一次只读验证,确认配置字段没被改名。
日志与监控。会话日志建议落盘(客户端大多支持 log: 配置或重定向 tee),定期看一下三件事:单次任务的实际回合数、被拒绝的操作类型、超出范围的文件改动。前两个反映任务单写得够不够清楚,第三个是范围失控的早期信号。
成本核算。结对智能体的账要算三笔:模型调用费(按 token 计,仓库上下文越大会放大)、人的审阅时间(每轮 diff 都要读,回合越多越贵)、返工成本(范围失控、改错文件后的重来)。三家工具的计价方式各不相同,具体价格与计费单位以官方页面为准;你能控制的是四项动作——把任务拆小、在任务单里写死允许修改的目录、把验收命令写进任务单、要求先给计划再动手。这四项做到位,通常比换工具更能压低总成本。
周期清理。每月跑一次 git worktree list 和 git branch --list 'duet/*',把过期的临时工作区和分支删掉,避免磁盘和分支列表一起长草。
