使用 Spring AI + LangGraph4j 构建 AI 搜索 MultiAgent 实战指南

35 阅读22分钟

使用 Spring AI + LangGraph4j 构建 AI 搜索 MultiAgent 实战指南

副标题: 基于图结构的多智能体工作流设计与实现

发布日期: 2026-02-13
阅读时间: 约 30 分钟
难度等级: 中级

关键词: Spring AI, LangGraph4j, MultiAgent, AI 搜索, Java 架构, 意图识别, 查询改写, DeepSeek API


摘要: 面向刚入行的 Java 程序员,介绍如何使用 Spring AI 和 LangGraph4j 框架构建一个完整的 AI 搜索 MultiAgent 系统。文章采用教程与技术深度分析结合的方式,从理论概念到实战实现,详细讲解意图识别、查询改写、内容搜索和结果整合四个核心 Agent 的设计与协作。重点阐述为何选择 MultiAgent 架构而非单 Agent 的设计决策,提供完整的代码示例和最佳实践,帮助读者在 2 小时内完成从零搭建到功能验证的全过程。


引言

面对用户查询,如何让 AI 系统能够智能判断是否需要联网搜索?如何优化查询以获得更好的搜索结果?如何整合多个搜索源生成准确答案?MultiAgent 架构为我们提供了优雅的解决方案。而 LangGraph4j 的图结构模型,让复杂的工作流编排变得前所未有的直观和灵活。

随着 AI 技术的发展,越来越多的应用开始集成智能搜索能力。传统的链式调用框架在处理复杂工作流时存在局限性——难以表达条件分支、循环和并行执行。LangGraph4j 基于图结构的状态机驱动模型,通过节点(Node)、边(Edge)和状态(State)的协作,为构建复杂的 MultiAgent 应用提供了更强大的能力。

本文将从理论和实战两个层面,详细介绍如何使用 Spring AI 和 LangGraph4j 框架构建一个完整的 AI 搜索 MultiAgent 系统。读者将理解图结构模型相比链式调用的核心优势,掌握 StateGraph、Agent 节点和状态管理的核心概念,并能够独立完成从零搭建到功能验证的全过程。

本文将依次介绍:核心概念解析(Spring AI + LangGraph4j)、MultiAgent vs 单 Agent 架构对比、图结构编排原理、系统架构设计、四个核心 Agent 的实战实现、最佳实践和性能优化建议。


目录

  1. 核心技术栈解析
  2. MultiAgent vs 单 Agent 架构深度对比
  3. AI 搜索 MultiAgent 系统架构设计
  4. 项目初始化与基础配置
  5. 意图识别 Agent 实现
  6. 查询改写 Agent 实现
  7. 内容搜索 Agent 实现
  8. 结果整合 Agent 实现
  9. LangGraph4j 工作流编排与 REST API 实现
  10. 最佳实践与性能优化

章节 1: 核心技术栈解析

在构建 AI 搜索 MultiAgent 系统之前,我们需要先了解两个核心技术框架:Spring AI 和 LangGraph4j。

1.1 Spring AI 框架概述

Spring AI 是 Spring 生态系统中的 AI 集成框架,旨在简化大语言模型(LLM)和其他 AI 服务与 Spring 应用的集成。它的设计思想与 Spring Boot 一脉相承——通过自动配置和声明式抽象,让开发者能够以最小的代码量集成 AI 能力。

Spring AI 的核心特性包括:统一的模型抽象(支持 OpenAI、Anthropic、Azure OpenAI 等多种提供商)、流式响应支持、函数调用(Function Calling)能力、以及与 Spring 生态的无缝集成。对于 Java 开发者来说,Spring AI 的最大优势在于学习曲线平缓——如果你熟悉 Spring Boot,你就能快速上手 Spring AI。

在 MultiAgent 系统中,Spring AI 主要负责底层的 LLM 调用和对话管理,为各 Agent 提供统一的 AI 能力接口。通过 Spring AI 的 ChatClient,我们可以方便地调用 DeepSeek 等大模型进行意图识别、查询改写和结果总结。

