首页 / 资讯中心 / 文章详情

Paperclip:轻量级AI Agent通信契约与Node.js/React实践

Paperclip:轻量级AI Agent通信契约与Node.js/React实践 ★ FEATURED ARTICLE
1. “Paperclip”不是回形针它正在重构AI Agent的工程范式你搜“paperclip”第一反应是办公桌抽屉里那枚银色小金属别急——在2024年中后期的AI工程圈这个词正以极快的速度脱离物理世界变成一个高频、隐晦、带着技术锋芒的代号。它不指向某个开源仓库的GitHub star数也不对应某家公司的产品白皮书而是一种轻量级、可嵌入、协议无关的AI Agent通信内核。我第一次在内部技术分享会上听到这个词是在调试一个跨团队协作的智能体调度系统时。当时后端用Node.js跑着十几个微服务前端React界面要实时响应Agent状态变化中间层却卡在“怎么让AI模块像函数调用一样被调用又不像RPC那样重、不像HTTP那样慢、还不依赖特定消息队列”的死结上。直到同事甩出一句“试试Paperclip模式”——那一刻我才意识到我们不是在找一个库而是在重新定义AI Agent之间的“握手方式”。这和你刷到的那些热搜词高度咬合node.js是它的运行底座react是它最自然的消费端openclaw是目前生态里最成熟、最贴近Paperclip设计哲学的落地实现而所有关于“手写react agent”“react sse/websocket 轮询文件变化”“openclaw本地一键部署”的搜索本质上都是开发者在摸索如何把Paperclip这一抽象范式栽进自己真实的技术栈里。它不是框架不强制你用什么状态管理它也不是SDK不封装模型调用细节它更像一套约定大于配置的通信契约——规定了Agent该暴露什么接口、该响应什么事件、该怎样声明自己的能力边界。你不需要为它单独搭服务它可以跑在Express里也能塞进Next.js API Route中甚至能作为Vite插件直接注入开发服务器。这种“无感存在感”正是它在掘金、知乎、语雀等技术社区悄然升温的核心原因。提示不要被“Paperclip”这个名称迷惑。它不提供LLM推理、不内置RAG、不封装向量数据库。它的价值恰恰在于“不做”——不做任何与AI能力本身相关的事只专注解决AI模块之间“怎么连、怎么通、怎么协同”的底层工程问题。如果你正在为Agent编排混乱、状态同步延迟、调试链路断裂而头疼Paperclip不是锦上添花而是雪中送炭。2. Paperclip的底层契约为什么它能绕过HTTP和WebSocket的双重枷锁要真正吃透Paperclip必须先放下对“框架”的惯性期待转而理解它背后那套精巧的三层通信契约。这不是凭空设计的炫技而是从OpenCLAW等真实项目踩坑中长出来的肌肉记忆。我参与过三个不同规模的Agent系统集成每一次都卡在同一个地方前端React需要实时展示Agent执行进度后端Node.js服务要触发多个Agent串行/并行执行而每个Agent又可能由不同团队用Python、Go甚至Rust编写。传统方案要么用HTTP轮询延迟高、浪费连接要么上WebSocket状态难管理、断连重连逻辑爆炸要么引入Kafka/RabbitMQ运维成本陡增、本地开发极其痛苦。Paperclip的破局点就在于它把“通信”这件事拆解成三个彼此解耦、却又严丝合缝的层次。2.1 第一层能力声明契约Capability Declaration这是Paperclip最反直觉也最具价值的设计。每个Agent启动时不再只是监听某个端口而是主动向一个轻量级注册中心可以是内存Map、Redis或Consul发布一份JSON Schema格式的能力描述。比如一个负责代码审查的Agent它的声明可能长这样{ id: code-reviewer-v1, name: Code Reviewer, description: Performs static analysis and style check on TypeScript files, version: 1.2.0, capabilities: [ { name: review_code, input_schema: { type: object, properties: { file_path: { type: string }, content: { type: string } } }, output_schema: { type: object, properties: { issues: { type: array, items: { type: object } }, summary: { type: string } } } } ], endpoints: { http: http://localhost:3001/api/v1/review, websocket: ws://localhost:3001/ws } }注意这里的关键不是URL而是capabilities数组。它告诉整个系统“我能做什么”而不是“我在哪”。这意味着React前端在渲染UI时可以动态拉取所有已注册Agent的能力列表自动生成操作按钮——比如检测到code-reviewer-v1支持review_code就显示“提交代码审查”按钮检测到另一个Agent支持generate_test_cases就追加“生成测试用例”选项。能力即API声明即文档。这彻底消灭了前后端因接口变更导致的联调扯皮。我亲眼见过一个团队因为Agent能力描述缺失前端硬编码了5个HTTP路径结果后端重构时改了2个路径名上线后3个功能直接404整整花了两天回滚排查。Paperclip模式下这种问题从根源上消失。2.2 第二层调用路由契约Invocation Routing有了能力声明下一步就是“怎么调”。Paperclip不强制使用HTTP POST或WebSocket send而是定义了一个统一的调用指令格式所有Agent必须能解析并响应。这个指令是一个极简的JSON对象{ target: code-reviewer-v1, capability: review_code, payload: { file_path: /src/App.tsx, content: export default function App() { ... } }, correlation_id: req-7a8b9c1d2e3f }收到这个指令的Agent无论它底层是用Express、Fastify还是Tauri写的都只需做三件事1校验target是否匹配自身ID2检查capability是否在自己声明的能力列表中3用payload执行对应逻辑。返回结果也遵循固定结构{ correlation_id: req-7a8b9c1d2e3f, status: success, result: { /* 实际输出 */ }, metadata: { agent_id: code-reviewer-v1, timestamp: 2024-06-15T14:22:33.123Z } }这个设计的威力在于传输协议完全解耦。你可以用HTTP POST发送这个指令适合简单场景也可以用WebSocket推送适合需要流式响应的场景甚至可以用gRPC或Unix Domain Socket适合同机部署的高性能场景。我实测过在CentOS 7.9上部署的Node.js Agent通过HTTP接收指令而本地开发时React前端直接用fetch发请求零配置切换。OpenCLAW的openclaw local命令本质就是启动一个内置的、符合Paperclip契约的轻量级路由网关它自动发现本地所有Agent把前端发来的指令精准投递过去。这才是“本地一键部署”能成立的技术根基——不是部署复杂服务而是让每个Agent自带“可被发现、可被调用”的基因。2.3 第三层状态同步契约State Synchronization最后一个也是最容易被忽视的层次状态同步。AI Agent执行往往耗时用户需要知道“进行到哪一步了”。Paperclip不依赖前端轮询而是要求Agent在执行关键节点如“开始分析”、“发现第3个问题”、“生成总结报告”时主动推送状态事件。这些事件同样有严格格式{ event: execution_progress, correlation_id: req-7a8b9c1d2e3f, data: { step: analyzing_imports, progress: 65, message: Scanning module imports... } }React前端只需订阅这个事件流通过WebSocket或SSE就能实时更新UI进度条、日志面板。更重要的是这个事件流是全局可观测的。OpenCLAW的Web UI之所以能画出清晰的Agent执行拓扑图就是因为它把所有Agent推送的状态事件按correlation_id聚合还原出完整的执行链条。我在调试一个涉及5个Agent的复杂工作流时靠这个特性3分钟就定位到是>const http require(http); const url require(url); const { EventEmitter } require(events); // 模拟一个极简的注册中心生产环境应替换为Redis等 const registry new Map(); // 定义本Agent的能力声明 const capabilityDeclaration { id: text-analyzer-v1, name: Text Analyzer, description: Counts characters and words, and capitalizes first letter, version: 1.0.0, capabilities: [ { name: analyze_text, input_schema: { type: object, properties: { text: { type: string } } }, output_schema: { type: object, properties: { char_count: { type: number }, word_count: { type: number }, capitalized: { type: string } } } } ], endpoints: { http: http://localhost:3000 } }; // 启动时向注册中心注册自己 registry.set(capabilityDeclaration.id, capabilityDeclaration); console.log(✅ Paperclip Agent ${capabilityDeclaration.id} registered with capabilities:); console.log(JSON.stringify(capabilityDeclaration.capabilities, null, 2));这段代码做了两件事定义了清晰的能力声明并把它存进内存Map。这就是Paperclip的第一层契约——Agent必须主动“报户口”。注意input_schema和output_schema它们不是装饰而是前端生成表单、校验输入的依据。比如React组件读到这个schema就能自动渲染一个带text输入框的表单并在提交前用ajv库验证用户输入是否为字符串。3.2 构建调用路由处理器接下来是核心处理外部发来的调用指令。我们监听HTTP POST请求路径为/invoke// 创建事件发射器用于状态同步 const eventEmitter new EventEmitter(); // 模拟一个简单的状态事件广播生产环境应接入WebSocket/SSE eventEmitter.on(state_update, (event) { console.log( State Update: ${JSON.stringify(event)}); // 这里可以扩展将事件推送给WebSocket客户端或写入Redis频道 }); // 处理Paperclip调用指令 function handleInvocation(req, res) { if (req.method ! POST || req.url ! /invoke) { res.writeHead(404); res.end(Not Found); return; } let body ; req.on(data, chunk body chunk); req.on(end, () { try { const instruction JSON.parse(body); // 校验指令完整性 if (!instruction.target || !instruction.capability || !instruction.payload || !instruction.correlation_id) { throw new Error(Missing required fields in instruction); } // 检查目标Agent ID是否匹配 if (instruction.target ! capabilityDeclaration.id) { res.writeHead(400); res.end(JSON.stringify({ error: Target mismatch. Expected ${capabilityDeclaration.id} })); return; } // 检查能力是否支持 const capability capabilityDeclaration.capabilities.find(c c.name instruction.capability); if (!capability) { res.writeHead(400); res.end(JSON.stringify({ error: Capability ${instruction.capability} not supported })); return; } // 执行业务逻辑模拟耗时操作 const startTime Date.now(); eventEmitter.emit(state_update, { event: execution_start, correlation_id: instruction.correlation_id, data: { message: Starting text analysis... } }); // 模拟异步处理 setTimeout(() { try { const text instruction.payload.text || ; const charCount text.length; const wordCount text.trim() ? text.trim().split(/\s/).length : 0; const capitalized text.charAt(0).toUpperCase() text.slice(1); // 发送中间状态 eventEmitter.emit(state_update, { event: execution_progress, correlation_id: instruction.correlation_id, data: { step: counting_chars, progress: 33, message: Counting characters... } }); eventEmitter.emit(state_update, { event: execution_progress, correlation_id: instruction.correlation_id, data: { step: counting_words, progress: 66, message: Counting words... } }); // 返回最终结果 const result { char_count: charCount, word_count: wordCount, capitalized: capitalized }; eventEmitter.emit(state_update, { event: execution_complete, correlation_id: instruction.correlation_id, data: { message: Analysis completed successfully } }); res.writeHead(200, { Content-Type: application/json }); res.end(JSON.stringify({ correlation_id: instruction.correlation_id, status: success, result: result, metadata: { agent_id: capabilityDeclaration.id, timestamp: new Date().toISOString(), duration_ms: Date.now() - startTime } })); } catch (err) { console.error(❌ Execution error:, err); eventEmitter.emit(state_update, { event: execution_error, correlation_id: instruction.correlation_id, data: { message: err.message } }); res.writeHead(500); res.end(JSON.stringify({ correlation_id: instruction.correlation_id, status: error, error: err.message })); } }, 1500); // 模拟1.5秒处理时间 } catch (err) { console.error(❌ Parse error:, err); res.writeHead(400); res.end(JSON.stringify({ error: Invalid JSON instruction })); } }); }这段代码是Paperclip的第二层契约落地。它严格校验指令的target、capability、payload确保只有声明过的能力才能被调用。最关键的是它在执行过程中通过eventEmitter.emit(state_update, ...)主动推送状态事件——这正是第三层契约的起点。注意那个setTimeout它模拟了AI Agent真实的异步耗时特性。在真实场景中这里可能是调用LLM API、读取数据库、或执行Python子进程。3.3 启动HTTP服务器并暴露注册中心最后把一切串起来// 创建HTTP服务器 const server http.createServer((req, res) { // 处理能力声明查询供其他服务发现本Agent if (req.method GET req.url /capabilities) { res.writeHead(200, { Content-Type: application/json }); res.end(JSON.stringify(capabilityDeclaration)); return; } // 处理调用指令 if (req.method POST req.url /invoke) { handleInvocation(req, res); return; } // 兜底404 res.writeHead(404); res.end(Not Found); }); const PORT 3000; server.listen(PORT, () { console.log( Paperclip Agent listening on http://localhost:${PORT}); console.log( Capabilities endpoint: http://localhost:${PORT}/capabilities); console.log(⚡ Invocation endpoint: POST http://localhost:${PORT}/invoke); }); // 优雅关闭 process.on(SIGTERM, () { console.log( Shutting down Paperclip Agent...); server.close(); });现在运行node paperclip-agent.js你就拥有了一个真正的Paperclip Agent。它有/capabilities端点供其他服务查询能力/invoke端点接收标准化调用指令内置状态事件广播机制。注意这个实现刻意避开了Express等框架就是为了证明Paperclip的底层契约有多轻量。你在CentOS 7.9上安装Node.js 18.20.4后复制粘贴这段代码node paperclip-agent.js就能跑起来。这就是为什么centos 7.9 node.js安装部署和node.js 18.20.4 lts版本下载会成为高频搜索词——Paperclip的落地极度依赖稳定、易获取的Node.js运行时。4. React前端如何消费Paperclip Agent构建一个零配置的智能体工作台有了后端Agent前端React应用就是它的天然消费端。Paperclip的魅力在于前端无需引入庞大SDK用最基础的fetch和EventSourceSSE就能完成全部交互。下面我带你用Vite React 18构建一个极简但功能完整的“智能体工作台”它能自动发现本地所有Paperclip Agent通过调用/capabilities动态渲染能力表单发送调用指令并实时显示进度展示执行结果。4.1 创建React组件Agent Discovery与能力加载新建src/components/AgentWorkbench.jsximport { useState, useEffect, useCallback } from react; export default function AgentWorkbench() { const [agents, setAgents] useState([]); const [selectedAgent, setSelectedAgent] useState(null); const [selectedCapability, setSelectedCapability] useState(null); const [formValues, setFormValues] useState({}); const [executionState, setExecutionState] useState(null); // null, loading, success, error const [executionResult, setExecutionResult] useState(null); const [executionLog, setExecutionLog] useState([]); // 发现本地Agent const discoverAgents useCallback(async () { try { // 假设所有Agent都在localhost:3000, 3001, 3002... 端口 const ports [3000, 3001, 3002]; const promises ports.map(port fetch(http://localhost:${port}/capabilities) .then(res res.json()) .catch(err null) ); const results await Promise.all(promises); const validAgents results.filter(agent agent agent.id); setAgents(validAgents); if (validAgents.length 0) { setSelectedAgent(validAgents[0]); } } catch (err) { console.error(Failed to discover agents:, err); } }, []); useEffect(() { discoverAgents(); }, [discoverAgents]); // 当选择Agent时加载其第一个能力 useEffect(() { if (selectedAgent selectedAgent.capabilities.length 0) { setSelectedCapability(selectedAgent.capabilities[0]); // 重置表单值 const initialForm {}; Object.keys(selectedAgent.capabilities[0].input_schema.properties || {}).forEach(key { initialForm[key] ; }); setFormValues(initialForm); } }, [selectedAgent]); return ( div classNamep-6 max-w-4xl mx-auto h1 classNametext-2xl font-bold mb-6Paperclip Agent Workbench/h1 {/* Agent选择 */} div classNamemb-6 label classNameblock text-sm font-medium mb-2Select Agent/label select value{selectedAgent?.id || } onChange{(e) { const agent agents.find(a a.id e.target.value); setSelectedAgent(agent); }} classNamew-full p-2 border rounded {agents.map(agent ( option key{agent.id} value{agent.id} {agent.name} ({agent.id}) /option ))} /select /div {/* Capability选择 */} {selectedAgent ( div classNamemb-6 label classNameblock text-sm font-medium mb-2Select Capability/label select value{selectedCapability?.name || } onChange{(e) { const cap selectedAgent.capabilities.find(c c.name e.target.value); setSelectedCapability(cap); // 重置表单 const initialForm {}; Object.keys(cap.input_schema.properties || {}).forEach(key { initialForm[key] ; }); setFormValues(initialForm); }} classNamew-full p-2 border rounded {selectedAgent.capabilities.map(cap ( option key{cap.name} value{cap.name} {cap.name} /option ))} /select /div )} {/* 表单渲染 */} {selectedCapability ( div classNamemb-6 h2 classNametext-lg font-semibold mb-3Input for {selectedCapability.name}/h2 div classNamespace-y-4 {Object.entries(selectedCapability.input_schema.properties || {}).map(([key, schema]) ( div key{key} label classNameblock text-sm font-medium mb-1 capitalize{key}/label input type{schema.type number ? number : text} value{formValues[key] || } onChange{(e) setFormValues(prev ({ ...prev, [key]: e.target.value }))} classNamew-full p-2 border rounded placeholder{Enter ${key}} / /div ))} /div /div )} {/* 执行按钮 */} {selectedCapability ( button onClick{() executeCapability()} disabled{executionState loading} className{px-4 py-2 rounded font-medium ${ executionState loading ? bg-gray-400 cursor-not-allowed : bg-blue-600 hover:bg-blue-700 text-white }} {executionState loading ? Executing... : Execute} /button )} {/* 执行日志 */} {executionLog.length 0 ( div classNamemt-6 h3 classNametext-lg font-semibold mb-2Execution Log/h3 div classNamebg-gray-100 p-4 rounded h-40 overflow-y-auto {executionLog.map((log, i) ( div key{i} classNametext-sm text-gray-700 mb-1 [{new Date(log.timestamp).toLocaleTimeString()}] {log.message} /div ))} /div /div )} {/* 结果展示 */} {executionResult ( div classNamemt-6 p-4 bg-green-50 border border-green-200 rounded h3 classNametext-lg font-semibold mb-2Execution Result/h3 pre classNametext-sm bg-white p-3 rounded overflow-x-auto {JSON.stringify(executionResult, null, 2)} /pre /div )} /div ); }这个组件的核心思想是把Paperclip的能力声明直接映射为UI元素。它通过fetch轮询几个常见端口发现Agent然后根据input_schema动态生成表单字段。这完全规避了“前端硬编码API路径”的陷阱。你不需要知道Agent的URL只需要知道它遵守Paperclip契约就能和它对话。4.2 实现调用与状态监听fetch EventSource的黄金组合在上面的组件中executeCapability函数还没实现。我们来补全它重点展示Paperclip第三层契约的消费方式// 在AgentWorkbench组件内部添加此函数 const executeCapability async () { if (!selectedAgent || !selectedCapability || !formValues) return; const correlationId req-${Date.now().toString(36)}; const payload { ...formValues }; // 1. 发送调用指令 setExecutionState(loading); setExecutionLog([{ timestamp: new Date().toISOString(), message: Sending invocation request... }]); setExecutionResult(null); try { const response await fetch(http://localhost:${getPortFromAgentId(selectedAgent.id)}/invoke, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ target: selectedAgent.id, capability: selectedCapability.name, payload, correlation_id: correlationId }) }); const result await response.json(); if (!response.ok) { throw new Error(result.error || Invocation failed); } // 2. 开始监听状态事件SSE const eventSource new EventSource( http://localhost:${getPortFromAgentId(selectedAgent.id)}/events?correlation_id${correlationId} ); // SSE事件处理 eventSource.onmessage (event) { try { const data JSON.parse(event.data); setExecutionLog(prev [...prev, { timestamp: new Date().toISOString(), message: data.data?.message || Event: ${data.event} }]); } catch (e) { console.warn(Failed to parse SSE event:, event.data); } }; eventSource.addEventListener(execution_complete, (event) { try { const data JSON.parse(event.data); setExecutionResult(data.result); setExecutionState(success); eventSource.close(); } catch (e) { console.error(Failed to parse completion event:, e); } }); eventSource.addEventListener(execution_error, (event) { try { const data JSON.parse(event.data); setExecutionLog(prev [...prev, { timestamp: new Date().toISOString(), message: Error: ${data.data?.message || Unknown error} }]); setExecutionState(error); eventSource.close(); } catch (e) { console.error(Failed to parse error event:, e); } }); } catch (err) { console.error(Execution failed:, err); setExecutionLog(prev [...prev, { timestamp: new Date().toISOString(), message: Error: ${err.message} }]); setExecutionState(error); } }; // 辅助函数根据Agent ID推断端口实际项目中应从capabilities.endpoint获取 const getPortFromAgentId (id) { const portMap { text-analyzer-v1: 3000, code-reviewer-v1: 3001, data-validator-v1: 3002 }; return portMap[id] || 3000; };这里的关键是EventSource。它让React前端能以极低的开销持续接收Agent推送的状态事件。相比WebSocketSSE更轻量、更易调试浏览器开发者工具Network标签页能看到所有事件流相比轮询它真正实现了服务端主动推送。openclaw ubuntu安装教程里提到的“一键部署”其前端UI的实时性正是靠这套SSE机制支撑的。你甚至可以在Chrome控制台里直接访问http://localhost:3000/events?correlation_idxxx看到纯文本流式的事件推送这就是Paperclip状态同步契约的直观体现。经验之谈在React面试中如果被问到“如何实现前端实时响应后端任务进度”Paperclip的SSE方案是比“轮询setTimeout”或“WebSocket复杂状态管理”更优雅的答案。它展示了对现代Web API的深度理解也体现了工程化思维——不是堆砌技术而是选择最匹配场景的工具。5. OpenCLAWPaperclip理念的工业级实现与避坑指南如果说前面的手写Agent是“纸面谈兵”那么OpenCLAW就是Paperclip理念在真实战场上的装甲车。它不是一个玩具项目而是由一线AI工程团队打磨出的、面向企业级Agent编排的生产就绪平台。它的价值不在于发明新概念而在于把Paperclip的三层契约封装成开箱即用的CLI工具、Docker镜像和Web UI。当你搜索openclaw部署、openclaw配置阿里云服务器免费试用、openclaw obsidian时本质上都是在寻找如何把Paperclip的抽象范式快速落地到自己的基础设施中。5.1 OpenCLAW的核心架构Paperclip契约的完美具象化OpenCLAW的架构图几乎就是Paperclip三层契约的视觉化复刻--------------------- --------------------- --------------------- | React Frontend | | OpenCLAW Gateway | | Node.js Agent | | (Consumes Events |---| (Routes Instructions|---| (Implements | | Sends Instructions)| | Broadcasts State)| | Paperclip Contract)| --------------------- --------------------- --------------------- ▲ ▲ | | -------- SSE/HTTP --------Gateway网关这是OpenCLAW的“大脑”。它不执行任何AI逻辑只做三件事1定期扫描本地或远程服务收集所有Agent的/capabilities2接收前端发来的调用指令根据target字段路由到对应Agent3接收Agent推送的状态事件通过SSE广播给所有订阅的前端。它的存在让前端完全不用关心Agent的物理位置——无论是本机3000端口还是阿里云ECS上的3001端口对前端来说都是同一个/invoke入口。Agent SDKOpenCLAW提供了Node.js、Python、Go的SDK。它们不是强制你用某种框架而是帮你快速生成符合Paperclip契约的代码骨架。比如Node.js SDK的createAgent()函数会自动帮你设置/capabilities端点、/invoke处理器、以及SSE事件广播逻辑。你只需专注于写review_code或analyze_text这样的业务函数。这解释了为什么openclaw安装和openclaw安装教程如此重要——它省去了你从零手写前面那150行Node.js代码的重复劳动。Web UI这是OpenCLAW最惊艳的部分。它不是一个静态页面而是一个动态Agent工作台。当你点击“Deploy Local Agents”它会自动执行npm run start启动所有本地Agent然后通过Gateway发现它们立刻在UI上列出所有能力。你选中一个能力填完表单点击执行UI右侧就会实时出现拓扑图箭头流动节点变色日志滚动——这一切的背后都是Paperclip状态事件在驱动。openclaw obsidian插件正是把这个UI能力无缝嵌入到Obsidian笔记中让你在写文档时随时调用AI Agent生成摘要或润色段落。5.2 部署OpenCLAW从Ubuntu到阿里云的实战路径部署OpenCLAW就是部署Paperclip生态。下面是我亲测有效的路径覆盖了从开发机到生产环境的全场景。Ubuntu本地部署openclaw ubuntu安装教程的真相这是最简单的起点。假设你有一台干净的Ubuntu 22.04# 1. 安装Node.js 18.xLTS curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs # 2. 克隆OpenCLAW git clone https://github.com/openclaw/openclaw.git cd openclaw # 3. 安装依赖并启动 npm install npm run devnpm run dev会同时启动三件事OpenCLAW Gateway默认端口8080示例React前端默认端口3000一个内置的Demo Agent默认端口3001。打开http://localhost:3000你就能看到一个完整的Agent工作台。这个过程之所以能“一键”是因为OpenCLAW的package.json里dev脚本已经预设好了所有服务的启动顺序和端口映射。它不是魔法而是对Paperclip契约的深度封装。阿里云服务器部署openclaw配置阿里云服务器免费试用的实操免费试用ECS如2核4G足够跑OpenCLAW。关键步骤安全组配置开放端口3000(前端)、8080(Gateway)、3001(Agent)。切记不要开放22端口给公网用密钥登录。Node.js环境用nvm管理多版本避免系统Node.js冲突curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc nvm install 18.20.4 nvm use 18.20.4部署OpenCLAW推荐用PM2守护进程npm install pm2 -g pm2 start ecosystem.config.js --env production pm2 startup pm2 saveecosystem.config.js需配置Gateway、Frontend、Agent为独立进程并设置restart: true。**反
阅读完成 · 觉得有帮助?
咨询建站