Ollama: Integração com LangChain

LangChain é o maestro de orquestração de aplicações de IA — modelos são atores, Chains são roteiros, e Agentes são diretores.

💡 Dica: O núcleo do LangChain é a arquitetura de três camadas Agente/Chain/Tool — Chain é um pipeline fixo (Prompt→LLM→Parser), Tool é uma capacidade externa invocável (consultar banco de dados, buscar documentos), e Agente é um tomador de decisão autônomo que escolhe dinamicamente quais Tools invocar. 90% dos cenários são bem servidos por Chains; use Agentes apenas quando decisões dinâmicas são necessárias.

📋 Pré-requisitos: Você deve dominar o seguinte primeiro

1. O Que Você Vai Aprender


2. Uma História Real de Uma CTO de Startup

(1) O Problema: Analisar Manualmente 50 Relatórios de Métricas Todo Mês

A empresa SaaS da Alice rastreia 50 métricas de negócio, exigindo análise manual de tendências e escrita de relatórios mensalmente. Um analista gasta 3 dias completando o trabalho, e sinais importantes de anomalia são frequentemente perdidos.

(2) A Solução: Agente LangChain para Análise Automatizada

Usando LangChain + Ollama para construir um Agente de IA que automaticamente lê dados de métricas, identifica anomalias e gera relatórios de análise:

PYTHON
from langchain_ollama import ChatOllama

llm = ChatOllama(model="qwen2.5", temperature=0.2)
result = llm.invoke("Analyze the 20% drop in MRR last month")

3. Conexão LangChain + Ollama

💡 Dica: O parâmetro base_url do ChatOllama padrão é http://localhost:11434. Se o Ollama estiver implantado em outro host ou em um Contêiner Docker, você precisa definir explicitamente base_url="http://ollama:11434" ou o endereço correspondente.

(1) Instalação e Inicialização

BASH
pip install langchain langchain-ollama langchain-community

(2) Dois Componentes Centrais

Componente Classe Propósito
Chat Model ChatOllama Geração de conversação
Embeddings OllamaEmbeddings Vetorização de texto
100%
flowchart TD
    A[LangChain App] --> B[ChatOllama<br/>qwen2.5 / llama3.2]
    A --> C[OllamaEmbeddings<br/>nomic-embed-text]
    B --> D[Ollama Server<br/>localhost:11434]
    C --> D
Parâmetro ChatOllama Tipo Padrão Descrição
model str Nome do Modelo
temperature float 0.8 Aleatoriedade
base_url str http://localhost:11434 Endereço do servidor
num_ctx int 2048 Janela de contexto

▶ Exemplo 1: Invocação Básica do ChatOllama

PYTHON
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, SystemMessage

# Initialize ChatOllama
llm = ChatOllama(model="qwen2.5", temperature=0.3)

# Simple invocation
response = llm.invoke("What is RAG?")
print(response.content)

# With system message
response = llm.invoke([
    SystemMessage(content="You are a data analyst. Be concise."),
    HumanMessage(content="What causes MRR to drop?")
])
print(response.content)

Saída:

TEXT
# Execution successful

4. Prompt Template + Chain

(1) Engenharia de Prompts Encadeados

Prompt Templates tornam prompts parametrizáveis, reutilizáveis e combináveis:

100%
flowchart LR
    A[Variáveis de Entrada] --> B[PromptTemplate]
    B --> C[ChatOllama]
    C --> D[Output Parser]
    D --> E[Resultado Estruturado]
Tipo de Chain Descrição Caso de Uso
LLMChain Prompt → LLM → Saída Raciocínio de passo único
SequentialChain Múltiplas Chains em série Análise em múltiplos passos
RouterChain Rotear com base na entrada Processamento por ramificação

▶ Exemplo 2: Prompt Template + Chain

PYTHON
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOllama(model="qwen2.5", temperature=0.3)

# Define prompt template
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a {role}. Be concise and professional."),
    ("human", "{input}")
])

# Build chain: prompt -> llm -> parser
chain = prompt | llm | StrOutputParser()

# Invoke with variables
result = chain.invoke({
    "role": "customer service agent for e-commerce",
    "input": "Customer wants to cancel order #12345"
})
print(result)

Saída:

TEXT
# Execution successful

5. Output Parser para Saída Estruturada

⚠️ Aviso: Modelos pequenos (menos de 3B parâmetros) geram estruturas JSON instáveis, causando falhas de parsing do PydanticOutputParser. Use um modelo 8B+ com format="json", e adicione lógica de retry com try/except no código.

(1) Output Parsers Comuns

Parser Propósito Formato de Saída
StrOutputParser Texto simples string
JsonOutputParser Objeto JSON dict
PydanticOutputParser Modelo Pydantic objeto tipado
CommaSeparatedListOutputParser Lista separada por vírgulas list[str]

(2) Comparação de Saída Estruturada Pydantic

Abordagem Vantagens Desvantagens
format=json Simples Sem validação de tipo
JsonOutputParser Tem dicas de schema Parsing pode falhar
PydanticOutputParser Validação de tipo completa Depende do modelo seguir o schema

▶ Exemplo 3: Saída Estruturada com Pydantic

PYTHON
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

# Define output schema
class CustomerIntent(BaseModel):
    intent: str = Field(description="Customer intent category")
    confidence: float = Field(description="Confidence score 0-1")
    order_number: str | None = Field(description="Order number if mentioned")

# Create parser
parser = PydanticOutputParser(pydantic_object=CustomerIntent)

# Build chain with format instructions
llm = ChatOllama(model="qwen2.5", temperature=0.1, format="json")
prompt = ChatPromptTemplate.from_messages([
    ("system", "Classify the customer intent.\n{format_instructions}"),
    ("human", "{query}")
])

chain = prompt | llm | parser

# Invoke
result = chain.invoke({
    "query": "I want to track my order #88765",
    "format_instructions": parser.get_format_instructions()
})
print(f"Intent: {result.intent}")
print(f"Confidence: {result.confidence}")
print(f"Order: {result.order_number}")

Saída:

TEXT
# Execution successful

6. Agente de Chamada de Ferramentas

⚠️ Nota: Agentes podem produzir saída instável — loops de raciocínio de modelos locais podem resultar em "loops infinitos" (chamando repetidamente a mesma ferramenta) ou "chamadas de ferramenta alucinadas" (chamando ferramentas inexistentes). Sempre defina max_iterations=3-5 para limitar a contagem de loops, e use temperature=0 para maior determinismo. Modelos 3B têm capacidades de Agente limitadas; 8B+ é recomendado.

💡 Dica: A capacidade de Function Calling dos modelos locais do Ollama não é tão estável quanto o GPT-4. Recomenda-se usar Agente ReAct + padrão decorador @tool em vez de Function Calling nativo para melhor compatibilidade, e temperature=0 pode melhorar a determinismo de chamada de ferramentas.

(1) Arquitetura do Agente

100%
flowchart TD
    A[Entrada do Usuário] --> B[Agente]
    B --> C{Precisa de Ferramenta?}
    C -->|Sim| D[Chamar Ferramenta]
    D --> E[Resultado da Ferramenta]
    E --> B
    C -->|Não| F[Resposta Final]
Tipo de Agente Descrição Caso de Uso
ReAct Agent Loop de raciocínio + ação Tarefas complexas que exigem chamadas de ferramentas
Structured Chat Chamada de ferramenta estruturada Multi-ferramenta, multi-parâmetro
OpenAI Functions Modo de chamada de função Parcialmente suportado pelo Ollama

(2) Padrões de Definição de Ferramenta

Método de Definição Descrição Exemplo
@tool decorator Ferramenta simples @tool def func(...)
StructuredTool Ferramenta com descrição StructuredTool.from_function(...)
Pydantic + BaseTool Ferramenta fortemente tipada class MyTool(BaseTool)

▶ Exemplo 4: Agente ReAct na Prática

PYTHON
from langchain_ollama import ChatOllama
from langchain_core.tools import tool
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate

# Define tools
@tool
def get_order_status(order_id: str) -> str:
    """Get the status of an order by its ID."""
    # Simulated database lookup
    orders = {
        "12345": "Shipped, arriving in 2 days",
        "88765": "Processing, shipping tomorrow",
        "99999": "Delivered on 2024-01-15"
    }
    return orders.get(order_id, f"Order {order_id} not found")

@tool
def check_product_stock(product_name: str) -> str:
    """Check if a product is in stock."""
    stock = {
        "wireless headphones": "In stock: 45 units",
        "laptop stand": "Out of stock, restock in 3 days",
        "usb cable": "In stock: 200 units"
    }
    return stock.get(product_name.lower(), f"Product '{product_name}' not found")

# Build agent
llm = ChatOllama(model="qwen2.5", temperature=0)
tools = [get_order_status, check_product_stock]

prompt = PromptTemplate.from_template(
    """Answer the following question. You have access to these tools:
{tools}

Use this format:
Question: the input question
Thought: what to do
Action: tool name (one of [{tool_names}])
Action Input: tool input
Observation: tool output
... (repeat Thought/Action/Action Input/Observation)
Thought: I know the final answer
Final Answer: the final answer

Question: {input}
{agent_scratchpad}"""
)

agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# Run agent
result = agent_executor.invoke({
    "input": "What is the status of order 88765?"
})
print(result["output"])

Saída:

TEXT
# Function defined successfully

7. Exemplo Abrangente: Agente de Análise de Métricas SaaS da Alice

