尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
从LLM-Chat到Agent-Chat:多Agent协作入口的升级实践与踩坑记录
这两年做LLM应用落地我最大的感受是真正难的不是把模型接进对话框而是把“对话”升级成“协作”。“从 LLM-Chat 到 Agent-Chat”这个标题说的不是换个前端页面那么轻松的事。早期我们做的LLM-Chat本质上就是“用户说一句、大模型回一句”的单轮或多轮问答模型背后要有什么工具、什么知识库全靠提示词里硬塞。而Agent-Chat则是把原本一个人干活的模型变成了一个有多工种、有分工、有上下级、有信息传递的团队。这篇文章我会从一套真实升级项目的视角把多Agent协作入口的设计思路、核心机制、实操代码和踩坑实录一次性讲清楚。适合正在做LLM应用工程化、想把“问答机器人”往“智能体协作”方向推进的开发者参考。1. 升级动机LLM-Chat的边界与Agent-Chat的必然1.1 LLM-Chat的经典形态与天花板早期我们线上跑的LLM-Chat系统架构其实非常简单。一个网关接收用户消息把消息连同系统提示词一起送给大模型大模型返回文本网关把文本回给用户。如果要接外部能力就靠函数调用或插件机制由模型决定要不要触发某个工具。这套架构上线快、调试直观但用一段时间后天花板很明显。第一个问题是“上下文混装”。所有工具的描述、知识库索引、对话历史、用户意图全塞在提示词里。工具少的时候还能靠模型自己理解工具一旦超过十个模型就开始“精神分裂”。要么频繁调用错误的工具要么在工具描述里迷失主线把用户问题带偏。我遇到过最典型的案例用户问“帮我对比两款产品的售后政策”模型居然去调用了“计算运费”工具因为在提示词里这个工具的描述和售后政策字段有重叠。第二个问题是“状态断裂”。LLM-Chat的每一次对话虽然带历史但本质上是一个无状态的请求-响应循环。一旦中间需要多步操作比如“先查库存→再算价格→最后生成订单”每一步都要靠模型自己记住中间结果而中间结果如果超过上下文窗口就被挤掉了。做过落地的人都懂这种链路跑十次能成两三次已经是运气。第三个问题是“能力不可编排”。LLM-Chat的调度是隐式的模型看到什么工具描述就决定用什么。但真实业务里很多任务是有固定流程的。比如售后工单先验证身份、再查订单、判断责任方、生成处理方案。这属于明确的流程编排靠模型自由发挥输出的稳定性完全不可控。1.2 多Agent协作解决的本质问题Agent-Chat的升级方向是把这个“单体大脑”拆成“多角色团队”。每个Agent只负责一个明确领域比如订单Agent只懂订单库存Agent只懂库存调度Agent只负责决定把问题交给谁。这带来的第一个质变是上下文隔离。每个Agent拥有自己独立的系统提示词、工具列表和记忆片段。调度层只需要传递与该Agent相关的上下文而不是把所有历史一股脑塞给每个模型。上下文长度暴跌模型精度反而大幅上升。第二个质变是流程显式化。任务编排不再依赖模型临场发挥而是通过代码定义好的协作协议完成。调度Agent把任务拆解成子任务分配给不同Agent子任务之间的依赖关系由调度层管理。模型负责单点智能代码负责流程稳定。第三个质变是可观测性。在LLM-Chat里你很难回答“这一步模型为什么调用这个工具”。但在Agent-Chat里每一步的决策者、执行者、输入输出都是独立的单元日志可以精确到“哪个Agent收到了什么、返回了什么、耗时多少”。线上排障效率完全不在一个量级。所以我从一开始就把这次升级定义为“入口升级”不是换一个大模型而是把原本单模型的对话入口改造成一个多Agent协作的调度入口。2. 入口升级的总体设计思路2.1 核心设计原则调度与执行分离这次升级我最坚持的一点是调度逻辑和Agent执行逻辑必须完全解耦。调度层不知道Agent内部怎么实现Agent内部也不知道上下游还有谁。所有协作都通过统一的消息协议完成。设计上我们分了四层。接入层负责接收用户请求做基础预处理比如会话识别、敏感词过滤、意图初判。接入层不调用任何大模型它只负责把请求包装成标准消息。调度层是整个系统的核心。它维护Agent注册表、路由规则、会话状态负责决定“这个消息应该给谁”。调度层可以调用大模型做路由判断也可以走规则路由取决于场景复杂度。执行层是各个业务Agent。每个Agent独立部署独立维护自己的提示词和工具。它们从调度层接收任务执行完把结果返回调度层。Agent之间不允许直接通信避免协作关系变成一团乱麻。记忆层负责会话级和任务级的状态存储。会话级状态记录用户与系统的完整交互历史任务级状态记录当前任务链中每个子任务的执行结果。2.2 为什么不让Agent直接通信一开始有同事提议让Agent直接互相调用比如订单Agent调支付Agent像微服务一样。这个方案听起来自然但实际跑起来是灾难。原因很简单Agent的调用路径不是恒定的同一个问题今天可能走A链路明天可能走B链路。如果Agent之间直接通信那么每次变更都要改多个Agent的代码而且日志会变成一团乱麻很难追踪一条请求到底经过了哪些节点。我们后来采用了“星型拓扑”所有消息都经过调度层中转。这样做的好处是第一链路清晰只要看调度层的日志就能还原完整调用链第二Agent开发完全解耦新增一个Agent只需要在调度层注册不需要改动其他Agent第三能力复用方便一个Agent可以被多条链路复用而不自知。代价是调度层可能成为性能瓶颈。我们的做法是调度层不处理重逻辑只做路由和消息转发控制在毫秒级。真正耗时的大模型推理都发生在执行层所以调度层只要做成无状态服务水平扩展很容易。3. 核心机制设计与实操细节3.1 Agent注册与能力声明Agent-Chat里的每个Agent都必须在调度层注册注册信息包含三个核心部分Agent唯一标识、处理能力描述、接口地址。Agent唯一标识是稳定ID比如“order_agent”“inventory_agent”。处理能力描述是给调度模型的“说明书”它必须写得清晰无歧义。接口地址是调度层调用Agent的HTTP端点。能力描述怎么写很有讲究。我的经验是不要写工作职责要写边界条件。比如订单Agent的描述不能只写“负责订单相关事务”要写清楚“负责查询订单状态、修改订单备注、生成订单退换货申请不负责支付操作支付问题转payment_agent”。边界写清楚路由准确率会提升很多。注册信息保存的时候我们还做了一层能力索引。调度层把每个Agent的描述文本做向量化存进向量库。当用户请求到来时调度层可以先做一次向量检索筛掉明显不相关的Agent只把候选Agent的描述塞给路由模型。这样即使业务方注册了几十个Agent路由模型每次只看三五个候选准确率和推理速度都能兼顾。3.2 消息路由与意图分发消息路由是Agent-Chat最关键的环节也是踩坑最多的环节。我们试过两种方案规则路由和模型路由。规则路由适用于意图明确的场景。比如消息里出现订单号且包含“查”字直接走订单Agent。这种方案快、便宜、可解释但覆盖不了复杂表达。用户说“我上周买的东西到现在没发货帮我看看”里面既没订单号也没有明确的“查”字规则就失效了。模型路由用的是调度模型加少数候选Agent描述做意图分类。这种方式灵活但有个隐藏风险调度模型的输出不是百分百稳定。我们遇到过模型把“退货退款”路由到“售后投诉”Agent的情况因为两个Agent的描述都提到了“退款”。最终我们采用了混合路由先规则后模型。规则命中就直接走规则结果同时记录置信度规则没命中才走模型路由。模型路由的结果也不是直接执行而是要经过一层校验检查目标Agent的边界描述是否与用户意图匹配。不匹配就拒绝并二次路由。另外强烈建议在路由消息时带上“路由理由”。调度模型输出目标Agent ID的同时输出一句自然语言的理由。理由是给开发人员排障用的也是给用户兜底用的。有一次路由错了用户反馈后我们看理由发现模型理解成了“用户想对比产品”但用户实际是想“开售后单”。理由字段帮我们快速定位了Agent描述里缺失的边界条件。3.3 上下文管理与记忆传递多Agent协作里最容易翻车的不是单个Agent的对话能力而是上下文怎么在多Agent之间传递。我们设计了三层记忆结构。第一层是用户会话记忆存的是用户和系统的总对话历史。这一层记忆属于用户不属于任何Agent。无论消息经过哪个Agent最终都要回到调度层调度层把当前消息和Agent的返回结果追加到会话历史里。第二层是任务上下文存的是当前任务链的执行状态。比如这次任务是“查订单并计算赔偿金额”那么订单Agent返回的订单信息会暂存在任务上下文里后续计算赔偿的Agent可以直接读取不需要用户重新提供。第三层是Agent私有记忆存的是Agent自己沉淀的知识和历史执行经验。这个不会传回调度层避免信息爆炸。实操中要给每一层记忆设置生命周期。用户会话记忆跟着会话走30天无活跃就清理任务上下文跟着任务走任务结束就销毁Agent私有记忆由Agent自己管理可以长期保存。我见过线上事故就是因为任务上下文没销毁上一个用户的理赔金额被下一个用户引用了。这种问题一旦发生后果很严重。3.4 协作协议与任务编排多Agent协作不能靠调度层“一个问题一个Agent”的简单分发解决真实任务往往是多个Agent接力完成。我们定义了一套轻量级的任务编排协议。协议核心是一个“任务对象”包含任务ID、目标描述、状态、子任务列表、上下文挂载点。调度层根据用户意图和已有流程定义决定当前任务的子任务序列。举个例子用户发起“退货退款申请”。调度层识别出需要三个子任务第一查订单状态第二校验退货退款资格第三生成退款单。这三个子任务有先后依赖调度层会在订单Agent返回成功后把订单数据写入任务上下文再带着任务上下文调用资格校验Agent最后调用提单Agent。编排不仅是串行也支持并行和条件分支。比如同时查库存和查价格可以并行如果资格校验不通过直接终止任务并生成失败原因不需要走到提单步骤。这些控制逻辑全部在调度层代码里写死不让模型自由发挥。我建议编排逻辑单独建一个流程定义文件用JSON或YAML描述不要硬编码在代码里。这样产品同学可以调整流程顺序开发不用跟着改代码。流程定义文件本身就是一份可读的文档上线前评审也方便。4. 关键代码实现与落地细节4.1 标准消息体与路由结构所有Agent之间传递的消息必须遵循统一的协议结构。我们用的是一套轻量JSON协议核心字段如下{ message_id: d3f2c1a9-7b0e-4a2f-9c56-8b4e2f0a1c7d, session_id: user_00x_20250101, task_id: task_8890123, sender: scheduler, receiver: order_agent, message_type: task_request, priority: normal, payload: { action: query_order, params: { order_id: A10086, customer_id: cust_001 } }, context_ref: { task_context_id: ctx_7788, include_keys: [order_snapshot] }, metadata: { timestamp: 2025-01-01T10:30:00Z, trace_id: trace_ab12cd } }这里有几个设计细节要特别注意。context_ref是用来“拉取”而不是“推送”上下文的。调度层不会把完整上下文随消息发给Agent而是给一个上下文ID和需要的键名。Agent根据ID去记忆层按需读取。这样做的好处是减少Agent的无效数据接收量在大上下文场景下效果尤其明显。message_type区分了任务请求、任务响应、状态查询、心跳等类型。调度层根据类型走不同的处理逻辑而不是所有消息一个流程。一开始我们只用了task_request和task_response两种后来线上排查问题发现信息不够又加了status_report和error_report让Agent主动上报执行状态。trace_id是贯穿整个任务链的追踪ID。所有Agent在日志里都必须输出这个ID这样调度层、执行层、记忆层的日志可以串联。没有trace_id的时候排查一次跨Agent问题要翻六七个系统日志有了之后一条命令全查出来。4.2 调度模型的路由与校验调度层调用模型的逻辑我用Python实现了一版核心思路是“候选过滤 决策 校验”。class AgentRouter: def __init__(self, agent_registry, vector_index): self.agent_registry agent_registry self.vector_index vector_index def route(self, user_message, user_intent): # 候选过滤先语义检索缩小范围 candidates self.vector_index.search(user_message, top_k5) candidate_metas [ self.agent_registry.get_agent_description(agent_id) for agent_id in candidates ] # 决策让模型从候选里挑一个最合适的目标 prompt self.build_routing_prompt( user_messageuser_message, user_intentuser_intent, candidatescandidate_metas ) decision self.routing_model.run(prompt) # 校验决策结果必须通过边界检查 target_agent decision[target_agent] boundary_ok self.boundary_check( user_messageuser_message, agent_metaself.agent_registry.get_agent_description(target_agent) ) if not boundary_ok: return self.fallback_route(user_message) return target_agentboundary_check的实现不复杂核心是判断Agent描述里的边界条件与用户消息是否冲突。比如Agent描述明确写了“不负责支付操作”但用户消息里出现了“扣款失败”就要拒绝这次路由。候选过滤这一步当初没有直接采用因为早期版本是把所有Agent的描述都塞给模型结果模型面对几十个描述时选择困难。改成候选过滤后路由准确率从78%提升到了91%最关键的是推理延迟降了将近一半。我还顺手做了一个路由置信度统计。调度模型返回一个0到1的置信度值低于0.6的请求自动转入人工兜底队列不让用户面对大概率错误的结果。线上跑了一段后用户投诉率明显下降。4.3 Agent执行器的封装模式执行层的Agent我们统一封装了一套执行器开发者只需要关注两件事处理什么任务、返回什么结果。class BaseAgent: def __init__(self, agent_id, llm_client, tools): self.agent_id agent_id self.llm_client llm_client self.tools tools async def handle_task(self, message): # 1. 从消息里解析任务参数 params message[payload][params] # 2. 从记忆层拉取需要的上下文 context await self.pull_context(message.get(context_ref)) # 3. 执行核心逻辑模型 工具协作 result await self.run_core(params, context) # 4. 把结果写回任务上下文 await self.push_result(message[task_id], result) # 5. 返回标准响应 return self.build_response(message, result) async def run_core(self, params, context): # 子类实现 raise NotImplementedErrorAgent的核心逻辑我们建议做成“工具优先、模型兜底”。能用确定性工具解决的比如查数据库、调接口就不走大模型。只有需要理解和生成文本的地方才调用模型。这样做的直接收益是省钱和提速。一个查库存的动作走SQL是几十毫秒走模型函数调用是几秒钟价格差上百倍。我还要求所有Agent的输出必须是结构化JSON不允许输出纯自然语言。即便最终要给用户看的回复也要在JSON里单独放一个user_facing_message字段。这样调度层可以把Agent的内部结果和展示文本分开处理方便后续做多轮追问和结果复用。4.4 会话状态机的设计Agent-Chat入口的会话状态比LLM-Chat复杂得多。LLM-Chat的会话状态就一个message数组Agent-Chat需要维护会话里的“当前活动任务”状态。我们用了一张表存会话状态核心字段如下字段说明session_id用户会话IDcurrent_task_id当前正在执行的任务ID空表示无活动任务task_status任务状态pending / running / waiting / finished / failed / cancelledwaiting_reason当前阻塞原因比如“等待用户补充地址信息”active_agents当前参与任务链的Agent列表task_context_ids该会话关联的任务上下文ID列表这张状态表是调度层判断“继续执行旧任务”还是“开启新任务”的依据。一个常见场景是用户在任务执行过程中追加新消息。比如用户先问“我的订单到哪了”调度层开启了查订单任务任务执行到一半用户又说“顺便帮我把收货地址改了”。此时调度层不能当作完全独立的新任务处理而是要把这条追加消息作为当前任务的补充输入。我们通过状态表判断如果当前任务处于waiting状态且新消息能解除阻塞则直接把新消息写入任务上下文让当前任务继续执行。这个设计在实操中帮我避免了一个大坑。最初版本是每条用户消息都独立路由导致用户说“好的”的时候调度层完全不知道“好的”指的是什么只能开一个无头无尾的闲谈任务。有了会话状态机后“好的”会被识别为对当前任务的确认指令直接推进任务流转。5. 常见问题与排查经验5.1 路由不准加规则还是换提示词线上最容易遇到的现象是同一个问题上午路由对了下午路由错了。排查这类问题我的顺序是先查规则命中日志再看模型路由置信度最后看Agent描述是否有改动。经验是路由不准大部分时候不是模型智商问题而是候选Agent描述出现了语义重叠。比如两个Agent都包含“退款”关键词模型就会随机派发。解决办法不是疯狂调提示词而是把语义重叠部分剥掉明确划分边界。有一次我们只改了订单Agent描述里的一句话把“处理退款”改成“处理订单退款支付环节的资金原路退回由支付Agent处理”路由准确率立刻回升。如果改了描述还不稳再考虑加硬规则覆盖高频场景。硬规则命中后不走模型同时不影响低频场景的灵活性。5.2 上下文串扰与脏数据多Agent上下文传递的最严重问题就是A任务的结果被B任务引用。我们踩过一次真实事故任务上下文的key命名太粗糙两个不相关的任务用了同一个key结果库存Agent读取到了订单Agent写入的数据。这个问题的根本解决办法是在上下文key上增加任务ID前缀。读取上下文的时候强行校验所属任务不允许跨任务读取。写入的时候也要带上写任务ID调度层在任务结束时统一校验上下文里的数据来源发现来源不一致直接隔离。另外建议上下文里的敏感字段单独加密存储。比如用户手机号、地址这类字段不应该在任务上下文里明文流转。我们后来把所有上下文数据的存储改为加密读取时按需解密日志里只输出脱敏后的值。5.3 Agent循环调用与任务卡死多Agent协作最怕的是A调BB又调A形成死循环。虽然我们设计了星型拓扑但逻辑层还是可能出现循环的。比如订单Agent在生成退款方案时发现需要发票信息于是请求发票Agent发票Agent验证发票后发现订单状态异常又请求订单Agent更新状态订单Agent更新状态后又触发退款方案重新生成……这个循环直到上下文爆掉才被截断。我们在调度层加了深度限制单个任务链的子任务数量不能超过20超过直接终止并触发人工审查。同时为每个子任务设置超时时间超时就标记失败并执行兜底逻辑。兜底逻辑不重新调Agent而是直接给用户回复“当前处理遇到问题已记录并转人工跟进”保证用户体验不卡死。这些限制看起来简单粗暴但确实管用。上线到现在半年没有发生过一次无限循环的事故。5.4 入口响应变慢与并发控制Agent-Chat的链路比LLM-Chat长单次请求可能经历调度模型、多个Agent的多次模型调用整体延迟翻了几倍。用户打字半天没反应体验很差。我的优化思路是“能并行就并行、能跳步就跳步”。并行执行上面说了调度的子任务里没有依赖的全塞进线程池。跳步是指如果某个环节的输出对当前任务结果没有影响就先不调用等用户追问时再补齐。比如用户只是问“能不能退货”就不需要先生成完整的退款单先查资格就够了等用户确认退货再走后续流程。给用户侧的反馈也要做分层先秒回“收到正在处理”让用户感知到系统响应了再把最终结果异步返回。这个前端交互的升级对体验的提升比后端优化还直观。6. 个人实操体会与后续扩展从LLM-Chat升级到Agent-Chat我最大的体会是问题复杂度不是线性增加而是指数增加。单模型对话只需要考虑“模型答得好不好”多Agent协作要面对的是“每个Agent答得好不好、路由对不对、上下文乱不乱、任务链能不能稳定跑完”。但熬过这轮升级系统的能力边界完全不一样了。以前遇到复杂任务只能回答“我暂时无法处理”现在可以直接拆解并执行这是量变到质变的区别。如果让我重新来一次我会在项目启动第一天就把可观测性做起来。trace_id、结构化日志、状态表这些不是后期补的优化项而是从一开始就要有的基础设施。中途再补观测的代价比想象中高一倍都不止。后续这个入口还可以往三个方向扩展一是把人工客服无缝接入Agent协作链路让用户在Agent处理不了的时候一键转人工工单上下文自动同步客服不用让用户复述第二遍二是把Agent的决策过程沉淀成可召回的历史案例出现类似问题时优先匹配成功经验减少模型的重复推理三是把Agent调度能力从“对话入口”抽象成“任务入口”也就是不仅用户通过聊天触发Agent业务系统的表单、定时任务、外部事件也能触发同样的协作流程。到那时候这个多Agent协作入口就不再只是聊天机器人的升级版而是整个业务系统的智能任务中枢了。
RELATED

相关推荐

电赛C题小车寻迹:MSP432主控、PWM与灰度阈值自适应拿分策略

电赛C题小车寻迹:MSP432主控、PWM与灰度阈值自适应拿分策略

简介:这是一份面向电子设计竞赛与嵌入式学习者的完整获奖方案,基于MSP432主控芯片实现了2022年电赛C题智能小车主从协同系统。主车利用OpenMV完成寻迹、停止线识别与障碍物测距,从车配合视觉辅助与蜂鸣器提示,并在软件层面涉及嵌入…

📅 2026/10/19 2:40:31
OpenCV Haar级联分类器人脸检测实战:原理、参数调优与经验总结

OpenCV Haar级联分类器人脸检测实战:原理、参数调优与经验总结

1. 先搞清楚Haar级联分类器的“底层逻辑”1.1 拿到一张人脸图,算法到底在找什么OpenCV里的Haar级联分类器,是我接触计算机视觉后第一个真正动手跑起来的人脸检测模型。你去看网上那些“三分钟人脸检测”教程,通常就是复制几行代码&#xff0c…

📅 2026/10/19 2:40:31
电赛C题小车寻迹:MSP432与OpenMV底层配置与高频考点全解析

电赛C题小车寻迹:MSP432与OpenMV底层配置与高频考点全解析

