Paperclip 适配器怎么选:五类接入方式的前提、限制与官方对照表
把 Paperclip 装起来、建好第一家公司之后,第一个真正卡人的问题不是界面,而是:这个 agent 到底靠什么跑起来?你在 agent 配置里要填一个 adapterType 和一份 adapterConfig,可选项有十来个,名字看着都差不多——claude_local、codex_local、opencode_local、hermes_local、hermes_gateway、process、http……选错了,轻则跑不通,重则跑通了但你在运行记录里啥也看不见。
Paperclip 官方文档对适配器的定义很直白:适配器是 Paperclip 编排层与 agent 运行时之间的桥,每个适配器知道怎么调起某一类 AI agent 并把结果捕获回来。换句话说,Paperclip 自己不”是”一个 agent,真正干活的进程由适配器负责启动。
这篇讲清执行层:适配器在一次心跳里做了几件事、内置有哪些类型、三个本地 CLI 适配器的接入前提和配置字段、凭据以谁为准、以及为什么同样跑通了运行记录的信息量能差一大截。全部依据官方文档原文,不同适配器之间只做并列,不下”哪个更好”的结论。
一次心跳里,适配器做了四件事
文档给出的执行链路是固定四步。当一次心跳(heartbeat)触发时,Paperclip 会:
- 查出这个 agent 的
adapterType和adapterConfig; - 带着执行上下文调用适配器的
execute()函数; - 由适配器去 spawn 或调用对应的 agent 运行时;
- 适配器捕获 stdout,解析用量/成本数据,返回一个结构化结果。
后面几乎所有差异都落在第 3、4 步上:第 3 步决定”接入前提是什么”(要不要本机装 CLI、要不要有登录态),第 4 步决定”你能看到多少”(纯文本还是结构化事件流)。
一个适配器包会被三个注册表分别消费,文档给的目录骨架是这样:
my-adapter/
src/
index.ts # Shared metadata (type, label, models)
server/
execute.ts # Core execution logic
parse.ts # Output parsing
test.ts # Environment diagnostics
ui-parser.ts # Self-contained UI transcript parser (for external adapters)
cli/
format-event.ts # Terminal output for `paperclipai run --watch`
Server 注册表执行 agent、捕获结果(来源是包根导出的 createServerAdapter()),UI 注册表渲染运行记录并提供配置表单(外部适配器走动态 ui-parser.js,内置走静态导入),CLI 注册表负责 paperclipai run --watch 的终端输出格式化。
内置适配器的完整清单
先把牌摊开。官方文档列出的内置适配器如下,Type Key 就是你要填进 adapterType 的值:
| 适配器 | Type Key | 官方描述 |
|---|---|---|
| Claude Code | claude_local | 本地跑 Claude Code CLI,条件允许时使用原生 ACP 引擎 |
| Codex | codex_local | 本地跑 OpenAI Codex CLI,条件允许时使用原生 ACP 引擎 |
| Gemini CLI | gemini_local | 本地跑 Gemini CLI(实验性——适配器包已存在,但尚未进入稳定类型枚举) |
| OpenCode | opencode_local | 本地跑 OpenCode CLI,支持多供应商的 provider/model 写法 |
| Cursor | cursor | 以后台模式运行 Cursor |
| Pi | pi_local | 本地跑一个内嵌的 Pi agent |
| Hermes | hermes_local | 通过 @paperclipai/hermes-paperclip-adapter 跑本地 Hermes CLI |
| Hermes Gateway | hermes_gateway | 通过该包的 /gateway 入口调用一个已在运行的 Hermes API server |
| OpenClaw Gateway | openclaw_gateway | 连接到一个 OpenClaw 网关端点 |
| Process | process | 执行任意 shell 命令 |
| HTTP | http | 向外部 agent 发送 webhook |
有两处必须单独标出来:
第一,gemini_local 是实验性的。 文档原文写明它”adapter package exists, not yet in stable type enum”——包在,但还没进稳定类型枚举。也就是说它和 claude_local、codex_local 不是同一个成熟度档位,上生产前你得自己掂量。
第二,Hermes 的两个 key 都是稳定内置。 想让 Paperclip 每次心跳都在同一台主机上启动本地 hermes CLI,用 hermes_local;Hermes 已作为 HTTP/SSE API server 在跑、想让 Paperclip 去调那个 server 而不是再 spawn 进程,用 hermes_gateway。旧的 @paperclipai/adapter-hermes-gateway 只作为废弃的兼容 shim 保留一个版本,新的插件覆盖应指向 @paperclipai/hermes-paperclip-adapter。
三个本地 CLI 适配器:前提与配置字段
claude_local、codex_local、gemini_local 是文档给了独立页面的三个。它们的共性是都要求对应的 CLI 本身在执行环境里可用,差异主要在鉴权方式、会话续接机制和几个专属开关上。
先看接入前提:
| 适配器 | CLI 前提 | 鉴权前提(官方原文口径) |
|---|---|---|
claude_local | claude 命令可用 | 适配器 env、环境 env 或宿主 env 里有 ANTHROPIC_API_KEY 或 CLAUDE_CODE_OAUTH_TOKEN;或者执行目标上有可用的 Claude Code 订阅登录 |
codex_local | codex 命令可用 | 宿主有 ~/.codex/auth.json 登录;或在适配器 env 里配 per-agent 的 OPENAI_API_KEY(Paperclip 会把它落成 $CODEX_HOME/auth.json) |
gemini_local | gemini 命令可用 | 设置 GEMINI_API_KEY 或 GOOGLE_API_KEY,或配好本地 Gemini CLI 鉴权 |
codex_local 这条有个容易踩的细节,文档写得很明确:Codex CLI 是从 auth.json 读凭据的,不是直接从进程环境变量读。所以如果你用的是自管的外部 CODEX_HOME,别指望设个环境变量就完事,得自己往那里写 auth.json。
再看配置字段。三者都必填 cwd(agent 进程的工作目录,必须是绝对路径;权限允许时缺失会自动创建),都支持 model、promptTemplate、env(支持 secret 引用)、timeoutSec(0 表示不超时)、graceSec(强杀前的宽限期)。差异在这几个:
| 字段 | 适配器 | 类型 | 官方说明 |
|---|---|---|---|
maxTurnsPerRun | claude_local | number | 每次心跳的最大 agentic 轮数,默认 300 |
dangerouslySkipPermissions | claude_local | boolean | 跳过权限提示,默认 true;无人值守(headless)场景下必需,因为交互式批准根本不可能发生 |
fastMode | codex_local | boolean | 启用 Codex Fast 模式,当前仅在 gpt-5.4 上支持,且消耗额度更快 |
dangerouslyBypassApprovalsAndSandbox | codex_local | boolean | 跳过安全检查,仅限开发环境 |
instructionsFilePath | codex_local / gemini_local | string | 一个 markdown 指令文件,会被前置到 prompt |
yolo | gemini_local | boolean | 传 --approval-mode yolo 用于无人值守运行 |
fastMode 的实际效果是 Paperclip 加上等价于下面这组 Codex 配置覆盖:
-c 'service_tier="fast"' -c 'features.fast_mode=true'
文档同时说明:Paperclip 目前只在选中模型为 gpt-5.4 时才真正应用它;在其它模型上,这个开关会保留在配置里但在执行时被忽略,以避免产生不受支持的运行。这个设计挺务实——开关不会静默改变行为,但也不会让你莫名其妙跑挂。
会话续接三家机制各不相同:claude_local 持久化 Claude Code 的 session ID,下次唤醒续上原会话;codex_local 用 previous_response_id 链式续接;gemini_local 持久化 Gemini session ID 并用 --resume 续接。claude_local 和 gemini_local 都写明续接是 cwd 敏感的:工作目录变了就开新会话;续接报未知会话错误时,适配器会自动用新会话重试。
技能注入(skills injection)也有区别:claude_local 建一个临时目录、把 Paperclip skills 软链进去再用 --add-dir 传入,不污染 agent 的工作目录;codex_local 软链进全局 ~/.codex/skills,gemini_local 软链进 ~/.gemini/skills,后两者文档都注明已有用户 skills 不会被覆盖。
凭据归属:沙箱里到底哪份登录会赢
这是三个本地适配器里最容易出玄学问题的地方。本地 CLI 适配器可以跑在 Paperclip 宿主机、SSH 目标或托管沙箱目标上,而在 CLI 启动之前,适配器就已经决定了哪个凭据来源是权威的。
两种拓扑:
| 适配器 | 凭据拓扑 | 在托管沙箱目标上谁赢 |
|---|---|---|
codex_local | host-owns-auth(宿主持有鉴权) | 宿主持有的 auth.json 会被软链进托管 CODEX_HOME 并上传到沙箱。若配了 per-agent OPENAI_API_KEY,Paperclip 改为写一份 API-key 形式的 auth.json,且该文件优先。烤进沙箱镜像里的登录会被遮蔽,因为 Codex 是带着 Paperclip 上传的 CODEX_HOME 跑的 |
claude_local | snapshot-owns-auth(快照持有鉴权) | 配置好的 ANTHROPIC_API_KEY 或 CLAUDE_CODE_OAUTH_TOKEN 优先于任何已存登录。否则 Paperclip 只上传经过脱敏的设置和 skill/运行时资产;当远端托管配置里没有 Claude 凭据文件时,它会从沙箱镜像自己的 $HOME/.claude 复制 .credentials.json 或 credentials.json 过来,此时镜像里的登录赢 |
顺带说两个 codex_local 的硬约束。一是托管 home 是空建的,适配器必须在启动 Codex 前把鉴权供给进去,否则 agent 以零凭据运行、供应商直接返回 401 Missing bearer;文档因此规定了 fail-fast:托管 home 既无可用 auth.json 又无配置 API key 时,运行以 adapter_failed 明确失败。二是每个 agent 被隔离到 <instance>/companies/<companyId>/agents/<agentId>/codex-home 并设置 OPENAI_API_KEY="",这样一个 agent 既不会花掉宿主的 API key,也不会共享另一个 agent 的 Codex 状态。真正外部的 CODEX_HOME(在托管公司目录树之外)被当作自管,永不 seeding 或覆盖。
关于高并发沙箱集群,文档给了一条带取舍说明的建议(这是官方文档的说法):优先用 per-agent OPENAI_API_KEY 而不是共享的 ChatGPT 订阅登录,因为 API-key 模式为每个托管 home 生成独立 auth.json,避免大量并发沙箱共用一份会轮换的订阅凭据;代价是 API-key 模式按 token 计量,而订阅鉴权走套餐的固定额度经济学。
反馈粒度:为什么同样跑通了,有的运行记录啥也看不见
这是选型时最容易被忽略、事后最容易后悔的一条。文档说得很清楚:适配器的选择决定了一次运行在 agent 还在干活时,运行记录能展示多少结构化的实时细节。所有适配器的 stdout 都会被流式写进运行日志并在 UI 里实时渲染(包括跑在沙箱执行目标上的运行,其日志会被 tail 并增量投递),但粒度取决于适配器发出的事件流。
文档给了三档,由细到粗:
| 档位 | 覆盖的适配器 | 你能看到什么 |
|---|---|---|
| 原生 ACP 引擎 | claude_local / codex_local / gemini_local 且 engine: "acp" | 完整结构化事件流 |
| CLI 包装 | claude_local、codex_local、cursor、opencode_local 等 | 解析各 CLI 自己的流式 JSON 输出 |
| 通用适配器 | process、http | 纯 stdout/stderr 文本行,没有结构化记录 |
第一档具体到事件类型:ACP 为每个有意义的运行时时刻发一条 JSONL 事件——acpx.session(会话身份)、acpx.status(进度文本加上下文窗口用量)、acpx.text_delta(助手/思考的 token 增量)、acpx.tool_call(工具标题、调用 id 及推进中的状态更新)、acpx.result(停止原因摘要)、acpx.error(错误码、消息、是否可重试)。它们被渲染成实时更新的消息块、思考块、工具块和状态块,且重复的 acpx.tool_call 状态更新会折叠进同一张工具卡片。
第二档能拿到助手文本、工具调用/结果和最终的用量/成本摘要,但粒度受限于 CLI 自己打印了什么——文档说得很实在:有的 CLI 输出工具进度,有的只有”调用/完成”这一对。第三档就只有原始输出,用 process 跑脚本又想在 UI 里看到工具调用时间线,那是不存在的。
官方给的推荐是(这是官方文档的说法):当选中的执行环境支持时,在 claude_local、codex_local 或 gemini_local 上使用原生 ACP 引擎,理由是丰富的 ACP 状态事件(含上下文用量)和增量的工具调用更新最接近”在本地盯着 agent 干活”的体验。注意这里有个前提条件——文档写的是”当执行环境满足 ACP 前置条件时”,具体前置条件在这几页里没有展开。
通用适配器与外部插件适配器
process 和 http 是两个不挑运行时的口子:前者执行任意 shell 命令,后者向外部 agent 发 webhook,代价是上一节说的第三档粒度。接入细节各有专页,见进程适配器怎么接本地 CLI和 HTTP 适配器接自建 Agent。
另有一类外部(插件)适配器:作为独立 npm 包发布,通过插件系统在启动时加载。文档目前列出的是 Droid——包名 @henkey/droid-paperclip-adapter,type key droid_local,本地跑 Factory Droid。装它不需要改 Paperclip 源码,文档给的两条路径是:
# Install from npm via API
curl -X POST http://localhost:3102/api/adapters \
-d '{"packageName": "my-paperclip-adapter"}'
# Or link from a local directory
curl -X POST http://localhost:3102/api/adapters \
-d '{"localPath": "/home/user/my-adapter"}'
外部适配器还可以自带 UI parser,告诉 Web UI 怎么渲染它的 stdout;不带的话 UI 会退回通用 shell parser。想自己写一个,见自己写一个 Paperclip 适配器。
选型对照表
把文档”Choosing an Adapter”一节的原始口径整理成表(这是官方文档的说法,不是我们的排序):
| 你的需求 | 官方给的选项 |
|---|---|
| 需要一个写代码的 agent | claude_local、codex_local、opencode_local、hermes_local,或以外部插件方式安装 droid_local |
| 需要最丰富的实时运行反馈 | claude_local、codex_local 或 gemini_local,并把 adapterConfig.engine 设为 acp(前提是执行环境满足 ACP 条件) |
| Hermes 在另一台主机上,或已作为服务在跑 | hermes_gateway |
| 只是要跑个脚本或命令 | process |
| 要调一个自定义的外部服务 | http |
| 要接 OpenClaw 网关 | openclaw_gateway(连接到一个 OpenClaw 网关端点) |
| 都不合适 | 自己写适配器,或做成外部适配器插件 |
配好之后别急着上生产。文档提到 UI 里有”Test Environment”按钮做配置校验,检查项包括:CLI 是否已安装且可访问、工作目录是否为绝对路径且可用(缺失且允许时自动创建)、鉴权信号提示,以及一次真实的 hello 探针确认 CLI 能跑起来。三家的探针命令分别是 claude --print - --output-format stream-json --verbose、codex exec --json -、gemini --output-format json "Respond with hello.",prompt 都是 Respond with hello.。
claude_local 的探针看到的是和真实运行同一套分层 env:选中某个 environment 时,其环境变量(含 secret 引用)会被解析并合并到适配器配置的 env 之下;缺失的 secret 绑定会以 environment_env_binding_missing 失败暴露出来,而不是让探针静默通过。
什么时候这套不适用,以及文档没说的
先说边界。适配器解决的是”用什么运行时执行一次 agent 运行”,它不解决什么时候执行、执行多久、花多少钱——那是心跳、看门狗和预算那一层的事,agent 被驱动的完整机制见 Agent 在 Paperclip 里怎么被驱动。
几条需要你自己拿主意的地方:
gemini_local 的实验状态。 官方标注它的适配器包已存在但尚未进入稳定类型枚举。它同时又出现在”最丰富实时反馈”的 ACP 推荐名单里——这两条并不矛盾,但意味着你要在”想要 ACP 粒度”和”想要稳定档位”之间自己权衡。
两个 dangerously* 开关。 claude_local 的 dangerouslySkipPermissions 默认就是 true,理由是无人值守场景下交互批准不可能发生;codex_local 的 dangerouslyBypassApprovalsAndSandbox 文档明确标注”dev only”。这两个名字里带 dangerous 不是装饰,配之前先想清楚这个 agent 的 cwd 里放的是什么。
沙箱凭据这块要按适配器分别推演。 同一套沙箱镜像,codex_local 下宿主登录赢、claude_local 下镜像登录赢——这两条方向相反。如果你的集群里两种 agent 混跑,别用同一套心智模型去排查”为什么用的不是我以为的那个账号”。
文档留了一处明确的未实现项。 codex_local 那页有一节”Deferred config-validation warning spec”,讲的是鉴权模式为订阅、且执行目标是远端/沙箱时应当发出的一条告警。文档自己写明这是一个尚未实现的告警,只是后续实现的规格说明。所以现在这个组合不会有任何提示,得靠你自己记住。
还有一些这几页没写的。 各适配器的性能差异、并发上限、成本对比,官方这几页没有给数字;ACP 引擎的具体前置条件,也只写了”当执行环境满足时”。落地前要确认这些,得去看执行语义那几页,或者在自己的环境里实测。
延伸阅读
- 从头读起:Paperclip 是什么:一个自己不跑 Agent 的控制平面,怎么管住一整家 AI 公司
- 本专题共 40 篇,完整分组目录见专题页
- Paperclip HTTP 适配器接入自建 Agent:要实现哪些端点、鉴权与回调契约怎么写
- Paperclip 进程适配器怎么用:把任意 shell 命令接进 Agent 编排,代价是什么
本文依据 Paperclip 官方仓库(github.com/paperclipai/paperclip,MIT 协议)的 docs/ 用户文档
与 doc/ 下的规范、运维与连接器手册整理,核对日 2026-08-17。
我们没有部署或运行过 Paperclip,因此不涉及界面外观与操作手感;
部分规范文档描述的是目标架构而非当前实现,文中已就地标注,不构成对实际行为的保证。
请以仓库最新内容为准。