如何用 @mlflow.test 编写 LLM 代理回归测试并在 CI 中做质量门禁
【免费下载链接】mlflowThe open source AI engineering platform for agents, LLMs, and ML models. MLflow enables teams of all sizes to debug, evaluate, monitor, and optimize production-quality AI applications while controlling costs and managing access to models and data.项目地址: https://gitcode.com/GitHub_Trending/ml/mlflow
当你给 agent 换提示词、换模型或重构工具时,需要确信没有悄悄破坏原本正常的行为。MLflow 让你把代理的行为与回归测试写成普通的pytest函数:用@mlflow.test标记测试,用mlflow.genai.evaluate对代理输出运行 scorers(内置或自定义,代码型或 LLM judge),然后对结果做断言。同一次 pytest 会话里的所有测试记录在同一个 MLflow run 下,CI 里的绿色检查结果和可浏览的通过/失败记录来自同一个来源。以下内容适用于 MLflow >= 3.14(@mlflow.test在 3.14.0 引入,源码中标记为 experimental)以及 pytest 环境。
先分清:回归测试不是又一次数据集评估
对数据集跑评估回答的是_测量_问题:“这个数据集上正确率/安全度/相关性分数是多少”,输出是聚合指标(如正确率 82%、安全度 95%)。回归测试回答的是_门禁_问题:“某个具体行为坏了吗”。每个测试都源于你见过的一次具体失败,并变成一个二值 pass/fail 检查,随每次变更运行,让那个问题不可能悄悄复现——比如曾经泄露系统提示词的 prompt 注入,或上周客户反馈的那三个问题。@mlflow.test就是为这个门禁流程设计的:它复用同一套 scorers 和evaluate()引擎,但把结果塑造成适合 pass/fail 断言和 CI 的形态。
准备条件:启用 pytest 插件
@mlflow.test通过一个 pytest 插件运行,它是 opt-in 的,需要启用一次。在pyproject.toml中加入:
[tool.pytest.ini_options] addopts = ["-p", "mlflow.pytest.plugin"]也可以只对单次运行启用:pytest -p mlflow.pytest.plugin。插件源码中列出的另一种持久启用方式是,在根目录conftest.py里写pytest_plugins = ["mlflow.pytest.plugin"](见 mlflow/pytest/decorator.py)。
如果没有启用插件,带@mlflow.test的测试会在运行时报错而不是静默跳过,错误信息为:
@mlflow.test requires the MLflow pytest plugin, which is not enabled in this pytest run. Enable it by adding pytest_plugins = ["mlflow.pytest.plugin"] to your root conftest.py, or by running pytest with `-p mlflow.pytest.plugin`.插件对标记测试做的事(见 mlflow/pytest/plugin.py):每个 pytest 会话创建一个 test run,测试体内的evaluate()继承这个 active run;并对@mlflow.test标记的测试启用 tracing autologging。
可选:在项目中运行一次uvx mlflow@latest agent setup(即mlflow agent setup),可以把 MLflow skills 安装进你的 coding agent(Claude Code、Codex 等),让它了解 tracing、scorers 和@mlflow.test的工作方式,帮你接好 tracing 并代写回归测试。
编写回归测试
把测试标记为@mlflow.test,用你的 agent 和编码了期望行为的 scorers 调用mlflow.genai.evaluate,然后对结果断言:
# tests/regression/test_support_agent.py import mlflow from mlflow.genai.scorers import Guidelines @mlflow.test def test_answers_concisely_in_english(agent): result = mlflow.genai.evaluate( predict_fn=agent.invoke, data=[{"inputs": {"question": "What are your support hours?"}}], scorers=[ Guidelines(name="is_english", guidelines="The answer must be written in English."), Guidelines(name="is_concise", guidelines="The answer must be a single sentence."), ], ) assert result.passed, result.reason示例中agent是你自己定义的pytestfixture,返回你的应用;agent.invoke是 MLflow 对每个输入调用的入口点。data中每一行的inputs对应一次代理调用。
两个结果字段决定门禁行为:
result.passed只有在每一行、每个 scorer 都通过时才为True;result.reason会点名失败的 scorers 并给出各自的 rationale,所以断言失败时 pytest 直接显示_为什么_失败,不需要再跑一遍。
scorers 可以使用 MLflow 的完整范围,包括内置 LLM judges、自定义 judges 和代码型 scorers。文档中同时提供了 Guidelines 这类内置 scorer 的实现可供查看。
好的回归套件不是提前写完的,而是从真实失败中长出来的:生产环境的一次错误、一个 thumbs-down、或记录在 trace 上的反馈,都是下一个测试的原料——把失败案例的输入固定下来,断言你真正期望的行为。
本地运行并验证结果
像运行任何 pytest 套件一样运行:
pytest tests/regression/test_support_agent.py整个会话被记录为单个 MLflow run。在 MLflow UI 打开Evaluation runs页面,选中该 run,可以逐个查看每个测试案例,包括对话、trace 和每条断言的结果:
判断测试是否通过的依据就是 pytest 断言本身:通过则套件为绿色;失败时 pytest 输出中的result.reason会告诉你是哪个 scorer 标记了输出、以及原因。
可选:并行运行整个测试套件
agent 测试很慢:每个测试都运行真实的 agent 和它的 LLM-judge scorers。pytest默认串行执行,一个不算大的套件也会累积到几分钟量级。pytest-xdist 把测试分散到多个 worker 进程来缩短时间。
先安装,并在conftest.py里加一个 hook,让每个 worker 都汇报到同一个 MLflow run——没有这个 hook 时,每个 worker 会各自记录一个 run,结果散落在“每个 worker 一个 run”里:
pip install pytest-xdist# conftest.py import os import mlflow def pytest_configure(config): # Put every worker's test cases on a single MLflow run. if not hasattr(config, "workerinput"): # controller only run = mlflow.start_run(run_name="regression-suite") mlflow.end_run() os.environ["MLFLOW_RUN_ID"] = run.info.run_id然后并行运行:
pytest -n auto # one worker per CPU core pytest -n 4 # fixed number of workers在 CI 中做质量门禁
因为这些就是普通的 pytest 测试,在 CI 里运行它们就是运行 pytest。把MLFLOW_TRACKING_URI指向一个持久的 tracking server(或 Databricks workspace),run 和 trace 会在任务结束后仍然被记录、可审查。如果测试使用 LLM-judge scorers,用MLFLOW_GENAI_JUDGE_DEFAULT_MODEL固定 judge 模型,让每次运行都用同一个模型评分。-n auto让套件并行运行,配合上一节的conftest.py使所有结果落在一个 run 上:
# .github/workflows/agent-regression.yml name: Agent regression tests on: [pull_request] jobs: regression: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install "mlflow>=3.14" pytest pytest-xdist - name: Run regression tests env: MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }} # Judge model for built-in / LLM-judge scorers (or pass model= to each scorer). MLFLOW_GENAI_JUDGE_DEFAULT_MODEL: "openai:/gpt-5-mini" OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: pytest -n auto tests/regression其中MLFLOW_TRACKING_URI和OPENAI_API_KEY需要配置为仓库的 GitHub secrets,指向你实际的 tracking server;MLFLOW_GENAI_JUDGE_DEFAULT_MODEL的值openai:/gpt-5-mini是文档示例,替换为你可用且有权访问的 judge 模型(也可以改为给每个 scorer 单独传model=)。
门禁效果的判定方式与单元测试一致:一条失败的断言使 pytest job 失败,使 check 失败,从而阻塞 pull request。测试失败时,pytest 输出中的result.reason信息指出是哪个 scorer 标记了输出以及原因,被记录的 MLflow run 则让你可以打开完整 trace 进行调试。
限制与边界
- 插件是 opt-in 的:未启用时测试运行阶段直接抛出上面提到的明确错误,不会出现“测试跑了但没有 MLflow run/trace 管理”的静默行为。
@mlflow.test目前标记为 experimental(3.14.0 引入),安装时使用mlflow>=3.14。- skip 和 xfail 的测试不计入该 run 的结果统计(见 mlflow/pytest/plugin.py),run 状态只反映
@mlflow.test标记的测试,不反映同一 pytest 会话中恰好运行的其他测试。 - LLM-judge 断言可能具有非确定性。文档给出的对应措施是让 judge 与人工反馈对齐,保持测试稳定。
下一步
- 用
mlflow agent setup安装 MLflow skills,让 coding agent 基于你的真实失败案例代写回归测试; - 把 LLM judge 与人工反馈对齐,降低 judge 断言的抖动;
- 在 trace 上收集人工与终端用户反馈,作为新回归测试的原料。
完整的流程文档见 docs/docs/genai/eval-monitor/regression-testing.mdx,会话状态管理实现在 mlflow/pytest/session.py。
【免费下载链接】mlflowThe open source AI engineering platform for agents, LLMs, and ML models. MLflow enables teams of all sizes to debug, evaluate, monitor, and optimize production-quality AI applications while controlling costs and managing access to models and data.项目地址: https://gitcode.com/GitHub_Trending/ml/mlflow
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考