@Service
public class ChatService {
    private final ChatClient chatClient;

    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    public String ask(String question) {
        return chatClient.prompt()
            .user(question)
            .call()
            .content();
    }
}

1.2 LangGraph4j 框架解析

LangGraph4j 是基于图结构的 LLM 应用框架,提供状态机驱动的 Agent 编排能力。与传统的链式调用不同,LangGraph4j 通过图结构模型,支持条件分支、循环、并行执行,为构建复杂的 MultiAgent 应用提供了更强大的能力。

核心概念

  1. StateGraph(状态图): 整个应用的容器,维护一个全局的 State 对象
  2. State(状态): 共享的数据结构,在节点之间传递信息
  3. Node(节点): 执行具体逻辑的单元(如意图识别 Agent)
  4. Edge(边): 描述节点之间的流转关系

LangGraph4j 是 LangChain AI 项目中 LangGraph 的 Java 版本移植,旨在为 Java 开发者提供更直观的工作流编排方式。相比传统的链式调用,图结构模型能够更自然地表达复杂的业务逻辑,特别是涉及条件判断、循环和并行的场景。

1.3 图结构 vs 链式调用

传统的链式调用框架(如 LangChain4j 的链式模式)将工作流表示为线性的步骤序列:Input → Step1 → Step2 → Output。这种模式对于简单的任务很有效,但在面对复杂场景时存在明显限制:

链式调用的局限:

  • 难以表达条件分支(如根据意图选择不同路径)
  • 不支持循环(如重试逻辑)
  • 执行顺序固定,缺乏灵活性
  • 难以可视化复杂的工作流

图结构模型的优势:

  • 支持条件分支:可以根据状态动态选择下一个节点
  • 支持循环:可以定义回退和重试逻辑
  • 支持并行:多个节点可以并行执行
  • 可视化友好:图结构直观展示工作流
  • 状态机驱动:清晰的执行路径和状态转换

例如,在 AI 搜索场景中,图结构可以优雅地表达以下逻辑:

  1. 意图识别节点 → 根据意图(QA/SEARCH)选择不同路径
  2. QA 路径 → 直接返回 LLM 答案
  3. SEARCH 路径 → 查询改写 → 内容搜索 → 结果整合 → 返回答案

1.4 Spring AI + LangGraph4j 协同工作

Spring AI 和 LangGraph4j 可以完美配合,各司其职:

  • Spring AI: 提供 LLM 调用能力、模型抽象、Prompt 管理
  • LangGraph4j: 提供工作流编排、状态管理、节点协作

在本文的 MultiAgent 系统中:

  • Spring AI 的 ChatClient 负责调用 DeepSeek API 进行意图识别、查询改写和结果总结
  • LangGraph4j 的 StateGraph 负责编排四个 Agent 节点的执行流程
  • AgentState 作为共享状态,在各节点之间传递查询、意图、搜索结果等信息

这种协同架构既保持了 Spring AI 简洁的 AI 调用接口,又通过 LangGraph4j 获得了强大的工作流编排能力。


章节 2: MultiAgent vs 单 Agent 架构深度对比

在设计 AI 搜索系统时,一个关键的架构决策是:使用 MultiAgent(多智能体)架构还是单 Agent(单一智能体)架构。本节将深入分析两种方案的优劣,帮助你做出明智的选择。

2.1 单 Agent 方案的局限

单 Agent 方案将所有逻辑集中在一个 Agent 中,用户查询直接交给这个 Agent 处理。表面上看,这种方式似乎简单直接,但在实际应用中存在明显问题:

职责不清:所有逻辑(意图识别、查询改写、搜索、整合)都混在一起,违反单一职责原则。代码难以理解和维护。

可扩展性差:如果需要添加新的能力(如图片搜索、语音输入),必须修改核心 Agent,容易引入 bug。

