Este guia irá levá-lo através de como usar uma das novas e poderosas funcionalidades do Ollama: a capacidade de transmitir respostas (streaming) e chamar ferramentas (como funções ou APIs) em tempo real. Isso muda o jogo para construir aplicações de chat que parecem vivas e podem interagir com o mundo ao seu redor.
O que você aprenderá neste tutorial:
- O que significam respostas por streaming e chamada de ferramentas no Ollama.
- Por que essa combinação é super útil para seus projetos de IA.
- Instruções passo a passo para implementar isso usando:
- cURL (para testes rápidos e acesso universal)
- Python (para aplicações backend)
- JavaScript (para aplicações web e Node.js)
- Uma olhada em como o Ollama lida inteligentemente com essas funcionalidades.
- Dicas para obter o melhor desempenho.
Quer uma plataforma integrada e completa para sua equipe de desenvolvedores trabalhar em conjunto com máxima produtividade?
Apidog entrega todas as suas demandas e substitui o Postman por um preço muito mais acessível!
Primeiros Passos: O Que Você Vai Precisar
Para acompanhar, você precisará de algumas coisas:
- Ollama Instalado: Certifique-se de ter a versão mais recente do Ollama rodando no seu sistema. Se não, vá para o site oficial do Ollama para baixar e instalar.
- Conhecimento Básico de Linha de Comando: Para os exemplos de cURL.
- Ambiente Python (para a seção Python): Python 3.x instalado, juntamente com
pip
para gerenciar pacotes. - Ambiente Node.js (para a seção JavaScript): Node.js e
npm
instalados. - Compreensão de JSON: Ollama usa JSON para estruturar dados e chamadas de ferramentas.
Compreendendo Ideias Chave: Streaming e Chamadas de Ferramentas
Vamos detalhar o que queremos dizer com "streaming de respostas" e "chamada de ferramentas".
O Que É Streaming de Respostas?
Imagine que você está conversando com uma IA. Em vez de esperar que ela pense e digite a resposta inteira antes de você ver qualquer coisa, streaming significa que a IA envia a resposta para você pedaço por pedaço, palavra por palavra, conforme a gera. Isso torna a interação muito mais rápida e natural, como uma conversa real.
Com o Ollama, quando você habilita o streaming ("stream": true
), você recebe essas atualizações incrementais.
Como Funciona a Chamada de Ferramentas?
A chamada de ferramentas permite que seus modelos de IA façam mais do que apenas gerar texto. Você pode definir "ferramentas" – que são essencialmente funções ou APIs externas – que a IA pode decidir usar para obter informações ou realizar ações.
Por exemplo, uma ferramenta poderia ser:
get_current_weather(location)
: Busca o clima atual.calculate_sum(number1, number2)
: Realiza um cálculo.search_web(query)
: Obtém informações da internet.
Você descreve essas ferramentas para o Ollama, e quando a IA determina que usar uma ferramenta ajudaria a responder à consulta do usuário, ela sinaliza sua intenção de chamar essa ferramenta com argumentos específicos. Sua aplicação então executa a ferramenta e pode enviar os resultados de volta para a IA para continuar a conversa.
Por Que Combinar Streaming com Chamada de Ferramentas?
A grande atualização do Ollama é que ele agora pode lidar com a chamada de ferramentas enquanto transmite respostas. Isso significa que sua aplicação pode:
- Receber texto inicial do modelo (transmitido).
- De repente, o stream pode indicar que uma chamada de ferramenta é necessária.
- Sua aplicação processa a chamada de ferramenta.
- Enquanto isso, o modelo pode até transmitir mais texto (por exemplo, "Ok, vou buscar o clima para você...").
- Assim que sua aplicação obtém o resultado da ferramenta, você pode enviá-lo de volta para o modelo, e ele continuará transmitindo sua resposta, agora informada pela saída da ferramenta.
Isso cria aplicações de IA altamente responsivas e capazes.
Quais Modelos Suportam Essas Funcionalidades?
Ollama habilitou isso para vários modelos populares, incluindo:
- Qwen 3
- Devstral
- Qwen2.5 e Qwen2.5-coder
- Llama 3.1
- Llama 4
- ...e mais estão sendo continuamente adicionados!
Como Fazer Sua Primeira Chamada de Ferramenta com Streaming Usando cURL
cURL é uma ótima maneira de testar rapidamente a API do Ollama. Vamos pedir o clima em Toronto.
Passo 1: Conceituando Sua Ferramenta
Nossa ferramenta será get_current_weather
. Ela precisa de:
location
(string): por exemplo, "Toronto"format
(string): por exemplo, "celsius" ou "fahrenheit"
Passo 2: Construindo o Comando cURL
Abra seu terminal e prepare o seguinte comando. Vamos detalhá-lo:
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"]
}
}
}
]
}'
Detalhes:
curl <http://localhost:11434/api/chat
:> O comando e o endpoint da API de chat do Ollama.d '{...}'
: Envia os dados JSON no corpo da requisição."model": "qwen3"
: Especifica qual modelo de IA usar."messages": [...]
: O histórico da conversa. Aqui, apenas a pergunta do usuário."stream": true
: Isso é chave! Diz ao Ollama para transmitir a resposta."tools": [...]
: Um array onde definimos as ferramentas disponíveis para o modelo."type": "function"
: Especifica o tipo de ferramenta."function": {...}
: Descreve a função."name": "get_current_weather"
: O nome da ferramenta."description": "..."
: Ajuda o modelo a entender o que a ferramenta faz."parameters": {...}
: Define os argumentos que a ferramenta aceita (usando JSON Schema).
Passo 3: Executar e Observar a Saída
Pressione Enter. Você verá uma série de objetos JSON aparecerem um após o outro. Este é o stream!
Exemplos de trechos do stream:
{
"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
}
(O modelo pode gerar alguns tokens de "pensamento" como <think>...celsius...</think>
dependendo do seu processo interno, estes também fazem parte do stream)
Então, crucialmente, você pode ver algo assim:
{
"model": "qwen3",
"created_at": "2025-05-27T22:54:58.100509Z",
"message": {
"role": "assistant",
"content": "", // O conteúdo pode estar vazio quando uma chamada de ferramenta é feita
"tool_calls": [
{
"function": {
"name": "get_current_weather",
"arguments": { // Os argumentos que o modelo decidiu!
"format": "celsius",
"location": "Toronto"
}
}
}
]
},
"done": false // Ainda não terminou, aguardando resultado da ferramenta
}
O Que Observar:
- Cada chunk é um objeto JSON.
"done": false
significa que o stream está em andamento. O chunk final terá"done": true
.- O objeto
"message"
contém: "role": "assistant"
"content"
: A parte de texto do stream."tool_calls"
: Um array que aparece quando o modelo quer usar uma ferramenta. Inclui oname
da ferramenta e osarguments
que ela decidiu.
Em uma aplicação real, quando você vê um chunk tool_calls
, seu código faria o seguinte:
- Pausar o processamento do stream (ou lidar com ele de forma assíncrona).
- Executar a função/API
get_current_weather
real com "Toronto" e "celsius". - Obter o resultado (por exemplo, "20 graus Celsius").
- Enviar este resultado de volta para o Ollama em uma nova mensagem com
role: "tool"
. - O modelo então usará esta informação para continuar gerando sua resposta, também transmitida.
Como Transmitir Chamadas de Ferramentas Usando Python
Vamos implementar uma ideia similar em Python usando a biblioteca oficial do Ollama.
Passo 1: Instalando a Biblioteca Python do Ollama
Se você ainda não o fez, instale ou atualize a biblioteca:
pip install -U ollama
Passo 2: Definindo Sua Ferramenta e Codificando em Python
O SDK Python do Ollama permite inteligentemente que você passe funções Python diretamente como ferramentas. Ele inspeciona a assinatura da função e a docstring para criar o esquema para a IA.
Vamos criar um exemplo simples de ferramenta de matemática (a entrada usa add_two_numbers
, mas o exemplo de saída mostra subtract_two_numbers
sendo chamado pelo modelo. Manteremos o add_two_numbers
fornecido para definição e deixaremos o modelo decidir o que fazer com base no prompt).
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.")
Explicação do Código Python:
- Importa
ollama
. - Função
add_two_numbers
: Esta é nossa ferramenta. A docstring e as type hints ajudam o Ollama a entender seu propósito e parâmetros. messages
: Começamos a conversa com a consulta do usuário.ollama.chat(...)
:
model
,messages
,stream=True
são similares ao cURL.tools=[...]
: Fornecemos a definição da ferramenta. O SDK Python é bastante flexível; você pode passar o objeto da função diretamente (por exemplo,tools=[add_two_numbers]
) se ele puder inferir o esquema, ou defini-lo explicitamente como mostrado.
- Iterando sobre
response_stream
:
chunk['message']['content']
: Esta é a parte de texto transmitida. Imprimimos imediatamente.chunk['message']['tool_calls']
: Se esta chave existir e tiver conteúdo, a IA quer usar uma ferramenta. Armazenamos estetool_call_info
e interrompemos o loop para lidar com ele.
- Lidando com a Chamada de Ferramenta:
- Extraímos o
tool_name
e ostool_args
. - Chamamos nossa função Python real (
add_two_numbers
) com esses argumentos. - Crucialmente: Em seguida, adicionamos a resposta parcial do assistente (que levou à chamada da ferramenta) e uma nova mensagem com
role: "tool"
e ocontent
como o resultado da nossa função convertido para string na listamessages
. - Fazemos outra chamada
ollama.chat
com essas mensagens atualizadas para obter a resposta final da IA com base na saída da ferramenta.
Fluxo de Saída Esperado:Você verá a pergunta inicial do usuário, então a resposta do assistente sendo transmitida. Se ele decidir chamar add_two_numbers
(ou subtract_two_numbers
como no exemplo de saída do material original, se o prompt fosse para subtração), você verá a mensagem "Detected Tool Call", os argumentos, o resultado da sua função Python, e então o assistente continuando sua resposta usando esse resultado.
(A saída de exemplo original mostrava:
<think>
Okay, the user is asking ...
</think>
[ToolCall(function=Function(name='subtract_two_numbers', arguments={'a': 3, 'b': 1}))]
Isso indica o processo de "pensamento" interno da IA e então o objeto de chamada de ferramenta estruturado que o SDK Python fornece.)
Como Transmitir Chamadas de Ferramentas Usando JavaScript (Node.js)
Agora, vamos fazer o mesmo com JavaScript, tipicamente para um backend Node.js ou aplicação web.
Passo 1: Instalando a Biblioteca JavaScript do Ollama
No diretório do seu projeto, execute:
npm i ollama
Passo 2: Definindo o Esquema da Ferramenta e Codificando em JavaScript
Em JavaScript, você geralmente define o esquema da ferramenta como um 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);
Explicação do Código JavaScript:
- Importa
ollama
. - Objeto
addTool
: Este é o esquema JSON que descreve nossa ferramenta para o Ollama. - Função
executeAddTwoNumbers
: Nossa função JavaScript real que implementa a ferramenta. - Função assíncrona
main
:
- O array
messages
inicia a conversa. await ollama.chat({...})
: Faz a chamada.tools: [addTool]
: Passa nosso esquema de ferramenta.stream: true
: Habilita o streaming.for await (const chunk of responseStream)
: Este loop processa cada chunk transmitido.chunk.message.content
: Parte de texto do stream.chunk.message.tool_calls
: Se presente, a IA quer usar uma ferramenta. ArmazenamostoolToCallInfo
.
- Lidando com a Chamada de Ferramenta: Similar ao Python, se
toolToCallInfo
estiver definido:
- Extrai nome e argumentos.
- Chama
executeAddTwoNumbers()
. - Adiciona a mensagem do assistente (que incluiu a requisição de chamada da ferramenta) e uma nova mensagem com
role: "tool"
e o resultado ao arraymessages
. - Faz outra chamada
ollama.chat
com as mensagens atualizadas para obter a resposta final.
Fluxo de Saída Esperado (similar aos exemplos de cURL e Python):Você verá a pergunta do usuário, então a resposta do assistente sendo transmitida. Quando ele decidir chamar addTwoNumbers
, ele imprimirá as informações da chamada da ferramenta, o resultado da sua função JavaScript, e então continuará transmitindo a resposta da IA com base nesse resultado.
A saída de exemplo original para JS parecia com:
Question: What is 2 plus 3?
<think>
Okay, the user is asking...
</think>
Tool call: {
function: {
name: "addTwoNumbers",
arguments: { a: 2, b: 3 },
},
}
Como Ollama Lida com a Análise de Ferramentas Durante o Streaming
Você pode se perguntar como o Ollama consegue transmitir texto e identificar chamadas de ferramentas de forma tão suave. Ele usa um novo e inteligente parser incremental.
- Forma Antiga: Muitos sistemas tinham que esperar pela resposta inteira da IA, então escanear por chamadas de ferramentas (geralmente formatadas como JSON). Isso bloqueava o streaming porque uma chamada de ferramenta poderia aparecer em qualquer lugar.
- Nova Forma do Ollama:
- O parser olha para o template específico de cada modelo para entender como ele sinaliza uma chamada de ferramenta (por exemplo, tokens especiais ou prefixos).
- Isso permite que o Ollama identifique chamadas de ferramentas "incrementalmente" conforme os dados chegam no stream, separando-as do conteúdo de texto regular.
- Ele é inteligente o suficiente para lidar com modelos que não foram explicitamente treinados com prefixos de ferramentas, mas ainda assim conseguem gerar estruturas de chamada de ferramenta válidas. Ele pode até recorrer à busca por estruturas semelhantes a JSON, se necessário, mas de forma inteligente, para não pegar qualquer JSON.
Por Que Isso É Melhor?
- Streaming Verdadeiro: Você obtém texto imediatamente, e as chamadas de ferramentas são identificadas em tempo real.
- Precisão: É melhor em evitar falsos positivos (por exemplo, se a IA fala sobre uma chamada de ferramenta que fez anteriormente, o novo parser tem menos probabilidade de acioná-la novamente por engano).
Dica: Melhorando o Desempenho com a Janela de Contexto
Para interações mais complexas, especialmente com chamada de ferramentas, o tamanho da "janela de contexto" que o modelo usa pode ser importante. Uma janela de contexto maior significa que o modelo lembra mais da conversa atual.
- Model Context Protocol (MCP): As melhorias do Ollama funcionam bem com MCP.
num_ctx
: Você pode frequentemente sugerir um tamanho para a janela de contexto. Por exemplo, 32.000 (32k
) tokens ou mais podem melhorar o desempenho da chamada de ferramentas e a qualidade dos resultados.- Trade-off: Janelas de contexto maiores usam mais memória.
Exemplo: Definindo a Janela de Contexto com cURL(Use um modelo que suporte contextos maiores, como llama3.1
ou llama4
, como sugerido no material original - embora o exemplo use 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
}
}'
Experimente esta configuração se você achar que a chamada de ferramentas não é tão confiável quanto gostaria.
Para Onde Ir a Partir Daqui?
Você agora tem os fundamentos para construir aplicações de IA sofisticadas e em tempo real com o Ollama usando streaming de respostas e chamada de ferramentas!
Ideias para explorar:
- Conecte ferramentas a APIs do mundo real (clima, ações, motores de busca).
- Construa agentes que podem realizar tarefas em várias etapas.
- Crie chatbots mais naturais e responsivos.
Consulte a documentação oficial do Ollama e seu repositório GitHub (incluindo o "Tool Streaming Pull Request" mencionado na fonte original para mergulhos técnicos mais profundos) para as últimas atualizações e exemplos mais avançados.
Quer uma plataforma integrada e completa para sua equipe de desenvolvedores trabalhar em conjunto com máxima produtividade?
Apidog entrega todas as suas demandas e substitui o Postman por um preço muito mais acessível!