Spring AI 实战:构建具备聊天记忆、可扩展、高并发的智能行程规划 Agent1. 引言在“AI + 业务系统”真正落地的过程中,很多团队会发现一个典型问题:只接一个大模型接口,很容易做出 Demo;但要做成一个能承载真实流量、具备上下文记忆、可观测、可扩展、可治理的 Agent 系统,难度会陡增。以“智能行程规划”为例,用户不会只问一句“帮我规划去北京的旅行”。真实场景中的对话往往是连续、多轮、动态变化的:“我五一想去杭州玩三天,预算 3000。”“不要太早起,酒店离西湖近一点。”“第二天下雨的话,把户外项目换成室内。”“另外我不吃辣,同行还有一位老人。”这类需求天然依赖上下文、用户偏好、实时外部数据和多步骤决策,因此非常适合 Agent 化建模。但如果没有工程化设计,系统很快会暴露出几个问题:对话上下文无限增长,Prompt 成本失控;多实例部署后,记忆状态不一致;外部地图、天气、景点服务抖动导致整体雪崩;高并发下 Redis、LLM、下游接口成为瓶颈;缺少可观测性,线上问题无法定位。本文不再停留在“能跑起来”的示例层面,而是从架构、原理、工程实现和生产优化四个维度,完整讲解如何基于 Spring AI 构建一个可用于真实业务的智能行程规划 Agent。文章目标如下:深入解释 Spring AI 中聊天记忆、Prompt 组装、Agent 编排的核心原理;给出适用于高并发场景的系统架构和工程治理方案;提供接近生产可用的代码骨架,而不是仅供演示的伪代码;用真实业务案例说明如何把“对话式 AI”落地为“可交付的业务能力”。2. 业务目标与真实挑战2.1 业务目标一个真正有价值的“智能行程规划 Agent”,至少要满足以下能力:理解多轮上下文,而不是只看当前一句话;识别长期偏好,例如预算、出行方式、饮食禁忌、酒店档次;结合实时外部信息,例如天气、路况、景区开放时间;输出结构化规划结果,便于前端渲染、改写和二次操作;在高峰时段保持可用,不能因为某个外部服务超时就整体失效。2.2 典型业务难点1. 上下文不是“越多越好”很多初学者会把所有对话历史都拼到 Prompt 中。这样做短期有效,长期一定出问题:Token 成本持续上升;响应延迟变长;历史噪声干扰当前意图;模型更容易“遗忘重点”。因此,记忆系统必须分层,而不是简单堆历史消息。2. 用户输入并不总是完整例如“帮我安排上海两天自由行”,系统其实缺少关键信息:出发地;人数;日期;预算;是否亲子;是否自驾;是否已有酒店。Agent 需要先补齐缺失参数,再规划,而不是一次性“脑补”所有内容。3. 行程规划本质上是“推理 + 工具调用 + 约束求解”生成一份可执行的行程,不只是自然语言输出,更像一个小型决策系统:需要查天气;需要查 POI;需要估算路程与时长;需要判断营业时间;需要做预算约束;需要在“用户偏好”与“实际可达性”之间平衡。4. 生产环境必须面对不稳定外部依赖经常抖动:天气接口偶发超时;地图服务限流;景点数据不全;LLM 响应慢或配额不足。如果没有超时、熔断、缓存、降级和异步化,系统会非常脆弱。3. 核心原理:Spring AI 中的记忆、上下文与 Agent3.1 Chat Memory 的本质从原理上看,聊天记忆并不是“大模型真的记住了你”,而是应用层在每次请求前,将与当前任务相关的历史上下文重新组织后送入模型。也就是说,所谓“记忆”本质上分为两部分:存储层:把历史消息、摘要、偏好、事实存下来;编排层:在当前请求到来时,决定把哪些内容送入 Prompt。Spring AI 在这件事上提供了两个关键能力:ChatClient:负责构建 Prompt、调用模型、处理返回结果;ChatMemory或记忆仓储能力:负责保存和读取消息历史。但在真实项目中,我们通常不会只保留“逐条消息”,而会做三层记忆。3.2 记忆分层模型1. 会话工作记忆保存最近 N 轮消息,用于维持当前对话连续性。适合存储:最近几轮用户追问;当前任务上下文;刚刚确定的限制条件。特点:时效性强;价值高;不能无限增长。2. 用户长期画像记忆保存跨会话稳定存在的偏好和事实。例如:偏好高铁而非飞机;酒店预算 500-800 元;同行有老人;忌口辛辣;偏好慢节奏、不赶行程。特点:更新频率低;业务价值高;适合结构化存储。3. 摘要记忆当会话过长时,系统不再保存全部明细,而是周期性做摘要压缩。例如把 20 轮对话压缩成:用户计划五一期间去杭州三日游,预算 3000 元,两人同行,其中一位老人,不接受高强度路线,偏好西湖和人文景点,希望酒店靠近西湖,第二天如遇下雨优先安排室内活动。特点:大幅降低 Token 消耗;保留高价值事实;适合长会话。因此,生产系统中的“聊天记忆”通常不是一个 List,而是如下组合:工作记忆(近 N 轮) + 摘要记忆(压缩上下文) + 用户画像(长期偏好)3.3 Agent 的执行本质行程规划 Agent 不是单次“问答”,而是一条有状态的执行链路:接收用户输入;识别意图;读取会话记忆和用户画像;判断信息是否充分;必要时追问补齐参数;调用天气、地图、POI、预算等工具;生成候选规划;输出自然语言答复和结构化结果;回写消息、摘要和画像。这意味着系统设计不能只围绕 Controller,而要围绕“Agent 编排链路”展开。4. 适合生产环境的总体架构4.1 架构设计目标我们希望系统具备以下特性:应用实例无状态,支持水平扩容;记忆存储外置,支持多实例共享;工具调用可隔离、可降级、可缓存;同步链路只做“用户必须等待”的事情;重任务异步化,避免请求线程被长时间占用;全链路可观测,便于分析延迟与失败原因。4.2 推荐架构4.3 架构分层说明接入层负责统一鉴权、限流、日志透传、灰度发布和 API 聚合。Agent 编排层系统核心,负责:Prompt 组装;记忆装载;工具调用;结果整形;降级兜底;事件投递。记忆层分离“短期会话记忆”和“长期画像记忆”:Redis:会话消息、摘要、临时状态;MySQL / Redis Hash:用户偏好、稳定画像;对象存储或 ES:审计日志、调试记录、长文本归档。工具层通过统一的 Tool Adapter 接口封装地图、天气、景点等能力,避免业务层散落大量外部调用逻辑。异步任务层适合处理:大批量备选路线计算;行程重排;复杂预算估算;规划结果落库;用户通知推送。观测层必须监控:LLM 平均耗时、P95、P99;Prompt Token / Completion Token;Redis 命中率;外部工具成功率;熔断触发次数;降级响应占比。5. 领域建模:不要把 Agent 只当成聊天机器人5.1 领域对象设计如果系统只返回一句自然语言,前端很难渲染、保存、编辑和重算。因此建议同时输出结构化对象。核心领域对象至少包括:TravelRequest TravelConstraint UserProfile DayPlan ActivityPlan RoutePlan BudgetPlan TravelPlanResult示例:public record TravelRequest( String sessionId, String userId, String userMessage, LocalDate startDate, Integer days, String destination, Integer travelers, BigDecimal budget, TravelConstraint constraint ) {} public record TravelConstraint( boolean withElderly, boolean withChildren, boolean avoidSpicyFood, boolean preferSlowPace, boolean preferPublicTransport, String hotelArea, ListString mustVisitPoi ) {}结构化建模的好处很明显:便于参数补齐;便于规则校验;便于结果落库;便于前端二次编辑;便于在异步任务中复用。5.2 对话驱动与结构化驱动结合推荐采用“双轨输出”:面向用户:输出自然语言解释;面向系统:输出 JSON 结构化行程。这样既保证交互体验,又方便业务系统继续处理。6. 技术选型建议下面给出一套适合大多数中大型项目的技术栈建议。组件推荐方案说明应用框架Spring Boot 3.x与 Spring AI 生态兼容AI 编排Spring AI统一 ChatClient、Tool、Advisor 机制模型接入OpenAI 兼容接口 / 企业模型网关屏蔽底层模型差异