维护困难:一个 bug 可能影响整个系统,排查和修复都很困难。代码耦合度高,任何修改都需要全面测试。

难以并行处理:由于所有逻辑是顺序执行的,无法充分利用并发能力,导致响应时间长。

难以测试:无法单独测试某个功能(如意图识别),必须运行整个系统,测试成本高。

2.2 MultiAgent 架构的核心优势

MultiAgent 架构将任务分解为多个 Agent,每个 Agent 专注于特定职责,通过协作完成复杂任务。相比单 Agent 方案,MultiAgent 具有以下核心优势:

职责分离:每个 Agent 专注于特定职责(意图识别、查询改写、内容搜索、结果整合),符合单一职责原则。代码清晰、易理解。

可扩展性:添加新功能时,只需创建新的 Agent 或扩展现有 Agent,不影响其他部分。如需要图片搜索,只需创建 ImageSearchAgent。

可维护性:每个 Agent 的代码相对独立,修改一个 Agent 不会影响其他 Agent。Bug 的范围可控,排查和修复更简单。

容错能力:单个 Agent 失败不会导致整个系统崩溃,可以实现优雅降级。例如,搜索引擎失败时,可以返回 LLM 生成的答案。

可测试性:每个 Agent 可以独立测试,编写单元测试更容易。例如,可以单独测试意图识别的准确率。

并行处理:某些 Agent 可以并行执行(如多个搜索查询并行处理),充分利用并发能力,提升响应速度。

2.3 LangGraph4j 图结构在 MultiAgent 中的价值

LangGraph4j 的图结构模型为 MultiAgent 架构提供了天然的表达能力:

状态机驱动:StateGraph 提供清晰的状态转换逻辑,Agent 之间的协作关系一目了然。状态管理自动化,无需手动传递。

工作流可视化:图结构直观展示 Agent 之间的协作关系,便于理解、调试和文档生成。团队协作时更容易沟通。

循环与条件分支支持:天然支持条件分支(如根据意图选择不同路径)和循环(如重试逻辑),这些在链式调用中难以实现。

并行执行:通过图结构可以定义并行执行的节点,如多个搜索查询可以同时执行,汇总结果后再处理。

可组合性:Agent 节点可以像积木一样组合,构建更复杂的工作流。工作流模块化,便于复用。

2.4 适用场景分析

何时选择 MultiAgent

  • 任务复杂,需要多个步骤或能力
  • 需要条件分支和动态路径
  • 需要并行处理提升性能
  • 需要良好的可扩展性和可维护性
  • 需要独立测试各模块

何时单 Agent 足够

  • 任务简单,单一能力即可完成
  • 不需要条件分支或循环
  • 不需要并行处理
  • 性能要求不高
  • 快速原型验证

AI 搜索场景的判断:AI 搜索任务涉及意图识别、查询改写、内容搜索、结果整合等多个步骤,需要根据意图选择不同路径,搜索引擎调用可以并行,这正是 MultiAgent 架构的典型应用场景。

2.5 权衡考量

虽然 MultiAgent 架构优势明显,但也需要考虑以下权衡:

复杂度增加:MultiAgent 需要额外的协调逻辑和状态管理,比单 Agent 更复杂。但对于复杂任务,这个复杂度是值得的。

协调开销:Agent 之间的通信和状态管理会带来一定的性能开销。但在大多数情况下,这个开销可以忽略,且可以通过优化减少。

适用场景:MultiAgent 适用于复杂任务,对于简单任务可能过度设计。因此,在选择架构时需要评估任务的实际复杂度。

学习成本:LangGraph4j 的图结构模型需要一定的学习成本,但一旦掌握,构建复杂工作流的效率会显著提升。

总结:对于 AI 搜索这类复杂任务,MultiAgent 架构的收益远大于成本。LangGraph4j 的图结构模型进一步降低了 MultiAgent 的实现复杂度,使其成为理想的选择。


章节 3: AI 搜索 MultiAgent 系统架构设计

