Commit 7e0c436f5b4131c055a7d576d28117ebdb92d8fb

Authored by zichun
1 parent 237d26ee

docs+ui: §16 gap-closure status; local chat page uses dev-login (blank stale tok…

…en, prod injects live token)
docs/agent-architecture.md
... ... @@ -207,12 +207,23 @@ ai_op_queue(
207 207 - **审计**:`ai_audit_log` 记 propose/confirm/cancel/query。
208 208 - **ERP 接入**:`ErpClient` dev-login(admin/666666)拿真实会话 token;读 `getBusinessDataByFormcustomId`,写 `addUpdateDelBusinessData`(`column` 列表 + `handleType`)。
209 209  
210   -**尚未做 / 被外部条件阻塞**(按原因归类):
211   -- **授权层(§7)**:机制可建,但 dev-login=admin 时全通、无意义;**需生产的透传用户 token 才能真正约束**。
212   -- **写:新增 / 删除 / 审核**:`create` 撞 NOT-NULL 连环(sId/sParentId…);`delete/审核` 格式与校验各异且后果重。正解是**架构里的 ERP 侧暂存执行器(跨团队)**;当前只做安全的 `update`。
213   -- **FormCollect(§5)**:需 ERP 前端在对话里渲染表单——**跨团队**。
214   -- **ERP 侧暂存执行器 + 预填 + 深链(§10)**:**跨团队**,本项目未覆盖。
215   -- **Langfuse(§1)**:需自托管实例——**基础设施**。
216   -- **AskUser 结构化选项**:当前 agent 用自然语言澄清(如 lookupRecord 命中多条会请用户说具体),功能已覆盖,结构化选项为后续优化。
217   -- **稳健 NL2SQL**:`queryData` 安全但选表/拼 join 精度有限(架构 §14.1 早已标注为待专项攻关)。
218   -- **现网安全发现上报**(后端权限关 / 旧 NL2SQL 越权 / 读 API 可写):**业务侧事项**,非本次代码。
  210 +## 16. 缺口补齐(2026-07-22,分支 `kg-edge-flow`)
  211 +
  212 +上一轮 §15 里「尚未做 / 被外部条件阻塞」的缺口,本轮全部补齐(含跨团队 ERP 侧)。均已编译通过(xlyAi mvn + ERP gradle)。
  213 +
  214 +**xlyAi 侧**
  215 +- **授权 + token 透传(§7)**:新增 `AgentIdentity` + `AgentFactory` —— **按每次请求的身份新建 agent**,把透传的用户 ERP token 与「表单权限集」(`sAuthsId` → `AuthzService.grantedIds`)放进每请求的工具实例(规避 LC4j 流式工具在回调线程执行、ThreadLocal 不可靠的问题,即架构说的 per-call context)。前端逐请求带 `authorization`+身份;`ErpClient` 所有读写 **转发用户 token**;**用户 token 过期绝不用 dev(admin) 重登**(防静默提权)。dev-login 仅作本地兜底。
  216 +- **写:新增 / 删除 / 审核**:`proposeCreate`(自动补主键/必填)、`proposeDelete`、`proposeExamine` 三个 HITL 工具,均只暂存 `ai_op_queue` draft、确认端点才执行;确认转发用户 token。`ai_op_queue` 加 `sPayload/sSourceRef/bAutoExecute/sResultBillId/sErrorMsg/tExecutedDate/tExpireAt`。
  217 +- **FormCollect(§5)**:`collectForm` 从 ERP 表单元数据(`gdsconfigformslave`:字段/控件/必填/下拉/默认)取 schema → SSE `form_collect` → **xlyAi 聊天页内渲染表单**(无需 ERP 前端),提交拼回 `proposeCreate`。
  218 +- **AskUser(§5)**:`askUser(question, options)` → SSE `question` → 前端渲染可点选项片。
  219 +- **Skills(§6)**:`ai_skill` 注册表 + `SkillService`(name+何时用进 system prompt)+ `loadSkill` 工具(按需注入完整 playbook);种子技能:新建报价 / 月度对账 / 库存查询。
  220 +- **KgSearch(§5/§11)**:`kgSearch` 暴露 L2 邻居/流转(`viw_kg_form_neighbors`)+ L3 字段→表列(`viw_kg_field_dict`),按词查、截断。
  221 +- **稳健 NL2SQL(§9)**:`QueryTool` 加**表白名单**(`viw_*` + 表单数据源 + 字段字典表,用 jsqlparser `TablesNamesFinder` 校验 → 挡住 `gdslogininfo`/`sysjurisdiction`/`ai_op_queue` 等敏感表)+ **单表租户谓词注入**(`sBrandsId`)+ prompt 品牌提示 + 自修复重试。
  222 +- **Langfuse(§1)**:`TracingChatModelListener` 增加**配置开关的 ingestion 导出**(generation span,走 JDK HttpClient,不引依赖);`docker-compose.langfuse.yml` 自托管;默认关闭。
  223 +
  224 +**ERP 侧(saas-8s+ `release/customer/2025/saas-8s+`,backup 分支未动)**
  225 +- **暂存执行器 + 预填 + 待办(§10)**:`AiStagingController @/ai` —— `execStaging/{sId}`(POST,执行)、`staging/{sId}`(GET,预填加载供原生表单深链)、`myTodos`(GET,AI待办);全部 `@Authorization`+`@CurrentUser`。`AiStagingService(Impl)` 读共享库 `ai_op_queue` → 以**用户身份**走 ERP 自己的写入/审核逻辑(`addUpdateDelBusinessData` / `doExamine`,复用租户隔离、单号、审核存储过程)→ 幂等 + 回写状态/结果。xlyAi 确认端点按 `erp.exec-staging.enabled` 委托它(生产路径)或直连(本地默认)。
  226 +
  227 +**仍属业务/运维决策(非代码缺口)**
  228 +- 现网安全发现(后端逐用户表单权限被注释关 / 读 API 可被 `bUpdate` 触发写 / 旧 NL2SQL 越权)——`docs/security-findings.md` 已成文,**是否整改由业务定**。授权层真正“收紧到非管理员”只有在**生产以真实用户 token 运行**时才能观测(本地 dev-login=admin 全通)。
  229 +- 报价改双确认、首个灰度只读场景选型 —— 业务确认项。
... ...
src/main/resources/templates/chat.html
... ... @@ -472,7 +472,10 @@
472 472 let brandsid= "1111111111";
473 473 let subsidiaryid= "1111111111";
474 474 let usertype= "sysadmin";
475   - let authorization="CE444885A9BCFDDE1FD793F8A0931301E9D7DE6CEDD9DE4B83ECE2219C7829A8F3419238942A93E9AD666629E18D159A8BB22EBE26EF12CD9A1EEDB89DC6FB33178153C379FB82F53B4B689DA1BE7060687D4EF8281542FFC87C4EB776974C6A538155B7ADAEE71E899235DC1122F426";
  475 + // ERP 登录 token(透传给后端 → 转发给 ERP,用于按真实用户身份读写;绝不进 prompt)。
  476 + // 本地独立聊天页无浏览器登录流程,留空 → 后端回退 dev-login(admin)读写;
  477 + // 生产环境由 ERP 外壳把用户的实时有效 token 注入这里,即启用逐用户 token 透传 + 表单权限收紧。
  478 + let authorization="";
476 479 let hrefLock = window.location.origin+"/xlyAi";
477 480  
478 481 const CONFIG = {
... ...