4.8 KiB
4.8 KiB
用户对话 API v1 架构
1. 组件边界
flowchart LR
UI[用户侧应用或 curl] -->|POST /api/chat\nChat Bearer + JSON| H[Chat Handler]
H -->|Prepare / Stream| S[Chat Service]
S -->|CreateSession / StreamMessage| A[SuperAgent Chat Adapter]
A -->|Open API Key + HTTPS/SSE| SA[SuperAgent]
SA -->|独立 MCP Bearer| M[POST /mcp]
M --> P[(PostgreSQL/PostGIS)]
三种凭证属于不同信任方向:
- Chat Bearer:用户侧应用到本 Go 服务,仅用于首版受控联调。
- SuperAgent Open API Key:本 Go 服务到 SuperAgent,只保存在服务端。
- MCP Bearer:SuperAgent 到本 Go 服务,只保护
/mcp。
三者必须使用不同值。
2. 请求生命周期
- Handler 校验请求方法、精确 Origin、Chat Bearer、媒体类型、Accept、请求体大小和严格 JSON。
- Service 校验消息和本地
conversation_id。 - 首轮请求由 Service 生成随机
conversation_id,并使用服务端固定测试主体创建 SuperAgent Session。 - Service 在内存中保存
conversation_id -> provider session_id;Provider Session ID 不返回客户端。 - Handler 开始 SSE,先返回
conversation事件。 - Adapter 把消息发送到已准备的 Session,只将经过清洗的
run.*/tool.*进度投影给 Handler。 - Adapter 严格确认最终内容、成功
run.completed和顶层end后,Handler 才发送message与done。 - 发生断流、超时、协议错误或失败 Run 时,不返回部分回答;当前映射失效,客户端下一次应创建新对话。
Handler 在没有可公开进度时每 15 秒发送不含数据的 SSE comment heartbeat,并把单请求写期限扩展到配置的总运行 deadline 之后 5 秒,以便返回终止错误。反向代理仍需显式关闭该路径的响应缓冲并设置相容的空闲超时。
3. 会话状态机
不存在
-> 创建 Provider Session
-> busy
-> 成功:idle
-> 上游结果不确定或失败:删除映射
idle
-> 新一轮 Prepare:busy
-> TTL 到期:惰性删除
busy
-> 同 conversation_id 的并发请求:409
会话存储是单进程内存映射:
- 进程重启后全部丢失。
- 多实例之间不共享,未配置粘性路由时后续轮次可能返回 404。
- 只保存随机本地 ID、Provider Session ID、占用状态和最后使用时间,不保存消息历史。
- SuperAgent 负责其 Session 内的上下文;本服务不会把完整历史在每轮重新发送。
4. 安全设计
- 客户端 DTO 没有
user_id、external_subject_id、角色、镇街范围、Provider Session 或 metadata 字段;未知字段直接拒绝。 - 固定测试主体由服务端配置,不能作为最终用户身份或权限依据。
- CORS 使用精确 Origin 列表,不支持
*或 credentials。 - Handler 日志只记录 request ID、结果、是否复用和耗时,不记录问题、答案或对话 ID。
- 进度只允许安全字符组成的
run.*/tool.*事件,以及工具名和状态;消息 delta、Provider ID、工具参数和结果不向客户端透传。 - 错误映射为稳定代码,不回显 Provider 响应正文、URL、Session、堆栈或 Secret。
- API 默认关闭;启用必须同时具备有效 SuperAgent 配置和独立 Chat Bearer。
- Chat 凭证默认至少 32 个可打印 ASCII 字符。为兼容已经交付且无法立即更换的旧客户端短凭证,只有在受控测试/迁移窗口显式设置
FIRE_SAFETY_CHAT_ALLOW_LEGACY_SHORT_TOKEN=true才允许短值;无论开关如何,凭证都必须非空、不超过 4096 字节且仅含 ASCII0x21-0x7e(无空格、控制字符或 Unicode)。该开关同时适用于原生 Bearer 和兼容xtoken,不影响 MCP 的至少 32 字符门禁;三种凭证必须不同。轮换后恢复false,新环境不得开启。 - 开关启用时只记录不含 Secret 的安全 warning,提醒运维在迁移完成后关闭兼容。
5. 伸缩与后续替换点
当前内存实现适合单实例受控联调。进入多实例或真实用户阶段前,需要把 ChatService 的本地状态替换或扩展为:
- 经验证的最终用户身份与动态数据授权上下文。
- 持久化或共享的会话映射,并明确并发租约、过期和恢复语义。
- 网关限流、滥用防护、请求配额和指标。
- 对话、工具调用和安全事件的脱敏持久审计。
- 主动取消 Provider Run,以及客户端断开后的终止策略。
这些扩展不能通过简单放宽当前静态 Token 或把客户端用户字段原样传给 Agent 来实现。
既有客户端所需的 DashScope 风格协议通过独立 Handler 适配并复用本文 Chat Service,不改变原生契约。公网入口和两种协议映射见 public-chat-entry-v1.md。