商品智能搜索失败归因分析技能-架构设计

商品智能搜索失败归因分析技能 - 架构设计

1. 技能概述

商品智能搜索失败归因分析技能(goods_search_fail_analysis)用于对大批量商品智能搜索失败数据进行自动化归因分析,输出可视化的 HTML 交互式报告。核心价值是将人工逐条排查失败原因的工作自动化,快速定位系统优化方向。

2. 目录结构

复制代码
goods_search_fail_analysis/
├── SKILL.md                                     # 技能说明文档
├── scripts/
│   └── analysis.py                              # 核心分析脚本
├── templates/
│   └── report_template.html                     # HTML 报告模板
├── prompt/
│   ├── match_fail_classification_prompt.md      # 分类提示词
│   ├── match_fail_detail_analysis_prompt.md     # 详细归因分析提示词
│   └── match_fail_subcluster_aggregation_prompt.md  # 子类聚合提示词
└── references/                                  # 业务知识库(略)

3. 业务架构

3.1 业务流程

复制代码
搜索失败数据 → 数据加载与分组 → 快速D类预筛 → 原因分类 → 子类聚合 → 抽样归因分析 → HTML报告生成

3.2 搜索失败原因分类体系

大类 编码 含义 典型场景
六要素书写不规范 A 入参数据在清洗阶段被"改坏"导致评分失败 规格被误清空、通用名被截断
召回异常 B ES 召回阶段未能返回相关候选数据 候选列表为空
评分过滤异常 C 已找到正确商品,但表述差异导致评分未达阈值 单位不等价(Ug vs μg)、大包装后缀
主数据缺失/其他 D 标品库中不存在与入参对应的商品 新上市规格、字段单边缺失

3.3 评分阈值体系

不同搜索来源有不同的字段评分阈值:

来源 通用名 规格 厂商 品牌
TEST_1 >60 >=70 >=80 >50
DEFAULT_CONSUMER >60 >70 >=80 >50
TEST_2 >60 >=80 - >=50

未定义的来源使用 DEFAULT_CONSUMER 阈值。

3.4 特殊分数含义

  • 81分:代表入参或库中数据某个字段值单边缺失(绝大部分情况为入参字段缺失),不是评分算法计算结果。

3.5 输入数据要求

输入为 CSV 或 Excel 文件,核心字段:

字段 说明
source 搜索来源编码
businessType 商品类型(药品、医疗器械、保健品等)
esDetail_originalParam 搜索原始入参(JSON)
esDetail_cleaning 字段清洗流水日志(JSON)
esDetail_candidates ES 召回候选数据及评分(JSON)

3.6 输出产物

  • HTML 交互式报告:按来源和商品类型分组展示分类分布、维度失败分布、子类详情及样本归因
  • Excel 导出(可选):搜索失败 case 数据、归因分析结果案例数据

4. 技术架构

4.1 整体流程图

复制代码
┌──────────────────────────────────────────────────────────────────┐
│                        数据加载与分组                              │
│  load_data() → _group_records_by_source_and_type()               │
└──────────────────────┬───────────────────────────────────────────┘
                       │ 按 source|businessType 分组
                       ▼
┌──────────────────────────────────────────────────────────────────┐
│              并发分组处理 (ThreadPoolExecutor)                      │
│                    _analyze_group()                                │
│                                                                    │
│  ┌────────────────────────────────────────────────────────────┐  │
│  │ Step 1: 快速D类预筛                                         │  │
│  │   quick_check_d_category()                                  │  │
│  │   - 规则1: 字段单边缺失(所有候选3+字段=81分)               │  │
│  │   - 规则2: 语义不一致(所有候选与入参语义不匹配)            │  │
│  └────────────────────────┬───────────────────────────────────┘  │
│                           ▼                                        │
│  ┌────────────────────────────────────────────────────────────┐  │
│  │ Step 2: 原因分类                                            │  │
│  │   LLM模式: _batch_classify_records() → 批量LLM调用          │  │
│  │   规则模式: _classify_by_rules() → 本地规则引擎              │  │
│  └────────────────────────┬───────────────────────────────────┘  │
│                           ▼                                        │
│  ┌────────────────────────────────────────────────────────────┐  │
│  │ Step 3: 子类聚合                                            │  │
│  │   generate_subclusters() → aggregate_subclusters()          │  │
│  │   使用LLM将细粒度子标签聚合为≤10个有意义的子类              │  │
│  └────────────────────────────────────────────────────────────┘  │
└──────────────────────┬───────────────────────────────────────────┘
                       ▼
┌──────────────────────────────────────────────────────────────────┐
│              统一批量归因分析 (所有分组)                             │
│  _batch_attribution_for_all_groups()                              │
│  - 从每个子类抽取 N 条样本                                        │
│  - 调用归因模型进行深度分析                                       │
│  - 输出 rootCause + suggestion + matchedCandidate                │
└──────────────────────┬───────────────────────────────────────────┘
                       ▼
┌──────────────────────────────────────────────────────────────────┐
│                    HTML 报告生成                                    │
│  generate_html_report() → 注入模板 → 输出交互式报告               │
└──────────────────────────────────────────────────────────────────┘

4.2 核心类:MatchFailAnalyzer

