Spring Boot + LangChain4j 流式 LLM Agent 服务架构设计

comsince
FshareIM Team本文介绍一套面向 AI 客服 / 问答助手场景的流式 LLM Agent 服务架构,技术栈为 Spring Boot 3 + WebFlux + LangChain4j + Redis + Kafka,采用 Chat Service + Governance Service 双服务分层设计,支持中等规模起步(日活十万级、峰值千级并发会话)并可平滑扩展至大规模。
日期:2026-06-12
场景:AI 客服 / 问答助手
规模:中等规模起步(日活十万级,峰值千级并发会话),可平滑扩展至大规模
技术栈:Spring Boot 3 + WebFlux + LangChain4j + Redis + Kafka
架构方案:Chat Service + Governance Service 双服务
1. 整体架构
1.1 设计目标
| 目标 | 指标 |
|---|---|
| 首 Token 延迟(TTFT) | P95 < 3000ms |
| 系统可用性 | > 99.9% |
| 峰值并发会话 | 1000 路(起步),扩展至 10000 路 |
| Governance 故障隔离 | 审计/计费故障不影响对话主链路 |
| 多租户扩展成本 | 改 Key 前缀 + 换实现类,不动主流程 |
1.2 架构全景
1.3 服务职责分工
Chat Service(延迟敏感,主链路)
- 接收用户请求,SSE 流式输出
- 调用 LangChain4j 流式推理
- Redis 读写会话历史
- Redis 检查配额(快速路径,无 RPC)
- Kafka 发布审计/取消/完成事件
- 首 Token 超时 + 总时长超时控制
Governance Service(异步治理,不在关键路径)
- 消费 Kafka 事件,落地审计日志
- 计算 Token 成本,更新配额账单
- 提供限流策略配置 Admin API
- 聚合 Prometheus 指标
- 预留多租户配额管理扩展点
关键设计决策:配额校验走 Redis 计数器(Chat Service 本地读),不走 Governance Service 同步 HTTP 调用。Governance 宕机不影响对话服务,配额扣减通过 Kafka 异步通知 Governance 结算。
2. 请求生命周期与数据流
2.1 正常完成链路(Happy Path)
2.2 异常与取消链路
| 场景 | 触发条件 | 处理动作 |
|---|---|---|
| 首 Token 超时 | 8s 无响应 | SSE error 事件,Kafka 发 status:timeout/phase:first_token,释放配额 |
| 用户中途取消 | SSE 连接断开 | doOnCancel() 触发,不写历史,Kafka 发 cancel 事件,释放配额 |
| 输出超长 | > 32000 chars | onPartialResponse 检测,sink.error(),SSE error 事件 |
| Provider 错误 | LLM 返回 5xx | 触发降级策略判断(详见第4节),Kafka 发 status:provider_error |
2.3 Kafka 事件流设计
| Topic | Partitions | Retention | 用途 |
|---|---|---|---|
| ai-audit-topic | 12 | 7d | 审计、成本结算 |
| ai-cancel-topic | 6 | 3d | 取消行为分析 |
| ai-cost-topic | 6 | 30d | 账单、配额核销 |
分区键:userId(同用户事件顺序消费,便于会话级成本聚合)
3. Chat Service 内部模块设计
3.1 包结构
3.2 核心流程:LangChain4j → Reactor Flux 桥接
3.3 关键接口定义(多租户扩展点)
QuotaService
ModelRouteService
SessionService
3.4 关键约束
onPartialResponse回调线程严禁阻塞 I/O(Redis/DB/Kafka 同步调用),否则拖慢 token 输出速率- Redis 写历史和 Kafka 发事件均使用
Mono.subscribe()(fire-and-forget),不 block 主流 doFinally保证quotaService.release()一定执行,即使 onError 或 cancel- StringBuilder 输出缓冲设 32000 chars 上限,防止超长生成撑爆堆内存
4. Governance Service + 降级策略
4.1 Governance Service 包结构
4.2 限流引擎(Chat Service 侧 Redis 执行)
三个维度独立控制:
| 维度 | Redis Key | 操作 | 默认阈值 |
|---|---|---|---|
| 用户 RPM | ai:quota:rpm:{userId} | INCR + EXPIRE 60s | 10次/分钟 |
| 用户并发会话 | ai:quota:concurrent:{userId} | INCR 进 / DECR 出 | 3路并发 |
| 模型全局并发 | ai:quota:model:{model}:concurrent | INCR 进 / DECR 出 | 主模型50,降级模型200 |
执行顺序(QuotaFilter 中):
- 检查 RPM → 超限返回 429
- 检查用户并发 → 超限返回 429
- 检查模型并发 → 超限触发降级模型选择(不直接拒绝)
- 三者均通过 → 放行
多租户扩展:Key 增加 {tenantId} 前缀,策略从 Governance Admin API 动态加载,Redis 缓存 30s。
4.3 四级降级策略
熔断器(Resilience4j CircuitBreaker):
- 每个 LLM Provider 一个实例
- 失败率阈值:50%(10次请求窗口内)
- HALF_OPEN 探测:30s 后单次探测
- 状态变更发 Kafka 事件 → Governance 记录
4.4 Kafka 消费设计
5. 状态管理与可观测性
5.1 Redis 数据模型
Key 命名规范:ai:{业务域}:{维度}:{id}
| Key | Type | TTL | 用途 |
|---|---|---|---|
ai:session:history:{sessionId} | String(JSON) | 12h(每次写刷新) | 会话历史 |
ai:quota:rpm:{userId} | String(INCR) | 60s | 用户 RPM 限流 |
ai:quota:concurrent:{userId} | String(INCR) | 无 | 用户并发槽 |
ai:quota:model:{model}:concurrent | String(INCR) | 无 | 模型全局并发槽 |
ai:circuit:{model}:state | String | 5min | 熔断器状态外部化 |
部署路径:单节点(开发)→ Redis Sentinel 1主2从(中等规模)→ Redis Cluster 3主3从(大规模)
会话历史(DB0)与限流计数器(DB1)分 DB,隔离故障影响。
5.2 核心监控指标
| 指标 | 说明 | 告警阈值 |
|---|---|---|
ai_chat_ttft_ms | 首 Token 延迟 | P95 > 3000ms 🔴 |
ai_chat_duration_ms | 总会话时长 | P95 > 30000ms 🟡 |
ai_chat_error_total | 错误次数(标签:error_type) | 错误率 > 5% 🔴 |
ai_chat_cancel_total | 用户取消次数 | - |
ai_chat_timeout_total | 超时次数(标签:phase) | 超时率 > 3% 🟡 |
ai_chat_inflight_sessions | 当前活跃会话数 | > 800 🟡 预警 |
ai_chat_quota_exceeded_total | 限流触发次数 | 突增 🟡 |
ai_cost_tokens_input_total | 输入 Token 累计 | 成本监控 |
ai_cost_tokens_output_total | 输出 Token 累计 | 成本监控 |
kafka_consumer_lag | Governance 消费延迟 | > 10000 🔴 |
5.3 分布式追踪
TraceId 全链路透传路径:
Span 层级(Micrometer Tracing + Zipkin/Skywalking):
5.4 容量规划
| 组件 | 中等规模(起步) | 大规模(扩展目标) | 扩容方式 |
|---|---|---|---|
| Chat Service | 2 实例 × 4C8G | 8~16 实例 × 4C8G | HPA(inflight_sessions) |
| Governance Service | 1 实例 × 2C4G | 3 实例 × 2C4G | Kafka Consumer 扩分区 |
| Redis | Sentinel 1主2从 × 4C8G | Cluster 3主3从 × 8C16G | 扩 Cluster 节点 |
| Kafka | 3 Broker × 4C8G | 5 Broker × 8C16G | 扩 Broker + 分区数 |
| MySQL | 1主1从 × 4C16G | 1主2从 × 8C32G | 读写分离 |
HPA 触发指标:inflight_sessions P50 > 400 → 扩容;TTFT P95 > 3s 持续 2min → 扩容(不依赖 CPU)
5.5 Nginx 网关关键配置
6. 多租户扩展点清单
当前设计为单租户,以下 5 处改动即可接入多租户,不动主流程:
| 扩展点 | 当前 | 多租户改动 |
|---|---|---|
| QuotaService Redis Key | ai:quota:rpm:{userId} | 增加 {tenantId} 前缀 |
| GovernanceProperties | 全局配置 | 改为按 tenantId 存 Redis,动态加载 |
| ModelRouteService | 默认主模型 | 增加 TenantModelPolicy,租户级模型绑定 |
| AuditLogService | 单表 | 增加 tenantId 分表路由 |
| AdminController | 全局 API | 增加 /tenants/{id}/quota API |
7. 关键配置参考
8. 前端消费约定
SSE 事件结构
前端处理约定
token事件 → 增量渲染completed事件 → 确认结束,关闭 loading 状态error事件 → 展示提示,允许重试warning事件 → 展示服务质量降级提示,不中断输出- 页面切换/用户主动停止 → 必须 调用
reader.cancel()取消请求,避免无效计费
9. 未覆盖范围(后续迭代)
| 项目 | 说明 |
|---|---|
| Tool Calling | 工具调用隔离服务,调用次数限制、权限控制 |
| RAG 集成 | 接入现有 RAG 企业架构 |
| 长会话摘要 | SummarizingSessionService,超长上下文自动压缩 |
| 流量录制回放 | 用于压测和线上问题复现 |
| A/B 测试路由 | ModelRouteService 扩展,按用户分桶选模型 |
| 多租户完整实现 | 基于第6节扩展点展开 |