简介:2022年电子设计竞赛C题江苏省赛区一等奖作品完整工程,主控采用MSP432超低功耗微控制器,面向电子竞赛参赛者、嵌入式爱好者和机器视觉学习者。方案基于主从双车寻迹系统,主车配备OpenMV摄像头模块完成图像识别、停止线检测与障…

📅 2026/10/19 2:40:31
MORE NEWS

更多资讯

📰

开源代码审查CLI工具:Git集成+LLM混合推理实战

1. 项目概述:一个真正能落地的开源代码审查 CLI 工具“open-code-review”这个名字乍一听有点抽象,但拆开来看就非常实在:open不是指“开源”这个宽泛概念,而是指“开放上下文”——它不锁死在某个 IDE 或 Web 界面里,…

📰

open-code-review:基于git diffs的开源LLM代码审查CLI工具

1. 这不是另一个“AI代码审查工具”,而是一套可落地的开源协作范式最近两周,我在三个不同规模的团队里被问到同一个问题:“你们用的 open-code-review 是怎么跑起来的?”——注意,没人问“它是什么”,而是直…

📰

Transformer搭建音乐生成模型:从MIDI Token到AI续写钢琴曲

把一段旋律丢给程序,让它接着往下写,还要补上像模像样的和声与节奏——AI谱曲这个方向,过去几年换过好几批“主角”,从隐马尔可夫到RNN,再到如今各种音乐生成Demo背后的真正主力:Transformer。这篇是这个系…

📰

STM32H743 FPU与CMSIS-DSP实现1024点FFT实战指南

简介:这份资源面向STM32嵌入式开发者与数字信号处理学习者,提供一套基于STM32H743、通过STM32CubeMX搭建的纯净FFT验证例程,解决全网缺少简单直接FFT性能验证工程的问题。包内共1698个文件,以722个C源文件、336个头文件、151个汇编…

📰

DAG-GNN:用图神经网络与连续优化从数据中学习有向无环图

如果只给你一张全是数字的表格,每一列是一个变量,每一行是一次观测,你能不能还原出这些变量之间的有向依赖关系?不仅要还原,还要保证这张图是一个DAG——有向无环图,不能有环路。这种从纯数据中“反推”结构…

📰

从GitHub PR到open-code-review:代码评审流程的自动化升级

1. 为什么我把团队的代码评审从GitHub PR搬到了open-code-review先说说背景。我们团队大概三十来人,维护着六个主仓库,平时走的是GitHub原生PR流程。从表面看,PR review该有的都有:行内评论、Reviewer列表、Approval机制。但实际跑…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