明确了技术栈和架构选择后,让我们设计具体的 AI 搜索 MultiAgent 系统。

3.1 系统整体架构

AI 搜索 MultiAgent 系统由以下核心模块组成:

  1. REST API 层:对外提供搜索接口,接收用户请求,返回搜索结果
  2. StateGraph 工作流层:使用 LangGraph4j 编排 Agent 节点
  3. Agent 层:四个核心 Agent 实现具体业务逻辑
  4. LLM 调用层:通过 Spring AI 调用 DeepSeek API
  5. 搜索引擎层:调用 Google/Bing API 获取实时信息
  6. 状态管理层:AgentState 作为共享状态在各节点间传递信息

架构图

用户请求
    ↓
[AiSearchController] (REST API)
    ↓
[StateGraph 工作流编排]
    ↓
    ├─→ [IntentAgent] (意图识别)
    │       ↓
    │   根据 intent 分支
    │       ├─→ [AnswerAgent] (直接返回 QA)
    │       └─→ [QueryRewriteAgent] (查询改写)
    │               ↓
    │           [SearchAgent] (内容搜索 - 并行)
    │               ↓
    │           [ResultMergeAgent] (结果整合)
    │               ↓
    └─→ 返回结果

3.2 LangGraph4j StateGraph 设计

StateGraph 是整个系统的核心编排器。我们将设计包含四个节点的图结构:

节点定义

  1. intent: 意图识别节点,判断用户查询类型
  2. query_rewrite: 查询改写节点,生成查询变体
  3. search: 内容搜索节点,调用搜索引擎 API
  4. merge: 结果整合节点,生成最终答案

边定义

  • 固定边: intent → query_rewrite
  • 条件边: query_rewrite → search (如果 intent = SEARCH)
  • 固定边: search → merge

状态类(AgentState)

public class AgentState {
    private String originalQuery;      // 原始查询
    private IntentType intent;          // 意图类型 (QA/SEARCH)
    private List<String> rewrittenQueries;  // 改写后的查询
    private List<SearchResult> searchResults; // 搜索结果
    private String finalAnswer;         // 最终答案

    // getters and setters
}

3.3 四个核心 Agent 的职责

1. IntentAgent(意图识别 Agent)

  • 职责:判断用户查询是普通问答还是需要联网搜索
  • 输入:原始查询
  • 输出:意图类型(QA/SEARCH)
  • 实现:使用 Spring AI ChatClient 调用 DeepSeek API

2. QueryRewriteAgent(查询改写 Agent)

  • 职责:在保持语义不变的前提下生成多个查询变体
  • 输入:原始查询
  • 输出:改写后的查询列表(3-5 个)
  • 实现:使用 Spring AI ChatClient 生成查询变体

3. SearchAgent(内容搜索 Agent)

  • 职责:调用搜索引擎 API 获取实时信息
  • 输入:改写后的查询列表
  • 输出:搜索结果列表
  • 实现:使用 WebClient 并行调用 Google/Bing API

4. ResultMergeAgent(结果整合 Agent)

  • 职责:整合多个搜索结果,生成准确、简洁的答案
  • 输入:搜索结果列表
  • 输出:最终答案
  • 实现:去重、排序、合并,使用 LLM 生成总结

3.4 Agent 之间的协作流程和数据流

  1. 用户请求 → AiSearchController 接收请求,创建初始 AgentState
  2. 意图识别 → IntentAgent 读取 originalQuery,调用 DeepSeek 判断意图,写入 intent
  3. 条件分支 → StateGraph 根据 intent 决定后续路径
    • 如果是 QA → 直接调用 AnswerAgent
    • 如果是 SEARCH → 进入查询改写流程
  4. 查询改写 → QueryRewriteAgent 读取 originalQuery,生成多个查询变体,写入 rewrittenQueries
  5. 内容搜索 → SearchAgent 读取 rewrittenQueries,并行调用搜索引擎 API,写入 searchResults
  6. 结果整合 → ResultMergeAgent 读取 searchResults,去重、排序、合并,生成 finalAnswer
  7. 返回结果 → StateGraph 返回最终的 AgentState,Controller 提取 finalAnswer 返回

