## 问题 `today_profit_loss` / `today_profit_loss_ratio` 在 `app/service/trade_service.py` 里是 **硬编码 `ZERO`**(持仓列表 L678、账户看板 L748-749),客户看板、持仓页、盈亏分析页的 「今日盈亏」永远显示 0.00。同一函数里的「持有盈亏」是**真算的** (`market_value - cost_amount`,L660 / L726),所以只有这一项是占位。 三份 2026-09-14 文档其实**都记录了这个事实**(接口文档第 11 条、SRS 第 212 / 458 / 615 行), 但**都埋在「注意事项」里,没有进第 0 章那份「★ 请先回答本章」的待确认清单** —— 业务翻文档时看不到,演示现场被问到就答不上来。而且 SRS 第 212 行还把它**错引到了 Q7** (Q7 讲的是场外阈值,与此无关)。 ## 改动 **docs/软件需求文档-2026-09-14.md** - 新增 **0.5 节「占位实现与本期边界」**,登记 **Q22**:客户看板的「今日盈亏」本期是否实现。 该节专门收这类「接口有、值还没真算」的偏差(不报错、单元测试全绿、只有业务看得出不对), 以后同类问题继续往这里追加。 - 第 0 章项数 21 -> 22;阻塞项清单补上 Q22。 - 修正 F-4.2 的错误引用(见 Q7 延伸 -> 见 Q22)。 - R2 状态改为「已提级为待决项 -> 见 Q22」。 - **R1 状态改为已修复**:组员提交 `4b7ee13`「修复管理员工作台函数缺少闭合大括号」 已解决 `workspace.js` 的语法错误。按该条自己要求的方式复验过 —— `node --experimental-vm-modules` + `vm.SourceTextModule` 遍历 `app/static/portal`, **44 个模块全部通过**(`node --check` 会假通过,不能用来判定)。 **docs/44-演示流程.md**(演示现场用) - §3「可能被问到的问题」新增话术:直说这是占位值、指出持有盈亏是真算的、 指向 SRS Q22 与两条口径的结论;并建议「时间紧就避开这一栏,被问到不要含糊也不要现编」。 - 场景 2(客户资产)加现场提示:讲「持有盈亏 / 总市值 / 可用资金」,不要指着「今日盈亏」讲。 **docs/后端接口文档-2026-09-14.md** - 第 11 条补上代码行号与交叉引用,并点明同一响应里的 `profit_loss` 是**真算的**。 ## 顺带交给业务:两条口径的可行性(实测,非推测) 业务要决定的是「要不要做」,但「能不能做」也得一起给,否则业务选完还要再问一轮: | 口径 | 数据现状 | 结论 | |---|---|---| | 用行情算(今收 − 昨收) | `fin_market_price` **只在同步时才写行**,实测每个产品**只有 2 行**(515450 只有 09-11 与 09-14,还跨了周末) | ❌ 取不到连续「昨收」 | | 用净值算(今净值 − 上一交易日净值) | `fin_nav_history` 每个产品 **120~160 行连续交易日净值** | ✅ 建议按这个口径 | ⇒ 文档建议按**净值口径**实现,并提醒业务一并确认语义:净值是日终数据, 该指标实际是「最近一个交易日的盈亏」,**不是盘中实时**。 ## 入库说明 三份 `docs/*-2026-09-14.md` 此前是**未跟踪文件**,本次一并入库(同一批文档交付物且互相引用)。 `.workbuddy/`(工具会话记忆)属工作区过程产物,**未入库**。
53 KiB
软件需求文档(SRS)——金融 Agent 平台
文档版本:v1.0(2026-09-14) 文档状态:待确认稿——第 0 章列出 22 项必须由业务方补充确认的问题,确认后本文件升为 v1.1 适用范围:场内基金模拟交易 + 客服问答 + 风控 + 投顾 + 场外基金运营 + 推介材料(六大业务域) 依据材料(均为仓库内既有文档,非本文件臆造):
docs/00数据库基线、docs/03端到端流程、docs/05接口文档、docs/22四大 Agent 拆解、docs/10业务域接入评估、docs/43场内产品手册、docs/44演示流程、docs/验收与审计/phase1-*、docs/28场外表登记、docs/31投顾灰度、docs/场外申购赎回工作流程图.md、以及app/service/*实际实现代码。
0. 需要业务方补充确认的问题(★ 请先回答本章)
本文件是在不臆造业务的前提下,依据仓库既有设计文档与已落地代码反推整理的。以下 22 项在现有材料中确实没有权威答案或存在口径冲突,其中标 [阻塞] 的会直接影响功能需求与验收标准的写法;标 [影响] 的只影响细节精度,可先按建议默认值推进。
0.1 范围与优先级(最高优先回答)
| # | 问题 | 现状 / 冲突点 | 影响 |
|---|---|---|---|
| Q1 | 一期交付范围是否就是"六大业务域全部"? 还是要分两批(如客服+场内交易先上,场外+推介后上)? | docs/22 §7 建议的建设顺序是 客服 → 投顾 → 风控 → 场外;但代码里六个域都已落地,docs/44 演示流程 8 个场景横跨全部域。文档需要一个明确的"本期交付边界"。 |
[阻塞] |
| Q2 | 本期是"演示验收"还是"生产上线"? 两者的非功能需求(可用性、备份、等保、并发量)量级差一个数量级。 | 现状:数据库口令、JWT 密钥走本地配置;docs/26 有密钥轮换设计;无出金/入金通道(docs/00 §5 明示"无充值提现与银行流水匹配通道")。 |
[阻塞] |
| Q3 | 是否仍严格限定"仅场内基金模拟交易"? 场外运营是否仅做"辅助核对+留痕",不产生真实资金动作? | AGENTS.md 规则 8 明确:场外运营独立,不得写入场内交易表;app/service/offsite_fund_service.py 确实只读到 OffsiteFundDocument 等 offsite_* 表。请确认这条边界在需求层面不可松动。 |
[阻塞] |
0.2 业务规则口径(现有文档明确写了"未定义",需业务填空)
| # | 问题 | 现状 / 冲突点 | 影响 |
|---|---|---|---|
| Q4 | 客服 RAG 的混合检索决策公式与分数分段阈值(向量分/关键词分如何加权、多少分以上直答、多少分以下转人工、中间区间怎么办)? | docs/22 §2.3 明确列为该设计自身未定义项;代码侧只落了 snippet/knowledge_id 与 TopK(FAQ 3 / 产品 5 / 政策 5),未见阈值常量。 |
[阻塞](直接影响"低置信不硬答"的验收判定) |
| Q5 | 低置信转人工的触发阈值与话术,以及"多轮澄清后仍无法解决"的兜底路径? | docs/03 只说"低置信不得硬答、转人工需带完整上下文";phase1 教师标准认可 [无法确认] 标记 + 真实热线 15936583816。阈值本身未给。 |
[阻塞] |
| Q6 | 风控规则引擎的规则清单从哪来? 是业务方给一份规则表(规则名/口径/阈值/等级),还是要我们从 docs/21、docs/25 反推? |
docs/22 §2.3 明确列为未定义;代码 app/service/risk_scan_service.py 已有扫描实现但规则阈值需与业务对齐。 |
[阻塞] |
| Q7 | 场上/场下若干"业务阈值"请业务给数:申购单笔份额上限比例(现为总份额 10%)、单一投资者持有比例上限(现为 20%)、赎回巨额比例(现为 20%)、申购最低金额(现为 >1 元)是否为最终口径? | 来自 app/service/offsite_fund_rules.py 实际常量 TEN_PERCENT=0.10、TWENTY_PERCENT=0.20、ONE_YUAN=1。这些是代码现状,不排除是占位值。 |
[影响] |
| Q8 | 场外"巨额赎回"是否要联动风控通知?清算是按单只基金聚合还是全市场聚合? | docs/场外申购赎回工作流程图.md 边界明确:AML 与开放期规则不在本次实现范围;风险通知/邮件回复/清算通知三条路径相互独立、无自动联动。请确认这是有意为之还是待补。 |
[影响] |
| Q9 | 合规检查放在生成前还是生成后?(docs/22 §6 列为待定决策) |
现状:推介材料代码里两者都有(_generate_tx 有"输入资料未通过合规校验"与"生成内容未通过合规校验"两个 422);客服侧未见显式前置校验。 |
[阻塞] |
| Q10 | 是否允许 Agent 给出"投资建议"? 边界是什么? | 现状代码是保守的:asset_allocation_service.py 常量 analysis_only: True 且 disclaimer = "分析结果仅供参考,不生成交易指令。";docs/43 明确客服不得承诺收益、不得修改风险测评。 |
[影响] |
| Q11 | 投顾灰度白名单的最终开放范围(现为 ADVISOR_ROLLOUT_CUSTOMER_IDS,空名单 = 全体客户 fail-closed)? |
docs/31 有开关与回滚手册;具体放量节奏需业务定。 |
[影响] |
0.3 缺失的输入材料(需要业务方提供文件)
| # | 问题 | 影响 |
|---|---|---|
| Q12 | 原始需求文档 HTML(设计提到 C:\Users\Windows\Desktop\金融\需求文档-修改版.html,本工作区不可达)能否提供? |
[阻塞]——本文件是从代码+设计反推的,若有原始需求,可对齐措辞与遗漏项。 |
| Q13 | 场外申购/赎回单的真实样例件(至少各 1 份 PDF/扫描件)。 | docs/22 明确"场外是唯一需要新表的模块,且缺样例单据"。没有样例,OCR 字段与规则无法验收。[阻塞] |
| Q14 | 投顾 21 张表的登记文档是否已有?(docs/28 只登记了场外 10 张 + 推广 7 张,投顾 21 张"登记文档待补") |
[影响]——影响投顾模块的数据字典完整性。 |
| Q15 | 部署环境是否具备 LibreOffice / soffice? | product_promotion_to_do_list.md 记录:推介材料 PPTX 已能真实生成,但 PDF 转换依赖部署环境的 LibreOffice,本机未验证。[阻塞](影响"PPT 导出"这项验收) |
| Q16 | 生产数据库/中间件规格(MySQL 8.0 版本、Redis、Milvus 版本与部署形态、Neo4j 是否必装)? | 现状:app/core/knowledge_schema.py 显示Milvus 集合 schema 因环境而异(本机 knowledge_id/snippet,架构师环境 doc_id/content/visibility/chapter),检索层做了运行时探测。生产环境以哪套为准需定。[影响] |
| Q17 | 模型与供应商清单(对话模型、Embedding 模型及其向量维度、是否允许外网调用、是否需私有化)? | docs/22 §6 明确:模型选择决定 Milvus schema,是待定决策。现状配置含 deepseek-flash 等。[阻塞] |
0.4 流程与角色
| # | 问题 | 影响 |
|---|---|---|
| Q18 | 客服工单与风控工单是否要真正打通?(docs/22 §2.3 列"跨 Agent 联动规则未定义") |
docs/03 验收要求"客服工单与风控工单不得混用",跨域升级路径未定。[影响] |
| Q19 | 是否需要"客户主动发起风险评估"入口,还是测评只由运营/客服在后台维护? | docs/43 说客服不能改风险测评;那客户自己能否改?未写明。[影响] |
| Q20 | 人工兜底的值守时段与 SLA(客服转人工后多久响应?风控告警多久必须处置?)? | docs/03 有状态机但无时间承诺;风控有 overdue 概念但阈值来源未明。[影响] |
| Q21 | 免责声明 / 适当性提示的标准文案由谁出?(合规部?) | 现状:代码里有 disclaimer 常量与 disclosures 结构,但正式文案需合规确认。[影响] |
0.5 占位实现与本期边界(★ 接口有、值还没真算)
本节专门登记一类偏差:接口存在、字段有返回、但值是占位常量。它不报错、单元测试全绿, 也不会被现有任何自动化检查发现 —— 只有业务对着真实口径才看得出不对, 因此是演示现场最容易被追问的地方。以后发现同类问题请继续往本节追加。
| # | 问题 | 现状 / 冲突点 | 影响 |
|---|---|---|---|
| Q22 | 客户看板的「今日盈亏」本期是否实现? | app/service/trade_service.py 里 today_profit_loss 是硬编码 ZERO:持仓列表 L678、账户看板 L748;today_profit_loss_ratio 同理(L749)。对比:同一函数里的「持有盈亏」是真算的(market_value - cost_amount,L660 / L726),所以只有「今日盈亏」恒为 0。客户看板、持仓页(T006)、盈亏分析页的该字段永远显示 0.00。 |
[阻塞] —— 演示必被问。若本期不做,需明确对外口径:要么前端不展示该列/卡片,要么显示 —,不要显示 0(0 会被当成真实值) |
若决定实现:口径与数据可行性(2026-09-14 实测核实)
| 候选口径 | 数据现状 | 可行性 |
|---|---|---|
(今日收盘价 − 昨收) × 数量,基准取 fin_market_price |
不可行:该表只在行情同步时写行,实测每个产品仅 2 行(如 515450 只有 2026-09-11 与 2026-09-14),取不到连续的「昨收」,且这两行还跨了周末 |
❌ |
(今日净值 − 上一交易日净值) × 数量,基准取 fin_nav_history |
可行:该表每个产品有 120~160 行连续交易日净值(由 tools/sync_nav_history.py 同步,按 (product_id, nav_date) 幂等 upsert) |
✅ |
⇒ 建议按净值口径实现。同时请业务确认语义:净值是日终数据,该指标实际含义是 「最近一个交易日相对前一交易日的盈亏」,不是盘中实时;当天净值同步之前它会与「昨日」一致。 这一点要在界面文案上讲清楚,否则又会被当成 bug。
建议回答方式:不必逐条写长文,可直接在本章表格后追加"Q1:……"式的短答,或在对话中直接回复序号+结论。标
[阻塞]的 12 项(Q1/Q2/Q3/Q4/Q5/Q6/Q9/Q12/Q13/Q15/Q17/Q22)建议优先给出,其余可先按本文给出的默认口径执行,后续修订。
1. 项目背景与目标
1.1 项目背景
本项目是一个面向基金业务的通用 Agent 平台,采用"厚平台、薄 Agent"的设计哲学:
- 厚平台:统一承担会话、幂等、长短期记忆、关系推理(Neo4j)、配置快照与发布、多模型路由、工具执行、合规校验、审计留痕、可靠事件投递(Outbox)等横切能力;
- 薄 Agent:业务 Agent 只负责"检索、分析、生成、归纳、分诊",不得自行实现鉴权、记忆、模型调用、审计等能力,必须继承公共
BaseAgent并由AgentFactory创建。
平台当前覆盖六大业务域:
| 域 | 业务Agent / 服务 | 数据表归属 |
|---|---|---|
| 客服问答 | CustomerServiceAgent |
场内基线的客服相关表 |
| 场内基金模拟交易 | 交易服务(非 Agent,确定性服务) | 场内 51 张表 |
| 风控 | RiskAgent + 规则引擎 |
场内基线的风控相关表 |
| 投顾 | AdvisorAgent |
advisor_* 21 张表 |
| 场外基金运营 | OffsiteFundAgent |
offsite_* 10 张表 |
| 基金推介材料 | PromotionMaterialAgent |
promotion_* 7 张表 |
1.2 项目目标
目标一:建一个"不绕过统一执行骨架"的 Agent 平台。 所有业务 Agent 走同一套七步执行流程(输入校验 → 记忆召回 → 意图识别 → 核心业务 → 生成与合规 → 数据落库 → 事件广播),保证鉴权、合规、审计、事件四条链路不可能被旁路。
目标二:让四类高风险业务在"人在环中"(Human-in-the-loop)下可用。
- 场内交易:模拟撮合,所有成交、资金、持仓均为平台内部虚拟数据,不涉及真实资金;
- 风控:规则引擎做确定性扫描,模型只用于生成"建议优化方向",不得替代规则判断;
- 场外运营:Agent 只做识别与核对,最终确认必须由运营人员点击;
- 投顾:只输出分析,不生成交易指令。
目标三:权威业务事实不可被记忆或模型覆盖。 记忆分层中,MySQL 中的权威事实(持仓、现金、成交、风险测评)优先级高于用户自述与 AI 推断;低版本记忆不得覆盖高版本。
目标四:满足课程/项目的阶段性验收标准。 一期 7 条验收标准(见第 6 章)已全部达成,附真机证据;本文件在此基础上把需求正式化。
1.3 业务模式
| 维度 | 说明 |
|---|---|
| 产品形态 | B2C 模拟交易 + B2B2C 运营辅助。客户端为访客/客户自助问答与模拟下单;员工端为客服工作台、风控工作台、投顾工作台、运营控制台 |
| 收入模式 | 无收入(模拟盘)。若转生产需业务补充商业模式(见 Q2) |
| 资金流 | 无真实资金流。场内为虚拟账户记账;场外只做单据核对与通知留痕,不做划款 |
| 数据流 | 行情来自外部接口(实时价 + 日K,落 fin_nav_history);其余全部为平台内部产生 |
| 合规模式 | 事前(适当性校验、白名单发布)+ 事中(模型生成后合规检查、人工确认闸门)+ 事后(全链路审计、trace_id 贯穿) |
2. 用户角色与典型使用场景
2.1 角色清单
平台共定义 8 类角色(5 个人类角色 + 3 个非人角色),每一类都带明确的禁止事项——这是本项目合规设计的核心,需求层面不可弱化。
| # | 角色 | 系统角色码 | 可以做 | 明确禁止 |
|---|---|---|---|---|
| 1 | 访客 | visitor |
浏览公开产品页、提问(受知识边界限制) | 不得访问任何客户数据;不得下单 |
| 2 | 客户 | customer |
提问、看自己资产/持仓/成交、做测评、确认方案、下单(模拟) | 不得查询他人任何数据 |
| 3 | 客服人员 | employee + 客服权限 |
受理咨询/投诉/转交工单、查知识库 | 不得做产品推荐 |
| 4 | 持证投顾 | advisor |
复核方案、解释风险、确认适当性 | 不得绕过适当性、不得承诺收益 |
| 5 | 运营人员 | operator / employee |
核实业务数据、处理异常、做最终确认 | 不得让 Agent 自动完成最终确认 |
| 6 | 风控专员 | risk_operator |
调查/排除/升级/结案告警 | 不得修改交易、资金、持仓事实 |
| 7 | 平台管理员 | admin |
配置、模型路由、知识发布、权限治理 | 不得绕过配置不可变版本机制 |
| 8 | 规则引擎(非人) | — | 确定性扫描 → 产生告警 | 不得用模型判断替代规则 |
| 9 | Agent(非人) | — | 检索/分析/生成/归纳/分诊 | 不得代客交易、不得越权查询、不得做最终业务决策 |
| 10 | 通用平台(非人) | — | 鉴权/记忆/工具/合规/审计/事件 | 不得被业务旁路 |
演示账号(来自
docs/44):cust_t/123456(客户)、risk_t/666666(风控)、admin_t/88888888(管理员)、advisor_t/abc12345(投顾)。另种子脚本tools/seed_test_rbac.py内置review_t(故意不授予角色、不设密码,用于边界测试)。
2.2 典型使用场景
| 编号 | 场景名 | 角色 | 触发 | 期望结果 |
|---|---|---|---|---|
| S-01 | 访客知识边界问答 | 访客 | 问"基金申购后多久确认" | 命中知识库给出答案;问超出范围内容时不硬答,给 [无法确认] 与热线 |
| S-02 | 客户查看资产 | 客户 | 打开"我的资产" | 返回现金余额、总市值、总资产;持仓查询不校验行情时效 |
| S-03 | 客户模拟买入 ⭐ | 客户 | 选基金、填数量(100 的整数倍) | 走完校验链→立即全额成交→生成订单+流水+持仓+资金变动 |
| S-04 | 客服多轮对话与转人工 | 客户/客服 | 连续追问或明确要求转人工 | 3 轮以上保持上下文;转人工时上下文完整带入工单 |
| S-05 | 风控告警处置 ⭐ | 风控专员 | 规则扫描产生告警 | 走 待处理 → 调查中 → 已排除/已结案;升级为独立标记 |
| S-06 | 风控日报流式查看 | 风控专员 | 打开日报 | SSE 流式产出;规则部分确定性,仅"建议优化方向"用模型 |
| S-07 | 投顾方案生成与复核 | 投顾 | 客户已填目标与画像 | 生成资产配置与产品推荐;只分析、不下单;需适当性+合同证据三重校验 |
| S-08 | 管理员配置治理 | 管理员 | 改配置/知识 | 走 draft→review→activate 不可变版本;If-Match 乐观锁防并发覆盖 |
| S-09 | 场外单据核对与回复 | 运营 | 收到申购/赎回邮件 | OCR+字段识别→NL2SQL 查数→规则核对→人工确认→按类型发通知 |
| S-10 | 推介材料生成 | 运营/市场 | 上传结构化资料 | 合规校验→生成 PPTX→复核→内部发送记录留痕 |
3. 功能需求(按模块划分 + 优先级)
优先级定义 P0 = 本期必须交付,缺失则验收不通过; P1 = 本期应交,可接受降级实现(如以人工替代自动化); P2 = 本期可不做,但需在架构上预留。
3.1 模块一:通用 Agent 平台底座(P0)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-1.1 | 提供统一七步执行骨架,业务 Agent 必须继承 BaseAgent,由 AgentFactory 创建 |
P0 | 无法绕过鉴权/记忆/模型路由/工具/合规/审计/事件 |
| F-1.2 | 统一成功信封 {"data":..., "meta":{"trace_id":...}};列表额外含 next_cursor/has_more |
P0 | 业务接口不得新增其他顶层字段 |
| F-1.3 | 统一错误信封 {"error":{code,message,retryable,field_errors}, "meta":{trace_id}} |
P0 | 36 个错误码,retryable 逐码标注(不由状态码推导) |
| F-1.4 | trace_id 全链路贯穿 |
P0 | 取值顺序:请求上下文→request.state→X-Trace-ID→空串;不得伪造 |
| F-1.5 | 幂等:Idempotency-Key,范围 = user_id + method + 规范化路径 + key |
P0 | 同键并发只产生一条消息/工单/领域事件;记录与业务写入同事务 |
| F-1.6 | 乐观并发:If-Match vs 行内容摘要,冲突→409 RESOURCE_VERSION_CONFLICT(可重试) |
P0 | 每个支持 If-Match 的资源必须同时提供返回 etag 的读接口 |
| F-1.7 | 游标分页:cursor 表示"取更旧一页";非法游标→400 INVALID_CURSOR |
P0 | 校验在权限闸门之后、数据访问之前 |
| F-1.8 | 限流 enforce_rate_limit 作为路由依赖,鉴权始终先于限流 |
P0 | 交易类(/api/v1/users/me/**)不限流 |
| F-1.9 | 三段式异步 Agent 运行:POST → 202 + status_url/events_url;轮询或 SSE 取结果 |
P0 | 需常驻 Worker,否则 agent_run 停在 queued |
| F-1.10 | SSE 契约:start/tools/replace/delta/done/error,心跳为注释行 |
P0 | 终态走重放模式;delta 按 sse_chunk_characters(默认 256)切分 |
| F-1.11 | 记忆分层:短期(Redis) → 情节(中期) → 长期(promotion) | P0 | 召回权威性:MySQL 权威事实 > 用户自述 > AI 推断 |
| F-1.12 | 配置发布:不可变版本,draft→review→activate→rollback | P0 | 一次请求内配置不得漂移;发布白名单为工具可用范围上限 |
| F-1.13 | 审计与事件:所有写操作留痕;Outbox 保证事件可靠投递 | P0 | 每条请求可凭 trace_id 追溯 |
3.2 模块二:认证与权限(P0)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-2.1 | 登录:POST /api/v1/auth/tokens |
P0 | 失败不区分原因,统一"用户名或密码不正确";用户不存在时仍走 dummy bcrypt 防时序侧信道 |
| F-2.2 | JWT 只携带 sub;角色/权限/data_scope 每请求实时解析 |
P0 | 支持即时吊销;ACCESS_TOKEN_TTL_SECONDS=1800 |
| F-2.3 | 访客令牌跳过身份解析 | P0 | 访客只能命中公开面接口 |
| F-2.4 | 新人引导闸门:客户未完成引导访问 /api/v1/**(onboarding 除外)→ 403 ONBOARDING_REQUIRED |
P0 | — |
| F-2.5 | RBAC:权限码定义源为 tools/seed_test_rbac.py 的 PERMISSIONS |
P0 | 该脚本为 DELETE 重建语义,未并入的权限码重建即消失(表现为"接口突然 403 且无报错") |
| F-2.6 | 三种 data_scope:self / own_customers / all |
P0 | 零跨客户访问(重要验收红线) |
3.3 模块三:客服 Agent 与知识库(P0)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-3.1 | 五类意图识别:faq / product_inquiry / policy_explain / chitchat / transfer_human |
P0 | 五类均需端到端可测 |
| F-3.2 | 三集合知识路由:FAQ TopK 3、产品 TopK 5、政策 TopK 5 | P0 | 检索层运行时探测字段名,不得硬编码 |
| F-3.3 | 知识只使用"已发布 + 在有效期"的版本 | P0 | 未发布版本不得被召回 |
| F-3.4 | 低置信不得硬答;转人工上下文完整 | P0 | 需 Q4/Q5 提供阈值 |
| F-3.5 | 知识管理三端点:上传 / 列表 / 删除 | P0 | 上传 201 / 列表 200 / 删除 200;客户访问上传应 403 |
| F-3.6 | 知识发布流程:上传→草稿/待审→抽取分块→法务审核→批准→向量化→发布生效 | P0 | 512/64 字符分块(非 token) |
| F-3.7 | 客服工单状态机:pending→assigned→processing→resolved→closed |
P1 | 与风控工单不得混用 |
| F-3.8 | 客户画像候选流程:候选→客户确认→管理员复核 | P1 | 候选视图不含对话原文证据 |
| F-3.9 | 一期验收:产品咨询 ≥5 题、准确率 ≥80% | P0 | 已达成(5/5) |
| F-3.10 | 一期验收:政策解释 ≥2 题 | P0 | 已达成(3/3) |
| F-3.11 | 一期验收:多轮上下文 ≥3 轮 | P0 | 已达成(3 轮) |
3.4 模块四:场内基金模拟交易(P0)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-4.1 | 20 只场内基金(13 ETF + 7 LOF)产品数据 | P0 | 风险等级 R1–R5;管理费 0.15%–1.20%/年;托管费 0.05%–0.20%/年 |
| F-4.2 | 账户看板:现金余额、总市值、总资产 | P0 | 注意:today_profit_loss / _ratio 当前为硬编码 0(占位),需业务确认是否本期实现 → 见 Q22(含数据可行性与建议口径) |
| F-4.3 | 持仓查询 | P0 | 只读持仓故意不校验行情时效 |
| F-4.4 | 下单(买入/卖出),市价全额成交 | P0 | 首版仅支持 price_type="market",limit_price 恒为 null |
| F-4.5 | 完整校验链(顺序不可调) | P0 | 见 5.5 节 |
| F-4.6 | 交易数量约束:1 手 = 100 份,最低 0.001 元价位 | P0 | quantity % lot_size == 0 |
| F-4.7 | 行情时效:MAX_QUOTE_AGE = 15 分钟 |
P0 | 超龄→所有委托 503,无自动刷新;需 python tools/sync_market_prices.py 补刷 |
| F-4.8 | 撤单 | P0 | 仅 待风控 状态可撤;其余→409 ORDER_NOT_CANCELLABLE |
| F-4.9 | 流水与资金流水查询 | P0 | 金额字段全部为字符串化 Decimal,非 JSON number |
| F-4.10 | 成交需满足幂等与事务原子性 | P0 | 订单+流水+持仓+账户同事务 |
3.5 模块五:风控(P0)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-5.1 | 规则引擎确定性扫描 → 产生告警 | P0 | 不得用模型判断替代规则 |
| F-5.2 | 告警处置:待处理 → 调查中 → 已排除/已结案 |
P0 | 五动作均需 risk:alert:write |
| F-5.3 | 升级为独立标记(非状态) | P0 | 返回 is_escalated/escalated_at/escalation_reason |
| F-5.4 | 风控日报:前 8 项确定性计算,仅"建议优化方向"可用模型 | P0 | SSE 事件 start/progress/replace/done |
| F-5.5 | 证据查询:8 类来源 customers/products/transactions/capital_flows/holdings/login_records/alerts/notifications |
P0 | 未知来源→404;须与前端 EVIDENCE_COLUMNS 对齐 |
| F-5.6 | 证据归档(multipart 上传) | P1 | 成功/失败均审计;try/finally close() |
| F-5.7 | 日报邮件发送 | P1 | 唯一曾漏鉴权的风控端点,现于 Service 层强制 risk:report:mail;默认 dry_run |
| F-5.8 | 扫描互斥:MySQL GET_LOCK('jr_risk_scan_schedule', 0) |
P0 | 锁在入口层获取,不得放在 RiskScanService.scan() 内(否则调度器自锁死) |
| F-5.9 | 风控专员不得修改交易/资金/持仓事实 | P0 | 边界红线 |
| F-5.10 | 列表 limit 上限严格:告警 max 5;证据/通知 max 10 |
P0 | 风控是唯一扩展 meta.total/meta.page_size 的域 |
3.6 模块六:投顾(P1)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-6.1 | 投资目标管理(AD001–AD007) | P1 | 目标/方案状态机失败返回 409 但复用 RUN_NOT_CANCELLABLE 字面量(已知文档缺陷,见 Q 补充说明) |
| F-6.2 | 组合分析(AD008) | P1 | status ∈ no_positions/valuation_required/ready;7 类警告码;图上下文降级不抛错 |
| F-6.3 | 资产配置(AD009) | P1 | 硬编码 C1–C5 战略比例;常量 analysis_only: True |
| F-6.4 | 产品推荐(AD010/AD011) | P1 | 三重校验:场内可交易 + 权威适当性 + 合同证据 |
| F-6.5 | 灰度放量:ADVISOR_ROLLOUT_ENABLED + ADVISOR_ROLLOUT_CUSTOMER_IDS |
P0 | 空白名单 = 全体 fail-closed;拒绝→403 AGENT_PERMISSION_DENIED + 审计 advisor.rollout_denied |
| F-6.6 | admin/super_admin 始终放行 |
P0 | — |
| F-6.7 | 不承诺收益、不绕过适当性 | P0 | 边界红线 |
3.7 模块七:场外基金运营(P1)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-7.1 | 邮件增量收取:IMAP UID 增量扫描 → MIME 解析 → 附件落盘 | P1 | 原文 EML + 附件哈希留存 |
| F-7.2 | 附件识别:OCR → 结构化字段抽取 | P1 | 申购 8 个必填字段;赎回 7 个必填字段 |
| F-7.3 | 单据字段:基金代码/名称/账户标识/申请编号/申请日期/代销机构/申购金额/金额单位/赎回份额 | P1 | 金额支持"万元"换算、币种前缀剥离 |
| F-7.4 | NL2SQL 只读查数(最新净值、最新总份额、申请前持有份额、可用份额) | P1 | 查询失败→无法判断,不得猜测 |
| F-7.5 | 确定性规则核对 | P0 | 见 5.7 节四规则 |
| F-7.6 | 运营人员最终确认(确认正常/确认异常) | P0 | 识别未完成时→422 不得确认 |
| F-7.7 | 通知四类型:risk/settlement/mail_return/normal_return/exception_return |
P1 | 校验规则严格:风控只发"确认异常"、清算只发"确认正常" |
| F-7.8 | 发送前必须完成运营确认(operator_confirmed) |
P0 | 未确认→422"邮件发送前必须完成运营确认" |
| F-7.9 | 清算统计只统计"确认正常 + 回复发送成功"的单据 | P1 | 口径见 5.7 |
| F-7.10 | 字段人工修正(OCR 字段 + NL2SQL 字段) | P1 | 修正值优先,原值落库不变;有缺失/低置信字段时默认进"编辑态" |
| F-7.11 | 附件在线预览(PDF/图片)与下载 | P2 | 仅白名单 MIME 内联;其余强制下载 + X-Content-Type-Options: nosniff |
| F-7.12 | AML 与开放期规则不在本次范围(边界明确) | — | 见 Q8 |
3.8 模块八:基金推介材料(P2)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-8.1 | 任务创建与结构化资料维护 | P2 | X001..X008 |
| F-8.2 | 附件类型与限额:经理照片(.jpg/.jpeg/.png/.webp)、业绩数据(.csv/.xlsx/.xlsm)、来源佐证(30MB, .pdf/.docx/.xlsx/.csv)、模板(50MB, .pptx) | P2 | sha256 去重→"duplicate": true |
| F-8.3 | 生成:4 种 code 结果(0 / 422 缺资料 / 422 输入未过合规 / 422 生成未过合规 / 503) |
P2 | HTTP 恒 200,业务码在 body |
| F-8.4 | 复核:要求 version.status == "pending_review" 且无阻断性合规发现 |
P2 | — |
| F-8.5 | 投递:要求 version.status == "approved" 且 delivery_channel == "internal_record" |
P2 | 首版只支持内部发送记录,未接入外部投顾端 |
| F-8.6 | PPTX 真实生成(10 段式大纲) | P2 | 已达成 |
| F-8.7 | PDF 转换 | P2 | 依赖部署环境 LibreOffice/soffice,本机未验证(见 Q15) |
3.9 模块九:前端与运维(P0)
| 编号 | 需求 | 优先级 | 验收要点 |
|---|---|---|---|
| F-9.1 | 四套页面:guest/、customer/、employee-console/、employee-risk/(+ employee-advisor) |
P0 | 挂载于 /portal/;/ 与 /portal/ 均 307 跳 /portal/guest/home/ |
| F-9.2 | 端点表集中在 common/api-client.js |
P0 | 改接口调用只改这一份 |
| F-9.3 | 健康检查:/internal/health/live、/internal/health/ready、/internal/metrics |
P0 | 无鉴权、无信封;ready 真实探测 MySQL/Redis/Milvus,超时 2s;不 ready→503 |
| F-9.4 | 一键启动:双击 启动金融Agent平台.bat |
P0 | 找解释器→检查中间件→刷新行情→起 API+Worker→等应答→开浏览器;重复双击安全 |
| F-9.5 | 演示数据一键准备:tools/seed_demo_data.py |
P0 | 10 步有依赖顺序;第 2 步非幂等(重跑会重置密码) |
| F-9.6 | 自检工具两条线互补 | P0 | e2e_smoke_test.py(业务 6 线 40 项)+ portal_api_check.py(契约 41 项) |
4. 非功能需求
4.1 性能需求
| 编号 | 指标 | 目标值 | 说明 / 现状依据 |
|---|---|---|---|
| N-1.1 | 访客一问端到端响应 | ≤ 5 秒 | 本机实测(Worker 在跑 + deepseek-flash)4.1–4.8 秒;其中受理环节仅占很小部分,主要耗时在模型生成 |
| N-1.2 | Agent 受理接口(POST /agent-runs) |
≤ 200ms(同步返回 202) | 三段式设计目的即为把长耗时甩给 Worker |
| N-1.3 | 异步运行结果可见时延 | ≤ 8 秒(P95) | 轮询/SSE 均可;需 Q20 补充 SLA |
| N-1.4 | 场内下单接口 | ≤ 500ms | 纯数据库事务 + 一次行情读取,无模型调用 |
| N-1.5 | SSE 首字节 | ≤ 1 秒 | 日报流式产出 |
| N-1.6 | 健康检查就绪判定 | ≤ 3 秒 | Milvus 探测超时 2s |
| N-1.7 | 列表接口分页 | 全部走游标/限额 | 风控告警 limit 最大 5,避免大结果集 |
| N-1.8 | 并发承载 | 需业务确认(见 Q2) | 演示级无需压测;生产级需给出目标 QPS |
| N-1.9 | 行情数据量 | ~120 个交易日日K | fin_nav_history 同步量级 |
4.2 安全需求
| 编号 | 需求 | 优先级 | 说明 |
|---|---|---|---|
| N-2.1 | 鉴权先于一切:鉴权 → 限流 → 权限 → 游标校验 → 数据访问 | P0 | 顺序错乱会产生"存在性预言机"(406 vs 404 泄露资源是否存在) |
| N-2.2 | 零跨客户访问:data_scope 三值严格生效 |
P0 | 验收红线 |
| N-2.3 | 零适当性违规:无匹配风险等级不得成交 | P0 | 校验链第 2 位 |
| N-2.4 | 零敏感信息泄露:audit:read-sensitive 脱敏为 {"redacted": true} |
P0 | — |
| N-2.5 | JWT 密钥管理与轮换 | P0 | docs/26 有设计;密钥不得进仓库 |
| N-2.6 | 登录防暴力破解:enforce_login_rate_limit |
P0 | — |
| N-2.7 | 登录不区分失败原因 + dummy hash 抗时序侧信道 | P0 | — |
| N-2.8 | 幂等防重:同键并发只产生一条副作用 | P0 | — |
| N-2.9 | 乐观锁防并发覆盖 | P0 | If-Match;冲突 409 且 retryable=true |
| N-2.10 | 附件安全:白名单 MIME/后缀;非白名单强制下载 + nosniff |
P0 | 防 XSS |
| N-2.11 | 不得绕过统一执行骨架(含合规、审计、事件) | P0 | AGENTS.md 规则 7 |
| N-2.12 | AI 输出不得作为最终业务决策 | P0 | 场外确认、风控处置、投顾下单均需人在环中 |
| N-2.13 | 工具可用范围 = 代码上限 ∩ 当前 active 发布白名单;缺配置失败关闭 | P0 | fail-closed |
| N-2.14 | 生产环境不得启用 SMTP 真实发信而未做鉴权 | P0 | 曾有风控邮件端点漏鉴权,已修(F-5.7) |
4.3 兼容性需求
| 编号 | 需求 | 说明 |
|---|---|---|
| N-3.1 | 数据库兼容:MySQL 8.0,utf8mb4,默认 schema aaa |
主键 BIGINT UNSIGNED;金额 DECIMAL(18,2),价格 DECIMAL(18,6),场内数量 DECIMAL(18,4) |
| N-3.2 | 基线不可变:docs/00 为不可变业务基线 |
只允许新增表/新增字段;禁止重命名、删除、复用已有字段,禁止改类型/可空性/业务含义 |
| N-3.3 | 前后端契约兼容:信封例外仅三处 | ① V001 裸 body;② K003 的 data 包 {items,count};③ 场外运营全域沿用旧式 {code,message,data}(成功 = code===0) |
| N-3.4 | 推介材料特例:422/503 放 body code,HTTP 保持 200 |
前端必须按 body 判断,不能只看 HTTP 状态 |
| N-3.5 | Milvus schema 环境差异:检索层运行时探测字段名 | 本机 knowledge_id/snippet;架构师环境 doc_id/content/visibility/chapter。任何地方不得硬编码字段名 |
| N-3.6 | config_release 是环境数据,不随代码合并 |
"白名单已发布"必须带环境限定;换环境需重发 |
| N-3.7 | 浏览器兼容:现代 Chromium / Edge / Safari(ESM 模块) | 注意 employee-console/workspace/workspace.js 存在语法错误(见第 6 章风险项) |
| N-3.8 | 解释器与依赖:Python ≥ 3.11(使用 datetime.UTC)+ fastapi/sqlalchemy/asyncmy/pydantic |
版本门槛必须实测 import 依赖,不能只看 --version |
| N-3.9 | 脚本编码:start.ps1 必须 UTF-8 with BOM;启动器 bat 必须 GBK + CRLF + 无 BOM |
缺 BOM 会导致 PowerShell 5.1 按 GBK 解析报语法错 |
| N-3.10 | 场外/推广/投顾 38 张表不进 docs/00 基线 |
依据 AGENTS.md 规则 8(场外独立);投顾 21 张登记文档待补(Q14) |
4.4 可靠性与可维护性
| 编号 | 需求 | 说明 |
|---|---|---|
| N-4.1 | 三段式异步 + 常驻 Worker | 无 Worker 时 agent_run 停在 queued,前端只显示"客服响应超时"——排查第一步是查 agent_run 最新行是否 queued |
| N-4.2 | 事件可靠投递(Outbox) | 幂等键并发只产生一条领域事件 |
| N-4.3 | 降级不抛错:外部依赖(Neo4j/NL2SQL)失败时降级标记而非异常 | 如 neo4j_unavailable:... |
| N-4.4 | 配置文件不可变版本 + 回滚演练记录 | docs/31 要求保留回滚演练记录 |
| N-4.5 | 观测:trace_id 可追溯 + /internal/metrics |
metrics 当前为 Prometheus 桩 jr_agent_up 1 |
| N-4.6 | Redis 丢失后,澄清轮次可从 MySQL 恢复 | 验收红线 |
5. 关键业务流程说明
5.1 通用 Agent 七步执行骨架(P0 核心)
所有业务 Agent 必须走同一骨架,任何一步都不可省略:
① 输入校验 → 结构校验(Pydantic)+ 业务前置校验;失败→422 AGENT_INPUT_INVALID
② 记忆召回 → 短期(Redis) → 情节(中期) → 长期;权威性:MySQL 事实 > 用户自述 > AI 推断
③ 意图识别 → 配置化意图分类(config_release 中的意图配置)
④ 核心业务 → 检索 / 计算 / 查询(工具执行,受白名单约束)
⑤ 生成与合规 → 模型生成 → 合规校验(不通过则不得输出)
⑥ 数据落库 → 与幂等记录同事务写入
⑦ 事件广播 → Outbox → 可靠投递
关键约束:④ 步的工具可用范围 = 代码上限 ∩ 当前 active config_release 的发布白名单,缺发布配置则失败关闭(fail-closed)。
5.2 客服五意图与知识路由(P0)
用户提问
↓
意图识别 ──┬─ faq → FAQ 集合 TopK 3
├─ product_inquiry → 产品集合 TopK 5
├─ policy_explain → 政策集合 TopK 5
├─ chitchat → 闲聊话术模板(customer_service_chitchat)
└─ transfer_human → 转人工,上下文完整带入工单
↓
置信度判定 ─┬─ 高 → 组织答案输出
└─ 低 → 【不得硬答】→ 标记 [无法确认] + 给人工热线 15936583816
↓
工单状态机:pending → assigned → processing → resolved → closed
已知口径:分块为 512/64 字符(非 token,不引入分词器依赖);低置信热线为真实号码 15936583816(非占位符)。
待确认:混合检索加权公式与分数分段(Q4)、转人工阈值(Q5)。
5.3 知识发布流程(P0)
上传文档 → 草稿/待审 → 文本抽取与分块 → 法务审核 → 批准
→ 向量化(Embedding)→ 发布生效(published + active)
约束:检索时只使用已发布且在有效期内的版本;发布是不可变版本,可回滚;一次请求内配置不得漂移。
5.4 投顾业务流程(9 步,P1)
① 客户填投资目标
② 客户完成风险测评(权威事实,Agent/客服不可修改)
③ 拉取客户画像(持仓/交易/偏好)
④ 组合分析(AD008)—— Neo4j 关系推理,失败降级
⑤ 资产配置(AD009)—— C1–C5 战略比例,analysis_only
⑥ 候选产品筛选(场内可交易 + 适当性 + 合同证据 三重校验)
⑦ 生成推荐方案(AD010/AD011)—— 含证据卡、排除清单、披露信息
⑧ 投顾复核 + 风险解释
⑨ 客户确认方案
✗ 全流程【不生成交易指令】,如需交易跳转至场内模拟交易
灰度闸门:/api/v1/advisor 除限流外,额外经 enforce_advisor_rollout;空白名单 = 全体客户 fail-closed;admin/super_admin 始终放行;拒绝→403 + 审计 advisor.rollout_denied。
5.5 场内模拟交易流程与校验链(P0 核心 ⭐)
客户提交委托
↓
【校验链——顺序不可调,任何一步失败即终止】
① 产品可交易? 否 → 422 PRODUCT_NOT_TRADABLE
② 适当性匹配? 否 → 422 SUITABILITY_MISMATCH
③ 行情未超 15 分钟? 否 → 503 FUND_QUOTE_UNAVAILABLE ← 全委托级拦截
④ 账户存在且已开户? 否 → 404 ACCOUNT_NOT_FOUND
⑤ quantity > 0?
⑥ quantity % lot_size == 0?
⑦ 买入:available_cash >= gross + fee?
否 → 422 INSUFFICIENT_FUNDS
⑧ 持仓比例上限? 超 → 422 HOLDING_RATIO_EXCEEDED
⑨ 卖出:available_quantity >= quantity?
否 → 422 INSUFFICIENT_HOLDING
↓
【成交】市价全额成交(首版仅 market)
买入 net = gross + fee
卖出 net = gross - fee
↓
【同事务写入】订单(SO…) + 成交(TX…) + 持仓 + 账户 + 资金流水(L…)
↓
【撤单】仅 status == "待风控" 可撤,其余 → 409 ORDER_NOT_CANCELLABLE
重要注意事项:
- 行情有效期仅 15 分钟(
MAX_QUOTE_AGE),超时后所有委托一律 503 且无自动刷新——这是演示最容易翻的一环。补刷命令:python tools/sync_market_prices.py(立即生效,无需重启服务)。 - 只读持仓查询故意不校验时效(
enforce_freshness=False)。 - 账户看板的
today_profit_loss/today_profit_loss_ratio当前为硬编码 0(占位实现),非真实当日盈亏——需业务确认是否本期实现。 - 所有金额字段均为字符串化 Decimal,前端不得按 number 处理。
- 客户必须状态为
已开户才能访问账户接口(employee映射为closed)。
5.6 风控流程(P0)
【扫描】定时/手动 → MySQL 互斥锁 GET_LOCK('jr_risk_scan_schedule', 0)
↓(锁在入口层获取,绝不在 RiskScanService.scan() 内——否则调度器自锁死)
规则引擎确定性扫描 → 产生告警(含等级:高/中/低)
↓ 高风险 → 创建通知(通知失败不回归已建告警,返回 notification_failure)
【处置】风控专员:待处理 → 调查中 → 已排除 / 已结案
· acknowledge 需 status == 待处理 且 ack_at is None
· investigate 需已确认且 status == 待处理
· exclude/resolve 需已确认且未结案
· escalate 独立标记(非状态),可随时升级
【日报】SSE 流式:start → progress → replace → done
前 8 类指标确定性计算;仅"建议优化方向"可用模型
【边界】风控专员不得修改交易、资金、持仓事实
列表限额:/risk/alerts max 5(默认 5);/risk/evidence/{source} 与 /risk/notifications max 10。
幂等范围:风控写操作使用**实际路径(含 alert_no)**作为 scope,绝不用模板路径。
5.7 场外基金运营流程(P1)
【收取】IMAP UID 增量扫描
→ MIME 解析 + 附件拉取 → 发件人/鉴权校验
→ 原始 EML + 附件哈希落盘(去重)
【识别】OCR(附件)→ DeepSeek 分类与字段抽取
申购必填 8 字段:基金代码/基金名称/账户标识/申请编号/申请日期/代销机构/申购金额/金额单位
赎回必填 7 字段:基金代码/基金名称/账户标识/申请编号/申请日期/代销机构/赎回份额
缺失或低置信 → 该附件默认进入【编辑态】,等人工修正
【查数】NL2SQL 只读查询(三阶段:query → calc → verify)
申购依赖:最新净值 / 基金最新总份额 / 申请前持有份额
赎回依赖:基金最新总份额 / 当前最新可用份额
查询失败 → 规则结果 = 无法判断(【不得猜测】)
【核对】确定性规则引擎(不读库、不调模型)
① 申购最低金额 标准化金额 ≤ 1 元 → 异常
② 申购后单一投资者持有比例 (申请前持有 + 本次份额) / 最新总份额 > 20% → 异常
③ 申购单笔份额上限 本次份额 > 最新总份额 × 10% → 异常
④ 赎回巨额比例 赎回份额 / 最新总份额 > 20% → 异常
⑤ 账户可用份额 赎回份额 > 可用份额 → 异常
每条规则输出:规则码/规则名/结果/单据值/库值/计算过程(实际值·规则值·比较)
【人工】运营人员确认 → 确认正常 / 确认异常
✗ 识别或核对未完成(recognition_exception / recognition_review /
recognition_retrying / query_failed)→ 422 不得确认
【通知】类型 → 接收方与前置条件
· risk → 风控接收人 ;仅允许"确认异常"
· settlement → 清算接收人 ;仅允许"确认正常"
· normal_return → 邮件返回接收人;仅允许"确认正常"
· exception_return→ 邮件返回接收人;仅允许"确认异常"
· mail_return → 邮件返回接收人;必须先完成人工确认
✗ 发送前必须 operator_confirmed = true,否则 422
【清算】统计口径:仅纳入「operator_decision == 确认正常」
且「notification_type ∈ (mail_return, normal_return) 且 status == 发送成功」的单据
按基金代码聚合
明确边界(来自流程图文档,不可自行扩张):
- 本次仅实现后端 / Agent / 数据 / 接口 / 异步 / 审计;
- AML 与开放期规则不在本次实现范围;
- 邮件回复、风控通知、清算通知三条路径相互独立,无自动联动;
- 邮件收取超时或断连时,按 IDLE 超时做 UID 补偿扫描;
- 场外流程独立,不得写入场内交易表。
5.8 记忆分层与召回权威性(P0)
短期记忆(Redis,短 TTL)
↓ 沉淀
情节记忆(中期,episodes)
↓ 提升(promotion)
长期记忆(含证据/冲突/提升/同步/删除链路)
↓
召回权威性(由高到低):MySQL 权威业务事实 > 用户自述 > AI 推断
约束:低版本记忆【不得覆盖】高版本;澄清轮次在 Redis 丢失后可从 MySQL 恢复
5.9 异常处理矩阵(摘要)
docs/03 §13 列出 15 行异常场景。核心原则:
| 异常类型 | 处理原则 |
|---|---|
| 模型超时/失败 | 降级答复,不得编造业务事实 |
| 外部依赖不可用(Neo4j/NL2SQL/Milvus) | 降级标记返回,不抛错给用户 |
| 行情过期 | 一律 503,明确提示,不静默用旧价 |
| 识别失败/低置信 | 进入人工修正态,不猜测 |
| 通知发送失败 | 记录失败原因与重试次数,不回归已产生的业务数据 |
| 并发冲突 | 409 + retryable=true,客户端可重试 |
| 幂等重复请求 | 返回首次结果,不产生重复副作用 |
6. 验收标准
6.1 一期验收标准(教师给定 7 条 —— 全部已达成)
| # | 验收标准(原文口径) | 结果 | 证据 |
|---|---|---|---|
| A1 | FastAPI 能启动,/docs Swagger 可访问 |
✅ | docs/验收与审计/phase1-acceptance-report.md 真机证据 |
| A2 | 建表成功(SHOW TABLES 返回 10 张) |
✅ | 实际库中为 52 张(超出标准) |
| A3 | FAQ 问答对导入 Milvus 且检索正确("基金申购后多久确认") | ✅ | FAQ 106 行,命中分 0.7837 |
| A4 | 客服 Agent 回答产品咨询 ≥5 题,准确率 ≥80% | ✅ | 5/5 |
| A5 | 能处理政策解释类问题 ≥2 题 | ✅ | 3/3 |
| A6 | 多轮上下文保持 ≥3 轮 | ✅ | 3 轮 |
| A7 | 知识管理接口:上传/列表/删除可用 | ✅ | 上传 201 / 列表 200 / 删除 200;客户访问上传 403 |
两项已记录的取舍(有意为之,非缺陷):
- 分块按 512/64 字符,非 token(避免引入分词器依赖);
- 低置信兜底热线为真实号码
15936583816,非占位符400-XXX-XXXX。
6.2 平台验收标准(18 条红线 —— 来自 docs/03 §15)
| # | 验收点 |
|---|---|
| B1 | Agent 均由工厂创建,权限隔离正确 |
| B2 | 七步骨架不可被旁路 |
| B3 | 客服五意图端到端可测 |
| B4 | 低置信不硬答;转人工上下文完整 |
| B5 | 知识只使用"已发布 + 有效"版本 |
| B6 | 客服工单与风控工单不得混用 |
| B7 | 场内模拟成交满足幂等与事务原子性 |
| B8 | 规则引擎与风控 Agent 边界正确(模型不替代规则) |
| B9 | 权威业务事实不被记忆覆盖 |
| B10 | 零跨客户访问 / 零适当性违规 / 零敏感信息泄露 |
| B11 | 每条请求可凭 trace_id 追溯 |
| B12 | 同幂等键并发只产生一条消息/工单/领域事件 |
| B13 | Redis 丢失后,澄清轮次可从 MySQL 恢复 |
| B14 | 配置按不可变版本发布/评审/生效/回滚;一次请求内无漂移 |
| B15 | 只使用备份端点;模型与提示词版本可审计 |
| B16 | 长期记忆具备证据/冲突/提升/同步/删除测试;低版本不覆盖高版本 |
| B17 | Neo4j 受视图/深度/数量/超时/data-scope 约束;失败不编造关系 |
| B18 | 所有迁移中,原有表名与既有字段定义保持不变 |
B18 是本项目最硬的一条:修改数据库文档或迁移前,必须对比基线并证明没有改变任何已有表名和字段定义。核验命令:
python tools/audit_schema.py。
6.3 交付前自检(两条线互补,都跑一遍)
| 工具 | 覆盖 | 命令 | 说明 |
|---|---|---|---|
| 业务链路冒烟 | 登录→下单→成交、风控扫描→处置闭环、客服问答,共 6 条线 40 项 | python tools/e2e_smoke_test.py |
--read-only 不动数据 |
| 接口契约体检 | 按前端方式调每个端点,核对状态码/信封形状/字段,共 41 项 | python tools/portal_api_check.py |
--write 加测写操作;--dangerous 再加测改生效配置的操作 |
| 数据库基线校验 | 表/字段与 docs/00 基线对比 |
python tools/audit_schema.py |
— |
| RBAC 种子一致性 | 权限码两套映射一致性 | python tools/check_rbac_seed_consistency.py |
曾有 advisor 在种子重建后拿到语义错误权限 |
⚠️ 跑验收脚本前必须先停掉常驻 Worker,否则会抢队列(见
docs/20)。
6.4 本期已知风险与未闭环项(验收时应逐条确认状态)
| # | 风险/缺口 | 影响 | 当前状态 |
|---|---|---|---|
| R1 | app/static/portal/employee-console/workspace/workspace.js 曾存在真实语法错误(submitRule,约 L500–539,缺一个 }) |
管理端工作台该模块无法加载 | ✅ 已修复(2026-09-14 提交 4b7ee13「修复管理员工作台函数缺少闭合大括号」)。复验:node --experimental-vm-modules + vm.SourceTextModule 遍历 app/static/portal,44 个模块全部通过。⚠️ 注意 node --check 会假通过,必须用真实 ESM 解析 |
| R2 | today_profit_loss 为占位 0 |
客户看板"今日盈亏"无意义 | ⚠️ 已提级为待决项 → 见 Q22(含数据可行性实测与建议口径:行情基准不可行、净值基准可行) |
| R3 | 投顾目标/方案状态机失败 409 复用 RUN_NOT_CANCELLABLE 字面量 |
错误码语义不准 | ⚠️ 已知文档缺陷 |
| R4 | ResourceNotFoundError 直接抛出得到 SESSION_NOT_FOUND,集成测试期望 RESOURCE_NOT_FOUND |
错误码不一致 | ⚠️ 推介材料模块遗留(来自 product_promotion_to_do_list.md) |
| R5 | PDF 转换依赖部署环境 LibreOffice/soffice | 推介材料 PDF 导出不可用 | ⚠️ 本机未验证(Q15) |
| R6 | 仅支持 price_type="market" |
无限价单 | ✅ 设计如此(首版范围) |
| R7 | 投顾 21 张表登记文档缺失 | 数据字典不完整 | ⚠️ 待补(Q14) |
| R8 | 场外缺真实样例单据 | OCR/规则无法端到端验收 | ⚠️ 需业务提供(Q13) |
| R9 | 无充值提现/银行流水匹配通道 | 依赖真实资金流的 AML 规则不可做 | ✅ 已在基线中明示"不得伪造"(Q8) |
| R10 | config_release 是环境数据不随代码合并 |
换环境需重发白名单 | ✅ 已知,需环境限定声明 |
| R11 | RUN_CANCELLED 不是 HTTP 错误类 |
不要当错误码处理 | ✅ 已澄清(它是 request_idempotency 的状态标记) |
| R12 | /internal/** 无鉴权(含真实 Milvus 探测) |
生产部署需网关层限制访问 | ⚠️ 上线前需网络隔离 |
7. 附录
7.1 端点规模
22 个路由模块,端点数量约 140 个(表格驱动的路由为循环注册,故为估算值)。精确核对命令:
python -c "from app.main import app; print(len([r for r in app.routes if hasattr(r,'methods')]))"
注:本工作区无
.venv(被.gitignore忽略,未随仓库分发),受管解释器缺项目依赖,故该命令未能本地执行。请在有.venv的环境执行:.\.venv\Scripts\python.exe -c "..."。
7.2 环境与命令口径
| 项 | 值 |
|---|---|
| 本机解释器 | .\.venv\Scripts\python.exe |
| 架构师环境 | D:\conda\envs\jr_py313\python.exe |
| 两者关系 | 等价,各用本机可用的那个(.venv 不进仓库,不存在统一问题) |
| 启动 API | python -m uvicorn app.main:app --port 8000(模块级变量是 app,不是 application) |
| 启动 Worker | python -m app.worker(必需,否则 Agent 永远 queued) |
| 一键启动 | 双击 启动金融Agent平台.bat 或 powershell -ExecutionPolicy Bypass -File start.ps1 |
| 刷新行情 | python tools/sync_market_prices.py |
| 演示数据 | python tools/seed_demo_data.py(10 步,第 2 步非幂等) |
| 前端入口 | /portal/(访问 / 会 307 跳到访客首页) |
7.3 数据表规模
| 域 | 表数 | 是否进 docs/00 基线 |
|---|---|---|
| 场内(含客服、风控相关) | 51 | ✅ 是 |
场外 offsite_* |
10 | ❌ 否(规则 8) — 登记于 docs/28 |
推广 promotion_* |
7 | ❌ 否 — 登记于 docs/28 |
投顾 advisor_* |
21 | ❌ 否 — 登记文档待补 |
| 合计(业务表) | 89 | 含 alembic_version 则为 90 |
7.4 已注册业务 Agent(7 个)
FundQueryDemoAgent、CustomerServiceAgent、RiskAgent、PlatformProbeAgent、AdvisorAgent、OffsiteFundAgent、PromotionMaterialAgent
7.5 已注册公共只读工具
search_knowledge(客服知识检索)、check_suitability(适当性校验)、query_customer_profile(画像)、query_fund_quote(行情)。
query_knowledge 是 search_knowledge 的别名(同一 handler,为兼容一期发布配置与旧客户端保留)。
其余业务线工具(风控、投顾、NL2SQL)按各自 Agent 白名单注册,全部在 bootstrap.py 的 get_agent_factory() 中。
7.6 本文档与既有文档的关系
| 本文档章节 | 权威来源 |
|---|---|
| 第 0 章 待确认问题 | 本文档新增(汇总 docs/22/docs/10/docs/28/product_promotion_to_do_list.md 的未定义项) |
| 第 1 章 背景目标 | docs/01、docs/03、AGENTS.md |
| 第 2 章 角色场景 | docs/03 §2、tools/seed_test_rbac.py、docs/44 |
| 第 3 章 功能需求 | docs/05 接口文档 + app/service/* 实际实现 |
| 第 4 章 非功能需求 | docs/00 §3、docs/26、docs/07、docs/08、实测数据 |
| 第 5 章 业务流程 | docs/03 §5–§13、docs/场外申购赎回工作流程图.md、app/service/offsite_fund_rules.py |
| 第 6 章 验收标准 | docs/验收与审计/phase1-*、docs/03 §15、docs/44 |
本文档不替代
docs/00(不可变业务基线)与docs/05(接口唯一权威)。若三者出现冲突,以docs/00/docs/05为准,并回头修订本文件。