Ragas 独立评估项目实施清单
1. 目标
基于 WeKnora 的公开 API 构建一个独立评估项目,不依赖 WeKnora 内置的 /evaluation 接口。
这个项目用于评估:
- 检索质量:WeKnora 是否召回了正确的 chunks。
- 生成质量:WeKnora 是否基于检索上下文正确、忠实地回答问题。
- 端到端 RAG 效果:问题 -> 检索 -> 回答 -> Ragas 指标。
最终输入 Ragas 的单条记录格式:
{
"user_input": "问题",
"response": "WeKnora 生成的答案",
"retrieved_contexts": ["检索到的 chunk 文本 1", "检索到的 chunk 文本 2"],
"reference": "标准答案",
"reference_contexts": ["标准答案依据的原文片段"]
}
2. 推荐独立项目结构
按照以下结构创建独立的项目:
README.md
pyproject.toml
.env.example
configs/
eval.yaml
data/
raw_docs/
pdf/
xlsx/
parsed_docs/
documents.jsonl
parse_summary.json
mineru_raw/
exported/
knowledge.jsonl
chunks.jsonl
testsets/
testset.raw.jsonl
testset.reviewed.jsonl
runs/
weknora_answers.jsonl
ragas_input.jsonl
reports/
ragas_scores.csv
summary.md
scripts/
01_upload_docs.py
02_wait_ingestion.py
03_export_chunks.py
04_parse_docs.py
05_generate_testset.py
06_review_testset.py
07_run_weknora_qa.py
08_build_ragas_input.py
09_run_ragas_eval.py
10_report.py
src/
weknora_eval/
api.py
schemas.py
loaders.py
parsers/
local.py
mineru.py
testset.py
sse.py
ragas_runner.py
report.py
pyproject.toml 示例:
[project]
name = "weknora-ragas-eval"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
"ragas>=0.3,<0.5",
"datasets>=2.19.0",
"pandas>=2.2.0",
"openpyxl>=3.1.0",
"requests>=2.32.0",
"sseclient-py>=1.8.0",
"python-dotenv>=1.0.0",
"pyyaml>=6.0.0",
"langchain>=0.2.0",
"langchain-community>=0.2.0",
"langchain-openai>=0.1.0",
"pypdf>=4.2.0"
]
[project.optional-dependencies]
pdf = [
"pymupdf>=1.24.0",
"pdfplumber>=0.11.0"
]
dev = [
"ruff>=0.6.0",
"pytest>=8.0.0"
]
安装命令:
python -m venv .venv
source .venv/bin/activate
pip install -e .
如果 PDF 解析效果不好,安装 PDF 增强依赖:
pip install -e ".[pdf]"
如果需要开发和测试工具:
pip install -e ".[dev,pdf]"
3. 环境配置
.env.example:
WEKNORA_BASE_URL=http://localhost:8080/api/v1
WEKNORA_API_KEY=replace-me
WEKNORA_KB_ID=replace-me
# Ragas 生成测试集和评测打分使用的模型服务。
# 这里不是 WeKnora 后端的模型配置,而是评估项目自己调用的 LLM/Embedding。
# 如果使用 OpenAI 官方接口:
OPENAI_API_KEY=replace-me
OPENAI_BASE_URL=https://api.openai.com/v1
# 如果使用 OpenAI 兼容服务,例如自建网关、OneAPI、LiteLLM、硅基流动、OpenRouter 等:
# OPENAI_API_KEY=replace-me
# OPENAI_BASE_URL=https://your-openai-compatible-endpoint/v1
# 用于 Ragas 自动生成 QA 测试集的 LLM。
RAGAS_GENERATOR_MODEL=gpt-4o-mini
# 用于 Ragas 评测打分的 LLM,也就是 judge/evaluator。
RAGAS_JUDGE_MODEL=gpt-4o-mini
# 用于 Ragas 中部分语义相似度或问题生成流程的 embedding 模型。
RAGAS_EMBEDDING_MODEL=text-embedding-3-small
TESTSET_SIZE=50
REQUEST_INTERVAL_SECONDS=0.2
这几个模型变量的来源:
| 变量 | 用途 | 从哪里来 |
|---|---|---|
RAGAS_GENERATOR_MODEL |
生成 QA 测试集 | 你选择的评估侧 LLM 服务中的模型名称 |
RAGAS_JUDGE_MODEL |
Ragas 指标打分,例如 faithfulness、context recall | 你选择的评估侧 LLM 服务中的模型名称 |
RAGAS_EMBEDDING_MODEL |
Ragas 生成/评估中需要 embedding 的步骤 | 你选择的评估侧 embedding 服务中的模型名称 |
OPENAI_API_KEY |
调用评估侧模型服务的 API Key | OpenAI 或 OpenAI 兼容服务提供 |
OPENAI_BASE_URL |
调用评估侧模型服务的 Base URL | OpenAI 官方或兼容服务地址 |
注意:
- WeKnora 自己回答问题时使用的是 WeKnora 后端已经配置好的模型。
- Ragas 评估项目调用的
RAGAS_GENERATOR_MODEL、RAGAS_JUDGE_MODEL、RAGAS_EMBEDDING_MODEL是独立的“评估侧模型”。 - 两边可以使用同一个模型服务,也可以分开。为了避免被测系统和评测裁判互相影响,建议评测侧 judge 模型能力不低于 WeKnora 回答模型。
- 如果你不用 OpenAI 官方服务,只要目标服务兼容 OpenAI Chat Completions 和 Embeddings API,一般可以通过
OPENAI_BASE_URL接入。
configs/eval.yaml:
weknora:
base_url: "${WEKNORA_BASE_URL}"
api_key: "${WEKNORA_API_KEY}"
knowledge_base_id: "${WEKNORA_KB_ID}"
timeout_seconds: 300
request_interval_seconds: 0.2
testset:
size: 50
include_pdf: true
include_xlsx: true
min_context_chars: 80
require_manual_review: true
parsing:
# 可选:local 或 mineru
provider: "local"
output_path: "data/parsed_docs/documents.jsonl"
local:
pdf_backend: "pymupdf" # 可选:pypdf, pymupdf, pdfplumber
xlsx_mode: "row_text" # 可选:row_text, markdown_table
min_chars: 80
mineru:
mode: "cli" # 可选:cli, http
cli_bin: "mineru"
output_dir: "data/parsed_docs/mineru_raw"
http_base_url: ""
api_key: ""
timeout_seconds: 600
fallback_to_local: true
qa:
one_session_per_question: true
disable_title: true
enable_memory: false
channel: "api"
ragas:
provider: "openai-compatible"
api_key: "${OPENAI_API_KEY}"
base_url: "${OPENAI_BASE_URL}"
generator_model: "${RAGAS_GENERATOR_MODEL}"
judge_model: "${RAGAS_JUDGE_MODEL}"
embedding_model: "${RAGAS_EMBEDDING_MODEL}"
metrics:
- faithfulness
- response_relevancy
- context_precision
- context_recall
- factual_correctness
4. Ragas 侧文档解析方案
Ragas 生成 QA 测试集前,需要先把原始 PDF/XLSX 转成统一的文本 Document。这里不要直接把文件路径交给 Ragas,而是先执行独立解析步骤,产出标准化的 documents.jsonl。
支持两种解析方式:
- 本地解析:适合快速验证、纯文本 PDF、结构简单的 XLSX。
- MinerU 解析:适合复杂 PDF、扫描件、表格/公式/多栏排版较多的文档。
4.1 统一解析产物
无论使用本地解析还是 MinerU,最终都要产出 data/parsed_docs/documents.jsonl,一行一个 Document:
{
"doc_id": "contract.pdf::page-1",
"source_file": "contract.pdf",
"file_type": "pdf",
"page": 1,
"sheet": null,
"row_index": null,
"content": "第1页解析后的正文文本...",
"metadata": {
"parser": "local:pymupdf"
}
}
XLSX 行级记录示例:
{
"doc_id": "sales.xlsx::Sheet1::row-12",
"source_file": "sales.xlsx",
"file_type": "xlsx",
"page": null,
"sheet": "Sheet1",
"row_index": 12,
"content": "产品: A产品\n年份: 2024\n销售额: 120万元",
"metadata": {
"parser": "local:openpyxl",
"columns": ["产品", "年份", "销售额"]
}
}
后续 Ragas 测试集生成只读取 documents.jsonl,不直接读取原始 PDF/XLSX。
4.2 本地解析
本地解析用于最低依赖、最快跑通。
PDF 可选 backend:
-
pypdf:依赖轻,适合文本型 PDF。 -
pymupdf:解析速度快,通常比 pypdf 稳。 -
pdfplumber:适合需要保留部分表格/版面信息的 PDF。
XLSX 解析模式:
-
row_text:每行转成列名: 值的文本,适合问答和检索。 -
markdown_table:每个 sheet 转成 Markdown 表格,适合保留表格整体结构,但长表容易过长。
本地解析配置:
parsing:
provider: "local"
output_path: "data/parsed_docs/documents.jsonl"
local:
pdf_backend: "pymupdf"
xlsx_mode: "row_text"
min_chars: 80
scripts/04_parse_docs.py 在本地解析模式下的职责:
- 遍历
data/raw_docs/pdf和data/raw_docs/xlsx。 - PDF 按页或按段落输出 Document。
- XLSX 按行或按 sheet 输出 Document。
- 过滤过短文本。
- 写入
data/parsed_docs/documents.jsonl。 - 保留
source_file、page、sheet、row_index等元数据。
4.3 MinerU 解析
MinerU 作为可选增强解析能力。适用于:
- PDF 版面复杂。
- PDF 中有表格、公式、多栏排版。
- 扫描件或图片型 PDF。
- 需要 Markdown 格式作为 QA 生成上下文。
MinerU 支持两种接入模式。
4.3.1 MinerU CLI 模式
配置:
parsing:
provider: "mineru"
mineru:
mode: "cli"
cli_bin: "mineru"
output_dir: "data/parsed_docs/mineru_raw"
timeout_seconds: 600
fallback_to_local: true
预期行为:
-
scripts/04_parse_docs.py调用 MinerU CLI。 - 每个 PDF 解析到
data/parsed_docs/mineru_raw/{file_stem}/。 - 从 MinerU 输出中读取 Markdown 或 JSON。
- 转换成统一
documents.jsonl。
CLI 命令需要按实际安装的 MinerU 版本适配。独立项目中应把 MinerU CLI 调用封装在 src/weknora_eval/parsers/mineru.py,不要把具体命令散落在业务脚本里。
4.3.2 MinerU HTTP 服务模式
如果已有 MinerU 服务,可以通过 HTTP 调用。
配置:
parsing:
provider: "mineru"
mineru:
mode: "http"
http_base_url: "http://mineru.example.com"
api_key: "replace-me"
output_dir: "data/parsed_docs/mineru_raw"
timeout_seconds: 600
fallback_to_local: true
预期行为:
- 上传 PDF 到 MinerU HTTP 服务。
- 等待解析任务完成。
- 下载 Markdown/JSON 结果。
- 转换成统一
documents.jsonl。
HTTP 接口路径需要按实际 MinerU 服务部署约定实现,因此 MinerU HTTP Client 必须做成可替换模块。
4.4 解析回退策略
建议实现以下策略:
- 默认使用配置指定的 provider。
- 如果
provider=mineru且某个文件解析失败:- 记录到
data/parsed_docs/failed_parse.jsonl。 - 如果
fallback_to_local=true,回退到本地解析。
- 记录到
- 如果本地解析结果为空或过短:
- 标记该文件为低质量解析。
- 不进入自动 QA 生成,等待人工处理。
失败记录格式:
{
"source_file": "contract.pdf",
"parser": "mineru:cli",
"status": "failed",
"error": "timeout",
"fallback_used": "local:pymupdf"
}
4.5 解析质量检查
解析完成后生成 data/parsed_docs/parse_summary.json:
{
"total_files": 3,
"parsed_files": 3,
"failed_files": 0,
"total_documents": 128,
"empty_documents": 0,
"avg_chars": 512.4,
"parser": "local:pymupdf"
}
最低质量要求:
- 每个文件至少产生 1 条 Document。
-
content非空。 - 大部分 Document 长度不低于
min_chars。 - metadata 中必须保留
source_file。
5. WeKnora API 调用契约
5.1 上传文档
如果独立评估项目负责把原始 PDF/XLSX 上传到 WeKnora,使用这个接口。
请求:
POST /api/v1/knowledge-bases/{knowledge_base_id}/knowledge/file
X-API-Key: <api-key>
Content-Type: multipart/form-data
Multipart 字段:
file=@/path/to/file.pdf
enable_multimodel=false
响应示例:
{
"success": true,
"data": {
"id": "knowledge-0001",
"knowledge_base_id": "kb-0001",
"type": "file",
"title": "contract.pdf",
"parse_status": "processing",
"enable_status": "disabled",
"file_name": "contract.pdf",
"file_type": "pdf",
"error_message": ""
}
}
需要持久化:
{
"knowledge_id": "knowledge-0001",
"file_name": "contract.pdf",
"file_type": "pdf",
"parse_status": "processing"
}
5.2 轮询文档入库状态
请求:
GET /api/v1/knowledge-bases/{knowledge_base_id}/knowledge?page=1&page_size=100
X-API-Key: <api-key>
响应示例:
{
"success": true,
"data": [
{
"id": "knowledge-0001",
"title": "contract.pdf",
"parse_status": "completed",
"enable_status": "enabled",
"file_name": "contract.pdf",
"file_type": "pdf",
"processed_at": "2026-04-20T10:03:00+08:00",
"error_message": ""
}
],
"page": 1,
"page_size": 100,
"total": 1
}
完成条件:
parse_status == "completed"
enable_status == "enabled"
失败条件:
parse_status == "failed"
5.3 导出 chunks
请求:
GET /api/v1/chunks/{knowledge_id}?page=1&page_size=100
X-API-Key: <api-key>
响应示例:
{
"success": true,
"data": [
{
"id": "chunk-0001",
"knowledge_id": "knowledge-0001",
"knowledge_base_id": "kb-0001",
"content": "分块文本...",
"chunk_index": 0,
"is_enabled": true,
"status": 2,
"start_at": 0,
"end_at": 500,
"chunk_type": "text",
"parent_chunk_id": "",
"metadata": null,
"image_info": ""
}
],
"page": 1,
"page_size": 100,
"total": 35
}
保存为 data/exported/chunks.jsonl:
{
"chunk_id": "chunk-0001",
"knowledge_id": "knowledge-0001",
"knowledge_base_id": "kb-0001",
"chunk_index": 0,
"content": "分块文本...",
"source_file": "contract.pdf",
"chunk_type": "text"
}
5.4 创建会话
建议每个评测问题创建一个独立 session,避免历史上下文影响答案。
请求:
POST /api/v1/sessions
X-API-Key: <api-key>
Content-Type: application/json
请求体:
{
"title": "ragas-eval-qa-0001",
"description": "Ragas evaluation session"
}
响应示例:
{
"success": true,
"data": {
"id": "session-0001",
"title": "ragas-eval-qa-0001",
"description": "Ragas evaluation session"
}
}
5.5 执行知识库问答
请求:
POST /api/v1/agent-chat/{session_id}
X-API-Key: <api-key>
Content-Type: application/json
请求体:
{
"query": "合同中的付款期限是什么?",
"agent_id": "builtin-quick-answer",
"agent_enabled": false,
"knowledge_base_ids": ["kb-0001"],
"disable_title": true,
"enable_memory": false,
"channel": "api"
}
如果要限制在指定文件内检索,可以传:
{
"query": "合同中的付款期限是什么?",
"agent_id": "builtin-quick-answer",
"agent_enabled": false,
"knowledge_ids": ["knowledge-0001"],
"disable_title": true,
"enable_memory": false,
"channel": "api"
}
响应类型:Server-Sent Events。
引用事件:
event: message
data: {
"id": "request-0001",
"response_type": "references",
"content": "",
"done": false,
"knowledge_references": [
{
"id": "chunk-0012",
"content": "买方应在收到合法有效发票后30日内完成付款。",
"knowledge_id": "knowledge-0001",
"chunk_index": 12,
"knowledge_title": "contract.pdf",
"start_at": 1200,
"end_at": 1480,
"seq": 12,
"score": 0.92,
"match_type": 3,
"metadata": {},
"chunk_type": "text",
"parent_chunk_id": "",
"image_info": "",
"knowledge_filename": "contract.pdf",
"knowledge_source": "file"
}
]
}
答案事件:
event: message
data: {
"id": "request-0001",
"response_type": "final_answer",
"content": "合同约定,付款期限为收到合法有效发票后30日内。",
"done": false,
"knowledge_references": null
}
结束事件:
event: message
data: {
"id": "request-0001",
"response_type": "final_answer",
"content": "",
"done": true,
"knowledge_references": null
}
需要提取:
{
"request_id": "request-0001",
"response": "合同约定,付款期限为收到合法有效发票后30日内。",
"retrieved_contexts": [
"买方应在收到合法有效发票后30日内完成付款。"
],
"weknora_references": [
{
"id": "chunk-0012",
"content": "买方应在收到合法有效发票后30日内完成付款。",
"knowledge_id": "knowledge-0001",
"chunk_index": 12,
"score": 0.92,
"knowledge_filename": "contract.pdf"
}
]
}
5.6 可选:读取落库后的消息
用于在 SSE 完成后校验或补取最终 assistant 答案。
请求:
GET /api/v1/messages/{session_id}/load?limit=10
X-API-Key: <api-key>
响应示例:
{
"success": true,
"data": [
{
"id": "assistant-message-0001",
"session_id": "session-0001",
"request_id": "request-0001",
"content": "合同约定,付款期限为收到合法有效发票后30日内。",
"role": "assistant",
"knowledge_references": [
{
"id": "chunk-0012",
"content": "买方应在收到合法有效发票后30日内完成付款。",
"knowledge_id": "knowledge-0001",
"chunk_index": 12,
"knowledge_title": "contract.pdf",
"score": 0.92,
"match_type": 3,
"chunk_type": "text",
"knowledge_filename": "contract.pdf"
}
],
"is_completed": true,
"is_fallback": false
}
]
}
5.7 可选:纯检索接口
用于只评估检索,不评估生成。
请求:
POST /api/v1/knowledge-search
X-API-Key: <api-key>
Content-Type: application/json
请求体:
{
"query": "合同中的付款期限是什么?",
"knowledge_base_ids": ["kb-0001"]
}
响应示例:
{
"success": true,
"data": [
{
"id": "chunk-0012",
"content": "买方应在收到合法有效发票后30日内完成付款。",
"knowledge_id": "knowledge-0001",
"chunk_index": 12,
"knowledge_title": "contract.pdf",
"start_at": 1200,
"end_at": 1480,
"seq": 12,
"score": 0.92,
"match_type": 3,
"chunk_type": "text",
"metadata": {},
"knowledge_filename": "contract.pdf",
"knowledge_source": "file"
}
]
}
6. QA 测试集生成方案
6.1 输入数据
建议同时保留两类输入:
-
data/parsed_docs/documents.jsonl中的标准化解析结果。 -
data/exported/chunks.jsonl中从 WeKnora 导出的 chunks。
推荐顺序:
- 优先基于
documents.jsonl生成候选 QA。 - 保存 QA 对应的来源文件和依据片段。
- 可选:把
reference_contexts匹配回 WeKnora 的 chunk ID,用于计算 hit@k、recall@k、mrr 等非 LLM 检索指标。
6.2 测试集记录格式
data/testsets/testset.raw.jsonl:
{
"sample_id": "qa-0001",
"user_input": "合同中的付款期限是什么?",
"reference": "付款期限为收到合法有效发票后30日内。",
"reference_contexts": [
"买方应在收到合法有效发票后30日内完成付款。"
],
"source_file": "contract.pdf",
"gold_chunk_ids": ["chunk-0012"],
"question_type": "single_hop",
"review_status": "pending"
}
人工审核后的 data/testsets/testset.reviewed.jsonl:
{
"sample_id": "qa-0001",
"user_input": "合同中的付款期限是什么?",
"reference": "付款期限为收到合法有效发票后30日内。",
"reference_contexts": [
"买方应在收到合法有效发票后30日内完成付款。"
],
"source_file": "contract.pdf",
"gold_chunk_ids": ["chunk-0012"],
"question_type": "single_hop",
"review_status": "approved"
}
6.3 问题类型建议
建议包含:
- PDF 单跳事实问答。
- PDF 多跳问答,例如跨相邻章节综合。
- PDF 定义、条件、例外条款类问题。
- XLSX 单行查询问题。
- XLSX 条件筛选问题。
第一阶段暂时避免:
- 复杂表格聚合问题,除非期望 WeKnora 本身支持表格计算。
- 依赖图片内容才能回答的问题。
- 需要外部知识的问题。
- 存在多个合理答案的模糊问题。
7. Ragas 输入构造方案
对每条审核通过的 QA:
- 创建一个干净 session。
- 调用
POST /agent-chat/{session_id},默认使用agent_id=builtin-quick-answer。 - 解析 SSE 中的 references 事件。
- 解析 SSE 中的 final_answer 事件。
- 构造一条 Ragas 输入记录。
data/runs/ragas_input.jsonl:
{
"sample_id": "qa-0001",
"user_input": "合同中的付款期限是什么?",
"response": "合同约定,付款期限为收到合法有效发票后30日内。",
"retrieved_contexts": [
"买方应在收到合法有效发票后30日内完成付款。"
],
"reference": "付款期限为收到合法有效发票后30日内。",
"reference_contexts": [
"买方应在收到合法有效发票后30日内完成付款。"
],
"session_id": "session-0001",
"request_id": "request-0001",
"weknora_references": [
{
"id": "chunk-0012",
"knowledge_id": "knowledge-0001",
"chunk_index": 12,
"score": 0.92,
"knowledge_filename": "contract.pdf"
}
]
}
8. Ragas 指标方案
第一阶段建议使用:
| 指标 | 必要字段 | 作用 |
|---|---|---|
| faithfulness | response, retrieved_contexts | 检查答案是否被检索内容支撑。 |
| response_relevancy | user_input, response | 检查答案是否切题。 |
| context_precision | user_input, retrieved_contexts, reference | 检查靠前的检索上下文是否相关。 |
| context_recall | retrieved_contexts, reference | 检查检索上下文是否包含足够证据。 |
| factual_correctness | response, reference | 检查答案与标准答案事实是否一致。 |
如果测试集里有 gold_chunk_ids,建议额外计算非 LLM 检索指标:
- hit@1
- hit@3
- hit@5
- recall@k
- mrr
- ndcg@k
9. 报告方案
生成 data/reports/summary.md:
# Ragas 评估报告
## 运行信息
- WeKnora Base URL:
- 知识库 ID:
- 测试集规模:
- 审核通过样本数:
- 失败样本数:
- Judge 模型:
## 聚合指标
| 指标 | 平均值 | P50 | 失败阈值 |
| --- | --- | --- | --- |
## 检索失败样本
| sample_id | 问题 | 预期文件 | 实际召回文件 | context_recall | 备注 |
## 生成失败样本
| sample_id | 问题 | 模型答案 | 标准答案 | faithfulness | factual_correctness |
## 改进建议
- ...
同时保存:
-
ragas_scores.csv:每条样本的指标。 -
weknora_answers.jsonl:WeKnora 原始输出。 -
ragas_input.jsonl:实际输入 Ragas 的数据。 -
failed_requests.jsonl:API 失败或 SSE 解析失败记录。
10. 实施清单
阶段 1:项目脚手架
-
创建独立仓库或目录
weknora-ragas-eval。 - 添加 Python 项目元数据和依赖锁定。
-
添加
.env.example。 -
添加
configs/eval.yaml。 -
创建
data/下的各级目录。 - 添加结构化日志。
- 添加重试和超时策略。
阶段 2:WeKnora API Client
-
实现
create_session。 -
实现
upload_file。 -
实现
list_knowledge。 -
实现
wait_ingestion_completed。 -
实现
list_chunks。 -
实现
knowledge_chat_sse。 -
实现
load_messages。 -
实现
knowledge_search。 - API 错误时保存响应体。
- 实现分页工具函数。
阶段 3:文档与 chunk 导出
- 上传 PDF 文件。
- 上传 XLSX 文件。
- 轮询直到所有文档 completed 或 failed。
- 导出全部 knowledge 元数据。
- 导出全部 chunks。
- 过滤 disabled chunks。
- 过滤空 chunks。
- 保留来源文件元数据。
阶段 4:Ragas 侧文档解析
- 实现本地 PDF 解析。
- 实现本地 XLSX 解析。
- 实现 MinerU CLI 解析适配。
- 实现 MinerU HTTP 解析适配。
-
将所有解析结果转换为
documents.jsonl。 - 记录解析失败文件。
-
生成
parse_summary.json。 - 支持 MinerU 失败后回退本地解析。
阶段 5:测试集生成
-
加载
data/parsed_docs/documents.jsonl。 - 使用 Ragas 生成候选 QA。
- 保存原始候选测试集。
- 增加人工审核字段。
- 生成审核后的测试集。
-
执行最低质量检查:
- 问题可以从给定上下文回答。
- 标准答案有依据。
-
reference_contexts非空。 - 记录来源文件。
阶段 6:运行 WeKnora QA
- 每条 QA 创建一个干净 session。
-
调用
agent-chat,默认使用builtin-quick-answer。 - 解析 SSE references 事件。
- 解析 SSE final_answer 事件。
- 按 chunk ID 去重引用。
- 保存原始答案和引用。
- 记录空答案失败。
- 记录空检索失败。
- 可选:通过 message load API 校验最终答案。
阶段 7:构造 Ragas 输入
- 合并审核后的 QA 与 WeKnora 输出。
-
构造
user_input。 -
构造
response。 -
构造
retrieved_contexts。 -
构造
reference。 -
构造
reference_contexts。 -
保留
sample_id、session_id、request_id和 references,便于排查。 - 校验必要字段不缺失。
阶段 8:运行 Ragas 评估
- 配置 judge LLM。
- 配置 embedding 模型。
- 运行 faithfulness。
- 运行 response relevancy。
- 运行 context precision。
- 运行 context recall。
- 运行 factual correctness。
- 保存逐样本分数。
- 保存聚合分数。
- 按样本捕获 Ragas 异常。
阶段 9:基于 chunk ID 的检索指标
-
如果存在
gold_chunk_ids,计算 hit@k。 - 计算 recall@k。
- 计算 mrr。
- 计算 ndcg@k。
- 对比 chunk-ID 指标和 Ragas LLM-based context 指标。
阶段 10:生成报告
- 生成 Markdown 报告。
- 写入运行信息。
- 写入聚合指标。
- 写入最差检索样本。
- 写入最差生成样本。
- 写入空检索数量。
- 写入 fallback 答案数量。
- 写入来源文件分布。
- 写入改进建议。
11. 验收标准
独立评估项目达到以下条件即认为可用:
- 可以上传一小批 PDF/XLSX 到 WeKnora。
- 可以检测文档入库完成。
- 可以从 WeKnora 导出 chunks。
-
可以通过本地解析或 MinerU 解析生成
documents.jsonl。 - 可以创建或导入至少 10 条审核通过的 QA。
- 可以对每条 QA 调用 WeKnora。
-
可以解析
response和retrieved_contexts。 - 可以构造合法的 Ragas 输入 JSONL。
- 可以产出逐样本 Ragas 分数。
- 可以产出可读的汇总报告。
- 所有中间产物都已保存,便于复盘和排查。
12. 首轮 Pilot Run
先用很小的数据集跑通闭环:
- 2 个 PDF 文件。
- 1 个 XLSX 文件。
- 10 条人工审核通过的 QA。
- 每条样本一个独立 session。
- 指标:
- faithfulness
- response_relevancy
- context_precision
- context_recall
- factual_correctness
预期产物:
data/exported/knowledge.jsonl
data/exported/chunks.jsonl
data/parsed_docs/documents.jsonl
data/parsed_docs/parse_summary.json
data/testsets/testset.reviewed.jsonl
data/runs/weknora_answers.jsonl
data/runs/ragas_input.jsonl
data/reports/ragas_scores.csv
data/reports/summary.md
只有当首轮确认以下问题都正常后,再扩展到 50-300 条样本:
-
retrieved_contexts没有系统性为空。 -
response能正确捕获。 - Ragas 输入字段合法。
- 人工审核确认 QA 集有评测意义。