From 03e682b89cf2fd61b416621b95a9c7c7cbfefcb2 Mon Sep 17 00:00:00 2001 From: wangwei Date: Wed, 1 Jul 2026 17:32:22 +0800 Subject: [PATCH] docs: add Chinese judge-prompt adaptation design spec Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../2026-07-01-chinese-judge-prompt-design.md | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-01-chinese-judge-prompt-design.md diff --git a/docs/superpowers/specs/2026-07-01-chinese-judge-prompt-design.md b/docs/superpowers/specs/2026-07-01-chinese-judge-prompt-design.md new file mode 100644 index 0000000..4880de2 --- /dev/null +++ b/docs/superpowers/specs/2026-07-01-chinese-judge-prompt-design.md @@ -0,0 +1,189 @@ +# 中文评判 Prompt 适配设计(judge_language: zh) + +**日期**: 2026-07-01 +**状态**: 已批准,待实现 +**范围**: 让 RAGAS 的 LLM 评判 prompt 从默认英文切换为中文,提升对中文语料的判定一致性(架构设计 §10.5)。通过场景 YAML 字段 `judge_language: zh` 和 score API 可选字段 `judge_language` 控制,默认 `en` 保持完全向后兼容。 + +--- + +## 1. 背景与目标 + +架构设计 §10.5 明确要求: + +> 语料为中文,评判模型选多语言能力充分者即可。RAGAS 评判 prompt 默认英文,对中文语料应启用其语言适配,将评判 prompt 切换为中文以提升判定一致性。 + +当前 `rag_eval/metrics/factory.py` 与 `webapp/services/inline_scorer.py` 构建的 RAGAS `ragas.metrics.collections` 指标全部使用默认英文 `instruction` + `examples`。本设计新增中文评判能力: + +- 场景 YAML 新增 `judge_language: zh`(默认 `en`)。 +- score 系列 API(`/api/score`、`/api/score/async`、`/api/score/session_async`)新增可选 `judge_language` 字段。 +- 采用 RAGAS 原生 `BasePrompt.adapt()` + 提交到仓库的持久化缓存文件,生产运行完全确定、零额外延迟。 + +**成功标准**: +- `judge_language: zh` 时,6 个 LLM 评判指标使用中文 prompt;`semantic_similarity`(纯 embedding)不受影响。 +- 默认 `en` 时,所有既有场景与 API 行为逐字节不变。 +- 单变量对比可行:同一数据集分别以 `en` / `zh` 各评一次,比较指标均值与方差。 + +--- + +## 2. 需要本地化的指标与 prompt(已从 RAGAS 0.4.3 源码核实) + +每个 LLM 评判指标把 prompt 存为**实例属性**,可在构建后覆盖: + +| 指标 | prompt 实例属性 | +|---|---| +| `faithfulness` | `statement_generator_prompt`, `nli_statement_prompt` | +| `answer_relevancy` | `prompt` | +| `context_recall` | `prompt` | +| `context_precision` | `prompt` | +| `noise_sensitivity` | `statement_prompt`, `faithfulness_prompt` | +| `factual_correctness` | `prompt`, `nli_prompt` | +| `semantic_similarity` | 无(纯 embedding,跳过) | + +权威映射(写入 `judge_prompts.py`): + +```python +METRIC_PROMPT_ATTRS = { + "faithfulness": ("statement_generator_prompt", "nli_statement_prompt"), + "answer_relevancy": ("prompt",), + "context_recall": ("prompt",), + "context_precision": ("prompt",), + "noise_sensitivity": ("statement_prompt", "faithfulness_prompt"), + "factual_correctness": ("prompt", "nli_prompt"), +} +``` + +`ragas.prompt.metrics.base_prompt.BasePrompt` 提供原生 `async adapt(target_language, llm, adapt_instruction=False)`:翻译 `examples`,`adapt_instruction=True` 时同时翻译 `instruction`,返回新 prompt 实例,并设置 `language` 属性。 + +--- + +## 3. 架构与数据流 + +``` +[一次性] scripts/build_judge_prompt_cache.py --language zh + 对每个指标的每个 prompt 调 adapt("chinese", llm, adapt_instruction=True) + → 写出 configs/judge_prompts/zh/__.json(提交入库) + +[运行时·YAML 场景路径] + runner → factory.build_metric_pipeline(scenario) + 若 scenario.judge_language == "zh": + localize_pipeline_prompts(registry, "zh") + +[运行时·score API 路径] + /api/score, /api/score/async, /api/score/session_async + → inline_scorer.score(..., judge_language=...) + → _build_metric_instances(...) + 若 language == "zh": localize_pipeline_prompts(registry, "zh") +``` + +两条路径共用同一个本地化器,保持 DRY。 + +--- + +## 4. 组件 + +### 4.1 一次性引导脚本 `scripts/build_judge_prompt_cache.py` + +- 参数:`--language zh`、`--judge-model `(默认取 settings)。 +- 对 `METRIC_PROMPT_ATTRS` 每个 (metric, attr):取活体 prompt 实例,`await prompt.adapt("chinese", llm, adapt_instruction=True)`,序列化为 JSON。 +- `adapt()` 失败重试若干次;仍失败则整体中止、不写半成品。 +- 产物提交入库,评审后即为生产资产。 + +### 4.2 缓存文件 `configs/judge_prompts/zh/__.json` + +按 `(metric, prompt_attr)` 命名,1:1 对应覆盖目标,零碰撞(多个指标各自独立生成,即使 prompt 类同名也互不影响)。 + +```json +{ + "metric": "faithfulness", + "prompt_attr": "nli_statement_prompt", + "language": "chinese", + "ragas_version": "0.4.3", + "source_hash": "<英文 instruction + 序列化 examples 的 sha256>", + "instruction": "……中文 instruction……", + "examples": [ { "input": { }, "output": { } } ] +} +``` + +### 4.3 运行时本地化器 `rag_eval/metrics/judge_prompts.py` + +公开函数:`localize_pipeline_prompts(registry: dict[str, Any], language: str) -> LocalizationReport` + +- `language == "en"` 或空 → 直接返回,不做任何事。 +- 对 registry 中每个已知指标的每个 prompt 属性: + 1. 从缓存目录读取对应 JSON(**内存缓存已解析结果**,按 language 键,首次读盘后复用,保证 `/api/score` 高频调用零额外磁盘 IO)。 + 2. 用**活体 prompt 实例的** `input_model` / `output_model` 从 JSON 重建 `examples`,覆盖 `prompt.instruction`、`prompt.examples`、`prompt.language`。 +- 返回 `LocalizationReport`(已应用 / 跳过 / 告警计数),供日志与测试断言。 + +### 4.4 配置面 + +- `rag_eval/settings.py`:新增 `ragas_judge_language`(env `RAGAS_JUDGE_LANGUAGE`,默认 `en`)作为唯一全局默认。 +- `rag_eval/shared/models.py`:`Scenario`(`@dataclass`)新增 `judge_language: str = "en"`,存放**已解析**的最终值。 +- **YAML 场景路径的解析在配置加载器**(`rag_eval/config`)完成:`judge_language = YAML 显式值 or settings.ragas_judge_language`;同时在此处校验值域 `{en, zh}`(与既有 metrics 校验同层,dataclass 本身不做校验)。因此 `Scenario.judge_language` 对 factory 而言是权威值。 +- `webapp/models.py`:`ScoreRequest` 新增 `judge_language: str | None = None`(`SessionScoreRequest` 继承自动获得);score API 路径解析 `request.judge_language or settings.ragas_judge_language`。 +- **统一优先级(两条路径一致)**:显式值(YAML 字段 / 请求字段)> `settings.ragas_judge_language`(默认 `en`)。 + +### 4.5 集成点改动 + +- `rag_eval/metrics/factory.py`:`build_metric_pipeline()` 构建 registry 后,若 `scenario.judge_language == "zh"`,调 `localize_pipeline_prompts(registry, "zh")`。 +- `webapp/services/inline_scorer.py`:`score()` 与 `_build_metric_instances()` 增加 `judge_language` 参数;构建指标后按需本地化。`(judge_model, embedding_model)` 缓存仅缓存 llm/embeddings,指标每次重建,故每次正确应用本地化,缓存键无需变动。 +- `webapp/api/score.py`、`webapp/services/score_job_manager.py`、`webapp/services/session_score_manager.py`:把 `request.judge_language`(回退到 settings 默认)透传给 `inline_scorer.score()`。 + +--- + +## 5. 错误处理与漂移检测 + +- **运行时缺文件 / JSON 损坏 / examples 按当前 schema 重建失败** → 记 WARNING,保留该 prompt 的英文默认,**绝不中断评分**(优雅降级)。 +- **`judge_language: zh` 但缓存整体缺失** → 告警一次,按英文继续。 +- **漂移检测**:加载时用当前英文源计算 `source_hash` 与缓存值比对: + - 不一致但 schema 仍有效 → 应用中文 + 记 loud WARNING「缓存已过期,请重新运行 build_judge_prompt_cache.py」。 + - schema 已失效(重建抛错)→ 自动回退英文。 +- **引导脚本** adapt 失败 → 重试后中止,不写半成品。 + +--- + +## 6. 测试(确定性,Mock LLM,遵循 AGENTS.md) + +新增 `tests/test_judge_prompt_localizer.py`: + +- fixture 缓存文件正确覆盖 `metric..instruction` 与 `.examples`(examples 按活体 model 重建成功)。 +- 缺文件 → 保留英文默认、不抛异常。 +- `source_hash` 不匹配 → 记告警仍应用中文;schema 失效 → 回退英文。 +- `language == "en"` → registry 完全不变。 +- 内存缓存:同一 language 第二次调用不再读盘(用可计数的假 loader 或 monkeypatch 断言)。 + +扩展/新增: + +- `Scenario` schema:`judge_language` 解析、默认 `en`、非法值报错。 +- `ScoreRequest`:`judge_language` 可选、默认 `None`。 +- 引导脚本:mock LLM(`adapt` 返回预置中文)→ 断言写出预期 JSON 结构与字段。 + +**可选人工验证(非 CI)**:固定小样本集分别以 `en` / `zh` 各评一次,比较均值/方差,并复核已知正确样本(如 “MAGNETOM Vida 设备总重 7370 kg”)。 + +--- + +## 7. 改动文件清单 + +**新增**: +- `rag_eval/metrics/judge_prompts.py` — 本地化器(加载/覆盖/hash/内存缓存) +- `scripts/build_judge_prompt_cache.py` — 一次性引导脚本 +- `configs/judge_prompts/zh/*.json` — 提交入库的中文 prompt 缓存 +- `tests/test_judge_prompt_localizer.py` — 测试 + +**修改**: +- `rag_eval/shared/models.py` — `Scenario.judge_language` 字段(存已解析值) +- `rag_eval/config`(YAML 加载器)— 解析 `judge_language` = 显式值 or settings 默认,并校验值域 +- `rag_eval/settings.py` — `ragas_judge_language` 默认 +- `rag_eval/metrics/factory.py` — `build_metric_pipeline` 接入本地化 +- `webapp/models.py` — `ScoreRequest.judge_language` +- `webapp/services/inline_scorer.py` — `score()`/`_build_metric_instances()` +参数+本地化 +- `webapp/api/score.py`、`webapp/services/score_job_manager.py`、`webapp/services/session_score_manager.py` — 透传 `judge_language` +- 示例场景 YAML(如 `scenarios/siemens_build/*`、一个 offline 示例)— 增加 `judge_language: zh` +- `README.md` — 简述机制与「如何重新生成缓存」 + +--- + +## 8. 兼容性与影响 + +- 三个 score 接口默认(不传 `judge_language`)行为**逐字节不变**,现有 Dify Tool 调用零影响。 +- YAML 场景默认 `judge_language: en`,既有 run 结果口径不变。 +- 仅当显式 `zh` 时切换中文 prompt;可随时通过重跑脚本刷新缓存。