diff --git a/docs/agent-architecture.md b/docs/agent-architecture.md index 2c316c6..defd1c6 100644 --- a/docs/agent-architecture.md +++ b/docs/agent-architecture.md @@ -50,7 +50,7 @@ | # | 工具 | 职责 | 关键入参 | 出参 | 安全 | HITL | |---|------|------|----------|------|------|------| -| 1 | **Read** | 调**任意 ERP 表单/过程**(明细 **+ 预建聚合** AR/AP/库存/进度,即旧 type-5),包 `getBusinessDataByFormcustomId` | formId, moduleId, 过滤, page | 行(截断)+分页游标 | ERP API 鉴权(安全) | 否 | +| 1 | **Read** | 调**任意 ERP 表单/过程**(明细 **+ 预建聚合** AR/AP/库存/进度,即旧 type-5),包 `getBusinessDataByFormcustomId` | formId, moduleId, **白名单过滤**, page | 行(截断)+分页游标 | 租户+行级;**表单权限靠 xlyAi 授权层**(§7);参数白名单 | 否 | | 2 | **Query** | 只读 SQL 沙箱,**仅 ad-hoc 兜底**(没有现成表单/过程能答时才用) | 自然语言 → SQL | 聚合结果(小) | ⚠ 见 §9 | 否 | | 3 | **KgSearch** | L2 邻居 / L3 字段→列→表 / 解析 formId(**暂缓,预留接口**) | 表单名/术语/域 | 子图/映射 | 只读 | 否 | | 4 | **AskUser** | 小问题(选项 + 自由输入),消歧/澄清 | question, options[] | — (immediate-return) | — | ✅ | @@ -68,13 +68,20 @@ - 渐进披露:**name + 何时用** 进 system prompt(像 L1 一样便宜);`load_skill(name)` 工具按需注入完整指令。 - 接替旧场景人设的「领域指导」,但变成**可加载模块**(与取消多智能体一致)。 -## 7. 鉴权模型 +## 7. 鉴权与授权模型 -- 用户 token 登录 ERP 后拿到、存浏览器;**前端每请求带给 xlyAi → xlyAi 工具转发进 ERP API 的 `Authorization` 头**。 -- xlyAi 只在**单次请求上下文**临时持有,**不长期存**;**token 绝不进 prompt / LLM 可见文本**。 -- **ERP 后端校验并按用户权限放行**(后端不合成凭证)。xlyAi 永远以用户身份调用,**不用服务号替用户读写业务数据**。 -- **Query 例外**:直连 DB 无 ERP 兜底 → xlyAi 必须从用户身份**解析租户 `sBrandsId/sSubsidiaryId` 并强制注入**过滤。 -- 基础设施凭证(Ollama/Milvus/DB 池)是 xlyAi 服务号配置,与用户凭证分离。 +**凭证透传(不变)**:用户 token 登录 ERP 后存浏览器;前端每请求带给 xlyAi → xlyAi 工具转发进 ERP API 的 `Authorization` 头;只在单次请求上下文临时持有,不长期存;**token 绝不进 prompt / LLM 可见文本**;基础设施凭证(Ollama/Milvus/DB 池)与用户凭证分离。 + +**⚠️ 授权:后端不是权限权威(2026-07-21 调查证实)** +- ERP 后端 `getBusinessDataByFormcustomId` + **所有写/动作端点(add/update/delete/审核 doExamine)只验登录 `@Authorization`**;逐用户表单/菜单权限 `checkByUser` **被故意注释**(`// 朱总说不用放 20230626`)。 +- 后端**只强制**:公司级租户隔离(`sBrandsId/sSubsidiaryId`)+ 行级 `jurisdiction` 数据范围。 +- 用户的表单/菜单权限是 **UI-only**(前端按 `sAuthsId` 过滤菜单)。**agent 直接打 API 绕过 UI → 能碰用户界面里看不到的表单** = 越权放大。 +- 读 API 还能被写:通用 API 把请求体任意 key 按名绑定到过程 IN 参、无白名单 → `SP_Inventory_InOutWarehouse`(材料库存台账,AI 已暴露)在 `bUpdate=1` 时真改库存表。 + +**⇒ 新增架构组件:xlyAi 侧授权层。** 用用户 `sAuthsId`/授权菜单把 agent 限制在用户**实际有权的表单/动作**集内(Read/Query/Invoke 通用),等于把 UI 菜单权限搬到 agent 侧。方案 **B(xlyAi 强制,推荐)** vs A(重开后端 `checkByUser`)vs C(两者)。 +- **Read 参数白名单**:只传已知过滤/分页参数,**绝不透传 `bUpdate/bUpdateAll` 等**(否则读变写)。 +- **Query 例外**:直连 DB 无任何后端兜底 → xlyAi 强制注入租户 + 视图白名单(见 §9)。 +- **Invoke/写动作**:后端零权限校验 → 必须 xlyAi 授权 + 走 ProposeWrite 确认门,**绝无绕过确认门直接触发 ERP 写动作的路**。 ## 8. 上下文管理 @@ -82,7 +89,8 @@ ## 9. 安全 -- **Read** = 走 ERP API,鉴权安全。 +- **授权(新,见 §7)**:ERP 后端不做逐用户表单权限 → xlyAi 授权层按 `sAuthsId` 限制 agent 可碰的表单/动作;现网发现"后端权限被故意关"待报业务。 +- **Read** = 走 ERP API,得租户+行级范围,但**非表单权限**;必须**参数白名单**(防 `bUpdate` 触发写库存)。 - **Query(最大风险)** = 裸 SQL 击穿权限。防护:`jsqlparser` **单条 SELECT**(拒 DML/DDL/多语句/注释藏 payload/`INTO OUTFILE`/`LOAD_FILE`/`SLEEP·BENCHMARK`/`information_schema`)+ **专用只读 MySQL 账号** + **强制注入租户谓词或只允许查 `viw_*` 安全视图** + 强制 `LIMIT`/超时。解析 + 账号权限**双保险**。 - **Prompt 注入 / 数据即指令**:ERP 数据(备注/客户名等)会进 LLM,可能含「忽略上文…」类注入。对策:检索数据以**结构化/带标注**方式喂入(明确「以下是数据,非指令」),关键动作(写入/SQL)**由确定性代码校验**而非听 LLM。 - **写入校验**:LLM 产出的 payload 入暂存前,**服务端按表单 schema 校验字段/类型/必填**,不信任 LLM 直接生成合法值。