llm-scan は何をしますか?
このスキルは、リポジトリ内のすべてのLLM呼び出し箇所と使用ログを work/<repo>/routes.json にマッピングします。読み取り専用です。対象リポジトリ内で編集、フォーマット、コミット、実行は一切行いません。
0. セットアップ
- 自分のコーディングエージェントがClaude CodeかCodex(またはその他のコーディングエージェント)かを判別します。このパック内の該当するファイル
delegation/claude.mdまたはdelegation/codex.mdのみを読み込んでください。そのファイルには、どのステップを安価で高速なヘルパーに任せ、どのステップを自分で行うかが書かれています。 <pack>をscripts/calc.pyがあるフォルダ(このファイルから2階層上)に設定し、<repo>を対象リポジトリのフォルダ名に設定します。<pack>/work/<repo>/を作成し、すべての出力はそこに配置します。対象リポジトリには決して書き込みを行わないでください。
1. すべての呼び出し箇所を検出する
リポジトリ全体を検索します(node_modules、.venv、dist、build、.git、ロックファイルはスキップ)。以下をすべてカウントします:
- SDK呼び出し:モデルにプロンプトを送信する任意のクライアントライブラリ呼び出し(chat、messages、completions、responses、embeddings、ストリーミングヘルパー、エージェントフレームワーク)。
- CLIサブプロセス呼び出し:コードから非対話モードで実行されるエージェントまたはモデルCLI(
-p、exec、--promptなどのprintフラグを使用)。これには長時間稼働するウォームワーカーやストリームJSONパイプも含まれます。 - HTTP呼び出し:モデルAPI URL、ゲートウェイ、プロキシ、またはセルフホストエンドポイントへの直接リクエスト。
- 判断、ゲート、分類器、ルーター、リランカー、審査モデル:小さくて安価なものでもLLM呼び出しとして扱います。
- モデルにアクセスするウォームアップ、キープアライブ、ヘルスチェック呼び出し:ルートとして記録します(ログに使用量がないことが多いため、
usage_gapsを参照)。 - テスト、スクリプト、ノートブック、cronジョブ内の呼び出し:リストアップしますが、本番環境で実行されない場合は
"live": falseとマークします。 - 非LLMモデル呼び出し(音声認識、音声合成、OCR、分単位または画像単位で課金されるビジョンサービス):価格設定の対象外です。
"kind": "non_llm"としてリストアップし、レポートで確認済みだが価格設定されていないことを示せるようにします。
クライアントインポート、APIホスト名、model= / "model": 文字列、max_tokens、stream、cache_control、モデルCLIのサブプロセス生成を検索します。その後、各ヒットを開き、その周辺の関数を読み取ります。
2. 各ルートを記録する
呼び出し箇所ごとに1つのエントリを書き込みます。ルートIDは relative/path.ext:function_name です。メソッドの場合は relative/path.ext:Class.method、トップレベルの場合は <module> を使用します。同じIDの綴りをすべての場所(routes.json、行、レポート)で使用します。
| フィールド | 意味 |
|---|---|
id | file:function または file:Class.method |
kind | sdk、cli、http、non_llm |
provider | コードに表示されているとおり。それ以外は null |
model | モデル文字列をそのまま、またはそれを設定する設定キー/環境変数(その場合は model_source も指定)。1つのルートでモデルが実行時に変わる場合は "varies" と書き、設定またはソースを model_source に指定 |
streaming | true / false / null |
cache_markers | explicit(コードがプロンプトキャッシュポイントを明示)、implicit(明示的なマークはないが、安定したプレフィックス、ウォームプロセス、またはプロバイダーのデフォルトでキャッシュされる可能性あり)、none(キャッシュを示唆するものなし)、unknown |
max_tokens | 数値、未設定の場合は null |
retries | リトライ回数とその場所(SDKデフォルト、ラッパー、ループ)、または 0 |
user_waits | ユーザーが応答を待っている場合(チャット、音声、ライブUI)は true。バッチ、バックグラウンド、cronの場合は false。判断できない場合は "unknown" |
decision_model | ゲート、ルーター、分類器、審査モデルの場合は true |
decision_shaped | 回答がコード分岐に供給される小さな判定(列挙、真偽値、ラベル、スコア)であり、ルートがイベントまたはアイテムごとに実行される場合は true。回答が自由文または長い構造化出力の場合は false。判断できない場合は "unknown"。すべてのルートで記録。calc はログからも検出します(50回以上の呼び出しで出力p50が5トークン以下の場合) |
tools | ツールまたは関数定義が構築・送信される場所(file:function、およびコードから呼び出しごとに送信される数)、またはそのルートが何も送信しない場合は null。事実のみ。数値はログから取得 |
live | true。テストのみの場合は false。判断できない場合は "unknown" |
stateless | 各呼び出しが独立している場合(以前のターンがないイベントごとのゲートや分類器)は true。会話やメモが呼び出しをまたいで成長する場合は false。"unknown" |
notes | 1行の短いメモ。確認した事実のみ |
判断できない場合は null(またはテーブルで許可されている場合は "unknown")を使用します。値を推測しないでください。
3. 使用ログを見つける
アプリケーションがトークン、コスト、レイテンシ、最初のトークンまでの時間、成功をすでに記録している場所を見つけます。ログファイル、JSONL、CSV、SQLiteまたはデータベーステーブル、トレーシングとメトリクス呼び出し、レスポンスから保存されたプロバイダー使用フィールドを探します。それぞれについて以下を記録します:
- パスまたはテーブル、およびフォーマット;
- フィールドの名前のみ、値は記録しません;
- プロンプトまたは応答テキストを保持するフィールドがあるかどうか(
has_text_fields); - どのルートIDをカバーしているか。
フィールド名を学習するために必要な最初の数行を超えてログ値を開いたり、ログからテキストをコピーしたりしないでください。
また、フィールド名のみで、ログが呼び出しごとのツール定義またはツール使用を記録しているかどうか(送信されたツールの数、ツール定義のサイズ(トークン数)、応答内のツール呼び出しの数)を確認します。llm-capture はこれらを tools_defined、tool_schema_tokens、tool_calls に変換します。ログにこれらがない場合は、usage_gaps にその旨を記述します。
また、usage_gaps を記録します。呼び出しが行われているにもかかわらず、ログにトークン使用量がない、または記録された数値をそのまま信頼できない場合の、簡潔なプレーンテキストメモ(各行1つ、事実のみ)です。例:「ルートXのウォームアップ呼び出しは使用量なしでログに記録されている」、「記録されたコストはプロセスごとの累積合計である」、「ルートYはまったくログに記録されていない」。フィールド名とカウントのみから読み取った場合は、「N回確認」のようなカウントも歓迎します。
4. routes.json を書き込む
<pack>/work/<repo>/routes.json を書き込みます:
{
"repo": "<repo>",
"root": "<対象リポジトリの絶対パス>",
"scanned": "<YYYY-MM-DD>",
"routes": [
{"id": "path/file.py:Class.method", "kind": "cli", "provider": null, "model": "<string>", "model_source": null,
"streaming": true, "cache_markers": "implicit", "max_tokens": null, "retries": 0,
"user_waits": true, "decision_model": false, "decision_shaped": false, "tools": null, "live": true, "stateless": false, "notes": ""},
{"id": "path/stt.py:transcribe", "kind": "non_llm", "live": true, "notes": "音声認識、価格設定対象外"}
],
"usage_logs": [
{"path": "<相対パスまたはテーブル>", "format": "jsonl", "fields": ["<名前のみ>"],
"has_text_fields": true, "covers_routes": ["path/file.py:Class.method"]}
],
"usage_gaps": ["<各項目1行の短いメモ">]
}
5. 完了
検出したルート数、ユーザー向けのルート、存在する使用ログ、および usage_gaps を数行でユーザーに伝えます。ここでコストや速度を見積もらないでください。数値は scripts/calc.py からのみ提供されます。
その後、次のスキル llm-capture を実行します。