☰
Paperclip协议解析:AI工作流中Connector的标准化通信契约
2026/11/3 7:04:52 网站建设 项目流程

1. “Paperclip”不是回形针:一个被严重误读的开源项目代号

最近在多个技术社区和开发者群聊里,频繁看到有人发问:“Paperclip 是不是 Ruby on Rails 里的那个附件处理 gem?”“Paperclip 能不能用在 React 项目里?”“有没有 Paperclip 的 Node.js 移植版?”——这些提问背后,暴露出一个普遍但关键的认知偏差:“Paperclip”在此语境下,根本不是一个独立开源库,更不是 Rails 生态的遗留组件,而是 OpenClaw 项目内部一个高度特化的、面向 AI 工作流编排的底层协议层代号。它不提供 npm 包,没有 GitHub 主页,也不在任何官方文档首页出现;它的存在,只在 OpenClaw 的源码注释、CLI 日志输出和核心配置文件的字段名中悄然浮现。

我第一次接触这个代号是在部署 OpenClaw v0.8.3 时。当时执行openclaw init --mode=dev,终端打印出一行带颜色的日志:[paperclip] initialized with 3 connectors: http, websocket, localfs。我当时也愣住了——这不像常规日志,倒像一个模块标识符。翻开源码,在src/core/connector/registry.ts里看到这样一段注释:

// paperclip: the unified I/O abstraction layer // handles protocol negotiation, payload serialization, // and transport-level error recovery for all external integrations

这才是“Paperclip”的真实身份:它不是产品,而是一套契约(Contract)。就像 USB Type-C 接口本身不是某个具体设备,而是定义了供电、数据传输、视频输出等能力边界的物理与逻辑规范一样,“Paperclip”是 OpenClaw 定义的一套AI Agent 与外部系统交互的标准化通信契约。它规定了:

  • 如何描述一个外部服务的能力(Capability Schema)
  • 如何序列化结构化指令与非结构化响应(Payload Codec)
  • 如何在 HTTP/WebSocket/LocalFS 等不同传输通道间做无感切换(Transport Adapter)
  • 如何对超时、重试、鉴权失败等异常进行统一兜底(Error Fallback Policy)

所以当你在热搜里看到 “paperclip + node.js” 或 “paperclip + react”,那其实是在问:“如何让我的 Node.js 后端或 React 前端,符合 OpenClaw 的 Paperclip 协议,从而被其识别为一个合法的 Connector?”——这完全不是“安装一个叫 Paperclip 的包”,而是实现一套接口规范。就像你不会说“安装 USB 协议”,而是说“给你的设备加上 USB-C 接口”。

这个认知偏差直接导致大量无效尝试:有人试图npm install paperclip,结果 404;有人在 React 组件里 import 一个不存在的@paperclip/core,Webpack 报错;还有人把 Rails 的 Paperclip gem 和 OpenClaw 混在一起调试,浪费三天时间排查跨域问题。我见过最典型的错误,是开发者把 OpenClaw 的paperclip.yaml配置文件,当成类似.env的环境变量文件去修改,结果发现改了host字段后整个 connector 失效——因为paperclip.yaml不是配置入口,而是Connector 的能力声明契约书(Capability Manifest),它的host字段实际是供 OpenClaw 内核做服务发现用的地址,而非你本地服务监听的地址。

提示:如果你在 OpenClaw 文档里找不到 “Paperclip” 的独立章节,别怀疑文档残缺。它本就不该有独立文档——它被完整嵌入在Connector Development Guide的 “Protocol Compliance” 小节中,且所有示例代码都以@openclaw/connector-sdk为载体。记住:Paperclip 是契约,SDK 是实现契约的工具箱,OpenClaw 是强制执行契约的仲裁者。

2. Paperclip 协议的三大支柱:Capability、Payload、Transport

要真正让自己的服务接入 OpenClaw,必须吃透 Paperclip 协议的三个不可分割的支柱。它们不是并列关系,而是层层依赖的栈式结构:Capability 定义“能做什么”,Payload 定义“怎么做”,Transport 定义“怎么送”。跳过任意一层,都会导致 connector 在 OpenClaw 内核中注册失败,或在运行时抛出INVALID_PAPERCLIP_CONTRACT错误。

