LangChain + Ollama na prática: guia completo para criar aplicações com LLM local

No mês passado, dei uma olhada na minha fatura da OpenAI: US$ 52,30. Para ser sincero, fiquei um pouco assustado. Sou um desenvolvedor independente, uso IA só de vez em quando e, ainda assim, tinha gastado tudo isso. Foi quando me lembrei do Ollama rodando localmente, com o Llama 3.1 gratuito à minha disposição.
Mas havia um problema: chamar a API do Ollama diretamente em uma aplicação exige bastante código. Formato da requisição, parsing da resposta, tratamento de erros… tudo isso se repete e fica cansativo. É aí que o LangChain ajuda: ele oferece uma interface pronta para Chat, RAG e Agent, além de permitir a troca de modelo com uma linha de código.
Este é o capítulo sobre integração com frameworks da série Ollama com LLM local na prática. Vamos começar pelo pacote langchain-ollama e avançar por três cenários: Chat, RAG e Agent. Se você já leu os artigos anteriores da série, sobre chamadas de API e implantação de vários modelos, este texto conecta essas partes em um único framework de desenvolvimento.
Primeiros passos com o pacote langchain-ollama
Antes de começar, vale mencionar uma armadilha em que caí. Eu usava langchain_community.llms.Ollama, e o código funcionava, mas algo parecia errado: toda vez que consultava a documentação, encontrava referências ao pacote “langchain-ollama”. Só depois descobri que o LangChain separou oficialmente a integração com o Ollama em um pacote independente, o langchain-ollama.
Por que usar o pacote oficial?
A tipagem é mais completa, e o preenchimento automático da IDE funciona melhor. A manutenção acompanha as versões principais do LangChain, o que reduz problemas de compatibilidade. Além disso, um pacote da comunidade pode ser descontinuado a qualquer momento, enquanto o pacote oficial é a opção de longo prazo. Isso faz diferença; já tive problemas com pacotes da comunidade abandonados.
A instalação exige apenas um comando:
pip install langchain-ollama
Depois de instalar, você encontrará três classes principais, cada uma voltada a um cenário:
| Classe | Finalidade | Cenário comum |
|---|---|---|
ChatOllama | Modelo de conversa | Chat com várias interações, sistemas de perguntas e respostas |
OllamaLLM | Conclusão de texto | Geração única, continuação de texto |
OllamaEmbeddings | Embeddings vetoriais | RAG, busca semântica |
Nos meus testes, ChatOllama é suficiente em 90% dos casos. O modelo de conversa aceita várias interações e também oferece streaming, exibindo a resposta aos poucos. Para o usuário, isso é muito melhor do que esperar o texto inteiro aparecer de uma só vez.
Veja um exemplo mínimo:
from langchain_ollama import ChatOllama
# Inicializa o modelo
llm = ChatOllama(
model="llama3.1:8b", # Nome do modelo, que deve ser baixado antes no Ollama
temperature=0.7 # Parâmetro de aleatoriedade, entre 0 e 1
)
# Envia uma mensagem
response = llm.invoke("Olá, apresente-se")
print(response.content)
Antes de executar o código, confirme que você baixou o modelo com ollama pull llama3.1:8b. Se ainda não instalou o Ollama, consulte o primeiro artigo introdutório da série.
O uso do modelo de embeddings OllamaEmbeddings é parecido. Ele serve principalmente para transformar texto em vetores. A seção sobre RAG mostra isso em detalhes; por enquanto, veja um exemplo simples:
from langchain_ollama import OllamaEmbeddings
embeddings = OllamaEmbeddings(model="nomic-embed-text")
# Gera o embedding de um único texto
vector = embeddings.embed_query("Este é um texto de teste")
print(f"Dimensões do vetor: {len(vector)}") # Normalmente exibe 768 ou mais
# Gera embeddings de vários textos em lote
vectors = embeddings.embed_documents([
"Primeiro texto",
"Segundo texto"
])
nomic-embed-text é um dos modelos de embeddings mais usados atualmente e foi criado especificamente para busca semântica. Ele produz vetores com muitas dimensões, normalmente 768 ou mais, e oferece resultados de busca bem melhores que os de modelos genéricos.
Chat na prática: várias interações e respostas em streaming
Fazer uma única chamada à API é simples, mas uma conversa real é mais complexa: o usuário continua fazendo perguntas, e o modelo precisa se lembrar do que foi dito antes. O LangChain usa uma lista de mensagens para resolver isso.
Como implementar uma conversa com várias interações
O LangChain oferece três tipos de mensagem:
SystemMessage: define o papel e o comportamento do modelo, por exemplo, “você é um assistente especializado em programação”HumanMessage: mensagem do usuárioAIMessage: resposta do modelo
Veja o código:
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
llm = ChatOllama(model="llama3.1:8b", temperature=0.7)
# Cria o histórico da conversa
messages = [
SystemMessage(content="Você é um assistente de desenvolvimento que explica conceitos técnicos de forma clara e concisa."),
HumanMessage(content="O que é uma API REST?"),
AIMessage(content="Uma API REST é um estilo de projeto de interfaces para serviços de rede que usa métodos HTTP, como GET, POST, PUT e DELETE, para operar recursos. Em termos simples, ela permite acessar dados por URLs."),
HumanMessage(content="E qual é a diferença para o GraphQL?")
]
# O modelo gera a resposta com base em todo o histórico
response = llm.invoke(messages)
print(response.content)
Nesse código, o modelo enxerga a resposta anterior e entende que o usuário está perguntando sobre a diferença entre GraphQL e REST. Sem o registro em AIMessage, ele poderia começar a explicar GraphQL do zero, interrompendo a continuidade da conversa.
Streaming: uma resposta que parece estar viva
Com streaming, o usuário não precisa ficar olhando para uma tela vazia enquanto espera. O texto aparece aos poucos, como se alguém estivesse digitando. Essa experiência é especialmente importante em respostas longas.
from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama3.1:8b")
# Exibe a resposta em streaming
print("Resposta do modelo: ", end="", flush=True)
for chunk in llm.stream("Escreva um algoritmo quicksort em Python e explique como ele funciona"):
print(chunk.content, end="", flush=True)
print() # Quebra a linha no final
O método stream() retorna um iterador, e cada chunk contém um pequeno trecho de texto. flush=True faz o conteúdo aparecer imediatamente, sem ficar preso no buffer.
Nos meus testes, o streaming reduziu bastante a sensação de demora, principalmente em respostas com mais de 100 caracteres. O usuário percebe que o sistema está “pensando”, não que ficou travado.
RAG na prática: busca em uma base de conhecimento local
RAG (Retrieval-Augmented Generation) é hoje um dos usos mais práticos de LLMs. Em termos simples, o sistema primeiro busca conteúdo relevante em uma coleção de documentos e depois pede ao modelo que responda com base nesse conteúdo. Assim, o modelo pode usar informações que não estavam nos dados de treinamento.
Entendendo o fluxo de RAG
Um sistema RAG completo tem cinco etapas:
- Carregar documentos — ler arquivos PDF, TXT, Markdown e outros formatos
- Dividir o texto — separar documentos longos em trechos menores para facilitar a busca
- Gerar vetores — usar um modelo de embeddings para transformar o texto em vetores numéricos
- Armazenar o índice — salvar os vetores em um banco de dados vetorial, neste caso o ChromaDB
- Recuperar e gerar — quando o usuário fizer uma pergunta, buscar trechos relevantes e pedir ao modelo que responda
Abaixo está o código completo. Eu o executei e confirmei que funciona:
from langchain_ollama import ChatOllama, OllamaEmbeddings
from langchain_chroma import Chroma
from langchain_community.document_loaders import PyPDFLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# === 1. Carrega o documento ===
# Aceita PDF, TXT, Markdown e vários outros formatos
loader = TextLoader("./my_document.txt") # Substitua pelo caminho do seu documento
docs = loader.load()
# === 2. Divide o texto ===
# chunk_size=1000 é um valor comum; cada trecho tem cerca de 1.000 caracteres
# chunk_overlap=200 cria sobreposição entre os trechos para evitar perda de contexto
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
splits = text_splitter.split_documents(docs)
# === 3 e 4. Gera os vetores e armazena o índice ===
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(
documents=splits,
embedding=embeddings,
persist_directory="./chroma_db" # Caminho para armazenamento persistente
)
# === 5. Cria o recuperador ===
# search_kwargs={"k": 4} recupera os quatro trechos mais relevantes
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# === 6. Cria a RAG Chain ===
template = """Responda à pergunta com base no contexto abaixo. Se o contexto não contiver informações relevantes, diga claramente: "O documento não contém informações relacionadas".
Contexto:
{context}
Pergunta: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
llm = ChatOllama(model="llama3.1:8b")
# Sintaxe LCEL (LangChain Expression Language), que conecta os componentes com o símbolo |
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# === 7. Faz uma consulta ===
response = rag_chain.invoke("Qual é o assunto principal do documento?")
print(response)
O código parece um pouco longo, mas fica bem claro quando é dividido em partes. O ponto principal é a criação de rag_chain: a sintaxe LCEL (LangChain Expression Language) do LangChain usa o símbolo | para conectar o recuperador, o template de prompt, o modelo e o parser da saída.
Algumas sugestões práticas para ajustar os parâmetros:
Se o conteúdo do documento for denso, como em documentação técnica, você pode reduzir chunk_size para 800. Para textos corridos, valores entre 1000 e 1500 também funcionam.
O valor de k, ou número de trechos recuperados, normalmente pode ficar entre 3 e 5. Um valor alto demais dilui a relevância; um valor baixo demais pode deixar informações importantes de fora.
Configure sempre persist_directory. Caso contrário, será necessário reconstruir o banco vetorial após cada reinicialização, o que leva tempo e desperdiça recursos.
Na primeira vez em que usei RAG, não configurei a persistência. Como resultado, precisava recriar todos os embeddings a cada alteração no código, e o processo era muito lento. Depois de adicionar persist_directory, passei a carregar diretamente o banco vetorial já criado, e a inicialização caiu para poucos segundos.
Agent na prática: chamadas de ferramentas baseadas em JSON
A principal diferença entre um Agent e uma conversa comum é que o Agent pode chamar ferramentas externas.
Por exemplo, se o usuário perguntar “como está o tempo hoje em Pequim?”, um modelo de conversa comum só consegue inventar uma resposta. O Agent primeiro chama uma ferramenta de previsão do tempo, obtém dados reais e depois responde.
A armadilha das chamadas de ferramentas no Ollama
É importante ser direto sobre uma limitação: o suporte do Ollama a chamadas de ferramentas não é tão completo quanto o da OpenAI. Os modelos da OpenAI têm suporte nativo a function calling e conseguem identificar com precisão quando chamar uma ferramenta e quais argumentos fornecer. Os modelos do Ollama, incluindo Llama 3.1, ainda não têm a mesma maturidade nessa área.
Qual é a alternativa? A solução apresentada pelo LangChain é um Agent baseado em JSON.
A ideia é fazer o modelo produzir JSON estruturado. O framework do Agent analisa esse JSON para decidir qual ferramenta chamar. Nos meus testes, o resultado foi razoável: não é tão fluido quanto o function calling nativo da OpenAI, mas dá conta de tarefas básicas.
Exemplo de ferramenta personalizada
Comece definindo algumas funções simples para as ferramentas:
from langchain_ollama import ChatOllama
from langchain_core.tools import tool
# Define as ferramentas
@tool
def get_weather(city: str) -> str:
"""Obtém a previsão do tempo para uma cidade"""
# Estes são dados simulados; em um projeto real, conecte uma API meteorológica
weather_data = {
"Pequim": "Ensolarado, 25 °C, boa qualidade do ar",
"Xangai": "Nublado, 22 °C, possibilidade de chuva leve",
"Shenzhen": "Quente, 30 °C, radiação UV intensa"
}
return weather_data.get(city, f"Não foram encontrados dados meteorológicos para {city}")
@tool
def calculate(expression: str) -> str:
"""Executa um cálculo matemático"""
try:
result = eval(expression) # Atenção: use uma implementação mais segura em produção
return f"Resultado do cálculo: {result}"
except:
return "Erro no cálculo; verifique a expressão"
@tool
def search_local_docs(query: str) -> str:
"""Pesquisa na coleção de documentos local"""
# Aqui você pode conectar o recuperador criado na seção sobre RAG
return f"Resultados da busca por '{query}': três registros relacionados foram encontrados"
O decorador @tool transforma uma função comum em uma ferramenta do LangChain. A docstring da função vira automaticamente a descrição da ferramenta, e o modelo usa essa descrição para decidir quando chamar cada uma delas.
Em seguida, crie o JSON Agent:
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOllama(model="llama3.1:8b")
tools = [get_weather, calculate, search_local_docs]
# Cria o template de prompt
prompt = ChatPromptTemplate.from_messages([
("system", "Você é um assistente prestativo que pode usar ferramentas para concluir tarefas."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
# Cria o Agent
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Executa a tarefa
response = agent_executor.invoke({
"input": "Consulte a previsão do tempo para Pequim hoje e calcule 23 + 45"
})
print(response["output"])
verbose=True exibe o processo de raciocínio do Agent, o que ajuda na depuração. Você verá como o modelo decide quais ferramentas chamar.
Resultado dos testes:
Executei algumas tarefas, e a taxa de sucesso do JSON Agent ficou em torno de 70% a 80%. Tarefas simples, como consultar o tempo ou fazer contas, quase sempre funcionam. Já tarefas complexas, com várias ferramentas combinadas, falham de vez em quando: o formato dos argumentos pode sair errado, ou o modelo pode escolher a ferramenta incorreta. Essa é uma limitação comum dos Agents com LLMs locais hoje; eles ainda não têm a mesma estabilidade da OpenAI.
Se você precisa de um Agent mais confiável, considere:
- Usar um modelo mais forte, como Qwen 2.5 ou DeepSeek
- Simplificar o fluxo da tarefa e reduzir o número de ferramentas
- Usar diretamente as chamadas de ferramentas nativas da OpenAI; o custo é maior, mas a estabilidade é muito melhor
OpenAI vs. Ollama: alterne com uma linha de código
Muita gente me pergunta se um projeto bem estruturado com LangChain pode usar tanto OpenAI quanto Ollama. A resposta é sim, e a troca é extremamente simples.
Opção 1: mudar o import
Suponha que você tenha este código com OpenAI:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4", temperature=0.7)
response = llm.invoke("Explique computação quântica")
Para trocar para o Ollama, basta mudar uma linha de import:
from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama3.1:8b", temperature=0.7)
response = llm.invoke("Explique computação quântica")
O restante do código, incluindo templates de prompt, criação de Chains e parsing da saída, não precisa mudar. A camada de abstração do LangChain funciona bem, e a troca de modelo é praticamente transparente para a lógica da aplicação.
Opção 2: API compatível com OpenAI
O Ollama também oferece uma maneira de se apresentar como OpenAI: a API compatível com OpenAI. A vantagem é que nem o import precisa mudar:
from langchain_openai import ChatOpenAI
# Altere apenas base_url e api_key; o restante permanece igual
llm = ChatOpenAI(
model="llama3.1:8b",
base_url="http://localhost:11434/v1", # Endpoint do Ollama compatível com OpenAI
api_key="ollama" # Pode ser qualquer valor; o Ollama não o valida
)
response = llm.invoke("Explique computação quântica")
Quando essa opção faz sentido? Quando seu projeto já usa ChatOpenAI em muitos pontos e você quer testar um modelo local sem alterar a estrutura do código.
Resumo da comparação
Depois de ver as formas de alternar, quando vale usar Ollama e quando vale usar OpenAI? A tabela abaixo resume as principais diferenças:
| Critério | OpenAI (GPT-4) | Ollama (Llama 3.1) |
|---|---|---|
| Custo | US$ 0,03/1.000 tokens de entrada | Gratuito, com o custo de energia da GPU local |
| Privacidade | Os dados são enviados à nuvem; cenários sensíveis a conformidade exigem cuidado | Processamento local; os dados não saem do dispositivo |
| Chamadas de ferramentas | Suporte nativo, estável e confiável | Exige JSON Agent, com taxa de sucesso de 70% a 80% |
| Velocidade de resposta | Rápida, com otimização na nuvem e primeiro token em 1 a 3 segundos | Depende da GPU local, normalmente entre 3 e 10 segundos |
| Capacidade do modelo | GPT-4 está entre os modelos mais fortes disponíveis | Llama 3.1 8B tem capacidade intermediária a alta; é suficiente para muitos usos, mas fica atrás do GPT-4 |
Minha recomendação:
- Aprendizado e protótipos pessoais: use Ollama para economizar e experimentar à vontade
- Produção e alta concorrência: use OpenAI para obter mais estabilidade e velocidade de resposta
- Dados sensíveis: use Ollama para manter os dados localmente
- Tarefas complexas com Agent: use OpenAI para ter chamadas de ferramentas mais estáveis
O ideal é ter as duas opções: usar Ollama durante o desenvolvimento para reduzir custos e OpenAI em produção para garantir estabilidade. Como a troca exige só uma linha de código, não há motivo para escolher apenas uma delas desde o início.
Conclusão
Agora você tem um mapa completo para integrar LangChain e Ollama.
Começamos pelo pacote langchain-ollama e pelas três classes principais: ChatOllama, OllamaLLM e OllamaEmbeddings. Em seguida, implementamos três cenários: Chat com várias interações e streaming, RAG para transformar documentos locais em uma base de perguntas e respostas, e chamadas de ferramentas com Agent, em que o JSON Agent serve como solução intermediária. Por fim, comparamos as estratégias para alternar entre OpenAI e Ollama: uma linha de código pode transformar um custo mensal de US$ 50 em uma solução local gratuita.
Quando escolher o Ollama?
Em uma frase: quando você quer economizar, preservar a privacidade ou simplesmente aprender a desenvolver com LLMs. Execute tudo localmente, experimente à vontade e não se preocupe com uma fatura inesperada.
Quando ainda vale usar OpenAI?
Em tarefas complexas com Agent, ambientes de produção com alta concorrência e cenários que exigem velocidade e estabilidade. As LLMs locais ainda não substituem completamente a experiência oferecida pela nuvem.
Se você ainda não testou, comece pelo Chat: o código é mais simples e o resultado é imediato. Depois, avance para RAG e conecte seus documentos locais para experimentar um modelo capaz de consultar seu próprio material. Deixe o Agent para depois, porque as chamadas de ferramentas ainda têm várias armadilhas e exigem mais paciência na depuração.
Os próximos artigos da série abordarão outros temas: implantação de vários modelos e troca entre eles no LangChain, otimização de desempenho para acelerar uma LLM local e implantação em produção para transformar uma aplicação local em um serviço utilizável. Continue acompanhando se esses assuntos forem úteis para você.
Se tiver dúvidas, deixe um comentário ou fale comigo no GitHub. Executei todos os exemplos de código e eles devem funcionar. Se aparecer algum erro, as causas mais prováveis são um modelo ainda não baixado ou uma dependência ausente; comece a investigação pela mensagem exibida.
Desenvolvimento com a integração LangChain + Ollama
Da instalação e configuração aos exemplos práticos de Chat, RAG e Agent para desenvolver aplicações com LLM local
⏱️ Estimated time: 60 min
- 1
Step 1: Instalar o pacote langchain-ollama
Execute o comando de instalação:
```bash
pip install langchain-ollama
```
Verifique se o Ollama está instalado e se o modelo já foi baixado, por exemplo com `ollama pull llama3.1:8b`. - 2
Step 2: Criar uma aplicação de Chat
Inicialize ChatOllama e envie uma mensagem:
```python
from langchain_ollama import ChatOllama
llm = ChatOllama(model="llama3.1:8b", temperature=0.7)
response = llm.invoke("Olá")
print(response.content)
```
Há suporte a conversas com várias interações e respostas em streaming. - 3
Step 3: Criar uma base de conhecimento RAG
Fluxo em cinco etapas:
• Carregar documentos (TextLoader / PyPDFLoader)
• Dividir o texto (RecursiveCharacterTextSplitter)
• Gerar vetores (OllamaEmbeddings)
• Armazenar o índice (ChromaDB)
• Recuperar e gerar (RAG Chain)
Parâmetros importantes: chunk_size=1000, k=4 e persist_directory obrigatório. - 4
Step 4: Implementar chamadas de ferramentas com Agent
Defina as funções das ferramentas e crie um JSON Agent:
```python
@tool
def get_weather(city: str) -> str:
"""Obtém informações meteorológicas"""
...
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools)
```
A taxa de sucesso fica em torno de 70% a 80%; para tarefas complexas, a recomendação é usar OpenAI. - 5
Step 5: Alternar entre OpenAI e Ollama
Opção 1: mudar o import
```python
from langchain_ollama import ChatOllama # Usar Ollama
from langchain_openai import ChatOpenAI # Usar OpenAI
```
Opção 2: API compatível com OpenAI, sem mudar o import
```python
llm = ChatOpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama"
)
```
FAQ
Qual é a diferença entre langchain-ollama e langchain_community.llms.Ollama?
Devo usar ChatOllama ou OllamaLLM?
Como configurar chunk_size e k em um sistema RAG?
Por que as chamadas de ferramentas do Ollama são menos estáveis que as da OpenAI?
Como alternar entre OpenAI e Ollama?
O Ollama é adequado para ambientes de produção?
15 min de leitura · Publicado em: 7 abr 2026 · Atualizado em: 4 set 2026
Guia Ollama LLM local
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Ollama API na prática: guia para clientes em Python e Node.js
Aprenda a usar a API do Ollama com os SDKs nativos para Python e Node.js, respostas em streaming, Agent Loop com ferramentas, modo thinking e integração compatível com a OpenAI
Parte 9 de 13
Próximo
Ollama Embedding na prática: busca vetorial local e RAG
Monte um sistema RAG local com Ollama: compare mxbai-embed-large, nomic-embed-text e Qwen3, escolha entre ChromaDB, FAISS e Milvus e implemente o fluxo completo em Python.
Parte 11 de 13



Comentários
Entre com GitHub para comentar