docs: add Dify score API integration design spec

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-06-22 14:51:52 +08:00
parent ccf25eb1f9
commit eee96eb158

View File

@@ -0,0 +1,138 @@
# Dify 集成 — 单题实时评分 API 设计
**日期**: 2026-06-22
**状态**: 已批准,待实现
**范围**: 在现有 FastAPI 服务中新增 `POST /api/score` 端点,供 Dify 外部 Tool 调用,实现单条问答记录的实时 RAGAS 指标评分。
---
## 1. 目标
让 Dify Agent 能在回答完问题后,将 `(question, answer, contexts, ground_truth)` 发给 siemens_ragas 服务,实时获取各 RAGAS 指标得分,用于质量监控或 Agent 自我改进。
---
## 2. API 规范
### `POST /api/score`
**请求体:**
```json
{
"question": "双源CT的时间分辨率是多少?",
"answer": "双源CT的单扇区时间分辨率为75ms。",
"contexts": "片段1双源CT采用两套管-探测器系统... |||| 片段2单扇区采集旋转135度...",
"ground_truth": "双源CT单扇区时间分辨率为75ms需旋转135度。",
"context_separator": " |||| ",
"metrics": ["faithfulness", "answer_relevancy"],
"judge_model": "deepseek-v4-flash",
"embedding_model": "text-embedding-v3"
}
```
**字段说明:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `question` | str | ✅ | 问题文本 |
| `answer` | str | ✅ | 待评分的回答 |
| `contexts` | str | ✅ | 检索到的上下文,多段用 `context_separator` 拼接 |
| `ground_truth` | str | ❌ | 标准答案缺失时跳过依赖它的指标context_recall、factual_correctness、semantic_similarity |
| `context_separator` | str | ❌ | 默认 `" \|\|\|\| "`(四个竖线,两侧各一空格) |
| `metrics` | list[str] | ❌ | 默认 `["faithfulness", "answer_relevancy", "context_recall", "context_precision"]` |
| `judge_model` | str | ❌ | 默认读 `.env``RAGAS_JUDGE_MODEL` |
| `embedding_model` | str | ❌ | 默认读 `.env``RAGAS_EMBEDDING_MODEL` |
**响应体200 OK**
```json
{
"scores": {
"faithfulness": 0.8750,
"answer_relevancy": 0.9200
},
"weighted_score": 0.8975,
"latency_ms": 3420
}
```
**错误响应:**
| 状态码 | 场景 |
|--------|------|
| 400 | 必填字段缺失、metrics 名称不合法 |
| 401 | 配置了 `SCORE_API_TOKEN` 但请求未携带有效 Bearer Token |
| 422 | 请求体 JSON 格式错误Pydantic 校验) |
| 500 | RAGAS 内部评分异常,附带 error 字段 |
**鉴权(可选):**
`.env``SCORE_API_TOKEN` 非空,则要求请求头携带 `Authorization: Bearer <token>`。为空则不鉴权(内网部署场景)。
---
## 3. 架构与文件改动
### 新文件
| 文件 | 职责 |
|------|------|
| `webapp/api/score.py` | 路由定义,请求验证,调用 InlineScorer |
| `webapp/services/inline_scorer.py` | LLM 客户端缓存 + RAGAS 评分逻辑封装 |
### 修改文件
| 文件 | 改动 |
|------|------|
| `webapp/models.py` | 新增 `ScoreRequest``ScoreResponse` |
| `webapp/server.py` | 注册 `score.router`,更新 `openapi_tags` |
| `rag_eval/settings.py` | 新增 `score_api_token: str | None` 字段 |
---
## 4. `inline_scorer.py` 设计
```python
class InlineScorer:
"""同步执行 RAGAS 单题评分,内部缓存 LLM 客户端。"""
def score(
self,
question: str,
answer: str,
contexts: list[str],
ground_truth: str | None,
metrics: list[str],
judge_model: str,
embedding_model: str,
settings: EvaluationSettings,
) -> dict[str, float | None]:
"""返回 {metric_name: score} 字典NaN 记为 None。"""
```
**客户端缓存策略:**
`(judge_model, embedding_model)` 为 key缓存 `(llm, embeddings)` 对象,避免每次请求都重建 AsyncOpenAI 连接。缓存为模块级单例(`_scorer_cache: dict`),线程安全(加 `threading.Lock`)。
**评分执行:**
复用 `build_metric_pipeline` 构建 `MetricPipeline`,然后 `asyncio.run(pipeline.score_sample(sample))` 执行。与现有 `evaluator.py` 模式一致。
**ground_truth 为空时的指标跳过逻辑:**
`context_recall``factual_correctness``semantic_similarity``noise_sensitivity` 需要 ground_truth若请求中未提供自动从 metrics 列表中移除这些指标,并在响应中对应字段返回 `null`
---
## 5. Dify 侧配置方法
1. 在 Dify 「工具」→「自定义工具」中创建新工具
2. 填写 OpenAPI Schema`/api/score` 端点对齐)
3. 鉴权方式API KeyBearer或无鉴权
4. 在 Agent / Workflow 节点中引用该工具,将 `question``answer``contexts` 变量映射到工具输入
---
## 6. 不在范围内
- 批量评分接口(异步 job
- Dify Workflow 节点插件(需要 Dify 插件开发框架)
- 评分结果持久化到 scores.csv
- 与现有 report_builder 集成展示