做多智能体协作系统的时候,很多人第一个跳进脑子里的念头是“我要用一个Agent框架”,然后一头扎进去调框架、配模型,最后发现跑起来的是个玩具,离能用的系统差着十万八千里。
我最近在搞一个内部项目,代号就叫“agency-agents”,目标很朴素:让几个各司其职的AI智能体协作处理一套完整的业务流,从接收需求、拆解任务、调用工具、汇总结果到最终输出报告,中间尽量不需要人工干预。折腾了两三周,踩了不少坑,也沉淀出一些可复用的设计思路。这篇就把我自己的完整设计过程和实操笔记整理出来,从架构思路到核心代码链路,再到我实际遇到过的坑和排查办法,一次性讲清楚。
1. 什么是agency-agents:从单体编排到智能体协作
1.1 它解决的是什么问题
先说我最初遇到的场景。平时要处理大量跨部门的协作请求,内容涉及资料检索、数据分析、文案生成、格式整理,链路很长。传统做法是写一堆脚本串起来,每个环节单独处理,中间的输出靠人来搬运,脚本之间只要某个上游格式变了一点,下游就跟着崩。而且脚本只能执行既定的逻辑,遇到没提前定义过的变体场景就无能为力。
所以我想要的东西很明确:不是一串固定流程的自动化脚本,而是一个由多个拥有不同“职能”的AI智能体组成的协作网络。每个智能体有自己擅长的事,比如有的负责理解用户需求,有的负责调用搜索引擎或数据库,有的负责写初稿,有的负责审查修正。它们像一个微型团队一样分工,彼此之间通过消息传递协作,共同完成一个复杂的整体目标。这个思路就是“agency-agents”——把原来单体式的自动化流程,升级成可扩展、可分工、相对自治的多智能体协作架构。
举个直观例子。以前处理“整理上一季度所有项目进展并形成月度报告”这个需求,脚本要写死:从A系统导数据、从B系统读文档、套用固定模板拼报告。现在用多智能体协作:需求智能体先解析出“上一季度”“项目进展”“月度报告”这几个关键要素,然后调度智能体决定调用哪些工具,数据智能体去拉取信息,写作智能体组织语言,审核智能体检查逻辑和缺失,最后再汇总交付。整个过程不需要把每一步都写死在代码里,智能体自己根据情况动态调整。
1.2 与传统自动化任务流的本质差异
很多人觉得多智能体就是“多个提示词脚本串起来”,这个理解挺容易跑偏的。传统自动化任务流的核心是单向数据管道,A的输出是B的输入,顺序固定,流程固定,异常处理靠人工预设规则。多智能体协作的核心是动态任务分配与反馈循环,智能体之间不只是数据传递,还包括任务请求、执行反馈、质量校验、重试协商。
打个比方,传统自动化像一条流水线,每个工位只做规定动作,零件按顺序流过;多智能体协作更像一个项目组,组员之间可以根据情况互相请求支援、交换信息、复查成果。
体现在工程上,有几个关键差异点:
- 任务分解是动态的:传统流程在编码时就要定义好全部步骤;多智能体能根据当前任务的具体情况,在执行期动态决定拆成哪几个子任务、分配给谁。
- 信息传递是双向的:不只是上游给下游传数据,下游智能体还可以反馈“数据不够”“格式不对”“需要补充上下文”,触发上游重新处理。
- 具备自校验和重试能力:审核智能体发现生成结果有问题时,可以直接把任务连同修正意见打回给执行智能体,形成一个闭环,而不是简单地中断流程。
- 智能体具备工具使用权:它们不是仅仅文本生成,而是可以按需调用外部API、数据库、文件系统等工具,相当于每个智能体都配了“手脚”。
我做的这个项目,一开始就是冲着这几个差异去设计的,但真正动手后才发现,把这几个点落实成工程代码,比想象中琐碎得多。下面会逐步拆解我踩过的弯路和最终采用的方案。
2. 整体架构设计:我是怎么构思这个协作网络的
2.1 先明确智能体边界,再谈协作
很多人设计Agent系统时一上来就写代码,结果每个智能体的职责边界模糊,互相抢活干或者互相踢皮球。我这次的做法是先花大半天时间理清角色分工,明确每个智能体的能力边界和不可替代性。
这个项目里我最终定义了五个角色:
- 规划智能体(Planner):接收原始需求,进行语义理解,将复杂目标拆分为有序子任务清单,并标注每个子任务的依赖关系。
- 执行智能体(Executor):负责调用具体工具完成任务,比如检索资料、查询数据库、调用API获取数据,是最直接的“动手者”。
- 写作智能体(Writer):将执行智能体拿到的结构化数据组织成可读性良好的文本内容,比如报告、摘要、邮件草稿。
- 审核智能体(Reviewer):对生成内容进行质量检查,包括逻辑一致性、信息完整性、格式合规性,必要时提出修改意见并打回。
- 协调智能体(Coordinator):作为总控节点,维护整个任务的状态机,调度消息流转,处理异常分支,相当于团队里的项目经理。
这个分工的灵感其实特别朴素——就是模仿一个真正的高效团队在做事。如果所有人都做所有事,信息会混乱;但如果每个人有明确的职责,协作效率会高很多。同样的逻辑放到智能体上,效果也类似。
在设计时我特意把执行和写作拆开,而不是合成一个全能的“什么都干”智能体。原因有三个:第一,职责分离后每个智能体的提示词更聚焦,生成质量更可控;第二,同一个执行结果可以被不同风格的写作智能体复用,比如一份数据既可以生成简报也可以生成长篇分析;第三,审查时能清晰定位错误来源,数据问题找执行智能体,表达问题找写作智能体,不用猜。
2.2 通信机制:消息总线与共享黑板
多智能体之间怎么通信,是我最早考虑的问题之一。对比了几种方案后,我没有选择让智能体之间直接互相调用函数,而是引入了一个中央消息总线,同时搭配共享状态存储,形成了“黑板架构”。
所谓黑板架构,其实是个很经典的AI概念:所有智能体不直接对话,而是往一块“共享黑板”上写信息、读信息。每个智能体各写各的区域,也能读取其他智能体的产出和状态。这么做的好处是显而易见的:
- 解耦:智能体之间不需要知道彼此的接口细节,只依赖统一的消息格式和黑板上的数据结构。
- 可观测性:任何时候都可以查看整个系统的运行状态,每个智能体当前在干什么、已经产出了什么,一目了然。排查问题的时候有据可查。
- 恢复能力:某个智能体挂掉了,可以从黑板上获取已经完成的部分继续接力,不需要整个流程重来。
消息结构我设计得比较轻量,每条消息包含:消息ID、来源智能体、目标智能体、消息类型、载荷数据、时间戳、任务关联ID。消息类型分为任务请求、任务响应、修正反馈、状态通知四类,够用且不复杂。
共享黑板我用了一个支持事务的内存数据库实现,每条子任务产生的中间数据、输出结果、状态变更都会记录在案,并且保留了版本历史。后来遇到上下文问题排查时,这套设计帮了大忙,后面会有详细说明。
2.3 调度策略:从显式编排到半自治协商
关于调度,要考虑的问题是要不要让智能体自己决定“下一步做什么”。极端的做法是完全自治,所有智能体自由竞争接管任务,系统弹性高但不可预测,出问题时非常难debug。另一个极端是流程写死,每一步哪个智能体做什么都是固定的,这又回到传统自动化的老路。
这次我采用了一个折中的策略:顶层显式编排,执行层半自治。
顶层Coordinator维护一个任务状态机,根据规划智能体给出的子任务清单,按依赖关系逐个激活对应的执行或写作智能体。这个层面是确定性的:什么任务轮到谁处理,是有序、可预期的。执行层内部则给了智能体一定的自主权:比如执行智能体拿到一个检索任务后,可以自己决定调哪个工具先做、拿到结果是否够用、需不需要二次检索。这种折中的好处是既保证了整体流程的可控性,又保留了智能体处理特殊情况时的灵活性。
具体到实现,Coordinator维护的任务状态包括:待处理、执行中、待审核、已通过、被打回、已完成、失败。每次消息到达时,根据当前状态和消息类型决定下一步动作。这套状态机是整个系统里最核心的骨架代码。
3. 核心价值与关键设计决策
3.1 为什么值得花精力做这套系统
在考虑要不要投入做多智能体系统时,我建议你先想清楚自己的需求到底适不适合。基于这次实践,我认为当需求满足下面几条中的至少两条时,多智能体架构能带来明显收益:
- 任务链路长,涉及多种不同类型的工作,且顺序不一定固定。
- 需要动态处理非结构化需求,无法提前穷举所有流程分支。
- 质量问题至关重要,需要专门的审查修正环节,而不是一次性生成就算完。
- 希望系统能力能持续扩展,未来可能要接入更多工具或新业务场景,而不希望每次都重写整个流程。
如果只是“把A数据转成B格式”这种高度确定性的需求,老实说,写个脚本几分钟搞定,不需要引入Agent。硬上多智能体不仅增加延迟和成本,还徒增排查难度。这是我一开始就给自己立的规矩。
3.2 方案选型时要注意的成本陷阱
做多智能体系统,第一个要正视的现实是:LLM调用成本和时间开销比单次生成高出数倍。一个简单的协作流程,可能需要4-8次模型调用才能完成。如果业务量很大,成本不是线性增长,而是倍数增长。
我在评估方案时做过一次实际测算。假设每个智能体平均调用消耗的token数约为3000(输入+输出取中值),一个典型任务需要6次智能体交互,那么单个任务的token消耗约为18000。对比单模型一次性完成可能只需要4000-6000 token,成本差距约3-4倍。
但这笔多出来的开销换来的是质量、稳定性和可扩展性。对内容质量要求高的场景(比如面向用户的报告、需要审核的正式文档),这个取舍是值得的。如果场景只是聊天对话或简单的文本改写,用单个大模型就够了,没必要上多智能体。
我最终的判断标准很简单:如果用户能接受“一次性生成,错了再重来”的模式,就走单模型;如果“生成后必须经过质量门禁才能交付”是硬性要求,就上多智能体协作。
3.3 模型选型与参数调优经验
在实际开发中,不同角色的智能体对模型的偏好是不同的,没必要所有智能体都统一用最强的模型。
规划智能体和协调智能体这类负责理解和决策的角色,我用的是推理能力更强的模型,因为它需要准确拆解复杂任务、理解依赖关系。执行智能体以工具调用为主,响应速度比推理深度更重要,所以选择了延迟更低的型号。写作智能体病不需要太强推理,但语言组织能力要好,使用的模型在长文本生成上表现更稳定。审核智能体最看重的是对细节的捕捉能力,我选了上下文窗口更大的模型,这样它能“看”到前置完整内容再检查,不容易遗漏问题。
参数设置上也有些门道。我把所有智能体的temperature统一调低到0.2以下,防止生成结果过于发散,尤其是规划、执行、审核这类需要确定性的角色。写作智能体会稍微调高到0.3-0.4,让措辞不会显得太死板。
另一个关键参数是max_tokens。很多初学者会忽略这个参数,导致生成到一半被截断,尤其长报告场景非常容易触发。我建议根据每个角色的输出形态预估并预留充足的长度上限。写作类任务的max_tokens设置过小是我踩过的比较低级但真实的坑。
4. 实操实录:从零搭起一个最小可用系统
4.1 技术栈选型与基础架构
技术栈这块我选了Python生态,原因很简单:无论是模型SDK、工具集成还是数据处理,Python都最省心。框架层面我没有套用现成的Agent框架,而是直接用异步框架自己管理状态和消息流转,外加一个内存态数据库做黑板存储。这样做一方面是因为我想精确控制调度逻辑,另一方面是我想把系统的运行逻辑完全握在自己手里,排查问题时不用去翻框架源码。
项目目录做了清晰的模块化:
agency-agents/ ├── agents/ │ ├── base.py # 智能体基类,定义消息处理接口 │ ├── planner.py # 规划智能体 │ ├── executor.py # 执行智能体 │ ├── writer.py # 写作智能体 │ ├── reviewer.py # 审核智能体 │ └── coordinator.py # 协调智能体,核心调度器 ├── bus/ │ └── message_bus.py # 消息总线 ├── tools/ │ ├── registry.py # 工具注册表 │ ├── web_search.py # 搜索工具封装 │ ├── db_query.py # 数据库查询工具 │ └── document.py # 文档读写工具 ├── storage/ │ └── blackboard.py # 共享黑板存储 ├── main.py # 入口 └── config.yaml # 模型配置4.2 消息与状态流转实现
先看基础的智能体基类。这里我把“接收消息-处理-回写消息”设计成了统一接口,并额外记录了一条消息的完整生命周期。基类代码如下:
class BaseAgent: def __init__(self, name, role_desc): self.name = name self.role_desc = role_desc self.blackboard = None self.model = None async def handle(self, message): raise NotImplementedError async def send(self, msg_type, target, payload, task_id): msg = Message( msg_id=uuid4().hex, source=self.name, target=target, msg_type=msg_type, payload=payload, task_id=task_id, ts=time.time() ) await self.bus.publish(msg) return msg真正核心的是消息总线的实现。它主要有三个能力:发布消息、路由消息、订阅状态变更事件。代码其实并不复杂,关键在设计上做了一件很重要的事——每条消息都会持久化一份副本到存储,这样后面排查和复盘的时候随时能还原整个协作过程。
class MessageBus: def __init__(self): self.subscribers = defaultdict(list) self.history = [] async def publish(self, msg): # 记录消息历史 self.history.append(msg) # 根据目标路由 subscribers = self.subscribers.get(msg.target, []) for callback in subscribers: await callback(msg) def subscribe(self, agent_name): def decorator(func): self.subscribers[agent_name].append(func) return func return decorator黑板存储的设计要点在于每个任务的所有中间状态都集中记录。我用字典以task_id为主键,记录这个任务下的所有子任务状态、每个智能体的输入输出、以及状态变更日志。这样工程上排查问题就变得特别直观。
Coordinator的状态机是最细碎的代码。它定义了一个任务状态字典,每个任务对应一个状态,并配备状态转移规则。实际开发中状态的定义不用太多,够用就行——太多反而增加维护成本,太少又容易逻辑混乱。
4.3 各智能体提示词设计要点
智能体效果好不好,提示词设计起决定性作用。我把自己用的提示词思路整理成几个核心要点,这比贴完整提示词更有价值。
规划智能体强调两件事:一是任务必须拆到“可直接执行”的粒度,二是标注依赖关系。我在提示词中明确要求它输出JSON格式的子任务清单,每个子任务必须包含:任务ID、任务描述、优先级、依赖列表、负责智能体类型和期望输出。这样做是为了让下游调度代码好解析,也让规划结果能被结构化记录。
执行智能体的提示词重点是工具选择策略。它拿到子任务时,有时会面临多个工具可用的情况。我在提示词里明确写了判断优先级:先判断哪个工具能满足核心需求,再看数据质量,最后考虑时效性。执行智能体还被告知:工具返回内容不完整时,必须明确指出缺了什么,而不是强行“编”一个答案。这是吸取了早期实验的教训。
写作智能体收到的是结构化数据和交付要求。它被要求必须严格基于数据事实组织文字,不能自行添加数据中不存在的细节。这条约束对生成内容的可信度至关重要。写作智能体的提示词还要求它在开头给出内容概要,方便审核智能体快速理解全貌。
审核智能体承担质检角色。它被要求按固定维度逐一排查:信息完整性、逻辑一致性、事实准确性、格式规范性,以及约束符合性。每个维度都必须给出“通过/不通过+原因”的明确结论。这是唯一一个我要求必须输出负面意见优先的智能体——不发现问题就等于没干活。
4.4 工具注册表与函数调用封装
执行智能体要“能干实事”,靠的是工具调用能力。我把工具封装做成两层:
第一层是工具注册表,所有工具统一注册,包含名称、描述、输入输出Schema。智能体通过工具名称选择和参数可读性确定调用哪个工具。第二层是执行器,根据智能体返回的函数调用指令来真正执行对应工具,并把结果重新包装成“工具返回消息”。
class ToolRegistry: def __init__(self): self.tools = {} def register(self, name, description, params_schema): def decorator(func): self.tools[name] = { "func": func, "description": description, "params_schema": params_schema } return func return decorator async def exec_tool(self, name, **kwargs): if name not in self.tools: raise ValueError(f"Unknown tool: {name}") tool = self.tools[name] # 调用前校验参数 # 这里可以做参数Schema校验,后续细讲 result = await tool["func"](**kwargs) return result工具注册的例子:
registry = ToolRegistry() @registry.register( name="search_web", description="检索公开网页信息,返回与查询词相关的文本片段列表", params_schema={ "query": {"type": "string", "required": True} } ) async def search_web(query): # 实际调用搜索服务的封装 results = await search_service.search(query) return results这样设计的核心价值在于:智能体不需要知道工具怎么实现,只需要明确“工具名称”和“参数”,而工具的新增、替换、下线都只需要改注册表,不用改任何智能体逻辑。
4.5 完整跑通一个协作任务
写一个最小示例帮助理解整个链路是怎么咬合的。
假设一个任务:“查询最近的行业动态,并形成一份简要摘要”。
- 用户在入口提交任务,Coordinator创建一个任务ID,并且把初始需求写入黑板。
- Planner被激活,读出需求,解析出关键要素:“行业动态”“最近”“简要摘要”。规划结果生成两个子任务:子任务A=检索行业动态,负责角色Executor;子任务B=将检索结果整理为摘要,负责角色Writer。
- Coordinator按照依赖顺序,先激活Executor处理子任务A。Executor收到子任务后,在工具注册表中选择search_web工具,执行检索,将结果写入黑板对应位置,并且发送“完成”消息。
- Coordinator检查依赖,发现子任务A已完成,激活Writer处理子任务B。Writer从黑板读取检索结果,按交付要求生成摘要文本。
- Reviewer被激活,检查摘要质量。它需要同时查看原始检索结果和生成的摘要,进行一致性比对。如果发现问题,回复“修正”指令给Writer;如果通过,回复“完成”。
- Coordinator汇总最终结果,标记任务完成。
这段流程里的每个环节都有日志记录、消息回传、状态更新,开发和排查时清晰可追溯。
纯粹来看,这个示例并不复杂,但正是这种“简单到可以掌控、又包含了完整协作闭环”的设计,才适合作为进一步扩展的地基。
5. 常见问题与排查技巧实录
这部分是我最想分享的内容。网上关于多智能体的教程大多停在架构图层面,真正跑起来时会遇到的问题却少有人详细记录。
5.1 智能体陷入无效循环导致任务卡死
作为一个运行中特别容易出现的问题,就是智能体之间的消息循环。比如审核智能体打回修正意见后,Writer修改了两次还是不满足要求,然后再次提交、再次被打回,形成死循环。日志里能看到同一条类型的消息反复出现,但任务毫无进展。
排查思路分几步。第一,立即去历史消息列表里搜索同一个task_id的消息,看消息内容和时间戳,判断是否陷入循环。第二,看循环里的失败原因,如果是同一原因反复打回,说明智能体能力不足或需求描述不清,需要优化提示词或任务拆解粒度。第三,从机制层面,给每个任务设置最大迭代次数上限,比如3次。达到上限后,任务进入“需人工介入”状态,交给人工接手处理,而不是无限耗下去。
修改后的代码里,我就是在Coordinator的状态机中增加了一个计数器,每次收到修正反馈时累加,超过阈值就自动创建一条人工处理工单。
5.2 上下文长度失控
多智能体协作里,上下文管理是最容易被低估的问题。每个智能体除了自己的任务输入,还需要了解足够的背景信息,但背景给得太多,token消耗直线上升,甚至直接触发模型上下文窗口溢出。
刚开始跑任务时我发现一个现象:任务稍微复杂一点,执行智能体的输入就暴增——因为Planning阶段生成的子任务列表、其他智能体的输出、历史修改记录全被一股脑塞给它,结果不仅慢,还经常报错。
后来我调整策略,把上下文分成三层:
- 核心上下文:当前子任务描述+所需的最小输入数据,这是执行必须的信息。
- 参考上下文:与该子任务直接相关的上游产出,可裁剪摘要后提供。
- 全局上下文:任务的原始目标、约束条件、最终交付要求,全局保留但不提供详细中间过程。
每层上下文的取舍原则是“相关性越强的越完整,相关性弱的只给摘要”。通过这套策略,单个智能体的输入token数下降了约40%,且没再触发上下文超限的问题。
5.3 输出格式不稳定导致解析失败
这是另一个高频坑。提示词里明明写了“输出JSON”,模型有时还是会在JSON外面加解释性文字,或者输出残缺的JSON,直接导致下游解析崩溃。
我在工程上做了双重保护。第一层,在提示词中给出严格字段定义和示例,不只是说“JSON格式”,还给出一个最小示例结构。第二层更重要——在代码里加了一个健壮的解析函数,尝试直接JSON解析失败后,自动截取文本中最接近JSON块的部分,再做一次解析。如果还是失败,就返回给模型让它重新输出。
这个“容错解析”的方法虽然没有彻底消灭格式错误,但把由格式问题导致的任务失败率从原来的15%左右降到了2%以下,效果相当明显。
5.4 工具调用参数错误与校验缺失
工具调用时,智能体生成的参数经常出现类型错误、缺失字段、甚至凭空捏造意图。特别是复杂的工具Schema,模型有时候会在不知情的情况下填错参数。
我在工具注册表中加了参数Schema校验步骤。每次执行工具前,先根据已注册的参数定义检查参数是否齐全、类型是否正确、枚举值是否合法。校验不通过时,不执行工具,而是把错误信息作为“工具返回消息”回传给智能体,让它自行修正后重试。通过这种方式,工具调用的失败率明显下降,也避免了很多因为参数错误导致的诡异问题。
async def exec_tool(self, name, **kwargs): tool = self.tools[name] schema = tool["params_schema"] # 参数校验 for param_name, rule in schema.items(): if rule.get("required") and param_name not in kwargs: raise ToolValidationError( f"Missing required param: {param_name}" ) if "function" in rule and not callable(rule["function"]): # 更严格的正则校验根据具体参数来写 pass return await tool["func"](**kwargs)5.5 最终交付时需要注意的“最后一公里”问题
整个链路跑通后,还遇到过几个容易忽略的细节。
第一,智能体的输出要做格式特殊的清洗。模型有时候会偷偷在输出里加Markdown标记,或者不必要地加引号,这些在直接交付给用户时会显得很不专业。我这里加了一个输出清洗层,统一处理这些问题。
第二,要保留每次任务全量追踪链路,因为一旦任务交付后发现质量问题,必须能回溯到具体是哪个环节出的问题,否则如果交付后才发现数据有误,找不到责任方就非常尴尬。我做了消息全量留痕,“在哪里产生”和“被谁修改过”都有记录,这解决了一个很重要的问题。
第三,为用户留一个“人工介入”出口。哪怕是审核不通过、即使自动修正多次都不达标的情况,系统也应该能优雅地将任务转给人工处理,而不是卡死或交付低质量结果。
6. 商业化落地建议与后续扩展思路
6.1 从原型到生产环境还缺什么
如果你已经跑通了上面的最小系统,接下来的问题是:怎么把它变成一个可以稳定支撑业务的生产系统。
以我的经验,下面几件事在落地阶段优先级最高:
- 配置化中心:把模型、token上限、温度、超时时间、最大迭代次数全部外置到配置中心,实现能不发布代码就调整参数。
- 可观测与告警:任务成功率、平均时延、token成本、失败环节分布,这些指标要能实时可视化,异常时能自动告警。没有这一步,系统规模一大就会失控。
- 对账与成本管控:每个任务消耗了多少token、调用了多少次模型、各智能体占比如何,需要能按维度量化。我的做法是把每笔调用和每条消息都打点记录,形成账本,然后定期汇总。
- 灰度与回滚机制:同一套系统处理新业务时,建议先用小流量验证,通过后再逐步放大;一旦出现质量滑坡,能快速回滚到调整前版本。
6.2 我认为值得扩展的三个方向
这个项目做到现在,我感觉它未来最有价值的三个扩展方向是:
第一个是让规划智能体具备“反思修正”的能力。目前的任务拆解一轮定死,特殊情况下不够灵活。如果规划智能体能根据部分任务执行结果动态调整后续子任务的拆解策略,系统对复杂场景的适应力会大大增强。
第二个是加入并行调度能力。当前Executor被设计成一次只能跑一个工具,其实检索类工具的执行是可以并行的。比如同时检索多个数据源,然后把结果聚合起来再统一交给下游。这种能力一旦引入,任务吞吐量会有质的提升。
第三个是建立知识沉淀机制。已经跑过的成功处理路径,可以沉淀成一个经验库——例如让协调智能体在跑通一个复杂任务后总结“凡是这类需求,标准的处理模板是什么”,未来遇到相似任务时直接套用模板,能够减少不必要的规划开销、降低延迟和成本。
我在实际使用中有个体会比较深刻:别怕初期系统“傻”,多智能体架构的好处本来就是能边跑边优化。关键要把系统设计得透明、可观测、可干预——透明决定你能否快速发现问题,可干预决定你发现问题后是否容易调整。推荐那条开始分配角色时的路线,先把最核心的链路打磨清楚,再逐步扩展能力,这个节奏对Agent系统来说最稳。