gogo-agent

单次对话多意图识别与执行

前面我们讲过了三层意图识别,把前面的链路总结一下,一次请求进来有两个情况: L1/L2 命中 L3 命中 三层意图识别里,L1(正则)和 L2(向量最近邻)本质都是单标签分类器——一条规则、一条最近邻,只能给出一个意图。而L3则承载…

TL;DR

前面我们讲过了三层意图识别,把前面的链路总结一下,一次请求进来有两个情况: L1/L2 命中 L3 命中 三层意图识别里,L1(正则)和 L2(向量最近邻)本质都是单标签分类器——一条规则、一条最近邻,只能给出一个意图。而L3则承载…

前面我们讲过了三层意图识别,把前面的链路总结一下,一次请求进来有两个情况: - L1/L2 命中 - L3 命中 三层意图识别里,L1(正则)和 L2(向量最近邻)本质都是单标签分类器——一条规则、一条最近邻,只能给出一个意图。而L3则承载着一个至关重要的功能,那就是用户的多意图识别! (IntentRecognitionResult(L1/L2 的产物)里 multiIntent 恒为 false)

// L1/L2 的便捷工厂:只会产出单意图(multiIntent=false)
public static IntentRecognitionResult single(Source source, IntentCategory category,
                                             Confidence confidence, String reason, Double score) {
    IntentItem item = new IntentItem(category, category.getDefaultTargetAgent(), confidence, reason);
    return new IntentRecognitionResult(source, List.of(item),
            category, false /* multiIntent 恒为 false */, reason, score);
}

用户的一句"审批过了,帮我规划下杭州行程,顺便看看那边的酒店,再帮我把回程的高铁订了",里面塞了三四个意图(行程规划、酒店查询、火车预订),而且它们之间有先后依赖——得先规划出方案,才谈得上订哪一班高铁。 这就带来三个必须解决的问题: 1. 识别:怎么从一句话里抽出多个意图,而不是只认出最显眼的那个? 2. 排序:多个意图谁先谁后?"先规划后预订"这种依赖关系必须被尊重,否则会出现"还没方案就去订票"的荒唐执行。 3. 执行与整合:怎么把多个子任务依次交给不同的专业子智能体去做,并把它们各自的结果拼成一次自然连贯的回复,而不是甩给用户三段互不相干的机器回答?

多意图的数据契约

L3 的系统提示词 intent-recognition-agent-system.md 把多意图 JSON 的格式钉死:

{
  "intents": [
    { "intent": "itinerary_planning", "target_agent": "itineraryPlanAgent",
      "confidence": "high", "reason": "用户审批已通过,明确要求行程规划,并指定途经点。" },
    { "intent": "hotel_search", "target_agent": "itineraryPlanAgent",
      "confidence": "high", "reason": "用户同时要求查询杭州酒店,属于行程规划后续动作。" }
  ],
  "primary_intent": "itinerary_planning",
  "multi_intent": true,
  "overall_reason": "用户一句话包含行程规划和酒店查询两个意图,二者有先后依赖关系,先规划再查酒店。"
}

契约里有三个专为"多意图执行"服务的字段,我们针对多意图的约束是这样的:

2. **多意图处理**:
   - 若一句话包含多个意图,必须全部识别出来,放入 `intents` 数组中。
   - 按**执行优先级/依赖关系**排序:有前后依赖的(如先申请后规划、先规划后预订),先执行的排前面。
   - 在 `primary_intent` 中指定最核心或最紧迫的意图。

多意图必走 MasterAgent

拿到意图识别的结果JSON 后,如果是多意图,我们必须强制走MasterAgent,因为多意图天然含有跨子智能体的编排与依赖,没有一个子智能体能独立完成,因此必须交给专门的协调者——MasterAgent。 于是多意图的执行入口收敛到这里:

private Mono<Msg> dispatchByIntent(String intentJson, List<Msg> inputMessages,
                                   String contextQuestion, String sessionId, String userId) {
    Optional<DirectDispatchPlan> planOpt = tryPlanDirectDispatch(intentJson);
    if (planOpt.isPresent()) {
        // 单意图快车道:直连子智能体
        return dispatchSubAgentDirectly(planOpt.get(), inputMessages, contextQuestion, sessionId, userId);
    }
    // 多意图(及低置信/兜底)走 MasterAgent 编排
    ReActAgent masterAgent = agentRegistry.getAgent(MASTER_AGENT_NAME);
    return masterAgent.call(buildMasterInput(inputMessages, contextQuestion, intentJson))
            .doOnSubscribe(s -> executionRegistry.register(sessionId, masterAgent))
            .flatMap(masterResult -> handleMasterResult(masterResult, sessionId));
}

注意最后一句:完整的意图 JSON(含有序 intents 数组)通过 buildMasterInput 被塞进 MasterAgent 的上下文——这是 MasterAgent 知道"该按什么顺序做哪几件事"的唯一依据。 但是需要注意的是,多意图的"依次执行"并不是一段 for 循环手写的调度代码,而是交给 MasterAgent(一个 ReActAgent)的推理循环去驱动——它把每个子智能体当成一个"工具",在 ReAct 的"思考→调工具→观察→再思考"循环里,按意图清单顺序一个个调用。 MasterAgent 提示词里专门有一段"多意图处理",这就是"依次执行"的行为契约:

版本提示

模型、框架与接口会持续变化。涉及版本号、参数与生产配置时,请在实践前对照对应官方文档。

LLMentor系统化学习大模型应用工程

内容来自个人课程知识库备份,并经过结构化整理。技术版本持续演进,生产使用前请结合官方文档验证。