CommunityProgramación y desarrollogithub.com

llm-scan

Encuentra cada lugar donde un repositorio llama a un LLM y escribe un mapa de rutas (routes.json).

¿Qué es llm-scan?

llm-scan es una skill diseñada para auditar el uso de modelos de lenguaje (LLM) dentro de un repositorio. Su función principal es escanear el código fuente en busca de todos los puntos de llamada a LLMs —ya sea mediante SDK, CLI, HTTP directo, o modelos de decisión/clasificación— y generar un archivo `routes.json` que documenta cada ruta. Esto incluye detalles como el proveedor, modelo, si es streaming, marcadores de caché, si el usuario espera la respuesta, y si es un modelo de decisión. También localiza los archivos de registro de uso existentes (logs, bases de datos) para identificar dónde se registran tokens, costo y latencia. Es una operación de solo lectura: nunca modifica el repositorio objetivo. La skill está diseñada para ser ejecutada primero, ya que su salida es necesaria para las skills complementarias `llm-capture` y `llm-diagnose`. Soporta agentes de codificación como Claude Code y Codex, ajustando su comportamiento según el archivo de delegación correspondiente. Al finalizar, informa al usuario sobre la cantidad de rutas encontradas y los registros de uso detectados, sin estimar costos (eso lo hace `scripts/calc.py`).

Compatible con✓Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/lokeshrana9999/llm-cost-skills/tree/HEAD/skills/llm-scan

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace llm-scan?

Esta skill mapea cada sitio de llamada a un LLM y el registro de uso de un repositorio en work/<repo>/routes.json. Es de solo lectura: nunca edita, formatea, confirma ni ejecuta nada dentro del repositorio objetivo.

0. configuración

  1. Detecta qué agente de codificación eres: Claude Code o Codex (o cualquier otro). Lee solo el archivo coincidente, delegation/claude.md o delegation/codex.md, en este paquete. Indica qué paso va a un ayudante rápido y barato y cuál se queda contigo.
  2. Establece <pack> como la carpeta que contiene scripts/calc.py (dos niveles por encima de este archivo) y <repo> como el nombre de la carpeta del repositorio objetivo. Crea <pack>/work/<repo>/; todas las salidas van allí. Nunca escribas dentro del repositorio objetivo.

1. encuentra cada sitio de llamada

Busca en todo el repositorio (omite node_modules, .venv, dist, build, .git, archivos de bloqueo). Cuenta todos estos:

  • Llamadas SDK: cualquier llamada a una biblioteca cliente que envía un prompt a un modelo (chat, messages, completions, responses, embeddings, helpers de streaming, frameworks de agente).
  • Llamadas CLI a subprocesos: una CLI de modelo o agente ejecutada desde el código en modo no interactivo (un flag de impresión como -p, exec, --prompt), incluidos workers cálidos de larga duración y pipes de stream-json.
  • Llamadas HTTP: solicitudes directas a una URL de API de modelo, una puerta de enlace, un proxy o un endpoint autoalojado.
  • Modelos de decisión, compuerta, clasificador, enrutador, reranker y juez, incluso si son pequeños o baratos. También son llamadas a LLM.
  • Llamadas de calentamiento, keepalive y health-check que golpean un modelo: regístralas como rutas (a menudo no tienen uso en los logs; ver usage_gaps).
  • Llamadas en pruebas, scripts, notebooks y trabajos cron: enuméralas, pero márcalas con "live": false si nunca se ejecutan en producción.
  • Llamadas a modelos que no son LLM (speech-to-text, text-to-speech, OCR, servicios de visión facturados por minuto o por imagen): están fuera del alcance para precios. Enuméralas con "kind": "non_llm" para que el informe pueda decir que se vieron y no se valoraron.

Busca importaciones de cliente, nombres de host de API, cadenas model= / "model":, max_tokens, stream, cache_control y lanzamientos de subprocesos de CLIs de modelo. Luego abre cada coincidencia y lee la función alrededor.

2. registra cada ruta

Escribe una entrada por cada sitio de llamada. El id de la ruta es relative/path.ext:function_name; para un método, relative/path.ext:Class.method; usa <module> si es de nivel superior. Usa la misma ortografía de id en todas partes (routes.json, filas, informe).

camposignificado
idfile:function o file:Class.method
kindsdk, cli, http, non_llm
providercomo lo muestra el código, si no null
modella cadena del modelo exactamente como está escrita, o la clave de configuración / variable de entorno que lo establece (entonces también model_source). Cuando el modelo de una ruta varía en tiempo de ejecución, escribe "varies" y nombra la configuración o fuente en model_source
streamingtrue / false / null
cache_markersexplicit (el código marca puntos de caché de prompt), implicit (sin marcas, pero un prefijo estable, proceso cálido o valor predeterminado del proveedor puede almacenarlo en caché), none (nada sugiere almacenamiento en caché), unknown
max_tokensel número, o null si no está configurado
retriescuenta y dónde (SDK predeterminado, wrapper, bucle), o 0
user_waitstrue si una persona está esperando la respuesta (chat, voz, UI en vivo); false para batch, background, cron; "unknown" si no puedes saberlo
decision_modeltrue para compuertas, enrutadores, clasificadores, jueces
decision_shapedtrue si la respuesta es un veredicto pequeño que alimenta una rama de código (un enum, un booleano, una etiqueta, una puntuación) y la ruta se ejecuta por evento o por elemento; false si la respuesta es texto libre o salida estructurada larga; "unknown" si no puedes saberlo. Regístralo para cada ruta; calc también lo detecta desde los logs (p50 de salida de 5 tokens o menos en 50+ llamadas)
toolsdónde se construyen y envían las definiciones de herramientas o funciones (file:function, y cuántas se envían por llamada si el código lo muestra), o null si la ruta no envía ninguna. Solo hechos; los números provienen de los logs
livetrue; false si solo es prueba; "unknown" si no puedes saberlo
statelesstrue si cada llamada es independiente (una compuerta o clasificador por evento que no envía turnos anteriores); false si una conversación o memo crece a través de llamadas; "unknown"
notesuna línea corta, solo hechos que viste

Usa null (o "unknown" donde la tabla lo permita) cuando no puedas saberlo. Nunca adivines un valor.

3. encuentra los registros de uso

Encuentra dónde la aplicación ya registra el uso (tokens, costo, latencia, tiempo hasta el primer token, éxito). Busca archivos de log, JSONL, CSV, SQLite o tablas de base de datos, llamadas de tracing y métricas, y campos de uso del proveedor guardados de las respuestas. Para cada uno, registra:

  • la ruta o tabla y el formato;
  • los NOMBRES de los campos, nunca los valores;
  • si algún campo contiene texto de prompt o respuesta (has_text_fields);
  • qué ids de ruta cubre.

No abras los valores de los logs más allá de las primeras líneas necesarias para aprender los nombres de los campos, y no copies ningún texto de ellos.

También observa, solo por NOMBRE de campo, si los logs registran definiciones de herramientas o uso de herramientas por llamada (un conteo de herramientas enviadas, el tamaño de las definiciones de herramientas en tokens, un conteo de llamadas a herramientas en la respuesta); llm-capture convierte esto en tools_defined, tool_schema_tokens y tool_calls. Si los logs carecen de ellos, dilo en usage_gaps.

También registra usage_gaps: notas cortas en texto plano (una línea cada una, solo hechos) donde ocurren llamadas pero los logs no contienen uso de tokens o los números registrados no se pueden confiar tal cual. Ejemplos: "las llamadas de calentamiento en la ruta X se registran sin uso", "el costo registrado es un total acumulado por proceso", "la ruta Y no está registrada en absoluto". Los conteos son bienvenidos ("visto N veces") cuando los leas solo a partir de nombres de campo y cuentas.

4. escribe routes.json

Escribe <pack>/work/<repo>/routes.json:

{
  "repo": "<repo>",
  "root": "<ruta absoluta del repositorio objetivo>",
  "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, no valorado"}
  ],
  "usage_logs": [
    {"path": "<ruta relativa o tabla>", "format": "jsonl", "fields": ["<solo nombres>"],
     "has_text_fields": true, "covers_routes": ["path/file.py:Class.method"]}
  ],
  "usage_gaps": ["<una nota corta cada una>"]
}

5. finalizar

Informa al usuario en pocas líneas cuántas rutas encontraste, cuáles son las orientadas al usuario, qué registros de uso existen y cualquier usage_gaps. No estimes costos o velocidades aquí; los números provienen solo de scripts/calc.py.

Luego ejecuta la siguiente skill, llm-capture.

Skills relacionados