Files
group_xinghuo_jinrong/README.md
T

161 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# JinRong · 金融四 Agent 智能管家
四个 Agent(客户财富 / 代理人助手 / 数据分析 / **风控监测**)共用统一数据层与合规底座;Agent 之间**不互调 LLM**,跨 Agent 协作走 L1/L2/L3 画像与预警表。
> **本分支(`risk-control-agent`)= 风控 Agent 模块的交付分支**。模块功能已全部交付(2026-09-07),合并 main 的事宜见《合并注意事项》一文,后续人员请按下表对号入座。
## 你是哪种后续人员?
| 角色 | 先读 |
| --- | --- |
| 接手模块开发 / 维护 | [交接文档.md](交接文档.md)(本地)→ [docs/memory/MEMORY.md](docs/memory/MEMORY.md) §0 → [docs/memory/TODO.md](docs/memory/TODO.md) |
| 负责把模块并入 main | [docs/项目框架设计/合并注意事项-风控模块并入main.md](docs/项目框架设计/合并注意事项-风控模块并入main.md)(自包含操作手册) |
| 了解需求 / 做方案评审 | [docs/PRD/PRD-风控监测Agent.md](docs/PRD/PRD-风控监测Agent.md)(v1.1)+ [附-风控规则表.md](docs/PRD/附-风控规则表.md) |
| 起环境跑演示 | [docs/项目框架设计/演示SOP-风控模块.md](docs/项目框架设计/演示SOP-风控模块.md) + 本页「快速启动」 |
## 模块交付状态(截至 2026-09-08)
**后端功能全部完成,全量 pytest 503 passed 0 failed(sqlite + 真 MySQL 集成),核心接口实调验收通过。**
| 里程碑 tag | 内容 |
| --- | --- |
| Wave 0 / T-04 / T-03 / T-21 | JWT 鉴权 · 审计中间件 · chat 闭环 · LangGraph+DeepSeek · Core 只读 Tool · 输入防护 · Milvus 知识库 |
| `risk-m1` | 适当性校验(已换核为 C×R 矩阵契约:match_result 五值 + JR-AST/FM 规则编号) |
| `risk-m2` | 事件线全链路(RISK-001~005 规则引擎 / 预警聚合 / L3 / AML / 交易网关 / 4 个 API) |
| `risk-m3` | 对话线闭环(风控四只读 Tool + StateGraph risk 分支) |
| 阶段一 | 对齐 main 基准 AL-01~08(SUIT-001~008 退役 → core_ro.check_suitability 矩阵判定) |
| `risk-m4` | 追加需求:FR-8 集中度预警 RISK-006 / FR-9 处置时效升级 RISK-007 / FR-10 代理人行为链 RISK-008 |
**前端接入面(2026-09-08 补齐,后端侧已齐)**:方案 B 会话管理三端点(`8328c24`)+ 方案 C SSE 流式对话(`01ec5fc`)。同步端点 `POST /api/chat` 契约不变,前端可任选同步/流式。详见下文「前端接入契约」。
**架构定位**:风控 Agent 为**独立封装模块**——模块内自带鉴权(`app/api/deps.py` + `app/service/auth_service.py`)、防护、trace、引擎工厂;与宿主的耦合只走 4 个接缝(挂载点 / AuthContext / settings / 引擎工厂),由 `tests/test_module_boundary.py` 防呆锁定。详见《[风控Agent模块边界与合并接缝标注.md](docs/项目框架设计/风控Agent模块边界与合并接缝标注.md)》。
## 铁律(改码前必记)
- Core 正式 C1~C5 不可被画像覆盖;Core 库只读(仅模拟交易网关可 INSERT core_trade)
- 审计表(audit_log 等)只 INSERT
- 代理人草稿不自动外发客户;风控不自动冻户
- 仅适当性 R-02 可阻断交易
- 四 Agent 不互调 LLM
- 不改表结构(改表需用户确认);新增依赖须用户确认
## 后端结构
```text
app/
├── api/ # 路由:chat、risk(4 API)、simulate、deps(JWT 鉴权工厂)、audit_middleware
├── service/ # agent_service(LangGraph StateGraph)、risk/*(rules/engine/alert/aml/L3/C4~C6)、
│ # suitability、tool_service、auth_service、input_guard、RAG 三层
├── tool/ # core_tools(Core 只读 Tool)、kb_tools(知识库检索 Tool)
├── gateway/ # trade_gateway 模拟交易网关(唯一可写 core_trade)
├── model/ # schemas、suitability(21 列契约)、entities(29 表 ORM 参考)
├── repository/ # core_ro(Core 只读,含 check_suitability 矩阵)、risk_repository、session_repository
├── config/ # settings(双库 + risk_* 阈值 + JWT)
└── utils/ # trace、authz、response(统一错误体)、db、exceptions
scripts/ # core 灌库、demo 演示数据、kb 知识库入库、cron 定时扫描、dev 签发 token
tests/ # 30+ 模块;_ddl.py 为 sqlite DDL 单一事实源;test_module_boundary.py 锁模块边界
data/kb/ # 6 只种子产品手册(知识库语料)
```
## 环境要求
- **Python 3.13**(项目依赖与 pytest 装在系统 Python 3.13.14)
- MySQL 8.0(双库:`jinrong_core` 模拟 Core 只读 / `jinrong_agent` 业务库)、Redis 8
- Neo4j Desktop(全图同步)、Ollama(bge-m3,1024 维,仅做 embedding)
- Windows 原生部署,不使用本地 Docker(见技术选型文档)
## 快速启动
```bash
cp .env.example .env # 填 MYSQL_PASSWORD / NEO4J_PASSWORD / DEEPSEEK_API_KEY
pip install -r requirements.txt
# 首次灌库与同步:见 docs/memory/FLOW.md §0(权威步骤)
uvicorn app.main:app --reload # → GET http://127.0.0.1:8000/health
python -m pytest # 基线 503 用例(系统 Python)
```
**演示库重灌(走查/集成测试前必做,两步缺一不可)**:
`scripts/core/reset.ps1`(交互式输密码)→ `scripts/demo/prepare_risk_demo.sql`。
⚠️ 只跑第一步不跑第二步 → 33 客户中 27 人风评过期、约 82% 适当性检查返回 risk_expired,这是种子设计不是 bug。
**调接口(JWT 通道)**:
```bash
# 签发 token(dev)
python scripts/dev/issue_dev_token.py --sub STAFF-90001 --roles risk_officer
# 调用须同时带两个头
curl -X POST http://127.0.0.1:8000/api/risk/suitability/check \
-H "Authorization: Bearer <token>" -H "X-Agent-Type: risk" \
-H "Content-Type: application/json" \
-d '{"customer_id":"CUST-1001","product_id":"PROD-005827"}'
```
dev 环境无 Bearer 时可用 `X-Debug-Role` / `X-Debug-Actor` 头兜底(仅 development + 未配 RS256 公钥时生效)。
## 核心接口一览
| 接口 | 说明 | 权限 |
| --- | --- | --- |
| `GET /api/risk/alerts` | 预警台账分页(FR-4) | risk_officer / risk_manager(只读)/ compliance(仅 aml) |
| `POST /api/risk/alerts/{id}/handle` | 人工处置(状态机 + 审计) | risk_officer |
| `POST /api/risk/suitability/check` | 适当性校验(C×R 矩阵,G-01 归属) | customer 本人 / advisor 名下 / risk_officer |
| `POST /api/risk/aml/scan` | 手动全量 AML 扫描(FR-5) | risk_officer |
| `POST /api/simulate/trade` | 模拟交易(适当性阻断 + 规则引擎) | risk_demo 或客户本人 |
| `POST /api/chat` | 对话(X-Agent-Type 分流四 Agent;风控线四只读 Tool) | 按准入矩阵 |
| `GET /api/chat/sessions` | 会话列表(本人 + 本 Agent 线,分页) | 按准入矩阵 |
| `GET /api/chat/sessions/{id}/messages` | 会话历史消息(seq_no 升序分页) | 仅本人会话 |
| `POST /api/chat/sessions/{id}/close` | 关闭会话(active→closed) | 仅本人会话 |
| `POST /api/chat/stream` | **SSE 流式对话**(OpenAI 兼容 chunk) | 按准入矩阵 |
> 对话线(含上述全部 `/api/chat*`)**仅 risk_officer**:`risk_manager` 放行 HTTP 台账只读(`GET /api/risk/alerts`),进对话线一律 403(PRD 4A.1 冻结口径)。
## 前端接入契约
**1)会话管理(方案 B)**
```bash
curl "http://127.0.0.1:8000/api/chat/sessions?limit=20&offset=0" \
-H "Authorization: Bearer <token>" -H "X-Agent-Type: risk"
# → {"items":[{session_id,agent_type,customer_id,title,status,created_at,...}],"total":2,"limit":20,"offset":0}
curl "http://127.0.0.1:8000/api/chat/sessions/<sid>/messages?limit=50&offset=0" ...
# → {"session_id":"...","items":[{seq_no,role,content,has_disclaimer,created_at}],"total":4,...}
```
**2)流式对话(方案 C,OpenAI 兼容 chunk)**
```
首帧 data: {"id":"<trace_id>","object":"chat.completion.chunk",
"choices":[{"delta":{"role":"assistant"},"finish_reason":null}],
"meta":{"session_id":"sess-…","trace_id":"…","has_disclaimer":true,
"disclaimer":"以上内容由 AI 生成,仅供业务参考,不构成投资建议。"}}
中间 data: {…,"choices":[{"delta":{"content":"文本块"}}]}
结束 data: {…,"choices":[{"delta":{},"finish_reason":"stop"}],"meta":{"has_disclaimer":true}}
data: [DONE]
异常 data: {"error":{"code":"STREAM_FAILED|PERSIST_FAILED","message":"…"}} → data: [DONE]
```
前端须知:
- **免责声明由首帧 `meta.disclaimer` 下发,前端需常驻渲染**(customer/risk 线合规要求);落库文本仍按原口径拼在尾部
- `401/403/404/409/429/400` 在流开始前返回**普通 JSON**,只有正常流才是 `text/event-stream`
- 断连/生成异常 = 整轮消息不落库(Tool 留痕仍可审计),前端需提示重试
- 心跳帧未做:长生成空隙靠反代 `proxy_read_timeout` 兜(已知遗留)
## 文档地图
| 目录 / 文件 | 内容 |
| --- | --- |
| [docs/memory/](docs/memory/) | 项目记忆六件套(MEMORY/TODO/REQUIREMENTS/FRAMEWORK/FLOW/ENVIRONMENT),入口为 MEMORY.md §0 |
| [docs/PRD/](docs/PRD/) | 风控 PRD v1.1(§4A = 追加需求)+ 风控规则表 |
| [docs/项目框架设计/](docs/项目框架设计/) | 架构设计 · 开发计划 · 实现方案 C4~C6 · 表设计(SQL 单一事实源)· 技术选型与 JWT 手册 · Core 模拟底座 · 演示 SOP · 边界标注 · **合并注意事项** |
| [docs/需求拆解/](docs/需求拆解/) | 业务场景优先级、数据交互矩阵、合规约束、四角色用户故事(docx) |
| [docs/业务记忆管理/](docs/业务记忆管理/) | 业务记忆分层手册 |
| [交接文档.md](交接文档.md) | 模块开发交接(本地保留,不入库) |
## 前端
React 19 + Vite 7 + TypeScript strict + Ant Design 5 + HashRouter——`web/` 目录尚未 init,为下一主线。
后端接入面已就绪,前端只需三件事:① `POST /api/chat/stream` 接 SSE(首帧拿 `session_id`/`disclaimer`,逐帧拼 `delta.content`,收到 `[DONE]` 收尾);② 进页面先 `GET /api/chat/sessions` 拉会话列表、选中后 `GET .../messages` 拉历史;③ 结束会话调 `POST .../close`。所有请求带 `Authorization: Bearer` + `X-Agent-Type`。