amz_review_analyse/main_voc分析.md
OnesvmWhoops 91e6c47fc0 迁移 DeepSeek Chat API,并支持本地 Qwen3 Embedding 向量化。
统一 voc_llm 密钥解析与默认模型;向量化改为本地 mlx 模型;更新 README、gitignore 与流水线文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 16:15:03 +08:00

14 KiB
Raw Blame History

main_voc分析.py 说明文档

VOC(Voice of Customer)分析全流程编排入口:合并原始 CSV → 清洗 → LLM 结构化 → 向量化 →(聚类 + 词频)→ 生成 HTML 报告。

本文档与 main_voc分析.py 同目录放置,风格对齐 prompts/README.md(表格 + 可执行示例 + 路径约定)。


1. 流程总览

flowchart LR
  S1[步骤1 合并CSV] --> S2[步骤2 清洗]
  S2 --> S3[步骤3 结构化 LLM]
  S3 --> S4[步骤4 向量化 API]
  S4 --> S5[步骤5 聚类 UMAP+HDBSCAN]
  S4 --> S6[步骤6 词频 spaCy+LLM]
  S5 --> S7[步骤7 报告 HTML]
  S6 --> S7
步骤 模块 是否调用 DashScope API
1 合并评论数据.py 否
2 content清洗.py 否
3 结构化_server.py 是(Chat 结构化;默认 8 路批间并行)
4 向量化.py 是(Embedding;默认 8 路批间并行)
5–6 聚类.py ∥ 词频.py 是(聚类调参评估 + 词频术语提取)
7 voc_report.py 是(报告撰写、词频分类、翻译等)

步骤 5 与 6 在 from_step ≤ 5 且两步均需执行时,由 ThreadPoolExecutor(max_workers=2) 并行运行。


2. 命令行输入 / 输出

2.1 输入(CLI 参数)

参数 必填条件 默认值 说明
--input-dir 是 — 原始 VOC评论数据文件 CSV 目录(目录内的所有*.csv 表头须一致)
--industry 是 Pet Supplies 行业名,写入结构化任务
--product 是 — 产品名
--merged-csv 否 merged_reviews.csv 步骤 1 输出路径
--cleaned-csv 否 merged_reviews_cleaned.csv 步骤 2 输出路径
--from-step N 否 1 从第 N 步执行到结束(N=1…7)
--only-step N 否 — 仅执行第 N 步(需已有前置产物)
--keep-db 否 默认会清理库 保留已有三个 .sqlite,不覆盖删除
--clean-intermediates 否 关闭 步骤 7 成功后删除中间 csv/sqlite,仅保留报告目录
--skip-wordfreq-llm 否 关闭 词频复用已有 output/voc_terms.json,跳过 LLM 术语提取
--filter-small-clusters 否 关闭 报告仅纳入簇内去重评论占比 ≥ 10% 的簇
--save-llm-raw 否 关闭 将报告 LLM 完整原文写入 {product}_voc_report.html 同目录 report_llm_raw.txt
--struct-workers 否 8(VOC_STRUCT_WORKERS) 步骤 3 结构化批间并行 Chat 请求数
--embed-workers 否 8(VOC_EMBED_WORKERS) 步骤 4 向量化批间并行 Embedding 请求数

2.2 输出

标准输出(stdout):流程结束后打印 JSON 字典(ensure_ascii=False),键随实际执行步骤变化,常见字段:

键 含义
merged_csv 合并后 CSV 路径
cleaned_csv 清洗后 CSV 路径
structured_job_id 结构化任务 ID
structured_db voc_structured.sqlite
embed 向量化模块返回信息(含 job_id 等)
clustering 聚类模块返回信息
wordfreq 词频模块返回信息
report_html 报告 HTML 绝对/相对路径
report generate_report 返回值

磁盘产物(项目根为 PROJECT_ROOT,即本文件所在目录):

路径 产生步骤 说明
merged_reviews.csv 1 多文件纵向合并
merged_reviews_cleaned.csv 2 清洗、去重后的评论
voc_structured.sqlite 3 结构化任务与逐条提取结果
voc_embeddings.sqlite 4 各实体短语 256 维向量
voc_clustering.sqlite 5 多阶段 UMAP+HDBSCAN 簇标签
output/voc_terms.json 6 LLM 归纳的产品专有名词 / 停用词
output/word_freq.csv 6 全量词频表(word, count)
output/{product}/{product}_voc_report.html 7 最终 VOC 分析报告(产品名经路径安全化)

{product} 目录名由 _safe_product_dir_name 生成:去除 <>:"/\|?* 等非法字符。

2.3 常用命令

cd "/Users/onesvmwhoops/Cursor_Project/VOC_LLM结构化"

# 全流程(默认写入 sqlite 前会清理旧库;加 --keep-db 则保留)
./310py/bin/python main_voc分析.py --input-dir "某目录" --product "产品名"

# 从步骤 4 续跑(product 可省略)
./310py/bin/python main_voc分析.py --from-step 4 --keep-db

