feat: batch update - gift card breakdown spec, backend APIs, miniprogram pages, ETL finance recharge, docs & migrations
This commit is contained in:
419
docs/prd/Neo_Specs/NS2-ai-prompt-refinement.md
Normal file
419
docs/prd/Neo_Specs/NS2-ai-prompt-refinement.md
Normal file
@@ -0,0 +1,419 @@
|
||||
# NS2:AI Prompt 细化 — ai-prompt-refinement
|
||||
|
||||
> 优先级:高(NS1 完成后立即执行,Prompt 细化是 AI 功能闭环的关键)
|
||||
> 预估工作量:中等
|
||||
> 前置条件:P5-A 已完成(AI 骨架就绪)、NS1 已完成(后端 API 数据结构确定)
|
||||
> 参考基准:`docs/prd/specs/P5-miniapp-ai-integration.md`(P5-B 阶段定义)
|
||||
|
||||
---
|
||||
|
||||
## 一、背景与目标
|
||||
|
||||
P5-A 阶段已交付 AI 集成管道:百炼封装、缓存 API、SSE 框架、应用 2/8 完整实现、应用 1/3/4/5/6/7 的触发机制和调用骨架。但应用 1/3/4/5/6/7 的 `build_prompt()` 函数仍为占位骨架,核心数据字段(`consumption_records`、`service_history`、`objective_data` 等)标记为 TODO。
|
||||
|
||||
本 SPEC 目标:将 6 个应用的 Prompt 拼接函数从骨架升级为完整实现,使 AI 应用能基于真实数据生成有价值的分析结果。
|
||||
|
||||
### 当前骨架状态
|
||||
|
||||
| 应用 | 文件 | 骨架状态 | 待细化字段 |
|
||||
|------|------|---------|-----------|
|
||||
| 应用 1 | `app1_chat.py` | 页面上下文文本化工具留接口 | `page_context`、`screen_content` 各页面文本化 |
|
||||
| 应用 3 | `app3_clue.py` | `build_prompt()` 占位 | `consumption_records`(DWD+DWS 订单明细全维度) |
|
||||
| 应用 4 | `app4_analysis.py` | `build_prompt()` 占位 | `service_history`、`assistant_info` |
|
||||
| 应用 5 | `app5_tactics.py` | `build_prompt()` 占位 | `service_history`、`assistant_info`(同应用 4) |
|
||||
| 应用 6 | `app6_note.py` | `build_prompt()` 占位 | `consumption_data`(同应用 3 的 main_data) |
|
||||
| 应用 7 | `app7_customer.py` | `build_prompt()` 占位 | `objective_data`(同应用 3 的 main_data) |
|
||||
|
||||
---
|
||||
|
||||
## 二、技术架构
|
||||
|
||||
### 2.1 数据获取层(新建共享模块)
|
||||
|
||||
Prompt 细化的核心是从数据库获取真实数据并格式化为 AI 可读的 JSON。多个应用共享相同的数据获取逻辑,应抽取为共享模块:
|
||||
|
||||
```
|
||||
apps/backend/app/ai/
|
||||
├── data_fetchers/ 🆕 新建
|
||||
│ ├── __init__.py
|
||||
│ ├── member_data.py # 客户数据获取(消费记录、会员卡、余额等)
|
||||
│ ├── assistant_data.py # 助教数据获取(基本信息、服务历史)
|
||||
│ ├── service_history.py # 服务记录获取(助教-客户维度)
|
||||
│ └── page_context.py # 页面上下文文本化(应用 1 专用)
|
||||
├── apps/
|
||||
│ ├── app1_chat.py 🔧 补充页面文本化调用
|
||||
│ ├── app3_clue.py 🔧 补充 consumption_records 拼接
|
||||
│ ├── app4_analysis.py 🔧 补充 service_history + assistant_info
|
||||
│ ├── app5_tactics.py 🔧 补充 service_history + assistant_info
|
||||
│ ├── app6_note.py 🔧 补充 consumption_data
|
||||
│ └── app7_customer.py 🔧 补充 objective_data
|
||||
```
|
||||
|
||||
### 2.2 数据获取函数设计
|
||||
|
||||
#### `member_data.py` — 客户数据获取(应用 3/6/7 共用)
|
||||
|
||||
```python
|
||||
async def fetch_member_consumption_data(
|
||||
site_id: int, member_id: int, months: int = 3
|
||||
) -> dict:
|
||||
"""获取客户近 N 个月消费数据(DWD+DWS 全维度)。
|
||||
|
||||
返回结构对应 P5 spec 中 main_data:
|
||||
- consumption_records: 台桌结账 + 商城订单明细列表
|
||||
- member_cards: 会员卡明细
|
||||
- card_balance_total: 储值卡余额合计
|
||||
- stored_value_balance_total: 储值余额合计
|
||||
- expected_visit_date: 预计到店日期
|
||||
- days_since_last_visit: 距上次到店天数
|
||||
"""
|
||||
```
|
||||
|
||||
数据源(全部通过 FDW):
|
||||
- `fdw_etl.v_dwd_settlement_head` + `fdw_etl.v_dwd_table_fee_log`(台桌结账)
|
||||
- `fdw_etl.v_dwd_store_goods_sale`(商城订单)
|
||||
- `fdw_etl.v_dwd_recharge_order`(充值记录)
|
||||
- `fdw_etl.v_dim_member_card_account`(会员卡明细)
|
||||
- `fdw_etl.v_dws_member_consumption_summary`(消费汇总 + 余额)
|
||||
- `fdw_etl.v_dws_member_visit_detail`(到店明细 → 计算预计到店日期)
|
||||
|
||||
> ⚠️ 金额口径:使用 `items_sum`(= table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money),禁止 `consume_money`
|
||||
> ⚠️ 会员字段断档(DQ-6/DQ-7):member_phone/member_name 通过 member_id JOIN dim_member
|
||||
|
||||
#### `assistant_data.py` — 助教数据获取(应用 4/5 共用)
|
||||
|
||||
```python
|
||||
async def fetch_assistant_info(
|
||||
site_id: int, assistant_id: int
|
||||
) -> dict:
|
||||
"""获取助教基本信息(花名、级别、工龄等)。"""
|
||||
|
||||
async def fetch_service_history(
|
||||
site_id: int, assistant_id: int, member_id: int, months: int = 3
|
||||
) -> list[dict]:
|
||||
"""获取助教服务该客户的历史记录。"""
|
||||
```
|
||||
|
||||
数据源:
|
||||
- `fdw_etl.v_dim_assistant`(基本信息)
|
||||
- `fdw_etl.v_dwd_assistant_service_log`(服务记录,按助教+客户筛选)
|
||||
- `fdw_etl.v_dws_member_assistant_relation_index`(关系指数)
|
||||
- `fdw_etl.v_dws_member_assistant_intimacy`(亲密度)
|
||||
|
||||
#### `page_context.py` — 页面上下文文本化(应用 1 专用)
|
||||
|
||||
```python
|
||||
async def build_page_text(
|
||||
source_page: str, context_data: dict, site_id: int
|
||||
) -> str:
|
||||
"""将页面数据转换为 AI 可读的结构化文本。
|
||||
|
||||
根据 source_page 类型,从数据库获取对应数据并格式化。
|
||||
"""
|
||||
```
|
||||
|
||||
支持的页面类型及数据获取:
|
||||
| source_page | 数据获取 | 文本化内容 |
|
||||
|-------------|---------|-----------|
|
||||
| `task-detail` | coach_tasks + member + notes + ai_cache | 任务信息 + 客户信息 + 备注 + AI 分析 |
|
||||
| `customer-detail` | member + consumption + clues | 客户全信息 + 消费记录 + 维客线索 |
|
||||
| `coach-detail` | assistant + tasks + notes | 助教信息 + 任务统计 + 备注 |
|
||||
| `board-finance` | finance DWS 汇总 | 财务数据摘要 |
|
||||
| `board-customer` | 当前筛选维度 top 列表 | 客户排名摘要 |
|
||||
| `board-coach` | 当前筛选维度排名 | 助教排名摘要 |
|
||||
| `performance` | salary_calc + daily_detail | 绩效数据摘要 |
|
||||
| `my-profile` | user info + assistant binding | 个人信息摘要 |
|
||||
|
||||
### 2.3 数据库连接模式
|
||||
|
||||
- 所有 FDW 查询通过 `get_etl_readonly_connection(site_id)` 或 `fdw_etl.*` 视图
|
||||
- 业务库查询通过 `get_connection()`
|
||||
- 查询前必须 `SET LOCAL app.current_site_id`(RLS 隔离)
|
||||
|
||||
---
|
||||
|
||||
## 三、各应用 Prompt 细化详细设计
|
||||
|
||||
### 3.1 应用 3:客户数据维客线索分析
|
||||
|
||||
`build_prompt()` 需要拼接的完整 JSON 结构(参考 P5 spec):
|
||||
|
||||
```json
|
||||
{
|
||||
"current_time": "2026-03-08 14:30:25",
|
||||
"member_nickname": "客户昵称",
|
||||
"main_data": {
|
||||
"consumption_records": [
|
||||
{
|
||||
"settle_date": "2026-03-05",
|
||||
"settle_type": 1,
|
||||
"items_sum": 280.00,
|
||||
"table_charge_money": 180.00,
|
||||
"assistant_pd_money": 80.00,
|
||||
"assistant_cx_money": 0,
|
||||
"goods_money": 20.00,
|
||||
"room_name": "VIP-3",
|
||||
"duration_minutes": 120,
|
||||
"assistant_names": ["张助教"]
|
||||
}
|
||||
],
|
||||
"member_cards": [
|
||||
{"card_type": "金卡", "balance": 1500.00, "gift_balance": 200.00}
|
||||
],
|
||||
"card_balance_total": 1700.00,
|
||||
"stored_value_balance_total": 1700.00,
|
||||
"expected_visit_date": "2026-03-10",
|
||||
"days_since_last_visit": 15
|
||||
},
|
||||
"reference": {
|
||||
"app6_clues": [...],
|
||||
"app8_history": [
|
||||
{"generated_at": "2026-03-01", "clues": [...]},
|
||||
{"generated_at": "2026-02-15", "clues": [...]}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
实现要点:
|
||||
- `consumption_records` 从 `v_dwd_settlement_head` + `v_dwd_table_fee_log` 获取,settle_type IN (1,3)
|
||||
- 金额字段逐项拆分(table_charge_money / assistant_pd_money / assistant_cx_money / goods_money),不使用 consume_money
|
||||
- `expected_visit_date` 从 `v_dws_member_visit_detail` 的到店间隔推算
|
||||
- reference 从 `ai_cache` 获取 app6 + app8 最近 2 套历史
|
||||
|
||||
### 3.2 应用 4:关系分析/任务建议
|
||||
|
||||
`build_prompt()` 需要拼接的完整 JSON 结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"current_time": "2026-03-08 14:30:25",
|
||||
"assistant_info": {
|
||||
"nickname": "张助教",
|
||||
"level": "高级",
|
||||
"hire_date": "2024-06-01",
|
||||
"tenure_months": 21,
|
||||
"monthly_customers": 45,
|
||||
"performance_tier": "A档"
|
||||
},
|
||||
"service_history": [
|
||||
{
|
||||
"service_date": "2026-03-01",
|
||||
"duration_minutes": 90,
|
||||
"items_sum": 250.00,
|
||||
"room_name": "VIP-3",
|
||||
"is_pd": true
|
||||
}
|
||||
],
|
||||
"task_assignment_basis": "优先召回",
|
||||
"customer_data": {
|
||||
"system_data": { /* 同应用 3 的 main_data */ },
|
||||
"notes": [
|
||||
{"recorded_by": "张助教", "content": "客户喜欢打斯诺克", "created_at": "2026-02-28"}
|
||||
]
|
||||
},
|
||||
"reference": {
|
||||
"app8_current": {...},
|
||||
"app8_history": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
实现要点:
|
||||
- `assistant_info` 从 `v_dim_assistant` + `v_dws_assistant_salary_calc` 获取
|
||||
- `service_history` 从 `v_dwd_assistant_service_log` 按助教+客户筛选
|
||||
- `customer_data.system_data` 复用 `member_data.fetch_member_consumption_data()`
|
||||
- `customer_data.notes` 从 `biz.notes` 获取该客户的全部备注
|
||||
- reference 从 `ai_cache` 获取 app8 最新 + 最近 2 套历史
|
||||
|
||||
### 3.3 应用 5:话术参考
|
||||
|
||||
结构与应用 4 基本一致,额外增加 `task_suggestion` 字段(应用 4 的返回结果)。
|
||||
|
||||
实现要点:
|
||||
- 复用应用 4 的 `assistant_info` + `service_history` + `customer_data` 获取逻辑
|
||||
- `task_suggestion` 从应用 4 的 `run()` 返回值传入(调用链:应用 4 → 应用 5)
|
||||
|
||||
### 3.4 应用 6:备注分析
|
||||
|
||||
```json
|
||||
{
|
||||
"current_time": "2026-03-08 14:30:25",
|
||||
"current_note": {
|
||||
"content": "客户说下周要带朋友来打球",
|
||||
"recorded_by": "张助教",
|
||||
"created_at": "2026-03-08 14:25:00"
|
||||
},
|
||||
"reference": {
|
||||
"member_nickname": "王先生",
|
||||
"consumption_data": { /* 同应用 3 的 main_data */ },
|
||||
"all_notes": [...],
|
||||
"app3_clues": [...],
|
||||
"app8_history": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
实现要点:
|
||||
- `current_note` 从触发上下文获取(备注提交事件传入)
|
||||
- `consumption_data` 复用 `member_data.fetch_member_consumption_data()`
|
||||
- `all_notes` 从 `biz.notes` 获取所有助教对该客户的全部备注
|
||||
- reference 从 `ai_cache` 获取 app3 + app8 历史
|
||||
|
||||
### 3.5 应用 7:客户分析
|
||||
|
||||
```json
|
||||
{
|
||||
"current_time": "2026-03-08 14:30:25",
|
||||
"member_id": 12345,
|
||||
"member_nickname": "王先生",
|
||||
"objective_data": { /* 同应用 3 的 main_data */ },
|
||||
"subjective_data": {
|
||||
"notes": [
|
||||
{"recorded_by": "张助教", "content": "...", "created_at": "..."}
|
||||
]
|
||||
},
|
||||
"reference": {
|
||||
"app8_current": {...},
|
||||
"app8_history": [...]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
实现要点:
|
||||
- `objective_data` 复用 `member_data.fetch_member_consumption_data()`
|
||||
- `subjective_data.notes` 从 `biz.notes` 获取全部备注,标注创建者
|
||||
- 主观信息需在 Prompt 中标注【来源:XXX,请甄别信息真实性】
|
||||
- reference 从 `ai_cache` 获取 app8 最新 + 最近 2 套历史
|
||||
|
||||
### 3.6 应用 1:页面上下文文本化
|
||||
|
||||
应用 1 的 `_build_page_context()` 和 `_build_source_context()` 需要根据 `source_page` 类型,调用对应的数据获取函数并格式化为文本。
|
||||
|
||||
实现要点:
|
||||
- 每个页面类型对应一个文本化函数
|
||||
- 文本化输出为结构化中文描述(非 JSON),便于 AI 理解
|
||||
- 数据量控制:每个页面上下文不超过 2000 字符,避免 token 浪费
|
||||
- 敏感信息脱敏:不传入 member_phone 等断档字段
|
||||
|
||||
---
|
||||
|
||||
## 四、数据库审查
|
||||
|
||||
### 4.1 数据获取涉及的表
|
||||
|
||||
| 数据获取函数 | 涉及表 | 连接方式 |
|
||||
|-------------|--------|---------|
|
||||
| `fetch_member_consumption_data` | v_dwd_settlement_head, v_dwd_table_fee_log, v_dwd_store_goods_sale, v_dwd_recharge_order, v_dim_member_card_account, v_dws_member_consumption_summary, v_dws_member_visit_detail | FDW |
|
||||
| `fetch_assistant_info` | v_dim_assistant, v_dws_assistant_salary_calc | FDW |
|
||||
| `fetch_service_history` | v_dwd_assistant_service_log, v_dws_member_assistant_relation_index, v_dws_member_assistant_intimacy | FDW |
|
||||
| `build_page_text` | 以上全部 + biz.coach_tasks, biz.notes, biz.ai_cache, public.member_retention_clue | FDW + 业务库 |
|
||||
|
||||
### 4.2 无需新建表
|
||||
|
||||
本 SPEC 不需要新建数据库表。所有数据获取基于 NS1 已建立的 FDW 映射和 P4/P5-A 已建立的业务表。
|
||||
|
||||
### 4.3 性能考虑
|
||||
|
||||
- `fetch_member_consumption_data` 涉及 7 张 FDW 表查询,建议:
|
||||
- 消费记录限制最近 3 个月(WHERE settle_date >= NOW() - INTERVAL '3 months')
|
||||
- 单次查询最多返回 100 条记录
|
||||
- 考虑使用 NS1 中建议的 `biz.task_detail_cache` 缓存聚合结果
|
||||
- 页面文本化(应用 1)需要实时获取数据,建议设置 5 秒查询超时
|
||||
|
||||
---
|
||||
|
||||
## 五、调用链与数据流
|
||||
|
||||
### 5.1 消费事件链
|
||||
|
||||
```
|
||||
新结算单到达
|
||||
→ 应用 3.build_prompt(member_data) → 百炼 API → ai_cache
|
||||
→ 应用 8.run() → member_retention_clue
|
||||
→ 应用 7.build_prompt(member_data + notes) → 百炼 API → ai_cache
|
||||
→ 应用 4.build_prompt(assistant_data + member_data) → 百炼 API → ai_cache
|
||||
→ 应用 5.build_prompt(app4_result) → 百炼 API → ai_cache
|
||||
```
|
||||
|
||||
### 5.2 备注提交事件链
|
||||
|
||||
```
|
||||
备注提交
|
||||
→ 应用 6.build_prompt(note + member_data) → 百炼 API → ai_cache
|
||||
→ 应用 8.run() → member_retention_clue
|
||||
```
|
||||
|
||||
### 5.3 应用 1 对话流
|
||||
|
||||
```
|
||||
用户点击 AI 入口
|
||||
→ 前端传入 source_page + context_data
|
||||
→ 后端 build_page_text(source_page, context_data)
|
||||
→ 拼接为首条 user message
|
||||
→ SSE 流式调用百炼 API
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、参考文档
|
||||
|
||||
| 文档 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| P5 AI 集成 spec | `docs/prd/specs/P5-miniapp-ai-integration.md` | Prompt JSON 结构定义、调用链时序 |
|
||||
| API 契约 | `docs/miniprogram-dev/API-contract.md` | 接口响应格式(决定数据结构) |
|
||||
| DWD-DOC 标杆 | `docs/reports/DWD-DOC/` | 金额口径、字段语义权威参考 |
|
||||
| AI 应用骨架代码 | `apps/backend/app/ai/apps/app*.py` | 当前骨架实现 |
|
||||
| 百炼客户端 | `apps/backend/app/ai/bailian_client.py` | API 调用封装 |
|
||||
| 缓存服务 | `apps/backend/app/ai/cache_service.py` | ai_cache 读写 |
|
||||
| NS1 接口设计 | `docs/prd/Neo_Specs/NS1-xcx-backend-api.md` | 后端数据结构参考 |
|
||||
|
||||
---
|
||||
|
||||
## 七、预审查清单(SPEC 启动前确认)
|
||||
|
||||
### 7.1 数据结构
|
||||
|
||||
1. **消费记录字段范围**:`consumption_records` 中每条记录需要包含哪些字段?是否需要包含折扣信息(discount_manual/discount_other)?是否需要包含支付方式明细(balance_pay/cash_pay/online_pay)?
|
||||
2. **服务记录字段范围**:`service_history` 中每条记录需要包含哪些字段?是否需要包含台桌类型(room_category)和客户评价?
|
||||
3. **备注内容截断**:`all_notes` 中每条备注是否需要全文传入?长备注是否截断?截断长度?
|
||||
4. **会员卡明细粒度**:`member_cards` 是否需要包含卡号、开卡日期、有效期等详细信息,还是只需要卡类型和余额?
|
||||
|
||||
### 7.2 Prompt 优化
|
||||
|
||||
5. **Token 预算**:每个应用的首条 Prompt 的 token 上限是多少?百炼 API 的单次请求 token 限制?
|
||||
6. **数据时间窗口**:消费记录默认取近 3 个月,是否需要可配置?不同应用是否需要不同时间窗口?
|
||||
7. **空数据处理**:当客户无消费记录/无备注/无服务历史时,Prompt 如何处理?是否需要特殊提示词?
|
||||
|
||||
### 7.3 页面文本化(应用 1)
|
||||
|
||||
8. **文本化格式**:页面上下文是输出为结构化中文文本还是 JSON?AI 对哪种格式理解更好?
|
||||
9. **数据量控制**:每个页面上下文的字符上限?是否需要根据页面类型动态调整?
|
||||
10. **实时性要求**:应用 1 的页面上下文是否需要实时获取最新数据?还是可以使用缓存(如 task_detail_cache)?
|
||||
|
||||
### 7.4 性能与安全
|
||||
|
||||
11. **FDW 查询并发**:多个数据获取函数是否可以并发执行(asyncio.gather)?FDW 连接池是否支持?
|
||||
12. **数据脱敏**:传入百炼 API 的数据中,哪些字段需要脱敏?member_phone 已断档不传,还有其他敏感字段吗?
|
||||
13. **错误降级**:某个数据获取函数失败时(如 FDW 超时),是否跳过该部分继续生成 Prompt?还是整体失败?
|
||||
|
||||
---
|
||||
|
||||
## 八、任务清单(草案,SPEC 细化后调整)
|
||||
|
||||
### Batch A:共享数据获取层
|
||||
- [ ] T1:创建 `data_fetchers/member_data.py`(客户消费数据获取,应用 3/6/7 共用)
|
||||
- [ ] T2:创建 `data_fetchers/assistant_data.py`(助教信息 + 服务历史获取,应用 4/5 共用)
|
||||
- [ ] T3:创建 `data_fetchers/page_context.py`(页面上下文文本化框架,应用 1 专用)
|
||||
|
||||
### Batch B:Prompt 拼接实现
|
||||
- [ ] T4:完善 `app3_clue.py` 的 `build_prompt()`(客户消费数据 → 维客线索分析)
|
||||
- [ ] T5:完善 `app4_analysis.py` 的 `build_prompt()`(助教+客户数据 → 关系分析)
|
||||
- [ ] T6:完善 `app5_tactics.py` 的 `build_prompt()`(复用应用 4 数据 + task_suggestion)
|
||||
- [ ] T7:完善 `app6_note.py` 的 `build_prompt()`(备注+客户数据 → 备注分析)
|
||||
- [ ] T8:完善 `app7_customer.py` 的 `build_prompt()`(客户全量数据 → 运营策略)
|
||||
|
||||
### Batch C:应用 1 页面文本化 + 联调
|
||||
- [ ] T9:实现各页面类型的文本化函数(task-detail/customer-detail/board-*/performance 等)
|
||||
- [ ] T10:补充 `app1_chat.py` 的 `_build_page_context()` 调用文本化函数
|
||||
- [ ] T11:端到端联调(触发事件 → Prompt 拼接 → 百炼调用 → 缓存写入 → 前端展示)
|
||||
Reference in New Issue
Block a user