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

83 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公网兼容对话入口 v1 架构
## 1. 调用链
```mermaid
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. 标识映射
```text
兼容 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。
测试页面使用浏览器 `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. 相关文档
- [`../specs/fire-safety-ymd-dashscope-compatible-chat-v1.md`](../specs/fire-safety-ymd-dashscope-compatible-chat-v1.md)
- [`chat-api-v1.md`](chat-api-v1.md)
- [`../workflows/user-chat.md`](../workflows/user-chat.md)
- [`../project/operations/nginx-public-entry.md`](../project/operations/nginx-public-entry.md)
- [`../specs/fire-safety-ymd-chat-page-v1.md`](../specs/fire-safety-ymd-chat-page-v1.md)