基于Dify-Eval构建LLM应用自动化评估体系:从数据驱动到效果验证
1. 项目概述让大模型应用的表现“有迹可循”在开发和迭代一个基于大语言模型LLM的应用时我们常常会陷入一种“感觉良好”的困境。比如你基于 Dify 搭建了一个智能客服或者文档问答机器人每次手动测试几个问题回答得都挺像那么回事流畅、相关甚至有点小惊喜。于是你信心满满地部署上线。然而一旦面对真实用户千奇百怪的提问或者仅仅是对提示词Prompt做了一点点“优化”整个系统的表现就可能变得飘忽不定时好时坏。更棘手的是你很难说清楚它到底“坏”在哪里是回答不准确还是逻辑混乱或者是检索的文档根本不对缺乏一套客观、可量化的评估体系迭代优化就像在黑暗中摸索全凭感觉。这正是dify-eval这个项目要解决的核心痛点。它不是一个独立的评估工具而是一个精巧的“粘合剂”和“自动化流水线”将三个在各自领域表现优异的开源工具——Dify低代码应用开发、LangfuseLLM应用可观测性、RAGASRAG评估框架——串联起来构建了一套从数据准备、批量测试、到多维度自动评分与效果对比的完整闭环。简单来说它的目标就是让你 Dify 应用每一次迭代的效果提升或倒退都能用清晰的图表和数据说话真正做到“有据可依有迹可循”。我花了几天时间深度体验了这个项目它给我的感觉更像是一个为 Dify 开发者量身定制的“质量保障QA中台”。你不再需要手动编写复杂的脚本去调用API、整理结果、再跑评估算法。dify-eval帮你把脏活累活都包了你只需要准备好测试问题它就能自动完成剩下的所有步骤并最终给你一份详细的“体检报告”。接下来我就结合自己的实操经验拆解一下这套系统的设计思路、具体怎么用以及过程中会遇到哪些“坑”。2. 核心设计思路与工具链解析在深入代码之前理解dify-eval如何将三个工具串联起来至关重要。这决定了我们后续配置和使用的逻辑。2.1 核心角色分工Dify, Langfuse, RAGAS 各司其职我们可以把评估一个 Dify 应用想象成一次“产品性能测试”Dify - 被测试的“产品”本身它是我们构建的LLM应用的生产环境。我们通过API向它发送问题输入它返回答案输出。dify-eval的核心任务之一就是自动化地、批量地向这个“产品”发起测试请求。Langfuse - 全方位的“监控与数据记录仪”当 Dify 应用处理请求时如果集成了Langfuse那么这次请求的完整生命周期都会被记录下来。这包括Trace追踪一次请求的完整会话轨迹。Span跨度Trace中的关键步骤比如“检索文档”、“调用LLM生成”。Generation生成每次调用LLM的详细输入Prompt和输出Completion。Event事件自定义的打点事件。 更重要的是Langfuse 提供了一个Dataset数据集功能。你可以把一组标准的问题和可选的标准答案上传到 Langfuse 作为一个数据集。dify-eval正是利用了这个功能将我们的测试集先“寄存”在 Langfuse然后再驱动 Dify 去处理这个数据集里的每一个问题并将每次处理产生的 Trace 与数据集中的条目关联起来。这样所有测试数据、过程数据和结果数据就都在 Langfuse 中汇聚了。RAGAS - 专业的“评分考官”它不关心过程只对“输入-输出”对进行打分。RAGAS 提供了多种评估指标例如Faithfulness忠实度生成的答案是否严格基于提供的上下文检索到的文档有没有胡编乱造Answer Relevance答案相关性答案是否直接回答了问题Context Relevance上下文相关性检索到的文档是否与问题真正相关Context Recall上下文召回率标准答案中的关键信息有多少在检索到的上下文中出现了dify-eval的工作就是从 Langfuse 中取出一次测试运行的“问题Input”、“Dify返回的答案Output”以及“检索到的上下文Context”喂给 RAGAS由 RAGAS 计算出各项分数然后再把分数写回 Langfuse 对应的 Trace 中。2.2 自动化流水线dify-eval如何串联三者整个流程可以被dify-eval的两个核心脚本自动化数据注入与测试执行 (run.py)输入你本地的一个CSV测试文件例如example.csv包含question列可选answer列。步骤1脚本读取CSV文件调用 Langfuse API在 Langfuse 中创建一个数据集并将所有问题和答案作为数据项Item上传。步骤2脚本获取刚创建的数据集ID然后遍历数据集中的每一个问题通过 Dify 的公开API接口即你应用的工作流API或聊天API发起请求。步骤3由于 Dify 已集成 Langfuse每次API调用都会产生一个 Trace。脚本会确保这个 Trace 与 Langfuse 数据集中对应的问题关联起来。输出在 Langfuse UI 上你可以看到一个数据集以及这个数据集下关联的数十或上百条 Trace每条 Trace 记录了对应问题的完整处理详情。自动化评估与评分 (evaluate.py)输入指定 Langfuse 中的一个数据集及其关联的某次测试运行通过dataset_id和session_id定位。步骤1脚本从 Langfuse 中批量拉取指定会话的所有 Trace。从每条 Trace 中解析出input(问题)output(Dify的答案)以及从 Trace 的 Span 信息中提取出本次请求检索到的contexts文档片段列表。步骤2脚本初始化 RAGAS 评估器。RAGAS 评估本身也需要调用 LLM通常是 GPT-4来判断答案质量。这里dify-eval设计得很灵活支持任何 OpenAI 兼容的 API如 OpenAI, Azure OpenAI, 或本地部署的 Xinference。步骤3将(input, output, contexts)三元组批量送入 RAGAS 评估器计算预先定义好的指标如忠实度、相关性等。步骤4将计算出的各项分数作为“评分Score”通过 Langfuse API 写回到对应的 Trace 中。输出在 Langfuse UI 的 Trace 详情页你可以看到新增的评分标签。更重要的是Langfuse 的 Dashboard 可以自动对这些分数进行聚合、可视化轻松比较不同版本测试的平均分、分数分布等。我的理解与补充这套设计的精妙之处在于“职责分离”和“数据中枢”。Dify 只管生成Langfuse 只管记录和存储RAGAS 只管评分。dify-eval作为胶水用自动化脚本消除了手动操作。而 Langfuse 作为数据中枢使得评估结果和过程追踪数据天然结合在一起可视化对比变得水到渠成。你甚至可以在 Langfuse 中直接对比两个不同时间点代表两次代码或提示词迭代的测试会话直观看到各项指标是上升了还是下降了。3. 环境准备与详细配置指南理论清晰后我们开始动手。这里我会基于我自己的部署经验给出更细致的步骤和避坑点。3.1 基础服务部署Dify 与 LangfuseDify 部署按照官方 Docker Compose 部署是最稳妥的方式。这里有一个关键点为了能让dify-eval从外部调用你需要确保 Dify 应用的“工作流”或“聊天”模块提供了公开访问的 API 端点。在 Dify 中创建好你的应用比如一个 RAG 问答应用。进入应用在“发布”选项卡中找到“API 访问”部分。如果你测试的是聊天型应用启用“聊天”API如果是工作流则发布工作流并获取其 API 地址和密钥。务必复制保存好这个 API 地址和密钥它将是dify-eval调用你应用的凭证。Langfuse 部署同样推荐使用 Docker Compose 部署 Langfuse。部署成功后访问其 Web UI默认http://localhost:3000完成初始注册。在 Langfuse 中你需要创建至少一个Project。所有后续的 Trace、Dataset 都会归属到这个项目下。进入项目设置找到API Keys部分创建一个新的密钥。同样保存好LANGFUSE_PUBLIC_KEY和LANGFUSE_SECRET_KEY。关键集成Dify 连接 Langfuse这是让整个流程跑通的核心环节。你需要在 Dify 应用中配置 Langfuse 的跟踪信息。在 Dify 应用的后台管理界面通常是http://你的dify地址/console找到“系统设置”或“模型供应商”相关区域。寻找“Langfuse”或“可观测性”集成选项。你需要填入 Langfuse 的公钥Public Key、私钥Secret Key以及Host即你的 Langfuse 服务地址如http://localhost:3000。配置成功后Dify 应用在处理请求时就会自动将追踪数据发送到你指定的 Langfuse 项目中。3.2 Dify-Eval 项目初始化与配置# 1. 克隆项目 git clone https://github.com/hustyichi/dify-eval.git cd dify-eval # 2. 配置环境变量 cp .env.example .env接下来是重头戏编辑.env文件。我结合源码和实测解释每个关键变量# Langfuse 配置 - 数据记录和存储中心 LANGFUSE_PUBLIC_KEYpk-lf-xxxxxx # Langfuse 项目的公钥 LANGFUSE_SECRET_KEYsk-lf-xxxxxx # Langfuse 项目的私钥 LANGFUSE_HOSThttp://localhost:3000 # 你的 Langfuse 服务地址 LANGFUSE_PROJECT_IDyour-project-id # Langfuse 中的项目ID在项目设置里能找到 # Dify 配置 - 被评估的应用 DIFY_APP_IDapp-xxxxxx # 你的 Dify 应用ID DIFY_API_KEYapp-xxxxxx # 你的 Dify 应用 API 密钥 # 注意DIFY_API_URL 需要指向你应用的具体 API 端点。 # 如果是聊天应用通常是https://api.dify.ai/v1/chat-messages # 如果是工作流则是你发布工作流后得到的专属 URL。 DIFY_API_URLhttps://api.dify.ai/v1/chat-messages # RAGAS 评估器配置 - 评分考官需要的 LLM # RAGAS 评估需要调用一个 LLM 来评判答案质量这里配置这个 LLM 的访问方式。 OPENAI_API_KEYsk-xxxxxx # 你的 OpenAI 格式 API 密钥 OPENAI_API_BASEhttps://api.openai.com/v1 # API 基础地址 # 如果你使用 Azure OpenAI 或本地模型如 Xinference, LocalAI只需将 BASE 改为对应的地址即可。 # 例如 Xinference: OPENAI_API_BASEhttp://localhost:9997/v1 EVALUATION_MODELgpt-4-turbo-preview # 用于评估的模型名称需与你的 API 服务匹配重要提示与避坑DIFY_API_URL是最容易出错的地方。务必确认你调用的是正确的端点。一个快速测试方法是在命令行用curl命令带上你的DIFY_API_KEY和DIFY_APP_ID去调用一下这个 URL看是否能收到正常响应。LANGFUSE_PROJECT_ID在 Langfuse UI 的项目设置页面可以找到是一个字符串 ID不是项目名称。关于评估模型使用 GPT-4 虽然准确但成本较高。对于内部迭代测试完全可以使用更经济的模型如gpt-3.5-turbo或者本地部署的Qwen2-72B-Instruct这类高性能开源模型通过 Xinference 提供 OpenAI 兼容接口。评估质量可能略有差异但用于横向对比版本效果是完全足够的。3.3 依赖安装与测试数据集准备项目使用 Poetry 管理依赖确保系统已安装 Poetry。# 进入项目目录后 poetry shell # 创建并激活虚拟环境 poetry install # 安装所有依赖准备你的测试数据集。项目提供了一个example.csv模板question,answer 公司的成立时间是什么时候,我司成立于2020年。 公司的主要业务有哪些,我们专注于企业级AI解决方案与云计算服务。 如何联系客服,请发送邮件至 supportexample.com 或拨打 400-xxx-xxxx。question列是必须的代表你要测试的问题。answer列是可选的代表该问题的“标准答案”或“参考答案”。如果提供answerRAGAS 可以计算像“答案相似度Answer Correctness”这类需要ground truth的指标如果不提供则只能计算 faithfulness、relevance 等不需要标准答案的指标。你可以根据你的应用场景构建几十到上百条有代表性的测试问题。问题应覆盖核心功能、边界情况和易错点。4. 核心脚本实操与过程解析环境就绪数据备好现在可以启动自动化流水线了。4.1 执行批量测试python run.py这个脚本完成了“数据上传”和“驱动测试”两步。python run.py --dataset_name “My_First_Eval” --input_file “./my_test_data.csv”--dataset_name: 指定在 Langfuse 中创建的数据集名称。--input_file: 你的测试数据 CSV 文件路径。脚本内部发生了什么读取与上传脚本读取你的 CSV 文件通过 Langfuse API 创建一个名为My_First_Eval的数据集并将每一行作为一个数据项Item上传。每个 Item 在 Langfuse 中会有一个唯一的id。创建会话脚本会在 Langfuse 中为本次批量测试运行创建一个Session。一个 Session 包含了本次运行的所有 Traces方便后续分组查看和比较。遍历与调用脚本遍历数据集中的每一个 Item即每一个问题构造请求体调用你在.env中配置的DIFY_API_URL。关联追踪在调用 Dify API 时脚本会在请求头中传递一个特殊的trace_id和dataset_item_id。这确保了 Dify 端产生的 Trace 能正确关联回 Langfuse 中对应的数据集项和本次会话。进度与日志脚本会打印进度成功或失败都会有相应日志。实操现场记录与注意事项网络与超时如果测试集很大比如100问题整个流程可能耗时较长。建议在.env同目录下可以临时设置 Python 的请求超时时间或者在脚本中增加重试逻辑原脚本可能比较简单。我遇到过一次因为网络波动导致中间某个请求失败整个脚本就停止了。建议对于重要测试可以先用小数据集5-10个问题跑通全流程。查看实时结果在脚本运行过程中你就可以打开 Langfuse UI进入对应的 Project 和 Dataset应该能看到 Traces 正在一条条生成并且状态是“Streaming”或“Completed”。点击任意一条 Trace可以看到 Dify 工作流执行的详细步骤、检索到的文档、LLM 的输入输出非常清晰。API 限速注意你的 Dify 云服务或自部署服务是否有速率限制。如果一次性发送大量请求可能导致部分失败。可以考虑在run.py的循环中增加time.sleep(0.5)来缓解。4.2 执行自动化评估python evaluate.py测试数据跑完后Traces 里已经有了输入问题和输出Dify的答案以及检索上下文如果应用是RAG。现在需要请“考官”RAGAS来打分。python evaluate.py --dataset_name “My_First_Eval” --session_name “run_20240527”--dataset_name: 之前创建的数据集名称。--session_name: 之前run.py运行时创建的会话名称。如果不指定脚本可能会使用该数据集下最新的会话。脚本内部发生了什么获取数据脚本根据数据集名和会话名从 Langfuse 拉取所有相关的 Traces。提取评估三元组对于每条 Trace脚本尝试解析出input(问题)output(模型回答)以及最重要的contexts。contexts的提取依赖于 Dify Trace 的特定结构通常是从名为“检索”或类似含义的 Span 中提取。这是最容易出问题的地方如果你的 Dify 工作流结构不同可能需要修改evaluate.py中的extract_contexts_from_trace函数。初始化评估器脚本使用.env中的OPENAI_API_BASE和OPENAI_API_KEY初始化 RAGAS 的评估器并指定评估模型 (EVALUATION_MODEL)。定义评估指标脚本中有一个DEFAULT_METRICS列表默认可能包含faithfulness,answer_relevance,context_relevance等。RAGAS 会根据这些指标进行计算。批量评估与回写脚本将三元组列表和指标列表交给 RAGAS。RAGAS 会批量调用 LLM 进行评估注意这会产生额外的 LLM API 调用费用。评估完成后脚本将每个指标的分值一个0到1之间的浮点数通过 Langfuse API 写回到对应 Trace 的scores部分。实操现场记录与注意事项评估成本这是实打实的 LLM API 调用。如果测试集有100条评估3个指标那么大约会产生 100 * 3 300 次 LLM 调用RAGAS 内部有优化但调用次数与数据量、指标数正相关。使用 GPT-4 成本不菲。强烈建议首次使用小数据集并确认评估结果符合预期后再扩大规模。也可以考虑使用更便宜的评估模型。上下文提取如果evaluate.py运行后在 Langfuse 中看不到分数首先检查日志。很可能是extract_contexts_from_trace函数无法从你的 Trace 中找到上下文。你需要打开一条成功的 Trace 详情页查看其 JSON 结构找到存储检索文档的路径然后相应地修改提取函数。指标定制DEFAULT_METRICS是可以修改的。RAGAS 提供了很多指标你可以根据需求增删。例如如果你没有标准答案 (answer)就不要包含answer_correctness这类指标。5. 结果查看、分析与版本对比所有步骤成功后价值的时刻就到了。5.1 在 Langfuse 中查看评估结果单次请求详情在 Langfuse 的 Traces 列表页找到你的会话下的任意一条 Trace 点击进入。在详情页除了能看到完整的调用链现在应该多了一个“Scores”部分。这里以标签页或图表形式展示了 RAGAS 给出的各项分数。你可以精确地看到对于某个具体问题你的应用在“忠实度”上得了0.8分在“答案相关性”上得了0.9分。批量评分概览在 Langfuse 的Dashboard或Analytics模块你可以创建基于 Score 的图表。例如可以创建一个图表显示本次会话所有 Traces 的faithfulness平均分、分数分布直方图等。这让你对本次测试的整体效果一目了然。数据集管理在 Dataset 页面你可以看到所有测试问题以及每个问题关联的最新 Trace 和评分。你可以在这里直接重新运行某个问题进行手动验证。5.2 多版本效果比较这是dify-eval结合 Langfuse 最强大的功能。假设你修改了 Dify 应用中的提示词想看看效果是提升还是下降了。进行第一次评估使用原始版本的应用通过run.py和evaluate.py完成一轮测试。记下这次运行的session_name例如v1_prompt。修改应用并部署修改你的 Dify 应用比如优化提示词、调整检索参数。进行第二次评估确保使用相同的测试数据集(My_First_Eval)。运行run.py时会关联到同一个数据集但会创建一个新的会话例如v2_prompt。然后运行evaluate.py针对新会话评分。在 Langfuse 中对比在 Langfuse 的 Dashboard 中你可以创建一个图表选择数据源为Dataset: My_First_Eval然后在筛选条件中选择Session并同时选中v1_prompt和v2_prompt。然后绘制faithfulness的平均分折线图或柱状图。你可以清晰地看到版本二的忠实度平均分从 0.75 提升到了 0.82。同样的方法可以对比所有指标。我的心得这种基于同一数据集、自动化评估的对比其说服力远超人工感觉。它把“我觉得好像更准了”变成了“客观数据显示答案忠实度提升了9%”。这对于向团队汇报迭代效果、或是决定是否上线某个修改提供了至关重要的数据决策依据。6. 常见问题排查与进阶技巧在实际操作中你肯定会遇到一些问题。这里记录一些我踩过的坑和解决方案。6.1 问题排查清单问题现象可能原因排查步骤与解决方案run.py上传数据集失败1. Langfuse 密钥或主机地址错误。2. 网络不通。1. 检查.env中的LANGFUSE_*配置确保公钥、私钥、主机地址正确无误。可用curl命令测试 Langfuse API 连通性。2. 确认 Langfuse 服务正常运行 (docker ps)。run.py调用 Dify API 失败1. Dify API URL 或密钥错误。2. Dify 应用未发布或 API 未启用。3. 请求超时或限流。1. 使用curl或 Postman 手动测试DIFY_API_URL确认能收到响应。2. 登录 Dify 控制台确认应用已发布且获取了正确的 API 密钥和端点。3. 在脚本中增加错误处理和重试机制或加入延时。Langfuse 中 Trace 无关联Dify 未正确集成 Langfuse 跟踪。1. 确认 Dify 后台已配置 Langfuse 的密钥和 Host。2. 手动在 Dify 应用界面提问检查 Langfuse 中是否有 Trace 生成即使不通过run.py。如果没有说明 Dify-Langfuse 集成有问题。evaluate.py报错无法提取上下文Trace 结构不符合脚本预期。1. 在 Langfuse UI 中打开一条 Trace查看其完整的 JSON 结构通常有“Raw Trace”或类似视图。2. 找到存储检索文本contexts的路径。修改evaluate.py中的extract_contexts_from_trace函数使其能正确解析你的 Trace 结构。evaluate.py评分失败或分数为 NaN1. RAGAS 评估模型调用失败。2. 输入数据格式不对如contexts为空列表。1. 检查.env中的OPENAI_API_*配置确保评估 LLM 可用。可以写个简单脚本测试 OpenAI 接口。2. 检查脚本日志看 RAGAS 评估时的输入数据。确保input,output,contexts都不是None或空字符串。对于contexts为空的情况RAGAS 的某些指标如faithfulness可能无法计算。Langfuse 中看不到评分1.evaluate.py运行出错但未终止。2. 评分写入了错误的 Trace 或项目。1. 仔细查看evaluate.py的运行日志确认是否有“Scores uploaded”之类的成功信息。2. 确认evaluate.py使用的dataset_name和session_name与run.py创建的一致。6.2 进阶使用技巧定制化评估指标dify-eval默认使用的DEFAULT_METRICS可能不完全符合你的需求。深入研究 RAGAS 的文档它提供了数十种指标。例如你可以加入context_recall需要标准答案来衡量检索的完整性或者加入aspect_critique来评估答案在某个特定维度如安全性、简洁性上的表现。只需修改evaluate.py中的指标列表即可。集成到 CI/CD 流水线你可以将dify-eval的评估流程脚本化并集成到你的 CI/CD如 GitHub Actions, GitLab CI中。每次代码合并或提示词更新自动触发一轮针对核心测试集的评估并将关键指标如平均忠实度作为一个检查点。如果分数低于某个阈值则自动标记构建失败或发出警报。这能将大模型应用的“质量门禁”落到实处。处理非RAG应用如果你的 Dify 应用不是 RAG 应用例如只是一个纯对话机器人那么contexts字段可能为空。你需要修改评估逻辑使用不需要上下文的指标例如answer_relevance答案相关性、answer_similarity如果有标准答案或者使用 RAGAS 的answer_correctness结合上下文和标准答案但上下文可为空需验证。更好的方式是根据你的评估目标自定义一些基于 LLM 的评判规则。优化评估成本抽样评估对于大型测试集不必对每条数据都进行全指标评估。可以随机抽样一部分进行详细评估。使用轻量级模型在迭代初期使用gpt-3.5-turbo进行快速、低成本的评估。在最终版本确认前再用gpt-4进行更精确的评估。缓存评估结果RAGAS 评估本身是确定性的对于相同的输入、输出、上下文和模型分数应相同。可以考虑将评估结果缓存起来避免重复计算。不过dify-eval目前每次运行都会重新计算。这个项目为我打开了一扇门让我意识到大模型应用的迭代可以如此数据驱动。它或许不是万能的比如在评估指标的选取、对复杂工作流的支持上可能需要一定的定制开发。但它提供的自动化框架和与 Langfuse 的深度集成已经极大地降低了构建评估体系的门槛。如果你正在严肃地开发和优化基于 Dify 的 LLM 应用我强烈建议你花点时间把dify-eval跑起来。最初的配置和踩坑可能会花费一些精力但一旦 pipeline 打通它带来的回报——清晰的优化方向和可靠的效果验证——绝对是值得的。