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

13 KiB
Raw Permalink Blame History

用户画像置信度实时更新开发计划

版本:v2.0
日期:2026-09-13
状态:待开发

1. 开发目标

用户完成风险问卷后,系统固定用户类型,并将初始画像置信度设置为 0.90。后续根据客服 Agent 已确认的对话证据和已确认的交易流水,实时调整当前画像置信度。

本功能有两个边界:

  1. 用户类型只允许保持不变,不能被对话或交易重新分类。
  2. 证据关系由 LLM 判断,置信度最终值由 BaseConfidenceCalcTool.update() 统一计算。

2. 最终业务流程

风险问卷完成
    -> 固定 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. 核心职责划分

原始数据读取器
    读取 Agent 记忆、对话归档、交易流水和产品信息

EvidenceBuilder
    将原始数据整理成统一证据输入

LLM EvidenceRelationJudge
    根据固定用户类型判断 support / conflict / neutral

BaseConfidenceCalcTool.update()
    使用当前已有 confidence 计算新的 confidence

ProfileConfidenceUpdater
    负责事务、并发锁、日志、缓存和事件状态

LLM 不直接写数据库,也不负责修改用户类型。

4. 用户画像规则

画像主表使用:

fin_customer_profile.risk_level
fin_customer_profile.confidence_score

问卷完成后:

risk_level = 问卷评定结果
confidence_score = 0.90

后续事件只能修改:

confidence_score
profile_version
update_time

禁止修改:

risk_level
risk_score

5. LLM 证据关系判断

5.1 判断目标

LLM 不是重新判断客户属于哪种类型,而是回答:当前这条证据,相对于已经固定的用户类型,是支持、冲突,还是无法判断?

允许的关系只有:

support   支持当前固定用户类型
conflict  与当前固定用户类型冲突
neutral   与类型无关、信息不足或无法判断

5.2 LLM 输入

对话证据输入示例:

{
  "user_type": "稳健型",
  "profile_definition": {
    "risk_tolerance": "低到中等",
    "principal_safety": "高",
    "return_preference": "稳定优先"
  },
  "evidence_source": "user_stated",
  "evidence": "我比较偏好本金安全,不希望本金出现明显亏损"
}

交易证据输入示例:

{
  "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:

{
  "relation": "support",
  "valid": true,
  "reason": "客户明确表达重视本金安全,与稳健型偏好低波动和本金保护的特征一致",
  "evidence_summary": "客户偏好本金安全"
}

输出字段:

relation          support / conflict / neutral
valid             true / false
reason            判断理由
evidence_summary  证据摘要

5.4 LLM Prompt 约束

用户类型已经确定,禁止修改用户类型。
只能判断当前证据与固定用户类型的关系。
只能返回 support、conflict 或 neutral。
信息不足、表达含糊或与风险偏好无关时返回 neutral。
不要根据证据重新分类用户。
必须返回 JSON,不输出额外文本。

5.5 判断示例

固定类型为“稳健型”:

“我比较偏好本金安全”
    -> support

“我可以接受本金大幅波动来追求高收益”
    -> conflict

“最近基金市场行情怎么样?”
    -> neutral

固定类型为“进取型”时:

“我比较偏好本金安全”
    -> conflict

同一条证据必须结合当前固定的 user_type 判断,不能脱离用户类型单独判断。

6. 统一证据结构

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 为空;判断后必须由程序校验:

ALLOWED_RELATIONS = {"support", "conflict", "neutral"}

if result.relation not in ALLOWED_RELATIONS:
    raise InvalidEvidenceResult()

7. 对话和交易证据

7.1 对话

数据来源:

  • memory_unit
  • conversation_archive

优先使用 Agent 已提取并确认的 memory_unit,避免直接处理全部原始对话。

Agent 对话
    -> Agent 提取画像事实
    -> memory_unit 写入或确认
    -> 生成画像证据事件
    -> LLM 判断证据关系

来源映射:

user_confirmed -> user_confirmed
user_stated    -> user_stated
ai_inferred    -> ai_inferred

7.2 交易

数据来源:

  • fin_transaction
  • fin_product

只有以下条件满足时才生成有效交易证据:

fin_transaction.status = 已确认
交易客户与画像客户一致
产品信息可读取

交易证据输入应包含:

交易类型、产品名称、产品类型、产品风险等级、交易金额、交易确认时间

待确认、风控挂起、已撤单、失败的交易不更新画像。

8. 置信度更新工具

8.1 保留现有 calc()

现有 calc() 继续保留,用于问卷初始化或长期记忆的完整重算。

8.2 新增 update()

BaseConfidenceCalcTool.update(
    current_confidence: float,
    source: str,
    relation: str,
    age_days: int = 0,
    threshold: float | None = None,
    calculated_at: datetime | None = None,
) -> ConfidenceResult

核心要求:

current_confidence 必须来自数据库当前值

更新规则:

support  -> 提高当前置信度
conflict -> 降低当前置信度
neutral  -> 不更新

计算结果必须限制在 0.0 到 1.0 之间。

返回结果建议包含:

ConfidenceResult(
    previous_confidence=...,
    confidence=...,
    confidence_delta=...,
    qualified=...,
    reason=...,
    model_version=...,
    calculated_at=...,
)

9. 事件触发机制

采用:

应用层事务 Outbox + 后台 Worker

9.1 对话触发

Agent 提取并确认画像事实
    -> 写入 memory_unit
    -> 同一事务写入 profile_confidence_event

9.2 交易触发

交易状态变为“已确认”
    -> 同一事务写入 profile_confidence_event

数据库 Trigger 不直接调用 LLM 或置信度工具。若未来存在绕过应用层的外部写库系统,再考虑增加数据库 Trigger 作为 Outbox 补充。

10. 事件表设计

建议新增:

profile_confidence_event

字段:

id
event_id
customer_id
category
source_type
source_record_id
status
retry_count
error_message
create_time
process_time

事件状态:

pending    待处理
processing 处理中
processed  已完成画像更新
ignored    无效或无关证据
failed     处理失败,可重试

增加唯一约束:

UNIQUE(event_id, category)

确保同一条对话或交易不会重复调整置信度。

11. Worker 处理流程

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 步必须在同一个数据库事务中完成。读取画像时使用:

SELECT *
FROM fin_customer_profile
WHERE customer_id = ?
FOR UPDATE;

12. 失败处理

LLM 超时或服务异常:

事件状态 = failed
retry_count + 1
保存 error_message
等待下次重试

LLM 返回格式错误或未知关系:

不更新画像
记录错误
事件进入 failed 或人工检查队列

LLM 判断为无关或无法判断:

relation = neutral
事件状态 = ignored
不修改 confidence_score

13. 数据库事务和缓存

画像更新、画像变更日志和事件状态更新必须在同一个 MySQL 事务中完成:

更新画像
写画像变更日志
标记事件 processed

事务成功提交后,再清理 Redis:

await CustomerProfileMemory().invalidate(customer_id)

14. 代码模块计划

14.1 置信度工具

文件:

tool/confidence.py

任务:

  • 新增 update()
  • 扩展 ConfidenceResult
  • 增加 support、conflict、neutral 测试
  • 保留 calc() 兼容现有长期记忆逻辑

14.2 LLM 证据判断器

建议新增:

service/profile_confidence/relation_judge.py

任务:

  • 维护 Prompt
  • 组织用户类型定义和证据输入
  • 调用 LLM
  • 解析结构化 JSON
  • 校验 relation、valid 和必填字段
  • 处理超时、格式错误和重试

14.3 证据服务

建议新增:

service/profile_confidence/evidence.py

任务:

  • 读取对话、Agent 记忆和交易流水
  • 统一转换为 ProfileEvidence
  • 生成稳定的 event_id

14.4 画像更新服务

建议新增:

service/profile_confidence/updater.py
service/profile_confidence/worker.py

任务:

  • 消费事件
  • 调用 LLM 判断关系
  • 调用 BaseConfidenceCalcTool.update()
  • 加锁更新画像
  • 写变更日志
  • 清理缓存
  • 更新事件状态

14.5 仓储和模型

需要新增或调整:

model/profile_confidence_event.py
model/fin_transaction.py
repositories/customer_profile.py
repositories/profile_confidence_event.py

任务:

  • 支持画像带锁查询
  • 支持置信度更新
  • 支持事件抢占和状态流转
  • 支持交易流水查询
  • 支持幂等约束

15. 测试计划

15.1 LLM 关系判断

固定类型为“稳健型”:

“偏好本金安全” -> support
“不能接受明显亏损” -> support
“可以承担大幅波动追求高收益” -> conflict
“最近基金行情怎么样” -> neutral

固定类型为“进取型”:

“偏好本金安全” -> 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. 开发顺序

第一阶段:实现 BaseConfidenceCalcTool.update()

第二阶段:实现 LLM EvidenceRelationJudge 和结构化输出校验

第三阶段:补充画像仓储的带锁读取和更新

第四阶段:新增 ProfileEvidence 和事件表

第五阶段:实现 Worker 及失败重试

第六阶段:接入 Agent 记忆确认流程

第七阶段:接入交易确认流程

第八阶段:接入画像变更日志和 Redis 缓存失效

第九阶段:补充幂等、并发和端到端测试

18. 第一版范围控制

第一版支持:

  • 固定用户类型:risk_level
  • 画像置信度:confidence_score
  • 证据来源:Agent 对话、已确认交易
  • LLM 关系判断:support / conflict / neutral
  • MySQL Outbox
  • 单 Worker 轮询
  • 画像更新日志

第一版暂不支持:

  • LLM 自动修改用户类型
  • 多类型概率分布
  • Kafka 或 RabbitMQ
  • 复杂多证据联合推理
  • 自动根据置信度重新分类客户