XpertChatCommand 由 Bull handoff worker 执行,worker 再通过 Redis Pub/Sub 把流式结果发布回来。
该架构覆盖:
POST /api/xpert/:id/chatPOST /api/xpert/:name/chat-app
目标
- 支持多个 API 实例和 worker 实例,不依赖粘性会话。
- 保持 HTTP API 和正常 SSE 流式事件格式不变。
- 避免 Xpert Chat SSE 请求因为进程内状态导致
Local task not found和Pending result timeout。 - Redis Pub/Sub 只做实时转发;浏览器断线后不补历史事件。
运行链路
核心组件
消息契约
controller 入队的 handoff message 类型为agent.chat_dispatch.v1。由于 job 可能在另一个进程执行,request 和 options 必须是可序列化数据。
runId 直接使用 handoff message 的 id。实时 Redis channel 约定为:
Callback Transport
AgentChatCallbackTarget 支持两类回传 transport:
handoff-message 是兼容模式,会继续通过 handoff 队列发布 callback message,因此仍需要 messageType。
redis-pubsub 是 Xpert Chat SSE 使用的模式,会直接向 Redis 发布实时 envelope:
SSE 语义
stream:原样转发为MessageEvent。complete:结束 SSE observable。error:发送 SSE error event,然后结束 observable。- 客户端断开:触发
StopHandoffMessageCommand({ messageIds: [runId] })。 - keepalive 行为保持不变,controller 仍然套用
keepAlive(30000)和takeUntilClose(res)。
运维与排障
- Redis 是 Bull 队列和实时 Pub/Sub 的必备依赖。
- API 实例和 worker 实例可以独立扩缩容;执行
XpertChatCommand的 worker 不需要和接收 HTTP 请求的进程相同。 - 如果请求卡住,优先检查 API 实例是否订阅了
ai:handoff:agent-chat:<runId>,handoff job 是否成功入队,以及 worker 是否发布了stream、complete或error。 Local task not found和Pending result timeout不应再出现在 Xpert Chat SSE 链路上。如果仍然出现,通常说明该请求还在走旧的本地 handoff 路径。