Avançado 13 minAPI

Chamadas de função e saídas em JSON estruturadas com Ollama

O function calling permite que um LLM decida por si mesmo chamar uma função do seu código — buscar a previsão do tempo, consultar uma base de dados, enviar um e-mail — retornando os argumentos no formato correto. O function calling no Ollama se baseia em dois componentes: o parâmetro format para garantir um JSON válido e o campo tools da API para declarar as funções disponíveis. Este guia mostra os dois em Python, quais modelos locais são realmente confiáveis e como tornar o conjunto mais robusto com validação de esquema e novas tentativas.

Por Mohamed Meguedmi·Atualização 2026-08-27·Testado no Windows, macOS e Linux

#Por que usar chamadas de função em execução local

Um LLM gera texto, não ações. O function calling preenche essa lacuna: em vez de responder em prosa, o modelo retorna um objeto estruturado que diz 'chame a função get_meteo com a cidade Paris'. Seu código executa a função, recupera o resultado real e depois passa para o modelo, que redige a resposta final. Esse é o mecanismo básico dos agentes e assistentes que interagem com o mundo externo.

Na execução local, o desafio é duplo. Primeiro, garantir que a saída seja um JSON 100% parseável — um modelo falador que acrescenta “Aqui está o JSON:” quebra todo o seu pipeline. Em seguida, garantir que o modelo escolha a função correta com os argumentos certos, o que se torna delicado com modelos pequenos. O Ollama lida com os dois aspectos por meio de sua API, mas há mecanismos de proteção que você precisa conhecer.

Saídas JSON garantidas
O parâmetro format restringe a decodificação: o modelo só pode produzir um JSON sintaticamente válido, podendo até seguir um esquema específico.
Chamada de função
O campo tools declara funções no formato OpenAI; o modelo retorna tool_calls com os argumentos a serem passados.
100 % local
Tudo roda na sua máquina via o daemon Ollama em http://localhost:11434, sem chave API nem vazamento de dados.

#Pré-requisitos e modelos compatíveis

O kit Copiloto Local

Este guia leva você ao modelo. O kit leva você ao copiloto que programa no seu editor.

  • Espaço online vitalício
  • PDF + arquivos
  • Atualizações vitalícias

O modo JSON (parâmetro format) funciona com qualquer modelo. A chamada de funções via tools, por sua vez, exige um modelo treinado para usar ferramentas — caso contrário, o campo tool_calls permanece vazio. Nem todos os modelos têm o mesmo desempenho: um 3B “compatível” no papel costuma errar os argumentos, enquanto um 14B+ funciona bem com esquemas simples.

Ollama instalado
Daemon iniciado e acessível em http://localhost:11434. Verifique com o comando ollama list.
SDK Python
pip install ollama pydantic — le client officiel plus Pydantic pour la validation.
Modelo confiável para uso de ferramentas
qwen3.5:9b, mistral-small (24B) e gpt-oss:20b são excelentes pontos de partida em 2026. Em Q4: Qwen 3.5 9B ≈ 6,6 GB, um 24B ≈ 14 GB de VRAM.
GPU recomendada
Uma RTX 3060 de 12 GB roda Qwen 3.5 9B com conforto; busque um modelo de 20-24B (RTX 4070/4080 de 16 GB) para uso de ferramentas realmente confiável.
i
Modo JSON ≠ chamada de função
O parâmetro format garante um JSON válido, mas não faz com que uma função seja chamada: o modelo preenche um objeto que VOCÊ interpreta. Já o campo tools aciona uma seleção real de função pelo modelo. É comum combinar os dois.

#Forçar um JSON válido com o parâmetro format

O caso mais simples: você quer que o modelo responda sempre em JSON, nunca em texto livre. Passe format: 'json' na chamada chat. O Ollama então restringe a decodificação token a token para produzir um objeto sintaticamente válido. Importante: mantenha uma instrução explícita no prompt descrevendo os campos esperados, caso contrário o modelo inventa uma estrutura.

json_mode.py
import ollama
import json

resp = ollama.chat(
    model='qwen3.5:9b',
    messages=[{
        'role': 'user',
        'content': (
            "Extrais le nom, la ville et l'age de ce texte et reponds "
            "UNIQUEMENT en JSON avec les cles nom, ville, age. "
            "Texte : Marie, 34 ans, habite a Lyon."
        ),
    }],
    format='json',  # contraint la sortie a un JSON valide
    options={'temperature': 0},
)

data = json.loads(resp['message']['content'])
print(data)  # {'nom': 'Marie', 'ville': 'Lyon', 'age': 34}
→
Sempre temperature 0
Para extração estruturada, defina temperature como 0. Você quer determinismo e conformidade, não criatividade. Isso reduz significativamente as alucinações nos campos.

#JSON estruturado por esquema (saídas estruturadas)

Desde o fim de 2024, o Ollama também aceita um esquema JSON completo em format (não apenas a string 'json'). A decodificação passa então a ser obrigada a respeitar o esquema: tipos, campos obrigatórios e enumerações. Isso é muito mais robusto do que usar apenas 'json', pois o modelo fica estruturalmente impedido de produzir um objeto que não esteja em conformidade com o esquema. Com Pydantic, o esquema é gerado automaticamente.

structured_output.py
import ollama
from pydantic import BaseModel

class Personne(BaseModel):
    nom: str
    ville: str
    age: int

resp = ollama.chat(
    model='mistral-small',
    messages=[{'role': 'user',
               'content': 'Marie, 34 ans, habite a Lyon.'}],
    format=Personne.model_json_schema(),  # schema JSON complet
    options={'temperature': 0},
)

# validation stricte : leve une erreur si non conforme
personne = Personne.model_validate_json(resp['message']['content'])
print(personne)  # nom='Marie' ville='Lyon' age=34

Aqui, a decodificação fica restrita à estrutura de Personne, e model_validate_json realiza uma nova etapa de validação no Python. Dupla camada de segurança: a saída tem garantia de poder ser analisada por um parser E de estar em conformidade com os tipos declarados. Esse é o padrão recomendado para qualquer extração de dados em produção local.

#API de ferramentas passo a passo em Python

Vamos ao verdadeiro function calling. Declaramos as funções no campo tools no formato OpenAI (name, description, parameters em JSON Schema). O modelo lê essas definições e, se considerar útil chamar uma função, retorna um ou mais tool_calls em vez de uma mensagem de texto. Cabe a você executar a função e devolver o resultado.

  1. 01
    Descrever as funções
    Para cada função, forneça um name claro, uma description precisa (o modelo a usa para escolher) e um parameters em JSON Schema que liste os argumentos e indique quais são required.
  2. 02
    Enviar a chamada com tools
    Passe a lista tools para ollama.chat. O modelo decide sozinho se chama uma função ou responde diretamente.
  3. 03
    Ler as tool_calls
    Verifique resp['message'].get('tool_calls'). Se estiver presente, o modelo deseja chamar uma função com os argumentos fornecidos.
  4. 04
    Executar e enviar de volta
    Chame a função Python real e depois passe seu resultado de volta ao modelo em uma mensagem com role 'tool', para que ele redija a resposta final.
tools_definition.py
def get_meteo(ville: str) -> str:
    # ici un vrai appel API ; on simule
    return f"Il fait 22 C et ensoleille a {ville}."

tools = [{
    'type': 'function',
    'function': {
        'name': 'get_meteo',
        'description': "Renvoie la meteo actuelle d'une ville donnee.",
        'parameters': {
            'type': 'object',
            'properties': {
                'ville': {
                    'type': 'string',
                    'description': 'Nom de la ville, ex: Paris',
                },
            },
            'required': ['ville'],
        },
    },
}]

#O ciclo chamada → execução → resposta

O function calling é um ciclo de ida e volta. Primeira chamada: o modelo retorna um tool_call. Você executa a função. Segunda chamada: você envia de volta o resultado, e o modelo redige a resposta em linguagem natural. Aqui está o ciclo completo, reutilizável para várias funções.

boucle_tools.py
import ollama

dispatch = {'get_meteo': get_meteo}

messages = [{'role': 'user',
             'content': 'Quel temps fait-il a Marseille ?'}]

resp = ollama.chat(model='mistral-small',
                   messages=messages, tools=tools)
msg = resp['message']
messages.append(msg)

for call in msg.get('tool_calls') or []:
    fn = call['function']['name']
    args = call['function']['arguments']
    resultat = dispatch[fn](**args)  # execution reelle
    messages.append({
        'role': 'tool',
        'name': fn,
        'content': resultat,
    })

# second appel : le modele redige la reponse finale
final = ollama.chat(model='mistral-small', messages=messages)
print(final['message']['content'])
!
Nunca execute os argumentos às cegas
O modelo controla o nome da função e seus argumentos. Use um dicionário de dispatch (lista branca) em vez de eval ou getattr dinâmico e valide cada argumento antes da execução. Um modelo comprometido ou que apresente alucinações não deve ser capaz de chamar qualquer coisa.

