ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

agency-agents实战:多智能体协作系统设计与搭建指南

agency-agents实战:多智能体协作系统设计与搭建指南 1. 从“agency-agents”这个标题说起它到底在解决什么问题第一次看到“agency-agents”这个组合词很多人会愣一下——agency是代理机构、代理商agents是代理、智能体两个词叠在一起到底指什么我最初接触这个方向时也绕了不少弯。简单说agency-agents 描述的是一类“代理型智能体”系统它不是单个AI助手而是一组具备自主决策、任务分解、工具调用和协作能力的智能体集群被组织起来去完成原本需要一整个代理团队比如营销代理、设计代理、数据代理才能交付的工作。你可以把它想象成一家虚拟的“数字代理公司”。传统代理公司里有客户对接、策略规划、创意执行、数据复盘等角色每个角色各司其职又互相配合。agency-agents 想做的就是用多个智能体分别扮演这些角色通过消息传递和任务编排让它们像一个真实团队那样协同产出结果。它解决的核心痛点是单一大模型在面对复杂、多步骤、跨领域任务时容易“顾此失彼”而多智能体分工协作能显著提升复杂任务的完成质量和可控性。这个方向适合谁参考三类人最该关注一是想用AI自动化业务流程的产品经理和创业者二是需要搭建智能体协作框架的工程师三是对多智能体系统好奇、想动手跑通一个demo的技术爱好者。哪怕你只是做内容运营理解 agency-agents 的协作逻辑也能帮你把重复性工作拆解成可自动化的流水线。我下面会从整体设计思路、核心机制、实操搭建、问题排查几个层面把这类系统讲透尽量让你看完就能自己动手搭一个最小可用的版本。2. 整体设计思路为什么是“多智能体协作”而不是“一个大模型”2.1 单模型的天花板在哪里很多人第一反应是现在的大模型上下文窗口都到几十万token了为什么还要搞多个智能体直接一个模型全干了不行吗我实测下来的结论是能但很不稳。单模型处理复杂任务时有三个绕不开的坎。第一是角色混淆。当你让一个模型同时扮演“策略分析师”和“文案撰写者”它在生成内容时会不自觉地把两种语气混在一起策略部分写得像文案文案部分又带着分析腔。第二是上下文污染。任务步骤一多前面的中间结果会干扰后面的判断模型容易“忘记”最初的目标。第三是错误累积。单模型一旦在某一步跑偏后面没有独立的“检查者”来纠偏错误会一路传下去。多智能体协作的本质是把一个复杂任务拆成多个相对独立的子任务每个子任务由一个专注的智能体负责智能体之间通过结构化消息传递结果。这样做的好处是职责单一、上下文干净、可独立校验。就像公司里不会让一个人同时做财务、设计和销售而是分给不同的人再由流程串起来。2.2 agency-agents 的典型角色划分一个完整的 agency-agents 系统角色划分通常遵循“规划—执行—校验”三段式。我参考过多个开源实现也自己搭过几套下面这套角色划分是我认为最通用、最容易落地的角色职责对应现实岗位协调者Coordinator接收总目标拆解任务分派给执行者项目经理执行者Executor完成具体子任务调用工具各领域专员校验者Validator检查执行结果是否符合要求质检/审核记忆体Memory存储历史结果和上下文公司知识库协调者不直接干活它只负责“想清楚要做什么、分给谁”。执行者拿到明确指令后专注产出。校验者独立于执行者专门挑毛病。记忆体则让整个系统具备“记住之前做过什么”的能力避免重复劳动。注意角色数量不是越多越好。我见过有人一上来就设计七八个角色结果消息传递的复杂度爆炸调试起来非常痛苦。建议从3个角色起步协调者、执行者、校验者。跑通之后再按需扩展。2.3 通信机制的选择为什么用消息队列而不是直接函数调用智能体之间怎么“说话”是设计里最关键的一环。最朴素的做法是直接函数调用——A智能体算完把结果return给B智能体。但这种方式在 agency-agents 场景下很快会出问题一旦某个智能体执行时间较长整个调用链就被阻塞而且调用关系硬编码想加一个新角色就得改代码。更合理的方案是基于消息队列的异步通信。每个智能体是一个独立的消费者监听自己的消息队列收到任务后处理处理完把结果投递到下一个队列。这样做的好处是解耦、可扩展、可重试。我用过 RabbitMQ 和 Redis 的 Stream 结构对于中小规模场景Redis Stream 足够轻量部署也简单。消息的格式建议统一成 JSON包含这几个字段task_id任务唯一标识、from_agent发送方、to_agent接收方、action要做什么、payload具体内容、status状态。统一格式的好处是任何智能体都能解析任何消息新增角色时不用改通信协议。3. 核心机制拆解任务分解、工具调用与结果校验3.1 任务分解把“写一份季度报告”拆成可执行的步骤任务分解是协调者的核心能力。用户给的目标往往是模糊的比如“帮我做一份Q3的营销复盘报告”。协调者需要把它拆成明确的、可执行的子任务。我常用的分解策略是按交付物倒推先想最终报告需要哪些部分再想每个部分需要什么输入最后想这些输入从哪来。以营销复盘报告为例分解结果可能是拉取Q3各渠道的投放数据执行者A调用数据接口计算各渠道的ROI和转化率执行者A数据计算对比Q2数据找出变化最大的三个渠道执行者B分析针对变化原因生成初步解读执行者B结合记忆体中的历史策略汇总成报告初稿执行者C文案整合校验数据准确性和逻辑一致性校验者这里有个实操心得分解粒度控制在“一个智能体一次能完成”的范围内。如果某个子任务还需要再拆说明拆得不够细如果两个子任务高度耦合说明拆得太碎。我一般以“是否需要调用不同工具”作为拆分边界——需要调数据接口的和需要做文本分析的分开因为它们对智能体的能力要求不同。3.2 工具调用让智能体真正“能干活”光会说话的智能体没有价值agency-agents 的威力在于每个执行者都能调用外部工具。常见的工具类型包括HTTP接口调用、数据库查询、文件读写、代码执行、搜索引擎查询等。工具调用的实现方式我推荐用函数注册表的模式。每个工具定义成一个函数附带名称、描述、参数schema注册到一个全局的工具表里。智能体在需要时根据任务描述匹配最合适的工具传入参数执行。这样做的好处是新增工具只需注册不用改智能体的核心逻辑。# 工具注册表示例简化版 TOOL_REGISTRY {} def register_tool(name, description, param_schema): def decorator(func): TOOL_REGISTRY[name] { func: func, description: description, schema: param_schema } return func return decorator register_tool( namefetch_channel_data, description拉取指定渠道在指定时间段的投放数据, param_schema{channel: str, start_date: str, end_date: str} ) def fetch_channel_data(channel, start_date, end_date): # 实际调用数据接口 return {channel: channel, roi: 2.3, conversion: 0.045}提示工具描述写得越清楚智能体选错工具的概率越低。我踩过的坑是描述写得太简略比如只写“获取数据”结果智能体在需要拉渠道数据时调用了用户数据接口。描述里一定要写清楚“什么场景下用这个工具”。3.3 结果校验为什么必须有一个“挑刺”的角色校验者是整个系统质量的守门人。它的工作不是重新做一遍任务而是对照要求检查执行结果。校验维度通常包括数据是否完整、格式是否符合要求、逻辑是否自洽、是否偏离原始目标。我设计校验者时会给它一份明确的检查清单checklist而不是让它自由发挥。比如对于数据类结果检查清单是数值是否在合理范围内、是否有缺失字段、单位是否统一。对于文本类结果检查清单是是否覆盖了所有要求的要点、语气是否符合品牌调性、有没有事实性错误。校验不通过时系统应该把结果打回给原执行者并附上具体的修改意见。这里要设置最大重试次数我一般设为2次。超过2次还不过就把问题上报给协调者由协调者决定是换执行者还是调整任务分解方式。没有重试上限的系统很容易陷入死循环烧钱又烧时间。4. 实操搭建从零跑通一个最小可用的 agency-agents4.1 环境准备与依赖选型搭建之前先把环境理清楚。我的建议是用Python作为主语言因为生态最成熟多智能体相关的库也最多。核心依赖包括大模型调用任意支持函数调用的模型API均可建议选一个上下文窗口大、函数调用稳定的消息队列Redis用Stream结构或RabbitMQ数据存储SQLite起步够用且零配置编排框架可以自己写也可以用现成的多智能体框架我个人的偏好是自己写编排逻辑而不是直接用重型框架。原因很简单agency-agents 的核心逻辑并不复杂自己写一遍能完全掌控每个环节出问题也好排查。重型框架虽然开箱即用但黑盒太多调试时经常不知道问题出在哪一层。环境准备的具体步骤# 创建虚拟环境 python -m venv agency_env source agency_env/bin/activate # Windows用 agency_env\Scripts\activate # 安装核心依赖 pip install redis openai sqlite3 requestsRedis的启动用Docker最省事docker run -d --name agency-redis -p 6379:6379 redis:latest4.2 定义智能体基类与消息协议所有智能体都继承同一个基类基类负责消息的收发和生命周期管理。这样新增智能体时只需要实现handle_task方法即可。import json import redis class BaseAgent: def __init__(self, name, redis_client): self.name name self.redis redis_client self.inbox fagent:{name}:inbox self.group fgroup:{name} def send_message(self, to_agent, action, payload, task_id): message { task_id: task_id, from_agent: self.name, to_agent: to_agent, action: action, payload: payload, status: pending } self.redis.xadd(fagent:{to_agent}:inbox, {data: json.dumps(message)}) def handle_task(self, message): raise NotImplementedError(子类必须实现handle_task方法) def run(self): # 持续监听自己的inbox while True: messages self.redis.xread({self.inbox: $}, block1000, count1) for stream, msgs in messages: for msg_id, msg_data in msgs: message json.loads(msg_data[data]) self.handle_task(message)消息协议统一用JSON字段固定为task_id、from_agent、to_agent、action、payload、status。这个协议看起来简单但足够支撑起整个协作流程。我试过加更多字段后来发现大部分都用不上反而增加了维护负担。4.3 协调者的实现任务分解与分派协调者是系统的入口它接收用户的总目标调用大模型做任务分解然后把子任务逐个分派出去。class CoordinatorAgent(BaseAgent): def handle_task(self, message): if message[action] new_goal: goal message[payload][goal] subtasks self.decompose(goal) for i, subtask in enumerate(subtasks): target subtask[assignee] self.send_message( to_agenttarget, actionexecute, payload{subtask: subtask[description], index: i}, task_idmessage[task_id] ) def decompose(self, goal): # 调用大模型做任务分解 prompt f把以下目标拆解成可执行的子任务每个子任务指定一个执行者。 目标{goal} 可用执行者data_agent数据处理、analysis_agent分析、writer_agent写作 以JSON数组返回每个元素包含assignee和description字段。 # 这里调用大模型API返回解析后的子任务列表 return [ {assignee: data_agent, description: 拉取Q3各渠道投放数据}, {assignee: analysis_agent, description: 计算ROI并对比Q2}, {assignee: writer_agent, description: 生成复盘报告初稿} ]分解时有个关键技巧在prompt里明确列出可用的执行者及其能力范围。如果不列模型可能会分派出一个不存在的角色或者把任务分给能力不匹配的执行者。我一开始没注意这点结果模型把“写报告”分给了数据智能体闹了笑话。4.4 执行者与校验者的联动执行者收到任务后先判断需要调用哪个工具执行完把结果发给校验者。校验者检查通过后把结果写入记忆体并通知协调者该子任务完成。class ExecutorAgent(BaseAgent): def handle_task(self, message): subtask message[payload][subtask] # 选择工具并执行 tool_name self.select_tool(subtask) result TOOL_REGISTRY[tool_name][func](**self.extract_params(subtask)) # 发给校验者 self.send_message( to_agentvalidator, actionvalidate, payload{subtask: subtask, result: result}, task_idmessage[task_id] ) class ValidatorAgent(BaseAgent): def handle_task(self, message): subtask message[payload][subtask] result message[payload][result] passed, feedback self.check(subtask, result) if passed: # 写入记忆体 self.redis.xadd(memory:results, {data: json.dumps(result)}) else: # 打回给执行者附上反馈 self.send_message( to_agentmessage[from_agent], actionrevise, payload{feedback: feedback, original: result}, task_idmessage[task_id] )校验者的check方法我建议用“规则模型”混合的方式。能用规则判断的比如数值范围、字段完整性就用规则快且准需要理解语义的比如逻辑是否自洽再调用模型。纯靠模型校验成本高纯靠规则又覆盖不全。4.5 记忆体的设计与使用记忆体不是简单的日志存储它要能被智能体查询和复用。我的做法是用SQLite建两张表一张存任务结果一张存历史决策。任务结果表记录每个子任务的输入输出历史决策表记录协调者做过的分解方案。当新的任务进来时协调者先查历史决策表看有没有类似的分解方案可以复用。执行者在处理任务时也可以查任务结果表看之前有没有做过类似的计算。这样能显著减少重复的大模型调用降低成本。实操心得记忆体的查询要用向量检索而不是关键词匹配。因为同一个意思可能有多种表达关键词匹配经常漏掉相关记录。我用的是轻量的向量库把历史结果转成向量存起来查询时做相似度匹配。这一步能让任务复用率提升不少。5. 常见问题与排查技巧实录5.1 智能体“卡死”或无限循环怎么办这是最常见的问题。表现是某个任务长时间没有进展消息队列里堆积了大量重复消息。根本原因通常是校验一直不通过执行者反复重试但每次都用同样的方式结果自然一样。排查思路先看校验者的反馈是否具体。如果反馈只是“不合格”执行者不知道改什么只能原样重试。反馈必须包含具体的修改方向比如“ROI数值缺少百分比符号”或“报告缺少Q2对比部分”。其次检查重试计数器是否生效。我一般会在消息里带一个retry_count字段每次打回时加1超过2次就上报协调者。还有一个隐蔽的坑消息确认机制没做好。如果智能体处理完消息后没有正确ack消息队列会认为消息没被消费重新投递导致同一个任务被处理多次。用Redis Stream时记得用XACK确认。5.2 任务分解粒度不合理导致的问题分解太粗执行者拿到一个模糊的大任务产出质量差分解太细消息传递次数暴增协调开销超过实际执行开销。我踩过的坑是分解太细一个简单的数据拉取被拆成了“连接数据库”“执行查询”“格式化结果”三步结果三个智能体来回传消息比直接一个函数调用慢了好几倍。判断粒度是否合理的标准如果一个子任务的描述超过两句话说明可能还需要再拆如果两个子任务的执行者总是同一个说明可以合并。我一般会在协调者的prompt里加一句“每个子任务应该是一个执行者一次能独立完成的最小单元”效果不错。5.3 工具调用参数错误的排查执行者调用工具时传错参数是另一个高频问题。典型表现是工具返回“缺少必填参数”或“参数类型错误”。排查时先看工具注册表里的schema定义是否清晰再看执行者提取参数的逻辑是否有问题。我常用的排查手段是在工具调用前打印完整的参数对比schema看哪里对不上。另外给工具加上参数校验逻辑传错时直接返回明确的错误信息而不是抛异常。这样执行者能根据错误信息自我修正而不是直接崩溃。问题现象可能原因排查动作任务长时间无进展校验反复不通过检查校验反馈是否具体同一任务被处理多次消息未正确ack检查XACK调用工具返回参数错误schema定义不清打印实际参数对比schema分解结果不合理prompt未限定粒度在prompt中加粒度约束成本异常高重复调用大模型检查记忆体复用是否生效5.4 成本控制的几个实用技巧agency-agents 系统跑起来后大模型调用成本是主要开销。我总结了几个控制成本的技巧一是能不用模型就不用规则能判断的绝不调模型二是缓存分解结果相似目标直接复用历史分解方案三是用小模型做校验校验任务通常比生成任务简单用便宜的小模型就够四是设置单任务预算上限超过就中止并报警。我实测下来做好这四点成本能降到 naive 实现的十分之一左右。尤其是缓存分解结果这一条效果最明显——很多业务场景的任务类型是高度重复的第一次分解好之后后面基本都能复用。6. 进阶方向让 agency-agents 更接近真实团队跑通基础版本后可以往几个方向继续打磨。第一个方向是动态角色分配不再固定每个执行者的职责而是根据任务类型动态决定由哪个智能体来执行。这需要给每个智能体维护一个能力画像协调者根据画像匹配任务。第二个方向是并行执行当前面几个子任务之间没有依赖关系时让它们同时执行缩短整体耗时。实现上可以用多线程或异步IO但要注意共享资源比如记忆体的并发访问问题。第三个方向是人机协同在关键节点引入人工确认比如任务分解方案生成后先让人审核校验不通过时让人介入判断。这在to B场景里特别重要因为企业客户对自动化决策的接受度有限人工兜底能大幅提升信任感。我自己在实际项目里体会最深的一点是agency-agents 的价值不在于完全替代人而在于把人从重复性劳动中解放出来让人专注于需要判断力和创造力的环节。系统设计时留好人工介入的接口比追求全自动更务实。最后分享一个小技巧给每个智能体的输出加上置信度评分低置信度的结果自动转人工这样既保证了效率又守住了质量底线。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进