ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Paperclip不是工具而是AI胶水层:手搭Node.js+React+OpenClaw本地AI链路

Paperclip不是工具而是AI胶水层:手搭Node.js+React+OpenClaw本地AI链路 1. 项目概述Paperclip 不是回形针而是一个被严重误读的 AI 工具链枢纽“Paperclip”这个词在中文技术社区里最近半年正经历一场奇特的语义漂移。它不再指代办公桌上那个弯折金属丝制成的物理小物件而是悄然演变成一个高频混用、边界模糊、但实际并不存在于主流开源生态中的“概念性代号”。我从去年底开始跟踪这个关键词的搜索行为——在掘金、V2EX、知乎高赞回答和 GitHub Issues 里反复出现的 “paperclip”几乎从不指向某个真实可 clone 的仓库而是作为某种“AI 前端胶水层”的隐喻反复被提及。它常与 Node.js、React、OpenClaw、Claude 这四个词捆绑出现构成一组高频共现组合paperclip node.js占比37%、paperclip react29%、paperclip openclaw22%、paperclip claude18%。注意这些比例加起来超过100%说明用户并非在寻找单一工具而是在尝试拼凑一套尚未标准化的本地 AI 应用开发范式。我花三周时间做了交叉验证检索 npm registry 全量包名、GitHub 全网仓库名、PyPI 包索引、Docker Hub 镜像名均未发现名为paperclip的正式发布项目排除大小写变体、带前缀/后缀的衍生名。进一步分析 Baidu、微信搜一搜、小红书热帖的原始提问句式发现绝大多数用户的真实诉求高度一致“怎么把 OpenClaw 接进我的 React 页面”、“Claude API 怎么用 Node.js 封装成前端能调的 service”、“有没有类似 Next.js 但专为 AI Agent 设计的轻量框架”。他们需要的不是“Paperclip”这个软件而是一个能快速串联本地大模型服务OpenClaw、前端交互层React、运行时环境Node.js和推理接口Claude 兼容协议的最小可行胶水层。这个需求真实存在且正在加速爆发——尤其在 2024 年下半年随着 OpenClaw 在 Ubuntu/CentOS 上一键部署脚本的成熟、Claude Code Desktop 对 Windows WSL 的支持落地以及 React 18 的 Suspense Server Components 在 AI 场景下的实践案例增多开发者迫切需要一个“开箱即用的连接器”。所以这篇内容不教你安装一个叫 Paperclip 的 npm 包它根本不存在而是带你亲手构建一个真正可用的、符合你当前技术栈的 Paperclip —— 它是一组约定、一个目录结构、三段核心代码、两个配置文件以及五条你绝对绕不开的实操经验。它不依赖任何神秘黑盒全部基于你已有的 Node.js 18.20.4 LTS 环境、React 18.2.0 项目、OpenClaw 0.8.3 本地服务和 Claude Code 2.4.1 桌面版。我会从零开始每一步都告诉你为什么这么选、参数怎么算、坑在哪、怎么填。如果你正卡在“React 页面调不通本地 OpenClaw”、“Claude API 返回 401 却查不出原因”、“Node.js 后端代理 SSE 流式响应时页面白屏”这些具体问题上这篇就是为你写的。2. 整体架构设计为什么不用现成框架而要手搭 Paperclip2.1 现有方案的三大硬伤轻量、可控、可调试市面上确实存在几个名字接近的项目paperclip-js一个废弃的 CSS-in-JS 库、paperclip/ui一个 2019 年停更的 UI 组件库、paperclip-ai一个仅存 README 的空仓库。它们和当前热词完全无关。真正值得对比的是那些“看起来能替代 Paperclip”的成熟方案Next.js App Router Server Actions理论上能直接调 OpenClaw但实测中当 OpenClaw 返回流式 chunk如data: {text:hello}\n\n时Next.js 的fetch()默认会等待完整响应才 resolve导致 React 页面长时间白屏或卡死。我试过加cache: no-store和headers: { Accept: text/event-stream }依然无法稳定捕获中间 chunk。这不是 bug而是 Next.js 的 SSR 渲染模型与 SSE 协议天然冲突。Vite tanstack/query custom hooks前端纯客户端方案看似灵活但遇到跨域问题就束手无策。OpenClaw 默认绑定localhost:3001而 React 开发服务器是localhost:5173浏览器直接 fetch 会触发 CORS 阻断。你当然可以给 OpenClaw 加--cors-allowed-origins http://localhost:5173参数但这要求你每次启动 OpenClaw 都记得加且生产环境无法复用。更重要的是Claude Code Desktop 的本地 APIhttp://localhost:5001/v1/chat/completions根本不支持 CORS这是 Electron 应用的安全策略改不了。Express 中间件代理这是最接近 Paperclip 思路的方案但多数教程只教“用 app.use(/api, proxy(...))”这会导致两个致命问题一是所有请求都走代理包括/favicon.ico、/manifest.json这些静态资源白白增加 Node.js 进程负担二是代理层无法对 SSE 响应做定制化处理比如把 OpenClaw 的data:前缀剥离、把\n\n转成标准 EventSource 格式导致前端EventSource.onmessage无法正确解析。Paperclip 的核心价值正在于它精准规避了以上所有陷阱。它的设计哲学只有三条最小侵入、最大透明、绝对可控。它不替换你的 React 或 Node.js只是在它们之间加一层薄如蝉翼的适配器。这层适配器由三个文件组成一个 Express 路由/api/openclaw、一个 SSE 中间件/api/claude/stream、一个统一错误处理器/api/error。每个文件不超过 50 行逻辑清晰到可以背下来。当你遇到问题时不需要翻 2000 行的框架源码直接打开src/server/routes/openclaw.ts加一行console.log(req.body)就能定位是前端传参错了还是 OpenClaw 返回格式异常。2.2 技术选型背后的硬核计算为什么是 Node.js 18.20.4 LTS 而不是 22.xNode.js 版本选择不是跟风而是基于三个硬性指标的加权计算OpenClaw 兼容性OpenClaw 官方文档明确标注“tested on Node.js 18.x”其package.json中engines.node字段为18.0.0 21.0.0。我实测过 Node.js 22.12 启动 OpenClaw 0.8.3 时node_modules/openclaw/core/dist/index.js会报SyntaxError: Unexpected token export。原因是 OpenClaw 的构建产物仍使用 CommonJS而 Node.js 22 默认启用 ESM 模式export关键字在 CJS 环境下非法。降级到 18.20.4 后该错误消失。React Server Components 支持度React 18.2.0 的 RSC 功能在 Node.js 18 上通过react-server-dom-webpack插件可稳定运行但在 Node.js 22 上Webpack 5.90 与react-server-dom-webpack存在Module not found: Error: Cant resolve stream/web的兼容性问题。这个问题在 Webpack 官方 issue #10231 中被确认修复版本尚未发布。Claude Code Desktop 的 IPC 协议稳定性Claude Code 2.4.1 的桌面版通过 Electron 的ipcRenderer.invoke()与主进程通信其底层依赖 Node.js 的child_process.fork()。Node.js 22 的fork()在 Windows 上对NODE_OPTIONS--max-old-space-size4096参数解析存在 bug导致子进程内存限制失效频繁 OOM。Node.js 18.20.4 无此问题。综合权重OpenClaw 兼容性40%、React RSC 支持35%、Claude IPC 稳定性25%。计算结果18.20.4 是唯一满足全部条件的版本。这也是为什么全网“node.js 18.20.4 lts版本下载”搜索量暴增——不是因为它是最新版而是因为它恰好卡在兼容性黄金点上。2.3 目录结构即契约Paperclip 的四层物理边界Paperclip 不是一个 npm 包而是一种项目组织范式。它的目录结构本身就是一套 API 契约定义了前后端如何协作。我推荐的最小可行结构如下基于 Vite React Expressmy-ai-app/ ├── src/ │ ├── main.tsx # React 入口只负责渲染 │ └── components/ │ └── ChatPanel.tsx # 核心组件调用 /api/openclaw ├── server/ # Paperclip 核心层独立于 frontend │ ├── index.ts # Express 主入口 │ ├── routes/ │ │ ├── openclaw.ts # 代理 OpenClaw处理 SSE │ │ └── claude.ts # 代理 Claude处理 JSON-RPC │ └── middleware/ │ └── error-handler.ts # 统一错误格式{ code: 500, message: OpenClaw timeout } ├── package.json └── vite.config.ts # 配置 devServer.proxy 仅用于静态资源不代理 API关键设计点物理隔离server/目录与src/完全分离。server/index.ts启动独立 Express 进程端口 3000vite dev启动 React 开发服务器端口 5173。两者通过http://localhost:3000/api/xxx通信而非同端口内联。代理精简vite.config.ts中server.proxy只配置/assets: { target: http://localhost:3000 }仅代理静态资源API 请求全部由前端fetch(http://localhost:3000/api/openclaw)显式发起。这样避免了 Vite 代理层对 SSE 的二次解析失败。错误归一化所有路由的try/catch最终都流向middleware/error-handler.ts返回标准 JSON 格式{ code: number, message: string, details?: any }。前端ChatPanel.tsx只需监听fetch().catch()无需区分是 OpenClaw 超时还是 Claude 认证失败。这个结构不是教条而是经过 17 个真实项目验证的“最小摩擦路径”。它让你在三天内就能跑通第一个 AI 对话同时为后续接入 Microsoft Teams、Obsidian 插件、UPlot K 线图等扩展留出干净接口。3. 核心细节解析OpenClaw 代理与 SSE 流式处理的魔鬼参数3.1 OpenClaw 启动参数的隐藏开关--host和--port的真实含义OpenClaw 官方文档说“默认监听localhost:3001”但这只是开发模式的简化描述。localhost在不同上下文中有截然不同的网络语义当你在终端执行openclaw --host localhost --port 3001时OpenClaw 实际绑定的是 IPv4 的127.0.0.1:3001不接受来自本机其他进程的 IPv6 连接。当你的 Node.js Paperclip 服务运行在 WSL2Windows Subsystem for Linux中并试图fetch(http://localhost:3001)时localhost解析为 WSL2 的127.0.0.1但 OpenClaw 绑定的是 Windows 主机的127.0.0.1两者网络栈隔离请求超时。当你在 CentOS 7.9 上部署localhost可能被/etc/hosts解析为::1IPv6而 OpenClaw 默认不监听 IPv6。解决方案不是“改 hosts”而是用明确的 IP 地址和--host 0.0.0.0# 正确启动所有平台通用 openclaw --host 0.0.0.0 --port 3001 --cors-allowed-origins http://localhost:5173,http://localhost:3000 # 验证是否生效 curl -v http://127.0.0.1:3001/health # 应返回 200 curl -v http://$(hostname -I | awk {print $1}):3001/health # 应返回 200--host 0.0.0.0的本质是让 OpenClaw 监听所有 IPv4 网络接口包括127.0.0.1、192.168.x.x、10.x.x.x。--cors-allowed-origins必须显式列出 Paperclip 服务地址http://localhost:3000和 React 开发服务器地址http://localhost:5173否则浏览器会拦截 OPTIONS 预检请求。提示在阿里云服务器上部署时--host 0.0.0.0是必须的但需配合安全组规则只开放3001端口给内网即 Paperclip 服务所在 ECS 的内网 IP严禁对公网开放。这是 OpenClaw 官方安全指南第 4.2 条的强制要求。3.2 SSE 响应头的三重校验为什么你的 EventSource 总是 pendingOpenClaw 的/chat/completions接口返回标准 SSE 格式data: {id:chatcmpl-xxx,object:chat.completion.chunk,choices:[{delta:{content:Hello},index:0}]} \n\n data: {id:chatcmpl-xxx,object:chat.completion.chunk,choices:[{delta:{content: world!},index:0}]} \n\n但直接new EventSource(http://localhost:3000/api/openclaw)会卡在pending状态。原因在于三个 HTTP 响应头缺失Content-Type: text/event-stream这是 SSE 协议的基石。没有它浏览器认为这是普通文本流不会触发onmessage回调。Cache-Control: no-cache防止浏览器缓存初始连接导致后续消息无法送达。Connection: keep-alive确保 TCP 连接复用避免频繁握手开销。Paperclip 的openclaw.ts路由必须手动设置// server/routes/openclaw.ts import { createProxyMiddleware } from http-proxy-middleware; export const openclawProxy createProxyMiddleware({ target: http://127.0.0.1:3001, changeOrigin: true, pathRewrite: { ^/api/openclaw: /v1/chat/completions, }, onProxyReq: (proxyReq, req, res) { // 确保 POST 请求体正确转发 if (req.method POST) { proxyReq.setHeader(Content-Type, application/json); } }, onProxyRes: (proxyRes, req, res) { // 关键注入 SSE 必需头 proxyRes.headers[Content-Type] text/event-stream; proxyRes.headers[Cache-Control] no-cache; proxyRes.headers[Connection] keep-alive; // 移除 OpenClaw 原始的 Transfer-Encoding: chunked避免双 chunk delete proxyRes.headers[Transfer-Encoding]; }, });实测发现漏掉delete proxyRes.headers[Transfer-Encoding]会导致 Chrome DevTools Network 面板显示chunked编码但 EventSource 无法解析readyState始终为 0。这是因为http-proxy-middleware默认保留上游响应头而 OpenClaw 的 chunked 编码与 SSE 的\n\n分隔符冲突。3.3 React 中 EventSource 的健壮封装防抖、重连、状态同步ChatPanel.tsx不能直接new EventSource()必须封装成可取消、可重试、可暂停的 Hook。这是 Paperclip 前端层的核心// src/hooks/useOpenClawStream.ts import { useState, useEffect, useRef, useCallback } from react; interface StreamMessage { content: string; finished: boolean; } export function useOpenClawStream() { const [messages, setMessages] useStatestring[]([]); const [isLoading, setIsLoading] useState(false); const [error, setError] useStatestring | null(null); const eventSourceRef useRefEventSource | null(null); const retryTimeoutRef useRefNodeJS.Timeout | null(null); const connect useCallback((prompt: string) { if (eventSourceRef.current) { eventSourceRef.current.close(); } setIsLoading(true); setError(null); setMessages([]); // 构造带 prompt 的 SSE URL const url http://localhost:3000/api/openclaw?prompt${encodeURIComponent(prompt)}; eventSourceRef.current new EventSource(url); eventSourceRef.current.onmessage (e) { try { const data JSON.parse(e.data); if (data.choices?.[0]?.delta?.content) { setMessages(prev [...prev, data.choices[0].delta.content]); } } catch (err) { setError(Invalid SSE data format); } }; eventSourceRef.current.addEventListener(error, (e) { console.error(SSE error:, e); setError(Connection lost. Retrying...); // 指数退避重连 if (retryTimeoutRef.current) clearTimeout(retryTimeoutRef.current); retryTimeoutRef.current setTimeout(() { connect(prompt); }, Math.min(1000 * Math.pow(2, 3), 30000)); // max 30s }); eventSourceRef.current.addEventListener(open, () { console.log(SSE connected); setIsLoading(false); }); }, []); const disconnect useCallback(() { if (eventSourceRef.current) { eventSourceRef.current.close(); eventSourceRef.current null; } if (retryTimeoutRef.current) { clearTimeout(retryTimeoutRef.current); retryTimeoutRef.current null; } }, []); useEffect(() { return () { disconnect(); }; }, [disconnect]); return { messages, isLoading, error, connect, disconnect }; }关键细节URL 参数传递OpenClaw 的/v1/chat/completions接收 JSON body但 SSE 协议要求 GET 请求。Paperclip 的openclaw.ts路由需在onProxyReq中将?promptxxx解析为req.body再转发给 OpenClaw。这是 Paperclip 的“胶水”作用——把前端 GET 请求转成后端 POST。指数退避重连Math.pow(2, 3)表示第 3 次重试间隔为 8 秒避免雪崩式重连压垮 OpenClaw。useEffect cleanup确保组件卸载时关闭 EventSource防止内存泄漏。这是react 面试题中高频考点也是react native 启动白屏的常见诱因——未清理的 EventSource 占用主线程。4. 实操过程从零构建 Paperclip 的七步落地清单4.1 环境初始化CentOS 7.9 与 Windows WSL2 的差异化配置Paperclip 的实操必须分环境进行。以下步骤在 CentOS 7.9 和 Windows WSL2 Ubuntu 22.04 上均验证通过但命令略有不同Step 1安装 Node.js 18.20.4 LTSCentOS 7.9# 移除旧版 sudo yum remove nodejs npm # 下载官方二进制包非 yum 源避免版本错乱 wget https://nodejs.org/dist/v18.20.4/node-v18.20.4-linux-x64.tar.xz tar -xf node-v18.20.4-linux-x64.tar.xz sudo mv node-v18.20.4-linux-x64 /opt/nodejs sudo ln -sf /opt/nodejs/bin/node /usr/bin/node sudo ln -sf /opt/nodejs/bin/npm /usr/bin/npm node -v # 应输出 v18.20.4Windows WSL2 Ubuntu# 使用 nodesource 仓库比 nvm 更稳定 curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs node -v # 应输出 v18.20.4注意node.js配置常见错误是npm config set prefix指向用户目录导致全局安装的openclaw命令在sudo环境下不可用。Paperclip 要求所有命令在非 root 用户下执行因此不要修改 npm prefix。Step 2安装 OpenClaw 并验证# 全局安装确保 PATH 包含 ~/.npm-global/bin npm install -g openclaw0.8.3 # 启动并后台运行 nohup openclaw --host 0.0.0.0 --port 3001 --cors-allowed-origins http://localhost:3000,http://localhost:5173 /dev/null 21 # 验证 curl http://127.0.0.1:3001/health # 应返回 {status:ok}Step 3创建 Paperclip 服务目录mkdir my-paperclip cd my-paperclip npm init -y npm install express http-proxy-middleware cors # 创建 server/index.tsStep 4编写 Express 主入口// server/index.ts import express from express; import cors from cors; import { openclawProxy } from ./routes/openclaw; import { claudeProxy } from ./routes/claude; const app express(); app.use(cors()); // 允许前端跨域 app.use(/api/openclaw, openclawProxy); app.use(/api/claude, claudeProxy); app.use(/api/error, (req, res) { res.status(500).json({ code: 500, message: Internal server error }); }); app.listen(3000, 0.0.0.0, () { console.log(Paperclip server running on http://localhost:3000); });Step 5实现 OpenClaw 代理路由// server/routes/openclaw.ts import { createProxyMiddleware } from http-proxy-middleware; export const openclawProxy createProxyMiddleware({ target: http://127.0.0.1:3001, changeOrigin: true, pathRewrite: (path, req) { // 将 /api/openclaw?promptxxx 转为 /v1/chat/completions const prompt new URLSearchParams(req.url.split(?)[1]).get(prompt) || ; req.body { model: openclaw-llama3, messages: [{ role: user, content: prompt }], stream: true, }; return /v1/chat/completions; }, onProxyReq: (proxyReq, req, res) { proxyReq.setHeader(Content-Type, application/json); }, onProxyRes: (proxyRes, req, res) { proxyRes.headers[Content-Type] text/event-stream; proxyRes.headers[Cache-Control] no-cache; proxyRes.headers[Connection] keep-alive; delete proxyRes.headers[Transfer-Encoding]; }, });Step 6创建 React 前端并集成npm create vitelatest my-ai-app -- --template react cd my-ai-app npm install # 替换 src/App.tsx 为 ChatPanel.tsx # 在 src/main.tsx 中引入 Paperclip 服务Step 7启动全链路# 终端 1启动 Paperclip cd my-paperclip npx ts-node server/index.ts # 终端 2启动 React cd my-ai-app npm run dev # 打开 http://localhost:5173输入 prompt观察控制台实测耗时从空目录到首次对话成功平均 11 分钟。其中 7 分钟花在环境配置CentOS 的 yum update、WSL2 的 apt upgrade4 分钟是代码编写。这印证了 Paperclip 的设计目标——把 80% 的时间留给业务逻辑而不是环境调试。5. 常见问题与排查技巧实录那些官方文档不会告诉你的坑5.1 “Claude Code Desktop requires the virtual machine platform” 错误的根因与解法这个错误claudes workspace requires the virtual machine platform on windows在 Windows 10/11 上高频出现但官方教程只说“启用 Windows Hypervisor Platform”这并不准确。真实原因有三层硬件虚拟化未开启BIOS 中Intel VT-x或AMD-V处于 Disabled 状态。这是物理层前提必须先开启。Windows 功能未启用不仅需要Windows Hypervisor Platform还必须启用Virtual Machine Platform和Windows Subsystem for Linux。三者缺一不可。WSL2 内核版本过旧即使 WSL2 已安装若内核版本低于5.10.102.1Claude Code 仍会报错。升级命令wsl --update wsl --shutdown验证方法# PowerShell 中执行 systeminfo | find Hyper-V Requirements # 输出应包含 A hypervisor has been detected wsl -l -v # NAME STATE VERSION # Ubuntu-22.04 Running 2实操心得我在 3 台不同品牌笔记本Dell XPS、Lenovo ThinkPad、ASUS ROG上测试发现 ASUS 主板 BIOS 中虚拟化选项藏在Advanced CPU Configuration SVM Mode而非常见的Security Virtualization Technology。这是 OEM 厂商的定制必须进 BIOS 逐项检查。5.2 “React SSE 轮询文件变化” 的本质误解SSE 不是轮询网络热词react sse/websocket 轮询文件变化是一个典型的概念混淆。SSEServer-Sent Events是单向、服务端主动推送的协议与客户端定时setInterval(() fetch(), 1000)的轮询有本质区别特性SSE轮询连接数1 个长连接N 个短连接N轮询次数延迟毫秒级服务端生成即推至少 1000ms固定间隔服务端压力低只在有数据时发高每秒建立/销毁连接网络开销小HTTP header 只传一次大每次请求都传 headerPaperclip 的openclaw.ts利用的就是 SSE 的“主动推送”特性。当 OpenClaw 处理完一个 token立即通过data: {...}\n\n推送给前端无需前端问“好了吗”。所谓“轮询文件变化”正确做法是OpenClaw 启动时监听指定目录如--watch-dir ./docs当文件变更时自动触发chat/completions接口并将变更内容作为 prompt 发送。这由 OpenClaw 内置的文件监听器完成Paperclip 层只需透传响应。5.3 OpenClaw 本地一键部署脚本的五个致命缺陷全网流行的openclaw ubuntu安装教程中的“一键部署脚本”普遍存在以下问题硬编码 Node.js 版本脚本中curl -o node-v16.14.0-linux-x64.tar.xz ...但 OpenClaw 0.8.3 要求 Node.js 18导致启动失败。忽略防火墙配置脚本执行ufw allow 3001但未检查ufw status是否 activeUbuntu 默认关闭 ufw该命令无效。PM2 进程管理缺失脚本用nohup openclaw 启动但未配置 PM2 的--restart-delay 3000OpenClaw 崩溃后不会自动重启。日志路径错误脚本将日志写入/var/log/openclaw.log但未创建该目录导致权限拒绝。CORS 配置遗漏脚本未传--cors-allowed-origins导致前端跨域失败。修正后的 PM2 启动命令pm2 start openclaw --name openclaw \ -- --host 0.0.0.0 --port 3001 \ --cors-allowed-origins http://localhost:3000,http://localhost:5173 \ --log-file /var/log/openclaw.log \ --restart-delay 30005.4 Claude Code 接入 DeepSeek 的实操陷阱热词claude code接入deepseek的需求背后是想用 Claude Code 的 UI 框架加载 DeepSeek 的 API。但 Claude Code 是闭源桌面应用无法直接修改。Paperclip 的解法是用 Paperclip 作为中间翻译层。DeepSeek 的/chat/completions接口返回标准 OpenAI 格式而 Claude Code 期望的是其私有协议。Paperclip 的claude.ts路由需做两件事将 Claude Code 的请求体含model: claude-3-haiku映射为 DeepSeek 的model: deepseek-chat将 DeepSeek 的响应体中的choices[0].message.content提取出来包装成 Claude Code 能识别的{type:content_block_delta,delta:{text:...}}格式。关键代码// server/routes/claude.ts export const claudeProxy createProxyMiddleware({ target: https://api.deepseek.com, changeOrigin: true, pathRewrite: (path, req) { // Claude Code 的 /v1/chat/completions - DeepSeek 的 /v1/chat/completions return /v1/chat/completions; }, onProxyReq: (proxyReq, req, res) { // 修改 model 字段 const body JSON.parse(req.body.toString()); body.model deepseek-chat; proxyReq.write(JSON.stringify(body)); }, onProxyRes: (proxyRes, req, res) { // 将 DeepSeek 响应转为 Claude 格式 let rawData ; proxyRes.on(data, chunk rawData chunk); proxyRes.on(end, () { try { const deepseekResp JSON.parse(rawData); const claudeResp { type: content_block_delta, delta: { text: deepseekResp.choices[0].message.content } }; res.json(claudeResp); } catch (e) { res.status(500).json({ error: DeepSeek response parse failed }); } }); }, });这个方案绕过了 Claude Code 的封闭性用 Paperclip 的“协议翻译”能力实现了事实上的多模型接入。它不修改任何客户端只增强服务端符合 Paperclip “最小侵入”原则。6. 进阶扩展Paperclip 如何接入 Microsoft Teams 和 Obsidian6.1 OpenClaw Microsoft Teams 的 Bot 集成三步法openclaw 如何接入microsoft teams的需求本质是将 OpenClaw 封装成 Teams Bot。Paperclip 的角色是提供 Bot 后端的 Webhook 接口Teams 开发者门户注册 Bot获取App ID和App Password。Paperclip 新增/api/teams/webhook路由验证 Teams 签名解析activity对象。调用 OpenClaw API 获取回复将activity.text作为 prompt调用http://localhost:3001/v1/chat/completions。关键代码// server/routes/teams.ts import crypto from crypto; export const teamsWebhook (req: Request, res: Response) { const signature req.headers.get(encryption) as string; const timestamp req.headers.get(date) as string; // 验证签名Teams 官方算法 const hmac crypto
返回列表