#Validação de esquema e padrões de retry

Ao rodar localmente, os modelos pequenos às vezes falham: argumentos ausentes, tipo incorreto, função inexistente. Nunca confie na saída bruta. Valide cada tool_call com Pydantic e, se a validação falhar, tente novamente com a mensagem de erro no contexto — muitas vezes o modelo se corrige na segunda tentativa.

retry_validation.py
from pydantic import BaseModel, ValidationError

class MeteoArgs(BaseModel):
    ville: str

def valider_appel(call):
    fn = call['function']['name']
    if fn not in dispatch:
        raise ValueError(f"Fonction inconnue: {fn}")
    args = MeteoArgs.model_validate(call['function']['arguments'])
    return fn, args

def appel_avec_retry(messages, max_essais=3):
    for essai in range(max_essais):
        resp = ollama.chat(model='mistral-small',
                           messages=messages, tools=tools)
        try:
            calls = resp['message'].get('tool_calls') or []
            return [valider_appel(c) for c in calls], resp
        except (ValidationError, ValueError) as e:
            messages.append({
                'role': 'user',
                'content': f"Erreur: {e}. Corrige et reessaie.",
            })
    raise RuntimeError('Echec apres retries')
Validar antes de executar
Um modelo Pydantic por função detecta argumentos ausentes ou com tipos incorretos antes que eles cheguem ao seu código.
Tentar novamente com feedback
Reinserir a mensagem de erro no contexto orienta o modelo para a correção. 2 a 3 tentativas quase sempre são suficientes.
Lista branca de funções
Rejeite qualquer nome de função fora do dispatch. Isso é tanto uma medida de segurança quanto uma proteção contra alucinações.
Fallback com tratamento adequado de falhas
Após N falhas, responda ao usuário com uma mensagem clara em vez de travar — especialmente com um modelo pequeno.

#As armadilhas dos modelos pequenos no uso de ferramentas

O uso de ferramentas é cognitivamente exigente: o modelo deve compreender a intenção, escolher a função adequada, mapear os argumentos e respeitar o formato. Com menos de 7B, os resultados são frágeis. A seguir, o que mais quebra localmente e como corrigir.

tool_calls vazio
O modelo responde em texto em vez de chamar a função. Normalmente um modelo não treinado para uso de ferramentas ou uma descrição de função muito vaga. Mude para Qwen 3.5 ou Mistral Small e melhore as descrições.
Argumentos inválidos
O modelo inventa ou esquece campos. Marque-os como obrigatórios usando required no esquema, reduza o número de funções expostas ao mesmo tempo e valide sistematicamente.
Função alucinada
O modelo chama uma função que não existe. Lista branca obrigatória do lado do dispatch.
JSON poluído
Sem formato, um modelo pequeno adiciona texto ao redor do JSON. Sempre use format='json' ou um esquema para extração pura.
Demasiadas funções
Acima de 5–6 ferramentas, os modelos pequenos se perdem. Segmente por subtarefa ou faça o roteamento em duas etapas.
→
Um bom equilíbrio para uso local
Para chamadas de função confiáveis sem GPU de alto desempenho, mistral-small (24B) em Q4 (≈14 GB de VRAM) geralmente oferece a melhor relação entre qualidade e recursos em uma RTX 4080. Com menos recursos, qwen3.5:9b (≈6,6 GB) dá conta de um conjunto pequeno de funções bem descritas, e gpt-oss:20b é uma alternativa muito rápida. Para uso realmente voltado para agentes, glm-4.7-flash (MoE 30B-A3B, ≈19 GB) se destaca se você tiver 24 GB de VRAM.

#Para se aprofundar

O function calling é a peça básica dos agentes e das integrações avançadas. Esses guias do site complementam este guia:

Integrar Ollama via API REST em Python
O endpoint compatível com a OpenAI na porta :11434, o streaming e o modo JSON em uma aplicação real FastAPI/Flask.
Criar um agente de IA local com LangChain e Ollama
Passar da chamada de funções em sua forma básica para um agente completo que encadeia ferramentas, memória e raciocínio.
MCP e LLM local: conectar servidores MCP ao Ollama
Padronizar o acesso a ferramentas (arquivos, web, bancos de dados) via Model Context Protocol em vez de definir cada função manualmente.
Este guia ajudou você?

Um comentário, um erro ou uma observação? Avise-nos; isso ajuda a melhorar o guia para todos.