- LLM 0.26 es una versión importante que permite conectar herramientas creadas como funciones de Python a modelos de OpenAI, Anthropic, Gemini y modelos locales de Ollama desde la CLI y la biblioteca de Python
- Las herramientas pueden instalarse como plugins y cargarse con
--tool/-T name_of_tool, o se pueden pasar funciones temporales de Python directamente desde la línea de comandos con --functions
- Además de las herramientas integradas
llm_version y llm_time, se ofrecen plugins para simpleeval, QuickJS, SQLite y Datasette; el modelo puede reintentar después de una llamada fallida consultando el esquema o usando otra expresión
- El nuevo
model.chain() de la API de Python detecta solicitudes de llamadas a herramientas, las ejecuta y vuelve a pasar el resultado al modelo; admite tanto funciones síncronas como herramientas con asyncio
- La implementación se volvió posible a medida que convergen los enfoques de uso de herramientas y llamadas a funciones de distintos proveedores; los próximos desafíos son ampliar los plugins, dar soporte a más plugins de modelos y admitir clientes de Model Context Protocol
Soporte para ejecutar herramientas en LLM 0.26
- LLM 0.26 agrega soporte para herramientas, la funcionalidad más grande desde el inicio del proyecto
- Desde la CLI de LLM y la biblioteca de Python, se puede dar a modelos de OpenAI, Anthropic, Gemini y modelos locales de Ollama acceso a herramientas representables como funciones de Python
- Al instalar nuevos plugins de herramientas, se pueden añadir nuevas capacidades al modelo que se esté usando
- Hay cuatro formas principales de uso
- Instalar una herramienta como plugin y cargarla con
--tool/-T name_of_tool
- Pasar código de funciones de Python directamente en la línea de comandos con la opción
--functions
- También se pueden pasar herramientas en la API de Python con enfoques como
tools=[locals]
- Las herramientas funcionan tanto en contextos asíncronos como síncronos
Ejecutar herramientas desde la CLI
- La versión más reciente de LLM se instala con
uv tool install llm, y una instalación existente se puede actualizar con uv tool upgrade llm
- Un ejemplo con OpenAI consiste en configurar la clave de API con
llm keys set openai y luego ejecutar lo siguiente
llm --tool llm_version "What version?" --td
llm_version es una herramienta de demostración simple incluida en LLM, y --tool llm_version expone esa herramienta al modelo
--tool puede especificarse varias veces, y también se puede usar la opción corta -T
--td es la abreviatura de --tools-debug, que imprime información sobre las llamadas a herramientas y sus respuestas para permitir ver el funcionamiento interno
- El modelo predeterminado suele ser
gpt-4o-mini; en el ejemplo se cambia el valor predeterminado a gpt-4.1-mini con llm models default gpt-4.1-mini
- Se puede indicar otro modelo con la opción
-m; también hay un ejemplo que ejecuta o4-mini junto con la herramienta integrada llm_time
llm --tool llm_time "What time is it?" --td -m o4-mini
- La respuesta de la herramienta
llm_time incluye campos como utc_time, utc_time_iso, local_timezone, local_time, timezone_offset e is_dst
Funcionamiento con varios modelos y plugins
- El mismo patrón de comandos puede usarse también con plugins de modelos que admiten herramientas
- El ejemplo con Anthropic Claude Sonnet 4 usa el siguiente flujo
llm install llm-anthropic -U
llm keys set anthropic
llm --tool llm_version "What version?" --td -m claude-4-sonnet
- El ejemplo con Google Gemini 2.5 Flash usa el siguiente flujo
llm install llm-gemini -U
llm keys set gemini
llm --tool llm_version "What version?" --td -m gemini-2.5-flash-preview-05-20
qwen3:4b, ejecutado con Ollama, también puede ejecutar herramientas simples
qwen3:4b es un modelo pequeño de 2.6 GB
ollama pull qwen3:4b
llm install 'llm-ollama>=0.11a0'
llm --tool llm_version "What version?" --td -m qwen3:4b
Plugins de herramientas para matemáticas, JavaScript, SQLite y Datasette
- Tareas en las que los LLM son débiles, como multiplicaciones de números grandes, pueden complementarse con llamadas a herramientas
- llm-tools-simpleeval expone la biblioteca simpleeval de Daniel Fairhead
- simpleeval es una biblioteca “Simple Safe Sandboxed Extensible Expression Evaluator for Python”
- Ofrece un sandbox suficientemente robusto para ejecutar expresiones simples de Python
- El ejemplo de cálculo se ejecuta así
llm install llm-tools-simpleeval
llm -T simple_eval 'Calculate 1234 * 4346 / 32414 and square root it' --td
- En la ejecución de ejemplo, el modelo primero calcula
1234 * 4346 / 32414 y obtiene 165.45208860368976; luego falla porque sqrt(...) no está definido y, tras cambiar a ** 0.5, obtiene 12.862818066181678
- Hay cuatro plugins de herramientas publicados
- llm-tools-simpleeval: soporte para expresiones simples, como matemáticas
- llm-tools-quickjs: proporciona acceso a un intérprete JavaScript QuickJS en sandbox; el entorno se conserva entre llamadas, por lo que se pueden reutilizar variables y funciones
- llm-tools-sqlite: proporciona acceso de solo lectura mediante consultas SQL a bases de datos SQLite locales
- llm-tools-datasette: ejecuta consultas SQL en instancias remotas de Datasette
Caja de herramientas de Datasette y reintento tras errores
- El plugin de Datasette funciona como una caja de herramientas que contiene varias herramientas internas
- Una caja de herramientas es un plugin que puede configurarse mediante un constructor
- El ejemplo de uso es el siguiente
llm install llm-tools-datasette
llm -T 'Datasette("https://datasette.io/content")' --td "What has the most stars?"
Datasette("https://datasette.io/content") pasa al plugin la URL de la instancia de Datasette que se va a usar
- Este ejemplo apunta a la base de datos de contenido que impulsa el sitio web de Datasette
- El modelo realiza tres llamadas
- Primero intenta con
SELECT name, stars FROM repos ORDER BY stars DESC LIMIT 1, pero falla porque no existe la columna stars
- Tras recibir el error, consulta el esquema de la base de datos con la herramienta
Datasette_schema()
- A partir del esquema, arma y ejecuta la consulta correcta
- Según la respuesta final, el repositorio con más estrellas es
datasette, con 10,020 stars
Crear herramientas temporales con --functions
- La opción
--functions ofrece una forma menos estructurada que los plugins para usar herramientas temporales
- Si se pasa directamente un bloque de código Python en la línea de comandos, las funciones definidas allí se convierten en herramientas que el modelo puede usar
- El ejemplo de herramienta para buscar en un blog llama a la página de búsqueda con
httpx y devuelve el HTML tal cual al modelo
llm --functions '
import httpx
def search_blog(q):
"Search Simon Willison blog"
return httpx.get("https://simonwillison.net/search/", params={"q": q}).content
' --td 'Three features of sqlite-utils' -s 'use Simon search'
- La implementación simplemente devuelve el HTML de la página de búsqueda sin procesar, pero funciona
- Se considera que la familia GPT-4.1 puede manejar incluso HTML tosco porque procesa 1 millón de tokens
- Hay que agregar
use Simon search al prompt del sistema para que el modelo use la herramienta de búsqueda proporcionada en lugar de responder por su cuenta
- Una mejor herramienta de búsqueda necesitaría instrucciones más detalladas y fragmentos relevantes de los resultados
- En el resultado de ejemplo, las funciones de
sqlite-utils que aparecen son la combinación de CLI y biblioteca de Python, la adición automática de columnas mediante alter=True y el soporte para plugins
Soporte de herramientas en la API de Python
- LLM es tanto una herramienta de CLI como una biblioteca de Python, y en la versión 0.26 también se agregó soporte para herramientas a la API de Python
- El ejemplo resuelve con una función-herramienta el problema de contar cuántas
r hay en “strawberry”
import llm
def count_char_in_text(char: str, text: str) -> int:
"How many times does char appear in text?"
return text.count(char)
model = llm.get_model("gpt-4.1-mini")
chain_response = model.chain(
"Rs in strawberry?",
tools=[count_char_in_text],
after_call=print
)
for chunk in chain_response:
print(chunk, end="", flush=True)
after_call=print es una forma de verificar las llamadas a herramientas, al igual que la opción --td anterior
- El nuevo método
model.chain() es similar a model.prompt(), pero detecta las solicitudes de llamadas a herramientas devueltas, las ejecuta y luego vuelve a llamar al modelo junto con el resultado
model.chain() puede ejecutar varias respuestas antes de entregar la respuesta final
- Al iterar sobre
chain_response, se pueden imprimir en streaming los tokens devueltos a lo largo de varias respuestas
- En el resultado de ejemplo, la herramienta
count_char_in_text se llama con char='r' y text='strawberry', y con base en el resultado 3 responde que strawberry contiene 3 letras r
- La biblioteca de Python también admite
asyncio, y las herramientas pueden ser funciones async def
- Si el modelo solicita varias herramientas asíncronas a la vez, la biblioteca las ejecuta simultáneamente con
asyncio.gather()
- También se admiten cajas de herramientas, por lo que pasar
tools=[Datasette("https://datasette.io/content")] a chain() tiene el mismo efecto que --tool 'Datasette(...)' en la CLI
Contexto de implementación y patrón de uso de herramientas
- El patrón de uso de herramientas es algo que se ha seguido desde que apareció por primera vez en el paper ReAcT, publicado en octubre de 2022
- El patrón básico es simple
- Se le indica al modelo que hay herramientas disponibles para usar
- El modelo solicita una acción de herramienta con una sintaxis especial como JSON, XML o
tool_name(arguments), y se detiene
- El código parsea esa salida y ejecuta la herramienta solicitada
- Se envía al modelo un nuevo prompt que incluye el resultado de la ejecución
- Este enfoque funciona hoy en casi todos los modelos
- Muchos modelos están entrenados específicamente para usar herramientas, e incluso existen rankings como el Berkeley Function-Calling Leaderboard
- OpenAI, Anthropic, Google, Mistral y Meta incluyen funciones de uso de herramientas o llamadas a funciones en sus API
- En el ámbito de los modelos locales, Ollama agregó soporte para herramientas el año pasado, y el servidor de llama.cpp también lo incluye
- En febrero de 2025, LLM lanzó primero soporte para esquemas, y lo tomó como un paso hacia el soporte de herramientas
- El desafío era diseñar una capa de abstracción que funcionara con varios modelos, y ahora que los enfoques de los proveedores convergieron claramente, fue posible implementarla
- El taller Building software on top of Large Language Models de PyCon US sirvió para terminar la implementación alfa, y también se ofrece la sección de herramientas del tutorial
Agentes y próximos planes
- Aunque el término “agents” todavía genera resistencia, en el mundo de los LLM se está convergiendo hacia tools in a loop, y LLM 0.26 también se acerca a esa forma
- Si se quiere construir un agente, LLM 0.26 puede ser un buen punto de partida
- El próximo trabajo está organizado en 13 issues dentro del milestone LLM tools v2
- Principalmente son mejoras en la visualización de logs de ejecución de herramientas y pequeños issues que no bloquearon esta versión
- Hay issues adicionales bajo la etiqueta tools
- El área que más expectativas genera es el potencial de los plugins
- Se está usando directamente la plantilla cookiecutter llm-plugin-tools
- Está previsto crear un tutorial relacionado
- También queda trabajo para agregar soporte de herramientas a más plugins de modelos
- El soporte para Model Context Protocol también forma parte del plan
- MCP está emergiendo rápidamente como una forma estándar para que los modelos accedan a herramientas
- Hace dos semanas no tenía soporte directo en las API de los principales proveedores, pero en los últimos 8 días se agregó a OpenAI, Anthropic y Mistral
- El objetivo es que LLM funcione como cliente MCP, para que los servidores MCP que escriba la gente puedan usarse fácilmente como fuentes adicionales de herramientas para LLM
1 comentarios
Opiniones de Hacker News
También vale la pena ver el renderizador de Markdown en streaming que escribí para esta herramienta: https://github.com/day50-dev/Streamdown
El contexto está en https://github.com/simonw/llm/issues/12, y también uso a diario https://github.com/day50-dev/llmehelp, que contiene una herramienta de tmux hecha sobre el
llmde Simonllm: un plugin de ZSH que usazlepara convertir inglés en comandos de shell con una sola tecla: https://github.com/day50-dev/ZummonerHoy lo usé con algo como
$ git find out if abcdefg is a descendent of hijklmnop, y elfor i in $(seq 1 6); do printf "%${i}sh${i}\n\n-----\n" | tr " " "#"; done | pv -bqL 30de otro comentario originalmente también era una entrada mucho más cercana al lenguaje naturalAl presionar
ctrl-x x, el búfer se envía a OpenRouter y se reemplaza por la sintaxis correcta en menos de un segundoAbrí un issue: https://github.com/simonw/llm/issues/1112
Incluí algunas opciones de diseño, pero todavía no siento que encajen del todo, así que me gustaría recibir feedback
llmjunto con el resaltado de sintaxis debatEsto aumenta mucho el riesgo de dispararse en el pie
La documentación https://llm.datasette.io/en/stable/tools.html advierte sobre la inyección de prompts, pero creo que un escenario más plausible es el daño que uno mismo se causa
Por ejemplo, si le das a una herramienta acceso a una cuenta de valores para automatizar operaciones, no hay nada que impida que el bot haga transacciones tontas incluso sin inyección de prompts
Cuando empiezas a conectar herramientas a un LLM, especialmente si esas llamadas a herramientas están autenticadas y pueden actuar en tu nombre, hay demasiadas formas de que las cosas salgan mal
El lado de MCP está viviendo esto a toda velocidad ahora mismo, y lo de GitHub MCP de ayer es un ejemplo: https://news.ycombinator.com/item?id=44097390
Puse una advertencia grande en la documentación y tuve cuidado de publicar como primeros plugins de herramientas solo aquellos que no pudieran causar daño. Por eso tanto el sandbox de QuickJS como el plugin de SQLite son de solo lectura
llma una cuenta de valores, el tonto no es el bot, sino la persona que lo conectóEn macOS no es terriblemente difícil, pero hoy faltan buenas herramientas fáciles de usar. Claude Code empezó a usar Seatbelt poco a poco para mejorar la experiencia de usuario
Puedes hacerte daño, y probablemente pase, pero también es riesgoso no evaluar las posibilidades. La gente común tiende a subestimar la posibilidad de dispararse en el pie, y la gente técnica tiende a subestimar el riesgo de no aprender nuevas posibilidades
Hace un año ya dejaba que un LLM ejecutara comandos locales en mi laptop y, aunque lo considero algo riesgoso, no pasó nada dañino. Incluso si existe la posibilidad de que ejecute
rm -rf /ante un prompt comofind out where I am and what weather it is going to be, es muy bajaDicho eso, encargarle operaciones bursátiles a un LLM sin saber cómo decide me parece demasiado riesgoso
Me gusta la idea del agente basado en terminal de la terminal Warp, pero no me convence el modelo tipo Cursor de “confía en nosotros y paga, que nosotros nos encargamos de los buenos prompts y de las llamadas al LLM”
Por eso estaba buscando un agente de terminal simple basado en CLI que compensara mis limitaciones con el shell, y la combinación de herramientas de terminal con
llmparece una solución livianaConozco bien el gran riesgo de dispararse en el pie, así que me pregunto si es posible pedir autorización en cada llamada a una herramienta, como hacen otros agentes. Por ejemplo, algo como “
llmestá por llamar arm -rf ./*. Presiona Y para confirmar” podría evitar en cierta medida que el LLM se descontrole en la terminal--full-autoSi usas
llm, también vale la pena ver Gtk-llm-chatSe integra con la herramienta de línea de comandos
llmy con el escritorio, y ofrece un ícono en la bandeja y una ventana de chat agradableHace poco lanzó la versión 3.0.0 y ofrece paquetes para los tres principales sistemas operativos de escritorio
Creo que este lanzamiento es un componente clave para liberar el potencial de los LLM sin las limitaciones de los clientes existentes
Después de que salió la alfa de 0.26, intenté hacer un plugin que interactuara con servidores MCP, pero fue bastante difícil. Hasta ahora logré conectarlo, obtener herramientas dinámicamente y usarlas, pero todavía no puedo pasar parámetros
La biblioteca oficial
mcpde Python presupone con bastante fuerza un flujo en el que ejecutasasyncio, te conectas al servidor y luego inspeccionas las herramientas disponiblesMantengo casi todo el plugin zsh/omz para autocompletado con tab del CLI
llmmediante vibe coding, pero el ritmo de lanzamiento de nuevas funciones es tan rápido que cuesta seguirloAun así, con algo como
llm -f README.md -f llm.plugin.zsh -f completions/_llm -f [https://simonwillison.net/2025/May/27/llm-tools/](<https://simonwillison.net/2025/May/27/llm-tools/>) "implement tab completions for the new tool plugins feature"se resuelve el 90%El repositorio es https://github.com/eliyastein/llm-zsh-plugin, y como intenté incluir la mayor cantidad posible de opciones y flags, está algo desordenado; me gustaría recibir feedback
Las generaciones futuras se preguntarán cómo lográbamos hacer nuestro trabajo, así como nosotros miramos a los programadores de ensamblador y pensamos: “¿cómo trabajaban?”
Me daba curiosidad cómo Claude Code conoce y usa las herramientas
Se le puede informar al LLM sobre herramientas y cómo usarlas, y un wrapper de ejecución puede gestionarlo, pero me parece que Claude Code tiene expectativas muy concretas sobre la API de llamadas a herramientas que usa el wrapper, y que probablemente fue reforzado con fuerza mediante postentrenamiento o fine-tuning
Por eso me pregunto si los frameworks de llamadas a herramientas de terceros que usan Claude están en desventaja frente al framework propio de Anthropic
Por separado, como se mencionaba en el artículo sobre el “ataque” a GitHub MCP, se puede engañar a un LLM para que use todos los permisos de las credenciales. Dado que GitHub tiene credenciales con permisos granulares, y en nuestra empresa también, sería bueno que alguien probara un protocolo para que el wrapper genere credenciales granulares y se las entregue al LLM
Imagino una estructura en la que se le dan credenciales más fuertes a la aplicación, y el LLM subordinado aprende a hacer “solicitudes de permiso” para tareas o recursos específicos. Si el usuario lo permite, el framework obtiene del servicio credenciales de alcance limitado y las usa para las llamadas a herramientas
Haría falta una configuración de herramientas bastante sofisticada: exponer una herramienta de “solicitar credenciales adicionales” y, cuando se invoque, preguntarle al usuario
La herramienta debe guardar las credenciales y nunca pasarle el token real al LLM; en su lugar, puede pasarle un símbolo como
creds1e indicarle que en solicitudes posteriores llame usandocreds1Me pregunto si viste este paper. Si es tan importante como parece, ¿no debería esta métrica estar en todas las system cards?
Evaluaron 12 LLM populares que afirman soportar contextos de 128K tokens o más, y aunque funcionan bien con contextos cortos, su rendimiento cae mucho a medida que aumenta la longitud del contexto. A 32K, 10 modelos cayeron por debajo del 50% de la línea base de longitud corta, y hasta GPT-4o, que tuvo un rendimiento excepcionalmente bueno, bajó de 99,3% a 69,7%
https://arxiv.org/abs/2502.05167
Por lo que sé, en las pruebas de needle in a haystack, Gemini 2.5 Pro y Gemini 2.5 Flash están muy por delante de otros modelos, así que sería bueno probarlo también con esos modelos
La semana pasada hice una demo de un chatbot para clientes basado en datos propietarios con 0.26a0
Los elementos clave que tuve que escribir yo mismo fueron el prompt del sistema, una herramienta para traer datos externos y una herramienta para realizar cálculos; gracias a esta librería, fue muy fácil construir la funcionalidad principal
La mayor parte del esfuerzo en la demo se fue en la plomería: crear una UI web agradable que mantuviera la conversación, se actualizara de forma natural aunque se refrescara el navegador por problemas de conexión, y permitiera iniciar nuevas sesiones de chat
No conocía
after_call=print, pero me enteré leyendo el post del blog y me dio gusto descubrirloUso las herramientas de Simon todos los días
Gracias a los pipes y a lo fácil que es cambiar entre Ollama local y modelos remotos, trabajar con ellas resulta muy cómodo