# 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` 顶部常量,改完直接重跑: ```python 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. 怎么跑 ```bash 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/data`、`POST /api/generate_procedure`、`POST /api/reeval`、`GET /api/procedure_status`、`GET /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-lite`(`build_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=`。 手动跑(一般由界面触发): ```bash python tool_extract.py --q q0000 --case-ids xhs_abc,gzh_def [--force] ``` --- ## 6. 产出结构(runs_full/q000N/form_A.json) ```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(`.env` 的 `MYSQL_*`,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.py` 的 `scan_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.json` 和 `tools/{case_id}.json`。界面回退只让「看」有数据,但提取脚本(tool_extract / 工序)仍读本地文件,故本地文件丢失后用此命令完整恢复。 - **建表**:首次跑一次 `python db.py init`(用 `CREATE TABLE IF NOT EXISTS`,可重复跑)。 - 驱动:`pymysql`(仓库 MySQL 约定)。装:`pip install pymysql`。 ```bash 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 不全,装齐依赖即可: ```bash 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 取空崩溃)。*