一个典型的澄清模块设计:

前置守护

  1. Pod级信号量限流判断:它防止单个 Pod 同时处理过多请求而被压垮

  2. Redis SETNX 幂等守卫:

    因为 Redis 是共享的,所以即使两个相同请求落到不同 Pod,守卫也是生效的。

    • 首次请求:通过 SETNX 写入带 TTL的PROCESSING,写入成功后进入业务流程,并在业务流程中不断更新TTL。
    • 重复请求:只要状态为 PROCESSING 或 DONE,均判定为重复并拒绝。
    • 执行成功:将状态更新为 DONE,并设置去重窗口 TTL;TTL 到期前,相同 reqId 仍会被拒绝。
    • 执行失败或取消:删除 Redis 记录,释放幂等占位,允许相同请求再次重试。

上下文聚合

拉取工作记忆、短期记忆、情景记忆、程序性记忆。

主路记忆写入

首先,在任务执行流程中,先记录用户当前问题,答案留空。

这样即使后台处理较慢,用户问题也可以先被记录。后续通过 reqid 精确找到该记录并补全回答。

Agent Loop

闲聊/任务 二分类判定,只加载短期会话记忆,如果是任务记忆,则加载全量上下文,进入任务分支判定。

reply:直接回答

clarify:要求澄清

task:进入分支路由,任务管理(创建即时/定时、更新、删除、作为代理发给下游Excutor)分支。

流式返回

服务端需要把编排结果转换成标准SSE 帧,包括
Processing:中间结果,SSE 名称为 processing
Complete:最终结果或错误结果,名称为 complete

SSE 基于 HTTP 长连接,服务端写数据到 response body,TCP 层面保证数据包送达对端操作系统——但应用层(浏览器/客户端代码)是否成功读取、解析、渲染,后端不知道。

工程上的补救方案:

方案 做法 适用场景
TCP 层面兜底 连接断开 → 后端 write() 抛异常 → 知道客户端已离开 断连检测(最低限度)
客户端 ACK(应用层确认) 前端收到 Complete 后,单独发一个 HTTP POST 告知”已收到完整结果” 需要可靠交付的场景
Event ID + Last-Event-ID SSE 规范自带:服务端每条消息带 id:,客户端重连时带 Last-Event-ID 头,告诉服务端”上次收到哪了”,服务端从断点续推 断线重连、不丢消息
双向通道兜底 不用纯 SSE,改用 WebSocket,客户端收到后回一个 ACK 帧 需要双向确认的实时场景

旁路记忆回写

前请求的 SSE 流已经结束了,更新任务执行轨迹。

优先保证用户请求和 SSE 可用,记忆只做旁路增强;记忆失败最多导致后续上下文缺失,不让本次请求失败。