跳到主要内容

DeepEval — 架构与原理

30 秒导读: DeepEval 是一个开源的 LLM 评测框架。你给它一组「输入 + 模型实际输出」的测试用例,再选几个指标(比如「答案相不相关」「有没有幻觉」「工具调对没」),它就像 pytest 跑单元测试一样,给每个用例打分、判定通过/失败。绝大多数指标内部是用一个 LLM 去当裁判(LLM-as-a-judge),把模型那段自由文本拆成能逐条判定的小命题再算分。


1. 这是什么(零基础也能懂)

一句话定义: DeepEval 是「给 LLM 应用写单元测试」的框架——把 pytest 那套 assert 思路,搬到「输出是一段自由文本、没有标准答案」的场景。

它要解决的真实痛点: 传统单元测试靠 assert output == expected。但 LLM 的输出是自然语言,没有唯一正确答案——同一个意思有一百种说法。你没法用字符串相等去判断「这个回答到底好不好」。DeepEval 的答案是:让另一个 LLM(或统计方法)来当裁判,按你定义的标准给输出打一个 0~1 的分,再和阈值比较得出通过/失败。

给谁用: 在搭 RAG 流水线、聊天机器人、AI agent 的工程师。典型用途——

  • 调 prompt / 换模型时,跑一批用例看分数有没有掉(防 prompt 漂移)。
  • 从 OpenAI 切到 Claude 前,用同一批指标确认质量没退化。
  • 把评测挂进 CI,像跑测试一样守住质量门槛。

它能做什么(功能速览):

能力说明
现成指标库40+ 指标:RAG(答案相关性/忠实度/上下文召回)、Agentic(任务完成/工具正确性)、多轮对话、安全(毒性/偏见/PII 泄漏)等
自定义指标GEval(自然语言描述标准)和 DAGMetric(决策树式确定打分)让你不写代码就造指标
任意裁判模型内置 OpenAI / Anthropic / Gemini / Ollama / 本地模型……裁判模型可换
pytest 集成deepeval test run,把评测当测试跑,挂 CI
数据合成Synthesizer 从文档自动造测试用例(golden)
链路追踪 + 组件级评测@observe 装饰器给 agent 的每一步(LLM 调用 / 检索 / 工具)单独挂指标

用起来什么样: 最小的一次评测——

# 示意,非源码:DeepEval 最小用法
from deepeval import evaluate
from deepeval.test_case import LLMTestCase
from deepeval.metrics import AnswerRelevancyMetric

# 1) 一个测试用例 = 输入 + 模型实际输出
test_case = LLMTestCase(
input="法国的首都是哪里?",
actual_output="巴黎是法国的首都,也是它最大的城市。",
)

# 2) 选一个指标,阈值 0.7
metric = AnswerRelevancyMetric(threshold=0.7)

# 3) 跑评测:内部用一个 LLM 当裁判,给出 score / reason / 通过与否
evaluate(test_cases=[test_case], metrics=[metric])

一句话直觉/类比: 把 DeepEval 当成「LLM 输出的 pytest + 阅卷老师」。pytest 负责「批量跑用例、收集通过/失败、出报告」这套骨架;阅卷老师(裁判 LLM)负责「这段没有标准答案的文字,按评分标准给几分」。DeepEval 的全部精华,就在于把「阅卷」这件主观的事,拆成一串可逐条判定的小问题,让分数稳定、可解释。


2. 顶层全景(它大概怎么转)

一次评测,数据从左到右流过四个部件:

你写的 选一组 跑起来 每个指标内部
┌──────────┐ ┌──────────┐ ┌──────────────┐ ┌────────────────────┐
│ 测试用例 │ ───► │ 指标 │ ───► │ evaluate() │ ───► │ 裁判 LLM 打分 │
│LLMTestCase│ │ Metric │ │ 执行引擎 │ │ (拆命题→裁决→算分) │
│ 输入+输出 │ │ 带阈值 │ │ 并发/缓存/报告│ │ → score / reason │
└──────────┘ └──────────┘ └──────────────┘ └────────────────────┘
▲ │
│ 统一模型抽象 │
└──────── DeepEvalBaseLLM ◄────────────────┘
(OpenAI/Claude/Gemini/本地… 可换)

怎么读这张图: 用例和指标是你提供的「原料」;evaluate() 是流水线总控(管并发、缓存、出报告);真正的智力活发生在最右——每个指标内部调一个裁判 LLM,把输出拆成小命题再算分。最底下的 DeepEvalBaseLLM 是统一的模型接口,让裁判模型可以任意替换。

部件一句话职责:

部件干什么在哪
LLMTestCase一条评测样本:input / actual_output / 可选 expected_outputcontexttools_calledtest_case/llm_test_case.py
BaseMetric所有指标的基类:定义 measure() / a_measure() / is_successful()thresholdscore 等字段metrics/base_metric.py
具体指标AnswerRelevancyMetricGEvalDAGMetricFaithfulnessMetric… 各自实现「怎么打分」metrics/<name>/
evaluate() / assert_test()对外两个入口:批量评测 与 单用例断言(pytest 用)evaluate/evaluate.py
执行引擎并发跑用例、缓存结果、收集 TestResult、出控制台报告evaluate/execute/evaluate/console_report.py
DeepEvalBaseLLM裁判模型的统一接口;initialize_model() 按配置挑具体 providermodels/base_model.pymetrics/utils.py
@observe + 追踪给 agent 的每一步建 span,可在组件级别挂指标tracing/tracing.pyevaluate/execute/agentic.py
pytest 插件deepeval test run 把评测当测试跑、收集进 test runplugins/plugin.py

主线走一遍(高层,不进代码):

  1. 你构造若干 LLMTestCase,并实例化几个指标(每个带 threshold)。
  2. evaluate(test_cases, metrics)。引擎按异步/同步把「用例 × 指标」组合分发执行。
  3. 每个指标的 measure(test_case) 跑起来:取出它关心的字段(如 inputactual_output),组装 prompt,调裁判 LLM,把回复解析成 命题列表 / 裁决 / 分数 + 理由
  4. 分数和 threshold 比较 → success。引擎收集每条结果,渲染成表格报告(可选上传 Confident AI 云端)。

3. 主线之外的两条暗线(先有个印象,细节在各章)

DeepEval 不止「跑指标」。两条贯穿全局的设计值得先点出来,后面章节展开:

暗线一:所有指标长一个样。 不管是 RAG 指标还是 agent 指标,内部几乎都是同一个套路——「把自由文本拆成小命题 → 对每条小命题做二元裁决 → 用命题比例算分 → 再让 LLM 写一句理由」。理解了这个套路(见 02 章),你就理解了一大半指标。

暗线二:评测既能「黑盒」也能「白盒」。

  • 黑盒(端到端): 只看 input → actual_output,不关心中间怎么产生的——上面的最小例子就是。
  • 白盒(组件级):@observe 给 agent 的每一步建 span,给单个 LLM 调用或单个检索步单独挂指标。这让你能定位「到底是检索拉错了,还是生成编造了」(见 04 章)。

4. 阅读地图(建议顺序)

本项目较大,拆成 4 章,由浅入深

顺序章节读完你会懂
101-test-case-and-metric-contract.md评测的两块地基:LLMTestCase 装什么、BaseMetric 规定每个指标必须实现什么。是后面所有章节的词汇表。
202-llm-judge-metrics.md最该读的一章。LLM 裁判指标的通用套路(命题→裁决→打分),以 AnswerRelevancyMetric 和旗舰的 GEval(含 logprob 加权打分这一精华)为例。
303-dag-deterministic-metric.md当「单个裁判 LLM」太不可控时,怎么用 DAGMetric 把打分拆成一棵确定性的决策树。
404-evaluate-and-tracing.mdevaluate() 流水线、pytest 集成、@observe 组件级评测、以及让裁判模型可换的 DeepEvalBaseLLM 抽象。

最短路径: 只想知道「它怎么给一段文本打分」→ 直接读 02 章。想把它挂进 CI / agent → 加读 04 章。


5. 横向对比(同 area 兄弟)

DeepEval 属于 evals-observability。和兄弟项目的取舍差异:

  • vs ragas ragas 专攻 RAG 四件套(DeepEval 也内置了 RagasMetric 做桥接,见 metrics/ragas.py);DeepEval 覆盖面更广(agent / 多轮 / 安全),且把「pytest 式断言」做成一等公民。
  • vs agentops / 纯 observability: 那类工具重在「记录 agent 跑了什么」;DeepEval 重在「判定跑得好不好」——它也有追踪(tracing/),但追踪是为「在组件级别挂指标」服务的。

核心区分点一句话:DeepEval 把评测当「测试」,把指标做成「可拆解、可解释、模型可换的裁判」。


6. 代码地图(导航索引)

主题文件关键符号
对外 API 暴露deepeval/__init__.py_expose_public_apievaluateassert_testinstrument
测试用例数据模型deepeval/test_case/llm_test_case.pyLLMTestCaseToolCallSingleTurnParams
多轮对话用例deepeval/test_case/conversational_test_case.pyConversationalTestCaseTurn
指标基类契约deepeval/metrics/base_metric.pyBaseMetricPromptMixinBaseConversationalMetric
评测入口deepeval/evaluate/evaluate.pyevaluateassert_test
执行引擎deepeval/evaluate/execute/a_execute_test_casesexecute_test_cases
旗舰自定义指标deepeval/metrics/g_eval/g_eval.pyGEvalcalculate_weighted_summed_score
确定性图指标deepeval/metrics/dag/DAGMetricDeepAcyclicGraphBinaryJudgementNode
模型抽象deepeval/models/base_model.pyDeepEvalBaseLLMgenerate_with_schema
模型选择deepeval/metrics/utils.pyinitialize_modelis_native_model
追踪 / 组件级评测deepeval/tracing/tracing.pyobserveObserver
pytest 插件deepeval/plugins/plugin.pypytest_runtest_callpytest_sessionstart