news 2026/9/1 9:54:24

Spring AI 2.x企业级Agent开发:多模型接入与工具调用实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI 2.x企业级Agent开发:多模型接入与工具调用实战

过去一年,很多 Java 团队开始尝试把大模型接进业务系统,但真正落地的项目并不多。原因不是“不会调 API”,而是卡在更现实的问题上:模型能聊天,却查不了航班、订不了票;对话一长就丢上下文;业务方今天要接这个模型、明天要换那个模型,代码改起来想砸键盘。如果你也在这个阶段,这篇文章值得看完。

本文要讲的是 Spring AI 2.x 下的企业级 AI Agent 开发思路,并从一个智能航空助手项目切入,完整拆解多模型接入、Tools 工具调用、MCP 协议集成、Skills 能力封装、多层记忆管理等全链路环节。读完你会得到三样东西:一张可落地的 Agent 技术地图、一套能跑通的项目骨架、一份避坑清单。先给一个明确判断:在 Java 生态里做 Agent,最值得投入的方向不是去重复造模型调用框架,而是把“让模型能调用真实系统”这件事工程化,Spring AI 正好提供了这条路。

整篇文章会按照“核心概念 -> 业务场景 -> 环境搭建 -> 关键实现 -> 验证排错 -> 工程建议”的顺序展开。如果你已经在 LangChain 或自研框架上踩过坑,看这篇文章会更有体感;如果你是第一次接触 Agent 开发,我会尽量把抽象概念落到代码和流程上。

1. 这篇文章真正要解决的问题

先说痛点。企业级 Agent 开发,表面看是“接入一个大模型”,实际难在三件事。

第一,模型和业务的连接。大模型只认识文字,不认识你数据库里的订单表、航班表、库存表。你要让它帮你查明天的航班,就必须给模型提供一种“触发外部系统”的机制。这个机制在 Spring AI 里叫 Tools,在行业标准里叫 Function Calling。Tools 写不好,Agent 就是个聊天机器人。

第二,多模型切换的成本。很多企业在实际项目里不会只用一个模型。推理用 A 模型,成本敏感的场景用 B 模型,甚至同一个功能需要 A/B 对比。如果上层的业务代码绑死了某个厂商的 SDK,每换一个模型都是一次大重构。Spring AI 的价值之一,是把不同模型的接入统一成一套抽象。

第三,Agent 状态的管理。一个真正的 Agent 不只是“一问一答”,它需要记住用户之前说过什么、知道用户的偏好、能够跨多轮对话完成一个复杂任务。这里就涉及多层记忆的设计,也是很多自研项目做到后期最容易失控的部分。

这篇文章要解决的核心问题,就是这三件事。它适合正在做 AI 应用落地的 Java 工程师、准备设计 Agent 架构的技术负责人,以及想把 Spring AI 应用在实际项目的同学。如果你期望的是“几天内写一个生产级 Agent”,那要把心态放平:本文给的是路线图和最小闭环,生产级还涉及监控、权限、灰度等工程细节,我会在最后聊。

2. 基础概念与核心原理

很多人看到 Spring AI、MCP、Agent、Tools、Skills 这些词就头大,总觉得是五座大山。其实拆开来看,它们解决的问题都很具体。

2.1 Spring AI 是什么

Spring AI 是 Spring 官方推出的 AI 应用开发框架,对标的是 Python 生态里 LangChain 那套东西,但它的底层架构和 Java/Spring 生态深度绑定。它的核心目标不是训练模型,而是让开发者用一套统一的 API 去对接不同大模型,然后把模型能力接入 Spring 的 Bean、配置、事务等基础设施。

从 1.x 到 2.x,Spring AI 在模型接入、ChatClient 调用、工具调用、可观测性等方面成熟了很多。最值得关注的一个变化是:官方把 Agent 能力的建设放到了更重要的位置,包括更稳定的工具调用链路、内存管理、以及与 MCP 协议的集成。本文中的代码以 Spring AI 2.x 为语境,具体版本以官方文档为准。

2.2 Agent 是什么

一个被用烂了的词。为了不过度抽象,我从工程角度给它下一个定义:Agent 是一个能够自主决策和调用工具的大模型应用,它会根据任务目标,循环执行“理解意图 -> 选择工具 -> 执行工具 -> 观察结果 -> 生成回复”的流程。

对比传统程序:传统程序是“用户点按钮,代码执行固定逻辑”;Agent 是“用户说一句话,模型决定调用哪个函数、怎么调、然后基于结果回答”。所以 Agent 的本质不是变得更聪明,而是把“决策权”从程序员转移给了模型。这也带来了不可控性,后面讲工程建议时会展开。

2.3 Tools 是什么

Tools,也叫工具函数、Function Calling。它的作用是给模型一把“钥匙”,让模型在对话过程中调用外部系统。

例如用户问“明天北京到上海有几趟航班”,模型本身不知道航班数据,但它知道有个工具叫searchFlights,于是它生成一个调用参数,框架帮你执行真正的航班查询方法,再把结果返回给模型,模型最终组织成自然语言回答。

在 Spring AI 里,最简单的方式是用@Tool注解标注一个 Java 方法,框架会自动把方法描述、参数结构注册给模型。

2.4 MCP 是什么

MCP 是 Model Context Protocol,模型上下文协议。可以把它理解成“模型的 USB-C 接口”。

在没有 MCP 之前,每个 Agent 接入一个数据源,都要写一套自定义集成。比如接入数据库写一套、接入文件系统写一套、接入第三方 API 又写一套。MCP 的出现,是为了统一这种连接方式:服务端把能力暴露成标准化工具,客户端通过 MCP 协议调用。

在 Spring AI 中,你可以把 MCP Server 暴露的工具注册为 Agent 可用的 Tools。这样做的好处是,一个 MCP Server 可以被多个 Agent 复用,也让 Agent 与外部工具的连接过程标准化了。

2.5 Skills 是什么

Skills 是比 Tools 更高一层的能力封装。一个 Skill 可以包含提示词模板、工具调用逻辑、输出格式约定,甚至是一套完整的处理流程。

举个例子:一个“航班改签 Skill”不只是调用“改签 API”,它还可能在改签前先检查用户身份、查询可改签航班、计算差价,再给出一段符合话术的回复。把这一整套封装成 Skill 后,Agent 能更稳定地执行这类任务,而不是每次从零推理。

2.6 多层记忆是什么

记忆决定 Agent 的“连续感”。如果没记忆,用户上一句说“我是金卡会员”,下一句问“那我有什么权益”,模型完全想不起来。

多层记忆通常包含三部分:会话记忆(保存当前对话轮次)、用户记忆(保存用户长期偏好)、应用记忆(保存业务系统里的历史数据)。有的架构还会引入向量数据库做长期记忆,通过语义检索找到与当前问题相关的历史信息。

下面用一个表格对比几个核心概念的差异,方便后面阅读。

概念解决什么问题和 Agent 的关系类比
Spring AIJava 生态统一接入大模型Agent 开发的底层框架类似 Web 开发里的 Spring Boot
Agent自主决策完成任务核心编排入口一个会思考的调用中枢
Tools / Function Calling让模型调用外部函数是 Agent 的“手”给模型装上的插件接口
MCP标准化外部工具接入协议是 Tools 的一种来源模型的 USB-C 接口
Skills将提示词+工具+流程封装成能力Agent 调用的“技能包”可复用的工作流模板
多层记忆让 Agent 记住上下文和长期状态Agent 的“文件系统”会话状态 + 用户画像

3. 智能航空项目场景与业务设计

在动手写代码之前,先明确我们的业务场景。

假设要构建一个航空出行助手,它要能处理下面的请求:

  • 查询航班:用户提供日期、出发地、目的地,查询可用航班。
  • 查天气:查询目的地天气,方便用户决定出行时间。
  • 预订机票:根据用户选择的航班生成订单。
  • 改签 / 退票:在符合规则的情况下完成变更。
  • 会员权益查询:查询用户会员等级和相关权益。

一个完整的 Agent 调用链路长这样:

用户提问“明天从北京去上海的航班有哪些,上海天气怎么样”——Agent 收到问题后拆解出两个意图:查航班、查天气。先调用航班查询工具,拿到航班列表;再调用天气查询工具,拿到上海天气信息;最后把两种结果整合成一段自然语言回复给用户。

这个例子看起来简单,但它是理解 Agent 全链路最好的入口。它同时用到了多模型接入、工具调用、上下文组织和外部服务集成。后面扩展到“预订机票”时,才需要引入用户记忆、多轮确认、订单状态管理等逻辑。

为了不让本文变成空谈,我建议项目结构按下图方式组织:

air-agent-demo ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── com/example/aiagent │ │ │ ├── AiAgentApplication.java │ │ │ ├── config │ │ │ ├── controller │ │ │ ├── agent │ │ │ ├── memory │ │ │ ├── skill │ │ │ └── tool │ │ └── resources │ │ └── application.yml

tool包放航班、天气等工具方法;skill包放可复用的技能模板;memory包放记忆管理;agent包放 Agent 编排逻辑。这个结构不是标准答案,但足够支撑后续扩展。

4. 环境准备与基础配置

进入实操阶段。先列一下本文使用的环境:

  • JDK 17 及以上。
  • Spring Boot 3.x。
  • Maven 3.6+。
  • Spring AI 2.x 版本(以当前官方稳定版为准)。
  • 一个兼容 OpenAI 协议的大模型 API Key,例如 DeepSeek 开放平台。

这里要说明一点:不同版本的 Spring AI 依赖坐标可能不同,本文重点是链路设计,依赖版本请以实际项目为准。

4.1 创建 Maven 工程

你可以通过 Spring Initializr 创建项目,然后手动加入 Spring AI 相关依赖。

<!-- pom.xml --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.x</version> <relativePath/> </parent> <properties> <java.version>17</java.version> <spring-ai.version>2.0.0</spring-ai.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring AI 核心 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>${spring-ai.version}</version> </dependency> <!-- 工具调用与 Agent 支持 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>${spring-ai.version}</version> </dependency> </dependencies>

提醒一下:不同版本的 Spring AI 可能会有 BOM 管理,更推荐在<dependencyManagement>里引入官方 BOM,避免版本冲突。上面这段依赖只是让概念落地,生产项目请参照官方文档调整。

4.2 配置 DeepSeek 模型

DeepSeek 提供了 OpenAI 兼容的 API,因此可以通过 Spring AI 的 OpenAI Starter 接入。核心配置如下。

# src/main/resources/application.yml spring: application: name: air-agent-demo ai: openai: base-url: https://api.deepseek.com api-key: ${DEEPSEEK_API_KEY} chat: options: model: deepseek-chat temperature: 0.3

这里的关键点有三个。

第一,base-url要指向兼容 OpenAI 协议的地址,DeepSeek 这类平台通常会给一个 OpenAI 兼容端点。

第二,api-key不要写死在配置文件里,推荐用环境变量${DEEPSEEK_API_KEY}代替,避免 Key 泄露。

第三,temperature在 Agent 场景不要设置太高。Agent 任务追求的是稳定执行工具,而不是天马行空的创意回答。航班查询、机票预订这类任务,temperature设置在 0.3 以下更可控。

4.3 理解 Spring AI 的 ChatClient

Spring AI 2.x 推荐使用ChatClient作为对话入口。它和RestClientWebClient的风格很像,你可以通过流式 API 构建请求。

@Configuration public class AiConfig { @Bean ChatClient chatClient(ChatClient.Builder builder) { return builder .defaultSystem("你是一个航空出行助手,负责查询航班、天气,并协助用户完成机票预订。") .build(); } }

这个 Bean 会被注入到后续的 Service 中。defaultSystem设置了系统提示词,让模型在整个对话中保持角色设定。

5. 多模型接入与统一调用

企业项目里,多模型是常态。可能的原因有很多:

  • 不同模型在不同任务上表现不同。
  • 成本控制:简单任务用小模型,复杂推理用大模型。
  • 容灾:某个模型服务不稳定,需要无损切换。

Spring AI 对这类需求的支持方式是定义统一的ChatModel抽象。当你引入 openai、anthropic、ollama 等 starter 时,Spring 容器里会生成对应的ChatModelBean。如果你引入了多家模型,可以在代码里通过@Qualifier选择要使用的模型。

先做一个最简单的多模型配置。

spring: ai: openai: base-url: https://api.deepseek.com api-key: ${DEEPSEEK_API_KEY} chat: options: model: deepseek-chat ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:7b

然后在代码里定义两个 Bean:

@Configuration public class ModelConfig { @Bean @Primary ChatClient deepSeekChatClient(ChatClient.Builder builder) { return builder .defaultSystem("你是一个严谨的航空助手") .build(); } @Bean("localChatClient") ChatClient localChatClient(ChatClient.Builder builder) { return builder .defaultSystem("你是本地部署的轻量级助手") .build(); } }

这里有两个ChatClientBean,一个走 DeepSeek,一个走本地 Ollama。业务代码中,默认场景注入主 Bean,需要本地模型时用@Qualifier("localChatClient")区分。

@Service public class FlightAgentService { private final ChatClient chatClient; private final ChatClient localChatClient; public FlightAgentService( @Qualifier("deepSeekChatClient") ChatClient chatClient, @Qualifier("localChatClient") ChatClient localChatClient) { this.chatClient = chatClient; this.localChatClient = localChatClient; } public String ask(String userMessage) { return chatClient.prompt() .user(userMessage) .call() .content(); } }

这段代码的意义在于:业务代码不再关心底层是 DeepSeek 还是 OpenAI,只依赖ChatClient这个统一抽象。以后接新模型,只需要新增配置和 Bean,业务层不用动。

这就是多模型接入的核心价值:不是炫技,而是把模型切换成本从“重构”降为“配置”。

6. Tools 与 MCP:让 Agent 真正触发业务动作

单纯的对话模型不能完成业务,所以要让模型具备工具调用能力。Spring AI 提供了两种常用方式:一种是@Tool注解方法,直接注册为模型可调用的工具;另一种是通过 MCP 接入外部标准化工具。

6.1 用 @Tool 实现航班查询

先定义一个航班查询方法,用@Tool注解描述它的功能。

package com.example.aiagent.tool; import org.springframework.ai.tool.annotation.Tool; import org.springframework.stereotype.Component; import java.time.LocalDate; import java.util.List; import java.util.Map; @Component public class FlightTools { @Tool(description = "查询指定日期从出发地到目的地的航班列表") public List<Map<String, String>> searchFlights(String from, String to, String date) { // 实际项目中这里会调用航班服务接口或数据库 if ("北京".equals(from) && "上海".equals(to)) { return List.of( Map.of("flightNo", "CA1519", "airline", "国航", "departTime", "08:00", "arriveTime", "10:15", "price", "1280"), Map.of("flightNo", "MU5102", "airline", "东航", "departTime", "09:30", "arriveTime", "11:45", "price", "980") ); } return List.of(); } }

@Tool注解里的description非常关键。模型并不知道这个 Java 方法背后有什么,它完全靠方法名、参数描述、注解描述来判断“什么时候调用这个工具”。描述越准确,Agent 的调用准确率越高。

6.2 让 Agent 使用 Tools

要使用上面的FlightTools,只需要在生成ChatClient时把它注册进去。

@Configuration public class AiConfig { @Bean ChatClient chatClient(ChatClient.Builder builder, FlightTools flightTools) { return builder .defaultSystem("你是一个航空出行助手,可以查询航班。") .defaultTools(flightTools) .build(); } }

这里有个容易踩坑的地方:项目里有多个@ToolBean 时,如果全部注册进ChatClient,会把模型的工具列表变得很庞大,影响推理效果和响应速度。更推荐的做法是分场景注入。例如“航班查询”场景只注册航班相关工具,“会员服务”场景只注册会员相关工具。

6.3 通过 MCP 接入天气查询

如果天气服务是一个独立的 MCP Server,那么 Spring AI 可以通过 MCP 客户端自动发现并注册它的工具,而不用手动编写@Tool方法。配置层面大致是这样的:

spring: ai: mcp: client: enabled: true type: sync connections: weather-server: url: http://localhost:8081/mcp

在代码里,MCP 暴露的工具会像普通 Tools 一样出现在ChatClient中。这对中大型团队非常有价值:航班系统、天气系统、订单系统各自维护 MCP Server,Agent 服务只需要订阅即可,不需要关心内部接口细节。

注意,MCP Server 本身是一个独立服务,Java 里可以用 Spring AI MCP Server 能力快速暴露一个工具端点。这里不展开全部代码,重点理解:MCP 是工具接入层的“标准化方案”,而@Tool是轻量化的“进程内方案”。

6.4 Tools 与 MCP 怎么选

很多初学者会纠结到底用 Tools 还是 MCP。我的判断是:

  • 如果工具只在本服务内使用,不存在跨团队、跨语言复用需求,用@Tool就够了。
  • 如果工具要被多个 Agent、多种技术栈共享,或者需要独立升级、独立部署,上 MCP 更合适。
  • 如果团队还在初期探索阶段,先用@Tool跑通闭环,后续再抽 MCP Server,完全来得及。
对比维度@Tool 直接注册MCP 接入
实现成本低,一个注解一个方法中,需要部署 Server 或客户端
复用性限于当前应用跨应用、跨语言复用
部署耦合进程内独立服务,可独立扩展
适合阶段原型、单体应用中大型团队、平台化阶段

7. Skills 与多层记忆:让 Agent 拥有可复用能力和长期状态

有了 Tools,Agent 能干活了;但离“企业级”还差两步:经验沉淀和状态记忆。

7.1 Skills 的本质

Skills 不是 Spring AI 强制规定的 API,它更像一种工程组织方式。一个 Skill 可以包含:

  • 固定的 System Prompt 片段。
  • 一组相关的 Tools。
  • 输出格式模板。
  • 异常处理逻辑。

举个例子,“机票改签 Skill”大概是这样的流程:先查询乘客订单,再判断是否满足改签条件,然后查询可选航班,计算差价,最后生成改签确认话术。如果你把这些逻辑拆开放在 Service 里,Agent 每次都要靠模型自己推理组合;如果封装成 Skill,Agent 只需要识别“用户要改签”,然后进入这个 Skill。

7.2 Skill 的 Java 实现思路

一个简单但实用的 Skill 可以这样设计:

package com.example.aiagent.skill; import org.springframework.ai.chat.client.ChatClient; import org.springframework.stereotype.Component; @Component public class FlightChangeSkill { private final ChatClient chatClient; public FlightChangeSkill(ChatClient chatClient) { this.chatClient = chatClient; } public String execute(String userMessage, String userId) { return chatClient.prompt() .system("你是机票改签助手。执行改签时,必须遵循以下步骤:" + "1. 先查询用户订单;" + "2. 判断是否满足免费改签条件;" + "3. 查询可改签航班;" + "4. 计算差价;" + "5. 输出改签确认信息。") .user(userMessage) .call() .content(); } }

这个例子展示的是“提示词级别的 Skill”。更复杂的 Skill 还可以把ChatClient的调用封装成对象方法,便于单元测试。总之,Skills 的核心价值是让 Agent 在重复任务上有稳定表现,不依赖模型每次的随机发挥。

7.3 多层记忆:会话、用户、长期

Agent 开发里,记忆是最容易失控的部分。先做分层:

第一层,会话记忆。保存当前会话的对话历史,这是保证多轮对话连贯的基础。Spring AI 提供了ChatMemory接口,可以基于内存、Redis 等实现。配置方式类似:

spring: ai: chat: memory: enabled: true window-size: 20

第二层,用户记忆。保存用户长期信息,比如“用户是金卡会员”“用户常飞北京-上海航线”。这些数据可以从业务系统同步到 Agent 上下文。在航空项目里,这就意味着每次对话前,Agent 会把用户偏好注入系统提示词。

第三层,长期记忆。适合用向量数据库存储历史交互记录。当新问题进来时,先做语义检索,找到用户过去问过的类似问题、处理过的历史订单,再交给模型回答。这个能力在 Spring AI 里通常与向量存储组件配合,本文先不展开。

下面给出一个简单的用户记忆注入示例:

@Service public class UserMemoryService { public String buildUserContext(String userId) { // 实际项目从数据库或缓存查询用户信息 return "用户ID: " + userId + ",会员等级: 金卡,常飞航线: 北京-上海,偏好靠窗座位。"; } }

然后在 Agent 调用前,把这段用户画像拼进系统提示词:

String userContext = userMemoryService.buildUserContext(userId); String answer = chatClient.prompt() .system("以下是用户画像信息,请结合这些信息为用户服务:" + userContext) .user(userMessage) .call() .content();

这里的要点是:记忆不是越大越好。把所有历史都塞进上下文,会让模型“注意力稀释”,响应变慢,成本变高,还容易出错。更务实的做法是:短期记忆保留关键对话轮次,长期记忆只选择与当前问题最相关的片段注入。

8. 跑通全链路:运行验证与效果演示

现在把前面的模块串起来,实现一个简单但完整的 Agent 请求入口。

@RestController @RequestMapping("/agent") public class AgentController { private final ChatClient chatClient; public AgentController(ChatClient chatClient) { this.chatClient = chatClient; } @PostMapping("/chat") public String chat(@RequestParam String userId, @RequestBody String userMessage) { return chatClient.prompt() .system("你是一个航空出行助手。如果用户询问航班,使用航班查询工具;如果询问天气,使用天气工具。回答要简洁准确。") .user(userMessage) .call() .content(); } }

启动项目后,可以发一个请求测试。

curl -X POST "http://localhost:8080/agent/chat?userId=1001" \ -H "Content-Type: text/plain" \ -d "明天北京到上海的航班有哪些?"

预期输出是一个航班列表,比如:

根据查询结果,明天北京到上海有以下航班: 1. CA1519,国航,08:00 起飞,10:15 到达,票价 1280 元。 2. MU5102,东航,09:30 起飞,11:45 到达,票价 980 元。

判断成功的关键不是输出是否“漂亮”,而是下面三点:

  • 模型是否识别出了正确意图。
  • 是否真正调用了searchFlights工具。
  • 返回内容是否基于真实工具结果,而不是模型编造。

如果你在日志里看到类似“Calling tool: searchFlights”的记录,说明工具调用链路已经打通。

如果请求返回“我不清楚明天的航班”,但日志里没有工具调用记录,优先排查@Tool是否注册成功、工具描述是否清晰。

9. 常见问题与排查思路

下面整理几类在 Spring AI Agent 开发中经常遇到的问题,按“现象 -> 原因 -> 排查 -> 方案”的格式给出。

问题现象可能原因排查方式解决方案
模型返回 content 为空,没有业务回复使用了兼容 OpenAI 协议的服务,但响应字段不标准,或模型把输出放到了其他字段打印完整响应体,查看实际返回的 JSON 结构;确认模型名称是否正确换用 OpenAI 兼容模型;如果空 content 与 DeepSeek 兼容接口有关,重点检查模型响应中的contentreasoning_content字段,必要时调整模型参数或版本
Agent 没有调用任何工具,直接回答工具未注册进 ChatClient;工具描述不清晰;系统提示词没有引导检查 ChatClient Bean 是否通过defaultTools注册;查看工具描述;测试时要求模型“使用工具回答”补充defaultTools;优化@Tool的 description;在系统提示词中加入工具使用规则
MCP 工具连接超时或不可用MCP Server 未启动;地址错误;网络策略限制用 curl 或浏览器访问 MCP Server 地址;查看服务日志确认 Server 启动成功;检查地址和端口;确认网络连通性
多模型切换后效果明显下降新模型的 Function Calling 能力较弱;参数差异;提示词不兼容单独测试新模型的工具调用;对比响应内容调整模型参数;为不同模型准备不同的提示词模板
上下文太长导致超限或费用飙升每轮对话把全部历史都传给模型打印实际发送的 prompt;观察 token 消耗使用窗口化记忆;摘要历史;只注入关键记忆
工具返回数据格式复杂,模型回答混乱工具返回值结构不友好查看模型看到的工具返回结果简化工具返回值;在工具中预先把数据整理成自然语言片段

其中“content 为空”这个问题在接入部分 OpenAI 兼容接口时比较容易出现,因为不同平台的响应结构存在差异。调试时不要只看content(),要打印完整的响应体,确认数据是真正为空,还是只是被框架过滤了。

10. 最佳实践与工程建议

到这里,项目已经能跑通了。但如果要从 Demo 走向生产,还有一些工程层的事情必须做好。

10.1 配置与密钥管理

大模型 API Key 是核心敏感信息,绝不能提交到 Git 仓库。推荐使用环境变量、配置中心或密钥管理平台。在 CI 流程中,还要加上密钥扫描。

10.2 工具安全边界

Tools 越强大,风险越大。一个能执行 SQL、操作文件系统、调用支付接口的 Agent,如果被恶意提示词利用,后果非常严重。建议做到:

  • 工具权限最小化。给 Agent 的工具只开放当前业务必需的能力。
  • 高危操作二次确认。例如“改签”和“退票”这类操作,在 Agent 执行前要弹出确认,或者走审批流。
  • 工具链访问控制。MCP Server 只暴露可信工具,不建议直接开放任意数据库或 shell 工具。

10.3 日志与可观测性

Agent 应用最怕“黑盒”。建议记录以下几类日志:

  • 请求入参:用户 ID、会话 ID、消息内容。
  • 模型调用:使用的模型、token 数、耗时、完整响应。
  • 工具调用:触发了哪个工具、入参、返回值、是否异常。
  • Agent 决策链路:每一步模型做了什么选择。

有了这些日志,线上问题才能快速定位。Spring AI 2.x 也提供了很多指标和可观测性扩展,生产项目建议接入。

10.4 测试策略

不要只看“最终回答好不好”。更要测试这些维度:

  • 工具调用触发准确率:意图明确时,是否总调用正确工具。
  • 参数解析正确率:用户说“北京到上海”,工具参数是否解析为from=北京, to=上海
  • 异常兜底:工具执行失败时,模型是否给出合理提示。
  • 多轮边界:用户中途换话题,是否还记得上下文。

可以把典型场景写成单元测试和集成测试,纳入 CI。

10.5 流程与版本管理

Agent 应用不是“训练一次就完事”。提示词改动、工具新增、模型切换,都会影响效果。建议把系统提示词、工具描述、Agent 流程设计纳入版本管理,并通过灰度验证后再全量发布。

11. 总结与后续学习方向

到这,我们实际走通了一条完整的链路:Spring AI 作为底层框架接入多模型,通过 Tools 和 MCP 让 Agent 调用真实业务系统,用 Skills 封装可复用能力,用多层记忆保持用户与对话状态。这个智能航空项目虽然以航班查询为最小案例,但它背后的问题模型——如何让大模型与 Java 业务系统安全、稳定、可控地协作,是所有 AI Agent 项目的共性。

接下来值得继续深入的方向有三个。

第一个是 RAG。把企业内部的航班政策、服务条款、退改签规则灌入向量数据库,让 Agent 在回答时先检索再生成,这能显著减少模型“幻觉”。

第二个是事件驱动与异步化。真实的企业 Agent 不会总是在 HTTP 请求里等模型算完,更常见的模式是任务队列、WebSocket 推流、定时触发等。把 Agent 的执行链路和业务事件总线结合,是工程化的重要一步。

第三个是多智能体协作。一个助手拆成“客服 Agent”“订单 Agent”“库存 Agent”,它们之间通过消息传递协作。Spring AI 的生态也在不断完善这类能力。

最后给你一个实际的建议:不要一开始就追求大而全。先用一个业务场景跑通“模型 + 工具 + 记忆”的最小闭环,再逐步叠加 MCP、Skills、RAG。这篇文章里的代码只是骨架,真正的价值在于你把它接到自己的业务数据源上。建议先收藏这篇文章,动手写一个自己的 Agent Demo,遇到问题再回来对照排错清单。这一步迈出去了,你会发现在 Java 里做 AI Agent,并没有想象中那么难。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 9:53:21

ViT 微调准确率掉到 72%?timm 三组参数拉回 90%

ViT 微调准确率掉到 72%&#xff1f;timm 三组参数拉回 90% 【免费下载链接】pytorch-image-models The largest collection of PyTorch image encoders / backbones. Including train, eval, inference, export scripts, and pretrained weights -- ResNet, ResNeXT, Efficien…

作者头像 李华
网站建设 2026/9/1 9:52:49

零基础三个月拿下SRC首杀,我的漏洞挖掘环境搭建实录

为什么从虚拟机开始&#xff0c;而不是直接买云服务器 三个月前我还是个连Linux命令都敲不利索的纯小白&#xff0c;现在已经在两个SRC平台拿到了首笔奖金。回头看&#xff0c;整个起点就是一台装好的Kali虚拟机。很多人建议新手直接租云服务器&#xff0c;但我劝你别急——本…

作者头像 李华
网站建设 2026/9/1 9:49:51

机器学习替代波形:加速引力波数据分析的工程实践

1. 先搞清楚“机器学习替代波形”到底解决了引力波数据分析的什么痛点 如果你正在处理引力波信号&#xff0c;无论是做参数估计、波形匹配还是数据注入&#xff0c;最头疼的环节之一可能就是计算波形模板。传统的数值相对论模拟&#xff0c;比如通过求解爱因斯坦场方程来生成一…

作者头像 李华
网站建设 2026/9/1 9:49:05

Excel数据筛选全攻略:从基础操作到FILTER函数与自动化

在日常数据处理工作中&#xff0c;我们经常需要从海量数据中快速定位出符合特定条件的记录。无论是筛选出某个部门的员工信息&#xff0c;还是找出销售额超过一定阈值的订单&#xff0c;亦或是提取特定格式的电话号码&#xff0c;手动查找不仅效率低下&#xff0c;而且极易出错…

作者头像 李华