3.5 项目结构设计

src/main/java/com/example/ai_search/
├── AiSearchApplication.java          # Spring Boot 主类
├── config/
│   └── AiConfig.java                # AI 配置类
├── state/
│   └── AgentState.java              # 状态类定义
├── agent/
│   ├── IntentAgent.java              # 意图识别 Agent
│   ├── QueryRewriteAgent.java        # 查询改写 Agent
│   ├── SearchAgent.java             # 内容搜索 Agent
│   └── ResultMergeAgent.java        # 结果整合 Agent
├── workflow/
│   └── AiSearchWorkflow.java        # StateGraph 编排
├── model/
│   ├── SearchRequest.java           # API 请求模型
│   ├── SearchResponse.java          # API 响应模型
│   └── SearchResult.java           # 搜索结果模型
└── controller/
    └── AiSearchController.java      # REST API 控制器

配置文件

  • application.yml: Spring Boot 配置(DeepSeek API Key、搜索引擎配置)
  • pom.xml: Maven 依赖配置

章节 4: 项目初始化与基础配置

4.1 创建 Spring Boot 项目

使用 Spring Initializr(start.spring.io/)创建项目:

  • Project: Maven
  • Language: Java
  • Spring Boot: 3.2.0
  • Dependencies: Spring Web, Spring WebFlux

4.2 Maven/Gradle 依赖配置

添加以下依赖到 pom.xml

<dependencies>
    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Spring AI -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
        <version>1.0.0-M4</version>
    </dependency>
    
    <!-- LangChain4j -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>0.34.0</version>
    </dependency>
    
    <!-- LangGraph4j -->
    <dependency>
        <groupId>io.github.fuyou-lxm</groupId>
        <artifactId>langgraph4j-langchain4j</artifactId>
        <version>0.1.0</version>
    </dependency>
    
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

4.3 配置文件设置

application.yml 中配置:

spring:
  ai:
    openai:
      api-key: ${DEEPSEEK_API_KEY}
      base-url: https://api.deepseek.com/v1
      chat:
        options:
          model: deepseek-chat
          temperature: 0.7
          max-tokens: 2000

# 搜索引擎配置
search:
  engine: google  # 或 bing
  google:
    api-key: ${GOOGLE_API_KEY}
    search-engine-id: ${GOOGLE_SEARCH_ENGINE_ID}
  bing:
    api-key: ${BING_API_KEY}

章节 5: 意图识别 Agent 实现

意图识别是整个系统的第一个关键节点。它决定了用户查询是需要联网搜索还是可以直接用 LLM 回答。

5.1 意图识别原理和策略

意图识别主要有两种策略:

关键词匹配策略

  • 基于规则,查询是否包含特定关键词(如"最新"、"2024"、"新闻")
  • 实现简单,但不够灵活
  • 需要维护关键词列表

LLM 分类策略

  • 使用 LLM 分析查询语义
  • 更准确,能够理解上下文
  • 需要 LLM 调用,增加延迟

本文采用 LLM 分类策略,通过 DeepSeek API 判断意图。

5.2 IntentAgent 核心代码实现

IntentAgent 作为 LangGraph4j 的节点函数,需要接收 AgentState 作为输入,返回更新后的 AgentState

package com.example.ai_search.agent;

