Files
Mutual_Fund/开发计划_用户画像置信度实时更新.md
2026-09-14 11:54:20 +08:00

652 lines
13 KiB
Markdown
Raw Permalink 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.
# 用户画像置信度实时更新开发计划
版本:v2.0
日期:2026-09-13
状态:待开发
## 1. 开发目标
用户完成风险问卷后,系统固定用户类型,并将初始画像置信度设置为 `0.90`。后续根据客服 Agent 已确认的对话证据和已确认的交易流水,实时调整当前画像置信度。
本功能有两个边界:
1. 用户类型只允许保持不变,不能被对话或交易重新分类。
2. 证据关系由 LLM 判断,置信度最终值由 `BaseConfidenceCalcTool.update()` 统一计算。
## 2. 最终业务流程
```text
风险问卷完成
-> 固定 user_type
-> confidence_score = 0.90
交易状态变为“已确认”
-> 生成交易证据事件
Agent 提取并确认对话事实
-> 生成对话证据事件
Worker 消费证据事件
-> 读取固定 user_type 及其画像定义
-> 调用 LLM 判断 support / conflict / neutral
-> 校验 LLM 输出
-> neutral 或无效证据标记 ignored
-> 读取数据库当前 confidence_score
-> BaseConfidenceCalcTool.update()
-> 更新 confidence_score
-> 写入画像变更日志
-> 清理 Redis 画像缓存
-> 标记事件 processed
```
## 3. 核心职责划分
```text
原始数据读取器
读取 Agent 记忆、对话归档、交易流水和产品信息
EvidenceBuilder
将原始数据整理成统一证据输入
LLM EvidenceRelationJudge
根据固定用户类型判断 support / conflict / neutral
BaseConfidenceCalcTool.update()
使用当前已有 confidence 计算新的 confidence
ProfileConfidenceUpdater
负责事务、并发锁、日志、缓存和事件状态
```
LLM 不直接写数据库,也不负责修改用户类型。
## 4. 用户画像规则
画像主表使用:
```text
fin_customer_profile.risk_level
fin_customer_profile.confidence_score
```
问卷完成后:
```text
risk_level = 问卷评定结果
confidence_score = 0.90
```
后续事件只能修改:
```text
confidence_score
profile_version
update_time
```
禁止修改:
```text
risk_level
risk_score
```
## 5. LLM 证据关系判断
### 5.1 判断目标
LLM 不是重新判断客户属于哪种类型,而是回答:当前这条证据,相对于已经固定的用户类型,是支持、冲突,还是无法判断?
允许的关系只有:
```text
support 支持当前固定用户类型
conflict 与当前固定用户类型冲突
neutral 与类型无关、信息不足或无法判断
```
### 5.2 LLM 输入
对话证据输入示例:
```json
{
"user_type": "稳健型",
"profile_definition": {
"risk_tolerance": "低到中等",
"principal_safety": "高",
"return_preference": "稳定优先"
},
"evidence_source": "user_stated",
"evidence": "我比较偏好本金安全,不希望本金出现明显亏损"
}
```
交易证据输入示例:
```json
{
"user_type": "稳健型",
"profile_definition": {
"risk_tolerance": "低到中等",
"principal_safety": "高"
},
"evidence_source": "behavior_inference",
"evidence": {
"transaction_type": "申购",
"product_name": "某股票型基金",
"product_risk_level": "R5",
"transaction_status": "已确认"
}
}
```
### 5.3 LLM 输出
必须使用结构化 JSON:
```json
{
"relation": "support",
"valid": true,
"reason": "客户明确表达重视本金安全,与稳健型偏好低波动和本金保护的特征一致",
"evidence_summary": "客户偏好本金安全"
}
```
输出字段:
```text
relation support / conflict / neutral
valid true / false
reason 判断理由
evidence_summary 证据摘要
```
### 5.4 LLM Prompt 约束
```text
用户类型已经确定,禁止修改用户类型。
只能判断当前证据与固定用户类型的关系。
只能返回 support、conflict 或 neutral。
信息不足、表达含糊或与风险偏好无关时返回 neutral。
不要根据证据重新分类用户。
必须返回 JSON,不输出额外文本。
```
### 5.5 判断示例
固定类型为“稳健型”:
```text
“我比较偏好本金安全”
-> support
“我可以接受本金大幅波动来追求高收益”
-> conflict
“最近基金市场行情怎么样?”
-> neutral
```
固定类型为“进取型”时:
```text
“我比较偏好本金安全”
-> conflict
```
同一条证据必须结合当前固定的 `user_type` 判断,不能脱离用户类型单独判断。
## 6. 统一证据结构
```python
class ProfileEvidence:
event_id: str
customer_id: int
category: str
source: str
raw_content: dict | str
relation: str | None
valid: bool | None
reason: str | None
occurred_at: datetime
```
在 LLM 判断前,`relation` 和 `valid` 为空;判断后必须由程序校验:
```python
ALLOWED_RELATIONS = {"support", "conflict", "neutral"}
if result.relation not in ALLOWED_RELATIONS:
raise InvalidEvidenceResult()
```
## 7. 对话和交易证据
### 7.1 对话
数据来源:
- `memory_unit`
- `conversation_archive`
优先使用 Agent 已提取并确认的 `memory_unit`,避免直接处理全部原始对话。
```text
Agent 对话
-> Agent 提取画像事实
-> memory_unit 写入或确认
-> 生成画像证据事件
-> LLM 判断证据关系
```
来源映射:
```text
user_confirmed -> user_confirmed
user_stated -> user_stated
ai_inferred -> ai_inferred
```
### 7.2 交易
数据来源:
- `fin_transaction`
- `fin_product`
只有以下条件满足时才生成有效交易证据:
```text
fin_transaction.status = 已确认
交易客户与画像客户一致
产品信息可读取
```
交易证据输入应包含:
```text
交易类型、产品名称、产品类型、产品风险等级、交易金额、交易确认时间
```
待确认、风控挂起、已撤单、失败的交易不更新画像。
## 8. 置信度更新工具
### 8.1 保留现有 calc()
现有 `calc()` 继续保留,用于问卷初始化或长期记忆的完整重算。
### 8.2 新增 update()
```python
BaseConfidenceCalcTool.update(
current_confidence: float,
source: str,
relation: str,
age_days: int = 0,
threshold: float | None = None,
calculated_at: datetime | None = None,
) -> ConfidenceResult
```
核心要求:
```text
current_confidence 必须来自数据库当前值
```
更新规则:
```text
support -> 提高当前置信度
conflict -> 降低当前置信度
neutral -> 不更新
```
计算结果必须限制在 `0.0` 到 `1.0` 之间。
返回结果建议包含:
```python
ConfidenceResult(
previous_confidence=...,
confidence=...,
confidence_delta=...,
qualified=...,
reason=...,
model_version=...,
calculated_at=...,
)
```
## 9. 事件触发机制
采用:
```text
应用层事务 Outbox + 后台 Worker
```
### 9.1 对话触发
```text
Agent 提取并确认画像事实
-> 写入 memory_unit
-> 同一事务写入 profile_confidence_event
```
### 9.2 交易触发
```text
交易状态变为“已确认”
-> 同一事务写入 profile_confidence_event
```
数据库 Trigger 不直接调用 LLM 或置信度工具。若未来存在绕过应用层的外部写库系统,再考虑增加数据库 Trigger 作为 Outbox 补充。
## 10. 事件表设计
建议新增:
```text
profile_confidence_event
```
字段:
```text
id
event_id
customer_id
category
source_type
source_record_id
status
retry_count
error_message
create_time
process_time
```
事件状态:
```text
pending 待处理
processing 处理中
processed 已完成画像更新
ignored 无效或无关证据
failed 处理失败,可重试
```
增加唯一约束:
```text
UNIQUE(event_id, category)
```
确保同一条对话或交易不会重复调整置信度。
## 11. Worker 处理流程
```text
1. 抢占 pending 事件
2. 读取 Agent 记忆、对话或交易原始记录
3. 构造 LLM 输入
4. 调用 LLM EvidenceRelationJudge
5. 校验 JSON 和 relation 枚举
6. relation=neutral 或 valid=false 时标记 ignored
7. 锁定 fin_customer_profile
8. 读取当前 confidence_score
9. 调用 BaseConfidenceCalcTool.update()
10. 更新 confidence_score 和 profile_version
11. 写入 customer_profile_change_log
12. 提交数据库事务
13. 清理 Redis 画像缓存
14. 标记事件 processed
```
第 7 至第 12 步必须在同一个数据库事务中完成。读取画像时使用:
```sql
SELECT *
FROM fin_customer_profile
WHERE customer_id = ?
FOR UPDATE;
```
## 12. 失败处理
LLM 超时或服务异常:
```text
事件状态 = failed
retry_count + 1
保存 error_message
等待下次重试
```
LLM 返回格式错误或未知关系:
```text
不更新画像
记录错误
事件进入 failed 或人工检查队列
```
LLM 判断为无关或无法判断:
```text
relation = neutral
事件状态 = ignored
不修改 confidence_score
```
## 13. 数据库事务和缓存
画像更新、画像变更日志和事件状态更新必须在同一个 MySQL 事务中完成:
```text
更新画像
写画像变更日志
标记事件 processed
```
事务成功提交后,再清理 Redis:
```python
await CustomerProfileMemory().invalidate(customer_id)
```
## 14. 代码模块计划
### 14.1 置信度工具
文件:
```text
tool/confidence.py
```
任务:
- 新增 `update()`
- 扩展 `ConfidenceResult`
- 增加 support、conflict、neutral 测试
- 保留 `calc()` 兼容现有长期记忆逻辑
### 14.2 LLM 证据判断器
建议新增:
```text
service/profile_confidence/relation_judge.py
```
任务:
- 维护 Prompt
- 组织用户类型定义和证据输入
- 调用 LLM
- 解析结构化 JSON
- 校验 relation、valid 和必填字段
- 处理超时、格式错误和重试
### 14.3 证据服务
建议新增:
```text
service/profile_confidence/evidence.py
```
任务:
- 读取对话、Agent 记忆和交易流水
- 统一转换为 `ProfileEvidence`
- 生成稳定的 `event_id`
### 14.4 画像更新服务
建议新增:
```text
service/profile_confidence/updater.py
service/profile_confidence/worker.py
```
任务:
- 消费事件
- 调用 LLM 判断关系
- 调用 `BaseConfidenceCalcTool.update()`
- 加锁更新画像
- 写变更日志
- 清理缓存
- 更新事件状态
### 14.5 仓储和模型
需要新增或调整:
```text
model/profile_confidence_event.py
model/fin_transaction.py
repositories/customer_profile.py
repositories/profile_confidence_event.py
```
任务:
- 支持画像带锁查询
- 支持置信度更新
- 支持事件抢占和状态流转
- 支持交易流水查询
- 支持幂等约束
## 15. 测试计划
### 15.1 LLM 关系判断
固定类型为“稳健型”:
```text
“偏好本金安全” -> support
“不能接受明显亏损” -> support
“可以承担大幅波动追求高收益” -> conflict
“最近基金行情怎么样” -> neutral
```
固定类型为“进取型”:
```text
“偏好本金安全” -> conflict
```
还需测试:
- 模糊表达返回 `neutral`
- 非法枚举被拒绝
- 非 JSON 输出进入失败重试
- LLM 不得修改 `user_type`
### 15.2 置信度工具
- support 使用当前置信度向上更新
- conflict 使用当前置信度向下更新
- neutral 不更新
- 置信度始终在 `0.0~1.0`
- 时间衰减生效
- 不同来源使用不同来源权重
### 15.3 事件和事务
- 已确认交易生成事件
- 待确认交易不生成有效事件
- Agent 记忆确认后生成事件
- 重复事件不会重复更新
- 并发事件不会丢失更新
- 画像更新失败时事件不会标记为 processed
- LLM 失败后可以重试
- 更新成功后 Redis 缓存失效
## 16. 验收标准
1. 问卷完成后 `confidence_score = 0.90`。
2. LLM 只判断证据关系,不修改用户类型。
3. LLM 输出只能是 `support`、`conflict` 或 `neutral`。
4. Agent 有效对话证据可以实时更新置信度。
5. 已确认交易可以实时更新置信度。
6. `BaseConfidenceCalcTool.update()` 使用数据库中的当前置信度。
7. 无效或 `neutral` 证据不会更新画像。
8. 用户类型 `risk_level` 始终保持不变。
9. 同一事件重复消费不会重复调整置信度。
10. 并发事件不会造成置信度丢失。
11. 每次更新都能追溯到具体对话或交易。
12. 画像更新成功后事件才标记为 `processed`。
13. LLM 或数据库失败时事件可以重试。
14. 更新成功后 Redis 不会继续返回旧画像。
## 17. 开发顺序
```text
第一阶段:实现 BaseConfidenceCalcTool.update()
第二阶段:实现 LLM EvidenceRelationJudge 和结构化输出校验
第三阶段:补充画像仓储的带锁读取和更新
第四阶段:新增 ProfileEvidence 和事件表
第五阶段:实现 Worker 及失败重试
第六阶段:接入 Agent 记忆确认流程
第七阶段:接入交易确认流程
第八阶段:接入画像变更日志和 Redis 缓存失效
第九阶段:补充幂等、并发和端到端测试
```
## 18. 第一版范围控制
第一版支持:
- 固定用户类型:`risk_level`
- 画像置信度:`confidence_score`
- 证据来源:Agent 对话、已确认交易
- LLM 关系判断:`support / conflict / neutral`
- MySQL Outbox
- 单 Worker 轮询
- 画像更新日志
第一版暂不支持:
- LLM 自动修改用户类型
- 多类型概率分布
- Kafka 或 RabbitMQ
- 复杂多证据联合推理
- 自动根据置信度重新分类客户