最新资讯
dev.to 我们在 DolphinBench 上测试记忆检索:纯关键词搜索暴露了自身回归 dev.to 别再把 Agent 写成 while 循环,把它建模为状态机 bloomberg.com Rightmove 与 Scout24 借 AI 产品应对低迷房市并上调展望 stackoverflow.blog 欢迎来到芯片时代:半导体制造、AI 数据中心与芯片设计的未来 www.youtube.com AI Agent 总犯同样的错:CentralAgent AI 将记忆重构为经验系统 pub.towardsai.net Netflix 科学家建议重采样 LLM 评判:5 次仅将误差棒缩小 13% pub.towardsai.net Jev 作为 LLM 前的静默层:构建提示感知的模型路由器 reddit.com OpenAI 称 Astra 仅满足 10% 安全任务标准 dev.to FreeToken:在自有 GPU 上运行前沿 MoE 模型及其内存需求 dev.to 当 AI Agent 说“完成”时,究竟完成了什么? dev.to 部署 Underdog Bark 3.0 Pro:逐字转写、自定义后端与分块设置 dev.to 为艰难对话构建 AI:五个 Agent、一条安全正则与一位盲评监督者
多元动态
登录 注册
AI编码 dev.to · @Rulestack

三个 Claude Code subagent 文件、frontmatter 中三种模型:每次启动的成本,以及校验器放过的那个字段

原文 我的收藏

作者在 .claude/agents/ 中维护三个自定义 Claude Code subagent(批量读取、独立评审、发布前评审),每个文件在 YAML frontmatter 中固定 model 与 effort。文章在 Claude Code 2.1.278、macOS、2026-09-22 环境下用 7 次 claude -p 调用做测量,考察每次启动首个 API 请求的成本、实际应答的模型、父会话 effort 不同时子代理 effort 是否保留,以及 Claude Code 对未知 frontmatter 键的处理。文中给出可复现的验证命令,并指出子代理系统提示中约 422 字符来自自定义文件、其余来自 harness。

AI推荐理由 作者在 Claude Code 2.1.278 上对三个自定义 subagent 做了可复现的实测:记录首次 API 请求成本、frontmatter 中 model/effort 是否真正生效、父会话 effort 是否影响子代理,以及未知 frontmatter 键的处理方式,并给出可重跑的 claude -p 命令。属于开发者可验证的一手测量,信息密度高;但样本仅 7 次调用、单一版本与平台,结论外推有限,且未给出完整结果数据。

72

正文

