ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于 context-retrieval-evals 的 Deep Agents 多文件上下文检索评测任务解析——以 cb-cloud-9 否定推理任务为例

基于 context-retrieval-evals 的 Deep Agents 多文件上下文检索评测任务解析——以 cb-cloud-9 否定推理任务为例 基于 context-retrieval-evals 的 Deep Agents 多文件上下文检索评测任务解析——以 cb-cloud-9 否定推理任务为例【免费下载链接】deepagentsThe batteries-included agent harness.项目地址: https://gitcode.com/GitHub_Trending/de/deepagents本篇文章以开源仓库 de/deepagents 中libs/evals/datasets/context-retrieval-evals/cb-cloud-9任务为实例完整讲解该任务从问题生成、语料构建、沙箱运行到模型判分的全链路并由此展开context-retrieval-evals数据集的设计思路与运行方法。读完本文你将掌握如何阅读一个 Harbor 评测任务、如何本地运行并判分这类多文件上下文检索任务以及仅凭指令在 10 文件语料上完成检索-关联-聚合推理这一评测范式对 Agent 能力的考验所在。cb-cloud-9 任务概述一个多文件语料上的否定推理题cb-cloud-9是context-retrieval-evals数据集共 30 个任务中的一员其问题指令instruction.md非常简短Among all people who live in the same state as the person with internet username reedjustin, who does NOT have any credit cards?Use only the files under/app/files. Write your final answer (and nothing else) to/app/answer.txt.这条指令包含两个关键约束只允许读取/app/files目录下的文件Agent 不得借助外部知识或联网查询来作答最终答案必须以纯文本形式写入/app/answer.txt除此之外不得输出任何多余内容。从问题的类型学角度看这是一道典型的negation否定推理任务先定位互联网用户名为reedjustin的人再找出与其同州的全部人群最后从中筛选出没有任何信用卡的那个人。按 README.md 中难度分层表cb-cloud-9属于medium中等难度且在其生成源头 Context-Bench 的原始分层中同样标注为medium其答案密钥ground truth记录在 case.json 中David Beck。该任务在数据集中归类的信息可以从其 task.toml 的元数据段中直接读出version 1.3 [metadata] source contextbench suite cloud difficulty medium source_difficulty medium question_type negation其中source/suite表明其数据来源是 Context-Bench 的cloud系列difficulty与source_difficulty分别记录校准后的难度档位与来源原始档位在本任务中二者一致question_type则标明了问题类型为negation。数据集背景从 Context-Bench 到 30 个 Harbor 任务cb-cloud-9并不是人工手写的单个评测用例而是由脚本从Context-Bench的cloud合成数据套件中自动生成的。据 context-retrieval-evals/README.md 说明数据集包含30 个上下文检索任务每个任务都完整携带整个语料库10 个文件因此 Agent 无法仅凭文件命名或大小猜测哪些文件有用必须真正执行检索→关联→聚合才能作答数据来源为 Context-Bench 的cloud系列合成记录person/vehicle/pet/account 等虚拟档案源数据为 100 条记录的filesystem_cloud.jsonl任务目录由libs/evals/harbor_adapters/contextbench适配器从这份 JSONL 逐行生成每个cb-cloud-i任务恰好对应第i条记录0 起始下标。关于 30 个任务的难度分配与代表性README 明确写道2 easy · 10 medium · 18 hard这是对全部 100 个源任务做配对评测后抽取的代表性样本难度分层保留的是 Context-Bench 原始分档difficulty与source_difficulty均保留在 task.toml 中而不是事后按模型表现贴的标签。calibration.json则作为机器可读的校准记录保存了配对评测的聚合数据其中cb-cloud-9在 bare harness 下两个模型的 pass6 均为 1.06 次 rollout 全部通过。任务目录结构与关键文件说明一个完整的cb-cloud-9任务目录包含以下内容cb-cloud-9/ ├── environment/ │ ├── Dockerfile # 沙箱镜像预装 curl将 files/ 复制到 /app/files │ └── files/ # 10 个文件语料git-ignored由 populate 命令生成 ├── solution/ │ └── solve.sh # 参考解printf David Beck /app/answer.txt ├── tests/ │ ├── case.json # 每任务唯一的提交文件问题 标准答案 │ ├── test.sh # 校验入口单源模板git-ignored │ ├── judge.py # LLM 判分器单源模板git-ignored │ └── rubric.txt # 判分提示词单源模板git-ignored ├── instruction.md # 发给 Agent 的任务指令 └── task.toml # Harbor 任务元数据 网络白名单这里有一个值得注意的单一来源single-sourced设计10 个文件构成的语料约 6.47 万行文本以及判分所需的test.sh/judge.py/rubric.txt在30 个任务之间逐字节完全相同因此它们并不逐个提交进仓库而是被 git-ignore 后由适配器在本地统一恢复每个任务真正独立提交的只有tests/case.json问题 标准答案。这一点在 README 中被称为 Corpus and verifier are single-sourced。沙箱环境Dockerfile 与网络白名单environment/Dockerfile 非常简单FROM python:3.12-slim # 构建阶段有网络预先安装 curl运行阶段不再执行 apt # 沙箱内所有外部流量都只能走任务网络白名单中的 HTTPS 端点。 RUN apt-get update \ apt-get install -y --no-install-recommends curl ca-certificates \ rm -rf /var/lib/apt/lists/* COPY files/ /app/files/该 Dockerfile 的设计意图是在镜像构建阶段此时有网络预装curl从而让沙箱内 Agent 的运行时引导跳过apt保证运行阶段的所有出站流量都严格经由 task.toml 中的网络白名单控制。task.toml 中的环境段配置为[environment] network_mode allowlist allowed_hosts [astral.sh, *.astral.sh, github.com, *.githubusercontent.com, pypi.org, *.pythonhosted.org, api.smith.langchain.com, api.anthropic.com, api.openai.com, generativelanguage.googleapis.com, openrouter.ai, *.baseten.co, api.fireworks.ai, ollama.com, api.groq.com, integrate.api.nvidia.com, api.x.ai]从适配器源码adapter.py的注释可以确认这里采用的是allowlist白名单而非 no-network。原因在于运行在沙箱内的 langgraph/dcode Agent 需要访问自身的包镜像源pypi 等以及所选模型的 API 端点来完成引导与作答任意其他网络流量仍被拦截从而防止 Agent 通过外网直接抄答案。白名单覆盖了评测工作流可选的所有模型供应商的API 端点而非答案来源站点。参考解solution/solve.shsolution/solve.sh 是数据集的参考解#!/bin/sh set -eu printf %s\n David Beck /app/answer.txt参考解直接以一行命令把标准答案写入/app/answer.txt用于验证整个评测链路构建镜像、运行、收取答案、判分是否打通而不代表检索推理过程本身。指令与答案的生成机制adapter.py 源码级解读理解了任务目录结构后再来看看这些文件究竟是如何被写出来的。任务生成的核心逻辑在 harbor_adapters/contextbench/adapter.py 中关键流程如下parse_task_id(cb-cloud-9)通过正则^cb-(?Psuite[a-z0-9])-(?Pindex\d)$解析出套件名cloud与记录下标9record_for_task_id从 vendored 的filesystem_cloud.jsonl中按下标读取第 9 条记录得到该记录的input问题、ground_truth标准答案与agent_args.extra难度、题型等元信息generate_task创建任务目录复制完整语料到environment/files/写入Dockerfile、.dockerignore、instruction.md、solution/solve.sh、tests/下的判分文件与case.json并生成task.toml任务 ID 与输出目录之间有严格的路径包含校验Path(task_id).name ! task_id即拒绝防止 ID 逃逸出数据集目录。instruction.md的生成代码adapter.py说明了一个细节任务的 instruction 就是记录中的input字段原文加上统一的两句运行约束只用/app/files、答案写入/app/answer.txt。因此 instruction.md 中的提问文本与 case.json 的input字段完全一致后者额外携带ground_truth: David Beck供判分使用。本地运行与填充语料由于语料和判分器是 git-ignored 的在本地运行前必须先用填充命令恢复它们。README 给出了两步标准流程uv run python -m harbor_adapters.contextbench.main --populate datasets/context-retrieval-evals uv run harbor run --path datasets/context-retrieval-evals ...第一步会调用populate_corpusadapter.py遍历数据集目录下所有source contextbench的任务把 vendored 语料vendor/files/*.txt复制到每个任务的environment/files/同时把templates/test.sh、templates/judge.py与vendor/rubric.txt复制进每个任务的tests/第二步再通过 Harbor 运行整个数据集。CIharbor.yml会在构建任务镜像之前自动执行--populate。除--populate外适配器的命令行入口 main.py 还支持参数作用--output-dir DIR生成任务时的输出数据集目录与--populate/--stamp-tiers互斥--task-ids ID...按 ID 生成指定任务如cb-cloud-1--limit N未指定--task-ids时生成cloud套件前 N 个任务--populate DATASET_DIR从单一 vendored 语料恢复各任务的environment/files/与判分文件--stamp-tiers DATASET_DIR用校准 JSON 覆盖每个任务的difficulty字段需搭配--calibration--calibration CALIBRATION_JSON--stamp-tiers读取的校准记录其中--stamp-tiers对应stamp_calibrated_tiersadapter.py生成期写入的difficulty默认等于 Context-Bench 源标签source_difficulty校准完成后把权威的实测档位盖回difficulty行同时保留source_difficulty作为溯源依据。判分机制基于 LLM 的 RubricGrader而非字符串比对这个数据集的判分是一个重要且容易误读的细节它不是把 Agent 输出与标准答案做字符串相等比较。按 README 与适配器注释判分忠实复刻了上游 Letta letta-evals 的model_judge方案——用一个 LLM 评委对照rubric.txt给分对措辞、人名、数字大小写都保持宽容。实现这一判分的正是 templates/judge.py该文件会被复制到每个任务的tests/judge.py其核心机制包括判分提示词读取/tests/rubric.txt作为评委提示模板用string.Formatter().vformat把{input}、{ground_truth}、{submission}三个占位符分别替换为任务问题、标准答案与 Agent 提交的答案文本调用方式通过 Chat Completions 接口调用评委模型使用json_schema响应格式强制返回{score: float in [0, 1], rationale}结构温度规则若评委模型是o1/o3/gpt-5这类推理模型则温度取 1.0因为这些模型 API 拒绝 0.0 温度传 0.0 会 400 报错其余模型取 0.0分数处理score clamp(float(score), 0.0, 1.0)任何异常一律记 0.0 分与上游行为一致/app/answer.txt缺失同样记 0.0容错调用失败会最多重试 5 次仍失败才记 0.0 并在日志中保留最后一次错误信息。与上游相比有两处由 harness 控制的刻意差异评委模型来自环境变量JUDGE_MODELS而非上游固定的gpt-5-mini提交物取自/app/answer.txt而非 Agent 的最后一条助手消息。评委模型与凭据全部由 harness 在 verifier 环境中注入OPENAI_API_KEY、OPENAI_BASE_URL、JUDGE_MODELS、JUDGE_PROVIDER代码中不硬编码任何密钥。由于api.openai.com已在任务网络白名单中判分调用无需额外放行。从 cb-cloud-9 看 Deep Agents 评测的关键能力点最后把cb-cloud-9放回整个评测框架中看它究竟在考核什么全语料检索Agent 拿到的instruction.md不含任何文件线索10 个文件必须逐个读取、筛选才能定位reedjustin及其所在州——对应context retrieval这一数据集命名由来跨记录关联需要把用户名→所在州→同州人群→信用卡持有情况这条推理链上的信息从不同文件或同一文件不同记录中拼接起来否定聚合who does NOT have any credit cards要求对聚合结果施加否定过滤这正是question_type negation的题型定义严格输出协议只能写/app/answer.txt且写答案且只写答案考验 Agent 对输出通道约束的遵守程度。通过 judge.py 这类与上游对齐的 LLM 判分器评测能够容忍模型在名字大小写、措辞变体上的差异把重点放在推理结论是否正确上。对于想要复现或扩展评测的开发者只需运行--populate恢复语料再以harbor run --path libs/evals/datasets/context-retrieval-evals启动即可而 adapter.py 中的生成逻辑也展示了如何把一条 JSONL 记录一键扩展成一个自包含、可判分的 Harbor 任务——这套记录即任务的流水线正是context-retrieval-evals30 个任务能够高效、一致地批量产出的根本原因。【免费下载链接】deepagentsThe batteries-included agent harness.项目地址: https://gitcode.com/GitHub_Trending/de/deepagents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进