资讯动态

TS/JS多Agent编排核心机制与实战:从单Agent到OpenClaw

发布时间:2026/10/13 4:53:23 来源:尧图企业网站定制
1. 从单Agent到多Agent不是炫技是需求倒逼先把话说在前面如果你的项目只有一个LLM调用确实没必要上多智能体。很多人在刚开始接触Agent的时候会把“多智能体”当成一个加分项仿佛Agent数量一多系统就显得高级。但在实际开发里多Agent是代价最高的一种架构它引入的并发、上下文、通信、状态一致性问题能把一个本来3天能上线的功能拖成3周。所以想搞清楚TS/JS生态里从单Agent演进到多Agent的路径得先弄明白到底什么场景下单Agent撑不住了。我在实际项目里最常遇到的情况是“角色混乱”。用一个Agent去处理全链路时你需要在System Prompt里同时塞入“你是客服”“你会写SQL”“你需要调用工单系统”“你还得做情绪安抚”Prompt越来越长模型在意图识别上越来越飘经常出现答非所问。另一个问题是工具集膨胀一个Agent挂着20个工具模型在每一步做工具选择时判断成本急剧上升而且容易选错。第三个问题是状态爆炸单Agent在做多步骤任务时上下文里堆满了中间过程一旦某个分支出错你很难定位是哪一步的决策污染了最终结果。这时候多Agent的优势就体现出来了每个Agent只负责一个职责域Prompt精简工具集小上下文独立失败边界清晰。说白了它就是软件工程里的“单一职责原则”在LLM应用层的投射。从单Agent到多Agent不是架构上的自嗨而是当你遇到上面三类问题时的自然解法。在TS/JS生态里做多Agent和Python生态思路类似但有个天然优势JS的事件循环天生适合处理Agent之间的异步消息流。Node环境下你用Promise、EventEmitter或者简单的消息队列就能搭出一套能跑的协作机制。而且TypeScript的类型系统对多Agent的状态管理非常友好设计得好编译期就能挡住一大半通信字段错误。当然多Agent不是银弹。如果任务足够简单比如“根据用户输入查个天气”单Agent足够。我的经验是一个Agent能清晰表述职责边界且工具数少于5个就不要拆。拆分的信号不是代码量而是“你发现单Agent的Prompt已经超过3000字或者它经常在一个上下文里做两种以上毫不相干的事”。2. 自己动手用TS写一个最小多Agent协作骨架讲再多理论不如直接看代码。这一节我会带你从零写一个基于Node.js TypeScript的最小多Agent系统。它不依赖任何重量级框架只是把协作的核心机制——消息路由、状态隔离、结果汇总——用最朴素的方式实现一遍。这里面有很多设计决策我会逐个拆解。2.1 先定义Agent接口约束比实现重要多Agent系统的第一步不是写Agent而是定义Agent之间的契约。我用TypeScript所以会先声明一个基础接口。这个接口是整个系统的“宪法”所有Agent都必须遵守它。type AgentId string; interface AgentContext { id: AgentId; role: string; taskQueue: Task[]; workspace: Mapstring, unknown; } interface AgentInput { from: AgentId; type: string; payload: unknown; } interface AgentOutput { to: AgentId | ROUTER; type: string; payload: unknown; } interface Agent { id: AgentId; role: string; handle(input: AgentInput, context: AgentContext): PromiseAgentOutput[]; }这里的核心是AgentOutput[]允许一个Agent在收到一条消息后产生零到多条输出。零条意味着它认为不需要继续处理多条意味着它可以同时派发多个子任务。这为后续的平行任务做好了铺垫。关于workspace这是每个Agent的私有工作区不直接共享。多Agent系统里最大的坑是“隐式共享状态”——两个Agent直接读一个全局对象看起来方便但写起来噩梦。用Map隔离需要共享的数据显式通过消息传递这是我能给的最朴素也最有效的建议。2.2 实现一个主管-员工模式总经理不写代码有了接口我们来实现一个经典模式Supervisor主管和Worker员工。主管负责接收用户请求拆解任务分发给不同Worker然后汇总结果。Worker只处理自己的细粒度任务。我用一个“客服工单分类”的例子来演示主管把用户的投诉内容分发给分类Agent和情绪分析Agent再把结果合并。class ClassificationAgent implements Agent { id classifier; role 工单分类员; async handle(input: AgentInput) { const content input.payload as { text: string }; // 实际开发中这里会调用LLM这里简化为关键词规则 const labels []; if (content.text.includes(退款)) labels.push(退款); if (content.text.includes(卡顿)) labels.push(性能); return [{ to: ROUTER, type: classification.done, payload: { labels } }]; } } class SentimentAgent implements Agent { id sentiment; role 情绪分析员; async handle(input: AgentInput) { const content input.payload as { text: string }; const sentiment content.text.includes(愤怒) ? negative : neutral; return [{ to: ROUTER, type: sentiment.done, payload: { sentiment } }]; } } class SupervisorAgent implements Agent { id supervisor; role 客服主管; async handle(input: AgentInput, context: AgentContext) { if (input.type user.request) { const text input.payload.text; // 派发两个子任务 return [ { to: classifier, type: classify, payload: { text } }, { to: sentiment, type: analyze, payload: { text } } ]; } if (input.type classification.done || input.type sentiment.done) { const responses context.workspace.get(responses) ?? []; responses.push(input); context.workspace.set(responses, responses); // 当两个子任务都完成时汇总结果 if (responses.length 2) { return [{ to: ROUTER, type: final.result, payload: { summary: 分类为${responses[0].payload.labels}情绪为${responses[1].payload.sentiment} } }]; } } return []; } }看到这里你可能已经发现问题主管Agent居然偷偷改了自己的workspace而且依赖“两条消息都收到”这个隐式条件。这正是我前面说的“状态隔离”在实际落地时的难点——为了演示方便我用工作区做了本地聚合但真正的生产系统需要更完备的消息关联机制比如用一个requestId把一次会话的所有消息串起来。这个我们后面聊OpenClaw时再展开。2.3 手工搭建的局限为什么你需要编排层上面这套东西确实能跑但如果你继续往下加Agent很快就会撞墙。第一路由逻辑写死在每个Agent里。每个Agent都知道“我该把结果发给谁”甚至知道全局有哪些Agent ID。这违反了低耦合原则一旦你新增一个Agent所有可能和它通信的Agent代码都要改。第二没有重试和超时机制。任何一个LLM调用都可能失败失败后谁来负责重试是发起方还是接收方手工代码里你会写大量try/catch最后整个系统全是防御代码主流程都看不清。第三没有上下文窗口的概念。真实场景中主管Agent需要记住整个会话的来龙去脉Worker Agent只需要知道当前这一个任务。如果全量传递Token成本爆炸。手工代码里你很容易变成“取message传message”根本没人管理记忆。第四没有可观测性。当你想知道“这个用户工单为什么被分类错了”你只能去翻日志。但Agent之间的消息流是异步的谁先到谁后到中间有没有消息丢了没有任何一个界面能完整回放。这些就是编排层Orchestration Layer要解决的问题。所谓编排层可以理解成一个“路由器 调度器 状态管理器 日志记录器”的组合体。它不关心你的Agent业务逻辑只关心Agent之间怎么协作、消息怎么流转、状态怎么回收、异常怎么处理。这个思路不是我发明的是所有成熟的多Agent系统沉淀出来的共性需求。3. OpenClaw到底帮你做了什么编排核心机制拆解说到这儿终于要进入标题里的主角OpenClaw。我这里说的OpenClaw指的是一个基于TypeScript实现的多智能体编排框架它的核心不是提供各种花哨的Agent能力而是把前面我列的四个痛点——通信路由、状态管理、容错重试、可观测性——以统一的方式解决了。我最早接触它是基于一个社区项目后来在多个生产环境里改造使用踩了一圈坑之后才敢拿出来写这篇总结。如果你手头没有OpenClaw的环境也没关系这一节你把它当做一个“优秀编排层该有的样子”去看后面遇到任何同类框架思路都是一模一样的。3.1 消息路由不再硬编码“发给谁”OpenClaw最核心的概念是一个全局的消息总线。Agent之间不直接引用对方的ID而是通过声明自己的“能力标签”来让路由层匹配。比如一个Agent在注册时声明capabilities: [text_classification]另一个Agent想要做分类时只需要向总线投递一个intent: text_classification的消息路由层会把消息自动分发给符合条件的目标Agent。这种方式带来的直接好处是新增Agent不需要修改任何既有代码。你只需要注册一个新能力路由表自动多一跳。我在一个采用这种设计的项目里从3个Agent扩展到12个Agent只动了新增文件和注册配置原有Agent一行没改。它的实现原理并不复杂本质是一个基于能力列表的订阅-发布模型。每个Agent在注册时把自己的能力写入一个共享RegistryRouter通过消息头的intent字段做匹配。匹配策略可以很简单——精确匹配能力名也可以做加权——比如一个Agent声明了classification另一个声明了text_classification.quickRouter根据规则选择一个最优的。// OpenClaw风格的消息定义 interface ClawMessage { id: string; intent: string; payload: unknown; from?: AgentId; retryCount?: number; timestamp: number; }实际注册Agent时你只需要写claw.register(new ClassificationAgent(), { capabilities: [text_classification], maxConcurrency: 3 });然后投递消息await claw.post({ intent: text_classification, payload: { text: 我要退款 } });后面的路由、分发、重试都跟你的业务代码无关。3.2 工作流与上下文窗口让每个Agent只看该看的东西多Agent协作里最容易被忽视的是“上下文隔离”。很多初学者会把整段对话历史传给每个Agent导致一个简单的翻译任务翻译Agent却要读完长达5000字的工作日志。OpenClaw解决这个问题的方式是提供一套显式的上下文传递API。它的核心概念叫TaskContext代表一次具体的任务执行单元。当主管Agent创建一个子任务时会自动生成一个子上下文只携带任务相关的数据。父上下文最终只保留汇总后的结论中间过程全部丢弃。这和人类工作很像项目经理只会告诉你说“把这份合同的条款提取出来”而不会把整个项目从立项到现在的全部邮件都发给你。// 创建子任务并显式传递数据 const childTask await claw.createTask({ intent: contract_extraction, input: { fileId: 12345 }, ttl: 60000 // 任务超时 }); const result await childTask.wait();这套机制还附带了一个很重要的能力状态回收。每个子任务有ttl超时后自动清理不会残留内存里的孤儿状态。我见过很多手工实现的多Agent系统跑着跑着内存上涨就是因为子任务完成后没人回收工作区。3.3 容错与恢复失败不是异常是常态LLM调用天然不可靠所以编排层必须把“失败”当成一级公民来处理。OpenClaw提供了三层容错单次重试、级联回退、人工兜底。单次重试很好理解一条消息发送后如果目标Agent没有在指定时间内返回路由层可以自动重新投递。这里有一个关键点必须保证消息投递的幂等性。否则重试时Agent会把同一个任务执行两遍。解决方案是在消息里带上唯一的taskIdAgent在处理前先检查自己是否已经处理过该ID。级联回退是指当主Agent连续失败Framework会自动寻找备选Agent。这有点像服务发现里的熔断降级。我在生产里就用过这个能力在线翻译Agent挂了自动切换到本地词典Agent至少能给出一个不完全正确但能用的结果而不是让整个流程崩溃。人工兜底最实用。编排层允许你给某个步骤配置一个“人工处理回调”当机器处理超过N次失败后把这个任务打包成一个待审单推给人工工作台。说实话做AI应用完全没有人工兜底就像不买保险开快车迟早出事。4. 实战用OpenClaw搭一个市场调研多Agent系统前面讲了这么多机制接下来是硬碰硬的实战。我用一个“竞品市场调研”的例子带你完整走一遍从需求拆解到系统跑通的全过程。这个例子我选了TS/JS社区最常见的场景不涉及任何敏感行业适合直接抄作业。4.1 需求拆解一个调研任务怎么分给多个Agent假设我们需要完成一个任务调研某类产品比如“智能猫砂盆”的用户口碑输出一份结构化报告。如果让一个Agent做它要同时完成搜索、信息抽取、情感分析、观点聚合、报告撰写直接崩溃。拆分后我们定义四个Agent采集Agent负责从公开平台拉取相关讨论文本。这里我们不讨论爬虫假设它通过API获取数据。信息抽取Agent从原始文本中提取产品名、价格、功能点、问题点。情感分析Agent对每条用户评价做正面/负面/中性判断。撰写Agent综合以上输出生成一份Markdown格式的调研报告。这四个Agent之间没有复杂的依赖链属于典型的并行聚合模式。主管Agent先并行派发采集任务等采集完成后再并行派发抽取和情感分析最后把结果汇总给撰写Agent。用OpenClaw实现这个编排逻辑可以写在路由规则或一个简单的流程定义里。import { Claw, task } from openclaw; const claw new Claw(); // 注册四个Agent claw.register(collector, collectorAgent, { capabilities: [web.search] }); claw.register(extractor, extractorAgent, { capabilities: [info.extract] }); claw.register(sentimenter, sentimenterAgent, { capabilities: [sentiment.analyze] }); claw.register(writer, writerAgent, { capabilities: [report.write] }); // 定义工作流 const workflow task(market_research) .step(collect, { intent: web.search, params: { query: 智能猫砂盆 用户评价 } }) .parallel( task(extract, { intent: info.extract }), task(sentiment, { intent: sentiment.analyze }) ) .step(report, { intent: report.write }) .build(); await claw.run(workflow, { input: { product: 智能猫砂盆 } });这只是伪代码级别的示例但骨架已经很清晰。你不需要关心每个Agent内部怎么调用LLM只需要在注册时告诉调度器“谁能干什么”。这样业务逻辑和调度逻辑完全分离。4.2 Agent内部实现一个负责抽取的Agent长什么样我们以信息抽取Agent为例展示在OpenClaw里写一个Agent的典型姿势。这里我假设用的是OpenAI接口但换成其他模型也一样重点是结构。import { ClawAgent } from openclaw; class ExtractorAgent extends ClawAgent { capabilities [info.extract]; async execute(message: ClawMessage) { const { rawText } message.payload as { rawText: string }; // 用结构化输出的方式调用LLM const response await llm.chat({ model: gpt-4o, messages: [ { role: system, content: 你是一个信息抽取器。只输出JSON包含字段product_name, features, issues, price_range。 }, { role: user, content: rawText } ], response_format: { type: json_object } }); const extracted JSON.parse(response.choices[0].message.content); return { type: info.extracted, payload: extracted }; } }要注意几点第一每个Agent只依赖message.payload不读取全局状态这样便于测试——你可以在单元测试里直接构造一个message不启动整个编排层单纯验证抽取逻辑。第二返回时带上type这相当于告诉路由层后续该谁处理。第三LLM调用最好封装成通用client不要在每个Agent里重复写配置。4.3 结果聚合与报告生成最后一个撰写Agent需要接收前面所有Agent的输出。这里最需要注意的是顺序。并行Agent完成顺序是不确定的撰写Agent必须等到所有必要结果都到达后才会被触发。OpenClaw的编排层会根据task的依赖关系自动等待但如果你是自己写代码就要用Promise.all之类的机制来保证。class WriterAgent extends ClawAgent { capabilities [report.write]; async execute(message: ClawMessage) { // 这里data中已有extract和sentiment的结果 const { extractResults, sentimentResults } message.payload; const report [ # 市场调研报告, , ## 功能点分布, extractResults.map(p - ${p.product_name}: ${p.features.join(,)}).join(\n), , ## 用户情感统计, 正面${sentimentResults.filter(s s.sentiment positive).length}, 负面${sentimentResults.filter(s s.sentiment negative).length} ].join(\n); return { type: report.generated, payload: { content: report } }; } }看到没有撰写Agent根本不关心数据是哪来的只要消息负载里带了extractResults和sentimentResults它就能干活。这就是编排层带来的模块化收益你可以只替换采集数据源或者只用新的情感分析模型其他Agent完全不受影响。5. 多Agent项目里的常见坑和排查心得再好的框架也架不住踩坑。这一节我不讲空话全部来自我在多个项目里真实的翻车记录。你如果正在做类似的事情对照着避雷。5.1 循环调用与死锁你的消息在鬼打墙多Agent系统最常见的故障不是代码崩溃而是Agent之间互相发消息形成一个环。A发消息给BB处理完又发消息给AA再发给B……直到超时。这种问题在人工路由时代非常隐蔽因为单个Agent看自己的逻辑都是正确的。一个排查技巧是给每一条消息带上traceId然后在消息总线层面加一个“每个traceId最多转发的Agent个数”上限比如10次。超过就报警这能快速发现问题。死锁则更多出现在同步等待场景。比如主管Agent用await childTask.wait()等待子任务但子任务的触发条件是主管发另一条消息这就自己等自己了。解决办法是要么用异步回调要么把超时时间设短一点让死锁自动暴露而不是永久挂着。我在开发里遇到最诡异的一次是Agent A处理完任务后想给自己发一条“继续下一批”的消息结果因为能力匹配太宽泛消息被路由给了Agent B。排查了半天最后发现是能力标签里重复声明了。所以给Agent声明能力时一定要精确不要图方便用一个很宽泛的标签。5.2 上下文污染你以为是负责任的传递其实是甩锅开发时最常见的问题是主管为了让子Agent“干活更精准”把自己上下文里的历史对话、系统提示、甚至其他子Agent的中间结果一股脑塞进去。结果子Agent的上下文越来越长推理越来越慢而且容易被无关信息误导。我的经验是每次传递前显式挑出本次任务需要的字段。如果你不能确定需要哪些字段就多传一个“摘要字段”让子Agent先看摘要按需请求更多信息。这比全量传递强一个数量级。举个例子抽取Agent需要的是原文但原文可能有5000字其中有效信息只有200字。与其让它读全量不如先行截断或做一个“重要片段抽取”。另一个上下文污染源头是循环内的变量引用。TypeScript的闭包非常容易让Agent在并发执行时拿到同一个引用对象导致数据串了。解决方法是使用不可变数据Object.freeze或structuredClone在消息边界处复制数据。我踩过一次之后定了个规矩任何跨Agent传递的payload必须是可JSON序列化的普通对象一旦涉及函数、引用类型就拒绝。5.3 并发与顺序的博弈什么时候并行什么时候串行多Agent系统并不是越并行越好。我见过有人同时发了10个并行子任务结果所有子任务都在竞态地调用同一个LLM接口触发限流最终耗时反而比串行还长。这提醒我们并行度需要全局控制。OpenClaw这类框架通常会提供统一的并发池你注册时设maxConcurrency调度器会自动排队。但是什么时候该并行什么时候必须串行我总结了两条经验如果子任务之间没有任何数据依赖且整体处理量可控比如10个以内才考虑并行。如果子任务生产的结果会被下游合并且合并逻辑要求顺序比如按时间排序那就不要让每个子任务自己返回时间戳而是由调度器在完成后统一加completionOrder字段避免排序不一致。还有一点不要用数组下标作为消息关联的依据。两个并行任务返回顺序可能不一致如果你在主管Agent里用result[0]去对应第一项很可能对应错。正确做法是每个任务放入一个唯一subTaskId返回时带上这个ID再按ID聚合。5.4 成本失控Token比你想的烧得快多Agent系统的成本不是“每个Agent一次调用的成本之和”而是“所有Agent的调用次数 × 上下文长度”的乘积。尤其链式调用一个任务解决不了会传导到下一个Agent错误也会放大。我见过一个调研任务因为采集Agent返回的数据格式不规范信息抽取Agent反复重试了8次最后一算光这一个任务的Token成本就是预期的5倍。控制成本的做法第一是给每个Agent设置单次调用超时和最大重试次数第二是尽量使用结构化输出减少无效的对话式往返第三是引入“缓存层”对同样的输入、同样的意图直接命中结果不重新调用LLM。我通常在编排层外面包一层Redis把intent payload的hash作为缓存key能省下不少冤枉钱。另外观察你的实际Token消耗最好在部署时对每个Agent的消耗单独打点。哪来的成本高一目了然。不要只看总费用那样你只能傻眼。6. 可观测性没有追踪你就是在盲开多Agent系统比传统API服务更需要可观测性。传统服务一条请求最多经过三四个服务链路追踪已经很关键多Agent一次任务可能有几十条消息分发给十几个Agent没有追踪的话问题复现都无从谈起。6.1 消息追踪要从设计阶段就做用OpenClaw这类框架时最简单的办法是利用它内置的追踪钩子。通常一个消息从投递到完成会有以下节点投递、路由匹配、Agent受理、Agent完成、后续路由。每个节点都应该打点。我一般是记录以下几个字段traceId一次业务请求的全局唯一IDmessageId单条消息的IDagentId当前处理的Agentintent消息意图duration这一步耗时inputPayloadSize和outputPayloadSize用来估算上下文负载status成功、失败、超时这些数据汇总以后你用任何日志平台都能重建一次任务的完整流程图。我在本地开发时最常用的是把消息流转打成一个树形结构每个父任务下面挂几个子任务一眼就能看出是不是有任务被重复派发。claw.on(message.processed, (event) { logger.log({ traceId: event.traceId, messageId: event.messageId, agentId: event.agentId, intent: event.intent, duration: event.duration, status: event.status }); });6.2 单元和集成测试Agent可以单个测协作必须整体验Agent的逻辑本身是纯函数式的所以单元测试非常容易。你直接构造一个输入消息调用agent.execute断言输出。难的是协作链路的测试。我的做法是写一组“集成测试脚本”模拟一次完整的用户请求然后断言最终输出里的核心字段。这里有一个反直觉的经验不要做严格的顺序断言。如果两个子任务是并发执行的你断言“消息A一定比消息B先处理”测试就会因为调度器的并发随机性而偶发失败。正确做法是断言“两者都完成了且结果正确”而不是“谁先谁后”。可观测性还要和告警联动。我推荐的告警指标是单次任务成功率和平均耗时是最核心的其次是每个Agent的重试次数占比然后是上下文平均长度如果持续上涨说明可能有状态泄漏。不要等用户投诉了你才发现问题好的告警能让你在用户感知之前就搞定。6.3 回调地狱与长任务异步才是归宿多Agent任务往往不是一次HTTP请求能完成的尤其是涉及实时数据采集和推理的场景一次任务可能跑几十秒甚至几分钟。如果前端一直同步等待体验极差也会导致超时。合理的方式是任务异步化提交任务后立刻返回一个taskId前端轮询或通过WebSocket接收进度后端编排层持续执行。在OpenClaw里实现异步任务也很简单claw.run()可以返回一个任务句柄你不需要await它完成。你可以在任意Agent的完成回调里通过WebSocket推送进度。比如调研任务采集Agent完成后推送“正在提取信息”撰写Agent完成后推送“报告生成中”。用户体验会好很多而且能避免网关超时。异步化带来的新问题是任务状态管理。你需要把taskId映射到当前运行阶段并且允许用户手动取消任务。取消实现的核心原则是“取消时向所有已派发的子任务投递一个中断消息”。不要试图“杀死”正在运行的Agent而是通过标记让它在下一个检查点主动退出。7. 从框架到生产最后的几个建议写到现在基础的东西都覆盖了。最后我再补几个实战层面的建议也算是我个人从“跑通Demo”到“上线稳跑”这阶段里最有价值的一些沉淀。第一个建议不要一上来就上一套“标准多Agent框架”。先把前面第二节的手工版本写通理解清楚消息流转、状态隔离、汇总的逻辑。只有当你真的觉得搭路由、做重试、做追踪这些事开始重复繁琐时再引入OpenClaw完整的编排能力。直接上手框架你很可能对底层机制一无所知出了问题无法排查。第二个建议Agent之间的接口设计要比对外的API更严格。对外的API你可能还有文档和联调Agent之间的消息没有任何人类审核全靠代码定义。所以一定要用TypeScript的强类型约束payload结构拒绝滥用any。每一条消息的类型都要有一个对应的Interface并且加一个version字段将来消息格式升级时可以兼容处理。第三个建议灰度发布时先替换一个Agent不要一次性替换全链路。比如你的调研系统跑得好好的想换一个更强的情感分析模型那就只换SentimentAgent其他Agent不动。对比新旧Agent在同一批数据上的输出差异确认没有回退后再扩大范围。这个思路和微服务架构里的“金丝雀发布”完全一致。第四个建议也是我认为最重要的给Agent赋予“不做某事”的能力。就像人一样一个Agent要清楚自己的能力和职责边界。当收到的消息不在自己的能力范围内时它能明确回复I cannot handle this并携带一条建议路由给哪个Agent而不是强行返回一个错误或者乱猜。这能极大降低跨Agent的错误传导。我在OpenClaw里见过有人在消息负载里加了一个abilityCheck字段让Agent在行动前先自检用了之后系统故障率下降不少。现在我回过头去看那些从单Agent一路演进过来的项目最有感触的一点是多Agent系统的复杂度主要不在每个Agent内部而是在Agent之间的连接。连接一旦清晰、可控、可观测整个系统就会变得异常稳定。反之即便每个Agent内部的Prompt写得再精细也可能因为一条消息路由错位而全线崩溃。如果你正打算在自己项目里做TS/JS多Agent开发把前面几节的手工版本先搭一遍再决定要不要引入OpenClaw。磨刀不误砍柴工Agent的每一个设计决策都会在将来的维护里反复出现。希望这篇基于实际体验的总结能帮你少走几步弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