We keep three custom Claude Code subagents in .claude/agents/: a bulk reader that fetches pages and logs so the main conversation does not have to, an independent reviewer that judges things without seeing the parent's reasoning, and a pre-ship reviewer that runs three checklists in one body. Each file pins a model and an effort level in its YAML frontmatter. Until this week we had never checked whether those two lines do anything. This is the measurement: what one launch of each agent costs on its first API request, which model actually answered, whether effort survived a parent session running at a different level, and what Claude Code does with a frontmatter key it has never heard of. Everything below was run on Claude Code 2.1.278 on macOS, on 2026-09-22, with seven claude -p invocations in a throwaway directory. The documentation quotes come from https://code.claude.com/docs/en/sub-agents, fetched the same day with trafilatura. The three files Stripped of their Japanese system prompts, the three definitions are almost identical in shape. Each has four frontmatter keys and nothing else: --- name: bulk-reader description: model: sonnet effort: xhigh --- Enter fullscreen mode Exit fullscreen mode --- name: deep-reviewer description: model: opus effort: xhigh --- Enter fullscreen mode Exit fullscreen mode --- name: preflight-reviewer description: model: inherit effort: high --- Enter fullscreen mode Exit fullscreen mode None of the three sets tools, so each inherits the full tool pool. The bodies are short: 5 to 8 bullet rules about quoting primary sources, separating verdicts from evidence, and never writing to anything public. The system prompt the longest one actually received was 1,702 characters, of which 422 were our file and the rest were the harness's own notes for subagents. That number matters later, when we ask where the launch tokens go. The check you can rerun in ten minutes You need a directory that is not your repo, so that your own instruction files do not pollute the number, and one agent file to launch. D=$(mktemp -d) mkdir -p "$D/.claude/agents" cp .claude/agents/bulk-reader.md "$D/.claude/agents/" cd "$D" claude plugin validate .claude/agents claude -p --output-format json --permission-mode default \ "Use the Agent tool to launch the subagent named bulk-reader (subagent_type: bulk-reader) exactly once, with exactly this prompt: \"This is a measurement probe. Do not read anything, do not call tools. Return 'ok'.\" Do not read any files yourself and do not call any other tool. When it returns, reply with only the subagent's reply verbatim." \ > run1.json Enter fullscreen mode Exit fullscreen mode Two places hold the answer. The JSON on stdout has a modelUsage object keyed by model, so if the subagent ran on a different model than the parent you get its usage as a separate bucket for free. The transcript is more precise: Claude Code writes the subagent's own JSONL at ~/.claude/projects///subagents/agent-.jsonl, and each assistant record there carries message.model, message.usage, and, new to us, a top-level effort key. This reads the first request: SID=$(python3 -c "import json;print(json.load(open('run1.json'))['session_id'])") P=~/.claude/projects/$(pwd | sed 's#/#-#g')/$SID/subagents python3 - "$P"/agent-*.jsonl <<'EOF' import json, sys for line in open(sys.argv[1]): r = json.loads(line) if r.get("type") == "assistant": u = r["message"]["usage"] print(r["message"]["model"], r.get("effort"), u["cache_creation_input_tokens"], u["cache_read_input_tokens"], u["input_tokens"], u["output_tokens"], u.get("output_tokens_details", {}).get("thinking_tokens")) break EOF Enter fullscreen mode Exit fullscreen mode Add --effort low to the claude -p line for a second run and you can see whether the file's effort beats the session's. That is the whole experiment; the rest of this post is what came out of it. What the documentation promises The sub-agents page has a table titled "Supported frontmatter fields", introduced by one sentence: "The following fields can be used in the YAML frontmatter. Only name and description are required." The rows we rely on: model: "Model to use: sonnet, opus, haiku, fable, a full model ID such as claude-opus-5, or inherit. When you omit it, Claude Code picks the model in the subagent model order." effort: "Effort level when this subagent is active. Overrides the session effort level. Default: inherits from session. Options: low, medium, high, xhigh, max; available levels depend on the model" tools: "Tools the subagent can use, as a comma-separated string such as Read, Grep, Bash or a YAML list. Inherits every tool available to subagents if omitted." The resolution order for the model is spelled out too: "The per-invocation model parameter", then "The subagent definition's model frontmatter, where inherit selects the main conversation's model", then "The CLAUDE_CODE_SUBAGENT_MODEL environment variable", then "The main conversation's model". So a model: line in the file loses only to an explicit model argument on the Agent tool call. We checked the parent transcripts: in all seven runs the Agent call carried exactly four keys, description, prompt, run_in_background, subagent_type, and no model. Whatever model the child ran on, the file decided it. On unknown keys the page says nothing directly. The section "Subagent files Claude Code skips" lists five conditions, all about name, description, the opening ---, and YAML that does not parse. A key the schema does not know is not among them. The validator is described just as narrowly: "Claude Code checks only the directory you name, and doesn't flag a file whose frontmatter parses but has no name." We read that as "an unknown key is silently accepted" and then tested it, because reading is not measuring. What each launch cost The first request of each agent, taken from its transcript. cache_read was 0 in every cold run, so the whole prefix was written into the prompt cache on that request. agent model in transcript effort in transcript cache_creation input output thinking bulk-reader (model: sonnet) claude-sonnet-5 xhigh 20,971 2 842 837 deep-reviewer (model: opus) claude-opus-5 xhigh 16,262 2 4 0 preflight-reviewer (model: inherit) claude-fable-5-1 high 16,222 2 4 0 The parent in every run was claude-fable-5-1, the model set in our user settings, so inherit resolved to the parent as documented, and opus resolved to claude-opus-5 rather than to the parent's family. The stdout JSON priced the two foreign-model buckets at list rates: $0.0609 for the sonnet launch and $0.1017 for the opus one (costBasis: "list" in the same object). The inherited launch is not priced separately because modelUsage merges it into the parent's fable bucket; you can only see it in the transcript. Two things about those numbers surprised us. First, 16,000 to 21,000 tokens for a subagent whose system prompt is under 2,000 characters. The transcript explains it: before the first request Claude Code attaches a skill_listing of 20,740 characters (every skill installed on this machine, including plugin ones), a deferred_tools_delta naming 67 tools, and the tool schemas themselves. The temporary directory had no CLAUDE.md, and this machine has no user-level one, so none of that is instruction files. It is the harness. Your agent file is a rounding error inside its own launch cost. Second, the sonnet run at effort: xhigh spent 837 thinking tokens deciding to say "ok", and a repeat launch spent 199. The opus run at the same xhigh and the fable run at high spent 0. We are not going to draw a rule from three samples of a two-character task, but it does mean the effort line is not free on every model: on the reader agent, the one we spawn most often, xhigh bought a few hundred tokens of reasoning about a prompt that said not to reason. Was effort honoured? The transcript's effort key answered this more cleanly than we expected. In the first three runs the parent session ran at high (its default here), so the pre-ship reviewer's effort: high was indistinguishable from inheritance. We reran two agents with the parent forced down: claude -p --effort low ... # parent transcript: effort low, perTurnEffort low Enter fullscreen mode Exit fullscreen mode Under that parent, the pre-ship reviewer's first request still recorded effort: high and the independent reviewer's still recorded effort: xhigh. That is the documented behaviour, "Overrides the session effort level", confirmed at the request level rather than in the /tasks panel. So all three of our files do what they say: the model line is applied, the effort line is applied, and each is applied independently of what the parent is doing. One detail for anyone reading these transcripts: the parent's records carry both effort and perTurnEffort, while a subagent whose file sets effort carries effort only, with perTurnEffort null, except for the inherit agent, where both were high. We do not know what perTurnEffort means in the harness and did not find it in the docs; we mention it only so nobody mistakes the null for "effort not applied". The field the validator waved through For the last probe we wrote a fourth file with two keys the documentation does not list: reasoning: xhigh, a plausible wrong guess at the effort field, and colour: red, the British spelling of the documented color. claude plugin validate .claude/agents printed "Validation passed" for the directory with all four files in it. The agent launched on claude-haiku-4-5-20251001, so model: haiku was read. Its transcript recorded effort: None, and the parent for that run was at low. reasoning: xhigh did nothing, and nothing told us. colour we could not observe in a headless run, but the documented field is color, and an unknown key that survives validation and loading has no way to reach the display code. This is the practical finding of the whole exercise. The documented fields work. The cost of a typo in a documented field is not an error; it is a silent fallback to session defaults. An efort: xhigh in the reviewer file would leave the reviewer running at whatever effort the parent happened to be at, forever, with Validation passed at every check. We have not built a guard for this yet. The obvious one is a commit-time test that reads the frontmatter of every file under .claude/agents/ and rejects any key outside the documented list (name, description, tools, disallowedTools, model, permissionMode, maxTurns, skills, mcpServers, hooks, memory, background, omitClaudeMd, effort, isolation, color, initialPrompt, experimental). Twenty lines of code; we will report when it exists rather than pretend it does. A cache-lifetime footnote Not the point of the post, but it fell out of the transcripts and changes how you should read repeated measurements. Every subagent request wrote its prefix with ephemeral_5m_input_tokens, while the parent's own requests in the same session used ephemeral_1h_input_tokens. The timestamps agree with a five-minute window: the pre-ship reviewer launched at 13:06:32 wrote 16,222 tokens, and the same agent launched at 13:10:28 read 16,222 and wrote 0; the reader launched at 13:04:27 wrote 20,971, and the same reader at 13:11:49 wrote all 20,971 again. The documentation has a frontmatter knob for exactly this, experimental with a cacheTtl key: "Set its cacheTtl key to 5m or 1h to choose the prompt cache lifetime for this subagent's requests". We have not turned it on; whether an hour-long cache on a 16,000-token prefix pays for itself depends on how often the same agent is launched, and our launch log does not yet answer that. What we are keeping The three files stay as they are. model: sonnet on the reader and model: opus on the reviewer are being applied, which is what justifies giving the reviewer a different model from the parent in the first place. effort: xhigh on the reader is the one line we now doubt: it is the cheapest agent by design, it launches most often, and it is the only one that paid thinking tokens on a do-nothing prompt. That decision needs a real workload measurement, not a probe, so it is a follow-up rather than a change. What changes is the checklist for editing those files. Run the validator, yes, but also launch the agent once with a probe and read the transcript's model and effort back, because the validator will not tell you that your effort line was spelled wrong. The transcript will, in one line, for about 16,000 tokens. Rulestack designs subagent files, skills and CLAUDE.md conventions for Claude Code, on sale at rulestack.gumroad.com. The three agent definitions measured here are the ones our own repository runs, and their frontmatter now carries a comment naming the field the validator ignores. The per-launch token counts get remeasured after each Claude Code release that touches subagents; the deltas are posted on @ai-shop.bsky.social.

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容