Olá, pessoal! Meu nome é Guilherme Silveira, sou instrutor e fundador aqui da Alura e estarei ministrando a aula para vocês. Por questões de acessibilidade, vou me descrever:
Audiodescrição: Guilherme se declara uma pessoa branca de cabelos pretos. Veste uma camiseta cheia de traçados cinzas na vertical e na horizontal. Ao fundo, há uma parede iluminada na cor verde e azul.
Vamos aprender a utilizar uma inteligência artificial baseada em LLMs (Modelos de Linguagem), dando continuidade ao curso de LangChain.
Como pré-requisito, é necessário ter feito o curso de LangChain. Faça isso primeiro, se ainda não o fez, e depois volte aqui para continuar.
Desejamos que nossa inteligência artificial generativa não apenas siga comandos sequenciais, mas também tome decisões automatizando o processo de tomada de decisão.
Por exemplo, suponha que estamos em uma escola de ensino médio, com estudantes se formando todos os anos. Alguns deles estão se formando no terceiro ano de ensino médio e estão procurando universidades para ingressar. Agora, precisamos decidir qual universidade recomendamos para cada estudante, quais vestibulares eles devem fazer, o que precisam estudar mais, o que precisam reforçar.
Temos várias decisões a serem tomadas. Às vezes, conhecemos professores em algumas universidades e entramos em contato para recomendar um estudante. Uma pergunta muito básica como "Que universidade você recomenda?" pode desencadear uma série de considerações.
Quais são os dados do estudante? Como ele se saiu em determinados assuntos no passado e neste ano? Quais são as universidades que têm perfis semelhantes a este? O estudante tem preferências por determinadas universidades? Ele prefere se mudar para fora do Brasil, ficar no Brasil, na cidade em que está?
Temos todas essas considerações e ferramentas à nossa disposição. Conseguimos pegar uma pergunta complexa, quebrá-la em partes menores e tomar decisões de acordo com as ferramentas que temos acesso. Temos rankings de universidades, um banco de dados com os dados do estudante dos últimos anos, contatos de pessoas que trabalham em certas universidades em nossos e-mails.
Como um agente humano, que decisão tomamos? Pegamos a pergunta, quebramos em partes e decidimos como respondê-la. Primeiro, usamos uma ferramenta de busca de dados para buscar os dados do estudante, depois usamos uma ferramenta de busca de dados para buscar professores que estudam em determinada universidade, para ver se temos um contato de algum deles em nossa ferramenta de busca de e-mails.
Todas essas decisões, esse plano de ação, é baseado na pergunta e nas ferramentas que temos disponíveis. Vamos aprender a criar um agente que é uma inteligência artificial. Essa decisão de qual é o plano de ação, quais são as ferramentas que vamos utilizar, e utilizar as ferramentas e executar o plano de ação, é o agente que vai fazer.
Vamos programar um agente capaz de responder diversas perguntas. No arquivo main.py
, temos:
// código omitido
pergunta = "Quais os dados de Ana?"
pergunta = "Quais os dados de Bianca?"
pergunta = "Quais os dados de Ana e da Bianca?"
pergunta = "Crie um perfil acadêmico para a Ana!"
pergunta = "Compare o perfil acadêmico da Ana com o da Bianca!"
pergunta = "Tenho sentido Ana desanimada com cursos de matemática. Seria uma boa parear ela com a Bianca?"
pergunta = "Tenho sentido Ana desanimada com cursos de matemática. Seria uma boa parear ela com o Marcos?"
pergunta = "Quais os dados da USP?"
pergunta = "Quais os dados da uNiCAmP?"
pergunta = "Quais os dados da uNi CAmP?"
pergunta = "Quais os dados da uNicomP?"
pergunta = "Dentre USP e UFRJ, qual você recomenda para a acadêmica Ana?"
pergunta = "Dentre uni camp e USP, qual você recomenda para a Ana?"
pergunta = "Quais as faculdades com melhores chances para a Ana entrar?"
pergunta = "Dentre todas as faculdades existentes, quais Ana possui mais chance de entrar?"
pergunta = "Além das faculdades favoritas da Ana existem outras faculdades. Considere elas também. Quais Ana possui mais chance de entrar?"
// código omitido
Por exemplo, "Quais os dados da Ana?", "Quais os dados da Bianca?", "Quais os dados da Ana e da Bianca?", "Crie um perfil acadêmico para ela.", "Compare o perfil acadêmico de duas pessoas.", "Estou sentindo a Ana desanimada com matemática. Será que o Marcos poderia ajudar ela com matemática? Ou será que a Bianca poderia ajudar ela com matemática?".
Continuando: "Quais são os dados da USP?", "Quais são os dados entre a Unicamp e a USP?", "Qual você recomenda para a Ana?", "Além das universidades favoritas da Ana, existem outras universidades que você recomenda?"
O agente que vamos implementar vai quebrar todas as perguntas humanas em um plano de ação. Ele buscará esses dados, cruzará informações e realizará o trabalho necessário. Há condições e tarefas que serão executadas pelo agente, não por nós. É a inteligência artificial do agente que estará atuando, não nós.
Vamos programar esse agente utilizando LLMs.
Até breve!
Neste projeto, utilizaremos o OpenAI e o LangChain, ferramentas que já foram empregadas no curso anterior, sendo um pré-requisito para este. No arquivo README.md
, estão contidas instruções para configurar o ambiente Python.
.venv
e ativando o ambientePara iniciar, abrimos um novo terminal clicando nos três pontos "…" na parte superior e depois nas opções "Terminal > New Terminal" ("Ctrl + Shift + '").
Nele, executamos o comando python -m venv .venv
para criar o diretório .venv
, onde os módulos serão instalados.
python -m venv .venv
Em seguida, ativamos o ambiente com o comando .venv/Scripts/activate
.
.venv/Scripts/activate
Será exibido "(.venv) PS
" antes de D:\CURSO 3860\langchain-agentes>
. Estamos usando o diretório .venv
para instalar as dependências.
Agora, vamos instalar as dependências com o comando pip install -r requirements.txt
.
pip install -r requirements.txt
As dependências já estão definidas e são as que utilizamos no curso anterior, quase todas. São elas: OpenAI, LangChain e a configuração de chaves no ambiente. Podemos observar isso no arquivo requirements.txt
.
requirements.txt
openai==1.13.3
langchain==0.1.11
langchain-openai==0.0.8
python-dotenv==1.0.1
main.py
Criaremos o arquivo main.py
, que vai definir uma pergunta. Para isso, clicamos com o botão direito no projeto e selecionamos a opção "New File" ("Novo arquivo") e digitamos "main.py". Neste arquivo, digitamos pergunta =
.
A pergunta que desejamos que o agente responda é: "Quais os dados da Ana?".
main.py
pergunta = "Quais os dados da Ana?"
Se importarmos uma LLM e fizermos a pergunta "Quais os dados da Ana?", ela inventará uma Ana e os dados, ou dirá que não conhece Ana nem os dados.
O que devemos fazer? Se somos um agente e nos dirigimos a Guilherme, que é um ser inteligente, e perguntamos: "Guilherme, quais são os dados da Ana?", o que Guilherme faz? A primeira coisa é perceber que a pessoa está pedindo os dados de alguém. Então, como agente inteligente, Guilherme processa a pergunta.
O primeiro passo é: precisamos processar essa pergunta e tentar entender qual é a ferramenta que Guilherme tem à disposição na cabeça dele, de matemática, física, geografia, etc., que essa pessoa está desejando acessar. Essa pessoa está desejando acessar dados da Ana.
Então, ela quer acessar as ferramentas do Guilherme que extraem dados da Ana. Essa é a primeira coisa que o agente Guilherme inteligente faz. E é isso que o nosso agente tem que ser capaz de fazer.
Como ela vai ser capaz de fazer isso? Criamos um agente, mas esse agente tem que ter uma ferramenta capaz de extrair dados de um estudante.
DadosDeEstudante()
Vamos criar essa classe? Criaremos essa classe chamada DadosDeEstudante()
que estende de BaseTool
do OpenAI.
main.py
class DadosDeEstudante(BaseTool):
pergunta = "Quais os dados da Ana?"
Seguiremos a orientação a objetos, conforme recomendado por eles. Para isso, importamos BaseTool usando from langchain.tools import BaseTool
.
from langchain.tools import BaseTool
class DadosDeEstudante(BaseTool):
pergunta = "Quais os dados da Ana?"
Agora podemos proceder com a implementação.
Como é que implementamos? Primeiro, definimos qual é o nome dessa ferramenta: name = "DadosDeEstudante"
. E vamos dar uma descrição (description
). Colocamos em várias linhas com aspas.
from langchain.tools import BaseTool
class DadosDeEstudante(BaseTool):
name = "DadosDeEstudante"
description = """"""
pergunta = "Quais os dados da Ana?"
O que essa ferramenta vai fazer? Esta ferramenta é para o Guilherme humano. É como se estivéssemos dizendo: Guilherme, esta ferramenta é capaz de, dado o nome de um estudante, extrair informações e dados sobre ele. É isso que vamos inserir na descrição: Esta ferramenta extrai o histórico e preferências de um estudante de acordo com seu histórico
.
from langchain.tools import BaseTool
class DadosDeEstudante(BaseTool):
name = "DadosDeEstudante"
description = """Esta ferramenta extrai o histórico e preferências de um estudante de acordo com seu histórico"""
pergunta = "Quais os dados da Ana?"
Essa é a descrição do que a ferramenta realiza, ou seja, será capaz de extrair os dados de um estudante. Para fazer isso, precisamos escrever o código. Criamos uma função que executa a tarefa com def run(self, input: str):
. Essa função receberá a si mesma e um input
, que é a pergunta: "Quais os dados da Ana?"
.
from langchain.tools import BaseTool
class DadosDeEstudante(BaseTool):
name = "DadosDeEstudante"
description = """Esta ferramenta extrai o histórico e preferências de um estudante de acordo com seu histórico"""
def run(self, input: str):
pergunta = "Quais os dados da Ana?"
Dado um string, devolvemos outra string. Para isso, adicionamos -> str
. Lembre-se, LLM trabalha com strings. Portanto, recebemos e devolvemos uma string, por padrão.
from langchain.tools import BaseTool
class DadosDeEstudante(BaseTool):
name = "DadosDeEstudante"
description = """Esta ferramenta extrai o histórico e preferências de um estudante de acordo com seu histórico"""
def run(self, input: str) -> str:
pergunta = "Quais os dados da Ana?"
Imagine que o input
é a pergunta. O que temos que fazer com essa pergunta? Sabemos que essa pessoa quer extrair dados, caso contrário, não estaria utilizando essa ferramenta. Se estamos usando uma régua, é porque a pessoa quer medir algo.
O que ela quer medir? Se analisarmos a frase que ela disse, por exemplo "Guilherme, meça esse mouse para mim, por favor.", precisamos extrair a palavra "mouse". Ou seja, dada a pergunta, sabemos que ela está falando de dados, caso contrário, não estaria usando essa ferramenta. Mas de quem? Precisamos extrair a palavra "Ana".
Então, aqui está a nossa frase: "Quais os dados da Ana?". Precisamos extrair a palavra "Ana". Como fazemos isso? Usamos a LLM. Consultamos a LLM e perguntamos: qual é o nome da pessoa mencionada nessa pergunta? Queremos saber o nome da pessoa mencionada na pergunta.
O que o def run()
vai fazer? Irá criar uma LLM para nós. Precisamos de uma LLM, então, digitamos llm =
. E usaremos a LLM chamada ChatOpenAI()
, que já utilizamos no curso anterior.
O model
("modelo") será o gpt-4o
e passamos a nossa chave, que é api_key
, igual a os.getenv("OPENAI_API_KEY")
. Logo após, precisamos importar o os
e o ChatOpenAI de from.langchain_openai import ChatOpenAI
.
from langchain.tools import BaseTool
import os
from langchain_openai import ChatOpenAI
# código omitido
def run(self, input: str) -> str:
llm = ChatOpenAI(model="gpt-4o"),
api_key=os.getenv("OPENAI_API_KEY"))
pergunta = "Quais os dados da Ana?"
Agora, criaremos a variável de ambiente.
No curso anterior, usamos uma biblioteca chamada dotenv
para isso. Primeiro, carregamos a biblioteca para poder utilizá-la. Usamos from dotenv import load_dotenv
. Na sequência, pedimos para carregar o dotenv
com load_dotenv()
.
from langchain.tools import BaseTool
import os
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
load_dotenv()
# código omitido
O dotenv
era um arquivo chamado .env
onde escrevíamos a chave openai_key
que temos. Para isso, clicamos com o botão direito na raiz do projeto e selecionamos a opção "New File" e digitamos ".env".
Criaremos uma chave usando OPENAI_API_KEY
.
.env
OPENAI_API_KEY
Vamos gerá-la agora.
Voltamos ao navegador com a aba aberta no OpenIA. Com a janela "Create new secret key" aberta, clicamos em "Create secret key" na parte inferior direita. Copiamos a chave gerada selecionando "Copy" à direita da sequência de caracteres.
Assim que terminarmos o curso, vamos desabilitar essa chave.
Voltamos ao arquivo .env
e colamos a chave:
.env
OPENAI_API_KEY = SequênciaDeCaracteres
Salvamos e temos essa nossa chave.
Portanto, quando chamarmos o método run()
do arquivo main.py
, ele vai estabelecer uma comunicação com a LLM para nós. Agora é o nosso trabalho decidir o que faremos com essa LLM: desejamos executar uma pequena cadeia de um passo.
Após o llm
, digitamos PromptTemplate()
. Esse PromptTemplate()
recebe um template específico. Vamos colocá-lo entre três aspas, que é: "Você deve analisar a {input} para extrair o nome de usuário informado."
Iremos extrair da palavra "input". Logo após, especificamos o formato de saída. Na linha seguinte, digitamos "Formato de saída: {formato_saida}
".
Este é o nosso template
. Portanto, inserimos template =
antes do PromptTemplate()
.
main.py
# código omitido
def run(self, input: str) -> str:
llm = ChatOpenAI(model="gpt-4o"),
api_key=os.getenv("OPENAI_API_KEY"))
template = PromptTemplate(template="""Você deve analisar a {input} para extrair o nome de usuário informado.
Formato de saída:
{formato_saida}""",
)
pergunta = "Quais os dados da Ana?"
Lembra do template? Era o prompt template e como o criávamos. Passaremos mais um parâmetro após o formato da saída.
Inserimos as variáveis de input, conhecidas como input_variables
. Elas constituem o único tipo de input que utilizamos. Além disso, há as variáveis parciais
, chamadas partial_variables
, que especificam o formato desejado de saída: partial_variables={"formato_saida" : }
.
Precisamos criar um formatador. Para isso, vamos utilizar um parser
. Anteriormente, desenvolvemos parser
de formatação que incluíam a função get_format_instructions
.
# código omitido
def run(self, input: str) -> str:
llm = ChatOpenAI(model="gpt-4o"),
api_key=os.getenv("OPENAI_API_KEY"))
template = PromptTemplate(template="""Você deve analisar a {input} para extrair o nome de usuário informado.
Formato de saída:
{formato_saida}""",
input_variables=["input"],
partial_variables={"formato_saida" : parser.get_format_instructions()})
pergunta = "Quais os dados da Ana?"
Portanto, precisaremos importar o PromptTemplate e o parse. Subimos para o começo do arquivo e digitamos os seguintes imports
:
# código omitido
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import JsonOutputParser
# código omitido
Precisamos criar o parser
que estamos planejando ter.
No template
, após o ChatOpenAI()
, pulamos uma linha e definimos o formato de saída: um parser
chamado jsonOutputParser()
, que se baseia em um objeto Python (pydantic_object=
) denominado ExtratorDeUEstudante
.
# código omitido
def run(self, input: str) -> str:
llm = ChatOpenAI(model="gpt-4o"),
api_key=os.getenv("OPENAI_API_KEY"))
parser = jsonOutputParser(pydantic_object=ExtratorDeUEstudante)
# código omitido
O ExtratorDeEstudante
irá extrair um estudante. Para informar isso, subimos o arquivo e, após o load_dotenv()
, criaremos uma classe chamada ExtratorDeEstudante()
que extrai o nome do estudante para nós.
Essa classe será um modelo BaseModel
utilizado na LLM para extrair o nome do estudante
, que é um campo em formato de string: estudante: str = Field("Nome do estudante informado, sempre em letras minúsculas. Exemplo: joão, carlos, joana, carla")
. São alguns exemplos que podemos utilizar.
# código omitido
class ExtratorDeEstudante(BaseModel):
estudante: str = Field("Nome do estudante informado, sempre em letras minúsculas. Exemplo: joão, carlos, joana, carla")
# código omitido
Precisamos importar tudo isso que mencionamos. Para isso, subimos o código e inserimos o seguinte import
:
# código omitido
from langchain_core.pydantic_v1 import Field, BaseModel
# código omitido
Assim, configuramos a llm
, definimos o formato de saída com parser
e preparamos um modelo para extrair a palavra "Ana" desta parte do texto.
Agora desejamos tentar executar. Para executar, vamos pegar nosso template
, passá-lo pela | llm |
e, depois de rodar o template
pela llm
, queremos extrair o parser
, a saída.
Qual é a saída do parser
? Será a saída da pessoa usuária. Chamaremos isso de cadeia
(chain).
# código omitido
partial_variables={"formato_saida" : parser.get_format_instructions()})
cadeia = template | llm | parser
pergunta = "Quais os dados da Ana?"
Essa é a cadeia que desejamos executar.
Invocamos essa cadeia
com .invoke({"input" : input})
. E tudo isso nos retornará a resposta
.
# código omitido
cadeia = template | llm | parser
resposta = cadeia.invoke({"input" : input})
pergunta = "Quais os dados da Ana?"
A resposta vai ter um campo chamado estudante. Usamos print(resposta)
para imprimir a resposta para verificá-la, e retornamos resposta['estudante']
para verificar se funciona.
# código omitido
cadeia = template | llm | parser
resposta = cadeia.invoke({"input" : input})
print(resposta)
return resposta['estudante']
pergunta = "Quais os dados da Ana?"
Criamos uma cadeia que extrai o nome do estudante. Por enquanto, apenas extraímos o nome, mas ainda não capturamos os dados completos. Queremos ver o agente Guilherme utilizando essa ferramenta.
Então, vamos executá-lo? Criamos um objeto DadosDeEstudante()
após a pergunta
, chamamos o método run()
com a pergunta. Primeiro, vamos executá-lo isoladamente, depois adicionamos um agente. Para isso, definimos que a resposta é essa e depois imprimimos a resposta com print(resposta)
.
# código omitido
cadeia = template | llm | parser
resposta = cadeia.invoke({"input" : input})
print(resposta)
return resposta['estudante']
pergunta = "Quais os dados da Ana?"
DadosDeEstudante().run(pergunta)
print(resposta)
Vamos tentar rodar, mas não garantimos que vai funcionar. Para tal, clicamos no ícone de play na parte superior direita.
O retorno abaixo foi parcialmente transcrito:
TypeError: Can't instantiate abstract class DadosDeEstudante without an implementation for abstract method '_run'
Tentamos rodar e ele disse que não pode instanciar porque falta o método run. Realmente, está faltando. O run()
tem um underline antes.
# código omitido
def _run(self, input: str) -> str:
# código omitido
Rodamos novamente e obtemos:
{'estudante': 'ana'}
Obtivemos o como retorno um JSON, que veio formatado corretamente, onde conseguimos extrair a palavra "Ana". Podemos até remover o print(resposta)
que colocamos antes do return resposta['estudante']
.
# código omitido
cadeia = template | llm | parser
resposta = cadeia.invoke({"input" : input})
return resposta['estudante']
pergunta = "Quais os dados da Ana?"
DadosDeEstudante().run(pergunta)
print(resposta)
Em resumo, temos uma ferramenta que, por enquanto, só consegue extrair a palavra Ana.
Agora, duas coisas são interessantes. Primeiro, ela lê dados de um arquivo CSV, de um banco de dados SQL, ou de qualquer outra fonte onde estejam os dados da Ana. Isso é muito importante.
Mas isso é um trabalho de banco de dados. Resolveremos isso. Mas o mais importante, viemos aqui para ele descobrir que esta é a ferramenta que ele deseja utilizar. A ideia não é simplesmente usar a LLM, já sabemos como usá-la. Aprendemos em um curso do LangChain como usar uma sequência. O que queremos agora é que ela perceba.
A LLM precisa entender que, ao receber a pergunta "Quais os dados da Ana?", deve utilizar essa ferramenta. Não deve inventar, mas sim mencionar as ferramentas disponíveis.
Vamos observar isso acontecer no próximo vídeo. Até lá!
Olá, pessoal! Para continuar, vamos fechar o terminal e o README
. Temos uma ferramenta e uma LLM (Language Model) pura, imaginemos, que não conhece essa ferramenta. Vamos criar essa LLM pura, representada por llm
e igual a ChatOpenAi
, como fizemos antes:
main.py
llm = ChatOpenAI(model="gpt-4o",
api_key=os.getenv("OPENAI_API_KEY"))
A llm
é uma conexão com uma LLM, e não sabe de nada nem ninguém. E temos várias ferramentas, que são as nossas tools
, onde vamos criar uma nova tool.
Para criar uma tool, usamos Tool
com "T" maiúsculo, e passamos três argumentos: o nome da nossa ferramenta (name
), o método "run" dessa ferramenta, que é a função (func
), e a descrição (description
) dessa ferramenta.
tools = [
Tool(name=,
func=,
description=)
]
Já temos essas três informações na classe DadosDeEstudante
. Então, basta instanciarmos DadosDeEstudante
.
Para isso, antes de definir as ferramentas que a nossa LLM vai ter em tools
, vamos criar a variável dados_de_estudante
, que recebe DadosDeEstudante()
:
dados_de_estudante = DadosDeEstudante()
Agora, na ferramenta Tool
, podemos definir o nome como dados_de_estudante.name
, a função dados_de_estudante.run
e a descrição dados_de_estudante.description
. Nossa Tool
ficará assim:
tools = [
Tool(name=dados_de_estudante.name,
func=dados_de_estudante.run,
description=dados_de_estudante.description)
]
Vamos comentar as linhas posteriores, de resposta
, pois temos interesse apenas em criar essa ferramenta por enquanto.
# resposta = DadosDeEstudante().run(pergunta)
# print(resposta)
Também precisamos importar o Tool
de langchain.agents
, no topo do arquivo:
from langchain.agents import Tool
Agora, temos uma LLM que não sabe nada e um conjunto de ferramentas. Queremos agora perguntar para essa LLM: "Quais são os dados da Ana?". Então, a LLM deve conseguir dizer "Para responder essa pergunta, eu preciso usar a ferramenta dadosdeestudante
", e, claro, usar a ferramenta dados_de_estudante
! Ela precisa realizar as duas tarefas.
Então agora, sim, queremos criar um agente de verdade. Vamos criar uma primeira versão dele usando a OpenAI. Para isso, declaramos agente
e chamamos create_openai_tools_agent()
, passando a llm
limpa como parâmetro, além das ferramentas que temos disponíveis, que estão em tools
.
agente = create_openai_tools_agent(llm, tools)
Vamos passar também um prompt de inicialização, porque a LLM não sabe o que é uma ferramenta. Precisamos escrever um prompt descritivo para essa tarefa, como: "Cara LLM, adoraria notificá-la que existe uma ferramenta chamada DadosDeEstudante que, se algum dia, por ventura, uma pessoa desejar extrair dados de estudante, use ela, não use outra".
Mas, dessa forma, precisaríamos fazer isso para cada uma das ferramentas que criarmos. Mas já temos essas informações contidas em tools
, com cada nome, função e descrição. Então, vamos passar um prompt para falar para a LLM apenas: "Temos as seguintes ferramentas disponíveis, use-as". Precisamos disso para ter um agente.
Esse prompt já está pronto e disponível no LangSmith, um repositório de vários tipos de prompts e conversações previamente preparadas para nós!
Vamos entrar na página do LangSmith para consultar esse repositório. Por exemplo, podemos utilizar o openai-functions-agent
, cujo prompt de sistema é "You are a helpful assistant" ("Você é um assistente prestativo"), bastante curto.
O instrutor também recomenda o
react-chat
, cujo prompt é bem mais longo e descritivo. Mas, como estamos usando um modelo de agente que utilizafunctions
, uma API específica da OpenAI, o prompt pode ser mais genérico.
Vamos retornar ao Visual Studio Code e importá-lo no início do arquivo com o seguinte código fornecido pelo repositório:
from langchain import hub
Agora, abaixo de tools
, definimos o prompt
como hub.pull("hwchase17/openai-functions-agent")
. Podemos dar print
nesse prompt
para visualizar seu conteúdo quando ele for executado e verificar que está funcionando:
prompt = hub.pull("hwchase17/openai-functions-agent")
print(prompt)
Agora precisamos instalar o repositório langchainhub
, porque não tínhamos usado ele antes. Vamos usar a versão mais recente em junho de 2024, a 0.1.15
(se for o caso, você pode usar versões mais recentes):
requirements.txt
langchainhub==0.1.15
Depois, rodamos pip install -r .\requirements.txt
no terminal e finalizamos a instalação.
Se executamos main.py
, recebemos no terminal o prompt esperado, então isso significa que ele está funcionando!
Agora, no nosso agente
, vamos também passar prompt
como parâmetro:
main.py
agente = create_openai_tools_agent(llm, tools, prompt)
Agora precisamos importar o create_openai_tools_agent
de langchain.agents
:
from langchain.agents import create_openai_tools_agent
Com isso, importamos o template de prompt e conseguimos criar o agente ao executar o código. Então, agora temos um agente!
Mas, ter um agente não é o suficiente, porque agora precisamos executá-lo.
Para executar um agente, precisamos de um executor, ou um AgentExecutor()
. Esse método vai receber o agente
que criamos, afinal, ele precisa saber que agente executar. O executor também vai receber as ferramentas, tools
.
AgentExecutor(agent=agente, tools=tools)
Podemos passar outros argumentos para ele posteriormente, o que faremos um a um para verificar os resultados.
Vamos importar também o AgentExecutor
, também do langchain.agents
:
from langchain.agents import create_openai_tools_agent, AgentExecutor
Salvamos e rodamos.
Agora, vamos executar esse agente, de fato. Para isso, chamamos o executor
junto do método invoke()
para invocar algo, como já conhecemos. Vamos usar como input a nossa pergunta
, que vai nos devolver uma resposta
. Também vamos dar um print
na nossa resposta
para conferi-la:
resposta = executor.invoke({"input" : pergunta})
print(resposta)
Mas, ao executar o código para testar, recebemos no terminal a resposta: "Para cumprir a solicitação, preciso que você forneça informações sobre a Ana". Por que não funcionou? Para descobrir, vamos analisar o log. Passamos no executor
a opção verbose
igual a true
. Isso vai mostrar para nós passo a passo do que foi executado.
AgentExecutor(agent=agente, tools=tools, verbose=True)
Vamos rodar novamente, e agora podemos acompanhar cada execução conforme elas acontecem. DadosDeEstudante
com Ana
foi invocado, sendo Ana
com "A" maiúsculo. Então, ele devolve a palavra "ana" com "a" minúsculo (a resposta de DadosDeEstudante
). Correto!
Mas a resposta da LLM traz o nome da Ana, a idade de 22 anos, a faculdade de Engenharia de Software que ela cursa, o período, preferências de estudo, média geral, áreas de interesse, etc.
Ou seja, a LLM inventou essa resposta, sem base na nossa ferramenta. No entanto, ele encontrou a ferramenta DadosDeEstudante
, chamou o estudante certo com a palavra "Ana", devolveu a palavra "ana", mas depois inventou.
Tentando novamente, a LLM não inventa informações, mas responde: "Os dados solicitados são referentes à Ana. Você deseja mais informações específicas sobre ela..?". Isso está correto, porque devolvemos apenas o nome da Ana, mas não os seus dados, então a LLM não pode nos ajudar com o que pedimos.
Às vezes ela decide inventar, e às vezes decide não inventar. Mas, o importante é que ela achou a ferramenta!
Agora que já sabemos quem é o estudante
, podemos substituir o return
pela declaração da variável estudante
dentro do run
, para salvar o resultado nela:
estudante = resposta['estudante']
Agora basta buscar esse estudante no nosso arquivo para retornar os seus dados. Vamos criar uma função, nesse arquivo mesmo, por enquanto, chamada busca_dados_de_estudante
, que vai receber o estudante
como parâmetro.
Essa função vai usar a biblioteca Pandas para ler um arquivo para nós. Então, chamamos o método pd.read.csv()
para ler um arquivo CSV. O caminho para esse arquivo CSV é "documentos/estudantes.csv"
, que passamos por parâmetro. Isso deve nos devolver os dados
, então os salvamos nessa variável: dados = pd.read_csv("documentos/estudantes.csv")
.
Depois, de dados
, vamos buscar o registro cujo campo USUARIO
seja igual a esse estudante
Vamos salvar esse resultado na variável dados_com_esse_estudante
. Essa é uma busca bem simples, mas pode ser feita uma busca no SQL ou uma busca mais inteligente.
E o que vamos retornar dessa função? Se estiver vazio, retornamos vazio. Então, if dados_com_esse_estudante.empty
, retornamos um dicionário vazio (return {}
). Se não, retornamos a primeira linha de dados_com_esse_estudante
, então, no caso do Pandas, usamos iloc[]
e passamos :1
, que significa "até o 1", representando apenas a primeira linha. Então adicionamos esse resultado a um dicionário com to_dict()
.
Nossa função ficará assim:
def busca_dados_de_estudante(estudante):
dados = pd.read_csv("documentos/estudantes.csv")
dados_com_esse_estudante = dados[dados["USUARIO"] == estudante]
if dados_com_esse_estudante.empty:
return {}
return dados_com_esse_estudante.iloc[:1].to_dict()
Como usamos o Pandas, precisamos importar essa biblioteca no início do nosso arquivo:
main.py
import pandas as pd
Também precisamos adicioná-la ao arquivo de requisições. Vamos instalar a versão atual, 2.2.2:
requirements.txt
pandas==2.2.2
E concluímos a instalação com pip install
no terminal.
Se você nunca usou Pandas, não se preocupe. Aprender Pandas não é o objetivo desse curso.
Agora precisamos criar o diretório documentos
no nosso projeto e, dentro dele, criar o arquivo estudantes.csv
. O conteúdo desse arquivo está disponível para acesso na atividade de preparação de ambiente desta aula. Com ele aberto, copiamos e colamos no arquivo que acabamos de criar.
O VS Code pode sugerir a instalação do plugin Rainbow CSV. Você pode instalá-lo, caso queira deixar o código CSV mais colorido e identificar os dados facilmente.
Temos vários estudantes cadastrados nesse arquivo, como a Ana
, que tem o usuário ana
, Ariel
, Marcos
, Bianca
, etc. Temos nossa base de dados para consulta.
Agora, na classe DadosDeEstudante
, quando já temos o estudante
, vamos chamar a função busca_dados_de_estudante()
, passando estudante
como parâmetro, e salvar o resultado na variável dados
. Com isso, vamos ler o nosso arquivo ou banco de dados e, depois, retornar os dados desse estudante (return dados
).
Mas precisamos tomar cuidado. Nossos dados estão num dicionário do Python, e queremos transformar isso num dicionário em texto string. Para isso, vamos precisar transformar num JSON. Então, no retorno, podemos fazer um json.dumps
para criar uma string baseada nos dados
desse estudante.
Por fim, podemos imprimir os dados
para saber o que foi salvo dentro dessa variável após a execução. Antes, podemos imprimir a string "Achei" para indicar que os dados foram encontrados. Com isso, teremos:
main.py
class DadosDeEstudante(BaseTool):
def _run(self, input: str) -> str:
# código omitido
dados = busca_dados_de_estudante(estudante)
print("Achei")
print(dados)
return json.dumps(dados)
Agora precisamos importar o json
no início do arquivo:
import json
Vamos salvar o arquivo e executá-lo para testar. No terminal, podemos visualizar o passo a passo da execução. Primeiramente, temos um indicativo de sucesso da execução com a mensagem "Invoking DadosDeEstudante
with Ana
".
Depois disso, a mensagem "Achei" com os dados da Ana são impressas em seguida, devolvendo-os para a LLM. Então, a LLM respondeu:
Aqui estão os dados da Ana:
- Nome: Ana
- Usuário: ana
- Ano de Formatura: 2029
- Scores:
- Matemática: 4
- ...
- Áreas Preferidas: Humanas ...
Está tudo correto conforme a base de dados que indicamos para a LLM. Ou seja, nossa função conseguiu ler essa base corretamente e devolver os dados para nós, organizados em um texto.
Então, temos uma ferramenta! Agora, da mesma forma que criamos essa ferramenta, podemos criar inúmeras outras.
Podemos testar a busca de outros estudantes, mudando a pergunta
. Para buscar os dados da Bianca
, podemos apenas trocar o nome:
pergunta = "Quais os dados de Bianca?"
E executamos o arquivo novamente. Nossa função vai buscar a palavra Bianca
no CSV, ou no nosso banco de dados, e trazer os dados dela:
Aqui estão os dados de Bianca:
- Nome: Bianca
- Usuário: bianca
- Ano de Formatura: 2029
- Scores:
- Matemática: 3
- ...
- Áreas Preferidas: Ciências ...
Para continuar, primeiro podemos melhorar esse código. Depois, vamos adicionar mais ferramentas. Vamos lá!
O curso LangChain: desenvolva agentes de inteligência artificial possui 119 minutos de vídeos, em um total de 33 atividades. Gostou? Conheça nossos outros cursos de IA para Programação em Inteligência Artificial, ou leia nossos artigos de Inteligência Artificial.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.