SpringAI 2.0实战:打造企业级智能航空Agent完整链路
2026/9/1 10:27:13 网站建设 项目流程

这次我们直接看一个比较重型的实战项目:SpringAI 2.0 企业级 AI Agent 智能航空项目。它不是简单跑一个 Hello World,而是把多模型接入、Tools 函数调用、MCP 协议集成、多层记忆、Skills 技能封装和 Agent 编排串成一条完整链路,目标场景是航空业务系统的智能化改造。

如果你正在做 Java 技术栈的 AI 应用,或者团队已经选型 SpringAI,但还没想清楚 Agent 怎么落地,这篇文章可以直接收藏。下面会从项目能力、架构设计、部署方式、功能验证、API 调用、性能观察和问题排查几个维度展开,尽量把整个项目拆到可以直接照着做。

1. 核心能力速览

在展开细节之前,先把项目的整体能力列出来。这里按企业级 AI Agent 项目的通用能力项整理,具体参数需要根据实际代码和配置确认。

能力项说明
项目类型Spring Boot 3.x + SpringAI 2.0 企业级 AI Agent 应用
核心功能多模型接入、Tools 工具调用、MCP 协议集成、多层记忆、Skills 技能封装、Agent 任务编排
业务场景智能航空项目,覆盖航班查询、旅客服务、机场信息、票务售后等场景
多模型支持可通过 SpringAI 统一接口接入 OpenAI、Ollama、DeepSeek、智谱、通义等模型
工具能力@Tool 注解定义函数,支持 Function Calling 自动选择工具并执行
MCP 支持基于 SpringAI MCP 模块接入 MCP Server,获取外部数据和能力
记忆能力支持 ChatMemory 等多层记忆策略,区分短期会话记忆与长期业务记忆
Skills 封装将提示词、工具策略和业务逻辑封装为可复用的技能模块
Agent 编排基于 ChatClient + Advisor 实现多步骤任务编排与工具调度
启动方式标准 Spring Boot 应用,Maven 打包后 java -jar 启动
接口 API提供 REST 接口,支持同步、流式、多轮会话和批量任务调用
资源需求如果使用云端模型 API,对本地资源要求低;如果接本地 Ollama,则需要配置显卡或大内存
适合人群Java 后端开发、架构师、AI 应用开发团队

从能力面看,这个项目覆盖的是 SpringAI 2.0 的核心功能面,不是单一模型的 Demo,而是把企业落地时需要用到的集成方案都纳入进来了。

2. 适用场景与使用边界

项目命名为“智能航空”,说明业务场景有明确指向,但技术链路本身可以复用到其他行业。

适合的场景包括:

  • 企业级 AI 助手:把内部业务系统以 Tools 方式开放给大模型,让模型能够查询航班、提交订单、获取旅客信息。
  • 多模型替换与灰度:通过 SpringAI 统一抽象,不修改业务代码即可切换底层大模型,适合多供应商策略。
  • MCP 生态集成:通过标准 MCP 协议接入数据服务、知识库、第三方工具,减少定制化开发。
  • 旅客服务自动化:多轮对话中维护上下文记忆,完成从“查航班”到“选座位”到“值机提醒”的长链路任务。
  • AI 能力中台建设:把 Skills、Tools、记忆策略沉淀为可复用模块,供多个业务线使用。

需要注意边界:

  • 涉及航班信息、旅客个人信息、票务订单等数据,必须经过授权和脱敏处理,不能在未授权环境下使用真实数据。
  • 大模型的工具调用不一定 100% 稳定,涉及支付、改签、退款等敏感操作必须有二次确认和人工兜底。
  • 如果使用本地模型,性能与显存占用取决于模型规模和推理配置,需要提前做压力测试。
  • MCP 服务端和客户端版本以及 SpringAI 版本之间存在兼容性问题,升级依赖时要谨慎验证。
  • 不要将生产环境下的大模型 API 密钥提交到公开仓库,也不要在日志中打印完整的上下文字段。

