HN 日本語サマリー

← 一覧へ戻る
プログラミング

SpotifyのPortalがClaude Codeのトークン使用量を90%削減

Portal by Spotify cut my Claude Code token usage by 90% (engineering.atspotify.com)

227 pointsby cebert126 コメント

要約

Spotifyのエンジニアは、AIコーディングエージェントにおけるトークン使用量の大部分が、推論ではなくI/O処理に費やされていることに気づきました。この問題を解決するため、彼らはPortalというツールを開発し、定型的なファイル読み込みやコード生成といった単純作業を低コストなモデルに委任する「モード」を導入しました。これにより、Claude Codeのような高価なモデルは、真に高度な推論が必要なタスクにのみ使用され、トークンコストを大幅に削減することに成功しました。

全文翻訳

SpotifyのPortalがClaude Codeのトークン使用量を90%削減した

AIコーディングエージェントが行う作業のほとんどは、思考ではなくI/Oです。

1つのメソッドに関する質問に答えるために5つのファイルを読み込む。隣接する20個のテストファイルと全く同じパターンに従うテストファイルを生成する。会議の後でドキュメントを更新する。数千ものトークンが消費され、ほとんど推論は行われません。ライセンス料ではなく、トークンが問題なのです。そして、あなたはこれらのすべてを、過剰に資格のあるフロンティアモデルに供給しています。もし、 grunt work(単調な作業)を、同じようにうまく処理できる、より安価なものにルーティングし、本当に必要な問題のために高価なモデルを節約できたらどうでしょうか?

これは決して私だけの問題ではありません。2028年までに、AIコーディングのコストは、開発者の平均給与を上回ると予想されています。エンジニアリングリーダーの4分の1は、すでに開発者1人あたり月額200〜500ドルをトークンに費やしています。中には2,000ドルをはるかに超える企業もあります。ツールはそれ自体で元が取れますが、それは、必要のない作業にフロンティアトークンを浪費するのをやめた場合だけです。

幸いなことに、この修正にはプラットフォームチームや新しいサブスクリプションは必要ありませんでした。ただ2つのモードがあればよかったのです。

2つのモード、コードなし

これはまさに、AiKA Modes in Portal by Spotify が構築されたユースケースです。モードとは、一時的なランタイムで実行される宣言的なエージェントです。AWS Lambdaをエージェントのために使うようなものです。指示を定義し、モデルを選択し、温度(temperature)のようなパラメータを設定し、MCPツールをアタッチします。Portalが残りを処理します。管理するインフラ、APIキー、長時間稼働するサーバーはありません。モードは、Portal CLIまたはAPIから呼び出すことができます。公開(会社全体と共有)することも、プライベートにすることも可能です。

このルーターを機能させるために、私は2つのモードを作成しました。どちらも例ではGemini 2.5 Flashをワーカーモデルとして使用していますが、modelフィールドはPortalインスタンスで設定されている任意のモデルを受け入れます。ご自身に合ったものを選んでください。

モード1: bulk-reader

Claudeが本来なら1つの質問に答えるために複数の大きなファイルを読み込む場合のため。

name: bulk-reader
description: Bulk file reader for code analysis - delegates I/O from Claude Code
instructions: You are a precise code analyst. Read the provided files and answer the question concisely. Output structured bullets only. No greetings, no prose, no preambles. Lead every bullet with the exact name, type, or line number. Use nested bullets for details. Skip anything the caller did not ask for.
visibility: public
model: gemini-2.5-flash
resourceLimits:
  temperature: 0.2
tags:
  - coding
  - delegation
モード2: code-writer

テスト、設定の足場(scaffolding)、型スタブ、または既存のパターンから出力が予測可能なもの全般のため。

name: code-writer

description: Boilerplate code generator - delegates output-heavy work from Claude Code

instructions: You generate code files based on a spec and reference files. Match the existing patterns, conventions, naming, and style exactly. Output only the code — no explanations, no markdown fences unless asked. If the spec is ambiguous, make reasonable choices that match the reference code's patterns.

visibility: public

model: gemini-2.5-flash

resourceLimits:
  temperature: 0.2

tags:
  - coding
  - delegation

「Output only the code」(コードのみを出力)という指示は重要です。これがなければ、モデルはすべてをMarkdownのフェンスと説明的な文章で囲み、Claudeはそれを解析しなければなりません。

ルーティング

この最初のバージョンは、CLAUDE.mdのルーティングルールのブロックでした。それはある程度機能しました。Claudeは指示を読み、自己ルーティングしてPortalに向かいました。しかし、問題がありました。ルールは助言的であり、強制力はありませんでした。Claudeはそれを無視することができました。そして、各プロジェクトは指示の独自のコピーを必要としました。

現在のバージョンは、shuntという名前のClaude Codeプラグインです。委任はPortal CLIアクションレジストリを通じて行われるため、このプラグインは、AiKAプラグインが有効になっている任意のPortalインスタンスに対して機能します。

レイヤー1: フック

Claude Codeのフックは、すべてのツール呼び出しの前に発火します。Shuntは2つのPreToolUseフックを登録します。

check-file-size は、すべてのRead呼び出しで発火します。ファイルが設定可能な行数しきい値(デフォルト: 350)を超えた場合、フックは読み込みをブロックし、Claudeに/bulk-readerスキルを使用するように指示します。ターゲットを絞った読み込みは通過します。Claudeはすでに必要なセクションを知っています。

check-bash-read は、大きなファイルに対するcat、head、tail、less、moreを捕捉します。パイプされたコマンド(cat file | grep)は、ターゲットを絞った読み込みであるため通過します。

しきい値は、SHUNT_MIN_LINES環境変数で設定可能です。シェルプロファイルまたは.claude/settings.jsonで設定してください。

{
  "env": {
    "SHUNT_MIN_LINES": "500"
  }
}
レイヤー2: スクリプト

Portal CLI呼び出しをラップする2つのbashスクリプトがあります。Claudeは名前付き引数でスクリプトを呼び出します。スクリプトは、リクエストの構築、アクションの呼び出し、エラーのアンラップ、標準エラーへのトークン使用量の報告など、すべてを内部で処理します。

モードは名前でアドレス指定され、Portalによって解決されます。大文字小文字を区別せず、まず自分のモード、次にチームのモード、そして公開モードが優先されます。公開されているbulk-readerをカスタマイズバージョンにフォークすると、設定なしで自動的に自分のバージョンが優先されます。

bulk-read は、各ファイルをXMLタグで囲んで明確な境界を作り、質問とともにbulk-readerモードに送信します。

bulk-read --question "What does this service do?" --paths src/Service.java src/Handler.java

# Follow-up: ask again with the same paths

bulk-read --question "Which methods call the database?" --paths src/Service.java src/Handler.java

すべての委任はワンショットです。呼び出しは一時的(サーバーサイドには何も保存されない)であり、フォローアップでファイルを再送信することは、重要な部分では無料です。なぜなら、コーパスはワーカーモデルに送られ、Claudeのコンテキストに入ることはないからです。

code-write は、仕様と参照ファイルをcode-writerモードに送信し、出力からMarkdownフェンスを剥がし、直接ディスクに書き込むことができます。Claudeは生成されたコードを見ることはありません。参照ファイルは必須です。パターンに一致するファイルがないと、ワーカーはプロジェクトのどこにも適合しないコンテキストのないコードを生成してしまうでしょう。

code-write --spec "Write tests for UserService" --reference tests/OrderTest.java --target tests/UserTest.java

# Output to stdout

code-write --spec "Generate a config stub" --reference config/existing.yaml
レイヤー3: スキル

2つのスキルファイルは、Claudeがいつ、どのようにスクリプトを呼び出すかを指示します。スキルは、説明と使用例を含むMarkdownファイルです。フックが読み込みをブロックすると、ブロックメッセージはClaudeに/bulk-readerスキルを指し示し、そこには正確な呼び出し構文が表示されます。

