Este projeto fornece um endpoint FastAPI para um agente conversacional construído usando Langchain e LangGraph. O agente pode conversar, usar ferramentas como busca na web (Tavily), e manter memória de conversação entre requisições.
agent_project/
│
├── app/ # Código principal da aplicação
│ ├── __init__.py
│ ├── main.py # Entry point do FastAPI
│ ├── api/ # Rotas e controladores
│ │ ├── __init__.py
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── routes.py # Endpoint /chat
│ │ └── schemas.py # Pydantic models da API
│ │
│ ├── agents/ # Lógica dos agentes LangGraph
│ │ ├── __init__.py
│ │ └── graph_agent.py # Construtor do agente ReAct
│ │
│ ├── tools/ # Ferramentas usadas pelos agentes
│ │ ├── __init__.py
│ │ ├── web_search_tool.py # Ferramenta Tavily Search
│ │ └── vector_search_tool.py # Placeholder para busca vetorial
│ │
│ └── llm/ # Setup dos modelos LLM
│ ├── __init__.py
│ └── openai_llm.py # Configuração do LLM OpenAI
│
├── tests/ # Testes (a implementar)
│ ├── __init__.py
│ ├── agents/
│ ├── api/
│ └── tools/
│
├── .env # Variáveis de ambiente (API Keys)
├── requirements.txt # Dependências Python
└── README.md # Este arquivoAqui está um passo a passo detalhado de como uma mensagem do usuário flui através do sistema:
-
Usuário Envia Mensagem:
- Um usuário (ou sistema cliente) envia uma requisição HTTP POST para o endpoint
/api/v1/chat. - O corpo da requisição inclui a mensagem (ex:
{"message": "Quem é o presidente do Brasil?"}). - Crucialmente, um header
X-Session-Id(ex:"session-123") é incluído para identificar a conversa específica.
- Um usuário (ou sistema cliente) envia uma requisição HTTP POST para o endpoint
-
FastAPI Recebe e Roteia:
- A aplicação FastAPI (
app/main.py) recebe a requisição. - Ela roteia a requisição para a função
chat_endpointdefinida emapp/api/v1/routes.py.
- A aplicação FastAPI (
-
Preparação no Endpoint (
chat_endpoint):- A mensagem do usuário é extraída do corpo da requisição.
- O
X-Session-Idé lido do header. - Um dicionário de configuração
configpara o LangGraph é criado, mapeando o ID da sessão para othread_id:{"configurable": {"thread_id": "session-123"}}. Isso informa ao agente qual memória de conversa usar. - A mensagem do usuário é formatada na estrutura de entrada esperada pelo agente LangGraph:
{"messages": [HumanMessage(content="Quem é o presidente do Brasil?")]}.
-
Invocação do Agente LangGraph:
- A instância pré-construída do agente (
graph_agent_executor_instancedeapp/agents/graph_agent.py) é invocada usandoainvoke(input, config=config). - Esta instância foi criada usando
create_react_agentdolanggraph.prebuilt, que monta um grafo de agente seguindo o padrão ReAct (Reasoning and Acting).
- A instância pré-construída do agente (
-
Dentro do Agente LangGraph (
create_react_agent):- Carregar Estado: O
MemorySaverdo agente (ocheckpointerpassado durante a criação) usa othread_iddaconfigpara carregar o estado anterior (histórico de mensagens) desta sessão de conversa específica ("session-123"). Se for a primeira mensagem, o estado estará vazio. - Loop ReAct: O agente executa um ciclo de raciocínio e ação:
- Pensar (LLM): O LLM configurado (
app/llm/openai_llm.py) recebe o histórico atual de mensagens e a lista de ferramentas disponíveis (TavilySearchResults,vector_search_placeholderdeapp/agents/graph_agent.py). Ele decide a próxima ação. Para "Quem é o presidente do Brasil?", ele provavelmente decidirá usar a ferramenta de busca na web (Tavily). - Agir (Chamada de Ferramenta): O LLM gera uma "chamada de ferramenta" (Tool Call), especificando qual ferramenta usar (
tavily_search_results_json) e os argumentos ({"query": "Quem é o presidente do Brasil?"}). - Executar Ferramenta: LangGraph intercepta a chamada, encontra a ferramenta
TavilySearchResultscorrespondente e a executa com a query. A ferramenta (app/tools/web_search_tool.py) interage com a API do Tavily. - Observar (Resultado da Ferramenta): Os resultados da busca do Tavily são retornados ao grafo do agente.
- Pensar Novamente (LLM): O resultado da ferramenta é adicionado ao histórico. O LLM recebe o histórico atualizado (UserInput -> LLM Thought/ToolCall -> Tool Result).
- Resposta Final (LLM): Com base nos resultados da busca, o LLM formula a resposta final (ex: "O atual presidente do Brasil é Luiz Inácio Lula da Silva."). Como nenhuma outra ferramenta é necessária, ele gera a
AIMessagefinal.
- Pensar (LLM): O LLM configurado (
- Salvar Estado: O
MemorySaver(checkpointer) salva automaticamente o histórico completo e atualizado da conversa associado aothread_id("session-123").
- Carregar Estado: O
-
Extração da Resposta no Endpoint:
- A chamada
ainvokena API retorna o dicionário completo do estado final do grafo (final_state). - A função
chat_endpointacessa a chave'messages'neste dicionário. - Ela recupera a última mensagem da lista, que é a
AIMessagefinal do LLM. - O conteúdo textual (
.content) destaAIMessageé extraído.
- A chamada
-
Envio da Resposta ao Usuário:
- O texto extraído é empacotado em um objeto
ChatResponse. - FastAPI serializa este objeto em JSON e o envia de volta como corpo da resposta HTTP para o usuário/cliente original.
- O texto extraído é empacotado em um objeto
-
Pré-requisitos: Certifique-se de ter Python 3.11+ e
uv(gerenciador de pacotes) instalados. -
Configuração Inicial (Ambiente e Dependências):
-
Windows:
- Execute o script
setup.bat. Ele irá criar o ambiente virtual, ativá-lo e instalar as dependências dorequirements.txtusandouv.
setup.bat
- Após a execução do script, o ambiente virtual (
.venv) estará criado e pronto para uso.
- Execute o script
-
macOS/Linux (ou Manualmente no Windows):
- Crie o ambiente virtual:
uv venv(oupython -m venv .venv) - Ative o ambiente:
- Windows:
.venv\Scripts\activate - macOS/Linux:
source .venv/bin/activate
- Windows:
- Instale as dependências:
uv pip install -r requirements.txt
- Crie o ambiente virtual:
-
-
Chaves de API:
-
Crie um arquivo chamado
.envna raiz do projeto. -
Adicione suas chaves de API necessárias, como no exemplo:
OPENAI_API_KEY=sua_chave_openai TAVILY_API_KEY=sua_chave_tavily # Adicione outras chaves se necessário (ex: Pinecone)
-
-
Executar o Servidor:
-
Certifique-se de que seu ambiente virtual está ativado.
-
Execute o servidor FastAPI usando Uvicorn:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
-
(Opcional) Se preferir usar o runner do
uv:uv run fastapi dev app/main.py --host 0.0.0.0 --port 8000
(Nota: O comando
uv run fastapi devpode não passar argumentos como--hoste--portcorretamente para o Uvicorn subjacente em todas as versões/configurações.uvicorndireto é geralmente mais confiável para especificar host/port).
-
-
Testar:
- Acesse a documentação interativa da API (Swagger UI) no seu navegador em
http://localhost:8000/docs. - Use a interface do Swagger ou uma ferramenta como
curlou Postman para enviar requisições POST parahttp://localhost:8000/api/v1/chat. - Inclua um corpo JSON como
{"message": "Sua pergunta aqui"}. - Importante: Inclua o header
X-Session-Id: seu_id_de_sessaopara habilitar e rastrear a memória da conversa. Use o mesmo ID para continuar uma conversa existente.
- Acesse a documentação interativa da API (Swagger UI) no seu navegador em