python 复制代码
class MatchFailAnalyzer:
    def __init__(self, data_path, api_key, api_base_url, max_workers,
                 classification_batch_size, attribution_batch_size,
                 llm_business_types, max_llm_classification_per_group,
                 classification_model_name, attribution_model_name,
                 num_attribution_samples)
关键参数
参数 默认值 说明
max_workers 5 最大并发线程数
classification_batch_size 5 分类阶段每批数据条数
attribution_batch_size 1 归因阶段每批数据条数
llm_business_types {"药品"} 使用LLM分析的商品类型
max_llm_classification_per_group 1000 每组最大LLM分类条数
num_attribution_samples 2 每子类抽取归因样本数

4.3 双模型策略

阶段 推荐模型 用途 特点
分类阶段 qwen-plus / gpt-3.5-turbo 批量原因分类、子类聚合 速度快、成本低
归因阶段 qwen-max / gpt-4 深度归因分析、优化建议 质量高、推理能力强

4.4 快速D类预筛算法

quick_check_d_category() 方法包含两条规则,按优先级执行:

规则1 - 字段单边缺失

  • 遍历所有候选数据
  • 检查6个评分字段(genericName, spec, manufacturer, approvalNum, tradeName, barcode)
  • 如果每条候选均有 ≥3 个字段评分为81分 → 归为D类

规则2 - 语义不一致

  • 对评分低于阈值且双方字段值非空的维度
  • 使用编辑距离计算语义相似度(阈值0.6)
  • 如果所有候选均与入参语义不一致 → 归为D类

4.5 LLM 调用链路

分类调用 (_classify_with_llm_batch)
复制代码
输入数据脱水(去除logs,仅保留前2条候选)
    → 填充 match_fail_classification_prompt.md
    → 调用分类模型
    → 解析JSON响应(含多策略容错)
    → 返回 [{index, mainLabel, subLabel}, ...]
归因调用 (_analyze_batch_detail)
复制代码
输入数据脱水(保留logs,仅保留前2条候选)
    → 填充 match_fail_detail_analysis_prompt.md
    → 调用归因模型
    → 解析JSON响应
    → 返回 [{index, rootCause, suggestion, matchedCandidate}, ...]
子类聚合调用 (aggregate_subclusters)
复制代码
收集所有子标签及其数量
    → 填充 match_fail_subcluster_aggregation_prompt.md
    → 调用分类模型
    → 合并相似子标签(最多保留10个)

4.6 并发模型

复制代码
                    ┌─── 分组1 ───┐
                    │              │
主线程 ──fork──────┼─── 分组2 ───┼──join──► 统一归因 ──fork──► 批次1
  (ThreadPool      │              │         (ThreadPool       ► 批次2
   max_workers)    └─── 分组N ───┘          max_workers)     ► 批次N
  • 分组级别:各 source|businessType 分组并发处理
  • 批次级别:分类和归因阶段内部按 batch_size 切分,并发调用 LLM
  • 线程安全:使用 threading.Lock 保护共享的性能统计数据

4.7 JSON 响应容错解析

_parse_llm_response() 实现6层容错策略:

  1. 直接 JSON 解析
  2. 清理 Markdown 代码块标记
  3. 提取 [...] 数组模式
  4. 逐对象 {...} 提取
  5. 修复常见 JSON 错误(尾逗号、未转义换行等)
  6. 完整字符串修复后重试

4.8 数据脱水策略

为节省 Token 消耗,发送给 LLM 的候选数据经过精简:

阶段 候选数量 包含 logs 说明
分类阶段 前2条 仅需值和分数判断类别
归因阶段 前2条 需要 logs 解释扣分原因

4.9 报告生成

使用 report_template.html 模板,注入分析结果生成单页交互式 HTML:

  • 按来源+商品类型分组展示
  • 客户端 JavaScript 实现分组筛选切换
  • 各大类(A/B/C/D)占比可视化
  • 维度失败分布统计
  • 子类展开/折叠详情
  • 样本6维度对比表格
  • 评分日志弹窗(Base64 编码传递)

5. 性能优化设计

优化手段 效果
快速D类预筛 无需LLM即可过滤大量D类数据,节省60-80% Token
双模型策略 分类用廉价模型,归因用高质量模型,成本降低50-70%
批量调用 减少API调用次数,降低网络开销
并发处理 分组级别+批次级别双重并发
数据脱水 分类阶段去除logs,减少Prompt长度
子类抽样 每子类仅抽取N条进行深度归因,避免全量分析
LLM分类上限 每组最多1000条进入LLM分类,超出直接归D类

6. 使用示例

bash 复制代码
# 规则引擎模式(无需API Key)
python analysis.py --data_path "data.xlsx" --output_path "report.html"

# 双模型 + 并发模式(推荐)
python analysis.py \
  --data_path "data.xlsx" \
  --output_path "report.html" \
  --api_key "sk-xxx" \
  --api_base_url "https://dashscope.aliyuncs.com/compatible-mode/v1" \
  --classification_model_name "qwen-plus" \
  --attribution_model_name "qwen-max" \
  --max_workers 10 \
  --classification_batch_size 10 \
  --attribution_batch_size 1 \
  --llm_business_types 药品 医疗器械

7. 依赖项

依赖 用途 必需
pandas + openpyxl Excel 读写 是(Excel输入时)
openai LLM API 调用 否(规则引擎模式无需)