# 仅重跑词频 LLM 之前的 spaCy 统计
./310py/bin/python main_voc分析.py --from-step 6 --skip-wordfreq-llm

# 仅生成报告
./310py/bin/python main_voc分析.py --only-step 7

2.4 程序式调用

from main_voc分析 import run_voc_analysis  # 别名 run_pipeline

result = run_voc_analysis(
    input_dir=Path("reviews_export"),
    industry="Pet Supplies",
    product_name="cat deterrent indoor",
    merged_csv=Path("merged_reviews.csv"),
    cleaned_csv=Path("merged_reviews_cleaned.csv"),
    from_step=1,
    clean_databases=True,  # 对应 CLI 未加 --keep-db
)

3. 七步数据流与数学 / 算法

步骤 1:合并 CSV(合并评论数据.py)

  • 输入:目录内表头一致的 *.csv。
  • 方法:pandas.concat 纵向合并;表头不一致则报错。
  • 输出:单表 merged_reviews.csv(utf-8-sig)。

步骤 2:清洗(content清洗.py)

  • 输入:合并 CSV,正文列 content(或兼容列名由下游结构化处理)。
  • 方法(规则型,无机器学习):
    • 去空行、亚马逊媒体占位文案、HTML 实体、常见噪声前缀;
    • 保留含字母/数字的行的词数 ≥ 4;
    • 按 content 去重(keep="first")。
  • 输出:merged_reviews_cleaned.csv。

步骤 3:结构化(结构化_server.py + 结构化_Prompt.py + prompts/)

  • 输入:清洗 CSV、industry、product_name。
  • 方法:DeepSeek Chat Completions(默认 deepseek-v4-pro,思考关闭),按输入 token 与条数动态分批(默认单批估算输入 ≤ 200K、最多 200 条/批,VOC_STRUCT_BATCH_MAX_REVIEWS 可覆盖);从评论中提取 JSON 字段(以 prompts/schema.yaml 为准)。
  • 输出:voc_structured.sqlite(analysis_jobs、comment_extractions)。

步骤 4:向量化(向量化.py + local_embedding.py)

  • 输入:最新或指定 job_id 的结构化实体;embed_text 由 audience / pain_point / aspect / opinion / aspect_opinion 等展开。
  • 方法:
    • 本地 MLX:Qwen3-Embedding-4B-mxfp8(默认 2560 维,L2 归一化);
    • 存储:float32 打包为 BLOB(struct.pack);
    • 默认批大小 16、串行推理(VOC_EMBED_BATCH_SIZE);M4 16GB 实测峰值约 1.5GB。
  • 输出:voc_embeddings.sqlite(embedding_items)。
  • 运行:推荐 ./310py/bin/python(Python 3.10+)。

步骤 5:聚类(聚类.py)

  • 输入:voc_embeddings.sqlite 中向量与元数据。

  • 核心数学管线(对每个聚类 stage 的子集):

    1. UMAP 降维(umap-learn)

      • n_components = min(30, n-2)
      • metric = cosine
      • min_dist = 0.1
      • random_state = 42
      • n_neighbors 由自动调参循环递增(初值 10,上限 45)
    2. HDBSCAN(hdbscan)

      • min_samples = 1,cluster_selection_method = eom
      • 初始 min_cluster_size = max(2, n // 20),若簇数 > 20 则增大 min_cluster_size 直至 ≤ 20 或无法再增
      • 标签 -1 表示离群点(各 stage 是否参与后续见模块内注释)
    3. 轮廓系数(sklearn.metrics.silhouette_score)

      • 在 UMAP 空间、非离群点上计算;用于早停:连续 8 轮中后 7 轮均低于窗口首值则回退轮廓最高的一轮。
    4. LLM 聚类质量评估(非传统指标,辅助调参)

      • 对各簇抽样短语,统计「跨簇语义相似」比例;> 10% 则继续增大 n_neighbors;≤ 10% 且轮廓 > 0.6 则停止。
  • 特例:子集样本数 n < 10 时不跑 HDBSCAN,每条独立簇 0..n-1。

  • 输出:voc_clustering.sqlite(多 stage:如 audience、簇内 pain_point、按情感分桶的 aspect_opinion 等)。

步骤 6:词频(词频.py)

  • 第 1 步(LLM):固定种子 SAMPLE_SEED=42 随机 25 条 content,归纳产品专有名词与专属停用词 → output/voc_terms.json。
  • 第 2 步(spaCy):
    • 英文分词与停用词过滤(含 EN stop words + 自定义停用词);
    • 专有名词按完整短语计数(protected spans);
    • 词形归并:_merge_word_forms 将复数/时态等 lemmatize 后合并计数;
    • 纯数字词剔除。
  • 输出:output/word_freq.csv。

步骤 7:报告(voc_report.py + prompts/report/)

  • 输入:voc_clustering.sqlite、voc_embeddings.sqlite、merged_reviews_cleaned.csv、word_freq.csv、可选 voc_structured.sqlite。
  • 方法:
    • 从库中聚合各 stage 簇与代表短语;
    • 多次 LLM 调用生成分析正文、词频六类归类、短语翻译等;
    • 词云字号:count^0.5 映射到 [14, 96] px;
    • 可选 min_cluster_review_ratio(默认 0.10)过滤小簇。
  • 输出:output/{product}/{product}_voc_report.html(内嵌词云、词频表、AI 报告、分簇表述)。

4. API Key 与模型

Chat(步骤 3 / 5 / 6 / 7)

统一经 voc_llm.py,默认 deepseek-v4-pro(chat_extra_body 关闭思考),https://api.deepseek.com。步骤 7 主报告在 voc_report.py 单独使用 Pro + reasoning_effort=max。

密钥优先级:

  1. DEEPSEEK_API_KEY
  2. DEEPSEEK_API_KEY_FILE
  3. 项目根 .deepseek_key

可选:DEEPSEEK_MODEL、DEEPSEEK_BASE_URL。

模块 用途
结构化_server.py 评论结构化
聚类.py 簇质量评估与调参
词频.py 专有名词 / 停用词
voc_report.py 报告、词频分类、翻译

Embedding(步骤 4)

无需 API Key。本地目录 Qwen3-Embedding-4B-mxfp8(或 VOC_EMBED_MODEL_PATH)。

仓库安全规范(见 .gitignore):

  • 禁止提交 .deepseek_key、.dashscope_key、voc_structured.sqlite 及含真实评论/密钥的敏感导出;
  • 密钥仅通过环境变量或本机未跟踪文件提供;
  • 文档与代码中勿写入真实 sk- 密钥。

5. 各模块职责

文件 职责
main_voc分析.py 七步编排、断点续跑、库清理策略、步骤 5/6 并行、CLI
合并评论数据.py 目录多 CSV 合并为一张表
content清洗.py 评论正文清洗、过滤、去重
结构化_server.py LLM 结构化入库、job 管理、库清理钩子
结构化_Prompt.py 组装结构化 prompt(被 server 动态加载)
向量化.py 结构化实体 → 256 维向量库
聚类.py UMAP + HDBSCAN 多阶段聚类 + LLM 调参
词频.py LLM 术语 + spaCy 全量词频
voc_report.py 聚类/词频/原文 → 单页 HTML 报告
prompts/ 可编辑 prompt 与 schema.yaml(见 prompts/README.md)
main_voc分析_jieba.py 可选变体入口:词频走 词频_jieba.py(jieba 分词),其余步骤与主流程类似

main 内主要函数

函数 作用
run_voc_analysis / run_pipeline 核心流水线
_should_run 根据 --from-step / --only-step 判断是否执行某步
_latest_job_meta 从结构化库读最新 job_id、industry、product_name
_resolve_industry_product CLI 下 product 自动补全
_clean_intermediates --clean-intermediates 时删除中间文件
_report_html_path 计算报告 HTML 路径

6. SQLite 与路径约定

库文件 写入步骤 主要内容
voc_structured.sqlite 3 analysis_jobs、comment_extractions
voc_embeddings.sqlite 4 embedding_items(向量 BLOB + 实体元数据)
voc_clustering.sqlite 5 各 stage 簇标签、调参日志、过滤元数据

默认清理策略(未加 --keep-db):

  • 步骤 3 运行 run_analysis(clean_databases=True) 时清理三个 sqlite(结构化写入逻辑见 结构化_server.py);
  • 步骤 4 若未重跑步骤 3,main 会单独删除 voc_embeddings.sqlite 与 voc_clustering.sqlite 再向量化;
  • 步骤 5/6 的 reset_db 与 clean_databases 联动。

行号溯源:结构化与向量化的 source_row 为 CSV 首条数据行为 1;对应 merged_reviews_cleaned.csv 物理行号 = source_row + 1(第 1 行为表头)。


7. 依赖与环境

cd "/Users/onesvmwhoops/Cursor_Project/VOC_LLM结构化"
uv venv 310py --python 3.12   # 与 .gitignore 中 310py/ 一致
uv pip install --python 310py/bin/python -r requirements.txt
# uv 虚拟环境无 pip,勿用「python -m spacy download」;直接装模型 wheel:
uv pip install --python 310py/bin/python "en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl"
export DEEPSEEK_API_KEY="sk-xxx"                   # 或配置 .deepseek_key(勿提交)
# 向量化推荐:./310py/bin/python main_voc分析.py ...

requirements.txt 中与数学/ NLP 相关的主要包:numpy、umap-learn、hdbscan、scikit-learn、spacy、openai、pyyaml。


8. 维护说明

  • 修改 LLM 话术:编辑 prompts/ 下对应 .md,勿改 schema.yaml 中 report.markers 四段标记名(见 prompts/README.md)。
  • 修改主流程步骤顺序或默认路径:改 main_voc分析.py 后请同步更新本文档。
  • 验收 prompt 加载:./310py/bin/python prompts/smoke.py(无需 Key);联调模型:./310py/bin/python prompts/smoke.py --live。

文档版本:与仓库 main_voc分析.py 七步流程一致。