Da primeira chamada à API até streaming, function calling, RAG e gestão de custos em produção. Um guia técnico completo para 2026, com exemplos em Python e JavaScript.
A primeira decisão impacta custo, qualidade e latência. Para a maioria dos casos: comece com um modelo mid-tier (GPT-4o-mini, Claude Haiku, Gemini Flash) e suba para frontier somente se qualidade for insuficiente.
| Critério | Escolha |
|---|---|
| Qualidade máxima | GPT-4o, Claude Sonnet 4, Gemini 2.5 Pro |
| Custo-benefício | GPT-4o-mini, Claude Haiku, Gemini Flash |
| Velocidade (chatbot real-time) | Groq (Llama), Claude Haiku, Gemini Flash |
| Privacidade / on-premises | Llama 3.1, Mistral, Qwen 2.5 via Ollama |
| Context longo (200K+) | Claude Sonnet, Gemini 2.5 Pro |
| Código e programação | Claude Sonnet, GPT-4o, DeepSeek Coder |
Dica de produção: use LiteLLM como camada de abstração. Você escreve o código uma vez e troca de modelo mudando apenas uma variável de ambiente. Economiza reescrita quando preços ou qualidade mudam.
Toda integração começa com uma chamada simples. O padrão é o mesmo em todos os provedores principais: mensagens com roles (system, user, assistant).
from openai import OpenAI
client = OpenAI(api_key="sua-chave-aqui")
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": "Você é um assistente útil em PT-BR."
},
{
"role": "user",
"content": "Explique o que é RAG em 2 parágrafos."
}
],
max_tokens=500,
temperature=0.7,
)
print(response.choices[0].message.content)
print(f"Tokens usados: {response.usage.total_tokens}")import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{
role: "system",
content: "Você é um assistente útil em PT-BR.",
},
{
role: "user",
content: "Explique o que é RAG em 2 parágrafos.",
},
],
max_tokens: 500,
temperature: 0.7,
});
console.log(response.choices[0].message.content);
console.log(`Tokens: ${response.usage.total_tokens}`);Com streaming, tokens aparecem à medida que são gerados — como o ChatGPT faz. A percepção de velocidade melhora drasticamente sem reduzir o tempo total de processamento.
with client.chat.completions.stream(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Escreva um poema sobre IA"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True) # imprime token a token// app/api/chat/route.ts
import { OpenAIStream, StreamingTextResponse } from "ai"; // Vercel AI SDK
import OpenAI from "openai";
export const runtime = "edge";
const openai = new OpenAI();
export async function POST(req: Request) {
const { messages } = await req.json();
const response = await openai.chat.completions.create({
model: "gpt-4o-mini",
stream: true,
messages,
});
const stream = OpenAIStream(response);
return new StreamingTextResponse(stream);
}Function calling permite que o LLM decida quando e como chamar funções que você define. É a base de agentes — o modelo pode buscar dados externos, chamar APIs e executar ações.
import json
tools = [
{
"type": "function",
"function": {
"name": "buscar_preco_modelo",
"description": "Busca o preço de um modelo de LLM por nome",
"parameters": {
"type": "object",
"properties": {
"nome_modelo": {
"type": "string",
"description": "Nome do modelo, ex: gpt-4o-mini"
}
},
"required": ["nome_modelo"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Quanto custa o GPT-4o?"}],
tools=tools,
tool_choice="auto",
)
if response.choices[0].finish_reason == "tool_calls":
tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
# Aqui você executa a função real
resultado = buscar_preco_modelo(args["nome_modelo"])
print(f"Modelo chamou: {tool_call.function.name}({args})")RAG (Retrieval-Augmented Generation) permite que o LLM responda com base nos seus dados sem fine-tuning. Você recupera trechos relevantes de um banco vetorial e os injeta no contexto da requisição.
import numpy as np
# 1. Gerar embedding da pergunta do usuário
def get_embedding(text: str) -> list[float]:
response = client.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
# 2. Buscar trechos relevantes (simplificado — use pgvector/Pinecone em prod)
def buscar_contexto(pergunta: str, documentos: list[dict]) -> str:
emb_pergunta = get_embedding(pergunta)
# Calcular similaridade cosseno com cada documento
scores = []
for doc in documentos:
score = np.dot(emb_pergunta, doc["embedding"]) / (
np.linalg.norm(emb_pergunta) * np.linalg.norm(doc["embedding"])
)
scores.append((score, doc["texto"]))
# Retornar top-3 mais relevantes
top3 = sorted(scores, reverse=True)[:3]
return "\n---\n".join([t for _, t in top3])
# 3. Injetar contexto no prompt
pergunta = "Qual o preço do GPT-4o?"
contexto = buscar_contexto(pergunta, documentos)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": f"""Responda com base APENAS no contexto abaixo.
Se a resposta não estiver no contexto, diga que não sabe.
CONTEXTO:
{contexto}"""
},
{"role": "user", "content": pergunta}
]
)
print(response.choices[0].message.content)Em produção, cache é a ferramenta mais eficaz para cortar custos. Requisições idênticas ou muito similares não precisam chegar ao LLM.
import hashlib
import redis
import json
r = redis.Redis(host="localhost", port=6379, db=0)
def llm_com_cache(messages: list, model: str = "gpt-4o-mini", ttl: int = 3600) -> str:
# Gerar chave de cache determinística
cache_key = hashlib.sha256(
json.dumps({"model": model, "messages": messages}, sort_keys=True).encode()
).hexdigest()
# Verificar cache
cached = r.get(cache_key)
if cached:
return json.loads(cached)["content"]
# Chamar LLM
response = client.chat.completions.create(model=model, messages=messages)
content = response.choices[0].message.content
# Salvar no cache
r.setex(cache_key, ttl, json.dumps({"content": content}))
return contentmax_tokens ao mínimo necessárioConteúdo relacionado: