Prhub

#40164 [Eval][CI] Add basic mrcr eval to tests/evals/

原始 PR 作者 mgoin 合并时间 2026-05-02 00:00 文件变更 8 提交数 3 评论 4 代码增减 +531 / -0

执行摘要

新增 MRCR 长上下文评估到 CI 测试套件

根据PR body,目的是为长上下文行为添加冒烟测试,使用OpenAI公开的openai/mrcr数据集。模型看到带多个近重复“针”的长对话,必须逐字复现指定早期助手回合,前置随机反猜测字符串。这一测试有助于捕捉长上下文场景下的性能回归。

本 PR 是 vLLM 项目在 CI 中引入长上下文准确度评测的重要起步。值得关注的设计决策包括:前缀门控评分机制(避免模型输出随机前缀作弊)、每针数单独阈值捕捉差异化退化、通过配置文件灵活控制测试参数。建议后续关注该评测在 CI 中的运行稳定性,并考虑扩展更多模型配置。

讨论亮点

Review中唯一的讨论线程:vadiklyutiy询问(line 33)为什么禁用思考(enable_thinking=False)。mgoin回应:对于这种需要精确复现早期回合的评估风格,禁用思考很重要,否则思考内容会污染评分。已解决,无进一步争论。

实现拆解

  1. 核心评估模块tests/evals/mrcr/mrcr_eval.py):定义 evaluate_mrcr 函数。通过 HuggingFace datasets 流式加载 MRCR 样本(按 needle 数 2/4/8 分桶),使用服务器 /tokenize 端点验证每个样本的精确 token 数,调用 /v1/models 自动获取模型 ID 和最大上下文长度。评分采用 score_mrcr:若响应不以随机前缀开头判 0 分,否则剥离前缀后使用 difflib.SequenceMatcher 计算与参考答案的相似度。默认设置 chat_template_kwargs.enable_thinking=False 关闭推理模型的思考过程,避免干扰精确复现。

  2. pytest 自动化测试tests/evals/mrcr/test_mrcr_correctness.py):定义 test_mrcr_correctness(config_filename),通过 RemoteOpenAIServer 上下文管理器启动 vLLM 服务器,执行评估,然后根据配置阈值(支持逐 needle 阈值或全局阈值)和容差进行断言。失败时收集所有不达标项。

  3. 参数化配置框架tests/evals/mrcr/conftest.py):pytest_addoption 添加 --config-list-file 选项,pytest_generate_tests 读取该文件中的 YAML 配置路径列表并动态生成测试用例。配置文件位于 configs/ 目录,示例 Qwen3.5-4B.yaml

  4. CI 集成.buildkite/test_areas/lm_eval.yaml):新增 test_area_mrcr 构建块,将 MRCR 测试纳入 Buildkite 流水线,确保每次合并前运行。

  5. 文档与辅助文件README.md 详细说明用法、评分逻辑和配置字段;__init__.py 使目录成为 Python 包;models-small.txt 列出默认配置列表。

文件 模块 状态 重要度
tests/evals/mrcr/mrcr_eval.py 评估引擎 added 7.76
tests/evals/mrcr/test_mrcr_correctness.py 正确性测试 added 6.64
tests/evals/mrcr/conftest.py 测试配置 added 6.09
.buildkite/test_areas/lm_eval.yaml CI 配置 modified 4.21
tests/evals/mrcr/configs/Qwen3.5-4B.yaml 模型配置 added 4.4
tests/evals/mrcr/README.md 说明文档 added 3.81

关键符号

evaluate_mrcr test_mrcr_correctness _load_mrcr_samples score_mrcr discover_server_model count_chat_tokens _call_chat _split_host_port pytest_addoption pytest_generate_tests

关键源码片段

tests/evals/mrcr/mrcr_eval.py test-coverage

核心评估逻辑实现,包含服务器发现、样本加载、并发请求、评分与结果聚合。

# tests/evals/mrcr/mrcr_eval.pydef score_mrcr(response: str, answer: str, random_prefix: str) -> float:
    '''前缀门控的 SequenceMatcher 比率;若缺少前缀则返回 0.0。'''
    if not response.startswith(random_prefix):
        return 0.0
    stripped = response[len(random_prefix):]
    return SequenceMatcher(a=answer, b=stripped, autojunk=False).ratio()
​
​
def _load_mrcr_samples(
    needles: list[int],
    max_prompt_tokens: int,
    num_samples: int,
    seed: int,
    base_url: str,
    model_name: str,
) -> list[dict]:
    '''流式加载 MRCR 样本,按 needle 桶数量均衡,并验证 token 长度。'''
    from datasets import load_dataset
​
    max_chars = max_prompt_tokens * 4 # CHARS_PER_TOKEN
    per_bucket = num_samples // len(needles)
    samples: list[dict] = []
​
    for idx, n in enumerate(needles):
        target = per_bucket + (1 if idx < (num_samples - per_bucket * len(needles)) else 0)
        ds = load_dataset(
            'openai/mrcr',
            data_files=NEEDLE_SHARDS[n],
            split='train',
            streaming=True,
        ).shuffle(seed=seed + n, buffer_size=16)
​
        taken = 0
        for row in ds:
            if int(row.get('n_chars', 0)) > max_chars:
                continue
            prompt = row['prompt']
            messages = json.loads(prompt) if isinstance(prompt, str) else list(prompt)
            n_tokens = count_chat_tokens(base_url, model_name, messages)
            if n_tokens > max_prompt_tokens:
                continue
            samples.append({
                'messages': messages,
                'answer': row['answer'],
                'random_string_to_prepend': row['random_string_to_prepend'],
                'n_needles': int(row['n_needles']),
                'n_tokens': n_tokens,
            })
            taken += 1
            if taken >= target:
                break
    return samples

评论区精华

禁用思考的原因 question

vadiklyutiy 询问 (line 33) 为什么禁用思考(`enable_thinking=False`)。mgoin 回应:对于这种需要精确复现早期回合的评估风格,禁用思考很重要,否则思考内容会污染评分。

结论:mgoin 的解释被接受,未产生进一步争论。 · 已解决

风险与影响

  1. 外部网络依赖:测试依赖 HuggingFace 数据集流式下载,网络不稳定可能导致超时或失败。数据集通过分片控制数据量,降低影响。
  2. CI 时间压力:长上下文推理耗时,Qwen3.5-4B 约 21 秒/40 样本,GPT-oss-20b 约 118 秒。可能在 CI 中增加可观察等待时间。
  3. 额外依赖:需要 datasets 库,需在测试环境预装。
  4. 阈值维护:模型行为可能随权重更新或代码变更变化,需定期调整配置中的阈值。
  5. GPU 资源:测试需要 GPU 节点执行 vLLM 服务器,CI 应确保可用性。

对用户无直接影响;对开发者的影响是合入前需通过 MRCR 测试,确保长上下文准确性不退化;对 CI 系统的影响是新增一个中等耗时的测试阶段,需要 GPU 节点;对团队维护的影响是新增了一系列配置文件,需要根据模型迭代更新阈值。

外部网络依赖 CI 耗时增加 额外 Python 依赖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论