Guia Técnico

Como Integrar LLMsem Aplicações

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.

IntermediárioPythonJavaScriptAPI RESTRAGProdução

Pré-requisitos

Conhecimento básico de Python ou JavaScript
Conta em OpenAI, Anthropic ou Google (API key)
Familiaridade com HTTP e APIs REST
01

Escolha do Modelo e Provedor

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érioEscolha
Qualidade máximaGPT-4o, Claude Sonnet 4, Gemini 2.5 Pro
Custo-benefícioGPT-4o-mini, Claude Haiku, Gemini Flash
Velocidade (chatbot real-time)Groq (Llama), Claude Haiku, Gemini Flash
Privacidade / on-premisesLlama 3.1, Mistral, Qwen 2.5 via Ollama
Context longo (200K+)Claude Sonnet, Gemini 2.5 Pro
Código e programaçãoClaude 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.

02

Chamada Básica à API

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).

Python
from openai import OpenAI

client = OpenAI(api_key="your-api-key-here")

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {
            "role": "system",
            "content": "You are a helpful assistant."
        },
        {
            "role": "user",
            "content": "Explain what RAG is in 2 paragraphs."
        }
    ],
    max_tokens=500,
    temperature=0.7,
)

print(response.choices[0].message.content)
print(f"Tokens used: {response.usage.total_tokens}")
JavaScript / Node.js
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: "You are a helpful assistant.",
    },
    {
      role: "user",
      content: "Explain what RAG is in 2 paragraphs.",
    },
  ],
  max_tokens: 500,
  temperature: 0.7,
});

console.log(response.choices[0].message.content);
console.log(`Tokens: ${response.usage.total_tokens}`);
03

Streaming para UX Responsiva

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.

Python — Streaming
with client.chat.completions.stream(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Write a poem about AI"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)  # prints token by token
Next.js — API Route com Streaming (Edge Runtime)
// 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);
}
04

Function Calling

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.

Python — Function Calling
import json

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_model_price",
            "description": "Retrieves the price of an LLM model by name",
            "parameters": {
                "type": "object",
                "properties": {
                    "model_name": {
                        "type": "string",
                        "description": "Model name, e.g. gpt-4o-mini"
                    }
                },
                "required": ["model_name"]
            }
        }
    }
]

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "How much does GPT-4o cost?"}],
    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)
    # Execute the real function here
    result = get_model_price(args["model_name"])
    print(f"Model called: {tool_call.function.name}({args})")
05

RAG — Contexto com Seus Dados

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.

Python — RAG Simples com OpenAI Embeddings
import numpy as np

# 1. Generate embedding for the user's question
def get_embedding(text: str) -> list[float]:
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    return response.data[0].embedding

# 2. Retrieve relevant chunks (simplified — use pgvector/Pinecone in prod)
def search_context(question: str, documents: list[dict]) -> str:
    q_emb = get_embedding(question)

    # Compute cosine similarity with each document
    scores = []
    for doc in documents:
        score = np.dot(q_emb, doc["embedding"]) / (
            np.linalg.norm(q_emb) * np.linalg.norm(doc["embedding"])
        )
        scores.append((score, doc["text"]))

    # Return top-3 most relevant
    top3 = sorted(scores, reverse=True)[:3]
    return "\n---\n".join([t for _, t in top3])

# 3. Inject context into the prompt
question = "How much does GPT-4o cost?"
context = search_context(question, documents)

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {
            "role": "system",
            "content": f"""Answer ONLY based on the context below.
If the answer is not in the context, say you don't know.

CONTEXT:
{context}"""
        },
        {"role": "user", "content": question}
    ]
)
print(response.choices[0].message.content)
Aprofundar: RAG vs Fine-Tuning — quando usar cada um →
06

Cache e Controle de Custos

Em produção, cache é a ferramenta mais eficaz para cortar custos. Requisições idênticas ou muito similares não precisam chegar ao LLM.

Python — Cache simples com Redis
import hashlib
import redis
import json

