本轮只改文档(12 份,无代码改动),把 `W27` 的代码实绩(`L0` 表层判定层 + 出口 `E6` 行情)在**全部交付面文档**上对齐。 此前工程侧已入库(3e24033),但答辩面文档仍留「五出口 / 六出口」旧口径,是最容易被评委当场戳到的自相矛盾点。 ## 一、口径统一:五出口 → 七出口 + `L0` - `D3.6`(被多处引为「五出口权威定义」):加**口径更新横幅**(列明 `W20` 六出口、`W27` 七出口 + `L0` 的演进线, 并写明「不变的」——转人工仍只是 `E5c`、白名单仍 4 类、`INV-1`~`INV-5` 一条没改);§3 标题加「起步定义」; **新增 §3.0**说明 §3.1—§3.4 的适用范围;本页 `D3.7` 配套行的金标计数 46→55、10→11 项指标。 - `D1.1`:7 处索引/清单行对齐(`D2.6` / `D2.10` / `D3.6` 的描述与计数),其余「五出口」全部保留为**历史记录**。 - `D2.6`:配套行补 `D3.9` 指向;**新增 `W27` 状态更新段**(金标扩容到 55 条 + 第七个出口 + 三处真缺陷修复), 并显式声明「上一条 `W24` 的『六个出口』口径已由本条扩为七个」。 - `D3.7`:性质行/读法/§0 计数对齐(46 → 55、十项 → 十一项指标);**§4 增补 `W27` 扩容后的分母口径表** (`M-1`/`M-4`/`M-5`/`M-6`/`M-10` = 55、`M-2` = 33、`M-2b` = 20、`M-3` 明示「考检索的 C 组」,门槛不变)。 - `D2.9`:引用表新增 `D3.9` 行;判分输入件由 `cases_46.json` 更新为 **`cases_55.json`**(附两个分母的产物名)。 - `D2.8`:`W27` 判定补充行(前批已入库,本轮核对通过)。 ## 二、HTML 规格文档:只声明口径,不重写历史 `D3.1`(需求开发文档)/ `D3.2`(知识库方案)/ `D2.2`(需求收敛版)/ `D2.4`(知识库收敛版) 四处 `§0.1` 之前各加一段 `callout-warn` 口径更新:说明「五出口」是 v1.x/v2.x 时点的**起步定义**、 现行是「七出口 + `L0`」,并明确**语义与安全结论全部有效、只是不再是全集**,指向 `D3.9` 与 `D2.6` §3。 (`_build` 已标注「已过期·请勿重新生成」,故直接在成品上改,不重跑生成器。) ## 三、`D2.10`(端到端答辩文档) `六出口` → **七出口 + `L0`**(徽标 / meta / Mermaid / S8 表 / 时间分配 / 文档关系表,共 5 处); §3.8 出口表**新增 `E6` 行情行**,正文补 `L0` 段落;§4.1 阈值表后**新增口径更新块** (区间重叠 ⇒ 单点阈值不存在;阈值降为安全下限;「跨集合回退 0.65」在代码中不存在); §6.1 标题与「两个分母都报」的实测块对齐 55 条;§11 补 `D3.9` 与 `W27` 证据文件。 ## 四、`D2.5` 演示脚本(答辩当天照着念的那份) **新增 §4.8「行情走势与闲聊」**——针对上轮被点名的两类,全部用 **2026-09-21 真 HTTP 实跑**的答复: - `159382这只ETF最近走势怎么样?` → `E6`,给出近 5/20/60/120 个净值日涨跌 + 区间高低 + 数据区间; - `南方稳健增利债券A最近走势怎么样?` → `E6-miss`,如实说「查不到公开的净值序列」,**拒绝编造**; - `你好呀` / `谢谢你` / `在吗` → 闲聊,**零检索**; - **反向守卫**「在吗,想问下南方稳健增利债券A的起投金额是多少?」→ 必须走知识作答(证明 `L0` 判的是整句); - 附「口径细节」:`E6` **不调模型**(固定模板 + 纯函数,数字全部来自 `fin_nav_history`), 闲聊**调模型但完全不查库**(新跑 `_w27_probe_guard.py` 单独验证反向守卫,另有 `_w27_probe_trend/chat.txt`)。 §6 表补两行(闲聊不再进检索 / 走势是算出来的),金标计数行改为 55 条并附两个分母的指标表。 ## 五、验证 - `_sync_check.py`:权威目录 → 仓库镜像 **0 缺失 / 0 不一致**(13 份同步)。 - `git diff --name-only`:12 份变更**全部是 `.md` / `.html`**,**无任何代码改动** ⇒ 不影响已绿的 `pytest 2094 passed / 3 skipped`(3e24033 已复跑)。 - 本轮实测证据保留在 `D:\桌面\金融\_w27_probe_guard.py` / `.txt`(答辩后勿删)。
南方基金智能业务平台
本项目是一个基于 FastAPI 和 MVC+S 架构的金融业务 Agent 平台,当前包含以下三项核心业务:
- 场外基金申购/赎回运营流程
- 产品推介材料与宣传海报生成
- 金融自然语言转 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
二、项目结构
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。建议使用独立虚拟环境:
conda create -n jr_py313 python=3.13
conda activate jr_py313
pip install -r requirements.txt
复制配置文件:
Copy-Item .env.example .env
然后根据本机环境修改 .env,至少配置:
MYSQL_DSN
JWT_PRIVATE_KEY_PATH
JWT_PUBLIC_KEY_PATH
.env、JWT 私钥、模型密钥和真实外部服务凭据禁止提交到 Git。
四、启动服务
4.1 数据库迁移
请确保 MySQL 已启动,并且 .env 中的数据库连接可用:
alembic upgrade head
python tools/audit_schema.py
4.2 启动 HTTP 服务
python -m uvicorn app.main:app --host 127.0.0.1 --port 8099
服务地址:
http://127.0.0.1:8099
OpenAPI 文档:
http://127.0.0.1:8099/docs
4.3 启动 Worker
需要异步处理 Agent 运行或场外邮件时,另开终端:
python -m app.worker
Worker 是否启用场外收信,取决于:
OFFSITE_MAIL_WORKER_ENABLED
OFFSITE_IMAP_ENABLED
OFFSITE_WORKER_USER_ID
五、功能一:场外基金申购/赎回
5.1 功能说明
场外流程面向运营人员,主要处理:
邮件接收
→ 附件保存
→ OCR/文档识别
→ 结构化字段提取
→ 申购/赎回规则计算
→ NL2SQL 查询资金和持仓数据
→ 运营人员确认
→ 创建通知
→ 发送或 dry-run
→ 审计和统计
支持的单据类型:
subscription:申购redemption:赎回summary:汇总材料other:其他材料
系统保留原始邮件、附件、识别结果、查询记录、规则结果、人工修正记录和审计记录。 人工修正不会覆盖 Agent 原始识别值。
5.2 主要接口
基础路径:
/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 核对的接口为:
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 功能说明
该模块用于新产品的结构化资料整理和宣传材料生成。当前生成链路为:
创建任务
→ 填写产品、经理、团队、策略、费用、业绩和风险资料
→ 上传经理照片、业绩数据、来源证据或模板
→ 合规检查
→ 生成 PPTX、宣传海报和可选 PDF
→ 审核
→ 发送给指定投顾
支持的输入附件:
manager_photo:基金经理照片performance_data:CSV/XLSX 业绩数据source_evidence:来源证据template_file:材料模板
支持的输出格式:
pptxposterpdf,需要配置 LibreOffice/soffice等转换器
模块会执行风险披露、费用结构、业绩数据、输入完整性和生成文本合规检查。 合规阻断时返回具体 findings 和补齐建议,不继续生成材料。
6.2 主要接口
基础路径:
/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 |
发送给投顾 |
创建任务和写入操作必须提供请求头:
Idempotency-Key: <唯一请求键>
6.3 权限与状态
主要权限:
promotion:writepromotion:readpromotion:reviewpromotion:deliver
材料任务状态包括:
draft
→ input_ready
→ generating
→ generated
→ pending_review
→ approved
→ sent
异常状态包括:
compliance_failed
rejected
failed
生成的文件默认保存到:
data/promotion_materials/
七、功能三:金融 NL2SQL
7.1 功能说明
NL2SQL 将自然语言问题转换为经过权限、业务域、表白名单和只读校验的 SQL。 业务 Agent 不直接连接数据库,而是通过公共只读工具调用:
业务 Agent
→ BaseAgent.call_tool
→ ToolExecutor
→ query_financial_data
→ 只读金融数据表
工具名称:
query_financial_data
权限码:
financial:nl2sql:read
7.2 支持范围
当前纳入查询范围的主要表:
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 调用示例
result = await self.call_tool(
"query_financial_data",
{
"question": "查询基金代码 000001 最近 30 天的净值",
"dry_run": False,
"limit": 50,
},
intent="financial_query",
context=context,
)
模糊问题会返回:
{
"status": "need_confirmation",
"message": "请确认查询范围、指标口径和时间条件。"
}
工具结果包含查询计划、SQL、参数、权限检查和执行摘要,并进入统一审计和运行持久化链路。
八、测试数据集
测试数据位于:
data/
当前数据集概况:
| 类型 | 数量 | 用途 |
|---|---|---|
.eml |
13 | 场外邮件及附件识别 |
.csv / .xlsx |
8 | 推介材料业绩数据 |
.png / .jpg |
35 | 经理照片、宣传图和测试图片 |
.pptx |
10 | 推介材料结构检查 |
.pdf |
9 | PDF 文件有效性检查 |
测试数据只用于本地测试和演示,不应直接作为生产业务数据导入。
九、测试与代码检查
9.1 运行完整测试
普通单元和契约测试:
python -m pytest tests/unit tests/contract -q -p no:cacheprovider
使用独立 MySQL 测试库并执行测试数据隔离:
python -m tools.run_tests_on_test_db tests -p no:cacheprovider
9.2 运行三项功能定向测试
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 代码质量检查
python -m ruff check app tests tools alembic
python -m mypy app
git diff --check
9.4 测试基线
最近一次项目回归记录:
关键三项功能定向测试:85 passed
全量自动化测试:559 passed, 1 skipped
Redis、真实 IMAP/OCR/DeepSeek/SMTP、Neo4j、Milvus 和浏览器 E2E 是否能执行, 取决于本机服务和凭据配置。外部服务关闭或不可用时,测试使用本地数据集、Mock 或 dry-run。
十、配置开关
场外邮件和外部识别:
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
产品推介材料:
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:三项功能数据集测试报告