Was macht llm-scan?
Dieses Skill kartiert jede LLM-Aufrufstelle und Nutzungsprotokoll eines Repositorys in work/<repo>/routes.json. Es ist schreibgeschützt: Es wird niemals etwas im Ziel-Repository bearbeitet, formatiert, committet oder ausgeführt.
0. Einrichtung
- Erkenne, welcher Coding-Agent du bist: Claude Code oder Codex (oder ein anderer Coding-Agent). Lese nur die passende Datei,
delegation/claude.mdoderdelegation/codex.md, in diesem Paket. Darin steht, welcher Schritt an einen billigen, schnellen Helfer geht und welcher bei dir bleibt. - Setze
<pack>auf den Ordner, derscripts/calc.pyenthält (zwei Ebenen über dieser Datei) und<repo>auf den Ordnernamen des Ziel-Repositorys. Erstelle<pack>/work/<repo>/; alle Ausgaben gehen dorthin. Schreibe niemals in das Ziel-Repository.
1. Finde jede Aufrufstelle
Durchsuche das gesamte Repository (überspringe node_modules, .venv, dist, build, .git, Lockfiles). Zähle alle davon:
- SDK-Aufrufe: jeder Client-Bibliotheksaufruf, der eine Eingabeaufforderung an ein Modell sendet (Chat, Messages, Completions, Responses, Embeddings, Streaming-Helfer, Agent-Frameworks).
- CLI-Subprocess-Aufrufe: ein Agenten- oder Modell-CLI, der aus Code im nicht-interaktiven Modus ausgeführt wird (ein Print-Flag wie
-p,exec,--prompt), einschließlich langlebiger Warm-Worker und Stream-JSON-Pipes. - HTTP-Aufrufe: direkte Anfragen an eine Modell-API-URL, ein Gateway, einen Proxy oder einen selbst gehosteten Endpunkt.
- Entscheidungs-, Gate-, Klassifikator-, Router-, Reranker- und Judge-Modelle, auch wenn sie klein oder billig sind. Auch sie sind LLM-Aufrufe.
- Warm-Up-, Keepalive- und Health-Check-Aufrufe, die ein Modell treffen: zeichne sie als Routen auf (sie haben oft keine Nutzung in den Protokollen; siehe
usage_gaps). - Aufrufe in Tests, Skripten, Notebooks und Cron-Jobs: liste sie auf, markiere sie aber mit
"live": false, wenn sie nie in der Produktion ausgeführt werden. - Nicht-LLM-Modellaufrufe (Spracherkennung, Text-to-Speech, OCR, Bildverarbeitungsdienste, die pro Minute oder pro Bild abgerechnet werden): liegen außerhalb des Rahmens für die Preisberechnung. Liste sie mit
"kind": "non_llm"auf, damit der Bericht sagen kann, dass sie gesehen und nicht bepreist wurden.
Suche nach Client-Imports, API-Hostnamen, model= / "model":-Strings, max_tokens, stream, cache_control und Subprocess-Spawns von Modell-CLIs. Öffne dann jeden Treffer und lies die umgebende Funktion.
2. Zeichne jede Route auf
Schreibe einen Eintrag pro Aufrufstelle. Die Routen-ID ist relative/path.ext:funktionsname; für eine Methode relative/path.ext:Klasse.methode; verwende <module> auf oberster Ebene. Verwende überall die gleiche Schreibweise der ID (routes.json, Zeilen, Bericht).
| Feld | Bedeutung |
|---|---|
id | datei:funktion oder datei:Klasse.methode |
kind | sdk, cli, http, non_llm |
provider | wie im Code gezeigt, sonst null |
model | die Modellzeichenfolge genau wie geschrieben, oder der Konfigurationsschlüssel / die Umgebungsvariable, die sie setzt (dann auch model_source). Wenn das Modell einer Route zur Laufzeit variiert, schreibe "varies" und nenne die Konfiguration oder Quelle in model_source |
streaming | true / false / null |
cache_markers | explicit (der Code markiert Prompt-Cache-Punkte), implicit (keine Markierungen, aber ein stabiles Präfix, ein Warmprozess oder eine Provider-Voreinstellung könnte es cachen), none (nichts deutet auf Caching hin), unknown |
max_tokens | die Zahl, oder null wenn nicht gesetzt |
retries | Anzahl und wo (SDK-Standard, Wrapper, Schleife), oder 0 |
user_waits | true, wenn eine Person auf die Antwort wartet (Chat, Sprache, Live-UI); false für Batch, Hintergrund, Cron; "unknown" wenn du es nicht sagen kannst |
decision_model | true für Gates, Router, Klassifikatoren, Judges |
decision_shaped | true, wenn die Antwort ein winziges Urteil ist, das einen Codezweig speist (ein Enum, ein Boolean, ein Label, ein Score) und die Route pro Ereignis oder pro Element läuft; false, wenn die Antwort freier Text oder lange strukturierte Ausgabe ist; "unknown" wenn du es nicht sagen kannst. Zeichne es für jede Route auf; calc erkennt es auch aus den Protokollen (Ausgabe p50 von 5 Token oder weniger bei 50+ Aufrufen) |
tools | wo Tool- oder Funktionsdefinitionen erstellt und gesendet werden (datei:funktion, und wie viele pro Aufruf gesendet werden, wenn der Code es zeigt), oder null, wenn die Route keine sendet. Nur Fakten; die Zahlen kommen aus den Protokollen |
live | true; false wenn nur Test; "unknown" wenn du es nicht sagen kannst |
stateless | true, wenn jeder Aufruf eigenständig ist (ein Gate oder Klassifikator pro Ereignis, das keine vorherigen Turns sendet); false, wenn eine Konversation oder ein Memo über Aufrufe hinweg wächst; "unknown" |
notes | eine kurze Zeile, nur Fakten, die du gesehen hast |
Verwende null (oder "unknown" wo die Tabelle es erlaubt), wenn du es nicht sagen kannst. Rate niemals einen Wert.
3. Finde die Nutzungsprotokolle
Finde, wo die Anwendung bereits die Nutzung aufzeichnet (Token, Kosten, Latenz, Zeit bis zum ersten Token, Erfolg). Suche nach Protokolldateien, JSONL, CSV, SQLite oder Datenbanktabellen, Tracing- und Metrikaufrufen sowie Provider-Nutzungsfeldern, die aus Antworten gespeichert wurden. Für jedes: zeichne auf:
- den Pfad oder die Tabelle und das Format;
- die FeldNAMEN, niemals Werte;
- ob ein Feld Eingabeaufforderungs- oder Antworttext enthält (
has_text_fields); - welche Routen-IDs es abdeckt.
Öffne keine Protokollwerte über die ersten paar Zeilen hinaus, die zum Erlernen der Feldnamen nötig sind, und kopiere keinen Text daraus.
Notiere außerdem, nur nach FeldNAME, ob die Protokolle Tool-Definitionen oder Tool-Nutzung pro Aufruf aufzeichnen (eine Anzahl gesendeter Tools, die Größe der Tool-Definitionen in Token, eine Anzahl von Tool-Aufrufen in der Antwort); llm-capture wandelt diese in tools_defined, tool_schema_tokens und tool_calls um. Wenn die Protokolle sie nicht enthalten, gib dies in usage_gaps an.
Notiere auch usage_gaps: kurze Klartext-Notizen (eine Zeile pro, nur Fakten), wo Aufrufe stattfinden, aber die Protokolle keine Token-Nutzung enthalten oder die protokollierten Zahlen nicht ohne weiteres vertrauenswürdig sind. Beispiele: "Warm-Up-Aufrufe auf Route X werden ohne Nutzung protokolliert", "Protokollierte Kosten sind ein laufender Gesamtwert pro Prozess", "Route Y wird überhaupt nicht protokolliert". Zählungen sind willkommen ("N Mal gesehen"), wenn du sie nur aus Feldnamen und Zählungen ausliest.
4. Schreibe routes.json
Schreibe <pack>/work/<repo>/routes.json:
{
"repo": "<repo>",
"root": "<absoluter Pfad des Ziel-Repositorys>",
"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": "speech-to-text, nicht bepreist"}
],
"usage_logs": [
{"path": "<relativer Pfad oder Tabelle>", "format": "jsonl", "fields": ["<nur Namen>"],
"has_text_fields": true, "covers_routes": ["path/file.py:Class.method"]}
],
"usage_gaps": ["<eine kurze Notiz pro"]
}
5. Abschluss
Teile dem Benutzer in ein paar Zeilen mit, wie viele Routen du gefunden hast, welche benutzerseitig sind, welche Nutzungsprotokolle existieren und eventuelle usage_gaps. Schätze hier keine Kosten oder Geschwindigkeiten; Zahlen kommen nur von scripts/calc.py.
Führe dann das nächste Skill aus: llm-capture.