Files
Neo-ZQYY/docs/prd/Neo_Specs/NS2-ai-prompt-refinement.md

522 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NS2AI 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-7member_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 应用 1biz_params 权限隔离(已实现,需确认)
> ✅ RNS1.4 已在 `app1_chat.py` 的 `_build_system_prompt()` 中实现 biz_params 拼接。
应用 1 通过 `biz_params.user_prompt_params` 向百炼 AI 传入用户身份信息,实现数据查询隔离:
```python
system_content = {
"task": "你是台球门店的 AI 助手...",
"biz_params": {
"user_prompt_params": {
"User_ID": str(user_id),
"Role": role, # "助教" | "管理者"
"Nickname": nickname,
},
},
}
```
权限控制规则(百炼平台侧执行):
- 助教身份:仅允许查询与该助教相关的数据,禁止查询其他助教业绩/工资/客户关系等敏感数据,禁止查询门店级财务数据
- 管理者身份:可查询该门店下所有数据
- 所有查询必须包含 `site_id` 过滤
NS2 需确认事项:
- 前端调用 `POST /api/chat/conversations/:id/messages` 时,是否正确传入 `user_id`/`role`/`nickname`
- 后端从 JWT token 中提取用户信息并传入 `_build_system_prompt()`,确保不可伪造
### 3.7 应用 1页面上下文传递与文本化
#### 当前问题P5 PRD 与 RNS1.4 实现的差异)
P5 PRD 原始设计:
```
前端跳转 chat.html 时传入 source_page + page_context + screen_content
→ 后端接收后文本化 → 拼接为首条 user message
```
RNS1.4 当前实现:
```
前端跳转 chat 页面时仅传入 contextType + contextId如 task/12345
→ 后端 _build_page_context() 为占位实现page_context 和 screen_content 为空
→ AI 无法获得页面上下文
```
#### 解决方案:后端根据 contextType 自动获取页面上下文
采用方案 B简化前端后端自动查询与 RNS1.4 已有的 `contextType`/`contextId` 参数兼容:
```
前端传入 contextType="task-detail" + contextId="12345"
→ 后端 build_page_text("task-detail", 12345, site_id)
→ 后端从数据库获取任务详情、客户信息、备注、AI 分析等
→ 格式化为结构化中文文本
→ 拼接为首条 user message 的 page_context 字段
```
#### contextType 映射表
| 前端 contextType | 后端数据获取 | 文本化内容 |
|-----------------|-------------|-----------|
| `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 | 个人信息摘要 |
| `task-list` | 长按的任务摘要 + 客户-助教关系 | 任务概要 |
| `customer-service-records` | 服务记录列表 | 服务记录摘要 |
#### 前端需要补充的参数
当前前端仅传 `contextType` + `contextId`,对于看板类页面需要额外传入筛选条件:
| contextType | 必传参数 | 可选参数 |
|-------------|---------|---------|
| `task-detail` | contextIdtaskId | — |
| `customer-detail` | contextIdmemberId | — |
| `coach-detail` | contextIdassistantId | — |
| `board-finance` | — | `timeDimension`(时间维度)、`areaFilter`(区域筛选) |
| `board-customer` | — | `dimension`(排序维度)、`typeFilter`(类型筛选) |
| `board-coach` | — | `dimension``projectFilter``timeDimension` |
| `performance` | — | `timeDimension` |
| `task-list` | contextIdtaskId | — |
| `my-profile` | — | — |
#### 实现要点
- 每个页面类型对应一个文本化函数,在 `data_fetchers/page_context.py` 中实现
- 文本化输出为结构化中文描述(非 JSON便于 AI 理解上下文
- 数据量控制:每个页面上下文不超过 2000 字符,避免 token 浪费
- 敏感信息脱敏:不传入 member_phone 等断档字段
- 看板类页面:若前端未传筛选条件,使用默认值(如 board-finance 默认"本月"
- 错误降级数据获取失败时page_context 传入"页面上下文获取失败",不阻断对话
---
## 四、数据库审查
### 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 入口
→ 前端传入 contextType + contextId+ 可选筛选参数)
→ 后端 build_page_text(contextType, contextId, site_id, filters?)
→ 从数据库获取对应页面数据,格式化为结构化中文文本
→ 拼接为首条 user message 的 page_context 字段
→ 注入 biz_paramsUser_ID/Role/Nickname到 system prompt
→ SSE 流式调用百炼 API
```
> ⚠️ 与 P5 PRD 原始设计的差异P5 设计为前端传入 `source_page` + `page_context` + `screen_content`
> RNS1.4 实际实现为前端传入 `contextType` + `contextId`,后端自动查询数据库获取上下文。
> NS2 沿用 RNS1.4 方案(后端自动获取),不要求前端传入原始页面数据。
---
## 六、参考文档
| 文档 | 路径 | 用途 |
|------|------|------|
| P5 AI 集成 spec | `docs/prd/specs/P5-miniapp-ai-integration.md` | Prompt JSON 结构定义、调用链时序 |
| AI 应用 Prompt | `docs/prd/ai-app-prompts.md` | 8 个应用的 System Prompt、biz_params 定义 |
| AI 需求文档 | `docs/prd/AI需求2.md` | 8 个应用的详细需求表、传参格式 |
| AI 应用→页面映射 | `docs/reports/2026-03-20__ai_app_page_mapping.md` | 各应用输出内容在哪个页面的什么位置展示 |
| API 契约 | `docs/miniprogram-dev/API-contract.md` | 接口响应格式(决定数据结构) |
| DWD-DOC 标杆 | `docs/reports/DWD-DOC/` | 金额口径、字段语义权威参考 |
| AI 应用骨架代码 | `apps/backend/app/ai/apps/app*.py` | 当前骨架实现(含 biz_params 已实现) |
| 百炼客户端 | `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` | 后端数据结构参考 |
| RNS1.4 任务计划 | `.kiro/specs/rns1-chat-integration/tasks.md` | 当前 chat 模块实施进度 |
---
## 七、预审查清单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. **文本化格式**:页面上下文是输出为结构化中文文本还是 JSONAI 对哪种格式理解更好?
9. **数据量控制**:每个页面上下文的字符上限?是否需要根据页面类型动态调整?
10. **实时性要求**:应用 1 的页面上下文是否需要实时获取最新数据?还是可以使用缓存(如 task_detail_cache
### 7.4 性能与安全
11. **FDW 查询并发**多个数据获取函数是否可以并发执行asyncio.gatherFDW 连接池是否支持?
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 BPrompt 拼接实现
- [ ] 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()` 调用文本化函数,根据 `contextType` 路由到对应文本化函数
- [ ] T11前端补充看板类页面的筛选参数传递board-finance/board-customer/board-coach 跳转 chat 时传入当前筛选条件)
- [ ] T12确认 biz_params 端到端正确性(前端 JWT → 后端提取 user_id/role/nickname → system prompt 注入 → 百炼权限隔离生效)
### Batch D联调与验证
- [ ] T13端到端联调触发事件 → Prompt 拼接 → 百炼调用 → 缓存写入 → 前端展示)
- [ ] T14应用 1 页面上下文联调(各入口页面 → contextType/contextId → 后端文本化 → AI 对话验证上下文感知)