1. Chains vs agents
Chain = sequência fixa de passos. Você define a ordem: prompt → modelo → parser → próximo prompt. Previsível, fácil de testar e de limitar custo.
Agent = o modelo escolhe a próxima ação. Você entrega um conjunto de tools (buscar, calcular, chamar API, ler arquivo) e o modelo decide qual usar, com base no objetivo.
- Use chain quando o fluxo é conhecido (classificar ticket → extrair campos → responder template)
- Use agent quando o caminho depende da entrada (pesquisar docs, consultar banco, comparar opções)
2. Tools e function calling
Uma tool é uma função com nome, descrição e schema de parâmetros. O modelo “vê” a descrição e decide chamar ou não. Exemplo de schema mental:
{
"name": "search_docs",
"description": "Busca na documentação interna por similaridade semântica",
"parameters": {
"query": "string",
"limit": "integer (default 5)"
}
}
Na prática (OpenAI / Anthropic / Gemini), isso vira function calling ou tool use: o modelo devolve um JSON estruturado, sua aplicação executa a função e devolve o resultado no próximo turno.
Regras úteis:
- Descrições claras e curtas — o modelo depende delas
- Poucas tools no início (3–6); muitas tools diluem a escolha
- Validar argumentos antes de executar (tipos, limites, path traversal)
- Timeout e sandbox para tools que tocam rede ou filesystem
3. LangChain na prática
LangChain organiza prompts, modelos, parsers e tools. Esqueleto mínimo de agent com tool de busca:
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
@tool
def search_docs(query: str) -> str:
"""Busca na base de documentação interna."""
# sua lógica de retrieval (pgvector, etc.)
return "trechos relevantes..."
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
("system", "Você é um assistente técnico. Use tools quando precisar de dados."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, [search_docs], prompt)
executor = AgentExecutor(agent=agent, tools=[search_docs], verbose=True)
result = executor.invoke({"input": "Como configurar o backup 3-2-1?"})
print(result["output"])
Comece com verbose=True para ver o raciocínio e as chamadas. Em produção, desligue e logue só o necessário.
4. LlamaIndex para RAG + agentes
LlamaIndex brilha quando o centro é dados indexados (PDFs, pastas, bancos). O fluxo típico:
- Carregar documentos → chunking → embeddings → índice
- Query engine ou agent que consulta o índice
- Resposta com fontes (citations)
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.llms.openai import OpenAI
documents = SimpleDirectoryReader("./docs").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine(similarity_top_k=4)
response = query_engine.query("Qual o procedimento de restore do Restic?")
print(response)
Para agent: use as_chat_engine ou integre tools extras (SQL, HTTP). LlamaIndex e LangChain se complementam — muitos times usam LlamaIndex no retrieval e LangChain na orquestração.
5. CrewAI: multi-agente
CrewAI modela papéis (researcher, writer, reviewer) e um processo (sequencial ou hierárquico). Útil quando a tarefa naturalmente se divide:
- Pesquisador busca e resume fontes
- Analista compara opções e trade-offs
- Redator gera o relatório final
from crewai import Agent, Task, Crew
researcher = Agent(
role="Pesquisador técnico",
goal="Coletar evidências sobre a pergunta",
backstory="Especialista em documentação de infraestrutura",
verbose=True,
)
writer = Agent(
role="Redator técnico",
goal="Escrever resposta clara e citada",
backstory="Engenheiro que documenta runbooks",
verbose=True,
)
task1 = Task(description="Pesquise: {pergunta}", agent=researcher)
task2 = Task(description="Escreva a resposta final com base na pesquisa", agent=writer)
crew = Crew(agents=[researcher, writer], tasks=[task1, task2])
result = crew.kickoff(inputs={"pergunta": "Como endurecer SSH em Ubuntu?"})
Multi-agente aumenta custo e latência. Só vale quando um único agent não consegue manter contexto ou especialização.
6. Quando usar o quê
- Chain simples — fluxo fixo, baixo risco, alta previsibilidade
- Agent + tools — precisa consultar docs, banco ou APIs de forma dinâmica
- LlamaIndex — o núcleo é RAG sobre muitos documentos
- CrewAI — tarefas longas com papéis distintos e revisão
Não comece com crew de 5 agentes. Comece com uma tool e um agent; meça qualidade e custo; só então especialize.
7. Cuidados em produção
- Loop infinito — limite de iterações (max_iterations) e de tokens
- Tools perigosas — shell, escrita em disco e HTTP externo precisam de allowlist
- Custo — logar tokens por tool call; agentes “pensam” em voz alta e gastam
- Observabilidade — trace de cada step (LangSmith, Phoenix, ou logs estruturados)
- Humano no loop — ações irreversíveis (deploy, delete, e-mail) pedem confirmação
Agentes são poderosos e frágeis. Trate-os como sistemas distribuídos: limites, retries, métricas e rollback.
8. O código explicado
Tool e prompt (LangChain)
| Trecho | O que faz |
|---|---|
{"name", "description", "parameters"} | Os três elementos de uma tool. O modelo lê a description para decidir se a chama, por isso ela deve ser clara e específica. |
@tool | Transforma a função em uma tool. O texto entre aspas triplas logo abaixo vira a descrição que o modelo lê. |
ChatOpenAI(model="gpt-4o-mini", temperature=0) | O modelo de linguagem. temperature=0 deixa as respostas mais estáveis e repetíveis. |
ChatPromptTemplate.from_messages([...]) | Monta o prompt com as mensagens de sistema e do usuário. |
("placeholder", "{agent_scratchpad}") | Espaço onde o agente registra as chamadas de tools e os resultados intermediários. |
create_tool_calling_agent(llm, [search_docs], prompt) | Cria o agente que usa o recurso nativo de chamada de ferramentas do modelo. |
AgentExecutor(agent=..., tools=..., verbose=True) | O laço que executa: pergunta ao modelo, roda a tool pedida, devolve o resultado ao modelo e repete até haver resposta final. O verbose imprime cada passo. |
executor.invoke({"input": ...}) | Executa com a pergunta. A resposta fica em result["output"]. |
LlamaIndex e CrewAI
| Trecho | O que faz |
|---|---|
SimpleDirectoryReader("./docs").load_data() | Lê os arquivos da pasta docs. |
VectorStoreIndex.from_documents(documents) | Cria os embeddings e o índice. Por padrão, o índice fica em memória. |
as_query_engine(similarity_top_k=4) | Recupera os 4 trechos mais parecidos com a pergunta e gera a resposta. |
Agent(role, goal, backstory) | Define um agente pelo papel, pelo objetivo e pelo contexto. |
Task(description=..., agent=...) | Uma tarefa atribuída a um agente. O {pergunta} é preenchido pelos inputs. |
Crew(agents=[...], tasks=[...]) e kickoff(inputs={...}) | Reúne o time e executa as tarefas em sequência. |
| Abordagem | Quem decide os passos | Custo e previsibilidade | Quando usar |
|---|---|---|---|
| Chain | você, em ordem fixa | baixo custo, previsível | fluxos lineares e bem conhecidos |
| Agent | o modelo, a cada passo | maior custo, menos previsível | quando os passos dependem da situação |
| Crew | vários agentes com papéis | o maior custo e latência | tarefas que exigem especialização separada |
As bibliotecas de agentes mudam com rapidez. Se algum import falhar, confira a documentação da versão instalada (pip show langchain) e fixe as versões no requirements.txt.
9. Erros comuns e como resolver
| Sintoma | Causa provável | Solução |
|---|---|---|
ImportError em langchain.agents | A API mudou entre versões. | Confira a documentação da versão instalada e fixe as versões. |
| Erro de autenticação do modelo | A chave da API não está definida. | Exporte OPENAI_API_KEY (ou a variável do provedor usado) no ambiente. |
| O agente nunca chama a tool | O nome ou a descrição da tool está vago. | Reescreva a descrição dizendo quando usar a tool e o que ela devolve. |
| O agente entra em laço e gasta muito | Não há limite de passos. | Defina um limite, como max_iterations no AgentExecutor. |
| O contexto estoura | A tool devolve texto demais. | Limite o tamanho do retorno e devolva só os trechos relevantes. |