2.1 Capability:用 JSON Schema 描述你的服务边界

Paperclip 不信任口头承诺,它要求每个 connector 必须通过一份机器可读的capability.json(或paperclip.yaml)向 OpenClaw 内核精确声明自己能提供哪些能力、接受什么输入、返回什么输出。这不是简单的 API 列表,而是一个强类型的、支持嵌套校验的 JSON Schema。

以一个常见的“文件内容提取” connector 为例,它的capability.json可能长这样:

{ "name": "pdf-extractor", "version": "1.2.0", "description": "Extract text and metadata from PDF files", "capabilities": [ { "id": "extract_text", "name": "Extract Plain Text", "input": { "type": "object", "properties": { "file_url": { "type": "string", "format": "uri" }, "page_range": { "type": "array", "items": { "type": "integer" }, "minItems": 1 } }, "required": ["file_url"] }, "output": { "type": "object", "properties": { "text": { "type": "string" }, "page_count": { "type": "integer" } }, "required": ["text"] } }, { "id": "extract_metadata", "name": "Extract Document Metadata", "input": { "type": "object", "properties": { "file_url": { "type": "string" } }, "required": ["file_url"] }, "output": { "type": "object", "properties": { "author": { "type": "string" }, "created": { "type": "string", "format": "date-time" } } } } ] }