import com.example.ai_search.state.AgentState;
import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 意图识别 Agent
 * 判断用户查询是否需要联网搜索
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class IntentAgent {

    private final ChatLanguageModel chatModel;

    /**
     * 识别意图(作为 LangGraph4j 节点函数)
     * @param query 用户查询
     * @return 意图类型
     */
    public AgentState.IntentType recognizeIntent(String query) {
        log.info("开始识别意图,查询: {}", query);

        String prompt = buildIntentPrompt(query);
        String response = chatModel.generate(prompt);
        
        // 解析响应
        IntentType intentType = parseIntentResponse(response);
        
        log.info("意图识别完成: {}", intentType);
        return intentType;
    }

    /**
     * 构建意图识别提示词
     */
    private String buildIntentPrompt(String query) {
        return String.format("""
            你是一个意图识别专家。请分析以下用户查询,判断是否需要联网搜索获取实时信息。

            用户查询:%s

            判断标准:
            1. 如果查询涉及最新事件、实时数据、时效性信息,需要联网搜索
            2. 如果查询是常识性问题、定义、概念解释等,不需要联网搜索
            3. 如果查询涉及特定时间范围(如"2024年"、"最新"),需要联网搜索
            4. 如果查询需要引用具体来源或数据,需要联网搜索

            请只返回以下两个关键词之一:
            - SEARCH(需要联网搜索)
            - QA(不需要联网搜索)

            直接返回关键词,不要输出其他内容。
            """, query);
    }

    /**
     * 解析意图响应
     */
    private IntentType parseIntentResponse(String response) {
        String normalizedResponse = response.trim().toUpperCase();
        if (normalizedResponse.contains("SEARCH")) {
            return IntentType.SEARCH;
        }
        return IntentType.QA;
    }
}

5.3 与 DeepSeek API 集成

使用 Spring AI 的 ChatLanguageModel 调用 DeepSeek API。配置方法在 4.3 节已说明。

5.4 状态更新逻辑

在 LangGraph4j 工作流中,节点函数不需要手动更新状态。LangGraph4j 会自动处理状态传递。IntentAgent 只需要返回意图类型,工作流会将其写入 AgentState

5.5 错误处理和边界情况处理

  • API 调用失败:默认返回 SEARCH,保证流程继续
  • 响应格式错误:默认返回 QA,安全保守策略
  • 空查询:抛出异常,由工作流捕获

章节 6: 查询改写 Agent 实现

查询改写的目的是在不改变语义的前提下,生成多个查询变体,提高搜索召回率。

6.1 查询改写策略和方法

同义词替换:将关键词替换为同义词,如"快速" → "极速"、"高效"

句式变化:改变句子结构,如"如何学习 Java" → "Java 学习方法"

语义扩展:添加相关概念,如"Spring Boot" → "Spring Boot 教程、Spring Boot 入门"

6.2 QueryRewriteAgent 核心代码实现

package com.example.ai_search.agent;

import com.example.ai_search.model.QueryRewriteResult;
import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 查询改写 Agent
 * 在保持语义不变的前提下生成多个查询变体
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class QueryRewriteAgent {

    private final ChatLanguageModel chatModel;

    /**
     * 改写查询
     * @param originalQuery 原始查询
     * @param queryCount 改写查询数量(包括原始查询)
     * @return 改写结果
     */
    public QueryRewriteResult rewriteQuery(String originalQuery, int queryCount) {
        log.info("开始改写查询,原始: {}", originalQuery);

        String prompt = buildRewritePrompt(originalQuery, queryCount);
        String response = chatModel.generate(prompt);

        List<String> rewrittenQueries = parseRewriteResponse(response);
        
        // 确保包含原始查询
        if (!rewrittenQueries.contains(originalQuery)) {
            rewrittenQueries.add(0, originalQuery);
        }

        log.info("查询改写完成,生成 {} 个查询", rewrittenQueries.size());
        
        return QueryRewriteResult.builder()
                .originalQuery(originalQuery)
                .rewrittenQueries(rewrittenQueries)
                .build();
    }

    /**
     * 构建查询改写提示词
     */
    private String buildRewritePrompt(String query, int count) {
        return String.format("""
            你是一个查询优化专家。请改写以下查询,生成 %d 个不同表达方式的查询。

            原始查询:%s

            改写要求:
            1. 保持语义不变,确保核心意图一致
            2. 使用不同的表达方式和词汇
            3. 涵盖不同的角度和侧重点
            4. 每个查询都应该是独立的搜索查询
            5. 不要改变查询的核心关键词

            输出格式:
            查询1:改写后的查询1
            查询2:改写后的查询2
            ...

            请只输出改写后的查询列表,不要输出其他内容。
            """, count, query);
    }

    /**
     * 解析改写响应
     */
    private List<String> parseRewriteResponse(String response) {
        return List.of(response.split("\n"))
                .stream()
                .map(String::trim)
                .filter(line -> !line.isEmpty())
                .map(line -> {
                    // 移除"查询X:"前缀
                    if (line.contains(":")) {
                        return line.substring(line.indexOf(":") + 1).trim();
                    }
                    return line;
                })
                .toList();
    }

    /**
     * 改写查询(简化版本,默认生成 3 个查询)
     */
    public List<String> rewriteQuery(String originalQuery) {
        return rewriteQuery(originalQuery, 3).getRewrittenQueries();
    }
}

