Files
fire-safety-ymd/docs/architecture/public-chat-entry-v1.md
T
2026-09-06 01:40:15 +08:00

6.8 KiB
Raw Blame History

公网兼容对话入口 v1 架构

1. 调用链

flowchart LR
    B[受控测试浏览器] -->|GET /chat 或 /chat/| N[Nginx]
    C[既有用户客户端] -->|HTTPS + xtoken\nDashScope 风格 JSON/SSE| N[Nginx]
    N -->|HTTP 127.0.0.1:16587<br/>宿主机映射到容器 :8080| D[兼容 Chat Handler]
    N -->|HTTP 127.0.0.1:16587| P0[可选 Chat Page Handler]
    D -->|ChatRequest / ChatTurn| S[共享 Chat Service]
    S -->|Provider-neutral port| A[SuperAgent Adapter]
    A -->|Open API Key + HTTPS/SSE| SA[SuperAgent]
    SA -->|独立 MCP Bearer| M[同域 /mcp]
    M --> P[(PostgreSQL/PostGIS)]

Nginx 不再直接调用 DashScope。它只负责 TLS、精确公开路径、基础限流和 SSE 传输设置;所有应用鉴权、输入校验、会话映射和上游调用都在 Go 服务内完成。

2. 双入站协议、单一用例

入站接口 面向对象 鉴权 Header 请求字段 成功事件
/api/chat 本项目原生客户端 Authorization: Bearer message、conversation_id conversation、progress、message、done
/api/v1/apps/{app_id}/completion 既有 DashScope 风格客户端 xtoken input.prompt、input.session_id、受限 parameters result,最终 finish_reason=stop
/chat、/chat/ 受控测试浏览器页面 页面本身不鉴权;页面发出的兼容请求使用用户输入的 xtoken /chat 返回 308 到 /chat/;/chat/ 返回 HTML 页面消费同一 result SSE
/chat/app.css、/chat/app.js 页面同源静态资源 页面资源不鉴权 CSS/JavaScript 页面加载资源

两个 Handler 都调用同一个 ChatService.Prepare 和 ChatTurn.Stream。兼容层只负责协议转换,不复制会话或 SuperAgent 业务逻辑。

/chat 和 /chat/ 是同一个最小测试页面入口,其中 /chat 规范化重定向到 /chat/,不是第三种对话协议。页面调用的仍是当前配置的 /api/v1/apps/{FIRE_SAFETY_CHAT_COMPAT_APP_ID}/completion,请求体、xtoken、SSE event: result、finish_reason 和 session_id 语义与既有第三方客户端完全相同。页面只把 session_id 保存在当前页面的 JavaScript 内存中,用于同一页面的后续轮次;刷新页面或关闭页面 后不会恢复会话。

3. 标识映射

兼容 output.session_id
  = 本地 conversation_id
  -> Chat Service 内存映射
  -> Provider session_id(永不返回客户端)

兼容 URL 中的 app_id 是配置的公开路由标识。它不能选择任意 Profile,也不参与授权;SuperAgent 目标仍由服务端 Base URL、Key 和已发布 Profile 决定。

4. 严格结果边界

兼容 Handler 会尽早发送一个无正文的 result 事件,让客户端取得会话 ID并建立 SSE。正文不会跟随上游 message.delta 实时透传。只有既有 Adapter 验证最终内容、成功 Run 和流终止标记后,Handler 才发送 finish_reason=stop 与最终文本。

这样保留了当前应急辅助场景的失败语义:断流或 Provider 协议不完整时,客户端不会把半截模型文本误当成已完成方案。代价是首版没有逐字动画;如后续必须实时输出,需要独立安全决策、取消/失败 UX 和新 Spec。

4.1 SuperAgent Trace 模式

上游消息流的 include_trace 由 FIRE_SAFETY_SUPERAGENT_INCLUDE_TRACE 控制,默认值为 false。两种模式都要求最终 AI 消息和顶层 event: end,但严格成功条件不同:

  • 无 Trace:最终 AI 消息的 finish_reason=stop + 非空顶层 message.final + 顶层 end。
  • Trace:最终内容 + run.completed(status=success) + 顶层 end。

无 Trace 只是不向调用方返回公开工具/步骤轨迹,不等于禁止 SuperAgent 执行中调用 MCP;Agent 是否实际调用消防工具仍必须通过完整对话和 /mcp 日志验证。当前受控诊断中,应用策略关闭 Trace 时 include_trace=true 返回 HTTP 403、Provider code open_agent_trace_disabled, 同一 Key 改为 include_trace=false 返回 HTTP 200。因此测试环境默认保持无 Trace;只有在外部 应用策略显式启用 trace_policy.enabled=true 后才可切换为 Trace 模式。

测试页面使用浏览器 fetch 发起 POST,以便同时设置 xtoken 并读取 SSE;它不会把 Token 写进 HTML、Cookie、localStorage、sessionStorage、URL 或服务端配置。用户每次打开页面都要手动 输入测试 xtoken,页面只在本次页面生命周期内使用该值。页面可展示用户输入的问题和最终回答, 但不承担身份认证、权限判断、历史持久化或审计职责。

5. 网络与伸缩边界

  • Docker 部署中 Go 在容器内监听 :8080,宿主机只发布 127.0.0.1:16587 给 Nginx;若直接运行二进制,则监听 127.0.0.1:16587。公网只开放 Nginx 443,PostgreSQL 5432 不对公网开放。
  • Nginx 对兼容路径关闭缓冲、缓存、gzip 和重试,超时必须覆盖 Go Chat Run Timeout;页面 HTML、 CSS 和 JavaScript 使用精确 location 反代,不能因只代理 /chat/ 而让资源路径落入默认 404。
  • /mcp 使用独立 Bearer;Chat xtoken、MCP Bearer 与 SuperAgent Open API Key 三者不得复用。
  • 当前会话在单进程内存中。多实例部署必须先实现共享会话映射或粘性路由;否则后续轮次可能落到另一实例并返回 404。
  • 浏览器可读取静态 xtoken,所以该入口仍只适用于受控联调;生产最终用户入口需要真实身份认证和动态授权。
  • 页面开关 FIRE_SAFETY_CHAT_PAGE_ENABLED 默认关闭。Nginx 可固定反代 /chat、/chat/、 /chat/app.css 和 /chat/app.js,但 Go 仅在开关开启且 Chat 兼容入口配置完整时注册路由; 关闭时四个路径均直接返回 404;开启时 /chat 才规范化为 308,跟随后 /chat/ 和资源 路径返回页面内容。
  • 页面与 API 使用同一公网 Origin 时,服务端 FIRE_SAFETY_CHAT_ALLOWED_ORIGINS 必须包含精确值 https://agent.nianxx.com。不使用通配符;Nginx 不注入或保存 xtoken。
  • 页面是静态测试工具,不是生产用户认证。任何能访问页面的人都可以看到输入框,凭证仍由用户 手动提供;页面开启前必须确认测试 Token 的范围和轮换计划。

6. 相关文档