Esta guía te explicará cómo usar una de las nuevas y potentes características de Ollama: la capacidad de transmitir respuestas (streaming) y llamar a herramientas (como funciones o APIs) en tiempo real. Esto cambia las reglas del juego para construir aplicaciones de chat que se sientan vivas y puedan interactuar con el mundo que las rodea.
Lo que aprenderás en este tutorial:
- Qué significan la transmisión de respuestas (streaming) y la llamada a herramientas en Ollama.
- Por qué esta combinación es súper útil para tus proyectos de IA.
- Instrucciones paso a paso para implementar esto usando:
- cURL (para pruebas rápidas y acceso universal)
- Python (para aplicaciones backend)
- JavaScript (para aplicaciones web y Node.js)
- Un vistazo a cómo Ollama maneja estas características de forma inteligente.
- Consejos para obtener el mejor rendimiento.
¿Quieres una plataforma integrada y todo en uno para que tu Equipo de Desarrolladores trabaje con máxima productividad?
¡Apidog satisface todas tus demandas y reemplaza a Postman a un precio mucho más asequible!
Primeros Pasos: Lo Que Necesitarás
Para seguir esta guía, necesitarás algunas cosas:
- Ollama Instalado: Asegúrate de tener la última versión de Ollama ejecutándose en tu sistema. Si no, dirígete al sitio web oficial de Ollama para descargarlo e instalarlo.
- Conocimientos Básicos de Línea de Comandos: Para los ejemplos de cURL.
- Entorno Python (para la sección de Python): Python 3.x instalado, junto con
pip
para gestionar paquetes. - Entorno Node.js (para la sección de JavaScript): Node.js y
npm
instalados. - Comprensión de JSON: Ollama utiliza JSON para estructurar datos y llamadas a herramientas.
Comprendiendo Ideas Clave: Streaming y Llamadas a Herramientas
Desglosemos qué queremos decir con "transmisión de respuestas" (streaming) y "llamada a herramientas".
¿Qué es la Transmisión de Respuestas (Response Streaming)?
Imagina que estás chateando con una IA. En lugar de esperar a que piense y escriba su respuesta completa antes de que veas algo, el streaming significa que la IA te envía su respuesta pieza por pieza, palabra por palabra, a medida que la genera. Esto hace que la interacción se sienta mucho más rápida y natural, como una conversación real.
Con Ollama, cuando habilitas el streaming ("stream": true
), obtienes estas actualizaciones incrementales.
¿Cómo Funciona la Llamada a Herramientas?
La llamada a herramientas permite que tus modelos de IA hagan más que simplemente generar texto. Puedes definir "herramientas" – que son esencialmente funciones o APIs externas – que la IA puede decidir usar para obtener información o realizar acciones.
Por ejemplo, una herramienta podría ser:
get_current_weather(location)
: Obtiene el clima actual.calculate_sum(number1, number2)
: Realiza un cálculo.search_web(query)
: Obtiene información de internet.
Describes estas herramientas a Ollama, y cuando la IA determina que usar una herramienta ayudaría a responder la consulta del usuario, señala su intención de llamar a esa herramienta con argumentos específicos. Tu aplicación luego ejecuta la herramienta y puede enviar los resultados de vuelta a la IA para continuar la conversación.
¿Por Qué Combinar Streaming con Llamada a Herramientas?
La gran mejora de Ollama es que ahora puede manejar la llamada a herramientas mientras transmite respuestas. Esto significa que tu aplicación puede:
- Recibir texto inicial del modelo (transmitido).
- De repente, la transmisión puede indicar que se necesita una llamada a una herramienta.
- Tu aplicación procesa la llamada a la herramienta.
- Mientras tanto, el modelo incluso podría transmitir más texto (por ejemplo, "Okay, buscaré el clima para ti...").
- Una vez que tu aplicación obtiene el resultado de la herramienta, puedes enviarlo de vuelta al modelo, y este continuará transmitiendo su respuesta, ahora informada por la salida de la herramienta.
Esto crea aplicaciones de IA altamente responsivas y capaces.
¿Qué Modelos Soportan Estas Características?
Ollama ha habilitado esto para varios modelos populares, incluyendo:
- Qwen 3
- Devstral
- Qwen2.5 y Qwen2.5-coder
- Llama 3.1
- Llama 4
- ...¡y se siguen añadiendo más!
Cómo Hacer Tu Primera Llamada a Herramienta con Streaming Usando cURL
cURL es una excelente manera de probar rápidamente la API de Ollama. Pidamos el clima en Toronto.
Paso 1: Conceptualizando Tu Herramienta
Nuestra herramienta será get_current_weather
. Necesita:
location
(string): por ejemplo, "Toronto"format
(string): por ejemplo, "celsius" o "fahrenheit"
Paso 2: Construyendo el Comando cURL
Abre tu terminal y prepara el siguiente comando. Lo desglosaremos:
curl <http://localhost:11434/api/chat> -d '{
"model": "qwen3",
"messages": [
{
"role": "user",
"content": "What is the weather today in Toronto?"
}
],
"stream": true,
"tools": [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for, e.g. San Francisco, CA"
},
"format": {
"type": "string",
"description": "The format to return the weather in, e.g. \\\\\\\\'celsius\\\\\\\\' or \\\\\\\\'fahrenheit\\\\\\\\'",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location", "format"]
}
}
}
]
}'
Desglose:
curl <http://localhost:11434/api/chat
:> El comando y el endpoint de la API de chat de Ollama.d '{...}'
: Envía los datos JSON en el cuerpo de la solicitud."model": "qwen3"
: Especifica qué modelo de IA usar."messages": [...]
: El historial de conversación. Aquí, solo la pregunta del usuario."stream": true
: ¡Esto es clave! Le dice a Ollama que transmita la respuesta."tools": [...]
: Un array donde definimos las herramientas disponibles para el modelo."type": "function"
: Especifica el tipo de herramienta."function": {...}
: Describe la función."name": "get_current_weather"
: El nombre de la herramienta."description": "..."
: Ayuda al modelo a entender qué hace la herramienta."parameters": {...}
: Define los argumentos que acepta la herramienta (usando Esquema JSON).
Paso 3: Ejecuta y Observa la Salida
Presiona Enter. Verás una serie de objetos JSON aparecer uno tras otro. ¡Esto es la transmisión (stream)!
Fragmentos de ejemplo de la transmisión:
{
"model": "qwen3", "created_at": "...",
"message": { "role": "assistant", "content": "Okay, " }, "done": false
}
{
"model": "qwen3", "created_at": "...",
"message": { "role": "assistant", "content": "I will " }, "done": false
}
{
"model": "qwen3", "created_at": "...",
"message": { "role": "assistant", "content": "try to get that for you." }, "done": false
}
(El modelo podría generar algunos tokens de "pensamiento" como <think>...celsius...</think>
dependiendo de su proceso interno, estos también son parte de la transmisión)
Luego, de manera crucial, podrías ver algo como esto:
{
"model": "qwen3",
"created_at": "2025-05-27T22:54:58.100509Z",
"message": {
"role": "assistant",
"content": "", // El contenido puede estar vacío cuando se realiza una llamada a herramienta
"tool_calls": [
{
"function": {
"name": "get_current_weather",
"arguments": { // ¡Los argumentos que el modelo decidió!
"format": "celsius",
"location": "Toronto"
}
}
}
]
},
"done": false // Todavía no terminado, esperando el resultado de la herramienta
}
Qué Observar:
- Cada fragmento es un objeto JSON.
"done": false
significa que la transmisión está en curso. El fragmento final tendrá"done": true
.- El objeto
"message"
contiene: "role": "assistant"
"content"
: La parte de texto de la transmisión."tool_calls"
: Un array que aparece cuando el modelo quiere usar una herramienta. Incluye elname
de la herramienta y losarguments
que decidió usar.
En una aplicación real, cuando veas un fragmento tool_calls
, tu código debería:
- Pausar el procesamiento de la transmisión (o manejarlo de forma asíncrona).
- Ejecutar la función/API real
get_current_weather
con "Toronto" y "celsius". - Obtener el resultado (por ejemplo, "20 grados Celsius").
- Enviar este resultado de vuelta a Ollama en un nuevo mensaje con
role: "tool"
. - El modelo luego usará esta información para continuar generando su respuesta, también transmitida.
Cómo Transmitir Llamadas a Herramientas Usando Python
Implementemos una idea similar en Python usando la librería oficial de Ollama.
Paso 1: Instalando la Librería de Ollama para Python
Si aún no lo has hecho, instala o actualiza la librería:
pip install -U ollama
Paso 2: Definiendo Tu Herramienta y Codificando en Python
El SDK de Ollama para Python permite inteligentemente pasar funciones de Python directamente como herramientas. Inspecciona la firma de la función y el docstring para crear el esquema para la IA.
Creemos un ejemplo simple de herramienta matemática (la entrada usa add_two_numbers
pero el ejemplo de salida muestra subtract_two_numbers
siendo llamado por el modelo. Nos ceñiremos a add_two_numbers
proporcionado para la definición y dejaremos que el modelo decida qué hacer basándose en la instrucción.)
import ollama
# Define the python function that can be used as a tool
def add_two_numbers(a: int, b: int) -> int:
"""
Add two numbers.
Args:
a (int): The first number as an int.
b (int): The second number as an int.
Returns:
int: The sum of the two numbers.
"""
print(f"--- Tool 'add_two_numbers' called with a={a}, b={b} ---")
return a + b
# --- Main conversation logic ---
messages = [{'role': 'user', 'content': 'What is three plus one?'}]
# Or, for the subtraction example in the original output:
# messages = [{'role': 'user', 'content': 'what is three minus one?'}]
print(f"User: {messages[0]['content']}")
# Make the chat request with streaming and the tool
# Note: ChatResponse type hint might be ollama.ChatResponse or similar depending on library version
response_stream = ollama.chat(
model='qwen3', # Or another capable model
messages=messages,
tools=[
{ # You can also define the tool explicitly if needed, or pass the function directly
'type': 'function',
'function': {
'name': 'add_two_numbers', # Must match the Python function name if you want it to be called directly by your code later
'description': 'Add two integer numbers together.',
'parameters': {
'type': 'object',
'properties': {
'a': {'type': 'integer', 'description': 'The first number'},
'b': {'type': 'integer', 'description': 'The second number'}
},
'required': ['a', 'b']
}
}
}
# Simpler way for Python: pass the function directly if the library supports easy schema generation from it
# tools=[add_two_numbers] # The SDK can often create the schema from this
],
stream=True
)
print("Assistant (streaming):")
full_response_content = ""
tool_call_info = None
for chunk in response_stream:
# Print the streamed content part
if chunk['message']['content']:
print(chunk['message']['content'], end='', flush=True)
full_response_content += chunk['message']['content']
# Check for tool calls in the chunk
if 'tool_calls' in chunk['message'] and chunk['message']['tool_calls']:
tool_call_info = chunk['message']['tool_calls'][0] # Assuming one tool call for simplicity
print(f"\\\\n--- Detected Tool Call: {tool_call_info['function']['name']} ---")
break # Stop processing stream for now, handle tool call
if chunk.get('done'):
print("\\\\n--- Stream finished ---")
if not tool_call_info:
print("No tool call was made.")
# --- If a tool call was detected, handle it ---
if tool_call_info:
tool_name = tool_call_info['function']['name']
tool_args = tool_call_info['function']['arguments']
print(f"Arguments for the tool: {tool_args}")
# Here, you'd actually call your Python tool function
if tool_name == "add_two_numbers":
# For safety, ensure arguments are of correct type if necessary
try:
arg_a = int(tool_args.get('a'))
arg_b = int(tool_args.get('b'))
tool_result = add_two_numbers(a=arg_a, b=arg_b)
print(f"--- Tool execution result: {tool_result} ---")
# Now, send this result back to Ollama to continue the conversation
messages.append({'role': 'assistant', 'content': full_response_content, 'tool_calls': [tool_call_info]})
messages.append({
'role': 'tool',
'content': str(tool_result), # Result must be a string
'tool_call_id': tool_call_info.get('id', '') # If your library/model provides a tool_call_id
})
print("\\\\n--- Sending tool result back to model ---")
follow_up_response_stream = ollama.chat(
model='qwen3',
messages=messages,
stream=True
# No tools needed here unless you expect another tool call
)
print("Assistant (after tool call):")
for follow_up_chunk in follow_up_response_stream:
if follow_up_chunk['message']['content']:
print(follow_up_chunk['message']['content'], end='', flush=True)
if follow_up_chunk.get('done'):
print("\\\\n--- Follow-up stream finished ---")
break
except ValueError:
print("Error: Could not parse tool arguments as integers.")
except Exception as e:
print(f"An error occurred during tool execution or follow-up: {e}")
else:
print(f"Error: Unknown tool '{tool_name}' requested by the model.")
Explicación del Código Python:
- Importa
ollama
. - Función
add_two_numbers
: Esta es nuestra herramienta. El docstring y las sugerencias de tipo (type hints) ayudan a Ollama a entender su propósito y parámetros. messages
: Iniciamos la conversación con la consulta del usuario.ollama.chat(...)
:
model
,messages
,stream=True
son similares a cURL.tools=[...]
: Proporcionamos la definición de la herramienta. El SDK de Python es bastante flexible; puedes pasar el objeto de la función directamente (por ejemplo,tools=[add_two_numbers]
) si puede inferir el esquema, o definirlo explícitamente como se muestra.
- Iterando a través de
response_stream
:
chunk['message']['content']
: Este es el texto transmitido. Lo imprimimos inmediatamente.chunk['message']['tool_calls']
: Si esta clave existe y tiene contenido, la IA quiere usar una herramienta. Almacenamos estatool_call_info
y rompemos el bucle para manejarla.
- Manejo de la Llamada a la Herramienta: Similar a Python, si
tool_call_info
está establecido:
- Extraemos el
tool_name
y lostool_args
. - Llamamos a nuestra función de Python real (
add_two_numbers
) con estos argumentos. - Crucialmente: Luego añadimos la respuesta parcial del asistente (que llevó a la llamada a la herramienta) y un nuevo mensaje con
role: "tool"
y elcontent
como el resultado de nuestra función convertido a string a la listamessages
. - Hacemos otra llamada a
ollama.chat
con estos mensajes actualizados para obtener la respuesta final de la IA basada en la salida de la herramienta.
Flujo de Salida Esperado:Verás la pregunta inicial del usuario, luego la respuesta del asistente transmitiéndose. Si decide llamar a add_two_numbers
(o a subtract_two_numbers
como en la salida de ejemplo del material original si la instrucción fue para una resta), verás el mensaje "Detected Tool Call", los argumentos, el resultado de tu función Python, y luego el asistente continuando su respuesta usando ese resultado.
(La salida de ejemplo original mostraba:
<think>
Okay, the user is asking ...
</think>
[ToolCall(function=Function(name='subtract_two_numbers', arguments={'a': 3, 'b': 1}))]
Esto indica el proceso de "pensamiento" interno de la IA y luego el objeto de llamada a herramienta estructurado que proporciona el SDK de Python.)
Cómo Transmitir Llamadas a Herramientas Usando JavaScript (Node.js)
Ahora, hagamos lo mismo con JavaScript, típicamente para un backend Node.js o una aplicación web.
Paso 1: Instalando la Librería de Ollama para JavaScript
En el directorio de tu proyecto, ejecuta:
npm i ollama
Paso 2: Definiendo el Esquema de la Herramienta y Codificando en JavaScript
En JavaScript, usualmente defines el esquema de la herramienta como un objeto JSON.
import ollama from 'ollama';
// Describe the tool schema (e.g., for adding two numbers)
const addTool = {
type: 'function',
function: {
name: 'addTwoNumbers',
description: 'Add two numbers together',
parameters: {
type: 'object',
required: ['a', 'b'],
properties: {
a: { type: 'number', description: 'The first number' },
b: { type: 'number', description: 'The second number' }
}
}
}
};
// Your actual JavaScript function that implements the tool
function executeAddTwoNumbers(a, b) {
console.log(`--- Tool 'addTwoNumbers' called with a=${a}, b=${b} ---`);
return a + b;
}
async function main() {
const messages = [{ role: 'user', content: 'What is 2 plus 3?' }];
console.log('User:', messages[0].content);
console.log('Assistant (streaming):');
let assistantResponseContent = "";
let toolToCallInfo = null;
try {
const responseStream = await ollama.chat({
model: 'qwen3', // Or another capable model
messages: messages,
tools: [addTool],
stream: true
});
for await (const chunk of responseStream) {
if (chunk.message.content) {
process.stdout.write(chunk.message.content);
assistantResponseContent += chunk.message.content;
}
if (chunk.message.tool_calls && chunk.message.tool_calls.length > 0) {
toolToCallInfo = chunk.message.tool_calls[0]; // Assuming one tool call
process.stdout.write(`\\\\n--- Detected Tool Call: ${toolToCallInfo.function.name} ---\\\\n`);
break; // Stop processing stream to handle tool call
}
if (chunk.done) {
process.stdout.write('\\\\n--- Stream finished ---\\\\n');
if (!toolToCallInfo) {
console.log("No tool call was made.");
}
break;
}
}
// --- If a tool call was detected, handle it ---
if (toolToCallInfo) {
const toolName = toolToCallInfo.function.name;
const toolArgs = toolToCallInfo.function.arguments;
console.log(`Arguments for the tool:`, toolArgs);
let toolResult;
if (toolName === 'addTwoNumbers') {
toolResult = executeAddTwoNumbers(toolArgs.a, toolArgs.b);
console.log(`--- Tool execution result: ${toolResult} ---`);
// Append assistant's partial message and the tool message
messages.push({
role: 'assistant',
content: assistantResponseContent, // Include content leading up to tool call
tool_calls: [toolToCallInfo]
});
messages.push({
role: 'tool',
content: toolResult.toString(), // Result must be a string
// tool_call_id: toolToCallInfo.id // If available and needed
});
console.log("\\\\n--- Sending tool result back to model ---");
const followUpStream = await ollama.chat({
model: 'qwen3',
messages: messages,
stream: true
});
console.log("Assistant (after tool call):");
for await (const followUpChunk of followUpStream) {
if (followUpChunk.message.content) {
process.stdout.write(followUpChunk.message.content);
}
if (followUpChunk.done) {
process.stdout.write('\\\\n--- Follow-up stream finished ---\\\\n');
break;
}
}
} else {
console.error(`Error: Unknown tool '${toolName}' requested.`);
}
}
} catch (error) {
console.error('Error during Ollama chat:', error);
}
}
main().catch(console.error);
Explicación del Código JavaScript:
- Importa
ollama
. - Objeto
addTool
: Este es el esquema JSON que describe nuestra herramienta a Ollama. - Función
executeAddTwoNumbers
: Nuestra función de JavaScript real para la herramienta. - Función asíncrona
main
:
- El array
messages
inicia la conversación. await ollama.chat({...})
: Realiza la llamada.tools: [addTool]
: Pasa nuestro esquema de herramienta.stream: true
: Habilita el streaming.for await (const chunk of responseStream)
: Este bucle procesa cada fragmento transmitido.chunk.message.content
: Parte de texto de la transmisión.chunk.message.tool_calls
: Si está presente, la IA quiere usar una herramienta. AlmacenamostoolToCallInfo
.
- Manejo de la Llamada a la Herramienta: Similar a Python, si
toolToCallInfo
está establecido:
- Extrae el nombre y los argumentos.
- Llama a
executeAddTwoNumbers()
. - Añade el mensaje del asistente (que incluía la solicitud de llamada a la herramienta) y un nuevo mensaje con
role: "tool"
y el resultado al arraymessages
. - Haz otra llamada a
ollama.chat
con los mensajes actualizados para obtener la respuesta final.
Flujo de Salida Esperado (similar a los ejemplos de cURL y Python):Verás la pregunta del usuario, luego la respuesta del asistente transmitiéndose. Cuando decida llamar a addTwoNumbers
, imprimirá la información de la llamada a la herramienta, el resultado de tu función JavaScript, y luego continuará transmitiendo la respuesta de la IA basándose en ese resultado.
La salida de ejemplo original para JS se veía así:
Question: What is 2 plus 3?
<think>
Okay, the user is asking...
</think>
Tool call: {
function: {
name: "addTwoNumbers",
arguments: { a: 2, b: 3 },
},
}
Cómo Ollama Maneja el Análisis de Herramientas Durante el Streaming
Quizás te preguntes cómo Ollama logra transmitir texto e identificar llamadas a herramientas de manera tan fluida. Utiliza un nuevo y astuto analizador incremental.
- Antigua Forma: Muchos sistemas tenían que esperar la respuesta completa de la IA, luego escanearla en busca de llamadas a herramientas (usualmente formateadas como JSON). Esto bloqueaba el streaming porque una llamada a herramienta podía aparecer en cualquier lugar.
- La Nueva Forma de Ollama:
- El analizador examina la plantilla específica de cada modelo para entender cómo señala una llamada a herramienta (por ejemplo, tokens especiales o prefijos).
- Esto permite a Ollama identificar las llamadas a herramientas "incrementalmente" a medida que los datos se transmiten, separándolas del contenido de texto regular.
- Es lo suficientemente inteligente como para manejar modelos que no fueron entrenados explícitamente con prefijos de herramientas pero que aún así logran generar estructuras de llamadas a herramientas válidas. Incluso puede recurrir a buscar estructuras similares a JSON si es necesario, pero de forma inteligente, para no simplemente tomar cualquier JSON.
¿Por qué es mejor esto?
- Streaming Verdadero: Obtienes texto inmediatamente, y las llamadas a herramientas se identifican sobre la marcha.
- Precisión: Es mejor evitando falsos positivos (por ejemplo, si la IA habla sobre una llamada a herramienta que hizo previamente, es menos probable que el nuevo analizador la active erróneamente de nuevo).
Consejo: Mejorando el Rendimiento con la Ventana de Contexto
Para interacciones más complejas, especialmente con la llamada a herramientas, el tamaño de la "ventana de contexto" que usa el modelo puede importar. Una ventana de contexto más grande significa que el modelo recuerda más de la conversación actual.
- Protocolo de Contexto del Modelo (MCP): Las mejoras de Ollama funcionan bien con MCP.
num_ctx
: A menudo puedes sugerir un tamaño para la ventana de contexto. Por ejemplo, 32,000 (32k
) tokens o más podría mejorar el rendimiento de la llamada a herramientas y la calidad de los resultados.- Compromiso: Ventanas de contexto más grandes usan más memoria.
Ejemplo: Estableciendo la Ventana de Contexto con cURL(Usa un modelo que soporte contextos más grandes, como llama3.1
o llama4
como se sugiere en el material original - aunque el ejemplo usa llama3.2
)
curl -X POST "<http://localhost:11434/api/chat>" -d '{
"model": "llama3.1",
"messages": [
{
"role": "user",
"content": "why is the sky blue?"
}
],
"options": {
"num_ctx": 32000
}
}'
Experimenta con esta configuración si encuentras que la llamada a herramientas no es tan fiable como te gustaría.
¿Hacia Dónde Ir Desde Aquí?
¡Ahora tienes los fundamentos para construir aplicaciones de IA sofisticadas y en tiempo real con Ollama usando transmisión de respuestas y llamada a herramientas!
Ideas para explorar:
- Conectar herramientas a APIs del mundo real (clima, acciones, motores de búsqueda).
- Construir agentes que puedan realizar tareas de varios pasos.
- Crear chatbots más naturales y responsivos.
Consulta la documentación oficial de Ollama y su repositorio en GitHub (incluyendo la "Solicitud de Extracción de Streaming de Herramientas" mencionada en el material fuente original para inmersiones técnicas más profundas) para las últimas actualizaciones y ejemplos más avanzados.
¿Quieres una plataforma integrada y todo en uno para que tu Equipo de Desarrolladores trabaje con máxima productividad?
¡Apidog satisface todas tus demandas y reemplaza a Postman a un precio mucho más asequible!