3. 智能航空项目架构与核心设计思路

这个项目的架构可以拆成五层来看。

3.1 应用入口层

基于 Spring Boot 3.x 构建,通过 REST Controller 暴露 HTTP 接口。业务上分为两个入口方向:

  • 面向 C 端旅客的“智能客服 / 出行助手”接口。
  • 面向内部运营人员的“数据查询 / 业务处理 / 任务分发”接口。

3.2 模型接入层

SpringAI 2.0 通过 ChatClient 和 ChatModel 统一了模型调用方式。无论底层是 OpenAI 还是 DeepSeek、Ollama、通义,业务代码里看到的都是同一个客户端 API。

核心代码结构如下:

@Autowired private ChatClient chatClient; public String chat(String userMessage) { return chatClient.prompt(userMessage) .call() .content(); }

在这个项目中,模型接入层还要处理一个关键问题:不同业务场景用不同模型。比如简单问答用轻量模型,复杂推理用强模型,票据信息抽取用本地私有化模型。这部分会做一个按场景路由的逻辑。

3.3 工具调用层(Tools)

Tools 是所有 Agent 能力的基础。SpringAI 2.0 支持通过注解声明一个方法为可调用工具,模型在回答时会判断是否需要调用这个工具,以及传入什么参数。

@Component public class FlightTools { @Tool("查询指定日期、航段之间的航班信息") public String queryFlights( @ToolParam(description = "出发城市") String departure, @ToolParam(description = "到达城市") String arrival, @ToolParam(description = "日期,格式 yyyy-MM-dd") String date) { // 调用真实的航班查询服务 return flightService.search(departure, arrival, date); } @Tool("查询航班实时状态") public String queryFlightStatus( @ToolParam(description = "航班号") String flightNo) { // 调用航班动态接口 return flightService.status(flightNo); } }

3.4 中层能力层

包含以下关键模块:

  • MCP 客户端模块:连接外部 MCP Server,获取天气、地理、机场延误信息等。
  • 记忆模块:会话记忆与长期记忆分段存储。
  • Skills 模块:把常用任务沉淀成技能模板。
  • Agent 编排模块:组合工具、模型和记忆完成多轮任务。

3.5 数据与外部系统层

项目对接航班数据库、旅客系统、订单系统、机场信息接口和其他 MCP 服务。这里的重点是所有外部资源都通过 Tools 或 MCP 暴露给大模型,不直接让模型访问数据库。

4. 多模型接入与路由配置

SpringAI 2.0 的多模型接入方式和早期版本不同。2.x 版本把 model 包拆分得更加清晰,每个模型有独立的 starter。

以 OpenAI 和本地 Ollama 为例,先在 pom.xml 中加入依赖:

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-ollama</artifactId> <version>2.0.0</version> </dependency>

然后在 application.yml 中配置模型服务地址和密钥:

spring: ai: openai: api-key: ${OPENAI_API_KEY} base-url: ${OPENAI_BASE_URL:https://api.openai.com} chat: options: model: ${OPENAI_MODEL:gpt-4o-mini} temperature: 0.7 ollama: base-url: http://127.0.0.1:11434 chat: options: model: qwen2.5:7b

这里的配置遵循一个原则:所有密钥和地址都从环境变量读取,不要硬编码。生产环境可以统一在配置中心管理。

在 Java 代码中,按场景调用不同模型:

@Service public class ModelRoutingService { private final ChatModel openAiChatModel; private final ChatModel ollamaChatModel; public ModelRoutingService( @Qualifier("openAiChatModel") ChatModel openAiChatModel, @Qualifier("ollamaChatModel") ChatModel ollamaChatModel) { this.openAiChatModel = openAiChatModel; this.ollamaChatModel = ollamaChatModel; } public String route(String scene, String prompt) { if ("complex_reasoning".equals(scene)) { return ChatClient.create(openAiChatModel) .prompt(prompt) .call() .content(); } // 默认走本地模型,节省成本 return ChatClient.create(ollamaChatModel) .prompt(prompt) .call() .content(); } }

更精细的做法是基于 ChatClient Builder 构建多个配置实例,把系统提示词、上下文窗口、模型参数都固化在对应的 ChatClient 里。这样业务层不需要关心模型类型,只关心 ChatClient 实例即可。

5. Tools 与 Function Calling 实战

Tools 是整个 Agent 项目中最容易踩坑,也是最重要的部分。SpringAI 2.0 中,把工具直接注册到 ChatClient 上即可,模型会自行决定是否调用。

5.1 定义航班查询工具

创建一个 Spring 组件,类中的方法用@Tool注解标记:

@Component public class FlightTools { @Tool("根据出发地、目的地和日期查询可用航班列表") public String searchFlights( @ToolParam(description = "出发城市") String from, @ToolParam(description = "到达城市") String to, @ToolParam(description = "出发日期") String date) { // 实际开发中这里调用航班服务接口 return """ [ {"flightNo":"CA1234", "from":"北京", "to":"上海", "time":"08:00-10:30", "price":980}, {"flightNo":"MU5678", "from":"北京", "to":"上海", "time":"12:30-14:50", "price":760} ] """; } @Tool("根据航班号和日期查询航班实时动态") public String getFlightStatus( @ToolParam(description = "航班号") String flightNo, @ToolParam(description = "日期") String date) { if ("CA1234".equals(flightNo)) { return "航班CA1234: 准点到达"; } return "航班" + flightNo + ": 延误,预计晚到30分钟"; } }

5.2 把工具绑定到 ChatClient

@Service public class FlightAgentService { private final ChatClient chatClient; public FlightAgentService(ChatClient.Builder builder, FlightTools flightTools) { this.chatClient = builder .defaultSystem("你是航空公司的智能助理,可以帮旅客查询航班、查询航班动态。") .defaultTools(flightTools) .build(); } public String ask(String question) { return chatClient.prompt(question).call().content(); } }

这里的核心机制是:SpringAI 会根据@Tool注解的方法生成 JSON Schema,然后在请求大模型时把工具描述传过去。模型返回一个“执行指令”,SpringAI 负责执行 Java 方法并再次把结果传回模型,最终生成回答。开发者只需要关心方法实现和返回值格式。

5.3 工具调用的异常处理

工具方法抛出异常时,SpringAI 会把这个错误信息传回模型,由模型生成一段“工具调用失败”的提示语。实际项目中最好在工具方法内部捕获业务异常,返回结构化错误信息。比如:

@Tool("查询航班价格") public String queryPrice(String flightNo) { try { return priceService.get(flightNo); } catch (Exception e) { return "查询航班价格失败:" + e.getMessage(); } }

这样模型可以基于错误信息继续与用户交互,而不是直接中断整个会话。

6. MCP 服务接入与协议集成

MCP 是这段开发链路里的重点,也是最近 Air 应用开发中讨论最多的一块。MCP 本质上是一个标准化的“接口描述 + 工具调用”协议,SpringAI 2.0 对它做了内置支持。

6.1 MCP 在项目里的作用

在航空业务场景中,MCP 适合接入这些外部能力:

  • 机场天气查询服务。
  • 机场延误公告。
  • 城市地面交通信息。
  • 酒店、租车等第三方服务。
  • 企业内部的航班数据 MCP Server。

引入 MCP 后,业务系统不再需要为每类外部数据开发一套定制接口,而是通过统一的 MCP Client 协议连接。数据提供方只要实现 MCP Server 标准,接入方就能直接使用。

6.2 SpringAI 接入 MCP Client

在 Spring Boot 配置文件中启用 MCP 客户端:

spring: ai: mcp: client: enabled: true name: flight-mcp-client type: SYNC

在代码中通过 MCP 工具访问外部服务:

@Service public class McpWeatherService { private final ToolCallbackProvider mcpToolProvider; public McpWeatherService(ToolCallbackProvider mcpToolProvider) { this.mcpToolProvider = mcpToolProvider; } public List<ToolCallback> getMcpTools() { return Arrays.asList(mcpToolProvider.getToolCallbacks()); } }

更完整的做法是把 MCP 工具注册到 ChatClient 中:

ChatClient chatClient = ChatClient.builder(chatModel) .defaultTools(mcpToolProvider.getToolCallbacks()) .build();

6.3 MCP 与 Tools 的区别

项目里同时存在@Tool和 MCP,两者的关系是:@Tool是进程内的、由本项目自己实现的函数能力;MCP 是跨进程的、通过标准协议从外部服务获取的工具能力。两者都表现为“给模型提供的工具”,但生命周期和管理方式不同。

实际开发中建议:

  • 业务核心能力用本地@Tool实现,保证速度和可控性。
  • 跨系统、跨团队的数据能力用 MCP 暴露,降低耦合。
  • 如果是独立部署的 MCP Server,避免每个业务实例重复建立连接,考虑连接池和超时控制。

7. 多层记忆与会话管理

企业级 Agent 和单轮问答最大的区别就是记忆。这个项目强调“多层记忆”,也就是不是只有当前聊天窗口的上下文,而是会区分不同层级的记忆并使用不同的存储方式。

7.1 ChatMemory 接口与常见实现

SpringAI 中记忆的底层接口是ChatMemory

public interface ChatMemory { List<Message> get(String conversationId); void add(String conversationId, List<Message> messages); void clear(String conversationId); }

常用实现有:

  • InMemoryChatMemory:基于内存存储,适合单机测试。
  • CassandraChatMemory:基于 Cassandra 存储。
  • 自定义JdbcChatMemory:存到关系型数据库,适合企业项目。

7.2 在 ChatClient 中启用记忆

记忆不是直接塞给 ChatModel,而是通过 Advisor 在请求前后处理消息。

@Service public class MemoryFlightAgent { private final ChatClient chatClient; private final ChatMemory chatMemory; public MemoryFlightAgent(ChatClient.Builder builder, ChatMemory chatMemory, FlightTools flightTools) { this.chatMemory = chatMemory; this.chatClient = builder .defaultSystem("你是航空智能客服,请基于上下文和工具调用结果回复用户。") .defaultTools(flightTools) .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) .build(); } public String chat(String userMessage, String conversationId) { return chatClient.prompt(userMessage) .advisors(a -> a.param("chat_memory_conversation_id", conversationId)) .call() .content(); } }

7.3 多层记忆的实现思路

在航空场景下,可以把记忆拆成三层:

  • 会话层:单次对话内上下文,通常 10~20 轮,用 ChatMemory 管理。
  • 用户偏好层:常驻旅客信息、常飞航线、偏好座位、饮食偏好。使用 Redis 或数据库存储,在构造系统提示词时注入。
  • 业务状态层:记录用户已经完成的步骤,比如已选航班、已提交订单、待支付状态。这部分要落在业务数据库,不能只放在模型上下文里。

代码示意:

public String buildContext(String userId) { String preference = userPreferenceService.get(userId); String flightOrder = orderService.getPendingOrder(userId); return """ 用户偏好:%s 待处理订单:%s """.formatted(preference, flightOrder); }

多层记忆的核心原则是:模型上下文只保存“对话推理需要的信息”,持久化信息及时落库,避免把整个业务库都塞进提示词。

8. Skills 技能封装与复用

Skills 在这个项目中指的是把某类任务的处理方式封装成可复用模块,可能包括提示词模板、输入参数校验、工具组合策略和回调处理。

8.1 Skills 与 Tools 的区别

很多开发者在最开始会混淆这两个概念。简单理解:

  • Tools 是能力:底层一个方法,模型可以调用它。
  • Skills 是策略:针对某类任务的完整处理方案,可能同时使用多个 Tools,并配有专门的系统提示词。

举例:给用户“办理值机”是一个 Skill,它会查看用户航班信息,调值机接口,返回登机牌。其中“查航班”是 Tool A,“调值机接口”是 Tool B,而“值机 Skill”决定了何时调用、参数怎么取、失败怎么响应。

8.2 Skills 的代码组织方式

在 Spring 项目中,我建议用配置类来定义 Skill:

@Component public class CheckInSkill { private final ChatClient chatClient; public CheckInSkill(ChatClient.Builder builder, FlightTools flightTools, PassengerTools passengerTools) { this.chatClient = builder .defaultSystem(""" 你是值机助手。你的任务: 1. 先查询用户的航班信息。 2. 确认旅客身份。 3. 查询是否支持在线值机。 4. 调用值机接口完成办理。 如果任何一步失败,请明确告诉用户失败原因,不要编造结果。 """) .defaultTools(flightTools, passengerTools) .build(); } public String checkIn(String userId, String flightNo) { return chatClient.prompt("用户ID: %s, 航班号: %s, 帮我办理值机".formatted(userId, flightNo)) .call() .content(); } }

8.3 Skills 的管理与发现

企业项目里 Skills 数量多了以后,需要做统一管理:

  • 按业务域分包:flight、ticket、passenger、airport。
  • 每个 Skill 提供元信息描述,便于上层 Agent 路由。
  • 关键 Skill 可以单独写单元测试,用固定输入验证输出。

Skills 这套思路并不复杂,难的是把它做得足够“业务化”。一个高可用的 Skill 必须经过反复的真实对话测试,把边界情况都覆盖到。

9. Agent 编排与多步骤任务测试

当多模型、Tools、MCP、记忆、Skills 都准备到位之后,下一步是把它们编排成一个 Agent。

9.1 一个典型的航空多步任务

旅客说:“帮我查一下明天从北京到深圳的航班,然后给我订最早那一班。”

这个请求在传统系统里需要写死逻辑,但 Agent 场景下模型会自动拆解:

  1. 调用searchFlights查询航班列表。
  2. 对比航班时间,选出最早一班。
  3. 调用createOrder创建订单。
  4. 如果用户之前保存过乘机人信息,则自动填充。
  5. 返回订单确认信息。

9.2 Agent 方法定义

@Service public class FlightAgent { private final ChatClient chatClient; public FlightAgent(ChatClient.Builder builder, FlightTools flightTools, OrderTools orderTools, ChatMemory chatMemory) { this.chatClient = builder .defaultSystem(""" 你是航空出行助手。请严格按以下顺序处理: 1. 查询航班信息必须使用工具。 2. 下单前必须与用户确认乘机人和航班。 3. 订单创建成功后输出订单号。 """) .defaultTools(flightTools, orderTools) .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) .build(); } public String execute(String prompt, String conversationId) { return chatClient.prompt(prompt) .advisors(a -> a.param("chat_memory_conversation_id", conversationId)) .call() .content(); } }

这段代码最核心的是defaultSystem中的顺序约束,它决定了 Agent 行为是否符合业务规范。

9.3 流式输出与长任务处理

对于耗时较长的查询和生成,建议使用流式接口,提升用户体验:

public Flux<String> stream(String prompt) { return chatClient.prompt(prompt).stream().content(); }

Controller 层返回Flux<String>,前端可以通过 SSE 方式消费。

如果任务链路复杂,涉及多次工具调用,建议在服务端做异步任务队列,不要让 HTTP 请求长时间占用线程。

10. 接口 API 调用示例

项目作为 Spring Boot 应用,天然提供 REST API。下面给出一套通用的接口设计。

10.1 开启接口服务

启动 Spring Boot 后,默认端口由server.port配置决定:

server: port: 8080

10.2 对话接口

@RestController @RequestMapping("/api/agent") public class AgentController { private final FlightAgent flightAgent; public AgentController(FlightAgent flightAgent) { this.flightAgent = flightAgent; } @PostMapping("/chat") public ResponseEntity<Map<String, String>> chat(@RequestBody ChatRequest request) { String reply = flightAgent.execute(request.message(), request.conversationId()); return ResponseEntity.ok(Map.of("reply", reply)); } @PostMapping("/chat/stream") public Flux<String> chatStream(@RequestBody ChatRequest request) { return flightAgent.stream(request.message()); } }

请求体定义:

public record ChatRequest(String message, String conversationId) {}

10.3 使用 curl 测试

curl -X POST http://127.0.0.1:8080/api/agent/chat \ -H "Content-Type: application/json" \ -d '{ "conversationId": "user-001", "message": "帮我查明天北京到上海的航班" }'

预期返回结果是一个 JSON,其中reply字段会包含模型生成的自然语言回答。

10.4 使用 Python 调用接口

import requests url = "http://127.0.0.1:8080/api/agent/chat" payload = { "conversationId": "user-001", "message": "帮我查明天北京到上海的航班" } response = requests.post(url, json=payload, timeout=60) print(response.json())

如果接入流式接口,可以使用requests的流式读取,或者直接使用httpx

import httpx with httpx.stream("POST", "http://127.0.0.1:8080/api/agent/chat/stream", json=payload) as r: for line in r.iter_text(): print(line, end="")

10.5 批量任务设计

批量任务是企业级场景的刚需,例如每天定时批量处理旅客的航班变动通知。推荐的做法是:

  • 维护一个任务表,存储任务的批次号、状态、输入参数。
  • 使用线程池或分布式任务框架异步执行。
  • 每条任务独立调用 Agent 接口。
  • 记录每次调用的 Token 消耗和执行耗时。
  • 失败任务自动重试,最多重试 3 次。
@Service public class BatchTaskService { private final ThreadPoolTaskExecutor executor; public void submitBatch(List<BatchTask> tasks) { for (BatchTask task : tasks) { executor.execute(() -> { try { String result = flightAgent.execute(task.getPrompt(), task.getConversationId()); task.markSuccess(result); } catch (Exception e) { task.markFailed(e.getMessage()); } }); } } }

11. 资源占用与性能观察方法

这个项目是纯 Java 服务,本身内存占用取决于 Spring Boot 应用和请求并发量。真正的资源压力来自两部分:大模型 API 的响应速度,以及本地模型的推理资源。

11.1 云端模型场景

如果使用 OpenAI、DeepSeek、通义等云端模型 API,本地服务不需要 GPU,主要关注:

  • JVM 堆内存:建议至少 512MB,具体看并发量。
  • 网络延迟:外部模型 API 延迟一般在几百毫秒到几秒。
  • Token 消耗:多轮对话和 Tools 描述会显著增加 Token 数,需要做成本监控。

11.2 本地 Ollama 场景

如果要把整个链路在本地跑起来,可以在开发机安装 Ollama,拉取一个小模型试验:

ollama pull qwen2.5:7b ollama serve

本地 7B 模型在 M 系列芯片或 8G 以上显存的显卡上可以运行,但速度和质量不如云端大模型。生产环境不推荐这种组合。

11.3 如何观测性能

建议在 Spring Boot 中集成以下观测手段:

  • 使用 Micrometer 记录每次请求耗时。
  • 记录模型调用的 Tokens 使用量。
  • 对工具调用方法埋点,统计执行时长。
  • 对接入的 MCP Server 做超时和熔断。

12. 常见问题与排查方法

结合 SpringAI 项目在本地开发和企业部署中常见的坑,整理如下:

问题现象可能原因排查方式解决方案
启动时提示 ChatClient 注入失败未配置模型 API Key,或 ChatClient.Builder 不存在检查 application.yml 中的 spring.ai 配置在环境变量中配置模型 API Key,确认依赖已引入
模型返回不调用工具工具方法没有被注册到 ChatClient检查 defaultTools 是否已加入工具类确认工具类是 Spring Bean,并在 ChatClient 构建时传入
调用工具报“无法解析方法参数”@ToolParam 描述不完整,模型生成参数不匹配查看模型返回的 function call 日志为每个参数补充完整 description 和类型
MCP 连接失败MCP Server 未启动,或客户端 url 配置错误检查 target url 是否可达先单独验证 MCP Server 是否在运行,再启动 Spring 应用
多轮对话中历史消息累积过多上下文超出模型窗口限制观察请求体的大小和模型报错使用 MessageWindowChatMemoryAdvisor 限制窗口大小,或做摘要压缩
工具执行后返回内容模型无法理解工具返回值格式不清晰查看工具返回的 JSON 字符串返回结构化 JSON,并加入必要的字段说明
流式接口首次响应过慢模型首 Token 延迟高打印请求和响应时间戳如果使用本地模型,考虑使用云端模型或提升硬件配置
API 返回 401 / 403API Key 无效或没有权限查看响应头和日志更换合法密钥,确认模型服务商账号内余额充足
批量任务大量失败并发数过高触发接口限流查看日志中的 HTTP 状态码在批量任务中引入重试和退避策略

排查这类问题最有效的方法,是把 SpringAI 的请求日志打开,查看模型返回的原始内容和 tool call 记录。只有看到真实链路,才能判断是模型理解问题、工具注册问题还是网络配置问题。

13. 最佳实践与使用建议

把这个项目跑通不难,但要用好、上生产,还需要遵循一些工程化建议。

13.1 保持工具返回结构化

工具返回的内容不要是野文本,尽量输出 JSON 格式。模型对结构化内容的解析能力远强于自由文本。比如查询航班的工具返回:

{ "flightNo": "CA1234", "from": "北京", "to": "上海", "departureTime": "08:00", "arrivalTime": "10:30", "price": 980, "status": "正常" }

13.2 系统提示词要写清边界

不要期望模型自己知道该做什么。每一步该调用什么工具、什么时候停止、什么时候要求用户确认,都要在系统提示词里规定清楚。

13.3 对敏感操作增加确认机制

改签、退票、支付这类操作,Agent 不能直接执行。建议流程:

  1. Agent 生成操作方案。
  2. 前端展示给用户确认。
  3. 用户确认后调用独立的业务接口。
  4. 接口内部校验权限和数据。

13.4 记忆不能盲目增长

任何长期运行的 Agent 都要面对上下文膨胀问题。建议:

  • 设置消息窗口上限,比如最近 10 轮。
  • 对长对话做摘要,保留关键用户意图。
  • 用户偏好写入业务库,不参与模型上下文。

13.5 模型与业务隔离

工具方法内部不能直接访问生产库,建议经过服务层和鉴权层。模型只接受工具返回的结果,不允许模型生成 SQL 后直接查询数据库。

14. 总结与下一步

这个 SpringAI 2.0 智能航空 Agent 项目最值得学习的地方,不是它解决了某一个算法问题,而是把企业级 Agent 需要的整套工程能力串起来了:多模型选型、工具注册、MCP 标准协议接入、多层记忆、Skills 封装以及最终的任务编排。纯 Java 技术栈的团队完全可以直接复用类似架构。

从验证顺序来看,建议先跑通最简单的“单模型 + 单 Tool”链路,确认 ChatClient 能正确调用工具;然后加入记忆,验证多轮对话的上下文是否稳定;接下来再考虑 MCP 接入和 Agent 编排。每一步都单独验证,不要一开始就把所有变量堆在一起,否则出了问题很难定位。

最容易踩的坑有三个:一是工具方法没有注册到 ChatClient,导致模型不调用工具;二是 MCP 服务连接失败但应用启动时不报错,直到实际调用才暴露;三是多轮对话后 Token 消耗暴涨,上下文超限。这三个问题在开发周期里迟早会遇到,可以先在本地准备对应的测试用例,免得生产环境再手忙脚乱。

后续可以扩展的方向也很多。比如把这个项目改造成航空部门内部的智能运营助手,接入更多业务工具;或者把 Skills 抽取成可配置的 JSON 策略,让产品人员可以调整提示词流程;再往前走一步,可以引入多 Agent 协作,让查询代理、订票代理、客服代理分工协作,形成真正完整的航空出行智能体。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询