487 lines
12 KiB
Markdown
487 lines
12 KiB
Markdown
# 南方基金智能业务平台
|
||||
|
|
|
|||
|
|
本项目是一个基于 FastAPI 和 MVC+S 架构的金融业务 Agent 平台,当前包含以下三项核心业务:
|
|||
|
|
|
|||
|
|
1. 场外基金申购/赎回运营流程
|
|||
|
|
2. 产品推介材料与宣传海报生成
|
|||
|
|
3. 金融自然语言转 SQL(NL2SQL)查询
|
|||
|
|
|
|||
|
|
项目中的场外基金运营、产品推介材料与场内基金模拟交易相互隔离。场外业务使用独立的
|
|||
|
|
`offsite_fund_*` 数据表和接口,不写入场内交易表。
|
|||
|
|
|
|||
|
|
## 一、技术栈
|
|||
|
|
|
|||
|
|
- Python `3.13`
|
|||
|
|
- FastAPI、Uvicorn
|
|||
|
|
- SQLAlchemy 2.x、Alembic
|
|||
|
|
- MySQL、Redis
|
|||
|
|
- Pydantic v2
|
|||
|
|
- JWT + RBAC
|
|||
|
|
- `python-pptx`、OpenPyXL、Pillow、Matplotlib
|
|||
|
|
- 可选:阿里云 DocMind/OCR、DeepSeek、SMTP、Milvus、Neo4j
|
|||
|
|
|
|||
|
|
## 二、项目结构
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
group_fqcd_jr/
|
|||
|
|
├── app/
|
|||
|
|
│ ├── api/controllers/ # HTTP 路由和请求参数校验
|
|||
|
|
│ ├── api/schemas/ # 请求/响应模型
|
|||
|
|
│ ├── core/ # 业务契约、配置和公共规则
|
|||
|
|
│ ├── model/ # SQLAlchemy 数据模型
|
|||
|
|
│ ├── service/ # 业务编排、规则和数据访问
|
|||
|
|
│ ├── infrastructure/ # 数据库、缓存和外部基础设施适配
|
|||
|
|
│ └── worker/ # 异步 Worker
|
|||
|
|
├── data/ # 测试与演示数据集
|
|||
|
|
├── docs/ # 架构、接口、数据库和业务说明
|
|||
|
|
├── tests/ # 单元、契约、集成和环境测试
|
|||
|
|
├── tools/ # 迁移、种子、检查和测试工具
|
|||
|
|
├── alembic/ # 数据库迁移
|
|||
|
|
├── hq.py # 南方基金行情数据适配模块
|
|||
|
|
├── nl2sql_yc.py # 金融 NL2SQL 兼容入口和查询逻辑
|
|||
|
|
├── .env.example # 环境变量模板
|
|||
|
|
└── README.md
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 三、环境准备
|
|||
|
|
|
|||
|
|
项目要求 Python `>=3.13,<3.14`。建议使用独立虚拟环境:
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
conda create -n jr_py313 python=3.13
|
|||
|
|
conda activate jr_py313
|
|||
|
|
pip install -r requirements.txt
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
复制配置文件:
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
Copy-Item .env.example .env
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
然后根据本机环境修改 `.env`,至少配置:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
MYSQL_DSN
|
|||
|
|
JWT_PRIVATE_KEY_PATH
|
|||
|
|
JWT_PUBLIC_KEY_PATH
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`.env`、JWT 私钥、模型密钥和真实外部服务凭据禁止提交到 Git。
|
|||
|
|
|
|||
|
|
## 四、启动服务
|
|||
|
|
|
|||
|
|
### 4.1 数据库迁移
|
|||
|
|
|
|||
|
|
请确保 MySQL 已启动,并且 `.env` 中的数据库连接可用:
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
alembic upgrade head
|
|||
|
|
python tools/audit_schema.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 启动 HTTP 服务
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
python -m uvicorn app.main:app --host 127.0.0.1 --port 8099
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
服务地址:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
http://127.0.0.1:8099
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
OpenAPI 文档:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
http://127.0.0.1:8099/docs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 启动 Worker
|
|||
|
|
|
|||
|
|
需要异步处理 Agent 运行或场外邮件时,另开终端:
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
python -m app.worker
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Worker 是否启用场外收信,取决于:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
OFFSITE_MAIL_WORKER_ENABLED
|
|||
|
|
OFFSITE_IMAP_ENABLED
|
|||
|
|
OFFSITE_WORKER_USER_ID
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 五、功能一:场外基金申购/赎回
|
|||
|
|
|
|||
|
|
### 5.1 功能说明
|
|||
|
|
|
|||
|
|
场外流程面向运营人员,主要处理:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
邮件接收
|
|||
|
|
→ 附件保存
|
|||
|
|
→ OCR/文档识别
|
|||
|
|
→ 结构化字段提取
|
|||
|
|
→ 申购/赎回规则计算
|
|||
|
|
→ NL2SQL 查询资金和持仓数据
|
|||
|
|
→ 运营人员确认
|
|||
|
|
→ 创建通知
|
|||
|
|
→ 发送或 dry-run
|
|||
|
|
→ 审计和统计
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
支持的单据类型:
|
|||
|
|
|
|||
|
|
- `subscription`:申购
|
|||
|
|
- `redemption`:赎回
|
|||
|
|
- `summary`:汇总材料
|
|||
|
|
- `other`:其他材料
|
|||
|
|
|
|||
|
|
系统保留原始邮件、附件、识别结果、查询记录、规则结果、人工修正记录和审计记录。
|
|||
|
|
人工修正不会覆盖 Agent 原始识别值。
|
|||
|
|
|
|||
|
|
### 5.2 主要接口
|
|||
|
|
|
|||
|
|
基础路径:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/api/v1/offsite-fund
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 方法 | 路径 | 用途 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `GET` | `/mails` | 分页查询场外邮件 |
|
|||
|
|
| `GET` | `/mails/{mail_id}` | 查看邮件详情 |
|
|||
|
|
| `POST` | `/mails/{mail_id}/deletions` | 软删除邮件 |
|
|||
|
|
| `GET` | `/mails/{mail_id}/recognition-fields` | 查看 OCR 识别字段 |
|
|||
|
|
| `PUT` | `/mails/{mail_id}/recognition-fields` | 保存 OCR 字段人工修正 |
|
|||
|
|
| `GET` | `/documents/{task_id}/nl2sql-fields` | 查看 NL2SQL 返回字段 |
|
|||
|
|
| `PUT` | `/documents/{task_id}/nl2sql-fields` | 保存 NL2SQL 字段人工修正 |
|
|||
|
|
| `GET` | `/documents/{task_id}/rule-results` | 查看规则判定结果 |
|
|||
|
|
| `POST` | `/documents/{task_id}/rule-results/recalculations` | 使用已有结果重新判定 |
|
|||
|
|
| `GET` | `/mailbox-status` | 查看收件游标状态 |
|
|||
|
|
| `POST` | `/mailbox-status/recoveries` | 恢复被阻塞的收件游标 |
|
|||
|
|
| `GET` | `/attachments/{attachment_id}/file` | 预览或下载原始附件 |
|
|||
|
|
| `POST` | `/documents/{task_id}/confirmations` | 运营人员确认单据 |
|
|||
|
|
| `POST` | `/documents/{task_id}/recognition-retries` | 重试识别异常单据 |
|
|||
|
|
| `POST` | `/documents/{task_id}/notifications` | 创建运营通知 |
|
|||
|
|
| `POST` | `/notifications/{notification_id}/send` | 发送通知 |
|
|||
|
|
| `POST` | `/settlement-statistics/recalculate` | 重算结算统计 |
|
|||
|
|
|
|||
|
|
触发场外单据 NL2SQL 核对的接口为:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
POST /api/tasks/{task_id}/trigger-agent-nl2sql
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.3 权限与安全
|
|||
|
|
|
|||
|
|
- 读取权限:`offsite:read`
|
|||
|
|
- 写入权限:`offsite:write`
|
|||
|
|
- 确认权限:`offsite:confirm`
|
|||
|
|
- NL2SQL 权限:`offsite:nl2sql`
|
|||
|
|
- 通知权限:`offsite:notify`
|
|||
|
|
- 请求中的 `operator_id` 必须与 JWT 身份一致
|
|||
|
|
- 所有写操作都进行权限校验、操作人校验、审计和状态流转校验
|
|||
|
|
- 通知发送支持幂等,SMTP 默认关闭并使用 dry-run
|
|||
|
|
|
|||
|
|
## 六、功能二:产品推介材料与宣传海报生成
|
|||
|
|
|
|||
|
|
### 6.1 功能说明
|
|||
|
|
|
|||
|
|
该模块用于新产品的结构化资料整理和宣传材料生成。当前生成链路为:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
创建任务
|
|||
|
|
→ 填写产品、经理、团队、策略、费用、业绩和风险资料
|
|||
|
|
→ 上传经理照片、业绩数据、来源证据或模板
|
|||
|
|
→ 合规检查
|
|||
|
|
→ 生成 PPTX、宣传海报和可选 PDF
|
|||
|
|
→ 审核
|
|||
|
|
→ 发送给指定投顾
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
支持的输入附件:
|
|||
|
|
|
|||
|
|
- `manager_photo`:基金经理照片
|
|||
|
|
- `performance_data`:CSV/XLSX 业绩数据
|
|||
|
|
- `source_evidence`:来源证据
|
|||
|
|
- `template_file`:材料模板
|
|||
|
|
|
|||
|
|
支持的输出格式:
|
|||
|
|
|
|||
|
|
- `pptx`
|
|||
|
|
- `poster`
|
|||
|
|
- `pdf`,需要配置 LibreOffice/`soffice` 等转换器
|
|||
|
|
|
|||
|
|
模块会执行风险披露、费用结构、业绩数据、输入完整性和生成文本合规检查。
|
|||
|
|
合规阻断时返回具体 findings 和补齐建议,不继续生成材料。
|
|||
|
|
|
|||
|
|
### 6.2 主要接口
|
|||
|
|
|
|||
|
|
基础路径:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/api/v1/fund-promotion-materials
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 方法 | 路径 | 用途 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `POST` | `/` | 创建推介材料任务 |
|
|||
|
|
| `PUT` | `/{task_no}/inputs` | 保存结构化输入资料 |
|
|||
|
|
| `POST` | `/{task_no}/attachments` | 上传照片、业绩文件或证据 |
|
|||
|
|
| `POST` | `/{task_no}/generations` | 生成推介材料 |
|
|||
|
|
| `GET` | `/{task_no}/compliance-checks` | 查看合规检查结果 |
|
|||
|
|
| `GET` | `/{task_no}` | 查询任务和已审核材料 |
|
|||
|
|
| `POST` | `/{task_no}/reviews` | 审核、驳回或要求修改 |
|
|||
|
|
| `POST` | `/{task_no}/deliveries` | 发送给投顾 |
|
|||
|
|
|
|||
|
|
创建任务和写入操作必须提供请求头:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Idempotency-Key: <唯一请求键>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.3 权限与状态
|
|||
|
|
|
|||
|
|
主要权限:
|
|||
|
|
|
|||
|
|
- `promotion:write`
|
|||
|
|
- `promotion:read`
|
|||
|
|
- `promotion:review`
|
|||
|
|
- `promotion:deliver`
|
|||
|
|
|
|||
|
|
材料任务状态包括:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
draft
|
|||
|
|
→ input_ready
|
|||
|
|
→ generating
|
|||
|
|
→ generated
|
|||
|
|
→ pending_review
|
|||
|
|
→ approved
|
|||
|
|
→ sent
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
异常状态包括:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
compliance_failed
|
|||
|
|
rejected
|
|||
|
|
failed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
生成的文件默认保存到:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
data/promotion_materials/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 七、功能三:金融 NL2SQL
|
|||
|
|
|
|||
|
|
### 7.1 功能说明
|
|||
|
|
|
|||
|
|
NL2SQL 将自然语言问题转换为经过权限、业务域、表白名单和只读校验的 SQL。
|
|||
|
|
业务 Agent 不直接连接数据库,而是通过公共只读工具调用:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
业务 Agent
|
|||
|
|
→ BaseAgent.call_tool
|
|||
|
|
→ ToolExecutor
|
|||
|
|
→ query_financial_data
|
|||
|
|
→ 只读金融数据表
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
工具名称:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
query_financial_data
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
权限码:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
financial:nl2sql:read
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 支持范围
|
|||
|
|
|
|||
|
|
当前纳入查询范围的主要表:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
sys_customer_assignment
|
|||
|
|
fin_customer_profile
|
|||
|
|
fin_risk_assessment
|
|||
|
|
fin_product
|
|||
|
|
fin_fee_rule
|
|||
|
|
fin_market_price
|
|||
|
|
fin_nav_history
|
|||
|
|
fin_holding
|
|||
|
|
fin_transaction
|
|||
|
|
fin_sim_order
|
|||
|
|
fin_sim_account
|
|||
|
|
fin_cash_ledger
|
|||
|
|
client_facing_content
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
支持:
|
|||
|
|
|
|||
|
|
- 基金净值、行情和历史收益查询
|
|||
|
|
- 费率和费用查询
|
|||
|
|
- 客户风险测评和画像查询
|
|||
|
|
- 持仓、交易、订单、账户和资金流水查询
|
|||
|
|
- 历史范围查询
|
|||
|
|
- 最多跨三个业务域查询
|
|||
|
|
- 结果行数限制,默认 50,最大 200
|
|||
|
|
- SQL dry-run
|
|||
|
|
|
|||
|
|
不支持或会被拒绝:
|
|||
|
|
|
|||
|
|
- 非白名单表
|
|||
|
|
- 非 `SELECT` 查询
|
|||
|
|
- 未通过客户数据范围校验的查询
|
|||
|
|
- 当前快照表的历史时点查询
|
|||
|
|
- 模糊且未确认查询范围、指标口径或时间条件的问题
|
|||
|
|
|
|||
|
|
### 7.3 调用示例
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
result = await self.call_tool(
|
|||
|
|
"query_financial_data",
|
|||
|
|
{
|
|||
|
|
"question": "查询基金代码 000001 最近 30 天的净值",
|
|||
|
|
"dry_run": False,
|
|||
|
|
"limit": 50,
|
|||
|
|
},
|
|||
|
|
intent="financial_query",
|
|||
|
|
context=context,
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
模糊问题会返回:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"status": "need_confirmation",
|
|||
|
|
"message": "请确认查询范围、指标口径和时间条件。"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
工具结果包含查询计划、SQL、参数、权限检查和执行摘要,并进入统一审计和运行持久化链路。
|
|||
|
|
|
|||
|
|
## 八、测试数据集
|
|||
|
|
|
|||
|
|
测试数据位于:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
data/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
当前数据集概况:
|
|||
|
|
|
|||
|
|
| 类型 | 数量 | 用途 |
|
|||
|
|
|---|---:|---|
|
|||
|
|
| `.eml` | 13 | 场外邮件及附件识别 |
|
|||
|
|
| `.csv` / `.xlsx` | 8 | 推介材料业绩数据 |
|
|||
|
|
| `.png` / `.jpg` | 35 | 经理照片、宣传图和测试图片 |
|
|||
|
|
| `.pptx` | 10 | 推介材料结构检查 |
|
|||
|
|
| `.pdf` | 9 | PDF 文件有效性检查 |
|
|||
|
|
|
|||
|
|
测试数据只用于本地测试和演示,不应直接作为生产业务数据导入。
|
|||
|
|
|
|||
|
|
## 九、测试与代码检查
|
|||
|
|
|
|||
|
|
### 9.1 运行完整测试
|
|||
|
|
|
|||
|
|
普通单元和契约测试:
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
python -m pytest tests/unit tests/contract -q -p no:cacheprovider
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
使用独立 MySQL 测试库并执行测试数据隔离:
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
python -m tools.run_tests_on_test_db tests -p no:cacheprovider
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9.2 运行三项功能定向测试
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
python -m pytest `
|
|||
|
|
tests/integration/test_offsite_fund_api.py `
|
|||
|
|
tests/integration/test_offsite_nl2sql_fields.py `
|
|||
|
|
tests/integration/test_offsite_notification_send.py `
|
|||
|
|
tests/integration/test_promotion_material_api.py `
|
|||
|
|
tests/unit/service/test_suitability_service.py `
|
|||
|
|
tests/contract/test_financial_nl2sql_tool_contract.py `
|
|||
|
|
-q -p no:cacheprovider
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9.3 代码质量检查
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
python -m ruff check app tests tools alembic
|
|||
|
|
python -m mypy app
|
|||
|
|
git diff --check
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9.4 测试基线
|
|||
|
|
|
|||
|
|
最近一次项目回归记录:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
关键三项功能定向测试:85 passed
|
|||
|
|
全量自动化测试:559 passed, 1 skipped
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Redis、真实 IMAP/OCR/DeepSeek/SMTP、Neo4j、Milvus 和浏览器 E2E 是否能执行,
|
|||
|
|
取决于本机服务和凭据配置。外部服务关闭或不可用时,测试使用本地数据集、Mock 或 dry-run。
|
|||
|
|
|
|||
|
|
## 十、配置开关
|
|||
|
|
|
|||
|
|
场外邮件和外部识别:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
OFFSITE_IMAP_ENABLED=false
|
|||
|
|
OFFSITE_MAIL_WORKER_ENABLED=false
|
|||
|
|
OFFSITE_OCR_ENABLED=false
|
|||
|
|
OFFSITE_DEEPSEEK_ENABLED=false
|
|||
|
|
OFFSITE_SMTP_ENABLED=false
|
|||
|
|
OFFSITE_SMTP_DRY_RUN=true
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
产品推介材料:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
PROMOTION_MATERIAL_STORAGE_DIR=data/promotion_materials
|
|||
|
|
PROMOTION_PDF_ENABLED=false
|
|||
|
|
PROMOTION_PDF_CONVERTER_PATH=
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
启用真实服务前,请先完成网络、凭据、权限、数据脱敏和回滚方案确认。
|
|||
|
|
|
|||
|
|
## 十一、安全与开发约束
|
|||
|
|
|
|||
|
|
- 所有业务请求都应经过统一 JWT、RBAC、客户范围和审计链路。
|
|||
|
|
- 不在业务 Agent 中自行读取密钥、直接连接数据库或绕过 `ToolExecutor`。
|
|||
|
|
- 场外业务不能写入场内交易表。
|
|||
|
|
- 数据库结构只能通过 Alembic 迁移修改。
|
|||
|
|
- 不删除、重命名或复用已有表和字段;历史结构不足时新增字段、新表或兼容读写。
|
|||
|
|
- 所有写接口应设计幂等键、状态机和重复提交保护。
|
|||
|
|
- 真实外部服务默认关闭,测试优先使用本地数据、Mock 和 dry-run。
|
|||
|
|
|
|||
|
|
## 十二、相关文档
|
|||
|
|
|
|||
|
|
- `docs/MVC/MVC架构.md`:项目架构和目录职责
|
|||
|
|
- `docs/00-新数据库基线设计.md`:数据库业务基线
|
|||
|
|
- `docs/05-接口文档.md`:接口权威说明
|
|||
|
|
- `docs/14-Agent组员统一接入说明书.md`:Agent 接入规范
|
|||
|
|
- `docs/15-金融NL2SQL工具接入说明.md`:NL2SQL 工具规范
|
|||
|
|
- `product_promotion_to_do_list.md`:推介材料模块开发记录
|
|||
|
|
- `测试报告/2026-09-12.md`:三项功能数据集测试报告
|
|||
|
|
|