cc vor 4 Wochen
Ursprung
Commit
616cad5816
3 geänderte Dateien mit 351 neuen und 53 gelöschten Zeilen
  1. 18 0
      .workbuddy/memory/2026-09-15.md
  2. 333 0
      AI_AGENT.md
  3. 0 53
      ai-server/src/main/resources/app.yml

+ 18 - 0
.workbuddy/memory/2026-09-15.md

@@ -0,0 +1,18 @@
+# 2026-09-15
+
+## 编写仓库级 AI Agent 协作指南
+- 产出:`E:\workspace\zsjz-ai\AI_AGENT.md`(仓库根,12 节)
+- 内容:项目定位(清鉴 = 纪检监察/经侦智能资金数据研判平台)、仓库结构、前后端技术栈、
+  后端分层落位约定、主/从数据源(PG master + DuckDB slave)、Agent 子系统(AgentScope 工具/SSE 协议/硬约束)、
+  dm 清洗模块、前端域目录约定、常用命令、Do/Don't、已知待清理项、提交检查清单。
+- 关键区分:`ai-server/src/main/resources/prompts/AGENTS.md` 与 `QingJian/agent/AGENTS.md`
+  是**产品运行时 AI 人格提示词**,不是编码助手约定,勿混改。
+- 发现的问题(已写入文档第 11 节):
+  1. `common/config/Result.java` 有未使用且无依赖的 `import io.milvus.param.R;`
+  2. `Result` 的 SUCCEED_CODE/FAILURE_CODE 非 final
+  3. `app.yml` 为 Solon 遗留配置,已失效;`context-path: "!/js/a/"` 语义可疑
+  4. ai-server 未见 @MapperScan
+
+## 环境备忘
+- Bash 工具在本机异常(`dirname: command not found`,PATH 损坏),改用 Glob/Read/Grep/PowerShell。
+- PowerShell 的 stdout 在该环境下未能回传,目录列表类操作优先用 Glob。

+ 333 - 0
AI_AGENT.md

