ホームHermesとは記憶スキルマルチプラットフォーム自動化コマンド一覧ブログDelegationMCP人格設定導入と移行活用シナリオ

【後編】1日$28を$8に圧縮した7つの防衛線

API費用削減に成功したAIエンジニアと最適化されたダッシュボードのイメージ

前編のあらすじ

Anthropicのサードパーティ締め出しにより、API従量課金へと移行した筆者。しかし、定額時代の「全部入りコンテキスト」のままエージェントを回した結果、1日で$28(月換算$800超)のAPI請求が発生。プロンプトの構造設計が事業原価に直結する時代への適応を迫られた。

本稿では、1日$28のコストを$8台まで圧縮し、年間約$7,200の削減に成功した7つの具体的な打ち手と、その実装コードを解説します。Hermes Agent、OpenClaw、Claude CodeなどでAPIを運用している方は、ぜひご自身の環境と照らし合わせてみてください。

お金の作り方を学ぶオンライン講座【Finorie|フィノリー】

打ち手1: プロンプトキャッシュを確実に効かせる「配列の順序」

Kimi K2.6やClaudeなどの自動プロンプトキャッシュには「先頭から連続して完全一致している部分のみキャッシュされる」という厳格なルールがあります。動的な値が先頭に混ざると、そこから後ろの数万トークンがすべてキャッシュミス(通常課金)になります。

悪い順序(キャッシュ破壊パターン)

[
  {"role": "system", "content"          
                  
        
	
	

: "時刻: 2026-04-20 10:00:00\nあなたは優秀なAIです。"},
  {"role": "system", "content": "<AGENTS_MD_CONTENT>"},
  {"role": "system", "content": "<BYTE_ROVER_MEMORY>"}
]

ここで時刻が変わるため以降全てミス。巨大なルールが毎回課金され、動的メモリも破壊要因になります。

良い順序(キャッシュ最適化パターン)

固定の巨大ブロックを絶対に先頭に配置し、動的な情報を末尾に追いやります。

def build_messages(user_input, agents_md, dynamic_memory):
    return [
        # ここから上は「絶対に不変」の巨大ブロック(キャッシュ対象)
        {"role": "system", "content": "あなたはシステムアーキテクト兼司令塔です。"},
        {"role": "system", "content": f"【基本ルール】\n{agents_md}"},
        {"role": "system", "content": "【利用可能ツール】\n" + get_tool_schemas_str()},
        # ここから下は「リクエスト毎に変わる」ブロック(キャッシュ対象外)
        {"role": "system"          
          
, "content": f"【現在のコンテキスト(ByteRover)】\n{dynamic_memory}"},
        {"role": "system", "content": f"【システム時刻】\n{get_current_time()}"},
        {"role": "user", "content": user_input}
    ]

この順序変更だけで、私の環境では20KトークンのAGENTS.mdが安定してキャッシュヒット($0.16/1M)するようになり、入力コストが80%以上削減されました。

打ち手2: cronジョブをローカルLLM(gemma4:e4b)へ分離する

10分に1回のメールチェックやログ監視など、定期実行されるcronジョブをフロンティアLLMの司令塔に任せるのはコストのブラックホールです。単純なルーティングや分類は、Ollamaで動く軽量なローカルモデルに一次受けさせます。

# cron_mail_router.py
import ollama
import json

ROUTER_PROMPT = """あなたはメールトリアージAIです。
以下のメールを読み、JSONで判定結果のみを出力してください。
{"priority": "urgent"|"normal"|"ignore", "needs_human": true|false}
"""

def evaluate_mail(email_data):
    # 軽量で高速な gemma4:e4b をローカルで実行 (コスト$0)
    response = ollama.chat(
        model='gemma4:e4b',
        messages=[
            {'role': 'system', 'content': ROUTER_PROMPT},
            {'role': 'user', 'content': f"Subject: {e        
        
mail_data.subject}\nBody: {email_data.body[:500]}"}
        ],
        format='json'
            
          
  )
    return json.loads(response['message']['content'])