このレイヤリングにより、システムは正常に機能低下します。Claudeがスキル説明を読まなくても、フックは高価な読み込みをブロックします。スキルはリダイレクトをよりスムーズにするだけです。

ベンチマーク

Javaのモノレポを4つのシナリオでテストし、Claudeがファイルを直接読み取る場合と、bulk-readerの要約を利用する場合、またはcode-writerを介してコードを書き込む場合のトークン消費量を測定しました。平均的なbulk-readの節約量は、驚異的な90%でした。

code-writeシナリオは、トークンでの測定がより困難です。shuntがない場合、Claudeは参照ファイルを読み、高価な出力トークンとして出力を生成します。shuntを使用すると、コードは直接ディスクに書き込まれ、Claudeはそれを決して見ません。

機能しないこと

編集の委任はできません。 ワーカーモデルの要約には、信頼できる行番号が含まれていません。Claudeが分析に基づいて編集を行う必要がある場合、直接特定のセクションを読む必要があります。フックは、この理由からターゲットを絞った読み込み(オフセット/制限付き)を許可しており、委任は理解のためのトークンを節約します。

推論の委任はできません。 ワーカーモデルは表面的なパターンを見つけましたが、私のテストにあった微妙なスレッドセーフティのバグを見逃しました。Claudeは、適切なコンテキストを与えられると、数秒でそれを発見しました。ルーティングは、デバッグ、アーキテクチャの決定、安全クリティカルなコードを明示的に除外しています。

レイテンシが積み重なります。 各委任はネットワークの往復です。Claude CodeからPortalバックエンドへ、ワーカーモデルへ、そして戻ってきます。応答は通常10〜30秒かかり、Portalは単一の呼び出しを30秒に制限しているため、非常に大きな生成はより小さな呼び出しに分割する必要があります。これは大きな読み込みには許容できますが、小さな読み込みには逆効果です。行数しきい値が存在するのはこのためです。それ以下では、委任のオーバーヘッドが節約分を超えます。

トークン節約は単なる始まり

このプラグインはClaude Codeの成果物ですが、その背後にあるアイデアは、AiKAモードによるモデルルーティングです。モードが負荷を支える部分です。

  • 再利用可能: 同じbulk-readerおよびcode-writerモードは、すべてのプロジェクトおよびPortal CLIにシェルアウトできるすべてのツールで機能します。
  • 共有可能: 両方のモードはAiKAで公開されています。誰でも自分で作成することなく、今日から使用できます。
  • コンポーザブル: ドキュメント用のdoc-writerモード、コードレビュー要約用のreviewerモード、i18n用のtranslatorモードを作成できます。それぞれ数クリックで利用可能です。
  • ルーティングの決定をワーカーから分離: プラグインはいつ委任するかを決定します。モードはどのように応答するかを決定します。Gemini Flashをより安価なモデルに交換したり、システムプロンプトを変更したり、MCPツールを追加したりしても、プラグインは変更されません。

これがAiKAモードの真の力です。モデルルーティングをシステムエンジニアリングの問題から設定の問題に変えます。インフラを構築するのではなく、欲しいものを記述して名前を付けます。

ご自身で試してみてください

  1. spotify/portal-ai-plugins マーケットプレイスから両方のプラグインをインストールします。

    1. claude plugin marketplace add spotify/portal-ai-plugins
    2. claude plugin install portal@portal
    3. claude plugin install shunt@portal

    portalプラグインは、shuntが委任するPortal CLIを提供します。

  2. 新しいClaude Codeセッションで、/portal:setup を実行して、Portalインスタンスに対してPortal CLIをセットアップおよび認証します。

  3. 準備完了です。複数のファイルにまたがる質問をしてみてください。

bulk-readerとcode-writerモードはすでに公開されているため、作成する必要はありません。カスタマイズしたい場合(異なるワーカーモデル、異なる指示など)は、Portalでフォークすると、あなたのバージョンが自動的に優先されます。

モードはプロジェクト間で再利用可能で、チームと共有できます。プラグインはルーティングを強制するため、気にする必要はありません。モードの詳細はこちら。