ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent 响应延迟过高?从工具治理角度提供两条思路

Agent 响应延迟过高?从工具治理角度提供两条思路 大模型的一次响应往往不止一个工具调用而工具的参数又是分片、逐步抵达的。系统如何一边把生成过程展示给用户一边在参数就绪时就尽早执行工具同时保证结果不乱、对话还能继续这背后是一套兼顾“展示”与“执行”两条通道的工程实现。下面用一个购物场景来类比。你在一家 AI 导购里问“帮我把两件商品加入购物车再算一下总价”。模型在“说话”的过程中其实已经在生成几个动作的参数加入 A、加入 B、计算总价。理想的做法是参数一凑齐就立刻去执行而不是等模型把整句话说完再统一动手——这样用户能更快看到结果。但提前动手又带来风险动作是否执行重复、结果顺序是否错乱、对话记录还能不能接下去。01 先区分三个时间点一个工具调用从“出现”到“完成”至少经历三个时间点。开始生成流里出现 tool_use 块此时只知道工具名和调用 ID参数还不完整。参数生成完毕收到该块的结束标记这时才能把缓冲区当作完整 JSON 解析并执行。工具执行完毕得到结果回传给模型模型才能据此继续下一轮推理。这套实现的入口在 StreamedRound.relay()执行任务由 EagerDispatcher 管理。核心思路是在第 2 个时间点就启动工具而不是等整个模型响应生成完。02 从模型请求到工具参数编排器先构造带工具定义的请求再调用流式接口。购物端与商家端的编排器使用同一套处理方式。模型返回的不是一次性完整 JSON而是一连串事件。解析器按内容块的 index 记录状态把参数一点点拼起来块开始记录工具名、调用 ID创建参数缓冲区。增量把 partial_json 追加到对应工具的缓冲区。块结束参数写完尝试解析完整 JSON。这里有个容易混淆的点解析器是逐个处理流事件的但工具任务可以并发运行。所谓“并行”主要是异步任务在时间上的重叠而不是开多个线程同时解析同一条模型流。项目还区分了两种 JSON 解析各自用途不能混用执行解析用 json.loads() 读取完整缓冲区要求结果是对象。只有它成功工具才可能执行。展示解析对支持渐进式卡片的工具可临时补齐未闭合的括号、略过未写完的字符串用于生成界面预览。两者绝不能混用容错解析出来的半成品只能展示不能触发有副作用的操作。最终卡片也会重新校验参数、补充服务端数据再发出正式的 UI 事件。这好比菜还没炒熟可以先让顾客看一眼“锅里在冒热气”但绝不能把半生不熟的菜端上桌。03 为什么能提前执行多个工具收到某个工具的块结束信号后relay() 调用 dispatcher.dispatch()。后者通过 asyncio.ensure_future() 创建执行任务并以调用 ID 为键保存。假设模型一轮生成了 A、B 两个工具调用时间线大致是这样模型生成 A 的参数 → A 的块关闭 → 启动 A。模型继续生成 B 的参数 → B 的块关闭 → 启动 B。模型响应结束 → 等待 A、B 全部完成 → 回填结果。于是两段耗时可以被重叠起来工具 A 的执行与模型生成后续内容重叠工具 A、B 的执行彼此重叠。就像流水线上提前开工上一件还在加工下一件的图纸已经送进来。流结束后编排器以模型最终消息里的 tool_use 列表为准。EagerDispatcher.collect() 对已经启动的调用复用其任务对还没启动的调用补充执行再用 asyncio.gather() 等待全部结果。这里用调用 ID 去重解决了“流中提前执行一次、读最终消息后又执行一次”的重复风险。gather() 的返回列表与传入列表同序所以结果虽然可能乱序完成但发出的结果事件和写入对话的结果仍按模型调用顺序排列。04 结果怎样回到模型和前端工具统一由 BaseToolExecutor.execute() 分派。它负责选择普通业务 handler、展示工具或委托工具并把参数错误和执行异常转换成统一的 ToolOutcome。一个 ToolOutcome 有两类产物result_text作为 tool_result 写入对话供下一轮模型调用读取。events例如正式卡片 UI、购物车更新供前端消费。编排器在一轮工具全部结束后发出结果事件再把所有 tool_result 作为一条 user 消息追加到模型对话。若还需要模型回答就进入下一轮模型调用。前端接收的是 SSE服务端把 AgentEvent 编码成 event: 与 data: 帧浏览器逐帧解析。渐进式预览和最终 UI 使用调用 ID 关联使最终卡片能接替预览卡片。要注意一个时序细节tool_call 可以在模型仍在生成时发给前端但这个项目的常规 tool_result 是统一 join 后再按顺序发出的。不能把“工具提前完成”直接理解成“完成瞬间就向前端发结果”——展示通道可以渐进结果交付仍然是有序的。05 并发带来的正确性问题提前并发只是调度方式业务约束仍必须在执行层保证。还是购物场景两个修改购物车的调用可能同轮执行如果“读取购物车、检查限制、写入购物车”这三步交错进行检查结果就可能被破坏——比如两个动作各自都以为限额还够同时写入后总额超限。项目用按 session 划分的 asyncio.Lock 包住这三步确保同一会话内的修改不会交错。还要处理不完整输入和中断参数始终不是有效 JSON保留已生成的对话内容给该调用一个错误 tool_result提示模型重试但不运行工具。流报错、连接中断取消已启动但未结束的任务若对话里留下没有结果的 tool_use补一个中断结果保证下一次请求的消息结构有效。服务端工具如模型侧的网络搜索记录其块但不通过本地执行器运行。06 提炼成设计原则与边界这套实现可以概括为逐块确定参数、按调用 ID 提前启动、轮末统一 join、按原顺序回填、由业务层保护共享状态。流式预览是独立的展示通道执行只接受完整参数。这样既缩短了模型生成与工具执行之间的空等时间也保住了工具只执行一次、结果有序、对话可继续这三项正确性要求。最后要说明范围上述逐块解析和提前调度是仓库的 Messages API 运行时实现。仓库另有 Agent SDK 路径它把工具注册给 SDK并收集完整响应。不能把这里的流程说成所有接入方式都自行实现了同一套解析。
返回列表