Olá a todos, aqui é a Nina do agntbox.com! Hoje, quero falar sobre algo que está chamando muita atenção no meu espaço de trabalho há algumas semanas: a nova versão do LangChain.js. Mais especificamente, explorei em profundidade o seu SDK atualizado e como ele torna minha vida como desenvolvedora de agentes de IA muito mais fácil – e às vezes, um pouco mais frustrante, mas de uma maneira boa, aquela do aprendizado.
Se você acompanha minhas publicações, sabe que sou uma grande fã de JavaScript pela sua versatilidade, e quando se trata de orquestrar grandes modelos de linguagem, LangChain.js sempre foi minha referência. Mas sejamos honestos, os primeiros passos tinham suas particularidades. Configurar cadeias complexas, gerenciar a memória entre as chamadas e integrar diversas ferramentas parecia, às vezes, como tentar reunir gatos. Com as últimas atualizações do SDK, entretanto, percebo uma mudança significativa em direção a esquemas mais intuitivos e uma melhor experiência para o desenvolvedor. E, sinceramente, já era hora.
Então, ao invés de um artigo genérico do tipo “o que é LangChain.js?” (já fizemos isso!), quero compartilhar minha experiência prática com o novo SDK, focando na maneira como ele simplifica o desenvolvimento de agentes, especialmente quando você está buscando agentes que realmente podem fazer coisas no mundo real – não apenas conversar.
Meus Dores de Cabeça na Criação de Agentes, Antes da Atualização
Antes de explorar as coisas boas, deixe-me pintar um quadro das minhas lutas passadas. Eu estava trabalhando em um projeto para um cliente – vamos chamá-los de “Acme Analytics” – que precisava de um agente para realizar tarefas de análise de dados. Esse agente precisava ser capaz de:
- Acessar um banco de dados SQL para recuperar dados brutos.
- Realizar cálculos estatísticos básicos (média, mediana, etc.).
- Gerar gráficos simples usando uma biblioteca de gráficos.
- Resumir os resultados e apresentá-los ao usuário.
Parece simples, não é? Bem, integrar todas essas “ferramentas” com um LLM, gerenciar a memória conversacional e garantir que o agente pudesse decidir corretamente qual ferramenta usar em qual momento era… uma jornada. Passei uma boa parte do meu tempo lutando com a engenharia de prompts para guiar o LLM, desenhando definições de ferramentas personalizadas que se adaptassem à estrutura existente do LangChain e depurando vazamentos de memória que surgiam do nada. Parecia que eu estava apenas remendando as coisas em vez de construir elegantemente.
O Tango da “Definição de Ferramenta”
Um dos maiores pontos de dor era a definição das ferramentas. Você tinha sua função, e então a envolvia em um objeto `Tool`, garantindo que sua descrição fosse absolutamente perfeita para que o LLM pudesse entender. Se sua descrição estivesse imprecisa em uma única palavra, o LLM poderia alucinar ou simplesmente ignorar sua ferramenta. Era uma dança delicada.
// Método antigo (simplificado para o exemplo)
import { Tool } from "langchain/tools";
const sqlQueryTool = new Tool({
name: "SQL_Query_Executor",
description: "Use esta ferramenta para executar consultas SQL no banco de dados da Acme Analytics. A entrada deve ser uma instrução SQL SELECT válida. Retorna o resultado da consulta.",
func: async (query: string) => {
// ... lógica para se conectar ao DB e executar a consulta
return "Resultados da consulta...";
},
});
Isso funcionava, mas era verboso, e qualquer alteração feita na função subjacente frequentemente significava que era preciso também reajustar a descrição. Dava para sentir que estava tendo uma camada de tradução muito manual.
Com o Novo SDK LangChain.js: Um Sopro de Ar Fresco?
Quando o novo SDK começou a ser lançado, eu estava cautelosamente otimista. “Melhores definições de ferramentas”, diziam eles. “Criação de agentes simplificada”, prometiam. Meu ceticismo era alto, mas minha necessidade de um fluxo de trabalho mais suave era ainda mais forte.
Decidi reconstruir uma versão simplificada do agente Acme Analytics usando os novos modelos do SDK, concentrando-me na integração das ferramentas centrais e na orquestração do agente. E, honestamente, fiquei agradavelmente surpresa.
Ferramentas Modernas com os Esquemas Zod
A maior melhoria, para mim, foi a maneira como as ferramentas são definidas. O novo SDK se baseia fortemente no uso do Zod para a validação dos esquemas de entrada. Isso pode parecer uma pequena mudança, mas é um grande passo à frente por várias razões:
- Segurança dos Tipos: Você obtém uma verificação de tipos apropriada para suas entradas de ferramentas, o que reduz consideravelmente os erros de execução.
- Descrições Mais Claras: O Zod permite que você adicione descrições diretamente aos seus campos de esquema, que o LangChain pode então usar para gerar uma descrição de ferramenta mais precisa e legível por máquina para o LLM. Isso significa menos engenharia de prompt manual do seu lado.
- Validação Integrada: Se o LLM tentar chamar sua ferramenta com argumentos inválidos, o Zod detecta isso imediatamente, oferecendo um melhor retorno de informação para a depuração.
Vamos revisitar nossa ferramenta de consulta SQL com a nova abordagem:
// Novo método com Zod
import { DynamicTool } from "@langchain/core/tools";
import { z } from "zod";
const sqlQueryTool = new DynamicTool({
name: "SQL_Query_Executor",
description: "Executa consultas SQL no banco de dados da Acme Analytics.",
schema: z.object({
query: z.string().describe("Uma instrução SQL SELECT válida a ser executada no banco de dados."),
}),
func: async ({ query }) => {
try {
// ... lógica para se conectar ao DB e executar a consulta
console.log(`Executando a consulta SQL: ${query}`);
// Simular um chamado ao banco de dados
await new Promise(resolve => setTimeout(resolve, 500));
if (query.includes("SELECT * FROM users")) {
return JSON.stringify([{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]);
}
return JSON.stringify([{ result: "Dados recuperados com sucesso para a consulta: " + query }]);
} catch (error) {
return `Erro ao executar a consulta: ${error.message}`;
}
},
});
Você vê a diferença? A propriedade `schema`, usando `z.object` e `z.string().describe()`, fornece uma maneira muito mais estruturada e sólida de definir o que sua ferramenta espera. A `description` da própria ferramenta continua sendo importante, mas as descrições detalhadas dentro do esquema fornecem ao LLM um contexto muito melhor para cada argumento. Percebi que o LLM é muito mais eficiente em gerar chamadas de função corretas quando ele tem esses esquemas explícitos para trabalhar.
Criação de Agentes Simplificada com `createOpenAIFunctionsAgent`
Outro campo onde o novo SDK brilha é na criação de agentes. Para quem utiliza os modelos da OpenAI (o que, sejamos realistas, é o caso de muitos de nós), a função `createOpenAIFunctionsAgent` foi uma bênção. Ela cuida de muito do código padrão envolvido na configuração de um agente capaz de usar as capacidades de chamada de função da OpenAI.
Antes, eu costumava construir manualmente objetos `RunnableSequence`, encadeando cuidadosamente um `ChatPromptTemplate`, o LLM e, em seguida, um `ToolExecutor`. Isso funcionava, mas parecia que estávamos montando móveis da IKEA sem todas as instruções.
Agora, é muito mais direto:
import { ChatOpenAI } from "@langchain/openai";
import { createOpenAIFunctionsAgent, AgentExecutor } from "langchain/agents";
import { ChatPromptTemplate } from "@langchain/core/prompts";
// ... (definição de sqlQueryTool como acima)
const llm = new ChatOpenAI({
model: "gpt-4-0125-preview", // Ou qualquer que seja o modelo atual que você preferir
temperature: 0,
});
const prompt = ChatPromptTemplate.fromMessages([
["system", "Você é um assistente IA útil capaz de analisar dados. Use as ferramentas fornecidas para responder perguntas sobre os dados da Acme Analytics."],
["human", "{input}"],
["placeholder", "{agent_scratchpad}"], // Importante para o processo de reflexão interna do agente
]);
const tools = [sqlQueryTool]; // Adicione outras ferramentas aqui se necessário
const agent = await createOpenAIFunctionsAgent({
llm,
tools,
prompt,
});
const agentExecutor = new AgentExecutor({
agent,
tools,
verbose: true, // Sempre bom ver o que o agente está fazendo!
});
// Testemos isso!
const result = await agentExecutor.invoke({
input: "Você pode me dar os nomes de todos os usuários do banco de dados?",
});
console.log("Resposta final do agente:", result.output);
Este snippet de código é muito mais claro! O `createOpenAIFunctionsAgent` gerencia a lógica complexa de conversão dos chamados de função do LLM em execuções reais de ferramentas. O `AgentExecutor` orquestra todo o processo, executando o agente, verificando se deve usar uma ferramenta, executando a ferramenta e retornando o resultado ao agente para um processamento posterior. A opção `verbose: true` é uma salvação para depuração, permitindo que você veja o raciocínio do agente passo a passo.
Gestão Aprimorada da Memória (Mais um Domínio a Desenvolver, mas Melhor!)
A memória sempre foi um assunto delicado em IA conversacional. Rastrear interações passadas sem sobrecarregar a janela de contexto do LLM é um equilíbrio constante. O novo SDK não resolve magicamente todos os problemas de memória, mas fornece formas mais suaves de integrar diferentes tipos de memória.
Para meu agente Acme Analytics, precisei de um simples buffer de conversa. A integração disso com a nova configuração do agente é bastante simples:
import { BufferWindowMemory } from "langchain/memory";
const memory = new BufferWindowMemory({
k: 5, // Manter as 5 últimas interações em memória
memoryKey: "chat_history", // Isso será passado ao prompt
returnMessages: true,
});
// ... (restante da configuração do agente)
// Modificar o prompt para incluir o histórico de chat
const promptWithMemory = ChatPromptTemplate.fromMessages([
["system", "Você é um assistente IA útil capaz de analisar dados. Use as ferramentas fornecidas para responder perguntas sobre os dados da Acme Analytics."],
new MessagesPlaceholder("chat_history"), // Espaço reservado para a memória
["human", "{input}"],
["placeholder", "{agent_scratchpad}"],
]);
const agentWithMemory = await createOpenAIFunctionsAgent({
llm,
tools,
prompt: promptWithMemory,
});
const agentExecutorWithMemory = new AgentExecutor({
agent: agentWithMemory,
tools,
memory, // Passar a memória aqui
verbose: true,
});
// Exemplo de interação
await agentExecutorWithMemory.invoke({
input: "Oi, o que você pode fazer?",
});
await agentExecutorWithMemory.invoke({
input: "Você pode me dar os nomes de todos os usuários do banco de dados?",
});
// A memória agora vai manter a interação "Oi, o que você pode fazer?"
O `MessagesPlaceholder` no prompt é crucial, permitindo que o `AgentExecutor` injete o `chat_history` da `BufferWindowMemory` diretamente no prompt. Embora os limites da janela de contexto ainda sejam uma realidade, essa integração torna a gestão desse histórico muito mais fluida do que antes.
Dicas práticas para seu próximo projeto de IA
Assim, depois de passar um bom tempo com o novo SDK LangChain.js, aqui está o que aprendi e o que recomendo se você estiver explorando o desenvolvimento de agentes:
-
Adote Zod para definições de ferramentas:
Sinceramente, é uma mudança significativa. Isso torna suas ferramentas mais sólidas, mais fáceis de entender para o LLM e oferece uma melhor segurança de tipo. Invista o tempo necessário desde o início para definir corretamente seus esquemas de ferramentas.
// Sempre definir um esquema claro para suas ferramentas const myNewTool = new DynamicTool({ name: "WeatherDataFetcher", description: "Recupera os dados meteorológicos atuais para uma determinada cidade.", schema: z.object({ city: z.string().describe("O nome da cidade para a qual recuperar o clima."), unit: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("A unidade de temperatura a ser retornada."), }), func: async ({ city, unit }) => { // ... lógica de chamada da API de clima return `O clima em ${city} é de 25 graus ${unit}.`; }, }); -
Comece com `createOpenAIFunctionsAgent` (se você estiver usando OpenAI):
Exceto se você tiver razões muito específicas para não fazê-lo, essa função simplifica enormemente a criação de agentes. Ela lida com as sutilezas da API de chamada de funções da OpenAI, permitindo que você se concentre em suas ferramentas e prompts.
-
Mantenha seus prompts focados e claros:
Embora com melhores definições de ferramentas, o prompt do sistema ainda seja a estrela polar do seu agente. Defina claramente seu papel, suas capacidades e todas as restrições. Use o espaço reservado `agent_scratchpad` para o monólogo interno do agente.
-
Ative `verbose: true` para depuração:
Quando as coisas dão errado (e elas dão!), `verbose: true` no seu `AgentExecutor` é seu melhor amigo. Isso imprime o raciocínio do LLM, qual ferramenta ele está tentando chamar e os resultados, ajudando a identificar rapidamente os problemas.
-
Gerencie a memória com cuidado:
Embora a integração tenha melhorado, lembre-se de que a memória custa tokens. Escolha o tipo certo de memória para seu caso de uso (por exemplo, `BufferWindowMemory` para conversas de curto prazo ou uma síntese mais sofisticada se a extensão do contexto for uma preocupação importante). Sempre inclua o `MessagesPlaceholder` em seu prompt ao usar a memória.
-
Teste de forma iterativa:
Construa uma ferramenta, teste-a. Integre-a ao agente, teste-a. Adicione outra ferramenta, teste novamente. O desenvolvimento de agentes IA é inerentemente iterativo. Pequenos testes focados economizam dores de cabeça depois.
O novo SDK LangChain.js parece representar um passo significativo em direção à facilitação do desenvolvimento de agentes IA e uma redução de erros obscuros. Não é perfeito, e sempre há uma curva de aprendizado com novas definições, mas as melhorias em relação às definições de ferramentas e orquestração de agentes tornam realmente meus projetos mais fluidos. Se você hesitar em explorar LangChain.js, ou se tiver tido uma experiência menos que satisfatória com as versões anteriores, este é o momento ideal para dar uma nova chance ao SDK atualizado.
Quais são suas experiências com o novo SDK LangChain.js? Alguma dica ou desafio interessante que você enfrentou? Deixe-me saber nos comentários abaixo! Boa codificação!
🕒 Published:
Related Articles
- La Nuova Frontiera dell’AI e i Vecchi Nemici
- Quando Sua Caixa de Ferramentas de IA Se Torna a Porta dos Fundos de Outra Pessoa
- Perchance AI Anxiety: Inside Out 2 & El Creador de Texto a Imagen que Nos Tiene Enganchados (¡y Estresados!)
- **TÍTULO: As ferramentas CLI que eu adoro e por que você também deveria amá-las**