“¿Este modelo admite llamadas a herramientas?” suena como una pregunta sobre el modelo. No lo es. Es una pregunta sobre el modelo y el endpoint en el que se invoca — y el mismo modelo puede responder que sí en uno y que no en otro. Esta página explica por qué, y cómo Entity Enricher resuelve la cuestión midiéndola en lugar de creer a un catálogo.
Envíe a la familia gpt-6 de OpenAI una solicitud con herramientas de función en el endpoint clásico /v1/chat/completions y la solicitud se rechaza de plano:
400 Bad Request Function tools with reasoning_effort are not supported. Use /v1/responses or set reasoning_effort to 'none'.
Envíe el mismo modelo, las mismas herramientas y el mismo prompt a /v1/responses y responde con normalidad: en ambos canales de salida estructurada, con o sin esfuerzo de razonamiento. Nada cambió en el modelo. Solo la dirección.
La consecuencia
Una capacidad no es una propiedad del modelo por sí solo. Es una propiedad del par (modelo, endpoint). Por eso, todo catálogo que almacena un único verdadero/falso por modelo responde a una pregunta que en realidad no puede ver.
Una ruta no es más que el endpoint al que se envía una solicitud. Mismo proveedor, mismo modelo, misma clave de API — pero un formato de transmisión distinto, una estructura de solicitud distinta y un conjunto de reglas distinto sobre qué puede combinarse. OpenAI ofrece dos de ellos, y la mayor parte del sector copió el más antiguo.
| Ruta | Forma del intercambio | Quién la habla |
|---|---|---|
Chat Completions /v1/chat/completions2023 | Sin estado: usted envía la lista completa de mensajes y recibe de vuelta el siguiente mensaje. No se conserva nada en el servidor entre llamadas. | OpenAI, y el estándar de facto del sector copiado por casi todos los demás: xAI, DeepSeek, Alibaba, Groq, Together, Ollama y la mayoría de las pasarelas compatibles con OpenAI. |
API Responses /v1/responses2025 | Devuelve una lista de elementos tipados (un elemento de razonamiento, un mensaje, una llamada a herramienta de función, una llamada a herramienta alojada), mantiene el estado en el servidor y puede transportar el razonamiento de un turno al siguiente. | Solo OpenAI. Un endpoint similar que hable el formato de Chat Completions no sirve automáticamente este. |
Por eso hoy “la API de OpenAI” resulta ambigua: hay dos, se solapan y no aplican las mismas reglas.
Los modelos de razonamiento rompieron el modelo de mensajes. El razonamiento interno de un modelo no es un mensaje: no es algo que él le haya dicho a usted, ni algo que usted le haya dicho a él. Chat Completions solo dispone de una lista de mensajes, así que no tiene dónde colocar el razonamiento, y lo que no puede representar lo descarta entre turnos.
La Responses API se diseñó en torno a esa carencia. El razonamiento es un elemento de primer nivel en la lista devuelta; puede volver cifrado y reproducirse en el siguiente turno, de modo que el modelo continúa a partir de su propio razonamiento en lugar de reconstruirlo.
Una llamada a una herramienta de función es un ida y vuelta: el modelo pide una herramienta, su código responde y el modelo continúa. En Chat Completions no hay dónde conservar el razonamiento durante ese ida y vuelta, por lo que la continuación se reanudaría en silencio sin él — el modelo tendría que rehacer el razonamiento que usted ya pagó, y probablemente lo rehiciera de otra forma.
Por eso el proveedor rechaza la combinación en lugar de degradarse en silencio. El mensaje de error no es una limitación del modelo; es la API más antigua admitiendo que no tiene espacio para lo que este modelo produce.
Si todas las capacidades prefirieran el mismo endpoint, una ruta sería un detalle de implementación en el que nadie tendría que pensar. Pero no es así.
La salida estructurada a través del canal de herramientas es exactamente la combinación que Chat Completions rechaza en un modelo de razonamiento, y la herramienta de búsqueda web alojada por el proveedor solo se acepta ahí.
Adjuntar bytes de audio sin procesar es algo que la vía de la Responses API no puede transportar, por lo que un modelo con capacidad de audio solo es accesible a través del endpoint más antiguo.
Un modelo, dos capacidades, dos endpoints distintos. No existe un único verdadero/falso que sea honesto con ambas: por eso Entity Enricher registra un mapa de capacidades por ruta, y por eso una ejecución que necesita dos capacidades ubicadas en dos rutas distintas se rechaza de forma explícita en lugar de perder una de ellas en silencio.
El sondeo de capacidades no envía una solicitud sintética escrita a mano. Recorre la ruta real del agente, el mismo código que sigue una ejecución de enriquecimiento, con la capacidad evaluada forzada, y deja que decida la respuesta del proveedor. Por tanto, lo que se mide es lo que la aplicación puede hacer realmente, no lo que la API podría aceptar en teoría.
Toda la escalera —canales de salida estructurada, visión, PDF, audio, búsqueda web, razonamiento y su control de esfuerzo por solicitud— se ejecuta una vez por cada ruta que el router puede elegir. Para casi todos los proveedores se trata de una sola ruta, y el sondeo cuesta exactamente lo mismo que siempre; solo los proveedores con forma de OpenAI, a los que realmente se puede llegar de dos maneras, se miden dos veces.
Una ruta que no responde a su primera llamada de texto plano simplemente no se mide, y un modelo sondeado se enruta solo a las rutas que respondieron — no hay recurso a otro endpoint, ni al seleccionar ni cuando falla una ejecución. Un modelo al que no responde ninguna ruta se retira, igual que aquel cuyas rutas no ofrecen ninguno de los dos canales de salida estructurada: el texto nunca es una alternativa, así que ese modelo no podría atender ni un solo enriquecimiento. Solo un sondeo posterior que demuestre un canal lo reincorpora. Las capacidades nunca se modifican porque una ejecución haya fallado: el sondeo es lo único que las mide.
La solicitud se aceptó y el modelo produjo el tipo de respuesta esperado.
Se registra como un verdadero medido para esa ruta, y prevalece sobre cualquier afirmación obtenida por scraping.
El proveedor rechazó explícitamente la capacidad, o el cliente se negó a construir siquiera la solicitud.
El único resultado autorizado a escribir un false. Un rechazo también es gratuito: nunca se factura.
Cualquier otra cosa: un límite de tasa, un nivel de acceso ausente, un tiempo de espera agotado, un 5xx del proveedor, un error no reconocido.
No se escribe nada, y el siguiente sondeo puede resolverlo.
Los dos errores no cuestan lo mismo. Un unknown incorrecto cuesta un nuevo sondeo: la capacidad simplemente se vuelve a medir más adelante. Un no incorrecto es silencioso y permanente: degrada el modelo en todas partes, lo elimina de los selectores y de la decisión de enrutamiento, y nadie llega a saber por qué. Por eso un fallo no reconocido no prueba nada, y se registra como que no prueba nada.
Un HTTP 200 demuestra que la solicitud fue aceptada. No demuestra que el modelo haya leído realmente el adjunto — un proveedor puede aceptar sin problema una imagen y entregarla a un modelo que nunca la mira. Por eso, cada sondeo que lleva contenido lleva uno cuya respuesta se puede comprobar:
| Capacidad | Payload enviado | Pregunta formulada |
|---|---|---|
| Visión | Una imagen roja uniforme | “¿Qué color predomina?” |
| Entrada PDF | Un PDF que contiene exactamente una palabra | “¿Qué palabra aparece en el documento?” |
| Entrada de audio | Un archivo de audio con un número contable de tonos | “¿Cuántos pitidos independientes?” |
Dos resultados separados, deliberadamente
La respuesta de contenido se registra junto al veredicto y nunca invierte el indicador de capacidad. Un modelo pequeño que interpreta mal un cuadrado rojo sigue admitiendo visión: el transporte funcionó, la modalidad se transmitió, el modelo simplemente era flojo. Confundir «no puede» con «lo hizo mal» eliminaría en silencio una capacidad funcional por una sola palabra equivocada; mantenerlas separadas le indica ambas cosas a la vez.
Los catálogos públicos de modelos como LiteLLM o PricePerToken declaran las capacidades como un hecho plano sobre un modelo, sin endpoint asociado. No es descuido: no existe un campo para ello. Pero significa que una afirmación puede ser perfectamente correcta en general y, aun así, errónea para el endpoint que utiliza su ejecución.
“Este modelo admite llamadas a herramientas.” Cierto en algún lugar. Sin decir dónde. Útil como punto de partida para un modelo que nadie ha sondeado todavía.
“En este endpoint, este modelo aceptó llamadas a herramientas en este momento.” Indica su ruta, de modo que puede compararse con la ruta que seguirá realmente una ejecución.
Nombrar la ruta es también lo que mantiene honesta una medición con el paso del tiempo. Un veredicto obtenido en un endpoint que el modelo ya no utiliza no es mejor evidencia que una afirmación: es evidencia sobre otra cosa. Sin la ruta registrada junto a ella, una medición antigua sería indistinguible de una actual y prevalecería sobre el catálogo para el endpoint equivocado. Con la ruta registrada, sencillamente no se aplica, y la afirmación se mantiene hasta que una medición en el endpoint correcto la sustituya.
Tanto el catálogo de modelos de la aplicación como el catálogo de modelos público incluyen un selector de Ruta junto a los filtros. Cambia la ruta por la que responden los iconos de capacidad de cada fila.
Cada fila responde por el endpoint en el que ese modelo se sirve realmente. Esta es la vista que coincide con lo que obtiene al ejecutar un enriquecimiento, y es la que conviene consultar salvo que esté investigando un endpoint concreto.
Fije toda la tabla a un solo endpoint y los iconos responderán únicamente por ese endpoint: así es como ve aparecer o desaparecer una capacidad al cambiar entre ellos, y como compara dos modelos en igualdad de condiciones.
Un modelo con una sola ruta accesible no muestra ningún selector: no hay nada que elegir, y sus iconos ya responden por el único endpoint que tiene. El selector aparece justo cuando la ambigüedad es real.
Nada, la mayoría de las veces, y esa es la idea. Usted nunca elige una ruta. Elige un modelo y describe su ejecución, y el enrutador selecciona el endpoint capaz de soportar lo que la ejecución necesita: las herramientas y la búsqueda web van donde se aceptan; un adjunto de audio va donde se transporta el audio.
El único caso que notará es un conflicto real: por ejemplo, solicitar búsqueda web y adjuntar un archivo de audio al mismo modelo de OpenAI, ya que ningún endpoint por sí solo admite ambas cosas. Esa ejecución se rechaza de forma explícita, indicando las dos capacidades y lo que puede transportar cada ruta, en lugar de ejecutarse y descartar una de ellas en silencio. Elimine uno de los requisitos, o elija un modelo que admita ambos, y continuará.
Y cuando un icono de capacidad le sorprenda, el selector de Ruta es la explicación: casi siempre está viendo un modelo cuya respuesta depende de dónde se hizo la pregunta.