用 Paperclip 搭了一个 3 人 AI 团队,自动写代码 + 审查 + 部署(踩了 4 个坑)
如果你在用 Claude Code 或者 Cursor 写代码,大概率遇到过这个问题:一个 Agent 干所有事,写完代码自己审查自己,质量全靠运气。就像让一个人既当运动员又当裁判,能公正才怪。
Paperclip 的思路不一样------它让你把多个 AI Agent 组织成一个"公司",每个 Agent 有自己的角色和职责,互相协作、互相审查。3 周前开源,GitHub 33K+ stars,MIT 协议。核心卖点:你的 AI Agent 不需要更好的 prompt,它们需要一个组织架构。
这篇文章我用 Paperclip 搭了一个 3 人 AI 团队:一个写代码、一个做 Code Review、一个跑测试。从安装到跑通,踩的坑都记下来了。
先装起来
前置条件:Node.js 18+、pnpm 9.15+。
bash
# 安装 pnpm(如果没有)
npm install -g pnpm
# 一键初始化(自带内嵌 PostgreSQL,不用额外装数据库)
npx paperclipai onboard --yes
这条命令会做三件事:拉代码、启动内嵌 PostgreSQL、创建你的第一个"公司"。跑完后打开浏览器访问 http://localhost:3000,能看到 Dashboard。
也可以纯 CLI 操作,不开浏览器:
bash
# 创建公司
paperclip company create --name "CodeTeam" --mission "Build and ship quality code"
# 查看公司状态
paperclip company status
到这一步大概 3 分钟。
核心概念:Agent = 员工
Paperclip 把 AI Agent 的管理类比成公司管理。几个核心概念:
- Company:一个项目或团队,包含多个 Agent
- Agent:一个有角色、职责、权限的 AI 实例
- Task:分配给 Agent 的具体工作
- Workflow:多个 Agent 协作的流程定义
这不是花哨的比喻,它真的按公司架构来设计------Agent 之间有汇报关系,有权限隔离,有审批流程。
定义 3 个 Agent 角色
我定义了 3 个角色,模拟一个最小的开发团队:
yaml
# ~/.paperclip/companies/codeteam/agents.yaml
agents:
- name: Coder
role: "Senior Developer"
provider: anthropic
model: claude-sonnet-4-20250514
tools:
- file_read
- file_write
- shell_exec
instructions: |
You write clean, production-ready code.
Always include error handling and input validation.
Never write code longer than 200 lines per file.
Add docstrings to all public functions.
- name: Reviewer
role: "Code Reviewer"
provider: anthropic
model: claude-sonnet-4-20250514
tools:
- file_read
instructions: |
Review code for bugs, security issues, and style.
Output a structured review with severity levels: critical/warning/info.
If any critical issue found, reject with clear reasons.
Be strict but fair.
- name: Tester
role: "QA Engineer"
provider: anthropic
model: claude-sonnet-4-20250514
tools:
- file_read
- shell_exec
instructions: |
Write and run tests for the given code.
Cover: happy path, edge cases, error handling, type validation.
Use pytest. Report pass/fail with details.
注意一个关键设计:Reviewer 只有 file_read 权限,不能改代码。这是故意的------审查者不应该有修改权限,只能提意见,让 Coder 自己改。这和真实团队的 Code Review 流程一样。
定义工作流:写 → 审 → 测
Agent 定义好了,还需要一个工作流把它们串起来。Paperclip 用 YAML 定义工作流,支持条件分支和循环:
yaml
# ~/.paperclip/companies/codeteam/workflows/code-pipeline.yaml
name: code-pipeline
description: "Write code, review it, test it"
steps:
- agent: Coder
task: "Write the code based on the requirement"
output: code_files
- agent: Reviewer
task: "Review the code written by Coder. Check for bugs, security issues, and code quality."
input: code_files
output: review_result
on_reject: goto step 1 # 被打回就让 Coder 重写
- agent: Tester
task: "Write pytest tests and run them. Cover happy path, edge cases, and error handling."
input: code_files
output: test_result
on_fail: goto step 1 # 测试不过也让 Coder 重写
max_iterations: 3 # 最多循环 3 次,防止死循环
on_reject 和 on_fail 是 Paperclip 的亮点------Agent 之间有反馈回路,不是线性执行完就结束。Reviewer 打回的时候会附上具体原因,Coder 拿到原因后针对性修改,而不是从头重写。
跑一个真实任务
启动工作流,给它一个有点难度的需求:
bash
paperclip task create \
--company CodeTeam \
--workflow code-pipeline \
--description "Write a Python function that validates email addresses. Requirements: 1) Handle empty/null input 2) Check @ symbol 3) Validate domain format 4) Support IP address domains like user@[192.168.1.1] 5) Reject multiple @ symbols 6) Return structured result with valid/invalid and reason"
在 Dashboard 上能看到实时进度,也可以用 CLI 查看日志:
bash
paperclip task logs --id task_001
输出大概长这样:
less
[14:01:02] [Coder] Writing email validator...
[14:01:08] [Coder] Created: src/email_validator.py (45 lines)
[14:01:10] [Reviewer] Reviewing src/email_validator.py...
[14:01:15] [Reviewer] REJECTED: [Critical] Missing handling for IP address domains
[14:01:15] [Reviewer] REJECTED: [Warning] No input type checking for non-string input
[14:01:17] [Coder] Rewriting based on review feedback...
[14:01:23] [Coder] Updated: src/email_validator.py (68 lines)
[14:01:25] [Reviewer] APPROVED: All critical issues addressed
[14:01:27] [Tester] Writing tests...
[14:01:33] [Tester] Created: tests/test_email_validator.py (89 lines)
[14:01:35] [Tester] Running: pytest tests/test_email_validator.py -v
[14:01:37] [Tester] PASSED: 14/14 tests passed
[14:01:37] Task completed successfully in 2 iterations
第一轮 Reviewer 发现了两个问题:一个 Critical(没处理 IP 地址域名),一个 Warning(没做类型检查)。Coder 根据反馈重写,第二轮通过。然后 Tester 写了 14 个测试用例,全部通过。
这就是多 Agent 协作的价值------Coder 第一版漏掉了 IP 地址域名的处理,如果是单 Agent 模式,这个 bug 就直接上线了。
看看最终生成的代码
Coder 经过 Reviewer 反馈后生成的最终版本:
python
# src/email_validator.py
import re
from typing import Union
def validate_email(email: Union[str, None]) -> dict:
"""Validate email address and return structured result.
Args:
email: Email address string to validate
Returns:
dict with 'valid' (bool) and 'reason' (str)
"""
if email is None or not isinstance(email, str):
return {"valid": False, "reason": "Input must be a non-null string"}
email = email.strip()
if not email:
return {"valid": False, "reason": "Empty string after trimming"}
if '@' not in email:
return {"valid": False, "reason": "Missing @ symbol"}
if email.count('@') > 1:
return {"valid": False, "reason": "Multiple @ symbols found"}
# Standard email pattern
standard = re.compile(
r'^[a-zA-Z0-9.!#$%&\'*+/=?^_`{|}~-]+'
r'@'
r'(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)*'
r'[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$'
)
# IP address domain pattern
ip_domain = re.compile(
r'^[a-zA-Z0-9.!#$%&\'*+/=?^_`{|}~-]+'
r'@\[(\d{1,3}\.){3}\d{1,3}\]$'
)
if standard.match(email) or ip_domain.match(email):
return {"valid": True, "reason": "Valid email address"}
return {"valid": False, "reason": "Invalid email format"}
注意 IP 地址域名的 ip_domain 正则------这是 Reviewer 第一轮打回后加上的。类型检查 Union[str, None] 也是。
踩坑记录
坑 1:内嵌 PostgreSQL 端口冲突
如果你本机已经跑了 PostgreSQL,onboard 会报端口 5432 被占用。两个解决方案:
bash
# 方案 1:指定其他端口
npx paperclipai onboard --yes --db-port 5433
# 方案 2:用你自己的 PostgreSQL
npx paperclipai onboard --yes --db-url postgresql://user:pass@localhost:5432/paperclip
坑 2:Agent 之间的上下文传递丢失
第一次跑的时候,Reviewer 说"I don't see any code files"。排查了半天,原因是 Coder 把文件写到了 /tmp/ 下面,而 Reviewer 只能读 workspace 目录。
在 Coder 的 instructions 里加一句就好了:
yaml
instructions: |
...
Always write output files to the current workspace directory.
Do not use /tmp or absolute paths.
坑 3:max_iterations 设太大烧 token
我一开始设了 max_iterations: 10,结果 Reviewer 和 Coder 来回拉扯了 7 轮,烧了 $2 的 API 费用。一个邮箱验证函数不值得。设成 3 就够了------3 轮还过不了,说明需求描述有问题,应该改需求而不是让 Agent 继续猜。
坑 4:免费模型不支持 tool_use
想省钱换了 OpenRouter 的免费模型,结果 Agent 不会调用 file_write 工具,只会在对话里输出代码。Paperclip 依赖模型的 function calling / tool_use 能力,免费模型大多不支持。至少得用 Claude Sonnet 或 GPT-4o-mini 这个级别的。
成本和效果数据
跑了 10 个类似复杂度的任务(单函数级别),统计了一下:
| 指标 | 数值 |
|---|---|
| 平均每个任务 token 消耗 | ~15K input + ~5K output |
| 平均每个任务成本(Claude Sonnet) | ~$0.12 |
| 平均迭代轮数 | 1.8 轮 |
| 代码一次通过率(Reviewer 没打回) | 40% |
| 测试一次通过率(Tester 没报错) | 70% |
一次通过率只有 40%,说明 Reviewer 确实在干活,不是摆设。60% 的情况下它都能挑出 Coder 遗漏的问题。
成本方面,单 Agent 写同样的代码大概 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0.05 ,三 A g e n t 是 0.05,三 Agent 是 </math>0.05,三Agent是0.12,贵了一倍多。但考虑到代码质量的提升,对于生产代码来说这个成本完全可以接受。
什么时候该用 / 不该用
适合的场景:
- 有明确分工的重复性任务(写代码 → 审查 → 测试)
- 需要多角度检查的场景(安全审计、文档校对)
- 想降低单 Agent 幻觉风险的场景
- 团队想建立 AI 辅助的标准化流程
不适合的场景:
- 简单的一次性任务(杀鸡用牛刀)
- 需要实时交互的场景(Paperclip 是异步批处理的)
- 预算紧张的个人项目(多 Agent = 多倍 token)
- 探索性的创意工作(Agent 之间的审查会限制创造力)
总结
Paperclip 干的事说白了就是:让 AI Agent 互相监督,别自己审查自己。
搭一个 3 人团队只需要两个 YAML 文件,10 分钟搞定。实测下来代码质量确实比单 Agent 好,尤其是边界条件和安全检查------Reviewer 总能挑出 Coder 漏掉的 case。
代价是 token 消耗翻倍,但对于重要的生产代码来说,花 $0.12 让三个 AI 互相 review 一下,比上线后出 bug 便宜多了。
你有没有试过让多个 AI Agent 协作的方案?效果怎么样?评论区聊聊。