feat(advisor-agent): Integrate advisor agent into merger with new API structure

- Merged `xinghuo/advisor-agent` into the `merger` branch, establishing a new API prefix `/api/advisor-agent` to avoid conflicts with existing endpoints.
- Implemented a comprehensive implementation plan detailing the integration steps, including conflict resolution, database migrations, and service adaptations.
- Introduced new files for advisor compliance, script templates, KYC, and market alerts, ensuring a cohesive addition to the existing architecture.
- Updated documentation to reflect the new structure and integration process, enhancing clarity for future development and maintenance.

This integration significantly expands the capabilities of the merger, providing a robust framework for advisor-related functionalities while maintaining compliance and operational integrity.
This commit is contained in:
2026-09-12 15:14:29 +08:00
parent 601ed258f3
commit 973bf1b834
5 changed files with 536 additions and 6 deletions
@@ -0,0 +1,313 @@
# 投资顾问 Agent · 从 `advisor-agent` 合并说明
> 日期:2026-09-12
> 源分支:`xinghuo/advisor-agent` @ `68df13c`(Sprint0~3 后端 MVP · 101 pytest)
> 目标分支:`merger`(AL-09 宿主 + 客服 / 风控 / 问数已接线)
> 状态:**接缝设计稿(未 merge、未改码)** — 实施前以本文 + `docs/superpowers/plans/2026-09-12-advisor-agent-merge.md` 为准。
---
## 0. 已拍板决策(2026-09-12)
| # | 决策 | 结论 |
| --- | --- | --- |
| D1 | API 前缀与契约 | **以 merger / 代销平台 API v0.1 为准**;**不保留** `/api/v1/*` 对外形态 |
| D2 | 冲突文件 | **只增不盖**;与 merger 同路径冲突时 **保留 merger**(同客服 / 问数合并说明) |
| D3 | 顾问侧命名 | 迁入代码 **按 merger 习惯重命名**(见 §2);禁止覆盖问数 `template_service`、平台 `compliance` |
| D4 | 集成方式 | **新增投资顾问 Agent + 接缝**;不接顾问独立 `main.py` / 第二套 JWT |
| D5 | 验证顺序 | **先接线 → 再跑全量 pytest**;Neo4j 以本机 Docker 已就绪为前提 |
| D6 | 图库 | 复用 merger 已有 **`scripts/sync/sync_neo4j.py` / `sync_advisor_rel.py`**,不迁入顾问分支重复同步实现 |
| D7 | HTTP 前缀 | **已定稿:** `/api/advisor-agent/*`(2026-09-12 确认) |
| D8 | 演示 UI | **不迁入** 源分支 `demo_ui/` · **不挂载** `/demo` StaticFiles(2026-09-12 确认) |
| D9 | 管理/审计 API | **第一批不迁入** 源分支 `admin/audit-logs`(2026-09-12:风控侧页面已覆盖合规查看诉求;见 §2.1) |
---
## 1. 一句话定位
投资顾问 Agent = **顾问工作台后端线**(合规文案检测 · 复制门闸 · 话术模板 · 市场异动 · KYC 采集),与:
- **平台 API**(`/api/advisors/*` 归属 · `/api/compliance/suitability-check` 适当性)
- **通用对话线**(`POST /api/chat` + `X-Agent-Type`)
- **问数线**(`/api/analyst/*`)
**并行存在**。合并时 **不替换** `main.py` 骨架、不覆盖 `auth_service.py`、不把 KYC 硬塞进 `chat.py`(与问数 §3.1 双轨理由相同:响应形态与审计字段不同)。
---
## 2. 重命名与路径对照(advisor → merger)
### 2.1 HTTP:废弃 `/api/v1`,统一业务域前缀
**推荐对外前缀:** `/api/advisor-agent`(**单数 advisor + agent**,与平台复数 `/api/advisors` 区分,避免路由与文档歧义)。
| 中文职责 | 源分支挂载(勿保留) | 合并后 canonical 路径(kebab-case) |
| --- | --- | --- |
| 顾问文案合规检测与规则库 | `/api/v1/compliance/*` | `/api/advisor-agent/compliance/content-check` · `.../compliance/rules` · `.../compliance/rules/{rule_id}` |
| 复制追踪门闸 | `/api/v1/copy/track` | `POST /api/advisor-agent/copy/track` |
| 话术模板 CRUD / 检索 / 引用 | `/api/v1/templates/*` | `/api/advisor-agent/script-templates/*` |
| 市场异动扫描 / 解读 / 反馈 | `/api/v1/market-alerts/*` · `/api/v1/market/*` | `/api/advisor-agent/market-alerts/*` · `/api/advisor-agent/market/*` |
| KYC 会话与采集对话 | `/api/v1/kyc/*` | `/api/advisor-agent/kyc/sessions` · `.../chat` · `.../complete` |
| 输入防护探测 | `/api/v1/guard/*` | `/api/advisor-agent/guard/check` |
| 顾问看板(个人/全局) | `/api/v1/dashboard/*` | `/api/advisor-agent/dashboard/*` |
| 资产配置(当前 stub) | `/api/v1/allocation/*` | `/api/advisor-agent/allocation/*` |
| ~~审计日志只读列表~~ | `/api/v1/admin/audit-logs` | **不迁入**(D9) |
**D9 说明(与风控页面的关系):**
- merger **风控菜单**已给合规/风控可看、可操作的 **业务留痕面**:例如 **预警台账**(`RiskAlertsPage` · compliance 角色看 AML 单并处置)、**适当性检查** / **AML 扫描**(操作结果写 `audit_log` / 业务表,页面上体现为「留痕」说明)。
- 源分支 `GET /admin/audit-logs` 是 **整张 `audit_log` 的通用翻页列表**,merger **前端目前没有对应页**;与上述风控台账 **用途重叠**(合规日常看单),**不是** MVP 合并必带。
- 投资顾问线 **仍须写** 共用 `audit_log`(合规检测 · KYC · 复制门闸等),与风控/问数 **同表**;日后若要做「全事件审计检索」,应在 **风控/运维统一入口** 扩展 API + 页面,**不要**再挂一条顾问专用 `admin/audit-logs`。
**平台层禁止占用 / 混淆:**
| 中文职责 | merger 已有路径 | 顾问迁入时 |
| --- | --- | --- |
| G-01 适当性判定 | `POST /api/compliance/suitability-check`(`app/api/compliance.py`) | **不得**把文案检测挂到 `/api/compliance/check` |
| 理财师客户归属 | `GET /api/advisors/{advisor_id}/customers` | **不得**用 `/api/advisors` 挂 KYC/合规 |
> 契约附录:合并落地后补 **`接口契约-代销平台API-v0.1.md` § 路由树** 一段「投资顾问 Agent 扩展」(与 v0.2 行情草案同级,标注 **已实现 / MVP**)。
### 2.2 路由文件(merger 习惯:按域拆分 + `main.py` 挂载)
| 中文职责 | 建议路径 | 说明 |
| --- | --- | --- |
| 顾问线路由聚合(可选) | `app/api/advisor_agent/__init__.py` | `APIRouter(prefix="/api/advisor-agent")` + `include_router` |
| 文案合规 API | `app/api/advisor_compliance.py` | 自源 `compliance.py` 改写 prefix/response |
| 话术模板 API | `app/api/advisor_script_templates.py` | 自源 `templates.py` |
| KYC API | `app/api/advisor_kyc.py` | 自源 `kyc.py` |
| 市场异动 API | `app/api/advisor_market.py` | 自源 `market.py` |
| 复制门闸 API | `app/api/advisor_copy.py` | 自源 `copy.py` |
| 输入防护 API | `app/api/advisor_guard.py` | 自源 `guard.py` |
| 看板 / 配置 stub | `app/api/advisor_dashboard.py` · `advisor_allocation.py` | 源分支同名改写 |
**不迁入(含 D9):**
| `app/api/admin.py`(`audit-logs` 列表) | 风控侧已有合规查看链路;通用审计查询留待平台统一 |
**不迁入(宿主/冲突):**
| 路径 | 原因 |
| --- | --- |
| `app/api/__init__.py`(v1 聚合) | 由 merger `main.py` 挂载 |
| `app/api/deps.py` | merger 完整 JWT + 归属矩阵 |
| `app/api/auth.py` | 统一 `app/api/auth.py` + `auth_service` 签发 |
| `app/api/chat.py` | 宿主对话线;顾问 KYC **独立 REST**,不走 Chat 四件套 |
| `app/main.py` | AL-09 宿主入口 |
### 2.3 Service / Repository 重命名(消除与问数撞名)
| 源分支 | 合并后 | 原因 |
| --- | --- | --- |
| `app/service/template_service.py` | `app/service/script_template_service.py` | merger 已有问数 **`template_service.py`(NL2SQL 模板)** |
| `app/service/template_vector_service.py` | `app/service/script_template_vector_service.py` | 话术 Milvus 专用 |
| `app/repository/template_repository.py` | `app/repository/script_template_repository.py` | 与上配套 |
| `app/service/auth_service.py` | **不迁入** | merger Auth SDK 唯一验签 |
| `app/service/llm_client.py` | `app/service/advisor_llm_client.py` | 与问数 `llm.py`、宿主 embedding 区分(可选,merge 时二选一) |
| `app/middleware/trace.py` | **不迁入** | 宿主 `TraceMiddleware` + `utils.trace` |
| `app/utils/response.py` · `success_response` | **不迁入** | 统一 `app/utils/response.py` 的 `ok` / `fail` / `error_body` |
| `app/utils/exceptions.py` · `AuthenticationError` | **不迁入** | 统一 `ApiError` / `PermissionDenied` + `register_error_handlers` |
### 2.4 模型层
| 策略 | 说明 |
| --- | --- |
| 请求/响应 Pydantic | **`app/model/advisor_schemas.py`**(对齐 `analyst_schemas.py`;**不**扩写 merger 巨型 `schemas.py` 覆盖) |
| ORM 实体 | **`app/model/entities/advisor.py`** 或追加 `entities.py` **仅新增类**(禁止覆盖已有 risk/analytics 映射) |
| 内部 Auth 视图 | 由 **`advisor_auth_adapter.py`** 从 `deps.AuthContext` 映射(见 §3.2) |
### 2.5 测试文件
| 源分支 | 合并后建议 |
| --- | --- |
| `tests/test_sprint*.py` · `tests/test_step*.py` | 保留文件名或统一 `tests/test_advisor_sprint*.py` |
| 断言中的 `/api/v1` | 全部改为 §2.1 canonical 路径 |
| 断言 `success_response` 形 | 改为 merger 统一响应 envelope(与 `test_wave6_analyst` 一致) |
---
## 3. S4 接缝设计(对齐问数 S3 · 客服 S2)
### 3.1 宿主挂载(唯一 `main.py` 改动面)
```python
# 示例:按域 router 逐个 include,或单一 advisor_agent 聚合 router
from app.api.advisor_compliance import router as advisor_compliance_router
# ...
app.include_router(advisor_compliance_router)
# 各 router 内部 prefix 已含 /api/advisor-agent/...
```
**不**挂载 `/demo` StaticFiles · **不复制** `demo_ui/`(D8);MVP 以 pytest + 既有 `web/` 为准。
### 3.2 鉴权接缝
1. 路由层:`Depends(get_platform_auth_context)`(与问数 / 平台 API 一致)。
2. 新增 **`app/api/advisor_auth_adapter.py`**(或扩展 `auth_adapter.py`):
- `deps.AuthContext` → 顾问服务内使用的视图(`actor_id` / `roles` / `permissions` / `trace_id`)。
- 源分支 `require_permission("compliance:check")` → merger **`has_permission` / 矩阵**;权限字符串 **原样保留** 或映射到现有 staff 角色(`advisor` / `compliance` / `admin`)。
3. **dev 测试账号**:在 merger `auth.py` / 种子 JWT 中补齐源分支文档中的 `advisor_test` · `compliance_test` · `admin_test` **权限集**(仅 development)。
4. **禁止**顾问代码 import 宿主 `gateway/*`;**禁止**宿主 import 顾问私有 repo 绕过 deps。
### 3.3 归属与客户访问
- KYC / 合规检测带 `customer_id` 的写读:**必须**走 merger 已有 **`assert_platform_customer_access` / `core_customer_advisor`** 口径(与问数 advisor 域一致)。
- 源分支 `ownership_service.py` 若与 `deps` 重复,合并后 **删私有版**,逻辑收敛到 `deps` + `core_ro`。
### 3.4 响应与异常
- 所有新 router 返回 **`ok(request, data)`** 或 **`fail(...)`** / 抛出 **`ApiError`**。
- 源分支 `ApiResponse` 包装层:仅在 adapter 测试期保留 thin wrapper,**不**对外暴露第二套 JSON 形。
### 3.5 共用底座表(agent_session / agent_message / audit_log)
merger **`01-mysql-共用底座.sql` 已建** 11 张底座表;源分支 Alembic `20260911_0001` **不得**在已灌库环境重复 CREATE。
| 动作 | 说明 |
| --- | --- |
| 跳过 | Sprint0 foundation 中与底座重复的 `CREATE TABLE` |
| 增量 | 仅执行顾问 **专用表** + **`agent_message` 唯一约束**(源 `20260912_0007`)等 **ALTER** |
| 写入 | KYC 会话写 `agent_session.agent_type='advisor'` · 消息写 `agent_message` · 审计写 `audit_log.agent_type='advisor'` |
### 3.6 Milvus / Embedding(与客服 fin_* · 问数并存)
| 集合 / 用途 | 策略 |
| --- | --- |
| `kb_script_templates` | 顾问话术向量;**仅扩展** `milvus_tool.py` / `embedding_tool.py`,**不**改 fin_* collection 名 |
| 降级 | 与源分支一致:Milvus/Ollama 不可用时 **关键词检索降级** |
| 灌库 | `scripts/sync/sync_template_vectors.py`(迁入并重命名路径到 `scripts/sync/sync_script_template_vectors.py` 可选) |
### 3.7 Neo4j(Docker 已就绪)
- **不**把 Neo4j 查询接进 KYC HTTP 主链路(一期)。
- 合并后验证:`python scripts/sync/sync_neo4j.py` · `sync_advisor_rel.py`(或 `prepare_all.ps1` 已有步骤)与顾问归属校验 **数据一致**。
- 源分支文档中的「28 客户 · 3 顾问 · 2 产品」验收,改为 **merger Core 种子 + 同步脚本** 复测一遍并记入 TEST-LOG。
### 3.8 memory_service
- merger `memory_service.py` 已含客服/游客逻辑;源分支扩展 **仅追加** 顾问/KYC 所需方法(或 `AdvisorSessionMessageRepository` 独立模块)。
- **禁止**用顾问版本覆盖整个 `memory_service.py`。
---
## 4. 数据库:Alembic → SQL 迁移(merger 习惯)
**不**把 `alembic/` 作为 merger 唯一迁移入口(与问数 / 客服一致),改为:
```text
scripts/agent/migrate-advisor-agent-sprint1-3.sql
→ compliance_rule · compliance_check_log
→ copy_track_log
→ script_template · template_use_log(及源 0004 全部对象)
→ market_alert(及关联索引)
→ kyc_session(及关联字段)
→ agent_message 上 uk_agent_message_session_seq(若本机尚无)
```
| 步骤 | 说明 |
| --- | --- |
| 前置 | `jinrong_agent` 已执行 01 共用底座 + 02 agent 专用(风控/问数/客服已有表) |
| 种子 | `scripts/seed/import_compliance_rules.py` · `import_script_templates.py`(迁入 `scripts/agent/` 或 `scripts/seed/`) |
| 重置 | **不**改 `scripts/core/reset.ps1` 破坏 core;可选 `scripts/agent/reset-advisor-agent.sql` 仅清顾问专用表 |
---
## 5. 合并什么 / 不合并什么
### 5.1 整包迁入(新增或重命名后迁入)
| 类别 | 源路径(示意) | 作用 |
| --- | --- | --- |
| 合规引擎 | `compliance_*_service.py` · `compliance_*_repository.py` | 硬规则 + 语义兜底 + 日志 |
| 复制门闸 | `copy_track_*` | WARN/BLOCK 与审计 |
| 话术 | `script_template_*`(重命名后) | CRUD · 混合检索 · 引用留痕 |
| 市场 | `market_*_service.py` · `market_alert_*` | 扫描 · 解读 · 反馈闭环 |
| KYC | `kyc_*` | 会话状态机 · 字段解析 · 消息序号 |
| 编排(未完成) | `agent_graph.py` · `agent_tools.py` | **可选迁入**;LangGraph 未落地前 **不挂 chat** |
| 评测脚本 | `scripts/eval/evaluate_compliance.py` · `evaluate_agent.py` | 开发回归资产 |
| 演示 | `scripts/demo/run_demo_smoke.ps1` | 改为调 canonical 路径后保留 |
| 测试 | `tests/test_sprint*.py` 等 | 改路径/响应/import 后解禁 |
| 文档 | `docs/开发文档/35~39` · `docs/演示文档/*` | 迁入 `docs/项目框架设计/` 或 `docs/需求拆解/` 子目录,**不**覆盖 `docs/memory/*` |
### 5.2 禁止覆盖(冲突时保留 merger)
| 文件 | 原因 |
| --- | --- |
| `app/main.py` | AL-09 宿主 |
| `app/api/deps.py` · `app/service/auth_service.py` | 唯一 JWT |
| `app/api/compliance.py` | 平台适当性 |
| `app/service/template_service.py` | 问数 D-06 |
| `app/repository/core_ro.py` | 含 `check_suitability` 等 |
| `app/config/settings.py` | **仅追加** `advisor_*` / `kyc_*` / `compliance_content_*` 字段 |
| `app/tool/milvus_tool.py` · `embedding_tool.py` | **手工合并** 增量,禁止整文件覆盖 |
| `docs/memory/*` · `web/` · 风控/问数/客服模块 | 全部保留 merger |
| `docs/项目框架设计/表设计/01-mysql-共用底座.sql` | 仅 **新 SQL 脚本** 追加顾问表,不改 canonical 01 历史 |
---
## 6. 测试与验收
### 6.1 顺序(与 D5 一致)
```text
1. worktree / 集成分支完成 §2 重命名 + §3 接缝(不推 main)
2. 执行 migrate-advisor-agent-sprint1-3.sql + 规则/模板种子
3. (可选)sync_script_template_vectors · Neo4j 同步
4. python -m pytest # 目标:merger 基线 + 顾问新增全绿
5. ruff check app tests scripts
6. Scope B 冒烟(§6.3)
7. 更新 FRAMEWORK 实现状态表 · TODO · MEMORY(§7)
```
### 6.2 基线期望
| 指标 | 合并前 merger | 合并后目标 |
| --- | --- | --- |
| pytest | **833 passed**(见 MEMORY §0) | **833 + M passed**(M ≈ 源分支 101,去重后略少) |
| 顾问子集 | — | `pytest tests/test_advisor_sprint*.py`(或原 sprint 名) |
### 6.3 Scope B 冒烟(canonical 路径)
1. `POST /api/advisor-agent/compliance/content-check` + advisor JWT → 200 + 风险等级
2. `POST /api/advisor-agent/copy/track` · WARN 需 confirm · BLOCK 拒绝
3. `GET /api/advisor-agent/script-templates/search?q=…` → 200(Milvus 不可用时关键词降级)
4. `POST /api/advisor-agent/kyc/sessions` → chat 一轮 → `complete`
5. `POST /api/compliance/suitability-check` **仍 200**(平台路由未回归)
6. `POST /api/analyst/chat` **仍 200**(问数 template_service 未回归)
---
## 7. Merge 操作顺序(SOP · 尚未执行)
```text
1. git worktree add ../JinRong-advisor-merge -b integrate/advisor-agent merger
2. git merge xinghuo/advisor-agent --no-commit # 或 git read-tree + 按 §5.1 只 checkout 新增路径
3. 冲突:按 §5.2 一律保留 merger,顾问逻辑拷贝到新文件名(§2)
4. 接缝:advisor_auth_adapter · main.py include_router · settings 追加 · requirements 追加
5. 删除误迁入:advisor deps/auth/main/alembic(迁移已转 SQL)
6. 改测试路径与响应形 · pytest 全绿
7. 文档:契约附录 · FRAMEWORK · 本说明状态改为「已接线」
```
---
## 8. 风险与开放项(合并不解决)
| 项 | 说明 |
| --- | --- |
| KYC Profile / 资产配置 | 源分支自述未闭环;合并 **不包含** S3-03~S3-08 |
| 前端工作台 | 不纳入本次 merge;`web/` 后续单独立项 |
| `/api/v1` 兼容 | **不做**;若演示客户端依赖,单独加 shim router(deprecated) |
| 101 vs 833 测试重叠 | `conftest` · DB fixture 以 merger 为准,顾问测试禁止 drop 宿主表 |
| 双 `llm_client` | merge 时统一配置项命名,避免 `.env` 键冲突 |
---
## 9. 修订记录
| 日期 | 说明 |
| --- | --- |
| 2026-09-12 | 首版:merge 优先 · `/api/advisor-agent` · 重命名表 · S4 接缝 · 不测前不 claim 完成 |