3 puntos por GN⁺ 2025-05-28 | 1 comentarios | Compartir por WhatsApp
  • 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

 
GN⁺ 2025-05-28
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 llm de Simon

    • Se me pasó otra cosa que hice sobre llm: un plugin de ZSH que usa zle para convertir inglés en comandos de shell con una sola tecla: https://github.com/day50-dev/Zummoner
      Hoy lo usé con algo como $ git find out if abcdefg is a descendent of hijklmnop, y el for i in $(seq 1 6); do printf "%${i}sh${i}\n\n-----\n" | tr " " "#"; done | pv -bqL 30 de otro comentario originalmente también era una entrada mucho más cercana al lenguaje natural
      Al presionar ctrl-x x, el búfer se envía a OpenRouter y se reemplaza por la sintaxis correcta en menos de un segundo
    • La biblioteca se ve realmente buena, y sería ideal que hubiera un hook para que un plugin pudiera encargarse de la forma en que se muestra el contenido de la herramienta
      Abrí 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
    • Alguna vez hice yo mismo renderizadores de Markdown en streaming en varios lenguajes para mostrar rápidamente la salida en streaming de un LLM, así que me alegra ver que no soy el único
    • Suena interesante, voy a revisarlo; por ahora estoy usando llm junto con el resaltado de sintaxis de bat
  • Esto 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

    • Sí, el riesgo realmente aumenta
      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
    • Si conectas llm a una cuenta de valores, el tonto no es el bot, sino la persona que lo conectó
    • El sandboxing será clave
      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
    • Creo que la discusión sobre dispararse en el pie no apunta al punto central
      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 como find out where I am and what weather it is going to be, es muy baja
      Dicho eso, encargarle operaciones bursátiles a un LLM sin saber cómo decide me parece demasiado riesgoso
    • Cualquier herramienta puede usarse mal
  • 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 llm parece una solución liviana
    Conozco 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 “llm está por llamar a rm -rf ./*. Presiona Y para confirmar” podría evitar en cierta medida que el LLM se descontrole en la terminal

    • Me preguntaba por qué esa terminal se anunciaba por todos lados y patrocinaba tantos proyectos; ahora entiendo que no es completamente gratis
    • Me parece que así es como funciona por defecto codex CLI cuando no le pasas --full-auto
  • Si usas llm, también vale la pena ver Gtk-llm-chat
    Se integra con la herramienta de línea de comandos llm y con el escritorio, y ofrece un ícono en la bandeja y una ventana de chat agradable
    Hace poco lanzó la versión 3.0.0 y ofrece paquetes para los tres principales sistemas operativos de escritorio

    • Me da curiosidad para qué lo usan además del chat normal
  • 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

    • Esta mañana probé si podía hacer una demo rápida de un plugin con MCP, y fue bastante complicado
      La biblioteca oficial mcp de Python presupone con bastante fuerza un flujo en el que ejecutas asyncio, te conectas al servidor y luego inspeccionas las herramientas disponibles
  • Mantengo casi todo el plugin zsh/omz para autocompletado con tab del CLI llm mediante vibe coding, pero el ritmo de lanzamiento de nuevas funciones es tan rápido que cuesta seguirlo
    Aun 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

    • Es un poco sorprendente que esto no sea ciencia ficción, sino simplemente la forma de programar actual
      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

    • Ese esquema de credenciales ya es posible hoy con el soporte de herramientas de los LLM
      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 creds1 e indicarle que en solicitudes posteriores llame usando creds1
  • Me 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

    • No había visto este paper, pero es realmente interesante
      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 descubrirlo

  • Uso 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