使用 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 的实战实现、最佳实践和性能优化建议。
目录
- 核心技术栈解析
- MultiAgent vs 单 Agent 架构深度对比
- AI 搜索 MultiAgent 系统架构设计
- 项目初始化与基础配置
- 意图识别 Agent 实现
- 查询改写 Agent 实现
- 内容搜索 Agent 实现
- 结果整合 Agent 实现
- LangGraph4j 工作流编排与 REST API 实现
- 最佳实践与性能优化
章节 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 应用提供了更强大的能力。
核心概念:
- StateGraph(状态图): 整个应用的容器,维护一个全局的 State 对象
- State(状态): 共享的数据结构,在节点之间传递信息
- Node(节点): 执行具体逻辑的单元(如意图识别 Agent)
- Edge(边): 描述节点之间的流转关系
LangGraph4j 是 LangChain AI 项目中 LangGraph 的 Java 版本移植,旨在为 Java 开发者提供更直观的工作流编排方式。相比传统的链式调用,图结构模型能够更自然地表达复杂的业务逻辑,特别是涉及条件判断、循环和并行的场景。
1.3 图结构 vs 链式调用
传统的链式调用框架(如 LangChain4j 的链式模式)将工作流表示为线性的步骤序列:Input → Step1 → Step2 → Output。这种模式对于简单的任务很有效,但在面对复杂场景时存在明显限制:
链式调用的局限:
- 难以表达条件分支(如根据意图选择不同路径)
- 不支持循环(如重试逻辑)
- 执行顺序固定,缺乏灵活性
- 难以可视化复杂的工作流
图结构模型的优势:
- 支持条件分支:可以根据状态动态选择下一个节点
- 支持循环:可以定义回退和重试逻辑
- 支持并行:多个节点可以并行执行
- 可视化友好:图结构直观展示工作流
- 状态机驱动:清晰的执行路径和状态转换
例如,在 AI 搜索场景中,图结构可以优雅地表达以下逻辑:
- 意图识别节点 → 根据意图(QA/SEARCH)选择不同路径
- QA 路径 → 直接返回 LLM 答案
- 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 系统由以下核心模块组成:
- REST API 层:对外提供搜索接口,接收用户请求,返回搜索结果
- StateGraph 工作流层:使用 LangGraph4j 编排 Agent 节点
- Agent 层:四个核心 Agent 实现具体业务逻辑
- LLM 调用层:通过 Spring AI 调用 DeepSeek API
- 搜索引擎层:调用 Google/Bing API 获取实时信息
- 状态管理层:AgentState 作为共享状态在各节点间传递信息
架构图:
用户请求
↓
[AiSearchController] (REST API)
↓
[StateGraph 工作流编排]
↓
├─→ [IntentAgent] (意图识别)
│ ↓
│ 根据 intent 分支
│ ├─→ [AnswerAgent] (直接返回 QA)
│ └─→ [QueryRewriteAgent] (查询改写)
│ ↓
│ [SearchAgent] (内容搜索 - 并行)
│ ↓
│ [ResultMergeAgent] (结果整合)
│ ↓
└─→ 返回结果
3.2 LangGraph4j StateGraph 设计
StateGraph 是整个系统的核心编排器。我们将设计包含四个节点的图结构:
节点定义:
- intent: 意图识别节点,判断用户查询类型
- query_rewrite: 查询改写节点,生成查询变体
- search: 内容搜索节点,调用搜索引擎 API
- 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 之间的协作流程和数据流
- 用户请求 → AiSearchController 接收请求,创建初始 AgentState
- 意图识别 → IntentAgent 读取 originalQuery,调用 DeepSeek 判断意图,写入 intent
- 条件分支 → StateGraph 根据 intent 决定后续路径
- 如果是 QA → 直接调用 AnswerAgent
- 如果是 SEARCH → 进入查询改写流程
- 查询改写 → QueryRewriteAgent 读取 originalQuery,生成多个查询变体,写入 rewrittenQueries
- 内容搜索 → SearchAgent 读取 rewrittenQueries,并行调用搜索引擎 API,写入 searchResults
- 结果整合 → ResultMergeAgent 读取 searchResults,去重、排序、合并,生成 finalAnswer
- 返回结果 → 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 Boot | Spring 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:结果 URLsnippet:结果摘要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 是整个系统的核心编排器。构建步骤:
- 创建
GraphBuilder - 添加节点
- 设置起点
- 添加边(固定边和条件边)
- 设置终点
- 编译图
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结尾(IntentAgent、QueryRewriteAgent) - 状态类使用
State结尾(AgentState) - 节点函数命名清晰(
intentNode、searchNode)
10.2 配置管理最佳实践
- 敏感信息保护:使用环境变量存储 API Key
- 环境配置:使用 Spring Profile 区分开发、测试、生产环境
- 配置验证:使用
@ConfigurationProperties验证配置
10.3 性能优化建议
- 状态缓存:缓存常见查询的结果
- 节点并发优化:使用
parallelStream()并行执行 - API 调用优化:设置合理的超时时间和重试策略
10.4 LangGraph4j 工作流优化
- 节点拆分:复杂节点可以拆分为多个子节点
- 状态瘦身:状态对象只包含必要字段
- 条件跳转优化:尽早判断条件,减少不必要的节点执行
10.5 监控和日志记录
- 日志记录:每个节点记录执行时间和结果
- 指标监控:监控 API 调用延迟、成功率
- 错误追踪:使用 Spring Boot Actuator 和 Micrometer
10.6 扩展性建议
添加新 Agent:
- 实现 Agent 类
- 在 StateGraph 中添加节点
- 添加边连接节点
集成其他 AI 能力:
- 图片搜索:创建
ImageSearchAgent - 语音输入:使用 Whisper API
- 代码生成:集成 Codex 或 Copilot
结论
本文介绍了如何使用 Spring AI 和 LangGraph4j 构建一个完整的 AI 搜索 MultiAgent 系统。通过图结构模型,我们实现了灵活的工作流编排,支持条件分支、循环和并行执行。
核心收获:
- MultiAgent 架构通过职责分离,提升了系统的可扩展性和可维护性
- LangGraph4j 的图结构模型相比链式调用,提供了更强大的工作流编排能力
- Spring AI 简化了 LLM 调用,让开发者专注于业务逻辑
下一步行动:
- 下载完整代码示例,运行并验证功能
- 尝试扩展新 Agent 或集成其他 AI 能力
- 探索 LangGraph4j 在更复杂场景中的应用
MultiAgent 架构不仅适用于 AI 搜索,还可以应用于智能客服、自动化工作流、内容生成等多个场景。希望本文能够为你提供启发和参考。
参考资源
文章标签: #Java #SpringAI #LangGraph4j #MultiAgent #AI #架构设计 #实战教程