6.3 改写质量控制

  • 语义一致性检查:通过 LLM 验证改写查询是否保持语义
  • 去重:使用集合去除重复查询
  • 数量控制:限制最多 5 个改写查询

6.4 原查询 vs 改写查询对比示例

原查询改写查询
如何学习 Spring BootSpring Boot 教程、Spring Boot 入门指南、学习 Spring Boot 的方法
2024 年最新的 AI 技术趋势2024 AI 技术发展、2024 年人工智能新进展、AI 领域 2024 年趋势

章节 7: 内容搜索 Agent 实现

内容搜索 Agent 负责调用搜索引擎 API 获取实时信息。

7.1 搜索引擎 API 集成

支持 Google Custom Search API 和 Bing Search API。

Google Custom Search API

  • 需要创建 Custom Search Engine (CSE)
  • 获取 API Key 和 Search Engine ID
  • 支持自定义搜索范围

Bing Search API

  • 需要 Azure 账户和 Bing Search API Key
  • 支持网页搜索、新闻搜索等

7.2 SearchAgent 核心代码实现

(代码已在 examples/SearchAgent.java 中提供,使用 WebClient 并行调用 Google Search API)

7.3 搜索结果解析和结构化

搜索结果包含:

  • title:结果标题
  • link:结果 URL
  • snippet:结果摘要
  • displayUrl:显示 URL

7.4 并发搜索优化

使用 parallelStream() 并行执行多个查询,充分利用并发能力:

queries.parallelStream().forEach(query -> {
    List<SearchResult> results = searchSingleQuery(query);
    allResults.addAll(results);
});

7.5 状态更新

搜索结果写入 AgentState.searchResults 字段。


章节 8: 结果整合 Agent 实现

结果整合 Agent 负责合并搜索结果并生成最终答案。

8.1 结果整合策略

  • 去重:根据 URL 去除重复结果
  • 排序:根据摘要长度和相关性排序
  • 合并:选择最相关的结果(最多 10 条)

8.2 ResultMergeAgent 核心代码实现

(代码已在 examples/ResultMergeAgent.java 中提供)

8.3 使用 LLM 生成总结性答案

基于选定的搜索结果,使用 LLM 生成准确、简洁的答案。

8.4 质量评估和结果优化

  • 去重算法:使用 URL 作为唯一键
  • 排序策略:根据摘要长度排序(摘要越长通常信息越丰富)
  • 结果数量限制:最多使用 10 条结果生成答案,避免超时

8.5 最终状态构建

将整合结果写入 AgentState.finalAnswer 字段。


章节 9: LangGraph4j 工作流编排与 REST API 实现

9.1 StateGraph 构建

StateGraph 是整个系统的核心编排器。构建步骤:

  1. 创建 GraphBuilder
  2. 添加节点
  3. 设置起点
  4. 添加边(固定边和条件边)
  5. 设置终点
  6. 编译图
GraphBuilder<AgentState> builder = StateGraph.builder(AgentState.class);

