多Agent 意图识别与路由
多 Agent 意图识别与路由
原文章:Agent 意图识别与路由
1. 原文的思想
生产环境推荐采用:
规则 + 小模型 + LLM + State + Router + Planner + Policy + Fallback
整体流程:
1 | |
核心原则:
简单问题规则解决,稳定问题小模型解决,复杂问题 LLM 解决;Router 负责分流,Planner 负责复杂任务编排,State 负责多轮上下文,Policy 负责约束,Fallback 负责兜底。
2. 我们的Agent流程图
总体流程图:
1 | |
简要流程图:
1 | |
3. 具体步骤的介绍
系统采用 主 Agent 统一理解请求、通过委派工具调用领域子 Agent、由子 Agent 执行业务 的方式。意图理解与领域选择在主 Agent 的推理过程中一起完成。
1 | |
1. 接收用户请求,准备上下文
请求进入 ChatService 后,系统获取用户、会话、权限以及本轮消息,结合会话历史和当前任务状态,准备 Agent 运行上下文。
上下文用于理解连续对话。例如,用户只说“继续”,需要结合已有任务判断继续什么;用户追问“这个文档中的图片”,需要找到此前上传文档的轻量引用。
对于已有待确认操作、部分任务恢复等场景,服务端会先尝试使用专用逻辑处理;需要常规语义理解和领域选择的请求,再进入主 Agent。
2. 装配当前用户可用的领域能力
AgentFactory 根据领域配置和用户权限,生成主 Agent 可以调用的子 Agent 集合:
- 公共域:由代码固定注册,承担文档处理、长任务规划和任务状态协调等能力。
- 业务域:通过 Paladin 配置系统提示词、Tool、Skill 和权限码。
系统先按用户权限过滤各领域的 Tool、Skill,再汇总实际可用的能力描述。某个领域过滤后没有任何可用能力,就不会注册对应的委派入口。
因此,主 Agent 的路由候选范围由实际配置和用户权限共同决定。
3. 主 Agent 理解意图,选择处理方式
主 Agent 结合以下信息判断用户需求:
- 当前用户请求及会话上下文。
- 当前任务状态。
- 各领域的可用能力描述。
- 系统提示词中的路由和执行规则。
随后决定直接回复、追问,还是委派给某个领域。
例如,普通活动查询应选择具备相关能力的活动域;文档理解请求应委派公共域;超出可处理范围的请求,则说明当前能力边界。
这里没有统一要求模型先输出 intent、slots、route 对象,而是通过选择委派工具和填写调用参数,表达意图理解与路由结果。
4. 判断是否需要先进行长任务规划
主 Agent 同时判断请求能否在当前轮次可靠完成。
对于需要长任务执行的请求,先委派公共域建立任务、保存完整计划并展示给用户,取得一次整体确认后,再按计划选择业务域执行。
判断依据包括:
- 是否需要批量、分批处理。
- 步骤之间是否存在依赖。
- 是否需要等待异步结果。
- 是否能够在单轮执行预算内可靠完成。
多意图不一定等于长任务,单领域请求也可能需要长任务规划。 例如,单领域的大批量操作仍可能需要计划与跨轮执行。
5. 通过委派工具调用目标子 Agent
每个可用子 Agent 都通过 AgentScope 的 SubAgentTool 包装成工具,注册到主 Agent 的工具集中,例如:
1 | |
主 Agent 生成对应的工具调用后,框架根据注册关系调用目标子 Agent。
模型负责选择委派工具,工具名称与子 Agent 的绑定关系由代码和配置确定。
在实际调用前,执行守卫会检查当前任务状态及执行阶段,约束需要先规划的请求,并限制主 Agent 每次只委派一个领域。
6. 子 Agent 使用本域工具执行业务
目标子 Agent 是领域内的 ReActAgent,持有本域系统提示词和经过权限过滤的 Tool、Skill。
子 Agent 根据委派目标选择能力、组织参数、调用工具,再根据返回结果决定下一步:
1 | |
参数处理分布在主 Agent、子 Agent 和具体工具中,没有统一的入口 Slot 管理层。缺少必要信息时,需要补充或追问;实际执行还受到参数校验、权限约束、任务状态和操作确认机制的限制。
识别出用户想执行某项操作,并不代表已经获得执行许可。
7. 根据结果继续编排,必要时保存进度
子 Agent 返回结果后,主 Agent 判断任务是否已经完成:
- 结果完整:进入最终回复。
- 需要其他领域能力:根据中间结果选择下一领域,继续委派。
- 需要长任务跨轮执行:记录真实结果、执行游标和剩余工作,通过任务机制安排后续推进。
- 缺少信息或执行结果不确定:按实际情况请求用户介入。
跨领域处理通过主 Agent 分步编排完成;当前约束下,每次只委派一个领域,领域内部再按运行时开放的安全能力执行。
8. 直接返回领域结果,或由主 Agent 汇总输出
每次领域委派都会携带 direct_return 参数:
true:本轮领域结果预计可以完整回答用户;返回后满足直返条件时,直接使用该结果。false:还需要后续调用、规划、参数确认或多领域综合,由主 Agent 继续处理。
最终回复基于工具和子 Agent 的真实返回结果生成。普通任务输出业务答案;等待确认的任务展示待确认内容;跨轮任务则根据实际执行状态反馈进度。
4. 关键问题
4.1 我们是直接调用大模型进行意图识别的吗
是的,普通业务请求的意图识别,主要由主 Agent 调用大模型完成。
不过,我们没有单独调用一次模型来“识别意图”,再调用另一个模块路由。实际流程是:
1 | |
例如,用户要求查询活动配置,模型根据活动域的能力描述,选择 delegate_to_activity_domain,框架再执行该委派工具。
所以更准确的表述是:
我们通过主 Agent 的大模型完成语义理解和领域选择,以工具调用的形式输出路由决策,再由程序负责校验和执行。
另外,已有操作的明确“确认”“取消”,以及部分任务恢复请求,会先经过服务端专用逻辑处理,并非所有输入都要重新交给大模型做业务路由。
4.2 复杂任务规划我们是怎么处理的?当主agent拿到一个很复杂的请求之后,他后续是怎么做的?
更具体地说,主 Agent 负责判断和委派,公共域负责生成并保存计划,任务服务负责确认状态、执行进度和续跑控制。 普通长任务与结构化批次的执行方式还有区别。 Annotation 1
公共域是我们系统中承载通用能力和任务协调能力的一个子 Agent
1 | |
1. 主 Agent 先判断:这个请求是否需要进入长任务流程
判断依据包括任务规模、步骤依赖、异步等待、结果体量和当前轮次的执行预算。
例如,一个请求包含“生成图片,再使用生成结果执行后续操作”,就需要考虑异步依赖,不能只看有几个对象。
这里也有程序约束:对于“多个对象分别处理、批量处理”等明显场景,服务端会通过规则标记需要先规划,执行守卫会拦截直接执行业务的调用。
因此,一般复杂度由模型结合上下文判断,部分明确场景由规则识别并强制进入规划流程。
2. 主 Agent 把规划任务委派给公共域
主 Agent 调用 delegate_to_common_domain,将用户目标和必要上下文交给公共域,当前阶段使用 direct_return=false。
公共域通过大模型和长任务工作流完成规划。工作流规定的首次规划顺序是:
1 | |
各次 Skill 加载独占一次工具调用批次,但会在同一次公共域委派内继续推理和执行,不需要用户每加载一次就回复“继续”。
这里的 Skill 是指导模型如何规划和调用工具的规范,实际业务目标仍由大模型结合请求、查询结果和可用能力进行拆解。
3. 公共域提交的是结构化计划,并真正保存下来
计划中的每个高层步骤可以包含:
| 字段 | 含义 |
|---|---|
title、description |
这一步做什么 |
domain |
负责处理的领域 |
sideEffect |
是否涉及写操作等副作用 |
waitForAsyncResult |
是否需要等待异步结果 |
batch |
可选的批次动作与各项业务参数 |
服务端校验计划格式;如果包含批次,还会检查动作是否有已注册执行器、参数是否合法。
保存成功后,任务会记录步骤、计划版本和摘要,进入:
1 | |
只有模型在回复中写出“一、二、三”,并不算规划成功;完整计划必须持久化。 对受控首次规划,委派返回时还会检查计划是否已经保存。
4. 展示完整计划,用户确认后再开始执行
系统向用户展示全部高层步骤,取得一次整体确认。
确认时,服务端会把当前 planVersion 记录为 confirmedPlanVersion,然后安排后续执行。开始运行轮次时,还会核对:
- 当前计划版本是否已经确认。
- 任务状态是否允许执行。
- 续跑事件是否有效。
- 任务是否超过执行期限。
因此,“用户确认”对应的是服务端保存的具体计划版本。用户补充要求导致计划实质变化时,需要更新计划并重新整体确认,不能沿用旧确认。
5. 确认后,按步骤类型选择执行方式
这里需要区分两条路径:
| 步骤类型 | 如何执行 |
|---|---|
| 普通长任务步骤 | 主 Agent 根据当前步骤和已有结果,委派对应领域;子 Agent 使用本域工具执行,再按任务协议记录结果 |
带有已注册 batch.action 的批次步骤 |
服务端 DeterministicBatchCoordinator 按固定参数逐项调用执行器,管理批量大小、操作标识、结果和游标 |
所以,前面“主 Agent 按计划委派业务域”的说法描述了普通步骤;已经声明合法结构化批次的步骤,可以由服务端直接推进,无需模型逐项编排。
一个计划也可以混合这两种步骤。例如,前面是静态参数批次,后面是需要消费前序结果的普通依赖步骤。
6. 每轮保存真实进度,剩余工作通过续跑机制推进
执行时不会要求一次模型调用完成全部工作。系统根据真实结果更新:
1 | |
接近本轮预算时,停止启动新业务调用,完成当前轮次收口,并根据状态安排后续推进。
续跑事件携带任务和事件标识。下一轮重新读取持久化状态,再恢复到当前步骤或剩余批次。因此,正常分批执行依靠保存的进度和续跑事件推进,不靠用户反复回复“继续”。
如果正在等待异步结果,则进入等待状态,由结果监控或核对流程衔接后续处理。
7. 异常时先判断能否安全继续,完成后输出结果
计划内写操作会先建立稳定操作标识,关联任务、计划版本、步骤及游标。执行结果不确定时,优先利用已有操作引用核对,降低重复执行风险。
后续处理取决于实际状态:
- 取得有效进展且仍有剩余:保存进度,继续推进。
- 异步操作尚未完成:等待结果。
- 副作用结果不确定:先核对已有操作。
- 计划实质变化:重新规划并确认。
- 连续没有有效进展、状态保存失败等情况:停止自动推进,等待用户处理。
- 任务全部完成:记录完成状态,返回业务结果。
我们的实现可以概括为:模型提出计划和业务决策,程序保存计划、绑定确认版本,并控制每轮执行与恢复。 当前计划主要按编号步骤和游标推进,不应直接描述成通用 DAG 调度器。