for mail in fetch_emails():
    decision = evaluate_mail(mail)
    # 本当に緊急・複雑なものだけ司令塔(Kimi/Claude)へ回す
    if decision['priority'] == 'urgent' or decision['needs_human']:
        invoke_frontier_agent(mail)

このレイヤー1(フィルター層)の導入により、無駄なAPIコールが1日50回から数回に激減しました。

打ち手3: 司令塔の Thinking モードを明示的にオフにする

Kimi K2.6やDeepSeek R1などの推論(Thinking)モードは強力ですが、出力トークンに「見えない推論トークン」が加算されます。単純なツール呼び出しやタスクの委譲判断にThinkingは不要であり、オンにすると出力コストが実質3〜4倍に跳ね上がります。

Moonshot(Kimi)のAPIを叩く際、タスク種別によってパラメータを動的に切り替える実装が必須です。

def call_kimi_agent(messages, task_type):
    # 設計、デバッグ、複雑な推論が必要なタスクのみThinkingを有効化
    needs_thinking = task_type in ["architecture_design", "complex_debug"]
    
    extra_params = {}
    if not needs_thinking:
        # 司令塔のルーティングや単純なツール実行時は無効化
        extra_params['thinking'] = {'type': 'disabled'}

    response = client.chat.completions.create(
        model='kimi-k2.6',
        messages=messag        
        


es,
        extra_body=extra_params # ここで制御
    )
    return response

打ち手4: AGENTS.md に「API節約ルール」をハードコードする

エージェントが自律的に動く際、「念のための再確認」を減らすプロンプトエンジニアリングです。以下の条項を AGENTS.md に追加するだけで、APIの往復回数(

=コスト)を劇的に抑えられます。

## 💰 効率とコスト管理ルール(最重要・厳守)

1. **記憶の保持(ファイル再読み取り禁止)**: 
   一度 `view_file` や `read_file` で取得したファイルの内容はコンテキスト内で記憶すること。同じファイルを2度読み込むことはトークンの無駄遣いであるため固く禁ずる。
2. **バルク処理の原則**: 
   タスク着手時、関連する複数のファイルの中身を知る必要がある場合は、1ターンのツール呼び出しで複数のファイルを並列に読み込むこと。1つ読んでから次を探すような直列処理は避ける。
3. **無駄な「Thinking」の抑制**:
   ツールを実行するだけのターンや、明確な事実を報告するだけのターンで長々と考察(Thinking)を出力しないこと。結論とツール呼び出しのJSONのみを簡潔に出力せよ。
4. **過度な自己修復ループの禁止**:
   同じエラーが3回連続で発生した場合、それ以上の自律的な修復を試みず、直ちに人間に支援を要請(ask_human)すること。

打ち手5: リポジトリの全文検索をRAG(ripgrep)で前処理する

巨大なプロジェクトディレクトリをエージェントに「探索」させると、見当違いのファイルを次々と view してコンテキストを食いつぶします。これを防ぐため、エージェントにはファイルシステムを直接触らせず、専用の「検索ツール」を提供します。

手軽で強力なのは ripgrep のラッパーツールの提供です。

import subprocess

def search_codebase(query, directory="."):
    """エージェントから呼び出される検索ツール"""
    try:
        # rgコマンドで関連箇所だけを高速に抽出
        result = subprocess.run(
            ["rg", "-n", "-C", "2", query, directory],
            capture_output=True, text=True, timeout=10
        )
        if not result.stdout:
            return "No matches found."
        
        # 結果が大きすぎる場合は切り詰める(コンテキスト保護)
        lines = result.stdout.split('\n')
        if len(lines) > 200:
            return '\n'.join(lines[:200]) + "\n... (Truncated. Please refine search query.)"
        return result.stdout
        
    except Exception as e:
        return str(e)

