初始化第一版
This commit is contained in:
commit
8a6c31c14d
83 files changed
+14302
No files matched your search
@@ -0,0 +1,82 @@
|
||||
# 用户对话 API v1 架构
|
||||
|
||||
## 1. 组件边界
|
||||
|
||||
```mermaid
|
||||
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. 请求生命周期
|
||||
|
||||
1. Handler 校验请求方法、精确 Origin、Chat Bearer、媒体类型、Accept、请求体大小和严格 JSON。
|
||||
2. Service 校验消息和本地 `conversation_id`。
|
||||
3. 首轮请求由 Service 生成随机 `conversation_id`,并使用服务端固定测试主体创建 SuperAgent Session。
|
||||
4. Service 在内存中保存 `conversation_id -> provider session_id`;Provider Session ID 不返回客户端。
|
||||
5. Handler 开始 SSE,先返回 `conversation` 事件。
|
||||
6. Adapter 把消息发送到已准备的 Session,只将经过清洗的 `run.*` / `tool.*` 进度投影给 Handler。
|
||||
7. Adapter 严格确认最终内容、成功 `run.completed` 和顶层 `end` 后,Handler 才发送 `message` 与 `done`。
|
||||
8. 发生断流、超时、协议错误或失败 Run 时,不返回部分回答;当前映射失效,客户端下一次应创建新对话。
|
||||
|
||||
Handler 在没有可公开进度时每 15 秒发送不含数据的 SSE comment heartbeat,并把单请求写期限扩展到配置的总运行 deadline 之后 5 秒,以便返回终止错误。反向代理仍需显式关闭该路径的响应缓冲并设置相容的空闲超时。
|
||||
|
||||
## 3. 会话状态机
|
||||
|
||||
```text
|
||||
不存在
|
||||
-> 创建 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。
|
||||
|
||||
## 5. 伸缩与后续替换点
|
||||
|
||||
当前内存实现适合单实例受控联调。进入多实例或真实用户阶段前,需要把 `ChatService` 的本地状态替换或扩展为:
|
||||
|
||||
- 经验证的最终用户身份与动态数据授权上下文。
|
||||
- 持久化或共享的会话映射,并明确并发租约、过期和恢复语义。
|
||||
- 网关限流、滥用防护、请求配额和指标。
|
||||
- 对话、工具调用和安全事件的脱敏持久审计。
|
||||
- 主动取消 Provider Run,以及客户端断开后的终止策略。
|
||||
|
||||
这些扩展不能通过简单放宽当前静态 Token 或把客户端用户字段原样传给 Agent 来实现。
|
||||
|
||||
既有客户端所需的 DashScope 风格协议通过独立 Handler 适配并复用本文 Chat Service,不改变原生契约。公网入口和两种协议映射见 [`public-chat-entry-v1.md`](public-chat-entry-v1.md)。
|
||||
@@ -0,0 +1,57 @@
|
||||
# 公网兼容对话入口 v1 架构
|
||||
|
||||
## 1. 调用链
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
C[既有用户客户端] -->|HTTPS + xtoken\nDashScope 风格 JSON/SSE| N[Nginx]
|
||||
N -->|HTTP 127.0.0.1:8080| D[兼容 Chat 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` |
|
||||
|
||||
两个 Handler 都调用同一个 `ChatService.Prepare` 和 `ChatTurn.Stream`。兼容层只负责协议转换,不复制会话或 SuperAgent 业务逻辑。
|
||||
|
||||
## 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。
|
||||
|
||||
## 5. 网络与伸缩边界
|
||||
|
||||
- Go 推荐只监听 `127.0.0.1:8080`,公网只开放 Nginx 443;PostgreSQL 5432 不对公网开放。
|
||||
- Nginx 对兼容路径关闭缓冲、缓存、gzip 和重试,超时必须覆盖 Go Chat Run Timeout。
|
||||
- `/mcp` 使用独立 Bearer;Chat `xtoken`、MCP Bearer 与 SuperAgent Open API Key 三者不得复用。
|
||||
- 当前会话在单进程内存中。多实例部署必须先实现共享会话映射或粘性路由;否则后续轮次可能落到另一实例并返回 404。
|
||||
- 浏览器可读取静态 `xtoken`,所以该入口仍只适用于受控联调;生产最终用户入口需要真实身份认证和动态授权。
|
||||
|
||||
## 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)
|
||||
@@ -0,0 +1,73 @@
|
||||
# 空间只读 MCP v1 架构
|
||||
|
||||
## 决策摘要
|
||||
|
||||
首版 MCP 内嵌在现有 Go 服务中,使用标准库实现 HTTP/JSON-RPC 协议层,使用 `pgx/v5` 原生连接池访问 PostgreSQL/PostGIS。没有引入 MCP SDK、Web 框架或 ORM。
|
||||
|
||||
采用这一边界是因为当前只需要 SuperAgent 已验证的 `2025-06-18` 四个方法和同步 JSON 响应;业务复杂度位于固定空间查询、权限范围和安全语义,而不是协议框架。
|
||||
|
||||
## 模块关系
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
APP["internal/app\n依赖装配与 readiness"]
|
||||
H["internal/handler\nBearer、JSON-RPC、schema、限流边界"]
|
||||
S["internal/service\n查询边界、超时、结果语义"]
|
||||
D["internal/domain\n稳定空间领域对象"]
|
||||
R["internal/repository\npgxpool、固定参数化 PostGIS SQL"]
|
||||
DB["8 张既有 PostGIS 表"]
|
||||
|
||||
APP --> H
|
||||
APP --> S
|
||||
APP --> R
|
||||
H --> S
|
||||
S --> D
|
||||
S --> R
|
||||
R --> D
|
||||
R --> DB
|
||||
```
|
||||
|
||||
Handler 不知道物理表名,Repository 不组织自然语言回答,Domain 不依赖 MCP 或 pgx。可信数据范围在应用装配时由配置传入 Service,并由 Repository 在 SQL 中应用:默认 `town_allowlist` 使用参数化镇街数组过滤;显式 `all` 使用服务端布尔参数放开镇街过滤。范围选择不进入工具 schema,模型无法扩大权限。
|
||||
|
||||
## 数据映射
|
||||
|
||||
| 领域结果 | 物理表 |
|
||||
| --- | --- |
|
||||
| 地名候选 | 以下 8 张表的名称、镇街、村庄和几何字段 |
|
||||
| 网格上下文、责任中队 | `st_2_fanghuowangge` |
|
||||
| 水源候选 | `st_2_mpslfh_t_slfh_syd`、`st_2_xianyouxushuichiguan` |
|
||||
| 指挥部候选设施 | `st_2_fanghuojianchazhan`、`st_2_fanghuoliaowangshao` |
|
||||
| 通道候选 | `st_2_xianyoufanghuotongdao` |
|
||||
| 风险区域 | `st_2_mudifenqu_mian`、`st_2_linqugongkuangqiye` |
|
||||
|
||||
姓名、联系电话和值班人员字段不进入领域结果,也没有出现在查询 SELECT 列表中。
|
||||
|
||||
## 空间约束
|
||||
|
||||
- MCP 入参固定为 WGS84 经纬度。
|
||||
- 地名搜索是坐标查询前的候选发现:记录点直接返回二维坐标;线使用首个组成线的起点,面使用 `ST_PointOnSurface` 产生代表点,并以 `location_kind` 明确区分。代表点不得自动升级为用户确认的演练点。
|
||||
- 防火通道原始 `geom` 已确认混合二维与 Z 维度,导入层必须使用不限定 typmod 的 `geometry` 保存原始事实。距离/最近点等 MCP v1 运算按二维地表语义解释;若底层函数需要降维,只能在只读查询或派生层显式处理,不得回写或静默修改原始几何。
|
||||
- 启用前要求实库所有非空几何 SRID 为 4326、类型符合表用途且坐标位于 WGS84 合法范围;这些属于硬门禁。
|
||||
- 点到点、点到线、点到面距离使用 PostGIS `geography` 米制计算。
|
||||
- 面覆盖使用 `ST_Covers`,边界上的点也视为位于网格/风险区内。
|
||||
- SQL 同时检查 SRID、类型和有效性。无效或空几何不自动修复、不改写原始事实,而是从全部 MCP 查询中排除;readiness 和工具结果明确告警结果可能不完整。readiness 发现异常类型、非 4326 SRID 或越界坐标时仍拒绝启用。
|
||||
- 2026-09-05 实库 audit 发现防火网格 4 条、林区工矿企业 4 条、墓地坟区 27 条无效面几何。用户选择首版排除这 35 条记录,后续如需修复必须在派生副本中审查,不覆盖原始 `geom`。
|
||||
- 距离结果只是地理邻近,不包含地形、路网、火势、天气和实时通行信息。
|
||||
|
||||
## 依赖决策
|
||||
|
||||
`github.com/jackc/pgx/v5 v5.10.0` 是当前唯一新增的直接依赖。项目只面向 PostgreSQL,并需要明确的连接池、context 和 PostgreSQL 参数行为,因此使用原生 `pgxpool`;空间计算仍全部由参数化 SQL/PostGIS 完成。
|
||||
|
||||
## 后续演进边界
|
||||
|
||||
- 动态用户/组织授权到位后,用可信身份解析器替换当前每 Token 的静态数据库全范围/镇街白名单,工具 schema 不增加可伪造的授权字段。
|
||||
- 路线规划必须新增专门的图网络/地形数据和高风险 Spec,不能扩写当前通道候选工具的描述来冒充路线能力。
|
||||
- 联系人字段如确需开放,必须有字段级权限、脱敏、审计和单独工具,不直接扩展当前结果。
|
||||
- 写入、派遣或状态变更工具需要人工确认、幂等、审计和独立安全评审。
|
||||
|
||||
## 协议与依赖依据
|
||||
|
||||
- [MCP 2025-06-18 Lifecycle](https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle)
|
||||
- [MCP 2025-06-18 Streamable HTTP Transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports)
|
||||
- [MCP 2025-06-18 Tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)
|
||||
- [pgx 官方仓库与版本策略](https://github.com/jackc/pgx)
|
||||
Reference in new issue
Block a user