r = redis.Redis(host="localhost", port=6379, db=0)

def llm_with_cache(messages: list, model: str = "gpt-4o-mini", ttl: int = 3600) -> str:
    # Generate deterministic cache key
    cache_key = hashlib.sha256(
        json.dumps({"model": model, "messages": messages}, sort_keys=True).encode()
    ).hexdigest()

    # Check cache
    cached = r.get(cache_key)
    if cached:
        return json.loads(cached)["content"]

    # Call LLM
    response = client.chat.completions.create(model=model, messages=messages)
    content = response.choices[0].message.content

    # Save to cache
    r.setex(cache_key, ttl, json.dumps({"content": content}))
    return content

Estratégias de Redução de Custo

  • Cache de respostas frequentes (Redis, Upstash)
  • Prompt caching nativo (Anthropic, OpenAI) para system prompts longos
  • Modelo menor para triagem, maior apenas para casos complexos
  • Limitar max_tokens ao mínimo necessário
  • Comprimir histórico de conversas longas

Monitoramento em Produção

  • Logar tokens de input/output por requisição
  • Budget limit por usuário/dia (bloquear ao atingir)
  • Alertas quando custo diário excede threshold
  • LangFuse ou Helicone para observabilidade detalhada
  • Dashboard de custo por feature/endpoint

Checklist de Produção

API key em variáveis de ambiente (nunca no código)
Rate limiting por usuário implementado
Timeout configurado (evitar requisições penduradas)
Retry com backoff exponencial para erros 429/500
Budget limit diário por usuário
Logging de tokens input/output por requisição
Validação de output antes de exibir ao usuário
Versão do modelo fixada (evitar breaking changes)
Fallback para modelo alternativo em caso de indisponibilidade
Dados sensíveis nunca enviados ao LLM sem DPA

Perguntas Frequentes

Qual a diferença entre usar a API diretamente e usar um framework como LangChain?
A API direta oferece mais controle, menor overhead e menos dependências — ideal para casos de uso simples. LangChain e similares abstraem patterns comuns (RAG, agentes, memória) e aceleram o desenvolvimento de sistemas complexos. Recomendação: comece com a API direta. Se precisar de agentes complexos ou RAG elaborado, avalie frameworks. Evite abstrações prematuras.
Como calcular o custo de um LLM em produção?
Custo = (tokens_input × preco_input/1M) + (tokens_output × preco_output/1M). Use tiktoken (Python) ou js-tiktoken para estimar tokens antes de enviar. Para GPT-4o: ~$2.50/1M input + $10/1M output. Para Claude Haiku: ~$0.25/1M input + $1.25/1M output. Multiplique pelo volume de requisições esperado. Adicione 20% de margem para tokens do sistema e formatação.
Como evitar que usuários abusem da minha integração com LLM?
Implemente: (1) autenticação obrigatória antes de qualquer chamada; (2) rate limiting por usuário (ex: 10 requisições/minuto); (3) limite de tokens por requisição; (4) budget limit diário por usuário — bloqueie automaticamente ao atingir; (5) monitoring de custo em tempo real com alertas. Nunca exponha sua API key no frontend.
Vale a pena fazer fine-tuning ou usar RAG?
RAG primeiro, sempre. Fine-tuning é caro (tempo + compute + dados rotulados), difícil de manter atualizado e não resolve alucinação. RAG adiciona contexto recuperado dinamicamente — mais fácil de atualizar e depurar. Use fine-tuning apenas para: adaptar o estilo/tom do modelo, melhorar performance em formato específico (JSON estruturado, código de nicho), ou reduzir latência em modelos menores especializados.
Como escolher entre stream e resposta completa?
Use streaming para interfaces de usuário (chatbots, editores de texto) — a percepção de velocidade melhora dramaticamente mesmo sem reduzir latência total. Use resposta completa para: processamento em batch (sem usuário aguardando), quando precisa parsear JSON da resposta inteira antes de agir, ou quando a latência total é menor que overhead de stream.

Conteúdo relacionado: