Files
siemens_ragas/docs/superpowers/specs/2026-07-01-chinese-judge-prompt-design.md
T

190 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 中文评判 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` | 使用函数式 `to_string()`(无 `instruction`/`examples`),无法通过 `adapt()` 本地化,**跳过** |
| `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/<metric>__<attr>.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 <model>`(默认取 settings)。
-`METRIC_PROMPT_ATTRS` 每个 (metric, attr):取活体 prompt 实例,`await prompt.adapt("chinese", llm, adapt_instruction=True)`,序列化为 JSON。
- `adapt()` 失败重试若干次;仍失败则整体中止、不写半成品。
- 产物提交入库,评审后即为生产资产。
### 4.2 缓存文件 `configs/judge_prompts/zh/<metric>__<attr>.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.<attr>.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;可随时通过重跑脚本刷新缓存。