Olá, pessoal, aqui é a Sarah do agnthq.com. Foram algumas semanas malucas, não é mesmo? Cada vez que eu fecho os olhos, aparece um novo agente de IA prometendo mudar minha vida, meu fluxo de trabalho ou pelo menos meu pedido de café. E, honestamente, muitos deles simplesmente… não cumprem. Eles são muito complexos, muito de nicho ou simplesmente não entregam o que prometem.
Mas, de vez em quando, algo genuinamente interessante surge. Algo que realmente me faz sentar e pensar: “Ok, isso pode ser útil.” Hoje, quero falar sobre um desses. Não é uma novidade brilhante, mas uma plataforma que vem evoluindo de forma constante e, na minha opinião, acaba de atingir um ponto ideal para uso prático do dia a dia: o novo framework de Agentes do LangChain com sua saída estruturada melhorada e capacidades de chamada de ferramentas.
Agora, antes que você faça uma cara de desânimo e pense: “Ótimo, outro artigo sobre LangChain”, escute o que tenho a dizer. Venho mexendo com LangChain desde praticamente o primeiro dia. Lembro dos primeiros dias, conectando LLMs e ferramentas, me sentindo como um Frankenstein digital. Era poderoso, com certeza, mas muitas vezes desajeitado, difícil de depurar e parecia um pouco como escrever código em Python 2 em 2024. As saídas podiam ser… criativas, para dizer o mínimo, e conseguir que um agente fizesse o que você queria de forma confiável, especialmente com vários passos, parecia mais uma oração do que programação.
As atualizações recentes, especialmente em relação à forma como os agentes interagem com as ferramentas e produzem saídas estruturadas, realmente mudaram o jogo para mim. Mudou de “playground experimental” para “realmente útil para meu trabalho como freelancer.” E isso é um grande negócio.
Minha frustração com agentes pouco confiáveis (e como isso ajuda)
Deixe-me pintar um cenário. Alguns meses atrás, eu estava tentando construir um agente simples para uma amiga que tem uma pequena loja de comércio eletrônico. O problema dela: os clientes frequentemente fazem perguntas muito semelhantes sobre produtos, envio e devoluções, e ela estava gastando muito tempo copiando e colando respostas. Minha ideia era um agente que pudesse:
- Consultar detalhes do produto (preço, disponibilidade) de um banco de dados fictício.
- Verificar zonas e prazos de entrega.
- Formular uma resposta educada e precisa.
Parece simples, certo? Não realmente. Minhas primeiras tentativas com LangChain foram uma bagunça. O agente às vezes alucinatava IDs de produtos, ou esquecia de chamar a ferramenta de envio, ou simplesmente dava uma resposta confusa em vez de uma resposta concisa. Fazer com que ele gerasse consistentemente um formato específico, como um objeto JSON contendo a resposta e as ferramentas que usou, foi um pesadelo. Eu passava horas tentando convencê-lo com prompts elaborados, apenas para ele falhar em um caso extremo.
É aqui que o novo framework de agentes brilha. O LangChain realmente aperfeiçoou como os agentes decidem quais ferramentas usar e, crucialmente, como eles relatam suas descobertas. É menos sobre esperar que o LLM “descubra” e mais sobre dar a ele um caminho claro e estruturado.
A ideia central: Melhor chamada de ferramentas e saída estruturada
A maior melhoria, na minha opinião, vem de uma combinação de fatores:
- Definição de Ferramentas Aprimorada: As ferramentas agora são definidas com esquemas Pydantic, tornando muito mais claro para o LLM quais entradas ele espera.
- APIs de Chamada de Funções (por exemplo, a da OpenAI): O LangChain usa isso por trás das cenas para tornar a seleção de ferramentas muito mais confiável. O LLM não apenas “adivinha” qual ferramenta usar; ele é informado explicitamente sobre as funções disponíveis e seus parâmetros.
- Parser de Saída Estruturada: Este é o Santo Graal para mim. Chega de tentar extrair uma resposta de um texto livre. Agora podemos definir exatamente qual estrutura esperamos que a resposta final do agente siga.
Vamos ver um exemplo simples para ilustrar isso. Imagine que temos uma ferramenta para obter o nível de estoque atual de um produto.
Exemplo: Uma ferramenta simples de verificação de estoque
Primeiro, definimos nossa ferramenta usando um modelo Pydantic para sua entrada:
from langchain_core.tools import tool
from pydantic import BaseModel, Field
class ProductStockInput(BaseModel):
product_id: str = Field(description="O identificador único para o produto.")
@tool("get_product_stock", args_schema=ProductStockInput)
def get_product_stock(product_id: str) -> dict:
"""
Obtém o nível de estoque atual para um dado ID de produto.
Retorna um dicionário com product_id e stock_level.
"""
# Isso normalmente consultaria um banco de dados
stock_data = {
"P101": 50,
"P102": 0, # Fora de estoque
"P103": 15
}
stock_level = stock_data.get(product_id, -1) # -1 para não encontrado
if stock_level == -1:
return {"product_id": product_id, "stock_level": "Produto não encontrado"}
return {"product_id": product_id, "stock_level": stock_level}
tools = [get_product_stock]
Note o `args_schema` aqui. Isso é crucial. Ele informa ao LLM exatamente quais argumentos `get_product_stock` espera e quais são seus tipos. Chega de ambiguidade.
Construindo o agente com saída estruturada
Agora, vamos construir um agente que usa essa ferramenta e, importante, fornece sua resposta final de forma estruturada. Para minha amiga do e-commerce, eu queria que o agente exibisse a consulta do cliente, a resposta do agente e quaisquer ferramentas que usou, tudo em um formato JSON organizado.
from langchain_openai import ChatOpenAI
from langchain import hub
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.messages import BaseMessage
from typing import List, Union, Dict, Any
# Defina o formato de saída estruturada para a resposta final do agente
class AgentResponse(BaseModel):
original_query: str = Field(description="A consulta original do cliente.")
agent_answer: str = Field(description="A resposta formulada do agente para a consulta.")
tools_used: List[str] = Field(description="Uma lista de nomes das ferramentas que o agente usou.")
metadata: Dict[str, Any] = Field(description="Qualquer metadado ou descoberta adicional das ferramentas.")
# Carregue o prompt base para o agente de ferramentas da OpenAI
prompt = hub.pull("hwchase17/openai-tools-agent")
llm = ChatOpenAI(model="gpt-4-0125-preview", temperature=0) # Usando um GPT-4 recente para confiabilidade
# Crie o agente
agent = create_openai_tools_agent(llm, tools, prompt)
# Crie o executor do agente
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Agora, definimos como o agente deve responder usando with_structured_output
# É aqui que acontece a mágica para uma saída estruturada confiável!
structured_agent_executor = agent_executor.with_structured_output(AgentResponse)
# Vamos testar!
query1 = "Qual é o nível de estoque do produto P101?"
response1 = structured_agent_executor.invoke({"input": query1})
print("\n--- Resposta 1 ---")
print(response1.json(indent=2))
query2 = "O produto P102 está disponível?"
response2 = structured_agent_executor.invoke({"input": query2})
print("\n--- Resposta 2 ---")
print(response2.json(indent=2))
query3 = "Qual é a capital da França?" # O agente não deve usar nossa ferramenta para isso
response3 = structured_agent_executor.invoke({"input": query3})
print("\n--- Resposta 3 ---")
print(response3.json(indent=2))
Quando você executa isso, verá na saída detalhada como o LLM primeiro identifica a necessidade do `get_product_stock`, chama-o com o `product_id` correto e, em seguida, usa o resultado para formular sua `agent_answer`. Mais importante, a *saída final* é um objeto `AgentResponse`, e não apenas uma string. Isso é incrivelmente poderoso para processamento posterior, registro ou até mesmo para exibir informações consistentes para um usuário.
O que eu adoro sobre `with_structured_output`
Esse método `with_structured_output` representa uma mudança significativa. Isso significa que posso integrar as respostas do agente de forma confiável em outras partes da minha aplicação. Não preciso escrever lógica de parsing frágil. Se o agente de alguma forma se desviar, o Pydantic frequentemente o identificará, fornecendo-me um erro claro em vez de falhar silenciosamente ou retornar dados irreais.
Para minha amiga do e-commerce, isso significa que seu portal de atendimento ao cliente agora pode exibir a resposta do agente com confiança, sabendo que está no formato correto. Podemos até registrar os campos `tools_used` e `metadata` para entender com que frequência o agente está usando ferramentas específicas ou se existem perguntas comuns que ele não consegue responder.
Além das ferramentas simples: Raciocínio de múltiplos passos com confiabilidade
O verdadeiro teste para um agente muitas vezes é o raciocínio de múltiplos passos. Vamos adicionar outra ferramenta: uma para obter tempos de envio estimados com base em um ID de produto e uma zona de destino.
from langchain_core.tools import tool
from pydantic import BaseModel, Field
# ... (ProductStockInput e get_product_stock permanecem os mesmos) ...
class ShippingInfoInput(BaseModel):
product_id: str = Field(description="O identificador único para o produto.")
destination_zone: str = Field(description="A zona de envio (ex: 'Zona A', 'Zona B').")
@tool("get_shipping_info", args_schema=ShippingInfoInput)
def get_shipping_info(product_id: str, destination_zone: str) -> dict:
"""
Fornece os tempos estimados de envio para um produto em uma zona específica.
Retorna um dicionário com product_id, zone e estimated_days.
"""
# Dados fictícios para envio
shipping_times = {
("P101", "Zona A"): "3-5 dias úteis",
("P101", "Zona B"): "5-7 dias úteis",
("P103", "Zona A"): "2-4 dias úteis",
("P103", "Zona B"): "4-6 dias úteis",
}
key = (product_id, destination_zone)
estimated_days = shipping_times.get(key, "Varia, por favor contate o suporte")
return {"product_id": product_id, "destination_zone": destination_zone, "estimated_days": estimated_days}
tools_multi = [get_product_stock, get_shipping_info]
# Recriar agente e executor com as novas ferramentas
agent_multi = create_openai_tools_agent(llm, tools_multi, prompt)
agent_executor_multi = AgentExecutor(agent=agent_multi, tools=tools_multi, verbose=True)
structured_agent_executor_multi = agent_executor_multi.with_structured_output(AgentResponse)
# Testar uma consulta de múltiplos passos
multi_step_query = "Qual é o estoque para P101 e quanto tempo levaria para enviar para a Zona A?"
response_multi = structured_agent_executor_multi.invoke({"input": multi_step_query})
print("\n--- Resposta de Múltiplos Passos ---")
print(response_multi.json(indent=2))
Você notará na saída detalhada que o agente agora chama inteligentemente `get_product_stock` primeiro, depois `get_shipping_info`, e combina as informações em uma resposta coerente, tudo respeitando a estrutura `AgentResponse`. Isso é um grande avanço em relação aos dias em que você tinha que encadear explicitamente essas chamadas de ferramentas ou torcer para que o LLM inferisse a sequência correta.
Minhas Conclusões & Por Que Isso Importa Agora
Então, por que estou dando tanta importância a isso agora? Porque parece que os agentes LangChain, especificamente com a combinação de `create_openai_tools_agent` e `with_structured_output`, finalmente amadureceram a um ponto onde são realmente práticos para desenvolvedores que constroem aplicações do mundo real. Chega de engenharia de prompt interminável para forçar uma saída em JSON, chega de parsing frágil de regex e significativamente menos “chamadas de ferramentas alucinatórias.”
Conselhos Práticos para Você:
- Revisite os Agentes LangChain: Se você tentou usar os agentes LangChain há um ano e ficou frustrado, agora é a hora de dar outra olhada. As melhorias na chamada de ferramentas e na saída estruturada são substanciais.
- Defina Ferramentas com Pydantic: Sempre defina suas entradas de ferramenta usando modelos Pydantic com descrições claras. Isso dá ao LLM a melhor chance de entender quando e como usar suas ferramentas.
- Adote `with_structured_output`: Este é seu melhor amigo para uma integração confiável de agentes. Defina um modelo Pydantic para a saída final do seu agente e use `agent_executor.with_structured_output(YourOutputModel)`. Isso economizará horas incontáveis de depuração e parsing.
- Comece Simples, Depois Expanda: Não tente construir um super-agente de imediato. Comece com uma ou duas ferramentas simples e uma estrutura de saída clara. Uma vez que isso esteja funcionando de forma confiável, adicione gradativamente mais complexidade.
- Use Descrições Detalhadas da Ferramenta: O campo `description` no seu decorador `@tool` é o que o LLM lê para decidir se deve usar uma ferramenta. Seja claro, conciso e explique o que a ferramenta *faz* e o que ela *retorna*.
- Use a Chamada de Funções da OpenAI: Embora este artigo se concentre no LangChain, a confiabilidade subjacente muitas vezes vem de LLMs como os modelos GPT da OpenAI, que possuem boas capacidades de chamada de funções. Certifique-se de estar usando modelos que suportam isso para os melhores resultados.
Acredito sinceramente que esses avanços tornam a construção de agentes inteligentes muito mais acessível e, mais importante, muito mais confiável. Para qualquer pessoa que está construindo recursos alimentados por IA, seja um bot de atendimento ao cliente, um assistente de análise de dados ou apenas automatizando tarefas tediosas, a capacidade de interagir de forma previsível com um agente e receber dados estruturados de volta é uma mudança significativa. Isso fez com que os agentes deixassem de ser uma demonstração interessante para se tornarem uma peça genuinamente útil do kit de ferramentas do desenvolvedor.
Isso é tudo por hoje. Vá experimentar e me diga o que você construiu! Deixe seus pensamentos e experiências nos comentários abaixo. Boa construção de agentes!
🕒 Published: