dagent_eval/docs/RAG-Eval平台技术规格说明书.md

61 KiB
Raw Blame History

RAG Eval 平台技术规格说明书

属性 内容
文档版本 v1.0
适用代码库 rag-eval/
最后更新 2026-05-18
读者对象 后端/前端开发、算法工程师、测试与运维
关联文档 框架设计稿14 组分批规则

目录

  1. 概述
  2. 系统架构
  3. 技术栈与代码组织
  4. 核心模块设计
  5. 数据模型
  6. 业务流程与时序图
  7. 评测指标体系
  8. REST API 概览
  9. 前端架构
  10. 部署、运维与安全
  11. 扩展开发指南

1. 概述

1.1 背景与定位

RAG EvalRAG Evaluation Framework是一套独立于业务 RAG 服务的评测平台,最初为 dagent 知识库与 Agent 能力构建,但通过 RAGAdapter 抽象层保持平台无关:任何能通过 HTTP 提供「语义检索」与「Agent 对话」能力的系统均可接入。

将评测从生产服务中剥离的设计动机包括:

  • 资源隔离:大批量评测(数万条问答、多轮循环)不占用线上推理配额;
  • 技术选型自由Judge 模型、Embedding 服务、存储均可独立升级;
  • 可复用:同一套指标与 UI 可对比不同版本 dagent、不同知识库切片策略或竞品 RAG
  • 可自动化SDK/CLI 适合接入 CI在发版前做回归门禁。

1.2 设计目标

目标 实现方式
检索 + 生成全链路评测 EvalRunner 编排 retrieve → 规则指标 → chat → LLM Judge
低标注成本 LLM 自动出题、Faithfulness 等无需 gold chunk
知识库专项能力 单跳/多跳召回、循环压测、MD 问答集解析
人机协作 Web UI 审核出题、查看 Judge 推理明细
可观测 任务进度、分章节报告、AI 文字解读

1.3 能力矩阵

平台在「评测深度」与「使用场景」两个维度上提供六类能力:

能力 典型用户 是否依赖 LLM Judge 主要产出
综合评测eval_task 算法/质量 是(部分指标) eval_report、雷达图
测试集 LLM 生成 数据标注 eval_sample
单跳召回测试 检索工程师 命中率、余弦相似度
多跳召回测试 检索工程师 可选 分跳命中、全链路命中
QA 生成qa_gen 数据生产 qa_gen_question
循环测试loop 大规模压测 多轮问答 + 召回验证

1.4 术语表

术语 含义
切片Chunk 知识库中文档经切分后的最小检索单元,含 chunk_id、headers、正文
单跳Single-hop 一个问题对应一次检索即可回答
多跳Multi-hop 需按跳次hop依次检索不同章节/文件
Judge 使用 LLM及 Embedding对回答/上下文打分的组件
Adapter 对接外部 RAG 平台的 HTTP 客户端封装
循环任务Loop 多轮「生成问答 → 去重 → 单跳验证」的自动化流水线
任务组 / 批次 大规模循环测试时,按每 100 切片一批、每 3 批一组的规划单位

2. 系统架构

2.1 逻辑分层架构

系统采用经典三层架构,评测核心逻辑集中在 Python SDKServer 负责持久化、任务调度与 API 暴露Frontend 负责交互与可视化。

flowchart TB
    subgraph Presentation["表现层"]
        UI["React Web UI<br/>Ant Design + ECharts"]
        CLI["rag-eval CLI"]
    end

    subgraph Application["应用层 (server/)"]
        API["FastAPI Routers<br/>11 模块"]
        SVC["Services<br/>task_service / loop_engine / dedup"]
        DB[("SQLite<br/>aiosqlite + WAL")]
    end

    subgraph Domain["领域层 (sdk/rag_eval/)"]
        RUN["EvalRunner"]
        ADP["RAGAdapter"]
        JUD["LLMJudge"]
        EVA["Retrieval Evaluators"]
        SJ["single_jump / multi_hop"]
        GEN["DatasetGenerator"]
    end

    subgraph External["外部系统"]
        DAG["dagent Platform<br/>semantic_search / agent/chat"]
        LLM["OpenAI 兼容 API<br/>DeepSeek / GPT / Qwen"]
        EMB["Embedding API"]
    end

    UI -->|REST JSON| API
    CLI --> RUN
    API --> SVC
    SVC --> RUN
    SVC --> SJ
    SVC --> DB
    RUN --> ADP
    RUN --> JUD
    RUN --> EVA
    ADP --> DAG
    JUD --> LLM
    JUD --> EMB
    SJ --> DAG

关键设计决策:

  1. Server 通过 sys.path.insert 引用 SDK,而非将 SDK 发布为独立 wheel 后再依赖——开发迭代快,但部署时需保证 sdk/server/ 目录相对位置固定。
  2. 长任务采用「提交后立即返回 + 后台 asyncio 协程」,状态写入 SQLite前端轮询进度。
  3. 循环任务暂停/恢复通过进程内 _loop_controls 字典 + asyncio.Event 实现,多 Worker 部署时需注意状态不共享(当前为单进程假设)。

2.2 部署架构

flowchart LR
    subgraph Dev["开发环境"]
        Vite["Vite Dev :5173"]
        Uvicorn["uvicorn :8021"]
        Vite -->|proxy /api| Uvicorn
    end

    subgraph Prod["生产 / Docker"]
        Nginx["nginx :80"]
        FE["frontend/dist 静态资源"]
        BE["uvicorn server:app"]
        SQL[("rag_eval.db")]
        Nginx --> FE
        Nginx -->|/api| BE
        BE --> SQL
        BE -->|挂载| FE2["StaticFiles 可选单端口"]
    end

    BE --> DAGENT["dagent 远程集群"]
    BE --> JUDGE["Judge API"]
组件 默认端口 说明
FastAPI 8021main.py/ 8003文档示例 开发时常用 8021
Vite 5173 仅开发,vite.config 代理 API
SQLite 文件 server/data/rag_eval.db WAL 模式,busy_timeout=30s

2.3 与 dagent 的集成边界

flowchart LR
    RE["RAG Eval"]
    RE -->|POST /dagent/knowledge/hub/semantic_search_knowledge/detail| SRCH["语义检索"]
    RE -->|POST /dagent/agent/chat SSE| CHAT["Agent 对话"]
    RE -->|知识库文件列表等| META["元数据 API<br/>qa_gen_dagent 使用"]

    SRCH --> CHUNKS["RetrievedChunk[]"]
    CHAT --> ANSWER["AgentResponse"]

DagentAdapter 不 import dagent 内部 Python 包,仅通过 HTTP 契约交互,保证评测框架可独立发版。


3. 技术栈与代码组织

3.1 技术栈

层级 技术 版本策略
语言 Python 3.10+ Server + SDK
Web 框架 FastAPI 异步路由、OpenAPI
数据库 SQLite + aiosqlite 嵌入式,适合单机大规模评测
HTTP 客户端 aiohttpAdapter、httpx/openaiJudge 全异步
前端 React 18、TypeScript、Vite、Ant Design SPA
图表 ECharts报告雷达图
包管理 pipserver、npmfrontend、Poetry 可选sdk

3.2 仓库目录详解

rag-eval/
├── docs/                              # 文档与数据资产
│   ├── RAG-Eval平台技术规格说明书.md     # 本文档
│   ├── task_groups_plan.json          # 14 组 × 42 批次机器可读规划
│   ├── exports/                       # 全量问答导出
│   └── …
├── sdk/rag_eval/
│   ├── adapters/          base.py, dagent.py
│   ├── judge/             base.py, openai_compatible.py
│   ├── evaluators/        retrieval.pyHit/MRR/NDCG
│   ├── dataset/           schema.py, generator.py
│   ├── single_jump/       parser, mapper, tester, report
│   ├── multi_hop/         parser, tester, report
│   ├── runner.py          综合评测编排
│   ├── report.py          EvalReport / SampleResult
│   └── cli.py             run / generate 子命令
├── server/
│   ├── main.py            应用入口、路由注册、静态资源
│   ├── api/               11 个 APIRouter 模块
│   ├── service/           后台任务与循环引擎
│   └── models/            db.py, schema.sql, 轻量迁移
└── frontend/src/
    ├── pages/             Config, Dataset, Task, Report, SingleJump, MultiHop, QaGen
    └── services/api.ts    REST 封装

3.3 进程内依赖关系

graph TD
    main["server/main.py"] --> api_mod["api/*"]
    main --> loop_eng["service/loop_engine.py"]
    api_mod --> task_svc["service/task_service.py"]
    task_svc --> runner["sdk: EvalRunner"]
    task_svc --> dagent["sdk: DagentAdapter"]
    loop_eng --> qa_api["api/qa_gen 逻辑"]
    loop_eng --> sj_api["api/single_jump 逻辑"]
    runner --> judge["sdk: OpenAICompatibleJudge"]

4. 核心模块设计

4.1 RAGAdapter 抽象层

职责:屏蔽各 RAG 平台 API 差异,向上提供统一的 retrievechat

# sdk/rag_eval/adapters/base.py概念接口
class RAGAdapter(ABC):
    async def retrieve(query, knowledge_hub_id, top_k=10, **kwargs) -> list[RetrievedChunk]
    async def chat(query, agent_id, **kwargs) -> AgentResponse

RetrievedChunk 字段:

字段 说明
chunk_id 切片唯一 IDdagent 为 knowledge_md_header_split_id
content 正文,用于 Judge 与展示
score 相似度得分dagent 由 1 - cosine_distance 推导)
headers 切片标题路径
file_id 所属文件

DagentAdapter.retrieve 实现要点:

  • 请求体:query, org_id, top_k, 可选 knowledge_hub_id, file_id_list
  • 合并 standard_answer_resultsrelated_knowledge_rerank_results_top 两路结果后截断至 top_k

DagentAdapter.chat 实现要点:

  • SSE 流式解析 data: 行,拼接 message_type 为 answer 的文本块
  • 记录端到端 latency_ms

4.2 EvalRunner 综合评测编排器

EvalRunner.run() 对数据集中每个 EvalSample

  1. asyncio.Semaphore(concurrency) 限制并发;
  2. RunConfig.should_eval() 决定计算哪些指标;
  3. 检索与生成可独立开关,也支持 selected_metrics 精细选择。

单样本流水线(逻辑顺序):

flowchart TD
    A[EvalSample] --> B{need_retrieval?}
    B -->|是| C[adapter.retrieve]
    C --> D{有 relevant_chunk_ids?}
    D -->|是| E[hit_rate / mrr / ndcg]
    C --> F{有 reference_answer?}
    F -->|是| G[Judge: context_precision / recall]
    B -->|否| H{need_generation?}
    E --> H
    G --> H
    H -->|是| I[adapter.chat]
    I --> J{无 retrieved_chunks?}
    J -->|是| K[补一次 retrieve]
    J --> L[Judge: faithfulness / relevance / groundedness / correctness]
    K --> L
    L --> M[SampleResult]

报告聚合:

  • 各指标算术平均(忽略 None
  • RAG Score = Faithfulness、Answer Relevance、Context Precision、Context Recall 四者的调和均值(任一项偏低则显著拉低总分);
  • Hallucination Rate = Faithfulness < faithfulness_threshold(默认 0.7)的样本占比。

4.3 LLMJudgeOpenAI 兼容实现)

设计原则Prompt 为中文;输出要求 JSON失败时返回 (0.0, raw_detail) 便于排查。

方法 算法概要 输出范围
score_faithfulness 回答拆声明 → 逐条验证是否可由 context 推出 支持声明占比
score_relevance 由回答反推 3 个问题 → 与原始问题 Embedding 相似度均值 01
score_correctness 与 reference 的事实一致性 JSON 评分 01
score_groundedness 声明级标注来源切片编号 有源声明占比
score_context_precision 逐 chunk 判定是否对答题有用 useful/(total)
score_context_recall 参考答案拆陈述 → 是否在检索文中被支持 supported/total

Faithfulness 两步法降低单次长上下文 Judge 的不稳定性,但会增加 LLM 调用次数(约 1 + N 次 claim 验证)。

4.4 单跳召回模块single_jump

子模块 职责
parser.py 解析 MD# 章## section_pathQn / **An:**
mapper.py section_path 模糊匹配知识库 file_idexact/contains/fuzzy
tester.py 并发调用 dagent 检索 APIRecallResult
report.py 汇总召回率、文件命中率、章节匹配率

命中判定:在 hit_top_k 范围内检查 expected_chunk_idfile_id 是否出现在召回列表。

4.5 多跳召回模块multi_hop

解析带 typehops[] 的多跳问答 MD对每一跳构造检索 query分别召回并合并去重支持 Agent 最终回答与分跳贡献分析。详见 multi-hop-example.md

4.6 循环引擎loop_engine

目标:对指定 file_ids 列表,在多轮中持续生成不重复问答并用单跳召回验证质量,直至达到 max_rounds / max_questions 或连续空轮。

单轮阶段:

stateDiagram-v2
    [*] --> FetchExisting: 新一轮开始
    FetchExisting --> QaGen: 拉取历史已批准题
    QaGen --> Dedup: LLM 出题 + 质量分
    Dedup --> SingleJump: Embedding 向量去重
    SingleJump --> WaitComplete: 创建单跳任务
    WaitComplete --> UpdateStats: 轮询完成
    UpdateStats --> CheckTerminate: 更新 loop_round
    CheckTerminate --> FetchExisting: 未终止
    CheckTerminate --> [*]: 达到上限或 stop

控制面:

操作 机制
暂停 pause_event.clear() + DB status=paused
恢复 pause_event.set()
停止 stop=True + DB status=stopped
孤儿恢复 启动时 recover_orphaned_loops() 将异常退出时的 running 改为 paused

4.7 去重服务dedup

循环任务中默认使用 Embedding 余弦相似度(非 LLM在 section 内及全局(global_dedup)检测重复题,阈值可配。历史题目从 qa_gen_question 表加载,支持跨任务全局去重以应对 14 组 42 批次大规模跑数。


5. 数据模型

5.1 ER 关系概览

erDiagram
    platform_config ||--o{ eval_task : uses
    judge_config ||--o{ eval_task : uses
    eval_dataset ||--o{ eval_sample : contains
    eval_dataset ||--o{ eval_task : ""
    eval_task ||--o{ eval_result : produces
    eval_task ||--|| eval_report : summarizes

    loop_task ||--o{ loop_round : has
    loop_round }o--|| qa_gen_task : links
    loop_round }o--|| single_jump_task : links
    qa_gen_task ||--o{ qa_gen_question : contains
    single_jump_task ||--o{ single_jump_result : contains

    multi_hop_task ||--o{ multi_hop_result : contains
    multi_hop_gen_task ||--o{ multi_hop_gen_question : contains
    prompt_template ||--o{ qa_gen_task : optional

5.2 核心表说明

表名 用途 关键字段
platform_config dagent 连接信息 base_url, org_id, token
judge_config Judge + Embedding model, embed_model
eval_dataset / eval_sample 综合评测数据集 relevant_chunk_ids JSON
eval_task / eval_result / eval_report 综合评测任务与结果 status, progress, 各指标均值
single_jump_task / single_jump_result 单跳召回 retrieved JSON, is_file_hit
multi_hop_task / multi_hop_result 多跳召回 hops, actual_hops JSON
qa_gen_task / qa_gen_question 出题与审核 status, embedding, chunk_id
loop_task / loop_round 循环压测 current_round, 累计统计字段
multi_hop_gen_task 多跳 QA 生成 source file/dagent
prompt_template Prompt 管理 content

5.3 任务状态机(综合评测)

stateDiagram-v2
    [*] --> pending: 创建任务
    pending --> running: 后台开始
    running --> done: EvalRunner 成功
    running --> failed: 异常
    done --> [*]
    failed --> [*]

5.4 迁移策略

models/db.py_run_migrations() 对已有库做向前兼容列追加(PRAGMA table_info 检测),避免破坏已有 rag_eval.db。新环境执行 schema.sql 全量建表。


6. 业务流程与时序图

6.1 综合评测任务Web → Server → SDK

sequenceDiagram
    autonumber
    actor User as 用户
    participant UI as React UI
    participant API as task.py
    participant SVC as task_service
    participant DB as SQLite
    participant RUN as EvalRunner
    participant ADP as DagentAdapter
    participant JUD as LLMJudge
    participant DG as dagent

    User->>UI: 新建评测任务
    UI->>API: POST /api/task/run
    API->>DB: INSERT eval_task (pending)
    API-->>UI: task_id
    API->>SVC: asyncio.create_task(run_eval_task)

    SVC->>DB: status=running
    SVC->>DB: 加载 dataset / configs
    SVC->>RUN: run(dataset, RunConfig)

    loop 每个 EvalSample并发 N
        RUN->>ADP: retrieve(question)
        ADP->>DG: semantic_search
        DG-->>ADP: chunks
        RUN->>JUD: context_precision / recall
        JUD-->>RUN: scores
        RUN->>ADP: chat(question)
        ADP->>DG: agent/chat SSE
        DG-->>ADP: answer stream
        RUN->>JUD: faithfulness / relevance / ...
        RUN->>DB: INSERT eval_result批量或逐条
    end

    RUN-->>SVC: EvalReport
    SVC->>JUD: 生成 interpretation 文案
    SVC->>DB: INSERT eval_report, status=done
    UI->>API: GET /api/report/{task_id}
    API-->>UI: 雷达图 + 明细

6.2 Faithfulness 评判(两步法)

sequenceDiagram
    participant RUN as EvalRunner
    participant JUD as OpenAICompatibleJudge
    participant LLM as Judge LLM

    RUN->>JUD: score_faithfulness(answer, contexts)
    JUD->>LLM: Prompt: 分解为原子声明 JSON
    LLM-->>JUD: ["声明1", "声明2", ...]
    loop 每条声明
        JUD->>LLM: Prompt: 声明是否可由资料推出 yes/no
        LLM-->>JUD: yes | no
    end
    JUD-->>RUN: score = supported_count / total_claims

6.3 单跳召回测试

sequenceDiagram
    actor User as 用户
    participant API as single_jump.py
    participant P as MD Parser
    participant M as FileMapper
    participant T as SingleJumpTester
    participant DG as dagent

    User->>API: POST /api/single-jump/task (multipart MD)
    API->>P: parse(md_content)
    P-->>API: sections[] + qa_pairs[]
    API->>M: map(section_path → file_id)
    M->>DG: 文件列表 / 路径匹配
    API->>DB: INSERT task + results (pending)

    loop 每条 QA并发
        T->>DG: semantic_search(question)
        DG-->>T: retrieved[]
        T->>T: 计算 is_file_hit, chunk_hit, cosine_sim
        T->>DB: UPDATE single_jump_result
    end

    API->>DB: task status=done
    User->>API: GET summary / results

6.4 循环测试(单轮)

sequenceDiagram
    participant LE as loop_engine
    participant DB as SQLite
    participant QG as qa_gen 流程
    participant DD as dedup
    participant SJ as single_jump 流程
    participant DG as dagent

    LE->>DB: 读取 loop_task / 历史轮次
    LE->>DB: 汇总已批准问题(可选 global_dedup
    LE->>QG: 按 file_ids 拉切片 → LLM 出题
    QG->>DB: qa_gen_question (pending)
    LE->>DD: Embedding 相似度过滤
    DD->>DB: status=approved | rejected
    LE->>SJ: 生成 MD → 创建 single_jump_task
    SJ->>DG: 批量检索
  SJ->>DB: single_jump_result
    LE->>DB: 更新 loop_round 统计
    LE->>LE: 检查 max_rounds / max_questions / stop

6.5 LLM 自动出题(测试集 / qa_gen

sequenceDiagram
    participant API as dataset.py / qa_gen.py
    participant GEN as DatasetGenerator
    participant ADP as DagentAdapter
    participant JUD as LLMJudge
    participant DG as dagent

    API->>ADP: 获取文件切片列表
    ADP->>DG: 知识库 API
    loop 每个切片
        GEN->>JUD: 根据 chunk 内容生成 Q&A
        JUD-->>GEN: question + answer
        GEN->>JUD: quality_score 评估
    end
    GEN->>API: EvalSample[] 或 qa_gen_question
    API->>DB: 持久化

6.6 配置管理流程

sequenceDiagram
    actor User as 用户
    participant UI as Config 页面
    participant API as config.py
    participant DB as SQLite

    User->>UI: 添加平台配置 / Judge 配置
    UI->>API: POST /api/config/platform | /judge
    API->>DB: INSERTAPI Key 明文存库,需注意权限)
    API-->>UI: config_id
    Note over UI,DB: 后续所有任务通过 config_id 引用

7. 评测指标体系

7.1 检索层(规则指标)

设召回序列为 $[c_1, \ldots, c_K]$,相关集合为 $R$。

指标 公式 / 定义 需要标注
Hit Rate@K R \cap \{c_1..c_K\} \neq \emptyset 则为 1否则 0 relevant_chunk_ids
MRR@K $\frac{1}{\text{rank}}$rank 为第一个相关 chunk 的位置 同上
NDCG@K 按相关度折损的 DCG 归一化 同上,实现见 evaluators/retrieval.py

7.2 检索层LLM 指标)

指标 含义 典型问题
Context Precision 召回切片中有多少比例对回答真正有用 噪声切片多 → 低
Context Recall 参考答案中的事实有多少能在召回中找到 切片不全 → 低

7.3 生成层

指标 含义 低分常见原因
Faithfulness 回答是否可仅从检索内容推出 幻觉、过度推断
Answer Relevance 回答是否切题 答非所问、冗长
Answer Correctness 与参考答案事实一致性 错误细节
Groundedness 声明是否有明确切片来源 无出处断言

7.4 综合指标

RAG Score调和均值


\text{RAG Score} = \frac{n}{\sum_{i=1}^{n} \frac{1}{s_i}}

其中 s_i 为 Faithfulness、Answer Relevance、Context Precision、Context Recall 中非空且 >0 的项。

Hallucination Rate


\text{Hallucination Rate} = \frac{|\{i : \text{faithfulness}_i < \tau\}|}{n}, \quad \tau = 0.7

7.5 单跳召回专用指标

指标 计算
召回率 有检索结果的问题数 / 总问题数
文件命中率 is_file_hit=1 / 有检索结果数
切片命中率 expected_chunk_id 出现在 top-K
平均余弦相似度 召回列表 1 - \text{cosine\_distance} 的统计
章节匹配率 成功映射 file_id 的 section 数 / 总 section 数

7.6 指标解读阈值(建议)

指标 优秀 良好 需关注
Hit Rate > 0.90 0.700.90 < 0.70
MRR > 0.80 0.600.80 < 0.60
Faithfulness > 0.85 0.700.85 < 0.70
RAG Score > 0.80 0.650.80 < 0.65
Hallucination Rate < 5% 515% > 15%

8. REST API 概览

所有路由前缀为 /api。下表为模块级索引,完整参数见 Swagger /docs

前缀 模块文件 职责
/api/config config.py 平台 / Judge CRUD
/api/dataset dataset.py 数据集、样本、导入、LLM 生成
/api/task task.py 综合评测任务
/api/report report.py 报告与样本明细
/api/single-jump single_jump.py 单跳任务与结果
/api/multi-hop multi_hop.py 多跳任务
/api/qa-gen qa_gen.py + qa_gen_dagent.py 出题(文件 / dagent 数据源)
/api/multi-hop-gen multi_hop_gen.py 多跳 QA 生成
/api/loop loop.py 循环任务、暂停/恢复、导出
/api/prompt-template prompt_template.py Prompt CRUD
/api/health main.py 健康检查

异步任务通用约定:

  • 创建接口返回 task_id
  • GET .../task/{id}status, progress, total, error_message
  • 完成后通过 report 或 export 接口拉取结果。

9. 前端架构

9.1 路由与页面

路径 页面 功能
/config Config 平台 / Judge 配置
/dataset Dataset 列表、详情、导入、生成
/task Task 创建综合评测
/report/:taskId Report 雷达图、明细、Judge 下钻
/single-jump SingleJump 上传 MD、进度、分章节报告
/multi-hop MultiHop 多跳测试
/qa-gen QaGen 出题任务与审核

9.2 数据流

flowchart LR
    Pages["pages/*"] --> API["services/api.ts"]
    API --> HTTP["services/http.ts<br/>axios baseURL=/api"]
    HTTP --> BE["FastAPI"]

开发模式 Vite 将 /api 代理至 http://127.0.0.1:8021;生产构建后由同源 FastAPI 或 nginx 转发。

9.3 报告可视化

Report 页使用 ECharts 雷达图展示各维度均值;表格列出 eval_result 逐条指标Modal 展示 judge_detail JSON 供人工复核 LLM 评判理由。


10. 部署、运维与安全

10.1 Docker Compose

docker-compose.yml 定义 serverfrontend 服务;Dockerfile.server 安装 Python 依赖并启动 uvicornDockerfile.frontend 多阶段构建静态资源。

10.2 数据备份

  • 核心资产server/data/rag_eval.db(循环测试后可达数 GB
  • 导出副本docs/exports/ 下 MD/JSON
  • 规划文件docs/task_groups_plan.json

建议定期备份 DB 与 exports避免仅依赖单机 SQLite。

10.3 性能调优

旋钮 位置 说明
concurrency RunConfig / 任务表单 增大可加速,受 dagent/Judge 限流约束
top_k 检索配置 影响检索耗时与 Context 指标
SQLite WAL db.py 已启用,避免长事务锁库
循环 global_dedup loop 创建参数 真时跨任务查重 SQL 较重

10.4 安全注意

  • judge_config.api_key 存于 SQLite 明文,需限制 DB 文件权限;
  • CORS 当前为 allow_origins=["*"],公网部署应收紧;
  • 导出脚本与 API 可能含完整问答与切片内容,注意数据分级。

10.5 运维脚本

脚本 用途
server/scripts/export_loop_all_groups.py 从 DB 导出 14 组全量问答
server/scripts/batch_create_tasks.py 批量创建循环任务
server/scripts/export_loop_batches_recall_md.py 导出召回 MD

11. 扩展开发指南

11.1 新增 RAG 平台 Adapter

  1. sdk/rag_eval/adapters/ 新建 my_platform.py
  2. 实现 retrieve / chat,映射为 RetrievedChunk / AgentResponse
  3. platform_config.type 增加枚举Server 侧 task_service 按 type 实例化。

11.2 新增评测指标

  1. LLMJudge 增加 score_xxx 方法;
  2. EvalRunner._eval_sample 中调用;
  3. SampleResult / eval_result 表增加列 + 迁移;
  4. 前端 Report 增加展示卡片。

11.3 新增 API 模块

  1. server/api/ 新建路由文件;
  2. main.py include_router
  3. frontend/services/api.ts 增加客户端方法。

11.4 测试建议

  • 单元测试evaluators/retrieval.py 规则指标边界;parser.py MD 样例;
  • 集成测试Mock dagent HTTP跑通 EvalRunner 单样本;
  • 回归:固定小数据集 + Judge 模型版本记录在报告中。

12. 数据库字段字典(详表)

本章列出主要表的字段语义,便于写 SQL 报表、对接 BI 或二次开发。JSON 列在 SQLite 中以 TEXT 存储,应用层 json.loads 解析。

12.1 platform_config

字段 类型 说明
id TEXT PK UUID hex
name TEXT 展示名称如「dagent 生产」
type TEXT 默认 dagent,预留其他 Adapter
base_url TEXT https://dagent.d-robotics.cc
org_id TEXT 组织 ID检索与对话必传
token TEXT 可选 Bearer Token
created_at TEXT ISO 时间戳

12.2 judge_config

字段 类型 说明
embed_base_url TEXT 为空则回退 base_url
embed_api_key TEXT 为空则回退 api_key
embed_model TEXT 去重与 Answer Relevance 使用

12.3 eval_sample

字段 类型 说明
relevant_chunk_ids TEXT JSON 数组Hit/MRR/NDCG 必需
knowledge_hub_id TEXT 样本级 hub可与任务级叠加
source_file_id TEXT 可选,追溯出题文件
metadata TEXT 扩展 JSON

12.4 eval_task

字段 类型 说明
eval_retrieval INTEGER 1/0与 selected_metrics 二选一逻辑在 RunConfig
eval_generation INTEGER 1/0
selected_metrics TEXT JSON 数组,非空时覆盖上述开关
file_id_list TEXT 检索时限制文件范围
concurrency INTEGER 默认 3
progress / total INTEGER 已完成样本数 / 总样本数

12.5 eval_result

逐样本存储完整评判:retrieved_chunks 为正文数组 JSONjudge_detail 为各 LLM 指标原始返回,供 UI 下钻。

12.6 single_jump_result

字段 说明
retrieved 原始 dagent 返回 JSON 数组,保留 cosine_distance_1
is_file_hit 预期 file_id 是否出现在召回列表
is_chunk_hit expected_chunk_id 是否在 hit_top_k 内
chunk_hit_rank 命中时排名,从 1 起
raw_chunk_headers 用于与 qa_gen 的 chunk_headers 对齐展示

12.7 qa_gen_question

字段 说明
status pending / approved / rejected
dup_of 若重复,指向主题库中已有题 id
dup_similarity 向量相似度
embedding 存 JSON 向量,去重用
chunk_content_preview 前 500 字,审核时免查库

12.8 loop_task

累计字段 total_generatedtotal_approvedtotal_recalledtotal_file_hit 等由引擎每轮刷新;expected_chunk_count 与分批规划对齐,用于校验从 dagent 拉取的切片数量是否完整。global_dedup=1 时去重范围扩大到全部已批准题目。

12.9 loop_round

每轮关联 qa_gen_task_idsingle_jump_task_idstatus 跟踪本轮是进行中还是已完成,便于服务重启后从断点阶段继续。


13. REST API 端点详解

以下按模块列出常用端点HTTP 方法后的路径均相对于 /api

13.1 配置 /config

方法 路径 说明
GET /config/platform 列表
POST /config/platform 创建body: name, base_url, org_id, token?
DELETE /config/platform/{id} 删除
GET /config/judge Judge 列表
POST /config/judge 创建 Judge + Embedding 配置

13.2 数据集 /dataset

方法 路径 说明
GET /dataset/list 所有数据集
GET /dataset/{id} 含样本列表
POST /dataset/create name, description
POST /dataset/sample/add 单条样本
POST /dataset/import multipart JSON 文件
POST /dataset/generate 触发 LLM 生成,返回 generate_task_id
GET /dataset/generate/{id} 生成进度
GET /dataset/chunks-preview 预览 hub 下切片规模

13.3 评测任务 /task 与报告 /report

方法 路径 说明
POST /task/run 创建并异步执行 eval_task
GET /task/list 任务列表含 status、progress
GET /report/{task_id} 聚合指标 + interpretation
GET /report/{task_id}/items 分页样本明细

13.4 单跳 /single-jump

方法 路径 说明
POST /single-jump/task Form: env_url, org_id, md_file, top_k, agent_id…
POST /single-jump/task/batch 批量文件
GET /single-jump/task/{id}/summary 汇总指标
GET /single-jump/task/{id}/sections 章节树
GET /single-jump/task/{id}/results ?section= 过滤
GET /single-jump/task/{id}/export-failed-md 导出失败题为 MD

13.5 循环 /loop

方法 路径 说明
POST /loop/task Form 创建循环任务
POST /loop/task/{id}/pause 暂停
POST /loop/task/{id}/resume 恢复
POST /loop/task/{id}/stop 停止
GET /loop/task/{id}/export ?format=md|json&category=all|hit|…

13.6 问题生成 /qa-gen

qa_gen.pyqa_gen_dagent.py 共享前缀 /api/qa-gen:前者上传 MD/文件列表出题,后者从 dagent 拉取目录树与切片。注意路由注册顺序避免路径冲突。

能力 端点示例
dagent 文件树 GET /qa-gen/dagent/tree?org_id=
创建出题任务 POST /qa-gen/task/from-dagent
审核 POST /qa-gen/question/{id}/approve

14. 循环引擎深度解析

14.1 启动与断点续跑

run_loop_taskasyncio.create_task 调用后立即返回。引擎启动时查询 loop_round 最后一条记录:

  • 若上一轮 single_jump 未完成,则继续等待或重试;
  • 若已完成且未达终止条件,则 current_round += 1 并新建 loop_round 行。

服务崩溃后,recover_orphaned_loopsstatus=running 改为 paused,人工确认后调 resume。

14.2 单轮各阶段耗时分布

gantt
    title 典型单轮耗时构成(示意)
    dateFormat X
    axisFormat %s
    section 出题
    拉切片与LLM生成     :a1, 0, 40
    section 去重
    Embedding批量比对   :a2, after a1, 15
    section 召回
    单跳并发检索        :a3, after a2, 30

实际占比取决于 concurrency、切片数、Judge 模型速度及 dagent 集群负载。组 1 批次 1 在远程环境上常见数千条 approved 题,单轮可能持续数十分钟。

14.3 终止条件

条件 行为
max_rounds > 0 且达到 正常结束
max_questions > 0 且累计 approved 达到 正常结束
连续若干轮无新 approved 可配置空轮退出(引擎内 consecutive_empty_rounds
用户 stop 立即写 stopped
异常 status=failederror_message 记录栈信息

14.4 与单跳模块的协作

循环引擎不直接调用 SingleJumpTester 类,而是通过内部函数或 API 层复用「生成 MD → 创建 task → 轮询完成」流程,保证与手动单跳使用同一套解析与命中逻辑,避免统计口径不一致。


15. 单跳 MD 格式与 FileMapper

15.1 MD 结构约定

# 第1章 章节展示标题

## path/to/file.md / doc_name
> 原始切片标题: 完整 headers 路径
# 1. doc_name_Document
> 由 LLM 自动生成的问答对

## Q1: 问题正文?

**A1:** 参考答案正文

> chunk_id: abc123...
  • # 第N章:人类可读章节名;
  • ## 行:与 FileMapper 键一致,通常为 file_name / doc_name
  • Q/A 编号:解析器正则提取;
  • 可选 chunk_id 行:用于切片级命中。

loop_recall_md.pysingle_jump/parser.py 共用同一套生成规则,保证「循环内导出 → 再导入单跳」不丢字段。

15.2 FileMapper 匹配策略

flowchart TD
    SP[section_path 来自 MD] --> E{精确匹配 file_path?}
    E -->|是| OK[file_id]
    E -->|否| C{路径包含?}
    C -->|是| OK
    C -->|否| F[模糊相似度]
    F -->|高于阈值| OK
    F -->|否| MISS[unmatched]

未匹配章节仍参与召回测试,但 is_file_hit 统计为未命中文件;报告中的「章节匹配率」帮助发现路径规范问题。


16. LLM Judge 调用链与成本

16.1 单样本 Judge 调用次数估算

设回答被拆为 N 条声明,检索上下文分为 K 个 chunk

指标 约 LLM 次数
Faithfulness 1 + N
Groundedness 1
Context Precision 1
Context Recall 1
Answer Correctness 1
Answer Relevance 1 + 3 次 embedding

综合评测全开时,单样本可达 10+ 次 LLM 调用。批量任务应合理设置 concurrencyselected_metrics,避免 Judge API 限流。

16.2 Prompt 语言与 JSON 解析

所有 Prompt 为中文指令,要求模型仅输出 JSONOpenAICompatibleJudge 对返回做 json.loads,失败时捕获异常并将 raw 文本写入 judge_detail 便于排查。生产环境建议选用 JSON 遵循能力较强的模型(如 GPT-4o、DeepSeek-V3

16.3 Embedding 用途

  • Answer Relevance:回答 → 生成 3 个假设问题 → 与原始问题做 cosine
  • 循环去重approved 题的 question 字段向量与新区块比对;
  • 二者共用 judge_config 中的 embed 三元组,可与 chat 模型异构部署。

17. 前端页面交互说明

17.1 测试集页

支持三种来源并列:表格手动新增、上传 JSON、侧栏触发「LLM 生成」并轮询 generate_task。详情页展示样本字段,可编辑 relevant_chunk_idsJSON 文本框)。

17.2 评测任务页

表单字段与 eval_task 表一一对应;提交后列表展示进度条 progress/total;完成后跳转 Report。删除任务不级联删除 report 时需确认实现(当前以实现为准)。

17.3 单跳报告页

左侧章节树,右侧问题列表;支持按 section 筛选、查看每条 retrieved JSON、导出未命中 MD。颜色区分 file_hit / chunk_hit / 空召回。

17.4 问题生成页

Tab 区分「文件上传」与「dagent 数据源」dagent 模式先加载文件树勾选 file_ids问题表支持 approve/reject、编辑 Q/Aembedding 去重结果展示 dup_similarity。


18. 故障排查手册

现象 可能原因 处理
任务长期 running 后台协程异常退出未写库 查 server 日志;手动改 status
Judge 全 0 分 API Key 无效或 JSON 解析失败 查 judge_detail 原始返回
Hit Rate 全空 未填 relevant_chunk_ids 补标注或关闭规则指标
单跳章节全 unmatched file 路径与知识库不一致 检查 MD ## 行与 dagent 路径
循环任务暂停无法恢复 进程重启后 _loop_controls 丢失 仅支持同进程 resume否则新起任务
SQLite database locked 并发写冲突 已设 busy_timeout避免多进程写同一库
导出 OOM 一次加载百万级 JSON 使用 export_loop_all_groups 按批次导出
dagent 429 并发过高 降低 concurrency

18.1 日志位置

开发时 uvicorn 标准输出;历史曾写入根目录 server*.log(已清理)。生产建议配置结构化日志到文件或 ELK。


19. dagent 远程集成实践

19.1 环境划分

环境 用途
dagent-dev 功能联调
dagent.d-robotics.cc 14 组循环生产数据所在

platform_configloop_task.env_url 应指向被测环境,避免 dev 数据写入生产库统计。

19.2 跨切片模式cross_chunk

当前部分 dagent 版本不支持检索 API 的 file_id_list 过滤,单跳与循环建议 cross_chunk=true,在更大池中检索后再用 is_file_hit 判断文件是否正确。这与「限定文件内检索」的理想实验设置不同,报告解读时需注明。

19.3 大规模跑数建议

  1. task_groups_plan.json 分批,每批 100 切片;
  2. 组间并行度受 Judge 与 dagent 配额限制,建议组内顺序、组间适度并行;
  3. 每批完成后执行 export_loop_all_groups.py 或 API export 做冷备;
  4. rag_eval.db 体积膨胀后 VACUUM 需停机维护。

19.4 问答集资产用途

docs/exports/ 下 23 万+ 题可用于检索离线评测、训练数据构造、Bad Case 分析、版本回归对比。JSON 行内含 chunk_id 可回连 dagent 切片。


20. SDK CLI 与配置参考

20.1 命令行

rag-eval generate --config config.yaml --output dataset.json
rag-eval run --config config.yaml --dataset dataset.json --output report.json

config.yaml 结构见 docs/config.example.yaml:含 platformjudgeagent_idknowledge_hub_idtop_kconcurrency 等。

20.2 编程式调用

Server 与 CLI 均依赖同一 EvalRunner,保证指标口径一致。自定义 progress_cb 可在 CI 中打印进度条。

sequenceDiagram
    participant CI as CI Pipeline
    participant CLI as rag-eval CLI
    participant RUN as EvalRunner
    participant ADP as Adapter

    CI->>CLI: run dataset.json
    CLI->>RUN: run(config)
    RUN->>ADP: retrieve + chat
    RUN-->>CLI: report.json
    CI->>CI: 阈值门禁 RAG Score > 0.75

21. 多跳召回与多跳出题(技术说明)

21.1 多跳问题模型

多跳样本除 questionanswer 外,核心结构为 hops[]:每一跳描述一个子问题、期望检索的 section_path / file_id,以及该跳对最终答案的贡献权重。评测时引擎按跳次顺序调用检索 API记录每跳 top-K 结果,再合并为 retrieved 全集用于兼容旧版统计。

全链路命中full_hit:所有期望跳的文件或切片均命中;部分命中partial_hit:至少一跳命中。与单跳相比,多跳更考察知识库跨文档关联能力。

21.2 多跳与 Agent 回答

若配置 agent_idjudge_config_id,在分跳检索完成后可调用 Agent 生成最终答案,并由 Judge 评判与标准答案的一致性。该路径同时消耗检索与对话配额,适合端到端 RAG 演示而非纯检索压测。

21.3 multi_hop_gen

multi_hop_gen_task 支持 source=file(上传结构化工单)或 source=dagent(按 org 拉目录)。hops_per_question 控制每题跳数,questions_per_group 控制每组生成数量。生成结果存入 multi_hop_gen_question,经人工审核后可导出为多跳 MD 再回流多跳召回测试。

flowchart LR
    GEN[multi_hop_gen] --> MD[多跳 MD]
    MD --> MH[multi_hop 测试]
    MH --> RPT[分跳命中报告]

22. DatasetGenerator 与测试集自动生成

22.1 流程

DatasetGenerator 接收 file_id_list,通过 Adapter 拉取每个文件的切片列表。对每个切片:

  1. 将切片正文(及可选图片多模态描述)填入出题 Prompt
  2. 调用 Judge LLM 生成「问题 + 参考答案」;
  3. 二次调用质量评估 Prompt低于 quality_threshold 的丢弃;
  4. 写入 eval_sample 或仅返回内存对象。

22.2 与综合评测的衔接

Web UI 的「LLM 自动生成」创建 generate_task 异步任务,完成后样本落入指定 eval_dataset。用户可人工删改再启动 eval_task,形成「半自动」评测流水线。

22.3 标注成本对比

方式 人工成本 适合场景
全手动 黄金集、合规场景
LLM 生成 + 人工抽检 快速扩容
循环测试自动生成 覆盖度优先、允许噪声

23. 报告对象模型EvalReport

EvalReportEvalRunner._build_report 构造,包含:

  • 任务级聚合:各 avg_* 字段、rag_scorehallucination_rate
  • 样本级列表:List[SampleResult],每条含指标分数字段与 judge_detail 字典;
  • 序列化:report.save(path) 输出 JSONCLI 与 Server 共用。

Server 额外调用 Judge 生成自然语言 interpretation,写入 eval_report 表,前端直接展示而无需客户端再调 LLM。

SampleResult 字段与 UI 映射:

字段 报告页展示
hit_rate, mrr, ndcg 检索卡片 / 雷达图轴
faithfulness 等 生成卡片
judge_detail Modal JSON
error 红色错误行

24. 并发模型与资源约束

24.1 asyncio 语义

Server 主线程运行在 uvicorn 事件循环上。run_eval_taskrun_loop_task、单跳后台任务均为 asyncio.create_task 调度的协程共享同一线程。CPU 密集操作(如大 JSON 解析)应避免阻塞过久,必要时用 asyncio.to_thread

24.2 Semaphore

EvalRunnerSingleJumpTester 均使用 asyncio.Semaphore(concurrency) 限制同时在飞的 HTTP 请求数。过大并发会导致:

  • dagent 返回 429 或超时;
  • Judge API 账单激增;
  • SQLite 写锁等待。

推荐生产从 35 起步,循环大规模任务可提到 1020 并监控错误率。

24.3 连接池

DagentAdapter 每次调用新建 aiohttp.ClientSession,简单但高并发下开销大。若需优化可改为 Session 复用(注意线程/协程安全)。


25. 类图SDK 核心类型

classDiagram
    class RAGAdapter {
        <<abstract>>
        +retrieve()
        +chat()
    }
    class DagentAdapter {
        +base_url
        +org_id
    }
    class LLMJudge {
        <<abstract>>
        +score_faithfulness()
        +score_relevance()
    }
    class OpenAICompatibleJudge {
        +client AsyncOpenAI
    }
    class EvalRunner {
        +adapter
        +judge
        +run()
    }
    class EvalSample {
        +question
        +reference_answer
        +relevant_chunk_ids
    }
    class EvalReport {
        +rag_score
        +results
    }
    RAGAdapter <|-- DagentAdapter
    LLMJudge <|-- OpenAICompatibleJudge
    EvalRunner --> RAGAdapter
    EvalRunner --> LLMJudge
    EvalRunner --> EvalReport
    EvalRunner --> EvalSample

26. 安全、合规与权限(建议)

当前版本为内网工具假设:无用户登录、无 RBAC。若对外暴露

  1. 增加 OAuth2 / 公司 SSOAPI 带 Bearer
  2. judge_config.api_key 改为 KMS 引用或环境变量注入,库内不存明文;
  3. 导出接口加审计日志;
  4. 按 org 隔离 platform_config,防止误测他人知识库。

27. 版本演进与已知限制

限制 说明 规避
单进程循环控制 pause/resume 不能跨 uvicorn worker 单 worker 或 Redis 协调
qa_gen 路由共用前缀 两模块同 prefix 注册顺序、集成测试
README 端口 8003 vs 代码 8021 历史文档差异 以实际启动参数为准
超大 SQLite 循环后 DB 数 GB 归档 exports、分库
file_id 过滤 部分 dagent 不支持 cross_chunk

28. 典型使用场景 walkthrough

28.1 场景 A发版前回归

  1. 维护固定 eval_dataset200 条黄金集);
  2. CI 中 rag-eval runselected_metrics 仅开 faithfulness + hit_rate
  3. 对比上一版本 report.jsonRAG Score 下降超过 5% 则失败。

28.2 场景 B新知识库冷启动

  1. qa_gen 从 dagent 选目录出题;
  2. 人工审核 10% 样本;
  3. 单跳全库 MD 导出召回报告;
  4. 针对 file_miss 章节调整切片策略。

28.3 场景 C远程 4140 切片覆盖

  1. task_groups_plan 建 42 个 loop_task
  2. 每组跑满 max_rounds=5 或直至收益递减;
  3. export_loop_all_groups.py 汇总;
  4. 用 exports JSON 训练或分析高频未命中 chunk。

28.4 场景 D多跳文档联调

  1. multi_hop_gen 生成推理链问题;
  2. 导出 MD → multi_hop 任务;
  3. 查看 hop_hit_countfull_hit 比例,定位薄弱跳次。

29. 与早期设计文档的关系

rag-eval-framework-design.md 撰写于框架立项阶段,侧重指标定义与分层理念。本文档(技术规格说明书)对齐当前代码实现补充了循环测试、多跳、qa_gen、SQLite 表结构及运维细节。若两处冲突,以本规格书与源码为准。


30. 名词索引(中英对照)

中文 英文 代码中的关键符号
评测运行器 Eval Runner EvalRunner
平台适配器 RAG Adapter RAGAdapter
评判器 LLM Judge LLMJudge
单跳 Single-hop single_jump
多跳 Multi-hop multi_hop
循环任务 Loop Task loop_task
调和均值 Harmonic Mean rag_score 计算
幻觉率 Hallucination Rate faithfulness < threshold
切片 Chunk RetrievedChunk
知识库 Knowledge Hub knowledge_hub_id

31. 检索规则指标实现细节

本节说明 sdk/rag_eval/evaluators/retrieval.py 中各函数的行为边界,便于复现论文指标或对接外部评测框架。

31.1 Hit Rate@K

对单个问题,若在召回列表前 K 个位置中至少出现一个 chunk_id 属于标注集合 relevant_chunk_ids,则该样本 hit=1否则为 0。数据集层面 Hit Rate 为所有样本 hit 的算术平均。该指标对「只要召回到一个相关文档即可」的场景敏感,无法区分相关结果排名优劣。

31.2 MRR@K

取第一个相关 chunk 的排名 rank从 1 开始),贡献 $1/\text{rank}$;若无相关则贡献 0。数据集 MRR 为样本 MRR 的平均。相比 Hit RateMRR 对「相关结果是否靠前」更敏感,适合排序质量评估。

31.3 NDCG@K

实现采用二元相关度:相关 chunk 为 1否则为 0。计算 DCG@K 时使用 $\sum_i \frac{2^{rel_i}-1}{\log_2(i+1)}$,再以理想 DCG 归一化。若标注集中有多个相关 chunk全部命中可获得更高 NDCG。K 默认与 RunConfig.top_k 一致。

31.4 与 LLM 检索指标的关系

Hit/MRR/NDCG 依赖离散的 chunk_id 标注Context Precision/Recall 依赖自然语言参考答案,可捕捉语义等价但 chunk_id 未标注的情况。生产评测建议两套指标并行规则指标看排序LLM 指标看语义覆盖。


32. Windows 与跨平台注意事项

server/main.pywin32 平台将 stdout/stderr 重定向为 UTF-8避免控制台 GBK 打印特殊 Unicode如数学符号时崩溃。single_jump/tester.pyloop_engine.py 同样调用 reconfigure(encoding='utf-8')

路径上 Server 使用 Path(__file__) 定位 sdkfrontend/dist,避免硬编码盘符。运维脚本应避免写死 d:/project/...,改用相对路径。

SQLite 在 Windows 上注意:

  • 勿将 rag_eval.db 放在同步盘OneDrive易导致锁异常
  • 杀毒软件实时扫描大库文件会拖慢写入,建议排除 server/data/

33. Docker 与 nginx 配置说明

docker-compose.yml 通常定义两个 serviceserver 暴露 API 端口,frontend 构建静态资源或由 nginx 托管。nginx.conf/api 反向代理至 uvicorn其余路径走静态文件并配置 try_files 支持 React Router 前端路由。

Dockerfile.server 安装 requirements.txt,复制 server/sdk/,工作目录设为 serverCMD 为 uvicorn。构建上下文应为 rag-eval 根目录而非 server/,否则找不到 sdk。

镜像内数据库路径需挂载 volume例如 - ./server/data:/app/server/data,防止容器销毁丢数。


34. 提示词模板prompt_template机制

prompt_template 表允许用户保存可复用的出题或评判 Prompt 正文。创建 qa_gen_task 时可指定模板 id生成逻辑将基础 Prompt 与模板合并,实现「同一套切片、不同题型」的 A/B。模板 CRUD 通过 /api/prompt-template 完成,前端可在问题生成页下拉选择。

设计意图是将 Prompt 版本从代码中解耦,使领域专家可在 UI 调整措辞而无需发版 Server。若模板为空则回退代码内默认 Promptdataset/generator.py 与 qa_gen 路由内联字符串)。


35. 数据导出格式说明

35.1 循环导出 JSON 结构

export_loop_all_groups.py 产出顶层字段:

  • exported_atenvironmentorg_id
  • task_groups[]:每组含 batches[]
  • 每 batch 含 questions[],单题含 questionreference_answerchunk_idfile_nameroundquality_score 等。

该格式适合用 jq/Python 做二次聚合,例如按 file_name 统计每文件出题数。

35.2 循环导出 MD 结构

与单跳解析器兼容,可直接作为下一轮 single-jump 上传文件,形成「生成 → 验证 → 修正 → 再验证」闭环。

35.3 综合评测 report.json

CLI rag-eval run --output report.json 输出 EvalReport 全量序列化,含 results 数组。可用于离线绘图或与历史版本 diff。


36. 质量保障建议(组织级)

  1. 黄金集:维护 100500 条人工审核样本,任何检索模型变更必跑;
  2. Judge 模型版本冻结:报告中记录 judge_config.model,避免不可比;
  3. 定期冷备rag_eval.db + docs/exports/ 双轨;
  4. 指标看板:从 eval_report 表 ETL 到 Grafana按日趋势监控 RAG Score
  5. Bad Case 例会:单跳 export-failed-md 导出未命中集,分配给切片优化负责人。

37. 读者常见问题FAQ

问:评测任务为何一直 pending
答:若未触发 create_task 或进程未启动后台协程,会停留 pending。检查 uvicorn 是否运行、API 是否返回 task_id。

问:能否只评检索不评生成?
答:可以。eval_retrieval=1eval_generation=0,或 selected_metrics 仅列检索项。

问:循环任务与 qa_gen 区别?
qa_gen 单轮出题+审核;循环在多轮中自动串联出题、去重、单跳验证并累计统计。

23 万题导出是否含重复?
答:去重后 approved 题;不同轮次可能对同一切片有不同问法,是否语义重复需用 embedding 再滤。

问:如何对接非 dagent 平台?
答:实现 RAGAdapter,在 Server 实例化处按 platform_config.type 分支。

RAG Score 很低但 Faithfulness 很高?
答:调和均值受 Context Precision/Recall 拖累,说明检索上下文质量差而非生成幻觉。


38. 文档贡献与维护

修改核心流程(如新增指标、表结构变更)时,请同步更新:

  1. 本技术规格说明书对应章节;
  2. 根目录 README.md 功能表;
  3. docs/README.md 索引;
  4. OpenAPI 注解(如有)。

Pull Request 模板可要求勾选「已更新技术文档」。


39. Server 启动生命周期

sequenceDiagram
    participant U as uvicorn
    participant M as main.py
    participant DB as init_db
    participant R as recover_orphaned_loops

    U->>M: import app
    M->>M: sys.path sdk
    M->>M: include_router × 11
  Note over M: lifespan start
    M->>DB: executeschema + migrations
    M->>R: running loop → paused
    M-->>U: yield app ready
    Note over M: 处理 HTTP 请求
    Note over M: lifespan end

应用启动时 init_db 执行 schema.sqlCREATE TABLE IF NOT EXISTS,随后 _run_migrations 对老库补列。任何 running 状态的 loop_task 在崩溃后被标记 paused,防止 UI 显示「运行中」却无法控制。

静态资源:若存在 frontend/distapp.mount("/", StaticFiles) 将 SPA 挂在根路径API 仍在 /api需注意路由匹配顺序API 路由先注册)。


40. 单跳 tester 请求载荷说明

SingleJumpTester 向 dagent 发起的语义检索 POST 体核心字段:

  • query:问题正文;
  • org_id:组织;
  • top_k:召回数量(展示用,命中判断可能用更小的 hit_top_k
  • knowledge_hub_id:若任务指定;
  • 可选 file_id_list:非 cross_chunk 时限制范围。

响应解析保留每条结果的 file_idknowledge_md_header_split_idcosine_distance_1headers 等原始字段写入 retrieved JSON以便报告页展示完整证据链。

错误处理:单条 QA 失败写入 error 字段不中断整任务summary 统计时排除或单独计数 error 行。


41. 去重算法dedup参数

service/dedup.py 对候选题计算 embedding与库中已批准题做余弦相似度。超过阈值则标记 dup_of 指向最相似题 id并可选自动 reject。

参数 典型值 影响
相似度阈值 0.850.92 越高越宽松
global_dedup true/false 跨 loop_task 比对
比对字段 question 仅问题文本,不含答案

全局去重在 14 组大规模跑数时显著增加 SQL 与 embedding 调用,但能有效降低「同一文档重复问法」占比。


42. 前端 http 客户端与错误处理

services/http.ts 基于 axiosbaseURL 设为 /api。响应拦截器统一处理 4xx/5xxAnt Design message.error 提示。文件上传使用 FormData,不手动设 Content-Type 以保留 boundary。

长轮询:任务列表页 setInterval 刷新 progress间隔约 25 秒;任务完成后清除定时器。大结果集分页:qa_gen questions 接口支持 page/page_size


43. 评测指标体系与 RAGAS 对照

本平台指标设计参考 RAGAS、TruLens 等框架的常见定义,但实现为独立中文 Prompt数值不可与 RAGAS 官方实现直接划等号。对照关系如下:

本平台 相近概念 差异
Faithfulness faithfulness 两步 claim 验证
Answer Relevance answer_relevancy 反推问题 + embedding
Context Precision context_precision LLM 判 useful
Context Recall context_recall 陈述级支持
Groundedness 部分 attribution 显式 chunk index

对外汇报时建议注明「内部评测框架」及 Judge 模型版本。


44. 性能基准(经验值,非承诺)

在「Judge=gpt-4o、dagent 内网、concurrency=3、样本 100 条、全开指标」条件下,单次 eval_task 约 1540 分钟,主要耗时在 Faithfulness 与 Context 类 LLM 调用。单跳 1000 题、top_k=10、concurrency=10约 1025 分钟,主要受 dagent 检索延迟制约。

循环任务单批 100 切片、5 轮、每切片 5 题量级,总 LLM 调用可达数万次,应安排在非高峰时段并监控配额。


45. 代码阅读路径(新人 onboarding

  1. sdk/rag_eval/runner.py — 理解主流程;
  2. sdk/rag_eval/adapters/dagent.py — 理解外部依赖;
  3. server/service/task_service.py — 理解持久化;
  4. server/api/task.py + frontend/pages/Task — 理解端到端;
  5. server/service/loop_engine.py — 理解最复杂编排;
  6. server/models/schema.sql — 理解数据全貌。

每模块配有本规格书第 4、6 章交叉引用。


46. eval_task 创建请求体字段说明

Web UI 提交 POST /api/task/runJSON 或表单字段与数据库列映射如下。理解该映射有助于用脚本批量建任务。

请求字段 必填 说明
dataset_id 已存在的数据集
platform_config_id dagent 连接
judge_config_id LLM 评判
agent_id 生成层对话用
knowledge_hub_id 检索范围
name 任务展示名
top_k 默认 10
eval_retrieval / eval_generation 布尔
selected_metrics JSON 数组,覆盖上述布尔
file_id_list 限制检索文件
concurrency 默认 3

创建成功后 Server 立即 asyncio.create_task(run_eval_task(task_id))HTTP 响应不等待评测结束。


47. 切片质量与评测结果的因果关系链

评测低分往往并非单一环节失败,建议按下列因果链排查:

flowchart TD
    A[切片过长/过短] --> B[检索噪声大]
    B --> C[Context Precision 低]
    A --> D[关键信息未切片]
    D --> E[Context Recall 低]
    E --> F[Agent 缺上下文]
    F --> G[Faithfulness 低或胡编]
    H[Agent Prompt 不当] --> G
    I[Embedding 模型不适配中文] --> B

平台提供单跳与循环工具定位 B 段;综合评测定位 CG需与知识库工程、Agent 配置协同优化。


48. 未来架构演进方向(规划,非承诺)

  1. 任务队列外置Redis + Celery/RQ支持多 Worker 与任务取消;
  2. PostgreSQL 选项:替代 SQLite 以支撑多实例写入;
  3. Judge 缓存:相同 (question, chunks) 哈希复用评判结果;
  4. 插件化指标Metric 接口注册UI 动态勾选;
  5. 权限与租户org 级隔离与审计;
  6. 标准数据集格式:导入 RAGAS/HuggingFace 格式。

上述方向来自实际运维痛点,实施优先级由产品决定。


49. 缩略语表

缩略语 全称
RAG Retrieval-Augmented Generation
LLM Large Language Model
SSE Server-Sent Events
WAL Write-Ahead Logging
API Application Programming Interface
SPA Single Page Application
CRUD Create Read Update Delete
ER Entity-Relationship
CI/CD Continuous Integration / Delivery
EVB 项目内知识库代号
org_id dagent 组织标识

50. 结语

RAG Eval 平台将可复现的指标体系贴近 dagent 的工程工具链大规模数据生产能力整合在同一仓库中。本文档从架构、数据、流程、API、运维五方面描述当前实现并配有二十余张 Mermaid 图辅助理解。随着代码迭代,请持续更新本文档与根目录 README保持「文档 — 代码 — 数据导出」三者一致,以便团队在任何时间点都能追溯评测结论的依据。


附录 A14 组循环测试与数据资产

大规模远程 dagent 循环测试将 4140 切片划分为 42 批次 × 14 组,详见 循环测试_14组分批规则.md。全量导出235,347 题)位于 exports/

flowchart TB
    subgraph Chunks["4140 切片 / 207 文件"]
        B1["批次 1-3<br/>组1"]
        B2["批次 4-6<br/>组2"]
        BDOT["…"]
        B14["批次 40-42<br/>组14"]
    end

    Chunks --> LT["loop_task × 42"]
    LT --> QR["qa_gen_question"]
    LT --> SR["single_jump_result"]
    QR --> EXP["docs/exports/ 汇总"]
    SR --> EXP

附录 B文档修订记录

版本 日期 说明
v1.0 2026-05-18 首版架构、时序图、数据模型、指标、API、运维与字段字典
v1.1 2026-05-18 扩充第 1220 章,满足万字技术规格要求

本文档随代码演进更新;若与实现不一致,以仓库源码为准。