Effort レベルと Ultracode
Claude Code の /effort ダイヤル(low〜xhigh)、ultracode モード、+500k トークンバジェット指示を学ぶ — 品質対コストをユーザーが握るダイヤルへ。
学ぶこと
セッション 25 ではどのモデルを動かすかを扱いました。このセッションでは 2 つ目のダイヤル、つまりそのモデルがどれだけ深く考えるかを扱います。Fable 5 時代の Claude Code は、推論の effort(労力)をユーザーが直接制御できるファーストクラスの設定として公開しています — 素早い low effort の一撃から、トークンコストは制約ではないとハーネスに明示的に伝えるモード ultracode まで。
読み終える頃には、次のことが理解できているはずです:
/effortが何を制御し、各レベルが何をトレードオフするのか- ultracode の正体(xhigh effort + 動的なワークフローオーケストレーション)
- オプトインする 2 つの方法 — プロンプト内のキーワード、またはセッションレベルのトグル
- ultracode が自動ではなくオプトインである理由
+500kのようなトークンバジェット指示と、budgetオブジェクトのハードシーリング(絶対上限)セマンティクス- ワークフロースクリプト内でサブエージェントごとに effort を設定する方法
課題
思考の深さが 1 つに固定されたモデルは、現実の仕事に合いません。変数のリネームと決済モジュールの監査は同じタスクではないのに、長年、ユーザーが握れる品質のノブはモデル選択だけでした。その結果、2 つの失敗パターンが繰り返し起きていました:
- 些細な作業への払い過ぎ。 1 行の編集に深い推論を適用するのは純粋な無駄です — 回答は遅くなり、トークンは増え、結果は同じ。
- 肝心なタスクでの考え不足。 徹底的で敵対的な精査を必要とした、その 1 件のマイグレーションレビューが、他のすべてと同じ effort しか受けられず、あなたはそれを後になって知ることになる。
スケールを正直に表現する方法もありませんでした。Claude Code に何十ものエージェントを問題に投入させたければ、「be very thorough(とにかく徹底的に)」といったプロンプトの言い回しが実際の挙動につながることを祈るしかなく、「ここまで使ってよい、それ以上は駄目」と伝える仕組みも存在しませんでした。コスト管理は願望であって、強制ではなかったのです。(セッション 21 のコスト手法 — /ja/tutorials/s21-cost-optimization 参照 — はこのギャップの回避策でした。この時代はそのギャップ自体を埋めます。)
仕組み
/effort ダイヤル
/effort はセッションの推論 effort を設定します。レベルは 4 段階、その上に特別な最上位設定があります:
/effort
│
├─ low less reasoning — fast, cheap; mechanical stages
├─ medium the middle of the dial
├─ high hard debugging, verification, judgment calls
├─ xhigh most exhaustive reasoning on demand
│
└─ ultracode = xhigh + dynamic workflow orchestration
トレードオフは想像どおりです:effort を下げれば応答は速く安くなり、上げればより多くのトークンコストと引き換えに、より徹底した推論が得られます。この時代を通じて一貫している指針はシンプルです — 安価で機械的な作業には low effort、検証と判断には高いティアを。
/model と同様に、/effort の選択は永続化できます。どちらのコマンドも、選択を新しいセッションのデフォルトとして保存できます。
Ultracode:xhigh + オーケストレーション
Ultracode は「もう 1 段上の effort レベル」ではありません。 xhigh effort に、動的なワークフローオーケストレーション(workflow orchestration)を組み合わせたものです。ultracode が有効なとき、Claude Code は次のように指示されます:
- 最速でも最安でもなく、最も網羅的で正しい答えのために最適化する
- すべての実質的なタスクでマルチエージェント Workflow オーケストレーションを使う
- トークンコストを明示的に制約ではないものとして扱う
最後の点こそが決定的な性質です。通常運転では、ハーネスは品質とコストのバランスを取ります。ultracode の下では、そのバランスが意図的に取り払われます:指示は「何を費やしてでも正しい答えを出せ」です。
オプトインする 2 つの方法
- キーワード。 プロンプトのどこかに “ultracode” という単語を含めると、そのターンは ultracode モードで実行されます。これは 1 回限りのオプトインで、次のプロンプトからは通常に戻ります。
> Audit src/payments/ for correctness bugs. ultracode
- セッショントグル。 セッションレベルで ultracode を選択します(例えば
/effort経由)。こちらは継続的なオプトインです:オフにするまで、セッション内のすべての実質的なタスクがフルの扱いを受けます。
なぜオプトインなのか
ultracode のワークフローは何十ものエージェントを起動し、大量のトークンを消費し得ます。そのスケールこそが狙いですが、それは同時に、ハーネスが黙ってそれを発動しない理由でもあります。設計原則はこうです:そのスケールはユーザーが明示的に要求しなければならない。 プロンプトの曖昧さに委ねることも、モデルが独断であなたのトークン支出を何倍にもすることもありません。ultracode と言えば ultracode が得られる — それだけです。
トークンバジェット指示
逆向きのコントロールも存在します:コスト制約を取り払うのではなく、それをハードな数字にするのです。プロンプトに +500k のような指示(directive)を書くと、そのターンにトークン目標が設定されます。
Workflow スクリプトの内部では、その目標は budget オブジェクトとして現れます:
| メンバー | 意味 |
|---|---|
budget.total | 目標値(数値)。指示がなかった場合は null |
budget.spent() | これまでに消費したトークン数 |
budget.remaining() | 上限までに残っているトークン数 |
重要な性質は 2 つ:
- プールは共有される。 1 つのバジェットが、そのターンのメインループとすべてのワークフローをまとめてカバーします。ワークフローごとのサブ割り当てを操作する余地はありません。
- 目標はハードシーリング(絶対上限)である。
spent()がtotalに達すると、それ以降のagent()呼び出しは例外を投げます。これはモデルが守ろうと努力するソフトなヒントではなく、ハーネス層での強制です。よく書かれたスクリプトはエージェントを起動する前にremaining()をチェックして優雅に縮退し、雑なスクリプトは実行の途中で死にます。
ワークフロー内のエージェント単位 effort
effort はセッションのダイヤルだけではありません。Workflow スクリプトはサブエージェントごとに推論 effort を設定できます:
agent(prompt, { effort: 'low' }) // low | medium | high | xhigh | max
サブエージェント単位のスケールが、セッションダイヤルより一段階先まで伸びていることに注意してください:max ティアが含まれます。ここで effort は、好みの設定ではなくアーキテクチャの道具になります。パターンはこうです:
- 安価で機械的なステージ(ファイル読み取り、検索、フォーマット、ファンアウトによる探索)→
low - 難しい検証・判定・統合のステージ → 高いティア
同じ原則はモデル選択(セッション 25 の 3 つのオーバーライドポイント)にも当てはまり、2 つのダイヤルは合成できます:low effort の haiku クラスのファインダーと、high effort の最上位ティアのジャッジが、3 行離れただけの同じスクリプトの中に共存できるのです。
ハンズオン例
この組み合わせを実際に動かしてみましょう。ハードバジェット付きで ultracode にオプトインしたターン —
> Audit src/payments/ for correctness bugs. ultracode +500k
— そしてバジェットガード付きの発見ループ。「発見が尽きるか、または資金が乏しくなるまで探し続ける」ための、標準的なスクリプトの形です。安価なファインダーが各ラウンドで low effort でファンアウトし、最後に high effort の統合エージェントが必ず実行できるよう、予備が取り置かれます。
export const meta = {
name: 'budget-guarded-audit',
description: 'Find issues until discovery runs dry or the token budget runs low',
phases: [{ title: 'Discover' }, { title: 'Synthesize' }],
};
phase('Discover');
const seen = []; // dedup against everything seen so far
let dryRounds = 0;
let round = 0;
while (dryRounds < 2) {
round += 1;
// budget.total is null when the user gave no "+500k"-style directive.
// Guard BEFORE spawning: once spent() reaches total, agent() throws.
if (budget.total !== null && budget.remaining() < 60000) {
log(`Budget guard: ${budget.spent()} spent, ` +
`${budget.remaining()} left — reserving the rest for synthesis.`);
break;
}
const results = await parallel([
() => agent(
`Round ${round}: hunt for correctness bugs in src/payments/. ` +
`Known findings (do not repeat): ${seen.join('; ') || 'none yet'}. ` +
`Return one line per NEW finding, or "NONE".`,
{ label: `finder-${round}-bugs`, phase: 'Discover', effort: 'low' }
),
() => agent(
`Round ${round}: hunt for error-handling gaps in src/payments/. ` +
`Known findings (do not repeat): ${seen.join('; ') || 'none yet'}. ` +
`Return one line per NEW finding, or "NONE".`,
{ label: `finder-${round}-errors`, phase: 'Discover', effort: 'low' }
),
]);
// parallel() never rejects; a thunk that throws resolves to null.
const fresh = results
.filter(Boolean)
.flatMap((text) => text.split('\n'))
.filter((line) => line.trim() && line.trim() !== 'NONE');
if (fresh.length === 0) {
dryRounds += 1;
} else {
dryRounds = 0;
seen.push(...fresh);
}
log(`Round ${round}: ${fresh.length} new, ${budget.spent()} tokens spent.`);
}
phase('Synthesize');
const report = await agent(
'Verify and write up these audit findings, most severe first:\n' +
seen.map((f, i) => `${i + 1}. ${f}`).join('\n'),
{ label: 'synthesis', phase: 'Synthesize', effort: 'high' }
);
log(report ? 'Audit complete.' : 'Synthesis agent was skipped.');
要となる行を順に見ていきます:
- ガードは各ラウンドの後ではなく前に実行される。 上限は
agent()が例外を投げることで強制されるため、起動した後にremaining()をチェックするのでは手遅れです。60k の予備はスクリプト自身のポリシーであり、統合ステージのための十分な余裕を残すためのものです。 nullチェックが重要。 プロンプトに+500k指示がなければbudget.totalはnullになり、ループは新規発見のないラウンド(dry rounds)の数だけで制限されます。- effort は役割ごとに分けられている。 ファインダーは
low— 求められるのは広さであって判断ではありません。統合はhigh— 判断を誤れば出力全体が台無しになる唯一の場所だからです。 - 重複排除は
seenに入ったすべてに対して行う。 各ラウンドのプロンプトが過去の発見を運ぶことで、ファインダーが同じ発見を延々と再浮上させないようにしています。 .filter(Boolean)は 2 種類の失敗形態を両方処理します:parallel()は例外を投げた thunk をnullに変換し、agent()自体も、ユーザーがエージェントをスキップした場合や終端的な API エラーで死んだ場合にnullを返します。
このスクリプトの背後にある Workflow API の全体 — meta、phase()、pipeline() と parallel() の違い、レジューム(再開)セマンティクス — は、セッション 27 のテーマです。
何が変わったか
| 以前 | Fable 5 時代 |
|---|---|
| 品質のノブ = モデル選択のみ | 独立した 2 つのダイヤル:モデル × effort |
| 「よく考えて」とプロンプトで懇願 | /effort レベル:low / medium / high / xhigh |
| スケールを伴う徹底性:予測不能 | Ultracode:xhigh + ワークフローオーケストレーション、契約として保証 |
| 大きな支出が暗黙のうちに起こり得た | スケールには明示的なオプトインが必要(キーワードまたはトグル) |
| コスト管理:メーターを見ながら祈る | +500k → ハードシーリング;上限に達すると agent() が例外を投げる |
| セッション全体で 1 つの effort | ワークフロースクリプト内でサブエージェント単位の effort(max まで) |
キーインサイト
品質対コストは、モデルの定数ではなく、ユーザーが握るダイヤルになりました。
このセッションのすべての要素は、同じアイデアを別の角度から見たものです。/effort は「どのモデルか」を「どれだけ深く働くか」から切り離します。ultracode はダイヤルを最大に固定したもの — ハーネスは契約としてコストを無視します。+500k 指示はダイヤルを数字に向けたもの — ハーネスは契約としてその超過を拒否します。そしてエージェント単位の effort は、ダイヤルを個々のワークフローステージにまで押し下げます。
保証がどこに宿っているかに注目してください。ultracode の網羅性もバジェットの上限も、どちらもハーネスによって強制されます — 上限で例外を投げる agent() 呼び出しは、ツール呼び出しをブロックする hook と同じく構造的なものであり、モデルが覚えておこうと努力する指示のような行動的なものではありません。それがこの時代を象徴する一手です:effort とコストに関する約束が、プロンプトから機構そのものへと移ったのです。
ダイヤルは意図を持って回しましょう:仕事の機械的な 90% には low effort、判断の誤りが高くつく場所には高いティア、正しさが本当にコストより重いときには ultracode — そしてそのトレードに書面での上限を付けたいときは、いつでもバジェット指示を。
次のセッション
セッション 27 では、このセッションが仄めかし続けてきた機構そのものを開きます:Workflow ツール — Claude Code のスクリプト化されたマルチエージェントオーケストレーション。制御フローは決定論的な JavaScript に、判断はモデルに宿ります。/ja/tutorials/s27-workflow-orchestration を参照してください。