エージェントは「ファイル全体」を読む前にこのツールで「関連する行とその周辺」だけを取得できるようになり、探索コストが1/10以下になります。

打ち手6: 会話履歴(Tool Calls)の早期圧縮・スライディングウィンドウ

フレームワークのデフォルト設定では、コンテキスト上限(例: 200K)ギリギリまで履歴を溜め込みます。しかし従量課金では「溜まった履歴を毎回再送信する」こと自体が課金対象です。DeepSeekの戦略に倣い、履歴が50%に達したら、古いツール呼び出し結果を大胆に破棄(Discard)する処理を挟みます。

def apply_context_sliding_window(messages, max_toke          
          
ns=256_000, threshold=0.5):
    current_tokens = estimate_tokens(messages) # トークン計算関数(tiktoken等)
    
    # 閾値(例: コンテキストの50%)を超えたら圧縮発動
    if current_tokens > (max_tokens * threshold):
        # システムプロンプト(先頭の固定情報)は絶対に保護する
        system_messages = [m for m in messages if m['role'] == 'system']
        
        # ツール呼び出しとその結果(最もトークンを消費する部分)を抽出
        tool_interactions = [m for m in messages if m.get('tool_calls') or m['role'] == 'tool']
        
        # 古いツール実行履歴の先頭75%を思い切って捨てる
        keep_count = max(1, len(tool_interactions) // 4)
        preserved_tools = tool_interactions[-keep_count:]
        
        # 直近のユーザーとアシスタントの対話は残す
        recent_conversations = [m for m in messages if m['role'] in ['user', 'assistant'] and not m.get('tool_calls')][-5:]
        
        return system_messages + preserved_tools + recent_conversations
        
    return messages

打ち手7: ByteRover 等による長期記憶の外部化

エージェントが「過去のプロジェクトで得た知見」や「ユーザーの好み(Vibe)」を維持しようとすると、システムプロンプトが肥大化し続けます。そこで、長期記憶はコンテキストから外し、ByteRoverのような外部のメモリ層(Memory Layer)に逃がします。

ポイントは、ByteRoverから取得したサマリを、プロンプトの「先頭」ではなく「末尾(動的領域)」に挿入することです(打ち手1参照)。これにより、長期記憶を維持したままプロンプトキャッシュの恩恵をフルに受けることができます。

まとめ: 実測データの推移と今後の展望

これらの打ち手を1週間かけて順次デプロイした結果、以下のようにコストダウンが実現しました。

導入した打ち手 削減額/日 1日の着地
導入前(K2.6 フル稼働・キャッシュ無視) - $28.00
打ち手2: cronをgemma4ローカル 判定に分離 -$12.00 $16.00
打ち手1: プロンプト配列の順序最適化(キャッシュ発火) -$3.00 $13.00
打ち手3: 司令塔のThinkingモード選択的オフ -$2.00 $11.00
打ち手4: AGENTS.mdへの効率ルール追加 -$1.50 $9.50
打ち手5: ripgrepによるRAG的探索の前処理 -$1.00 $8.50
打ち手6: 会話履歴の早期圧縮(50%閾値でDiscard) -$0.50 $8.00

結果的に、エージェントのタスク完遂能力や自律性を一切落とすことなく、コストだけを約70%カットすることに成功しました。

Anthropicの締め出しは、短期的には私たちに「API破産」の恐怖を与えました。しかし長期的には、開発者が「コンテキストの経済学」を真剣に学び、システムアーキテクチャを最適化する良い劇薬になったと感じています。

まずは一番効果の大きい「cronジョブのローカル分離」「プロンプト順序の修正(キャッシュ化)」から試してみてください。ダッシュボードの請求額が目に見えて減っていく快感は、コードをリファクタリングしてパフォーマンスが向上した時の喜びに似ています。

【前編】Anthropic締め出しの衝撃と「API破産」からの生還を読む

この記事をシェア: