1. 项目概述:构建生产级智能行程规划Agent的挑战与机遇
在当今AI技术快速落地的浪潮中,行程规划作为典型的复杂决策场景,正从传统的规则引擎向基于大模型的智能Agent演进。我最近主导的一个旅游平台智能化升级项目,就深刻体会到从Demo到生产环境的巨大鸿沟。初期我们仅用3天就接入了大模型API实现基础对话功能,但随后花了整整6周时间才让系统真正达到线上服务标准。
这个过程中最关键的认知转变是:真正的业务级Agent不是简单的"问-答"系统,而是一个融合了上下文管理、工具调用、约束求解和异步处理的分布式状态机。以用户询问"帮我安排上海三天两夜游"为例,背后涉及12个关键参数的提取、5个外部服务的协同调用、以及持续多轮的偏好协商。如果只是将对话历史无脑拼接到Prompt中,不仅成本会呈指数级增长,系统响应速度也会从最初的2秒恶化到15秒以上。
2. 核心架构设计
2.1 分层记忆系统实现
2.1.1 会话工作记忆管理
在我们的生产实践中,采用Redis的Stream数据结构存储最近5轮对话,配合TTL设置实现自动过期。关键实现代码如下:
public class RedisChatMemoryStore implements ChatMemoryStore { private final RedisTemplate<String, Object> redisTemplate; public void addMessage(String sessionId, ChatMessage message) { redisTemplate.opsForStream().add( "chat:session:" + sessionId, Collections.singletonMap("content", serialize(message)) ); // 保持最近5条消息 redisTemplate.opsForStream().trim("chat:session:" + sessionId, 5, false); } }重要提示:Stream相比简单的List结构更适合高并发场景,其内部的分片机制可以有效避免热点Key问题。我们在压测中发现,当QPS超过500时,List结构的延迟会明显上升。
2.1.2 用户画像记忆建模
长期偏好存储采用Redis Hash结构,设计时特别注意了字段的版本控制:
public class UserProfile { private String userId; private Map<String, PreferenceCategory> preferences; private String version = "v2"; // 结构变更时升级 @Data public static class PreferenceCategory { private String source; // "explicit"|"inferred" private LocalDateTime updateTime; private Object value; } }这种设计允许系统:
- 区分用户明确声明的偏好(如"不吃辣")和系统推断的偏好(如"常选择4星级酒店")
- 支持灰度发布时的数据结构迁移
- 通过version字段实现自动兼容处理
2.2 工具调用层的工程实践
2.2.1 统一工具接口设计
我们抽象出ToolExecutor接口,所有外部服务调用都通过该接口进行:
public interface ToolExecutor { ToolResult execute(ToolRequest request); String toolName(); default boolean isAvailable() { return true; } }典型实现如天气查询工具:
@Slf4j public class WeatherToolExecutor implements ToolExecutor { private final WeatherApiClient client; private final CircuitBreaker circuitBreaker; public ToolResult execute(ToolRequest request) { WeatherRequest weatherRequest = parseRequest(request); return circuitBreaker.run(() -> { WeatherData data = client.query(weatherRequest); return buildSuccessResult(data); }, fallback -> buildFallbackResult(weatherRequest)); } }2.2.2 熔断与降级策略
每个工具都配置独立的熔断器(使用Resilience4j实现),关键参数如下表所示:
| 参数 | 天气服务 | POI查询 | 路线规划 |
|---|---|---|---|
| 失败阈值 | 50% (10s窗口) | 40% (30s窗口) | 30% (1m窗口) |
| 等待持续时间 | 30秒 | 1分钟 | 2分钟 |
| 慢调用阈值 | 800ms | 1.5s | 3s |
| 降级策略 | 返回缓存 | 返回精简结果 | 切换算法 |
3. 生产环境优化技巧
3.1 Prompt工程实践
3.1.1 动态模板组装
我们发现直接拼接历史消息会导致模型注意力分散,改为使用结构化模板:
你是一个专业的行程规划助手,请根据以下信息为用户制定方案: # 用户基本信息 {{userProfileSummary}} # 当前会话目标 {{currentGoal}} # 最近3轮对话摘要 {{recentSummary}} # 已知约束条件 {{constraints}} 请按以下步骤思考: 1. 检查信息是否完整,缺失关键参数则提问 2. 调用相关工具获取最新数据 3. 生成包含时间、地点、预算的详细方案 4. 输出Markdown格式结果和结构化JSON通过A/B测试,这种模板使平均对话轮次减少2.3轮,Token消耗降低42%。
3.2 性能优化方案
3.2.1 异步处理流水线
对于耗时操作,我们设计了三阶段处理流程:
graph TD A[同步阶段] -->|即时响应| B[返回初步确认] A -->|异步任务| C[详细规划] C --> D[缓存中间结果] D --> E[Webhook通知] E --> F[客户端刷新]具体实现采用Spring的@Async注解配合Redis Pub/Sub:
@Async("planningExecutor") public void asyncGeneratePlan(PlanRequest request) { try { PlanContext context = buildContext(request); publishProgress(request.getSessionId(), "start"); DayPlan[] plans = new DayPlan[request.getDays()]; for (int i = 0; i < request.getDays(); i++) { plans[i] = generateDayPlan(context, i); publishProgress(request.getSessionId(), "day-" + i); } redisTemplate.opsForValue().set( "plan:result:" + request.getSessionId(), serialize(plans), Duration.ofHours(1) ); publishCompletion(request.getSessionId()); } catch (Exception e) { publishError(request.getSessionId(), e); } }3.2.2 缓存策略
我们采用三级缓存架构:
- 本地缓存(Caffeine):存储高频访问的用户画像,TTL=5分钟
- 分布式缓存(Redis):存储会话状态和临时结果,TTL=1小时
- 持久化存储(MySQL):最终方案存档,长期保存
关键配置示例:
spring: cache: multi: local: spec: maximumSize=1000,expireAfterWrite=5m redis: timeToLive: 1h keyPrefix: "plan:cache:"4. 监控与治理
4.1 可观测性设计
我们搭建的监控看板包含以下核心指标:
| 指标类别 | 具体指标 | 报警阈值 |
|---|---|---|
| 性能 | LLM P99响应时间 | >3s |
| 成本 | 每会话平均Token | >2000 |
| 质量 | 用户修正率 | >30% |
| 稳定性 | 工具调用错误率 | >15% |
Prometheus配置示例:
- name: llm_metrics metrics_path: /actuator/prometheus static_configs: - targets: ['ai-service:8080'] relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: prometheus:90904.2 典型问题排查案例
案例1:记忆污染问题
现象:用户反馈系统突然"忘记"了之前确认的预算限制
排查过程:
- 检查Redis内存使用率,发现达到95%
- 分析Key分布,发现大量未设置TTL的临时Key
- 追溯代码,发现异步任务未正确清理中间状态
解决方案:
- 为所有临时Key添加自动过期
- 增加Redis内存监控
- 实现状态清理钩子
案例2:工具调用雪崩
现象:雨天大量用户查询导致地图服务不可用
根因分析:
- 天气工具超时设置过长(5s)
- 未实施请求排队
- 降级策略不完善
优化措施:
- 引入Bulkhead模式限制并发
- 添加二级缓存(昨天数据+预测数据)
- 实现智能降级算法
5. 演进方向
在实际运营中,我们持续收集到以下改进需求:
- 多模态输出:支持生成包含地图截图、景点图片的富媒体方案
- 协作规划:允许多人实时编辑同一行程
- 动态调整:根据实时交通、天气自动优化已生成方案
- 个性化推荐:基于用户历史行为推荐小众景点
技术预研发现,要实现这些能力需要:
- 升级到支持GPT-4级别的多模态模型
- 引入Operational Transformation算法处理并发编辑
- 搭建事件驱动的实时处理流水线
- 完善用户行为埋点与分析体系
一个典型的扩展架构如下:
graph LR A[客户端] --> B[API Gateway] B --> C[实时协作服务] B --> D[AI编排层] D --> E[记忆系统] D --> F[工具集市] C --> G[CRDT存储] F --> H[地图服务] F --> I[天气服务] F --> J[POI数据库]在实现这些高级特性时,需要特别注意:
- 实时性与一致性的权衡
- 多模态数据的存储成本
- 复杂交互的调试工具链
- 隐私与合规要求
经过半年多的迭代,我们的系统目前每天处理超过15万次规划请求,平均响应时间控制在1.2秒以内,用户满意度达到92%。这证明基于Spring AI构建生产级Agent是完全可行的,关键在于从一开始就采用正确的架构模式和工程实践。