
做Agent开发也有一段时间了从最早拿单个模型玩ReAct循环到后来发现单Agent在真实业务里真的会“卡壳”上下文一长就忘事、工具一多就乱调、稍微复杂点的任务单点跑还容易挂。后来我开始研究多Agent协作试过几套方案也踩了不少坑最终基于LocalClaw搭了一套本地化的多Agent协作系统跑了几个真实场景效果确实比单Agent稳很多。这篇就把整个搭建过程、设计思路、核心代码和调试记录都梳理出来给同样在做Agent编排的开发者一些参考。1. 从单Agent到多Agent为什么非要协作1.1 单Agent的“天花板”在哪很多人一开始接触Agent都是从单个智能体开始的给一个系统提示词挂几个工具然后让模型自主决定调用什么、怎么完成任务。这个阶段体验确实很新鲜但用到真实任务上问题就一个个冒出来了。最明显的是上下文熵增。模型能处理的上下文窗口是有限的哪怕支持128K甚至200K实际跑起来你会发现一旦让Agent连续执行超过5到10个步骤前面的历史记录就开始稀释后面的执行逻辑。比如让它先搜索资料、再整理大纲、再写初稿、再自查一遍执行到后半段它经常会忘记最初的需求约束输出的内容跟题目已经偏离得很远了。另一个问题是工具调度冲突。我在单个Agent上挂了搜索、网页抓取、代码执行、文件读写四类工具模型在决策的时候经常分不清该用哪个。明明该调搜索的地方它去读了本地文件该写代码验证的地方它反复用自然语言推测。不是模型不够聪明而是单一Agent的决策空间太大工具选择的任务压力全压在一套思维链上错误率自然就上去了。还有一个容易被忽略的点单点故障。Agent执行过程中一旦触发坏循环比如反复调用同一个工具拿相同结果整个任务就卡死了而且排查起来非常困难因为所有日志混在一起根本分不清是哪一步出了问题。1.2 多Agent协作的常见组织模式多Agent系统的核心思路就一句话让每个Agent只干一件专业的事再用一个调度层把它们串起来。就像公司里不是一个全能员工包揽所有活而是产品经理、研发、测试、运营各司其职中间有项目经理统筹。实际工程里常见的协作模式有这么几种主管-工人模式Supervisor-Worker一个主管Agent负责任务拆解、分配和结果验收多个工人Agent并行执行子任务。这种模式适合任务边界清楚、可以拆成独立模块的场景也是最容易落地的一种。流水线模式Pipeline任务按阶段依次流转上一个Agent的输出直接作为下一个Agent的输入。适合内容生成、数据处理这类有明显工序链的场景。竞标模式Auction一个任务广播给多个Agent谁的条件最好、能力最匹配谁来执行。适合有多个异构Agent、需要动态选择执行者的场景但实现复杂度偏高。我自己实践下来的体感是千万不要求大求全一上来就搞一个复杂的竞标系统。从主管-工人或者流水线起步先把任务的流转逻辑跑通再逐步加复杂度这才是稳的路子。1.3 LocalClaw在Agent编排生态里的定位LocalClaw属于本地优先的Agent编排框架核心定位是解决我自己写多Agent系统时最头疼的几件事Agent如何定义、如何通信、如何共享工具、如何做容错和观测。它本身不直接提供模型能力而是对接底层的推理服务我们内部接的是本地部署的量化模型。这套架构的好处是数据链路完全在自己可控范围内不需要把业务数据送到外部接口同时编排层的逻辑是通用的以后想换更强的模型只需要改配置不用动Agent代码。2. LocalClaw核心特性剖析为什么会选它2.1 本地优先隐私、成本与可控性我们选择LocalClaw最核心的考量是“本地优先”这四个字。实际业务里有大量数据不适合走外部模型接口比如内部文档、用户隐私信息、未公开的产品方案。把这些东西拼到外部提示词里等于把敏感信息送出内网合规上和心理上都过不去。LocalClaw的默认设计就是本地闭环Agent定义、任务调度、消息传递全部在本地进程完成模型调用也通过本地推理服务或私有化部署的接口。这样数据流通的每一跳都在自己掌控范围内审计起来非常清楚。另外本地化也省去了按Token计费的成本压力。多Agent跑起来的Token消耗是相当惊人的像流水线模式下一个任务经过4个Agent每个Agent都要做多轮推理Token消耗是单Agent的好几倍。用本地模型虽然单次推理质量略低于顶级闭源模型但胜在可以无限跑、随便调整体调试效率反而更高。提示如果你打算做多Agent系统的二次开发尽量选带清晰Python API的编排框架避免被某个厂商的专属格式绑定住。LocalClaw这一点做得比较舒服Agent配置就是普通Python对象迁移成本低。2.2 Agent通信编排机制多Agent系统最关键的技术细节其实是Agent之间的消息通信。LocalClaw的实现是基于一个进程内的事件总线每个Agent通过发布和订阅消息来协作调度器负责把消息路由给正确的接收方。这里有个容易误解的地方Agent之间的“对话”和人与人的对话是两回事。如果直接让AgentA的输出拼接到AgentB的对话历史里很快就会把B的上下文撑爆。合理做法是让Agent间传递结构化的任务包包含任务标识、目标、输入数据和产出要求而不是大段自然语言聊天记录。LocalClaw里每个Agent实例独立维护自己的上下文窗口外部传入的是结构化任务对象Agent处理完把结果写到共享的结果区由调度器决定下一步交给谁。这种设计让每个Agent的上下文只包含它自己职责范围内的信息大幅降低了上下文污染问题。2.3 工具注册与权限控制工具管理是另一个让我花了不少时间研究的功能点。LocalClaw提供一个装饰器风格的注册机制用registry.register就可以把一个普通Python函数封装成Agent可调用的工具。这个设计比让模型直接写代码执行要安全得多——工具函数的入参、出参和超时都是显式定义的模型只能按定义调用不能越界执行任意代码。工具级权限控制也很重要。我给不同Agent配置的工具集合是不同的调研Agent只能调搜索和抓取写作Agent只能调文档读写审核Agent只能调规则校验工具。这样即使某个Agent的提示词被诱导它能造成的破坏也被限制在自身工具边界内。3. 实战搭一套内容生产多Agent协作系统3.1 系统需求与Agent分工设计我拿一个“技术博客内容生产”任务来演示整套系统。任务输入是一个宽泛的主题输出是一篇经过调研、资料收集、撰写、审核四个环节的完整文章。这个场景天然适合流水线模式每个环节的职责边界很清晰。四个Agent的设计如下Agent名称角色定位核心职责使用工具researcher选题规划将宽泛主题拆解出具体选题方向和文章框架搜索、知识库查询collector资料收集围绕选题框架收集素材、数据、参考来源搜索、网页抓取、链接解析writer内容撰写基于素材完成文章初稿文档读写、模板渲染reviewer质量审核检查逻辑、查资料真实性、纠正格式规则校验、引用检查这个分工看似简单但实际效果比单Agent强很多。比如调研阶段researcher只关心选题结构不会陷入细节collector只做素材采集不会被写作思路带偏writer拿到的是整理好的结构化素材不需要自己边想框架边找资料写出来的内容更专注。reviewer作为最后一道关卡可以单独使用更严格的提示词用不同温度参数甚至更大模型做校验这也是单Agent很难实现的弹性配置。3.2 环境准备与安装安装LocalClaw很简单直接用Python包管理器安装pip install localclaw需要注意Python版本我们用的是3.10及以上。模型后端我接的是本地的推理服务用的量化模型。如果你没有本地模型也可以配置LocalClaw指向已有的模型网关地址格式上支持OpenAI风格接口。用本地方案跑4个Agent单任务全流程推理时间在3到5分钟之间具体取决于模型速度和文本长度。如果嫌慢可以给collector这类并行度高的环节多开几个Agent实例LocalClaw的调度器支持同一Agent多实例并发消费任务。3.3 定义Agent与注册工具核心代码先创建工具注册中心把Agent会用到的能力注册进去。这里我用一个模拟搜索工具做示例实际项目中替换成对应API调用即可from localclaw import ClawOrchestrator, AgentConfig from localclaw.registry import ToolRegistry registry ToolRegistry() registry.register(web_search, timeout15) def web_search(query: str, top_k: int 5) - list[dict]: 搜索Web并返回结果列表每项包含title、url、snippet # 示例实现实际环境替换为搜索API或本地索引查询 return [ {title: 示例结果, url: https://example.com, snippet: 这是搜索摘要} for _ in range(top_k) ] registry.register(fetch_page, timeout10) def fetch_page(url: str) - str: 抓取某个URL的正文文本内容 # 示例实现实际环境替换为抓取逻辑 return 页面正文示例 registry.register(read_doc, timeout5) def read_doc(path: str) - str: 读取本地文档内容 with open(path, r, encodingutf-8) as f: return f.read() registry.register(write_doc, timeout5) def write_doc(path: str, content: str) - str: 将内容写入本地文档 with open(path, w, encodingutf-8) as f: f.write(content) return f已写入: {path} registry.register(rule_check, timeout5) def rule_check(text: str) - dict: 基础规则校验检查字数、标题结构、敏感词命中 checks { min_length: len(text) 500, has_title: text.startswith(# ), sensitive_hits: 0 } return checks工具定义好之后接着定义四个Agent。每个Agent的system_prompt是关键它决定了这个Agent的行为边界。我的经验是提示词里一定要写清楚三件事自己是谁、只做什么、不做什么以及输出格式。尤其“不做什么”非常重要能拦住很多边界外的想象researcher AgentConfig( nameresearcher, role选题规划, system_prompt( 你是技术内容规划专家。你只负责分析用户给出的宽泛主题 输出一份选题规划包含标题、目标读者、文章大纲输出为YAML格式。 你不负责收集详细资料也不编写文章正文。 必须输出YAML不要输出解释性文字。 ), tools[web_search, read_doc], ) collector AgentConfig( namecollector, role资料收集, system_prompt( 你是资料收集专员。你根据研宄输出的大纲逐项查找相关资料、数据、案例 整理成Markdown素材包每条素材标注来源URL。 你不撰写文章只收集和整理素材。 ), tools[web_search, fetch_page], ) writer AgentConfig( namewriter, role内容撰写, system_prompt( 你是资深技术写作者。你根据素材包和选题规划撰写完整技术文章 要求逻辑清晰、有实操细节、语言自然。输出为Markdown格式。 你不搜索资料只基于素材包写作。 ), tools[read_doc, write_doc], ) reviewer AgentConfig( namereviewer, role质量审核, system_prompt( 你是严谨的内容审核员。你检查文章的逻辑结构、资料引用、格式规范性 发现问题时输出修改意见清单没有问题则回复PASS。 你根据审核意见修复文章直接输出修订后的完整Markdown。 ), tools[rule_check, read_doc, write_doc], )这里每个Agent的tools列表就体现了最小权限原则researcher不碰抓取、writer没有搜索权限想越界也越不了。3.4 编排协作流程调度与消息传递Agent定义完后创建编排器实例配置模型后端和全局参数orche ClawOrchestrator( model_backendlocal-claw://ollama/qwen2.5-7b-instruct, global_max_turns40, # 整个任务的全局最大推理轮次 message_timeout30, # 单条消息超时秒数 max_retries2, # 出错重试次数 result_dir./artifacts, # 中间产物输出目录 )把Agent注册进编排器然后配置流水线步骤。这里我用pipeline方法定义顺序执行链orche.add_agent(researcher) orche.add_agent(collector) orche.add_agent(writer) orche.add_agent(reviewer) orche.pipeline( steps[ (researcher, propose_outline), (collector, collect_materials), (writer, draft_article), (reviewer, review_article), ], # 关键配置审核不通过时退回给上一环节 feedback_loopTrue, )feedback_loop是这套系统的灵魂配置。它允许reviewer的输出不是简单进入人工处理而是触发目标Agent的重新执行。这个机制天然支持内容迭代写作初稿、审核发现问题、退回重写、再审直到通过或达到轮次上限。最后传入初始任务启动全流程task { user_intent: 写一篇关于本地部署大模型工具链的入门教程, constraints: { target_audience: 刚接触大模型的开发者, min_length: 2000, style: 务实干货少废话, } } result orce.run(task) print(最终产物:, result.artifact_path)3.5 运行观测与结果验证LocalClaw会把每一轮消息路由、工具调用、Agent间数据传递全部记录到result_dir下。我强烈建议你跑完第一个任务后先去翻一遍这些日志。你会发现很多有意思的细节比如写作Agent可能偷偷把素材包里的数据改了格式或者审核Agent在没有问题的时候依然给出了泛泛的修改意见。我第一次跑的时候reviewer连续三轮给了“建议丰富案例”这种空泛意见writer也一遍遍地加内容把文章越改越长接近全局轮次上限才结束。后来我在reviewer的提示词里加了硬性约束“如果没有发现明确的事实错误、结构缺陷或格式问题必须输出PASS不得给出主观风格建议”问题立刻解决了。这个案例给了一个重要经验多Agent系统的输出质量往往不取决于单个Agent有多聪明而取决于边界约束写得有多好。每个环节的验收标准越明确整体系统的输出就越稳。4. 实测翻车记录常见问题与排查清单4.1 Agent之间“抢话”与上下文断裂第一次跑通系统时我遇到了一个很典型的问题collector输出的素材包没有按照researcher的大纲结构组织导致writer拿到素材后自行猜想大纲写的文章跟最初选题规划完全对不上。原因是collector的提示词里没有明确要求“严格遵循输入大纲的章节结构”它自由发挥了。排查的时候我翻了日志发现researcher传给collector的YAML大纲里章节结构是用中文序号标记的而collector没有很好地解析这种格式。解决办法分两步一是规范researcher输出格式让大纲章节结构改成JSON数组字段名固定为section_title和key_points二是在collector的提示词中显式声明必须逐项对应大纲不得增删章节。经过这两步修改后信息传递的损耗就少多了。4.2 任务死循环与控制策略多Agent系统最容易让初学者崩溃的问题就是死循环。打开一次任务日志发现两个Agent在互相传递相同的消息来来回回几十轮不终止既烧Token又浪费时间。排查后发现reviewer对某个结论不认可返回修改意见给writerwriter改动后提交reviewer依然不认可同样的问题。因为两个Agent基于同一个模型思维模式高度一致第一次生成的判断在后续轮次中很难自我推翻。一个有效控制手段是给Agent的prompt增加“可妥协条款”明确允许在双方都无法进一步改进时由最后一级Agent输出当前最优版本并结束流程。同时在编排层设置target_tolerance比如审核Agent连续两次给出相似的修改建议时调度器自动跳过退回流程直接收当前版本为最终稿。虽然不是最优解但至少保证任务不会死循环。4.3 工具误调用的权限治理还有一个让我冷汗直冒的问题写作Agent在读素材包时出现了幻觉路径。它拼接了一个本不存在的相对路径去读文件然后通过工具调用报错信息“推理”出了内容硬生生编了一段不存在的文档摘要写进了文章。这个问题的根源是工具返回的错误被直接拼进Agent上下文模型把它当成了素材来用。我在工具层做了修正凡是文件不存在的错误工具返回固定的字符串“ERROR: file not found”而不是把系统抛出的详细异常信息传回给Agent。这样排除了错误信息被误用为事实的可能性。另一个治理手段是给writer的工具加白名单路径限制只允许读取result_dir下的文件越权路径直接拒绝。工具权限边界这件事宁可多限制不要少限制。问题现象可能原因排查思路解决方案下游Agent输出与上游规划不一致上游输出格式不规范、提示词未约束遵循结构查看消息路由日志确认上下游传递内容统一结构化输出格式提示词显式要求逐项对应两个Agent反复反驳、流程卡死同源模型思维趋同、缺乏退出机制统计反馈轮次观察修改意见是否相似增加可妥协条款设置tolerance自动收尾工具调用返回的报错被当素材使用异常信息拼入上下文检查工具调用记录确认Agent引用错误文本隔离工具异常信息返回固定占位文本单个Agent上下文被前序Agent输出撑爆Agent间传输原始对话记录查看各Agent上下文长度统计改用结构化任务包传递独立维护上下文经过几轮修正这套基于LocalClaw的多Agent系统现在已经稳定运行了。就我个人的实际体验而言多Agent协作真正的难点不在模型能力而在于任务边界怎么划分、消息格式怎么约定、失败路径怎么兜底。LocalClaw把这些基础设施做得很省心剩下的工程细节还是得自己一点点打磨。如果你也准备搭类似系统我建议从两个Agent的小流水线开始跑先把消息传递和权限边界理顺再加入第三个、第四个逐步扩大规模。这种循序渐进的方式会比一步到位省下不少调试成本。