Olá, sejam todos muito bem-vindos ao curso Orquestrando Agentes e Multiagentes com o Landgraf. Meu nome é Carlos Eduardo e serei o instrutor nesta e nas próximas aulas.
Audiodescrição: Carlos Eduardo é um homem branco, com cabelo, barba e olhos castanhos. Ele usa óculos de armação preta e está nos estúdios da Alura, com uma parede colorida e uma estante ao fundo.
Neste curso, trabalharemos com o Landgraf para a construção e orquestração de agentes e multiagentes de inteligência artificial. Vale lembrar que o Landgraf é um dos frameworks mais utilizados no mercado de trabalho quando o assunto é agentes de IA.
Em resumo, o que vamos aprender é o seguinte: vamos criar um agente utilizando o conceito do React, conceituar os principais componentes do Landgraf e aplicá-los na prática.
Vamos aprender a realizar uma busca na internet utilizando também o WebScraping (raspagem de dados da web) para capturar as informações que desejamos. Vamos explorar sobre persistência e streaming (transmissão de dados) e como utilizá-los em agentes e multiagentes.
Além disso, vamos criar um projeto que utiliza o conceito de Human-in-the-Loop (humano no circuito) e interações entre humano e máquina para extrair o melhor dos dois mundos, maximizando essa interação entre humano e máquina.
Por fim, vamos colocar todos esses conceitos em prática, orquestrando multiagentes de IA e criando uma interface gráfica que será muito interessante. Para finalizar o nosso curso, vamos desenvolver um assistente de e-mail que realiza a triagem de e-mails importantes. Ele também será capaz de agendar reuniões com uma interação de Human-in-the-Loop, perguntando à pessoa se deseja que o agente agende a reunião, além de responder e-mails automaticamente.
Esperamos que vocês gostem.
Vamos iniciar nossa primeira aula desenvolvendo um agente react. Este nome é derivado da combinação do padrão de reasoning (raciocínio) com acting (ação), significando que o agente primeiro raciocina e, em seguida, decide qual ação tomar dentro de um mesmo fluxo.
Começaremos com a instalação dos pacotes necessários. Embora já tenhamos executado essa etapa, vamos rodar novamente para garantir. Para isso, utilizamos os seguintes comandos:
%pip install -U google-generativeai
%pip install google-ai-generativelanguage==0.6.15
%pip install -U langchain-google-genai
%pip install -U langchain-community
%pip install -U langgraph
Em seguida, faremos as importações: os
para trabalhar com variáveis de ambiente, re
para expressões regulares, além das importações do Google, LangGraph e Typing.
import os
import re
import google.generativeai as genai
from langgraph.graph import StateGraph, END
from typing import TypedDict
Vamos implementar um padrão react de forma natural, o que significa que a função de raciocinar e agir será fornecida via prompt para o agente. Este conceito é baseado em um artigo disponível no GitHub, que recomendamos para quem se interessa por pesquisa. Segundo o artigo, as principais vantagens de um modelo react para um agente de diálogo são a precisão, facilidade, versatilidade e eficiência.
O exemplo que abordaremos hoje é baseado em um blog de Simon Wilson, que também é uma excelente fonte para quem deseja explorar outros modelos além dos agentes react.
Como vamos trabalhar com API Keys, é importante mencionar que estamos utilizando o VS Code. Nossas API Keys serão armazenadas em um arquivo .env
, que usamos para guardar senhas e informações que não queremos expor, por questões de segurança. Se estiver utilizando o Google Colab, é possível inserir a chave em Secrets.
Para configurar a API Key, carregamos as variáveis de ambiente e configuramos a chave do Google Gemini:
import os
from dotenv import load_dotenv
import google.generativeai as genai
load_dotenv()
os.environ['GOOGLE_API_KEY'] = os.getenv('GEMINI_API_KEY')
genai.configure(api_key=os.getenv('GOOGLE_API_KEY'))
Estamos utilizando a LLM do Google, especificamente a chave do Gemini. Caso prefira outra LLM, como a da OpenAI ou Antropic, não há problema. O Google oferece créditos de 300 dólares, o que é bastante útil. Para criar uma chave API, acesse o aistudio.google, faça login, procure por "Get API Key" e depois "Criar Chave API". No VS Code, coloque a chave no .env
; no Colab, insira em Secrets.
Sempre que configuramos uma API Key, é importante realizar um teste para verificar seu funcionamento. Vamos fazer um teste clássico de "Hello World" em Python, utilizando o modelo Gemini 2.5 Flash, que é altamente recomendado para essa funcionalidade. Carregamos as variáveis de ambiente, incluindo a chave do Google Gemini, e verificamos a resposta:
model = genai.GenerativeModel('gemini-2.5-flash')
response = model.generate_content("Hello world")
print(response.text)
Isso confirma que nossa API Key do Google está funcionando corretamente.
Com a API Key funcionando, passamos para a definição do nosso modelo. Nesta aula, utilizaremos a classe Agent
, onde definiremos a estrutura e o comportamento do nosso agente. Assim, criamos a classe Agent
e parametrizamos o agente como um agente de sistema.
client = genai.GenerativeModel("gemini-2.5-flash")
class Agent:
def __init__(self, system=""):
self.system = system
self.messages = []
if self.system:
self.messages.append({"role": "system", "content": self.system})
def __call__(self, message):
self.messages.append({"role": "user", "content": message})
result = self.execute()
self.messages.append({"role": "assistant", "content": result})
return result
def execute(self):
# Constrói o prompt com todo o histórico de mensagens
prompt = ""
for msg in self.messages:
prompt += f"{msg['role']}: {msg['content']}\n"
# Envia para o Gemini
response = client.generate_content(prompt)
return response.text
Nós fazemos isso como se fosse um atributo. Temos aqui as variáveis de armazenamento de uma String (cadeia de caracteres), recebida por um parâmetro de sistema, como um atributo do sistema. Criamos uma lista vazia para armazenar essas informações e estabelecemos uma condição. Se a mensagem for fornecida pelo sistema, então é uma String vazia.
A outra função que iremos criar se chama Call
. O que o agente faz? Ele pega a mensagem do sistema, que é uma String, e anexa essa mensagem à matriz existente de mensagens. Utilizamos o método append
para anexar essa mensagem ao histórico de mensagens. Por fim, criamos a função de executar, para construir o ambiente com todo o histórico de mensagens.
Vamos executar isso. Também temos um exemplo para verificar se está tudo funcionando: perguntamos qual é a capital da França, e ele deve responder que é Paris. Assim, está funcional.
# Exemplo de uso
if __name__ == "__main__":
agent = Agent(system="Você é um assistente útil e objetivo.")
print(agent("Qual é a capital da França?"))
Lembramos que comentamos sobre a criação de um agente React usando o prompt. Precisamos fazer uma mensagem bem específica. Vamos descrever essa mensagem e depois analisá-la em detalhes para entender o que realmente estamos fazendo. Pedimos para ele executar esse ciclo de pensamento, ação, pausa e observação. Ele produzirá a resposta final da interação. O pensamento descreve o que o agente está pensando claramente. A ação executa as ações disponíveis para ele, que são as ferramentas que vamos criar. Explicaremos isso mais adiante.
Durante a pausa, ele faz a distinção entre as duas interações: pensamento e ação. Por fim, na etapa de observação, ele sinaliza o resultado das ações e o que será feito. Vamos lá. Vou colar o prompt aqui e explicar. O prompt são as instruções que damos ao agente React. Deixamos claro que ele funciona em um ciclo de pensamento, ação, pausa e observação. Ao final do ciclo, ele fornece uma resposta. Ele usa o pensamento para descobrir seu raciocínio e a ação para executar as ferramentas. Depois, vem a observação, que é o resultado da ação executada.
PROMPT_REACT = """
Você funciona em um ciclo de Pensamento, Ação, Pausa e Observação.
Ao final do ciclo, você fornece uma Resposta.
Use "Pensamento" para descrever seu raciocínio.
Use "Ação" para executar ferramentas - e então retorne "PAUSA".
A "Observação" será o resultado da ação executada.
Ações disponíveis:
- consultar_estoque: retorna a quantidade disponível de um item no inventário (ex: "consultar_estoque: teclado")
- consultar_preco_produto: retorna o preço unitário de um produto (ex: "consultar_preco_produto: mouse gamer")
Exemplo:
Pergunta: Quantos monitores temos em estoque?
Pensamento: Devo consultar a ação consultar_estoque para saber a quantidade de monitores.
Ação: consultar_estoque: monitor
PAUSA
Observação: Temos 75 monitores em estoque.
Resposta: Há 75 monitores em estoque.
""".strip()
É importante deixar dois exemplos de ações disponíveis para ele. Ainda não criamos essas ações, mas faremos isso em breve. As ferramentas que o agente terá disponíveis são: consultar o estoque e consultar o preço do produto. Estamos criando um agente React que será um auxiliar de inventário de uma loja de informática. A ferramenta de consultar estoque retornará a quantidade disponível de itens no inventário, e a ferramenta de consultar o preço do produto retornará o preço unitário de um produto. Se perguntarem o preço, ele responderá, e se perguntarem a quantidade de um material, ele também responderá.
Outra coisa importante é incluir exemplos de perguntas, tanto para consulta de estoque quanto para consulta de preço. Por fim, um exemplo de resposta.
Por enquanto, é isso. Já temos as APIs mapeadas no projeto, a classe do agente definida, e acabamos de criar nosso prompt. Na próxima aula, vamos para a estrutura do estado e definiremos as ferramentas. Nos vemos lá!
Vamos continuar desenvolvendo nosso agente React, criando um agente para nossa loja de materiais de informática, que funcionará como um auxiliador de inventário. Vamos recapitular o que já fizemos: já temos as importações necessárias, o modelo definido e o prompt também. Agora, vamos trabalhar com as ferramentas desse agente, habilitando o que ele pode fazer.
Para isso, vamos criar a estrutura do agente, ou agent state. Essa parte é muito importante, pois o agent state define o estado compartilhado entre os nós do grafo. Explicaremos isso mais adiante, especificamente o que é um nó e o que é uma aresta condicional, mas, conforme as aulas progredirem, entenderemos melhor. Basicamente, um grafo é como um mapa de decisões, representando o fluxo de execução do agente. Podemos pensar em um modelo de fluxograma de qualquer processo de uma empresa, com caixinhas, setas e pontos de decisão. Todo esse ambiente é um grafo. O nó é como as caixinhas desse fluxograma maior, um passo específico no raciocínio ou na ação de um agente. Detalharemos tudo sobre os componentes do Language Graph na próxima aula.
Para esta aula, é importante falarmos sobre o agent state. Vamos criar uma classe chamada AgentState
. Para isso, usaremos a classe AgentState
como TypedDict
.
class AgentState(TypedDict):
Teremos a pergunta
, que será uma String representando a pergunta original do usuário.
pergunta: str
O histórico
será uma lista de Strings, contendo o histórico de mensagens entre o agente e o LLM.
historico: list[str]
A ação pendente
será uma String que armazenará a próxima ação a ser executada.
acao_pendente: str
E a resposta final
, que também será uma String.
resposta_final: str
Agora, vamos rodar essa classe e definir as ferramentas que nosso agente pode utilizar. Isso é muito importante. Vamos criar duas funções: consultar_estoque
e consultar_preco_produto
. No nosso prompt, já colocamos essas duas ferramentas disponíveis para consulta do agente, então já existe a instrução de que elas existem. Precisamos criar essas ferramentas.
Primeiramente, vamos criar a função consultar_estoque
, que trará todos os produtos do nosso estoque e a quantidade de produtos disponíveis.
def consultar_estoque(item: str) -> str:
"""
Simula a consulta de estoque de um item no inventário.
"""
item = item.lower()
estoque = {
"monitor": 75,
"teclado": 120,
"mouse gamer": 80,
"webcam": 40,
"headset": 60,
"impressora": 15
}
if item in estoque:
return f"Temos {estoque[item]} {item}s em estoque." #criamos uma máscara para a resposta, para ficar mais elegante e profissional
else:
return f"Item '{item}' não encontrado no inventário." #criamos também uma resposta para produtos não localizados no inventário
Em seguida, criaremos a função consultar_preco_produto
, que trará os valores dos produtos listados anteriormente.
def consultar_preco_produto(produto: str) -> str:
"""
Simula a consulta do preço unitário de um produto.
"""
produto = produto.lower()
precos = {
"monitor": 999.90,
"teclado": 150.00,
"mouse gamer": 99.50,
"webcam": 120.00,
"headset": 180.00,
"impressora": 750.00
}
if produto in precos:
return f"O preço de um(a) {produto} é R$ {precos[produto]:.2f}."
else:
return f"Produto '{produto}' não encontrado na lista de preços."
Notem que utilizamos máscaras de resposta para tornar a interação mais elegante. Assim, ao invés de responder apenas a quantidade, utilizamos essas máscaras. Caso a resposta não seja encontrada, haverá um placeholder indicando que o item não foi encontrado em estoque. O mesmo se aplica à consulta de preço.
Dessa forma, nosso agente já conseguirá consultar o estoque e o preço de um produto. Antes de incluir essas ferramentas para nossos agentes, vamos verificar se elas estão funcionando. Vamos fazer um print de consulta_estoque("teclado")
, que deve informar a quantidade de teclados em estoque.
print(consultar_estoque("teclado"))
Vamos ver se funciona. Observem que ele responde com a máscara que definimos. Caso contrário, ele responderia apenas "120".
Vamos realizar outro teste e consultar um produto. Vamos verificar o preço da impressora.
print(consultar_preco_produto("impressora"))
O preço da impressora é de R$750. Muito bem, constatamos que está funcionando. Já definimos o agente, o agent state
, a classe agente
, a classe agent state
e agora as ferramentas. Precisamos integrar o agente com essas ferramentas para que ele consiga, de forma autônoma, executar suas próprias funções. Isso tornará nosso agente mais potente e permitirá que ele faça consultas no estoque.
Vamos criar uma nova função chamada run_react_agent
. Vamos colar a função inteira e explicar seus detalhes. Vamos criar a função, trazendo a pergunta como uma string e também o número de interações, que será cinco. Utilizaremos o modelo do Gemini 2.5 Flash novamente.
def run_react_agent(pergunta: str, max_iterations: int = 5) -> str:
model = genai.GenerativeModel('gemini-1.5-flash')
chat = model.start_chat(history=[])
chat.send_message(PROMPT_REACT)
current_prompt = pergunta
for i in range(max_iterations):
response = chat.send_message(current_prompt)
response_text = response.text.strip()
print(f"--- Iteração {i+1} ---")
print(f"Modelo pensou/respondeu:\n{response_text}\n")
if response_text.startswith("Resposta:"):
return response_text.replace("Resposta:", "").strip()
match = re.search(r"Ação:\s*(\w+)\s*\[\s*(.*)\s*\]", response_text)
if match:
action_name = match.group(1).strip()
action_arg = match.group(2).strip()
observacao = ""
if action_name == "consultar_estoque":
observacao = consultar_estoque(action_arg)
elif action_name == "consultar_preco_produto":
observacao = consultar_preco_produto(action_arg)
else:
observacao = f"Erro: Ação '{action_name}' desconhecida."
current_prompt = f"Observação: {observacao}\nResposta:"
print(f"Executou ação: {action_name}({action_arg})")
print(f"Observação: {observacao}\n")
else:
return f"Erro: O agente não conseguiu extrair uma Ação ou Resposta final após {i+1} iterações. Última resposta: {response_text}"
return "Erro: Limite máximo de iterações atingido sem uma resposta final."
Começamos com um histórico de lista vazia para iniciar o loop de interações dos ciclos React. Enviamos o current prompt
para o modelo responder, capturando a resposta gerada com .strip
para retirar espaços extras, tornando a resposta mais apresentável.
Há uma condição para execução da ação ou ferramenta. As ferramentas que estamos criando são para consulta de estoque ou preço do produto. Estamos agregando as funções criadas para esse agente, definindo qual ação será escolhida: consultar estoque ou produto. O current prompt
prepara o próximo input com a observação, incluindo a etapa de observação ou resultado da ação. Isso torna a execução do agente mais visual e atraente. Máscaras são usadas para tratar possíveis erros de interação.
Vamos rodar a função run_react_agent
e verificar seu funcionamento. Perguntamos ao agente quantos mouses gamers estão no inventário.
pergunta_1 = "Quantos mouses gamers estão no inventário?"
print(f"***Interação 1: {pergunta_1}***")
resposta_1 = run_react_agent(pergunta_1)
print(f"\n**RESPOSTA FINAL DO AGENTE 1:** {resposta_1}\n")
print("\n"+"="*50 + "\n")
Ele traz a interação, mostrando que o modelo React possui duas grandes interações: pensamento e ação. O pensamento é quebrado na interação 1 e a ação na interação 2. O agente determina que deve consultar o estoque para mouses gamers, utilizando a função consulta_estoque
, uma das duas que criamos. Ele executa e traz a resposta: temos 80 mouses gamers em estoque. Como a pergunta é simples, a resposta é repetida: 80 mouses gamers em estoque. O pensamento do agente é: "Recebi a observação de que há 80 mouses gamers em estoque, agora posso formular a resposta final." Tudo isso foi gerado com o LLM mapeado, no caso, o Gemini, que traz a resposta final: "Há 80 mouses gamers em estoque."
Criamos as ferramentas necessárias para a consulta do agente, incluímos essa ferramenta no nosso agent state
e criamos uma nova função de Realm React Agents
, onde agregamos todas as funções criadas para que o agente auxiliador de estoque funcione. Na próxima aula, tentaremos novas interações com esse agente. Até lá!
O curso LangGraph: Orquestrando agentes e multiagentes possui 331 minutos de vídeos, em um total de 57 atividades. Gostou? Conheça nossos outros cursos de IA para Dados 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
Matricule-se no plano PLUS e garanta:
Mobile, Programação, Front-end, DevOps, UX & Design, Marketing Digital, Data Science, Inovação & Gestão, Inteligência Artificial
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ê participa de eventos exclusivos, pode tirar dúvidas em estudos colaborativos e ainda conta com mentorias em grupo com especialistas de diversas á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.
Para estudantes ultra comprometidos atingirem seu objetivo mais rápido.
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.
Conecte-se ao mercado com mentoria personalizada, vagas exclusivas e networking estratégico que impulsionam sua carreira tech para o próximo nível.