// 添加节点
builder.addNode("intent", this::intentNode);
builder.addNode("query_rewrite", this::queryRewriteNode);
builder.addNode("search", this::searchNode);
builder.addNode("merge", this::mergeNode);
builder.addNode("qa", this::qaNode);

// 设置起点
builder.setEntryPoint("intent");

// 添加条件边
builder.addConditionalEdges("intent", this::shouldSearch, Map.of(
    "SEARCH", "query_rewrite",
    "QA", "qa"
));

// 添加固定边
builder.addEdge("query_rewrite", "search");
builder.addEdge("search", "merge");

// 设置终点
builder.setFinishPoint("qa");
builder.setFinishPoint("merge");

// 编译图
Graph<AgentState> graph = builder.build();

9.2 图编译和执行

执行工作流:

// 初始化状态
AgentState initialState = new AgentState();
initialState.setOriginalQuery(query);

// 执行图
AgentState finalState = graph.invoke(initialState);

9.3 REST API 端点设计

POST /api/search 接收用户查询,返回搜索结果。

请求格式

{
  "query": "如何学习 Spring Boot"
}

响应格式

{
  "query": "如何学习 Spring Boot",
  "answer": "Spring Boot 是一个快速开发框架...",
  "intentType": "WEB_SEARCH",
  "sources": [...],
  "totalResults": 5
}

9.4 端到端测试

curl -X POST http://localhost:8080/api/search \
  -H "Content-Type: application/json" \
  -d '{"query":"如何学习 Spring Boot"}'

章节 10: 最佳实践与性能优化

10.1 代码组织和命名规范

  • Agent 类以 Agent 结尾(IntentAgentQueryRewriteAgent
  • 状态类使用 State 结尾(AgentState
  • 节点函数命名清晰(intentNodesearchNode

10.2 配置管理最佳实践

  • 敏感信息保护:使用环境变量存储 API Key
  • 环境配置:使用 Spring Profile 区分开发、测试、生产环境
  • 配置验证:使用 @ConfigurationProperties 验证配置

10.3 性能优化建议

  • 状态缓存:缓存常见查询的结果
  • 节点并发优化:使用 parallelStream() 并行执行
  • API 调用优化:设置合理的超时时间和重试策略

10.4 LangGraph4j 工作流优化

  • 节点拆分:复杂节点可以拆分为多个子节点
  • 状态瘦身:状态对象只包含必要字段
  • 条件跳转优化:尽早判断条件,减少不必要的节点执行

10.5 监控和日志记录

  • 日志记录:每个节点记录执行时间和结果
  • 指标监控:监控 API 调用延迟、成功率
  • 错误追踪:使用 Spring Boot Actuator 和 Micrometer

10.6 扩展性建议

添加新 Agent

  1. 实现 Agent 类
  2. 在 StateGraph 中添加节点
  3. 添加边连接节点

集成其他 AI 能力

  • 图片搜索:创建 ImageSearchAgent
  • 语音输入:使用 Whisper API
  • 代码生成:集成 Codex 或 Copilot

结论

本文介绍了如何使用 Spring AI 和 LangGraph4j 构建一个完整的 AI 搜索 MultiAgent 系统。通过图结构模型,我们实现了灵活的工作流编排,支持条件分支、循环和并行执行。

核心收获

  • MultiAgent 架构通过职责分离,提升了系统的可扩展性和可维护性
  • LangGraph4j 的图结构模型相比链式调用,提供了更强大的工作流编排能力
  • Spring AI 简化了 LLM 调用,让开发者专注于业务逻辑

下一步行动

  1. 下载完整代码示例,运行并验证功能
  2. 尝试扩展新 Agent 或集成其他 AI 能力
  3. 探索 LangGraph4j 在更复杂场景中的应用

MultiAgent 架构不仅适用于 AI 搜索,还可以应用于智能客服、自动化工作流、内容生成等多个场景。希望本文能够为你提供启发和参考。


参考资源


文章标签: #Java #SpringAI #LangGraph4j #MultiAgent #AI #架构设计 #实战教程