Respuesta rápida
¿Cómo funciona el tool calling en LLMwithCrypto?
Envía tus funciones en tools, en el formato de OpenAI. Cuando el modelo quiera una, LLMwithCrypto devuelve finish_reason: "tool_calls" con el nombre de la función y los argumentos en JSON; tu código la ejecuta y envía el resultado de vuelta como un mensaje tool. Para respuestas estructuradas, response_format: {"type": "json_object"} pide JSON válido. Ambos funcionan en los modelos que los admiten, según la documentación del 23 de octubre de 2026.
¿Qué modelos admiten tools y JSON?
El streaming funciona en todos los modelos; el tool calling y la salida JSON dependen de lo que admita cada modelo.
Prueba tu propio esquema en el modelo que piensas usar antes de depender de él. Un modelo que no admite tools responde en texto plano en lugar de llamar a la función; un modelo que no admite el modo JSON devuelve un error 400 para response_format.
¿Qué es el bucle?
Describe las funciones
Cada tool tiene un
name, undescriptionque el modelo lee para decidir cuándo usarla, yparameterscomo JSON Schema.Envía la conversación con tools
El modelo o bien responde en texto, o bien se detiene con
finish_reason: "tool_calls"y una o más llamadas enmessage.tool_calls.Ejecuta cada llamada
Analiza
function.arguments(una cadena JSON), ejecuta tu función y nunca confíes ciegamente en los argumentos: valídalos como cualquier entrada de usuario.Envía los resultados de vuelta
Añade el mensaje del asistente y luego un mensaje
toolpor cada llamada con sutool_call_idy el resultado como texto. Vuelve a llamar a la API; repite hasta que el modelo responda en texto.
import json
import os
from openai import OpenAI
client = OpenAI(
base_url="https://llmwithcrypto.com/api/v1",
api_key=os.environ["LLMWITHCRYPTO_API_KEY"],
)
tools = [
{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Return the delivery status of an order.",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
},
}
]
def get_order_status(order_id):
return {"order_id": order_id, "status": "shipped", "eta": "2026-10-25"}
messages = [{"role": "user", "content": "Where is my order A-1042?"}]
while True:
resp = client.chat.completions.create(model="gpt-oss-120b", messages=messages, tools=tools, max_tokens=300)
msg = resp.choices[0].message
if not msg.tool_calls:
print(msg.content)
break
messages.append(msg)
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_order_status(**args)
messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})
¿Cómo se ve una llamada a una tool en la respuesta?
El mensaje del asistente no tiene texto, tiene un array tool_calls, y la elección termina con finish_reason: "tool_calls". Los argumentos llegan como una cadena JSON, no como un objeto. Los ids y recuentos de abajo son ilustrativos.
{
"id": "chatcmpl-3c9d27e1",
"object": "chat.completion",
"created": 1792742400,
"model": "gpt-oss-120b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_7f31",
"type": "function",
"function": {
"name": "get_order_status",
"arguments": "{\"order_id\": \"A-1042\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 118,
"completion_tokens": 22,
"total_tokens": 140
}
}
¿Cómo controlo cuándo se usan las tools?
"tool_choice": "auto"(el valor por defecto cuandotoolsestá definido): el modelo decide."tool_choice": "none": el modelo responde en texto aunque haya tools listadas."tool_choice": "required": el modelo debe llamar al menos a una tool.{"type": "function", "function": {"name": "get_order_status"}}: el modelo debe llamar a esa.
Cada definición de tool se envía como entrada en cada llamada, así que las descripciones largas y muchas tools aumentan los tokens de entrada. Mantén las descripciones cortas y envía solo las tools que necesita un paso.
¿Cómo obtengo una salida JSON válida?
Define response_format como {"type": "json_object"} y describe las claves esperadas en el mensaje de sistema: el modo JSON garantiza que la respuesta se pueda parsear, no que tenga las claves que quieres. Mantén temperature bajo para una salida estable y comprueba el objeto parseado en tu código antes de usarlo.
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://llmwithcrypto.com/api/v1',
apiKey: process.env.LLMWITHCRYPTO_API_KEY,
});
const resp = await client.chat.completions.create({
model: 'gpt-oss-120b',
messages: [
{ role: 'system', content: 'Reply with a JSON object {"sentiment": "positive" | "negative" | "neutral", "reason": string}.' },
{ role: 'user', content: 'The delivery was late but support fixed it in an hour.' },
],
response_format: { type: 'json_object' },
temperature: 0.2,
max_tokens: 150,
});
const result = JSON.parse(resp.choices[0].message.content);
console.log(result.sentiment, '-', result.reason);
Tools y JSON: preguntas frecuentes
¿Las llamadas a tools tienen coste extra?
No tienen una tarifa propia. Las definiciones de tools, la llamada y los resultados que envías de vuelta son tokens, facturados como cualquier otro. Pagas por token desde tu saldo: los tokens de entrada y de salida se cuentan con el tokenizador propio del modelo y se cobran al precio de ese modelo por 1M de tokens. Una llamada que termina en error no cuesta nada.
¿Puede el modelo llamar a varias tools a la vez?
Algunos modelos devuelven más de una llamada en tool_calls. Ejecútalas todas y envía un mensaje tool por cada llamada antes de la siguiente petición.
¿La API ejecuta mis funciones?
No. El modelo solo indica qué función llamar y con qué argumentos; tu código la ejecuta. No se ejecuta nada por nuestra parte y no se almacena nada del intercambio: No guardamos tus prompts ni las respuestas del modelo: una vez enviada una respuesta, su texto desaparece. Cada llamada deja una línea de log con la hora, la cuenta, el modelo y el recuento de tokens, que se borra a los 30 días.