A POC consiste em criar uma estrutura de agentes simples, usando Python puro (para os agentes), com 3 agentes executores e um agente gerente (que possui agentes abaixo dele).
A ideia é que o agente gerente faça o planejamento da tarefa com base no prompt. Para isso, eu uso um modelo melhor (no caso, o OpenAI O1 mini) para fazer o planejamento (qual subagente faz o quê) e executo as tarefas em seguida. Por fim, com base nos resultados dos subagentes, eu gero a resposta final.
O teste a seguir basicamente tenta cruzar a informação da data de inauguração do condomínio do usuário (14/03/2014), que o agente “Conhecedor da casa” conhece, com personalidades que nasceram nessa data. É um prompt que precisa de múltiplas etapas, e é isso que queremos avaliar.
Resultado obtido:
> [Usuário]: Alguém famoso nasceu no dia da inauguração do meu condomínio?
> ...
> [Agente]: Sim, várias personalidades famosas nasceram no dia **12 de março**, a mesma data da inauguração do seu condomínio. Algumas delas incluem:
1. **Albert Einstein** (1879) – Físico teórico renomado por desenvolver a teoria da relatividade.
2. **Jack Kerouac** (1922) – Escritor famoso pela obra "On the Road".
3. **Liza Minnelli** (1946) – Atriz e cantora premiada, vencedora de diversos prêmios, incluindo o Oscar.
Essa coincidência torna a data da inauguração do seu condomínio ainda mais especial!
O resultado está QUASE certo, apenas Albert Einstein, segundo minha busca, nasceu em 14/03 e não em 12/03. De qualquer forma, podemos ver que o gerente foi capaz de planejar as etapas usando os subagentes para responder ao prompt, conforme esperado.
Abaixo, o código para executar a POC. Foi usado Poetry para gerenciar as dependências.
Arquivo pyproject.yaml
:
[tool.poetry]
name = "agent"
version = "0.1.0"
description = ""
authors = ["Alisson R. Perez <756802+alissonperez@users.noreply.github.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.10"
openai = "^1.61.0"
prompt-toolkit = "^3.0.50"
[tool.poetry.group.dev.dependencies]
icecream = "^2.1.4"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Arquivo main.py
from openai import OpenAI
from dataclasses import dataclass, field
from prompt_toolkit import prompt, PromptSession
from prompt_toolkit.history import FileHistory
from icecream import ic
client = OpenAI()
def answer(prompt, model):
ic(model, prompt)
completion = client.chat.completions.create(
model=model,
messages=[
{
"role": "user",
"content": prompt
}
]
)
return completion.choices[0].message.content
@dataclass
class Agent:
name: str
short_description: str
description: str
llm_model: str = 'gpt-4o-mini'
subagents: list['Agent'] = field(default_factory=list)
_default_answer: str = 'Responda diretamente a solicitação feita usando o conhecimento que tenho até então:'
_subagents_by_name: dict[str, 'Agent'] = field(init=False, default_factory=dict)
def __post_init__(self):
for subagent in self.subagents:
self._subagents_by_name[subagent.name] = subagent
def answer(self, prompt, previous_context=None):
previous_context = previous_context or []
if not len(self.subagents):
context = [
f'Eu sou o {self.name}.',
f'{self.description}',
'\n'.join(['Tenho o seguinte contexto até o momento:'] + previous_context) if previous_context else '',
'---',
'Recebi a seguinte solicitação:',
prompt,
'---',
'---',
'',
self._default_answer,
]
return self._answer(context)
else:
context = [
f'Eu sou o {self.name}.',
f'{self.description}',
]
steps_prompt = context + [
'---',
'Conheço os seguintes subagentes que podem ajudar:',
'\n'.join([f'- {subagent.name}: {subagent.short_description}' for subagent in self.subagents]),
'---',
'Recebi a seguinte solicitação:',
prompt,
'---',
'Elabore uma linha de raciocinio para responder a solicitação, informe o nome do agente caso uma etapa precise de algo dele.',
'',
'Formato de resposta esperado: "[agente],[etapa]" separados apenas por quebra de linha, exemplos:',
'agenteX: Buscar sobre X assunto',
'agenteY: Calcular Y coisa',
]
steps = answer('\n'.join(steps_prompt), self.llm_model)
previous_context = previous_context + [
'---',
'Etapas calculadas para responder à solicitação:',
steps,
]
ic(steps)
splited = steps.split('\n')
for step in splited:
agent, *instructions = step.split(':')
agent = agent.strip()
instructions = ':'.join(instructions).strip()
agent_answer = self._subagents_by_name[agent].answer(instructions, previous_context + [])
ic(agent, agent_answer)
previous_context.append(self._build_answer(agent, agent_answer))
previous_context += [
'---',
f'Agora, com base nas informações obtidas até então, {self._default_answer}',
'Solicitação:',
prompt,
]
return self._answer(previous_context)
def _answer(self, context: list[str]):
return answer('\n'.join(context), self.llm_model)
def _build_answer(self, agent_name, answer):
return '\n'.join([
'---',
f'"{agent_name}" respondeu o seguinte:',
answer,
])
if __name__ == '__main__':
agente = Agent(
name='Conhecedor de casa',
short_description='Fornece informações gerais sobre onde o usuário mora (Cond. Miami Gardens)',
description='O endereço do condomínio é: , o condomínio possui 1000 moradores e foi inaugurado em 12/03/2014',
)
buscador = Agent(
name='Buscador de informações',
short_description='Busca informações gerais sobre algo na internet, trazendo dados de wikis, blogs, etc.',
description='Retorno sempre um resumo simples sobre uma informação solicitada e da forma que foi solicitada, simulando um resultado de busca na internet',
)
escritor = Agent(
name='Escritor de textos',
short_description='Escreve textos com base em informações fornecidas, é ótimo para criar respostas com base no que já é conhecido.',
description='Ao receber um contexto e uma solicitação, escrevo um texto bem suscinto e amigável para o usuário, com base no que foi solicitado.',
)
orquestrador = Agent(
name='Gerente',
short_description='Gerente que organiza as tarefas solicitadas pelo usuário.',
description='Eu sou o gerente, posso te ajudar a encontrar informações, responder perguntas, etc. para o usuário',
llm_model="o1-mini",
subagents=[agente, buscador, escritor],
)
our_history = FileHistory(".chat-history-file")
session = PromptSession(history=our_history)
while 1:
user_input = session.prompt('>')
print(orquestrador.answer(user_input))
Para executar, instale as dependencias com o Poetry e rode a app: poetry run python main.py