@@ -0,0 +1,333 @@
+# AI Agent 协作指南 · zsjz-ai(清鉴)
+
+> 本文件是**仓库级**约定,供 AI 编码助手(WorkBuddy / Claude Code / Cursor / Copilot 等)在本仓库内改代码时遵守。
+>
+> ⚠️ 别和下面两个文件搞混 —— 它们是**产品运行时的 AI 人格提示词**,不是给编码助手看的:
+> - `ai-server/src/main/resources/prompts/AGENTS.md`
+> - `QingJian/agent/AGENTS.md`
+>
+> 改那两个文件 = 改产品里 AI 研判专家的人设与话术;改本文件 = 改编码助手的行为约定。
+
+---
+
+## 1. 项目一句话定位
+
+**清鉴(QingJian)** —— 面向纪检监察 / 经侦机关的智能资金数据研判平台。
+
+业务闭环:
+```
+多源异构数据导入(话单 CDR / 银行账单 / 第三方支付 / 基站轨迹 / 外部库表)
+   → 清洗治理(dm 模块)
+   → 建模分析(通话·资金·轨迹·人物画像·图谱)
+   → 可视化(ECharts / G6 关系图 / 离线栅格地图)
+   → AI 对话式研判(AgentScope Agent + RAG + SQL 工具)
+```
+
+领域术语(写注释/命名时沿用它,不要自创):
+`资金回流`、`闭环交易`、`快进快出`、`通联异常`、`时空伴随`、`白手套`、`攻守同盟`。
+
+---
+
+## 2. 仓库结构
+
+```
+zsjz-ai/
+├─ pom.xml                    # 父 POM(packaging=pom),Spring Boot 3.5.16,仅聚合 ai-server
+├─ ai-server/                 # 后端:Spring Boot 3 + MyBatis-Plus + AgentScope
+├─ ai-frontend/               # 前端:Vue3 + Vite7 + TS + Ant Design Vue(JeeSite 脚手架血统)
+├─ sql/                       # 建表 / 初始化脚本(*.sql)
+├─ QingJian/                  # 运行期工作空间素材(agent 提示词、skills、conf、db、license)
+├─ cmd/  lib/  pmtiles.exe    # 本机工具(regInfo.exe 授权、mbtiles→pmtiles 转换等)
+└─ enc.md  readme.md
+```
+
+`QingJian/` 不是源码目录,是**运行时数据目录**(含 `.db`、license 证书、导入模板),改动需谨慎。
+
+---
+
+## 3. 技术栈
+
+### 后端(ai-server)
+
+| 项 | 值 |
+|---|---|
+| JDK | **25** |
+| 框架 | Spring Boot 3.5.16 |
+| 持久层 | MyBatis-Plus 3.5.17 + dynamic-datasource 4.5.0 |
+| 主库 | **PostgreSQL** + pgvector(master) |
+| 分析库 | **DuckDB**(slave,按工作空间切换) |
+| 缓存 | Redis |
+| 图库 | Neo4j(配置存在,非全链路强依赖) |
+| 鉴权 | Sa-Token 1.46 |
+| Agent | **AgentScope 2.0.1**(harness + dashscope/ollama/openai + mem0 + rag-simple + redis) |
+| 检索 | Lucene 10(core/queryparser/analysis-common/highlighter) |
+| 其他 | fesod-sheet(Excel)、Hutool、Guava、MapStruct 1.6.3、commons-compress、JNA |
+| 启动类 | `com.zsjz.ai.App` |
+| 端口 | `8980` |
+
+> `ai-server/src/main/resources/app.yml` 是 **Solon 时代遗留配置,已不生效**,只作历史参考,不要照它改。
+> 生效配置是 `application.yaml` + `application-dev.yaml`。
+
+### 前端(ai-frontend)
+
+- Vue 3.5 + TypeScript 5.9 + Vite 7 + **pnpm 10**(`preinstall: only-allow pnpm`,禁止 npm/yarn)
+- Ant Design Vue 4.2.6、Pinia 2.3、vue-i18n 11、UnoCSS 66
+- 图可视化:**G6 5**、X6、`@relation-graph/vue`;图表 **ECharts 6**
+- 地图:**maplibre-gl + pmtiles**(离线栅格底图)
+- Markdown:vditor、streamdown-vue、markdown-it
+- Node 要求:`>=20.19 || >=22.12`
+
+**接口前缀 `/js`**,开发环境由 `.env.development` 代理到 `http://127.0.0.1:8980`:
+```
+VITE_PROXY = [["/js","http://127.0.0.1:8980/js",false]]
+VITE_GLOB_API_URL_PREFIX = /js
+```
+
+---
+
+## 4. 后端分层与落位约定
+
+包根:`com.zsjz.ai`
+
+```
+com.zsjz.ai
+├─ App.java                      启动类
+├─ common/                       跨模块复用
+│  ├─ config/                    Result、WebConfig、MybatisPlusConfig、LicenseFilter、
+│  │                             DuckdbUnpooledDataSource、BigDecimal 序列化器
+│  ├─ base/                      Query、TreeNode、BasicColumn、Cleaned、ErrorEnum
+│  ├─ enums/  constants/  utils/
+│  └─ model/<domain>/{dto,entity,query,vo}/     ★ DTO / 实体统一放这里
+└─ module/<domain>/
+   ├─ controller/                仅收参 + 调 service
+   ├─ service/  service/impl/
+   └─ mapper/   (XML 在 resources/mappers/<domain>/*.xml)
+```
+
+`<domain>` 固定取值:`agent` `call` `dm` `external` `govern` `graph` `otg` `person` `plat` `track` `trans`
+
+配套资源:
+```
+ai-server/src/main/resources/mappers/<domain>/<Xxx>Mapper.xml
+```
+
+### 命名规范
+- 查询入参 → `common.model.<domain>.query.XxxQuery`
+- 出参 DTO → `common.model.<domain>.dto.XxxDTO`
+- 数据库实体 → `common.model.<domain>.entity.Xxx`
+- Service 接口 `XxxService`,实现 `XxxServiceImpl`
+- 类名后缀:Controller / Service / Mapper / DTO / VO / Entity / Query / Enum / Const
+
+### 编码规则
+1. **Controller 不写业务逻辑**,只做参数校验 + 转调 service。
+2. 分页统一用 MyBatis-Plus `Page<T>`(`PaginationInnerInterceptor(DbType.DUCKDB)` 已注册)。
+3. **统一返回 `Result<T>`**:`Result.succeed(data)` / `Result.failure(msg)`。
+   > 存量 Controller(如 `CallNightController`)有直接返回裸对象的历史写法;**新增代码一律用 `Result`**,存量代码按需渐进改造。
+4. 金额/比率用 `BigDecimal`(已配 `BigDecimalSerializer` / `BigDecimalDeserializer`),禁用 double。
+5. 鉴权取当前用户:`StpUtil.getLoginIdAsLong()`。**会话、消息、模型配置等用户级资源必须带 userId 做归属校验**,不能只按 id 查。
+6. 跨库访问用 `@DS("slave")`(参考 `SqlAnalysisTool` 依赖的 `SqlQueryMapper`);不标注则走 master。
+7. 注释用中文,Javadoc 写清「做什么 + 为什么」,不写废话。
+8. 新增枚举尽量实现 `HasInnerEnum`,与存量保持一致。
+
+---
+
+## 5. 数据层要点
+
+| 数据源 | 用途 |
+|---|---|
+| **master**(PostgreSQL + pgvector) | 平台元数据、`table_info`/`table_field`、Agent 会话/消息、模型与 Provider 配置、RAG 索引状态、向量检索 |
+| **slave**(DuckDB) | **按工作空间切换**的案情库;Agent 的 `execute_sql` 只在这里跑 |
+| Redis | 会话/缓存、Sa-Token、mem0 |
+| Neo4j | 图谱(配置在 `application-dev.yaml`) |
+
+- 表/字段元数据三表链路:`meta_raw_sheet` → `table_info` → `table_field`
+- 建表脚本放 `sql/`,新增表结构务必同步补脚本 **和** 元数据三表
+- `mapUnderscoreToCamelCase` 已开启
+
+### ⚠️ 环境配置
+`application-dev.yaml` 内含**本机数据库密码 / 内网 IP**,属于开发便利配置。
+- 不要把真实凭证提交到公开仓库
+- 不要在生产 profile 复用 dev 配置
+
+---
+
+## 6. Agent 子系统(`module/agent`)★ 核心
+
+### 架构
+AgentScope `HarnessAgent` + `Toolkit` + 中间件:
+
+```
+controller/   AgentChatController(REST + SSE)、AgentModelController
+service/      AgentChatService、AgentModelService、AgentModelProviderService
+tools/        SqlAnalysisTool、RagSchemaSearchTool、PythonAnalysisTool、
+              GraphRenderTool、WorkspaceInfoTool
+intent/       意图识别(IntentService / IntentMiddleware / IntentEnum)
+followup/     追问生成(FollowupService / FollowupMiddleware)
+rag/          RagSchemaService、EmbeddingModelFactory、RagProperties
+python/       PythonExecutor(沙箱执行)
+sql/          SqlResultStore(结果集缓存,供前端分页)
+prompt/       PromptLoader、PromptHelper
+scaffold/     WorkspaceScaffolder(工作空间初始化)
+mapper/       Agent*Mapper、SqlQueryMapper、RagVectorMapper
+entity/       AgentChatSession、AgentMessage、AgentModel、AgentModelProvider、RagIndexStatus
+```
+
+### 工具清单(`@Tool` 注解)
+| 工具 | 说明 |
+|---|---|
+| `execute_sql` | 在当前工作空间 DuckDB 上执行**只读** SQL,返回 resultId + 列定义 + 当前页 + 总行数 |
+| `list_tables` | 列出工作空间全部表(中英文名、字段类型与中文注释) |
+| `search_table_schema` | 基于 pgvector 的表结构语义检索 |
+| `render_chart` | 渲染 ECharts 图表(**禁止**用于关系图) |
+| `render_graph` | 渲染力导向关系图谱 —— 关系图**只能**走这里 |
+| `python_analysis` | Python 脚本分析 |
+| `workspace_info` | 工作空间信息 |
+
+### 硬约束(不要放宽)
+- 结果集上限 **100,000 行**,超出要求模型加 `LIMIT` / `WHERE`
+- `page_size` 默认 50,上限 500
+- 单元格字符串截断 **500** 字符
+- 只读白名单首词:`select / with / pragma / describe / show / explain`,**禁止多语句(含分号)**
+- `render_chart` 会硬拦截 `series.type == "graph"`,强制改走 `render_graph`
+
+### SSE 流式协议
+`POST /chat/stream`,事件按序:`tool_call` → `tool_input` → `tool_result` → `token`(多次) → `done` / `error`
+
+payload 结构:
+```ts
+{ type, data?, toolCallId?, toolName?, toolInput?, toolResult?, error?, sessionKey? }
+```
+前端消费方:`ai-frontend/src/cms/api/chat.ts`。**改动协议必须前后端同步**。
+
+### 提示词
+- 运行时系统提示词:`ai-server/src/main/resources/prompts/AGENTS.md`
+- 未经明确要求,**不要重写人格设定与输出格式**(【异常概览】/【资金链路分析】/【通联行为画像】/【时空碰撞结果】/【研判结论与建议】),那是产品行为的一部分。
+
+---
+
+## 7. 数据清洗 / 治理(`module/dm`)
+
+```
+dm/
+├─ pre/     PreTask、PreDataListener、DateNumberConverter、Str2NullConverter
+├─ clean/
+│  ├─ DataCleaner(接口)、CleanResult、CleanCache、DirtyDataHandler、StrategyType
+│  ├─ impl/cleaner/   各数据源清洗器(Call*/Trans*/Track*/External*/...)
+│  ├─ impl/loader/    数据装载器
+│  └─ func/           可复用清洗函数:FunAbs/FunRadix/FunReplace/FunTime/FunMultiplier/...
+└─ mapper/  CleanErrorLogMapper、DmMapper、PersonRelEdgeMapper、EdgeConfMapper
+```
+
+- 新增一种数据源导入 = 新增一对 `Loader` + `Cleaner`(命名对齐 `XxxDataLoader` / `XxxDataCleaner`)
+- 清洗错误必须落 `CleanErrorLog`,不要静默吞掉
+- 可复用变换优先写成 `func/Fun*` 而不是在 Cleaner 里硬编码
+
+---
+
+## 8. 前端约定
+
+目录按业务域划分,与后端 `<domain>` 基本对齐:
+
+```
+ai-frontend/src/
+├─ core/     脚手架通用层:components/、layouts/、api/、hooks/、store/、router
+├─ cms/      AI 对话(views/chat、components/Chat*、api/chat.ts)
+├─ case/     案件:数据导入/清洗/治理/人物画像/线索推送
+├─ call/     话单分析(night、continuous、sensitive...)
+├─ trans/    资金分析
+├─ track/    轨迹分析
+├─ person/   人员
+├─ plat/     平台/模板
+├─ dm/       清洗类型定义
+└─ graph/    图谱(G6 编辑器、力导向布局 worker、资金流向图)
+```
+
+每个业务域内:`api/`(请求 + `types/dto.ts`、`types/query.ts`)、`views/`、`components/`、`hooks/`、`types/`。
+
+### 规则
+1. **优先复用 `src/core/components/*`**(BasicTable / BasicForm / BasicModal / Description / AnalysisPagination 等),不要新造轮子。
+2. 组件用 `<script setup lang="ts">`,`defineProps` / `defineEmits` 显式类型化。
+3. 新增接口先写 `src/<domain>/api/types/{dto,query}.ts` 的 TS 类型,**与后端 DTO 字段保持一致**(改后端字段时同步改这里)。
+4. 样式:UnoCSS 原子类 + Less(组件内 `<style lang="less" scoped>`)。
+5. 只能用 pnpm。
+
+---
+
+## 9. 常用命令
+
+### 后端
+```bash
+# 编译
+mvn -pl ai-server -am clean compile
+# 打包(跳过测试)
+mvn -pl ai-server -am clean package -DskipTests
+# 运行
+mvn -pl ai-server spring-boot:run
+# 只跑 ai-server 的测试
+mvn -pl ai-server test
+```
+启动后:`http://localhost:8980`
+
+### 前端
+```bash
+cd ai-frontend
+pnpm install          # = pnpm bootstrap
+pnpm dev              # 开发服务器
+pnpm type:check       # vue-tsc --noEmit
+pnpm lint:eslint
+pnpm lint:prettier
+pnpm lint:stylelint
+pnpm lint:all         # 全量(含 install)
+pnpm build            # 生产构建
+pnpm preview:dist     # 预览 :3100
+```
+
+### 依赖服务
+PostgreSQL(**需装 pgvector 扩展**)、Redis、Neo4j(按需)。
+
+---
+
+## 10. 硬性规则:Do / Don't
+
+### ✅ Do
+- 新业务按 `module/<domain>/{controller,service,mapper}` + `common/model/<domain>/{dto,entity,query,vo}` 落位
+- 改 SQL 同步改 `resources/mappers/**/*.xml`
+- 改后端 DTO 字段 → 同步前端 `src/<domain>/api/types/*.ts`
+- 改表结构 → 补 `sql/` 脚本 + `table_info` / `table_field` 元数据
+- 新增 Agent 工具 → 写清 `@Tool(description=...)` 与 `@ToolParam`,返回结构化 JSON + 中文说明
+- 大查询一律带 `LIMIT` / `WHERE`,分页返回
+- 提交前跑通后端 compile 与前端 `type:check`
+
+### ❌ Don't
+- 不要动 `ai-server/src/main/resources/app.yml`(Solon 遗留,已失效)
+- 不要把密钥 / 真实库密码 / 内网地址硬编码进提交
+- 不要在 Java 里拼接 SQL 字符串(用 MyBatis XML 或 `LambdaQueryWrapper`)
+- 不要放宽 `execute_sql` 的只读白名单、行数上限、单元格截断
+- 不要让 `render_chart` 渲染关系图
+- 不要绕过 Sa-Token 的用户归属校验
+- 不要在仓库里存放原始敏感案情数据
+- 未经要求不要改写 `prompts/AGENTS.md` / `QingJian/agent/AGENTS.md` 的人格与输出格式
+- 不要用 npm / yarn 装前端依赖
+
+---
+
+## 11. 已知待清理项(改到就顺手修)
+
+1. `common/config/Result.java` 顶部有 `import io.milvus.param.R;` —— **未被使用且 pom 中无 milvus 依赖**,属遗留脏引用,建议直接删除。
+2. `Result` 的 `SUCCEED_CODE` / `FAILURE_CODE` 是**非 final 的 public static 字段**,可被外部篡改,建议改 `final` 或换成常量/枚举。
+3. `common/config/WebConfig.java` 与 `application.yaml` 的 `context-path: "!/js/a/"` 写法源自 Solon 语法,在 Spring Boot 下语义可疑,改动前先确认前端 `/js` 前缀的实际解析链路。
+4. `ai-server` 未声明 `@MapperScan`,确认 mapper 是靠 `@Mapper` 注解还是 XML 绑定注册;新增 Mapper 时跟随现有写法。
+5. `pom.xml` 中 `testcontainers` 等依赖已声明但未见到对应测试,可评估是否裁剪。
+
+---
+
+## 12. 提交前检查清单
+
+- [ ] 后端 `mvn -pl ai-server -am clean compile` 通过
+- [ ] 前端 `pnpm type:check` + `pnpm lint:eslint` 无错
+- [ ] 接口字段变更 → 后端 DTO/VO 与前端 TS 类型同步
+- [ ] 表结构变更 → `sql/` 补脚本 + 元数据三表同步
+- [ ] 新增/修改 Agent 工具 → `description` 更新,必要时同步提示词
+- [ ] 用户级资源接口 → 带 `StpUtil.getLoginIdAsLong()` 归属校验
+- [ ] 无密钥 / 密码 / 敏感数据入库
+- [ ] 中文注释齐全,无调试 `System.out.println` 残留

+ 0 - 53
ai-server/src/main/resources/app.yml

@@ -1,53 +0,0 @@
-server:
-  port: 8980
-  contextPath: "!/js/a/"
-  request:
-    fileSizeThreshold: 1024mb
-
-solon.app:
-  name: 'QingJian'
-  group: 'VectorExplore'
-
-solon.logging:
-  appender:
-    console:
-      level: debug
-      pattern: "%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %magenta(${PID:-}) --- %-15([%15.15thread]) %-56(%cyan(%-40.40logger{39}%L)) : %msg%n"
-    file:
-      name: "${log.path:}"
-      maxFileSize: "20 MB"
-      maxHistory: "3"
-      level: debug
-      pattern: "%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level ${PID:-} --- %-15([%15.15thread]) %-56(%-40.40logger{39}%L) : %msg%n"
-
-qingjian:
-  version: "3"
-  db1:
-    class: "org.noear.solon.data.dynamicds.DynamicDataSource"
-    strict: false
-    default: case #指定默认的内部数据源 NCC 默认NCC的sqlserver
-    plat:
-      type: "org.apache.ibatis.datasource.unpooled.UnpooledDataSource"
-      driver: org.sqlite.JDBC
-    case:
-      type: "com.qingjian.common.config.DuckdbUnpooledDataSource"
-      driver: org.duckdb.DuckDBDriver
-      memoryLimitInMiB: 4096
-      threads: 8
-
-#默认
-mybatis.db1:
-  typeAliases:
-    - "com.qingjian.common.model.*.entity.*"
-  mappers:
-    - "classpath:mappers/*/*.xml"
-  configuration:
-    cacheEnabled: false
-    mapperVerifyEnabled: false
-    mapUnderscoreToCamelCase: true
-    # 开启枚举类型自动转换(关键)
-    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
-    #org.apache.ibatis.logging.nologging.NoLoggingImpl
-    #logImpl: org.apache.ibatis.logging.stdout.StdOutImpl
-  globalConfig:
-    banner: false