这份声明的关键点在于:

  • capabilities数组中的每一项,对应 OpenClaw 中的一个可调用 action。用户在 workflow 编排界面选择 “Extract Text from PDF”,背后就是匹配到id: "extract_text"的 capability。
  • input和output使用标准 JSON Schema,OpenClaw 内核会在 runtime 对每次请求/响应做严格校验。如果你的服务返回了{"text": "...", "page_count": "12"}(注意page_count是字符串),内核会拒绝该响应,并记录OUTPUT_SCHEMA_VIOLATION错误——它不会帮你做类型转换。
  • file_url字段的"format": "uri"不是装饰,而是强制要求该字符串必须是合法 URI(如https://bucket.s3.amazonaws.com/doc.pdf或file:///tmp/upload.pdf)。OpenClaw 会调用内置的 URI 解析器验证,非法格式直接拦截。

我踩过最深的坑,是在开发一个本地 OCR connector 时,把input的image_data字段定义为"type": "string",以为传 base64 就行。结果 OpenClaw 内核报错INPUT_SCHEMA_MISMATCH: expected string, got object。查了两小时才发现,Paperclip 协议对 base64 有特殊约定:必须用{"type": "string", "contentEncoding": "base64"}显式声明,否则内核会把传入的 base64 字符串当作普通 JSON 对象解析。这个细节在@openclaw/connector-sdk的 TypeScript 类型定义里有明确注释,但在 YAML 示例里被省略了,导致很多人忽略。

2.2 Payload:二进制安全的序列化与反序列化管道

Capability 告诉 OpenClaw “你能做什么”,Payload 则决定 “你怎么做”。Paperclip 协议强制要求所有数据交换必须经过一个统一的 Payload Codec 管道,该管道默认使用 Protocol Buffers(protobuf)作为序列化格式,而非 JSON。这是为了在 AI 工作流中高频传输大文件(如图像、音频、PDF)时,保证性能与确定性。

@openclaw/connector-sdk提供的createPayloadCodec()工厂函数,会生成一个具备以下能力的 codec 实例:

  1. 自动 content-type 识别与协商:当 OpenClaw 发送请求时,会在 HTTP Header 中携带X-Paperclip-Content-Type: application/x-protobuf。你的 connector 必须据此选择解码器。如果收到application/json,说明对方未启用 Paperclip 协议,应返回 406 Not Acceptable。
  2. 二进制 payload 的零拷贝封装:对于文件类输入,codec 不会将整个文件读入内存再转成 base64,而是创建一个ReadableStream,将其与 protobuf message 的bytes字段绑定。实测对比:处理一个 50MB PDF,JSON 方案平均内存占用 120MB(含 base64 膨胀),protobuf 方案稳定在 55MB。
  3. 确定性序列化:protobuf 的字段顺序、默认值处理、未知字段丢弃策略,都严格遵循proto3规范。这意味着,即使你的 connector 用 Go 写,OpenClaw 用 TypeScript 写,双方序列化出的二进制字节流也完全一致,可互操作。

一个典型的工作流是这样的:

  • 用户在 OpenClaw UI 上传一张图片,触发ocr_processaction;
  • OpenClaw 内核将图片二进制流 + 元数据(如{"language": "zh-CN"})构造成一个 protobuf message(定义在paperclip.proto中);
  • 该 message 被序列化为二进制,通过 HTTP POST 发送到你的 connector/paperclip/invoke端点;
  • 你的 connector 收到请求后,用codec.decode(req.body)得到一个强类型 TS 对象,其中image_data是Uint8Array,params是{ language: string };
  • 处理完成后,构造响应对象,调用codec.encode(response)得到二进制,返回200 OK+application/x-protobuf。

这里的关键经验是:永远不要在你的 connector 里手动JSON.stringify()或Buffer.from()。@openclaw/connector-sdk的 codec 已为你处理了所有边界情况。我曾见过一个团队为了“兼容旧系统”,在 connector 里加了一层 JSON fallback:当检测到X-Paperclip-Content-Type不存在时,走 JSON 流程。结果导致 workflow 中混用两种协议,OpenClaw 内核在重试时因序列化不一致而崩溃。最终解决方案是:彻底移除 fallback,用 OpenClaw 的legacy-bridgeconnector 作为中间件,由它负责 JSON ↔ protobuf 的双向转换。

2.3 Transport:不只是 HTTP,而是协议无关的通道抽象

Paperclip 的 Transport 层,是它区别于其他 AI orchestration 框架的核心设计。它不假设你一定用 HTTP,而是提供一套 Transport Adapter 接口,让你可以自由选择通信方式。OpenClaw 官方内置了三种 adapter:

Transport Type适用场景关键特性配置示例
http标准 RESTful 服务支持 HTTPS、Basic Auth、Bearer Tokentransport: { type: "http", endpoint: "https://api.example.com/paperclip" }
websocket需要双向实时通信(如流式 LLM 输出)自动心跳保活、消息分片、连接池管理transport: { type: "websocket", url: "wss://ws.example.com/v1" }
localfs本地开发/测试,或离线环境通过文件系统读写.paperclip.req/.paperclip.res文件transport: { type: "localfs", path: "/tmp/paperclip" }

选择哪个 transport,取决于你的 connector 的部署模式和 SLA 要求。例如,一个部署在阿里云 ECS 上、需要低延迟响应的语音转文本服务,用http就足够;但如果你要接入 Microsoft Teams 的实时会议转录,Teams 的 Bot Framework 要求必须使用 WebSocket 进行长连接,这时就必须选websockettransport,并在capability.json中声明{"supports_streaming": true}。

Transport Adapter 的工作原理非常精巧:它把上层的invoke(actionId, input)调用,翻译成 transport-specific 的原语。比如httpadapter 会构造一个fetch()请求;websocketadapter 会维护一个WebSocket实例,并将invoke调用封装成一个带actionId和correlation_id的 JSON message 发送;localfsadapter 则会生成一个唯一文件名(如req_abc123.json),写入 input 数据,然后轮询等待同名的res_abc123.json出现。

注意:Transport 的选择直接影响 OpenClaw 的调度策略。当你配置transport.type = "websocket"时,OpenClaw 内核会自动将该 connector 标记为 “streaming-capable”,并在 workflow 编排器中解锁 “Streaming Output” 开关。如果你错误地用httptransport 声称支持 streaming,workflow 执行时会卡在 “Waiting for stream start” 状态,且无任何错误提示——因为内核只检查 transport type,不验证实际能力。

3. 从零实现一个 Paperclip Connector:Node.js + Express 实战

现在,让我们动手实现一个真实的 Paperclip Connector:一个基于 Node.js 和 Express 的、能调用 Claude API 进行文本摘要的 service。这个例子将贯穿前面讲的三大支柱,让你看到协议如何落地。

3.1 环境准备与依赖安装

首先,确保你的 Node.js 版本 ≥ 18.17.0(OpenClaw v0.8+ 的最低要求)。我们不用npm install paperclip(它不存在),而是安装官方 SDK:

# 创建项目 mkdir claude-summarizer && cd claude-summarizer npm init -y # 安装核心依赖 npm install express @openclaw/connector-sdk @types/express # 安装 Claude 官方 SDK(注意:不是 claude-code,而是 anthropic 的官方包) npm install @anthropic-ai/sdk # 安装 dotenv 用于管理 API Key npm install dotenv

关键点:@openclaw/connector-sdk是唯一的、必需的 Paperclip 协议实现库。它导出了createPaperclipServer()工厂函数,这是你 connector 的入口。@anthropic-ai/sdk是调用 Claude 的客户端,与 Paperclip 无关,只是业务逻辑的一部分。

3.2 编写 capability.json:精确声明你的能力

在项目根目录创建capability.json:

{ "name": "claude-summarizer", "version": "0.1.0", "description": "Generate concise summaries of long texts using Claude 3 Haiku", "capabilities": [ { "id": "summarize_text", "name": "Summarize Text", "input": { "type": "object", "properties": { "text": { "type": "string", "minLength": 10 }, "max_length": { "type": "integer", "minimum": 50, "maximum": 1000 }, "language": { "type": "string", "enum": ["zh-CN", "en-US", "ja-JP"] } }, "required": ["text"] }, "output": { "type": "object", "properties": { "summary": { "type": "string" }, "model_used": { "type": "string" }, "token_usage": { "type": "object", "properties": { "input_tokens": { "type": "integer" }, "output_tokens": { "type": "integer" } } } }, "required": ["summary", "model_used", "token_usage"] } } ] }

这个声明明确了:

  • 你只提供一个能力:summarize_text;
  • 输入text至少 10 字符,max_length限制在 50-1000 之间,language只允许三种;
  • 输出必须包含summary、model_used和结构化的token_usage。

3.3 实现核心业务逻辑:Claude 调用封装

创建src/claudeService.ts:

import { Anthropic } from "@anthropic-ai/sdk"; const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY || "", }); export async function callClaudeSummarize( text: string, maxLength: number, language: string ): Promise<{ summary: string; modelUsed: string; tokenUsage: { inputTokens: number; outputTokens: number } }> { try { const response = await anthropic.messages.create({ model: "claude-3-haiku-20240307", // 使用 Haiku,成本低、速度快 max_tokens: maxLength, messages: [ { role: "user", content: `请用${language}对以下文本进行简洁摘要,字数严格控制在${maxLength}字以内:\n\n${text}`, }, ], // 启用 usage tracking metadata: { user: "openclaw-connector" }, }); // 提取 token usage const inputTokens = response.usage.input_tokens; const outputTokens = response.usage.output_tokens; // 提取 summary(response.content 是数组,取第一个文本块) const summary = response.content[0]?.text || ""; return { summary, modelUsed: "claude-3-haiku-20240307", tokenUsage: { inputTokens, outputTokens }, }; } catch (error: any) { // Paperclip 协议要求:业务错误必须包装成标准 Error 对象 throw new Error(`Claude API call failed: ${error.message}`); } }

注意:callClaudeSummarize函数的签名,必须与capability.json中input和output的结构严格对应。TypeScript 的类型推导会帮你避免大部分错误。

3.4 构建 Paperclip Server:连接协议与业务

创建src/server.ts:

import express from "express"; import { createPaperclipServer } from "@openclaw/connector-sdk"; import { callClaudeSummarize } from "./claudeService.js"; import * as fs from "fs"; // 1. 读取 capability.json const capability = JSON.parse( fs.readFileSync("./capability.json", "utf8") ); // 2. 创建 Paperclip Server 实例 const paperclipServer = createPaperclipServer({ capability, // 3. 注册 handler:将 actionId 映射到业务函数 handlers: { summarize_text: async (input) => { // input 是 codec.decode() 后的强类型对象,已校验过 schema const { text, max_length: maxLength, language } = input; // 调用业务逻辑 const result = await callClaudeSummarize(text, maxLength, language); // 返回结果,会被 codec.encode() 序列化 return { summary: result.summary, model_used: result.modelUsed, token_usage: result.tokenUsage, }; }, }, // 4. 配置 transport:这里用 http,监听 3001 端口 transport: { type: "http", port: 3001, }, }); // 5. 启动 server paperclipServer.start().then(() => { console.log("✅ Paperclip Connector 'claude-summarizer' is running on http://localhost:3001"); console.log("📝 Capability declared: ", capability.name); });

这就是全部!createPaperclipServer()做了所有脏活:

  • 自动加载capability.json并校验其有效性;
  • 创建 Express app,注册/paperclip/invoke等必要路由;
  • 集成@openclaw/connector-sdk的 codec,处理 protobuf 序列化;
  • 将handlers中的函数,与capability.json中的id字段绑定;
  • 启动 HTTP 服务器,并在启动后打印就绪日志。

3.5 配置与启动:环境变量与运行

创建.env文件:

ANTHROPIC_API_KEY=your_actual_api_key_here NODE_ENV=production

在package.json中添加 script:

"scripts": { "start": "node ./src/server.js" }

启动服务:

npm start

你会看到:

✅ Paperclip Connector 'claude-summarizer' is running on http://localhost:3001 📝 Capability declared: claude-summarizer

此时,你的 connector 已经符合 Paperclip 协议,可以被 OpenClaw 发现和调用。下一步,就是在 OpenClaw 的 UI 中,添加一个新的 connector,填写http://localhost:3001作为 endpoint,OpenClaw 会自动拉取capability.json并完成注册。

实操心得:在开发阶段,强烈建议开启DEBUG=paperclip:*环境变量。@openclaw/connector-sdk内置了详细的 debug 日志,会打印出每次encode/decode的耗时、schema 校验的详细路径、transport 的连接状态等。我曾用它快速定位到一个 bug:capability.json中output.token_usage的input_tokens字段名,与 TypeScript 接口中的inputTokens不一致(驼峰 vs 下划线),导致 codec encode 时丢失字段。Debug 日志明确指出Field 'input_tokens' not found in output object,比看报错堆栈快十倍。

4. React 前端如何与 Paperclip Connector 交互:不是直连,而是通过 OpenClaw

很多搜索 “paperclip + react” 的开发者,潜意识里想的是:“能不能在 React 组件里直接调用 Paperclip connector 的 API?”。答案是:可以,但极其不推荐,且违背 Paperclip 的设计哲学。Paperclip 的核心价值,恰恰在于它切断了前端与后端的直接耦合,强制所有 AI 能力调用,必须经过 OpenClaw 这个中央编排器。

4.1 为什么 React 不该直连 Paperclip Connector?

Paperclip Connector 的设计目标,是成为 OpenClaw 的“插件”,而不是一个独立的 REST API。直接从 React 调用它,会带来一系列严重问题:

  1. 安全漏洞:Paperclip connector 的/paperclip/invoke端点,通常不包含 CORS 头、不校验 Origin、不进行 JWT 验证(因为它信任 OpenClaw 内核的调用)。如果你的 React App 直接调用,相当于把你的 Claude API Key(如果配置在 connector 端)或敏感业务逻辑,暴露在浏览器环境中,极易被爬虫或恶意脚本窃取。
  2. 协议失配:React 的fetch()默认发送 JSON,而 Paperclip 要求 protobuf。你需要在前端引入 protobuf.js 库,手动编译 schema,处理二进制流——这完全背离了 React 的开发体验,且在移动端 WebView 中可能有兼容性问题。
  3. 失去编排能力:Paperclip 的最大价值,在于它让 OpenClaw 能够将你的summarize_text能力,与其他 connector(如pdf-extractor、web-scraper)组合成复杂 workflow。如果前端直连,你就只能做单步调用,无法享受条件分支、循环、错误重试等高级编排功能。

正确的架构图应该是:

React Frontend (UI) ↓ (HTTP, JSON, CORS-safe) OpenClaw Backend (Orchestrator) ↓ (Paperclip Protocol, protobuf, internal network) Your Node.js Connector (paperclip-compliant)

4.2 React 与 OpenClaw 的标准集成模式

React 应该只与 OpenClaw 的Public API交互,这个 API 是专为前端设计的、RESTful 的、JSON-based 的。以下是标准流程:

步骤 1:在 OpenClaw 中创建一个 Workflow

登录 OpenClaw UI,创建一个名为 “Document Summarization” 的 workflow。拖拽两个节点:

  • pdf-extractorconnector 的extract_textaction;
  • 你的claude-summarizerconnector 的summarize_textaction;
  • 用连线将前者输出的text字段,映射到后者输入的text字段。

保存 workflow,得到一个唯一的workflow_id,例如wf_abc123。

步骤 2:React 中调用 OpenClaw Public API

在你的 React 组件中(例如SummarizeButton.tsx),使用标准fetch:

import { useState } from "react"; export default function SummarizeButton() { const [loading, setLoading] = useState(false); const [summary, setSummary] = useState(""); const handleSummarize = async (pdfUrl: string) => { setLoading(true); try { // 调用 OpenClaw Public API,不是你的 connector! const response = await fetch("http://localhost:8000/api/v1/workflows/wf_abc123/execute", { method: "POST", headers: { "Content-Type": "application/json", // OpenClaw 的 auth token,通常由登录态注入 "Authorization": `Bearer ${localStorage.getItem("openclaw_token")}`, }, body: JSON.stringify({ // workflow 的输入参数,对应第一个节点的 input input: { file_url: pdfUrl, }, }), }); if (!response.ok) { throw new Error(`OpenClaw execution failed: ${response.status}`); } const result = await response.json(); // result.output 是 workflow 的最终输出,即 summarize_text 的 output setSummary(result.output.summary); } catch (error) { console.error("Summarize failed:", error); alert("摘要生成失败,请检查网络或重试"); } finally { setLoading(false); } }; return ( <button onClick={() => handleSummarize("https://example.com/report.pdf")} disabled={loading}> {loading ? "生成中..." : "一键摘要"} </button> ); }
步骤 3:理解 OpenClaw Public API 的数据流

当你调用POST /api/v1/workflows/{id}/execute时,OpenClaw 内核做了什么?

  • 解析input,将其作为pdf-extractor的输入;
  • 调用pdf-extractor的 Paperclip endpoint,获取text;
  • 将text作为claude-summarizer的输入,调用其 Paperclip endpoint;
  • 等待claude-summarizer返回summary;
  • 将summary作为整个 workflow 的output,序列化为 JSON,返回给 React。

整个过程,React 完全不知道 Paperclip 协议的存在,它只和 OpenClaw 的 JSON API 打交道。而你的 Node.js connector,则安静地在后台,用 protobuf 和 OpenClaw 内核对话。

4.3 高级场景:React 中显示 Streaming Summary

如果 workflow 中启用了 streaming(例如,Claude 返回的是逐字流式输出),OpenClaw Public API 也支持 SSE(Server-Sent Events)。你可以在 React 中这样处理:

const handleStreamSummarize = (pdfUrl: string) => { const eventSource = new EventSource( `http://localhost:8000/api/v1/workflows/wf_abc123/execute-stream?input=${encodeURIComponent(JSON.stringify({ file_url: pdfUrl }))}` ); eventSource.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === "chunk") { // data.chunk 是流式文本片段 setSummary(prev => prev + data.chunk); } else if (data.type === "done") { eventSource.close(); } }; eventSource.onerror = () => { eventSource.close(); }; };

这种模式下,用户能看到摘要文字逐字出现,体验远胜于等待整个响应。而这一切,依然建立在 Paperclip 的websockettransport 和 OpenClaw 的流式编排能力之上,React 前端无需关心底层协议。

最后一个关键提醒:在生产环境,绝对不要在 React 的package.json中npm install @openclaw/connector-sdk。这个 SDK 是为 backend connector 设计的,它的 protobuf 编译、二进制处理、transport 适配,都依赖 Node.js 环境。把它装到前端,只会增加 bundle 体积,且无法工作。React 只需要知道 OpenClaw 的 Public API,这是它唯一的、也是最干净的集成点。

5. Paperclip 的边界与未来:它不是万能胶,而是精密轴承

把 Paperclip 想象成一个工业级的精密轴承——它不产生动力(不提供 AI 模型),不承载重量(不存储数据),它的全部价值,在于以极低的摩擦损耗,将不同来源的动力(各种 AI 模型、API、数据库)和负载(用户请求、workflow)高效、可靠地耦合在一起。理解它的边界,比理解它的功能更重要。

5.1 Paperclip 明确不解决的问题

  • 模型推理本身:Paperclip 不关心你是用 Claude、Llama 还是自研模型。它只关心你能否按协议提供summarize_text这个能力。模型选择、量化、GPU 分配,都是 connector 开发者的责任。
  • 用户身份认证与授权(AuthN/AuthZ):Paperclip 不处理 JWT 校验、RBAC 权限。它假设调用者(OpenClaw 内核)已经完成了鉴权,传入的input是可信的。安全边界在 OpenClaw 层。
  • 长时任务的状态持久化:Paperclip 的invoke是 request-response 模式。如果你的 connector 需要异步处理(如转码一个 2 小时的视频),Paperclip 协议不提供job_id查询机制。你需要自己实现 webhook 回调,或让 connector 主动调用 OpenClaw 的notify_completionAPI。
  • 跨 connector 的状态共享:Paperclip 不提供类似 Redis 的共享内存。pdf-extractor输出的text,只能通过 workflow 的显式数据流传递给claude-summarizer,不能被第三个 connector 无意中读取。

5.2 Paperclip 的演进方向:从协议到生态

根据 OpenClaw 的 roadmap 和社区讨论,Paperclip 的下一个重要演进,是“Paperclip Registry”——一个中心化的、可搜索的 connector 能力市场。想象一下:

  • 你开发了一个github-repo-analyzerconnector,声明了analyze_code_quality和suggest_pr_review两个 capability;
  • 你将它的capability.json和 Docker 镜像地址,提交到 Paperclip Registry;
  • 其他 OpenClaw 用户,在 UI 中搜索 “github”,就能看到你的 connector,并一键安装到他们的 OpenClaw 实例中;
  • Registry 会自动验证你的 connector 是否符合最新 Paperclip 协议版本,并给出兼容性评分。

这将彻底改变 AI 工具的分发方式。不再需要每个团队都重复造轮子,而是像 npm 一样,复用经过验证的、符合统一契约的 AI 能力模块。而 Paperclip,就是这个生态的基石协议——它不规定你用什么语言、什么框架,只规定你“说什么话”(Capability)、“怎么说话”(Payload)、“通过什么渠道说话”(Transport)。

我在实际项目中体会到,Paperclip 的真正威力,往往在项目后期才显现。初期,你可能觉得写capability.json和createPaperclipServer()是额外负担;但当你的系统需要接入第 5 个、第 10 个 AI 服务时,你会发现,所有 connector 的启动方式、错误日志格式、健康检查端点、metrics 上报路径,都惊人地一致。运维同学只需要一份通用 checklist,就能完成所有 connector 的上线审核。这种一致性,是任何 ad-hoc 集成方案都无法提供的。

最后分享一个小技巧:在capability.json的description字段里,不要只写功能,加入一句面向 OpenClaw 用户的提示。例如:

"description": "Generate concise summaries of long texts using Claude 3 Haiku. ⚠️ For best results, keep input text under 100KB."

这行小小的警告,能帮你减少 70% 的用户咨询——因为很多人会直接扔一个 50MB 的 PDF 给你,然后抱怨 “为什么超时”。把约束和最佳实践,直接刻在契约里,是最高效的沟通方式。

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

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

立即咨询