README.md 11 KB

fixed_query_eval · 固定 Query 搜索评估

search_eval/ 下新建的自包含模块。用写死的 4 组 query(不走动作×类型正交矩阵选词), 对每组 query 做「同义扩展 + 多渠道搜索 + 合并去重 + LLM 评分」,并提供一个去掉矩阵的查看界面。

不改动任何原 search_eval/ 文件——搜索/评估引擎全部 import 复用,server/index 是复制后改造。


1. 这个模块做什么

4 组写死的 query(产品名 + 意图词)
   │  产品名锁死,只对意图词扩同义(评测→测评/实测/体验;案例→作品/效果/实例)
   ▼
每组多措辞 × 3 渠道(xhs/x/gzh) 各搜 10 条
   │  search_all 内建按 (platform, cid) 去重 + found_by_queries 记录命中措辞
   ▼
合并去重后的帖子池 → 视频转写 → LLM 多模态评分(同 search_eval 的 rubric)
   ▼
runs_full/q000N/form_A.json  →  server.py(:8770) 卡片界面浏览/筛选/排序/工序提取

与原 batch_3forms.py 的区别:不生成 query、不做 A/B/C 三形式对比,只用固定 4 组 query 直接搜,单一形式(沿用 form_A 字段名让前端零改动)。


2. 文件结构

fixed_query_eval/
├── run_search.py    ★ 生产脚本:固定 query + 同义扩展 + 合并去重 + 评分 → runs_full/
├── tool_extract.py  ★ 工具解构:帖子 → 结构化工具知识条目(gemini-3.1-flash-lite)
├── server.py        查看后端(复制自 ../server.py + 加 sys.path + 工具解构端点;矩阵自动降级)
├── index.html       查看前端(删正交矩阵 + 4-query 选择条 + 工具解构按钮/弹层/详情 tab)
├── runs_full/       产出目录
│   └── q000N/
│       ├── form_A.json          搜索+评分结果
│       └── tools/{case_id}.json  工具解构结果(每帖一份)
└── README.md        本文件

3. 改 query / 同义词(最常改的地方)

全部集中在 run_search.py 顶部常量,改完直接重跑:

QUERIES = [
    {"id": "q0000", "product": "GPT image2",      "intent": "评测"},
    {"id": "q0001", "product": "GPT image2",      "intent": "案例"},
    {"id": "q0002", "product": "nano banana pro", "intent": "评测"},
    {"id": "q0003", "product": "nano banana pro", "intent": "案例"},
]
INTENT_SYNONYMS = {
    "评测": ["评测", "测评", "实测", "体验"],     # 产品名 + 这些词分别搜,再合并去重
    "案例": ["案例", "作品", "效果", "实例"],
}
DEFAULT_PLATFORMS = "xhs,x,gzh"
DEFAULT_MAX_COUNT = 10   # 每条措辞每渠道取帖数(默认 10,控制成本)

加产品 / 加意图词:往 QUERIES 加条目即可;新意图词记得在 INTENT_SYNONYMS 配同义(没配则原样单条搜)。


4. 怎么跑

cd examples/process_pipeline/script/search_eval/fixed_query_eval

# ① 跑搜索 + 评分(已存在 form_A.json 的 query 默认跳过)
python run_search.py                       # 全部 4 组
python run_search.py --only-q q0,q2        # 只跑指定
python run_search.py --force               # 覆盖重跑
python run_search.py --no-eval             # 只搜不评分(省钱,验证召回用)

# ② 起查看界面(端口 8770,与原 search_eval server 同端口,别同时开)
python server.py                           # http://0.0.0.0:8770

run_search.py 主要参数:--platforms --max-count --eval-model(默认 gemini-flash-lite) --max-concurrent --no-transcribe --no-images --only-q --force


5. 查看界面(server.py :8770)

复用原 search_eval 界面的全部功能,只去掉正交矩阵:

  • 顶部 Query 选择条(4 组 query,替代原矩阵导航)→ 点击切换看某组结果
  • 渠道 tab(全部 / 小红书 / X / 公众号)
  • 卡片:标题 / 配图 / 互动数 / 知识类型标签
  • 评分详情弹窗、相关性过滤阈值、综合分排序
  • 「重评当前 query」「工序提取」按钮保留

接口(与原 server 一致):GET /api/dataPOST /api/generate_procedurePOST /api/reevalGET /api/procedure_statusGET /api/procedure_log


5.5 工具解构(从帖子提取结构化工具知识)

把帖子(正文 + 配图)里提到的工具,用 gemini-3.1-flash-lite 提炼成结构化条目,每个工具一条。

两个入口

  • 批量:query 选择条上「🔧 工具解构」按钮 → 弹层勾选「当前 query + 当前渠道」的帖子 → 确认 → 后台批量解构。
  • 单帖:帖子详情弹窗的「工具解构」tab(在「对应工序」后面)→ 未解构则「开始解构」,已解构则展示工具卡片。

解构结果字段(每个工具):工具名称 / 实质作用域 / 形式作用域 / 创作层级(制作层·创作层)/ 来源链接 / 输入 / 输出 / 用法 / 案例 / 缺点 / 最新更新时间。null 字段在 UI 自动省略。

版本(多版本共存):每次解构生成一个版本号 v_月日时分(如 v_06102158),保留历史不覆盖。详情页工具头部有「版本下拉」可切回历史版本对比(改了 prompt 后重新解构,能看不同版本)。默认显示最新版本。

展示:工具头部「卡片视图 / 表格视图」切换;表格列对应 fqe_tools 字段。案例 字段为结构化对象数组 [{输入,输出,效果}],卡片/表格均按结构渲染。

实现要点

  • Prompt 外置:解构 prompt 在 prompts/tool_extract_system.md(不塞代码里,便于单独迭代);tool_extract.py 启动时读取。
  • tool_extract.py 单次多模态 LLM 调用(正文 + 配图),比工序解构(多轮 agent)轻得多;复用引擎的收图 / 帖子格式化 / JSON 重试封装。
  • 模型固定 google/gemini-3.1-flash-litebuild_eval_llm_call("gemini-flash-lite"),OpenRouter 后端);评分筛选用的也是 OpenRouter,与之一致。
  • 结果存 runs_full/{q}/tools/{case_id}.json已解构默认跳过(详情页「重新解构」可强制覆盖)。
  • server 走 subprocess 起 tool_extract.py(同工序解构模式),LLM 重依赖留子进程,server 本身保持轻量。

相关接口:POST /api/extract_tools {q, case_ids[], force?}GET /api/tools_status?q=&case_id=GET /api/tools_data?q=&case_id=

手动跑(一般由界面触发):

python tool_extract.py --q q0000 --case-ids xhs_abc,gzh_def [--force]

6. 产出结构(runs_full/q000N/form_A.json)

{
  "form": "A",
  "query": "GPT image2 评测",          // 评估锚点(用户真实意图)
  "original_q": "GPT image2 评测",     // server 用作 query 标签
  "phrasings": ["GPT image2 评测", "GPT image2 测评", "GPT image2 实测", "GPT image2 体验"],
  "platforms": ["xhs", "x", "gzh"],
  "total": 80,
  "results": [ /* 去重池:帖子 + llm_evaluation + found_by_queries(哪些措辞命中)*/ ]
}

schema 与 batch_3forms.py 完全一致,所以本目录 server/index 与原版数据契约相同。


6.5 数据库存储(双写 MySQL)

搜索/评分结果和工具解构结果在落本地 json 的同时写入 MySQL(.envMYSQL_*,host rm-t4n…,库 agent-…)。

两张表db.py 自动建,幂等):

  • fqe_posts —— 每行一个 (query, 帖子):q / query_text / case_id / platform / title / url / body / images / like_count / publish_time / found_by / knowledge_type / overall_score / llm_evaluation。唯一键 (q, case_id),重跑 upsert 不重复。
  • fqe_tools —— 每行一个解构出的工具:q / case_id / 工具名称 / 实质作用域 / 形式作用域 / 创作层级 / 来源链接 / 输入 / 输出 / 用法 / 案例 / 缺点 / 最新更新时间 / model。重新解构按 (q, case_id) 先删旧再插新。

特性

  • 双写:DB 是附加存储,本地 json 仍是查看界面的主数据源;DB 写入失败不阻断(打印告警,本地 json 已落盘)。
  • 本地清空时自动回退读库server.pyscan_runs() 先读本地 runs_full/*/form_A.json本地缺的 query 自动从 fqe_posts;详情页工具 tab(/api/tools_data)本地无结果时也回退读 fqe_tools。所以即使 runs_full 被清空,界面仍能从库展示数据(本地优先)。
  • 从库重建本地python db.py rebuild —— 把库里数据写回本地 runs_full/{q}/form_A.jsontools/{case_id}.json。界面回退只让「看」有数据,但提取脚本(tool_extract / 工序)仍读本地文件,故本地文件丢失后用此命令完整恢复。
  • 建表:首次跑一次 python db.py init(用 CREATE TABLE IF NOT EXISTS,可重复跑)。
  • 驱动:pymysql(仓库 MySQL 约定)。装:pip install pymysql
python db.py init                              # 建表(幂等)
python db.py rebuild                           # 本地文件丢失后,从库重建 runs_full
python run_search.py                           # 搜索结果自动双写 fqe_posts
python tool_extract.py --q q0000 --case-ids …  # 工具结果自动双写 fqe_tools

默认每措辞每渠道搜 10 条(run_search.py 顶部 DEFAULT_MAX_COUNT,原为 20,调小控成本)。


7. 环境依赖注意 ⚠️

run_search.py 会触发 agent.tools.builtin 的完整注册链(同原 batch_3forms.py),需要:

  • Pillow(PIL,图像处理)
  • fastapi[server] 依赖

若报 ModuleNotFoundError: No module named 'PIL' / 'fastapi',说明当前 venv 不全,装齐依赖即可:

pip install -e '.[all]'          # 在仓库根
# 或最小补:pip install Pillow fastapi uvicorn websockets

server.py(查看界面)不依赖上述链,缺这些也能起、能看已有产出。


8. 与原 search_eval 的关系

search_eval/ fixed_query_eval/
query 来源 动作×类型正交矩阵生成 + 三形式(A/B/C) 写死 4 组,单一形式
搜索引擎 search_and_evaluate.py import 复用同一份(零改动)
评分 rubric eval_prompt_template.md 同上(复用)
查看界面 矩阵导航 + 卡片 去矩阵,4-query 选择条 + 卡片
产出 runs_full/q*/form_A\|B\|C.json runs_full/q*/form_A.json

实现说明:搜索/评估/转写/中译英全部复用 ../search_and_evaluate.py 的函数(只读 import); server/index 复制自原版后做最小改造(server 加一行 sys.path 复用兄弟模块 + 矩阵自动降级; index 用 CSS 隐藏矩阵 DOM 并新增 #navQ 选择条,矩阵元素保留在 DOM 以免 JS 取空崩溃)。