ℹ️ Info: O AgentExecutor do LangChain padrão é max_iterations=15, mas modelos locais raciocinam mais lentamente. Definir para 3-5 previne loops infinitos. Também defina verbose=True para observar o processo de raciocínio do Agente.

PYTHON
# ============================================
# Comprehensive: SaaS metrics analysis agent
# Uses LangChain + Ollama for automated analysis
# ============================================

from langchain_ollama import ChatOllama
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate
import json

# Simulated metrics database
METRICS_DB = {
    "mrr": {"current": 85000, "previous": 106250, "change": -20},
    "churn_rate": {"current": 8.5, "previous": 5.2, "change": 63},
    "arr": {"current": 1020000, "previous": 1275000, "change": -20},
    "active_users": {"current": 12500, "previous": 11800, "change": 6},
    "cac": {"current": 250, "previous": 180, "change": 39},
    "ltv": {"current": 2400, "previous": 3200, "change": -25}
}

@tool
def get_metric(metric_name: str) -> str:
    """Get a SaaS metric value. Available: mrr, churn_rate, arr, active_users, cac, ltv."""
    data = METRICS_DB.get(metric_name.lower())
    if data:
        return json.dumps(data)
    return f"Metric '{metric_name}' not found. Available: {list(METRICS_DB.keys())}"

@tool
def compare_metrics(metric1: str, metric2: str) -> str:
    """Compare two metrics and identify correlations."""
    m1 = METRICS_DB.get(metric1.lower())
    m2 = METRICS_DB.get(metric2.lower())
    if not m1 or not m2:
        return "One or both metrics not found."
    return json.dumps({
        "metric1": {"name": metric1, **m1},
        "metric2": {"name": metric2, **m2},
        "correlation_note": "Both metrics show negative trends"
    })

# Build analysis agent
llm = ChatOllama(model="qwen2.5", temperature=0.2)
tools = [get_metric, compare_metrics]

prompt = PromptTemplate.from_template(
    """You are a SaaS metrics analyst. Analyze data and provide insights.
Available tools: {tools}

Format:
Question: the input
Thought: what to do
Action: tool name from [{tool_names}]
Action Input: tool input
Observation: tool output
... (repeat as needed)
Thought: I have enough information
Final Answer: detailed analysis with actionable recommendations

Question: {input}
{agent_scratchpad}"""
)

agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=5)

# Run analysis
if __name__ == "__main__":
    result = executor.invoke({
        "input": "MRR dropped 20% last month. Analyze the key metrics and identify likely causes with recommendations."
    })
    print("\n=== Analysis Report ===")
    print(result["output"])

❓ Perguntas Frequentes

P: Qual é a diferença entre langchain-ollama e langchain-community? R: langchain-ollama é o pacote oficial de integração do Ollama, contendo ChatOllama e OllamaEmbeddings. langchain-community também inclui integrações legadas, mas o pacote oficial é recomendado.

P: O que devo fazer se as chamadas de ferramenta do Agente forem instáveis? R: Reduza a temperature para 0, garanta que as descrições das ferramentas sejam claras, e use format=json para forçar saída estruturada. Modelos pequenos (3B) têm capacidades de Agente limitadas; 8B+ é recomendado.

P: Como escolher entre LangChain Chains e Agentes? R: Use Chains para fluxos de trabalho fixos (Prompt → LLM → Parser), e Agentes para tomada de decisão dinâmica (selecionando autonomamente ferramentas e passos). Chains são suficientes para 90% dos cenários.

P: O que devo fazer se o parsing do PydanticOutputParser falhar? R: Adicione format="json" para forçar saída JSON. Adicione instruções de formato explícitas no prompt. Em caso de falha, recue para JsonOutputParser.

P: Modelos Ollama suportam Function Calling? R: Parcialmente. qwen2.5 e llama3.1 têm alguma capacidade de Function Calling, mas não é tão estável quanto o GPT-4. Agente ReAct + decorador @tool é recomendado como alternativa.

P: Como depurar o processo de raciocínio de um Agente? R: Defina verbose=True para visualizar o loop Thought/Action/Observation do Agente. LangSmith (tracelangchain.com) pode visualizar a cadeia de execução completa.


📖 Resumo


📝 Exercícios

  1. Básico (⭐): Construa uma Chain com ChatOllama + PromptTemplate para implementar classificação de intenção de atendimento ao cliente (saída em formato JSON).
  2. Intermediário (⭐⭐): Crie um Agente ReAct com 2 ferramentas (consultar pedido + verificar estoque), e teste chamada de ferramentas com 3 perguntas diferentes.
  3. Avançado (⭐⭐⭐): Construa um Agente de análise de métricas SaaS para Alice — incluindo pelo menos 4 ferramentas (obter métrica, comparar métricas, gerar descrição de gráfico, enviar alerta), produzindo um relatório de análise estruturado.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%