|
|
@@ -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` 残留
|