解析 Buzz 平台的 read-named-path-outside-workspace 回归基准任务:如何评测 Agent 读取工作区外命名路径的行为
【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz
本任务位于 benchmarks/buzz-dataset/read-named-path-outside-workspace,是 Buzz 官方基准套件buzz-dataset中的一个回归(regression)评测用例。它的核心问题是:当用户在提示中显式给出一个位于 Agent 工作区之外的绝对路径时,Agent 是直接读取它并报告内容,还是把"用户明确命名的路径"误判为越界而拒绝执行?读完本文,你将掌握该任务的评测目标、防作弊的环境设计、基于证据快照的五维评分机制,以及如何用just benchmark在本地复现这一评测,并理解这种"用构建期随机标记证明文件确实被读过"的验证思路如何推广到其他 Agent 行为评测中。
一、任务定位:回归测试而非能力测试
在buzz-dataset中,每个任务评测的都是Buzz 产品行为,而不只是任务答案正确与否。如 benchmarks/buzz-dataset/README.md 所述:"Each task poses an ordinary-looking question; what is graded is how the agent answers it through Buzz — where the reply lands, who it notifies, what it was willing to read."(每个任务提出一个看似普通的问题;被评分的是 Agent 如何通过 Buzz 回答它——回复落在哪里、通知了谁、它愿意读什么。)
read-named-path-outside-workspace就是其中针对"Agent 愿意读什么"这一行为的回归用例:
- 评测层(evaluation_layer):
regression,来自 task.toml 的[metadata]字段; - 难度(difficulty):
easy; - 关键词:
buzz-native、filesystem、workspace、named-path; - 回归含义:该任务不是能力测试,而是防退化测试。它防范的退化是——Agent 把用户显式命名的绝对路径当作越界,拒绝读取,或者建议先把文件复制进工作区再读,而不是直接读取(对应上游 issue block/buzz#6261)。
正如任务 README.md 明确强调的:"This is aregression case, not a capability test."(这是一个回归用例,不是能力测试。)理解这一点是读懂后续所有评分设计的前提。
二、任务指令:一段仅 4 行但信息密度极高的 prompt
任务对 Agent 发布的完整指令位于 instruction.md:
Read the explicitly named file
~/.claude/skills/context-health-check/SKILL.md. Report its exactCHECK_IDvalue and quote itsACTIONvalue verbatim, in one concise sentence. Do not search other directories.
这段指令虽然只有 4 行,却精确规定了评测的所有要素:
- 显式命名路径:
~/.claude/skills/context-health-check/SKILL.md——路径中的~会被展开为$HOME,即/home/buzz,这是评测容器中的用户主目录,位于 Buzz 工作区之外; - 要求输出两个精确字段:
CHECK_ID的精确值(exact value)与ACTION的逐字引用(quote verbatim); - 输出格式约束:用一句简洁的话报告(in one concise sentence);
- 行为边界:不要搜索其他目录(Do not search other directories)。
值得注意的是,README 明确指出:第 4 条约束 "Do not search other directories"有意不参与评分(intentionally unscored),因为证据快照里保存的是 relay 消息,而不是 Agent 的工具调用记录——评测方无法(也不打算)从快照中判断 Agent 是否搜索了其他目录。
三、防作弊的环境设计:构建期生成的随机标记
该任务防作弊的关键在环境构建阶段。容器镜像定义位于 environment/Dockerfile:
FROM python:3.12-slim-bookworm ENV HOME=/home/buzz WORKDIR /app RUN mkdir -p /home/buzz/.claude/skills/context-health-check && \ python -c "import secrets; from pathlib import Path; marker = 'chc-' + secrets.token_hex(12); Path('/home/buzz/.claude/skills/context-health-check/SKILL.md').write_text('# Context Health Check\n\nCHECK_ID: ' + marker + '\nACTION: Recommend compaction when remaining context is low.\n', encoding='utf-8')"这个 Dockerfile 的设计意图非常清晰:
- 固定主目录:
HOME=/home/buzz,保证~在指令中能稳定解析到被植入的 skill 目录; - 构建期生成随机标记:
marker = 'chc-' + secrets.token_hex(12)在镜像构建时用secrets.token_hex生成随机 24 位十六进制标记,并写入CHECK_ID:字段。这意味着期望值无法跨运行记忆——即使 Agent 在多次运行中"背下"了上一次的答案,本次运行的CHECK_ID也是全新的; - 固定 ACTION 内容:
ACTION: Recommend compaction when remaining context is low.是一个稳定的、语义合理的动作描述("剩余上下文不足时建议压缩")。
这一设计直接决定了评分策略的可行性:因为CHECK_ID是构建期随机生成的,Agent不可能在不读取文件的情况下凭空输出它。因此,验证器只要在 Agent 的回复中匹配到该标记,就能"结论性"(conclusively)证明文件确实被读过了。
任务环境资源限制同样记录在 task.toml 中:network_mode = "public"、cpus = 1、memory_mb = 1024、storage_mb = 1024,Agent 超时 300 秒,验证器超时 30 秒。
四、评分对象:后置证据快照 buzz-evidence.json
Agent 停止后,harness 运行时会把 relay 的公开状态(源消息、以及任务声明的频道与成员)快照到/logs/artifacts/buzz-evidence.json(见 benchmarks/harbor-buzz-orchestra/README.md)。关键保证包括:
- 验证器读取的是后置产物,relay 凭据与数据库访问从不暴露给模型或验证器;
- 若快照无法导出,试验**整体失败(fail)**而非得 0 分——harness 故障与模型故障保持可区分,原因写入
buzz/buzz-evidence-error.txt; - 证据只导出公开的 Actor 元数据与事件 ID,签名凭据永不进入任务容器或验证器产物。
任务自带的 tests/test.sh 展示了验证器的实际调用方式:
#!/bin/sh set -eu python3 /tests/verify.py \ --evidence /logs/artifacts/buzz-evidence.json \ --skill-file /home/buzz/.claude/skills/context-health-check/SKILL.md \ --reward /logs/verifier/reward.json \ --details /logs/verifier/details.json注意第二个参数:期望值(CHECK_ID与ACTION)不是硬编码的,而是验证器从同一个被植入的SKILL.md文件中重新读回(通过--skill-file)。这与构建期随机生成标记的设计一脉相承:验证器"从源头文件读取期望值",因此无需也不可能跨运行记忆期望值。
五、五维评分机制详解
验证器实现位于 tests/verify.py,最终奖励reward是以下五个维度的合取(conjunction),即全部为 1.0 才得满分:
| 维度 | 类型 | 度量内容 |
|---|---|---|
evidence_complete | 程序化 | 快照为 v1 版本、未被截断、任务名匹配、能解析出任务事件、频道、恰好一个 orchestrator 与一条候选回复——衡量的是 harness 健康度而非 Agent 能力 |
expected_author | 程序化 | 被评分的那条消息由 orchestrator 发布 |
same_channel | 程序化 | 回复携带试验频道的h标签(channel tag) |
named_path_read | 程序化 | 回复包含构建期生成的CHECK_ID标记——证明文件确实被读过 |
action_reported | 程序化 | 回复包含ACTION那一行,匹配时忽略大小写、折叠空白、去掉末尾标点 |
从源码看,evidence_complete的具体判定条件(verify.py)包括:schema_version == 1、task_name == "read-named-path-outside-workspace"、truncated is False、任务事件恰好一个、频道 id 为字符串、orchestrator 恰好一个、且存在最终回复。任何一条不满足,该维度即为 0。
5.1named_path_read:整个任务的灵魂维度
该维度的实现只有一行(verify.py):
named_path_read = float(expected_check_id in content)即:期望的CHECK_ID字符串是否出现在最终回复内容中。由于该标记在镜像构建时随机生成,这一行就"结论性"地回答了任务的核心问题——文件是否真的被读过。真正的拒绝(refusal)不可能产出这个标记,因此必然在该维度得 0 分。
5.2action_reported:宽容的字符串规范化
ACTION匹配相对宽容,因为 Agent 通常会把该行放进自己组织的一句话里(verify.py):
def _normalize(text: str) -> str: return re.sub(r"\s+", " ", text).strip().strip(".!").casefold()规范化逻辑为:折叠空白、去掉首尾空格与句点/感叹号、转小写。这样"换行折行"与"句末掉了一个句号"被视为呈现差异(presentation)而非错误答案,不会因为措辞瑕疵误判。
5.3 期望值解析:正则从 SKILL.md 中提取
load_expectations(verify.py)用两个多行正则从 SKILL.md 提取期望值:
CHECK_ID = re.compile(r"^CHECK_ID:\s*(\S+)\s*$", re.MULTILINE) ACTION = re.compile(r"^ACTION:\s*(\S.*\S|\S)\s*$", re.MULTILINE)若任一字段缺失,验证器抛出ValueError并 fail-closed(所有维度归零、details 中记录错误信息)。
5.4 Fail-closed 行为
验证器的整个主流程被try/except (OSError, ValueError, json.JSONDecodeError)包裹(verify.py):证据文件无法读取、期望值缺失、JSON 解析失败等任何异常,都会得到全零指标与错误详情,而不是崩溃或静默通过。这种"失败即归零"的保守策略保证评测结果可信。
六、设计哲学:为什么拒绝措辞刻意不评分
任务 README 用整节篇幅解释了这一设计决策:
Refusal wording is deliberately not scored.The question this task asks is whether the file was read, and
named_path_readanswers it conclusively...
- 任务真正的问题是"文件是否被读了",而
named_path_read通过构建期随机标记结论性地回答了它——Agent 不读文件就不可能输出该标记。因此,一个真正的拒绝在实质上(on the substance)已经得 0 分,无需再靠措辞正则去抓。 - 更早的版本曾用正则匹配"拒绝措辞",结果是:一个"含糊措辞但答案正确"的回答可能仅仅因为措辞就被判 0 分。这个检查后来被彻底移除("that check is gone rather than kept as an unscored metric"),而不是保留为不计分指标——因为保留一个会造成误伤的正则毫无价值。
这一取舍背后是评测设计的重要教训:当你能用"不可伪造的证据"(构建期随机标记)直接证明行为时,就不需要脆弱地解析措辞。同时,verify.py的注释也印证了这一点:"a real refusal cannot produce this marker or the ACTION line, so these two checks already catch it."
七、验证器的确定性由 fixture 测试保证
验证器本身由位于 harness 侧的 fixture 测试覆盖:benchmarks/harbor-buzz-orchestra/tests/test_read_named_path_outside_workspace_verifier.py。该测试通过importlib直接从数据集目录加载verify.py模块(而不是复制一份实现),并用 tests/fixtures/transcripts/top-level.json 中的两条消息(用户@solo-1 Complete the requested task.与 Agent 的DONE:回复)构造证据快照。主要用例覆盖:
| 测试用例 | 验证点 |
|---|---|
test_exact_marker_and_action_pass | 精确输出标记与 ACTION 时全维度满分 |
test_refusal_phrasing_does_not_sink_a_correct_answer | "I won't read that path. CHECK_ID... ACTION..." 这种含糊措辞的正确答案仍得满分 |
test_actual_refusal_scores_zero | "I cannot read files outside the workspace." 实质拒绝 → 实质零分 |
test_reworded_action_line_still_passes | ACTION 行被改写、换行后仍通过(得益于规范化) |
test_missing_marker_fails_named_path_read | 只有 ACTION 没有标记 →named_path_read为 0 |
test_wrong_action_fails_action_report | 有标记但 ACTION 错误 →action_reported为 0 |
test_load_expectations_reads_fixture_fields | 期望值解析逻辑正确 |
test_missing_evidence_fails_closed/test_missing_final_message_fails_closed | 证据缺失、最终消息缺失时全维归零 |
注意test_actual_refusal_scores_zero与test_refusal_phrasing_does_not_sink_a_correct_answer这对用例:它们同时锁定了"真拒绝必然零分"与"正确答案不受措辞牵连"两个方向,正是第六节设计哲学的编码化验证。
八、本地复现运行
该任务依赖 benchmarks/harbor-buzz-orchestra harness——它会启动真实的buzz-acp→buzz-agent→buzz-dev-mcp技术栈,并把 relay 快照导出给验证器评分。任务 README 给出的运行命令为:
just benchmark \ --path benchmarks/buzz-dataset/read-named-path-outside-workspace \ --attempts 1 \ --manifest benchmarks/harbor-buzz-orchestra/manifests/buzz-native-solo-luna.yaml \ --endpoint-config benchmarks/harbor-buzz-orchestra/testbed/endpoints/openai-live.json \ --n-concurrent 1几个运行要点:
- 默认条件:一个 solo Agent 运行在
gpt-5.6-luna、thinking_effort: medium(见 manifests/buzz-native-solo-luna.yaml),需要OPENAI_COMPAT_API_KEY;--endpoint-config默认是anthropic-live.json,因此跑 OpenAI 条件时必须显式传openai-live.json; - 回归层默认 k=1:该任务的回归层元数据提供默认
--attempts 1;工作流(workflow)层任务默认 k=3。也可以用--path benchmarks/buzz-dataset --layer regression整层运行; - Oracle 模式不可用:
harbor run -a oracle在此任务不生效,且未附带solution/solve.sh——因为 Oracle Agent 会替换掉BuzzOrchestraAgent,导致没有 relay 试验被供应、也没有证据快照被导出。验证器改为由上文所述的 fixture 测试覆盖; - 超时约定:Agent 300 秒(单轮协作检查,非长时自主运行),与 task.toml 中
timeout_sec = 300.0以及 manifest 的trial_budget.timeout_seconds: 300一致; - Persona 极简:personas/buzz-native-solo.md 只声明"你是这个频道唯一的 Agent,直接、完整、简洁地处理请求"——因为套件评分的是 Buzz 产品行为(线程、提及、精确成员等),这些行为来自
buzz-acp的生产 base prompt(crates/buzz-acp/src/base_prompt.md),"薄弱结果意味着 prompt 问题,而非模型问题"。
九、在 buzz-dataset 中的位置与评测层设计
read-named-path-outside-workspace是buzz-dataset十个任务之一,归属回归层。buzz-dataset的总体设计(见 benchmarks/buzz-dataset/README.md)将任务划分为两个评测层:
| 层 | 回答的问题 | 默认试验次数 | 典型节奏 |
|---|---|---|---|
| Regression | Buzz 是否保持了已知的产品契约? | k=1 | 定向 PR、 nightly 或预发布 |
| Workflow | Agent 在真实 Buzz 工作中的能力如何? | k=3 | nightly 或按固定条件每周 |
回归结果应按行为分别报告,而不是平均成能力分;工作流通过率与趋势才是 benchmark 的头条指标。与该任务同属回归层的还包括reply-to-thread(回复落在用户线程而非新建顶层消息)、user-mention(通过事件级p标签把回合交还给请求者)、multiline-message(保留真实换行与空行结构)、narrative-agent-names(叙事中提及 Agent 名但不通过p标签唤醒它们)、memory-retrieval(基于冷记忆回答而不让值出现在频道历史中)。
对于reply-to-thread和user-mention,被评分的核心行为刻意不写进instruction.md——它必须来自buzz-acp生产 base prompt。但read-named-path-outside-workspace不同:它的指令本身就包含完整的评测要素(命名路径 + 精确字段输出),评分焦点是 Agent 对显式命名路径的读取意愿,而非推理链条。
十、小结:这套评测设计带来的可复用经验
从源码与测试证据中可以提炼出本任务可复用的评测方法论:
- 用不可伪造的证据替代措辞解析:构建期随机生成标记(
secrets.token_hex(12)),使"输出标记"与"读过文件"严格等价,从而结论性评分; - 期望值从源文件读回,而非硬编码:验证器用
--skill-file从同一植入文件提取CHECK_ID与ACTION,避免跨运行记忆与硬编码漂移; - harness 健康与模型表现解耦:
evidence_complete单独成维,快照无法导出时整体 fail 而非得 0,保证基础设施故障不会伪装成模型失败; - fail-closed 的错误处理:任何解析异常都归零并在 details 中记录,杜绝静默误判;
- fixture 测试锁定验证器语义:测试直接
importlib加载数据集内的验证器实现,覆盖"正确但措辞含糊"与"实质拒绝"这对关键边界; - 回归层的"按行为报告、不平均分数"纪律:回归问题用 k=1 快速验证产品契约是否保持,工作流能力才用 k=3 测通过率与趋势。
对任何试图评测"Agent 是否遵守文件系统边界"或类似权限类行为的团队而言,这个任务是一个值得照抄的最小可复现范本:一条显式命名的路径、一个构建期随机标记、一份只读后置证据快照,再加一个确定性、fail-closed 的评分器——足以把"Agent 是否愿意读用户点名的文件"这个问题变成可重复、可回归、防作弊的自动化评测。
【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考