9.0 KiB
Arquitetura
Visão Geral
O Assistente Analítico é composto por três camadas principais: interface (Streamlit e FastAPI), agente de IA (LangGraph com Bedrock) e dados (DynamoDB).
┌─────────────────────────────────────────────────────────┐
│ Interfaces │
│ ┌────────────────────┐ ┌────────────────────────┐ │
│ │ Streamlit (8501) │ │ FastAPI (8000) │ │
│ │ front.py │ │ api.py │ │
│ └────────┬───────────┘ └──────────┬─────────────┘ │
│ │ │ │
│ └──────────┬──────────────┘ │
│ ▼ │
│ orquestrador.main(query, history, model, base) │
│ │ │
│ ┌───────────────────▼──────────────────────────┐ │
│ │ agent_bedrock — LangGraph │ │
│ │ ┌────────┐ ┌───────┐ ┌────────────┐ │ │
│ │ │ Model │───▶│Router │───▶│ Tools │ │ │
│ │ │ Node │◀───│ │ │ Node │ │ │
│ │ └────────┘ └───────┘ └────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Serviços AWS │ │
│ │ ┌──────────┐ ┌────────────────────────────┐ │ │
│ │ │ Bedrock │ │ DynamoDB │ │ │
│ │ │ (LLMs) │ │ (contexto + dados pré- │ │ │
│ │ └──────────┘ │ processados) │ │ │
│ │ └────────────────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Observabilidade │ │
│ │ ┌──────────┐ ┌──────────────────────────┐ │ │
│ │ │ Langfuse │ │ CloudWatch Logs │ │ │
│ │ └──────────┘ └──────────────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Módulos do Backend
O pacote backend é organizado por responsabilidade:
backend/
├── config.py ← variáveis de ambiente
├── dynamo.py ← depende de config
├── tools.py ← depende de config, dynamo
├── agent_bedrock.py ← depende de config, tools
└── orquestrador.py ← depende de config, dynamo, agent_bedrock
Não há dependências circulares entre os módulos.
config.py
Lê todas as variáveis de ambiente na inicialização e exporta como constantes:
| Variável | Descrição |
|---|---|
TABLE |
Tabela DynamoDB |
REGION |
Região AWS |
AWS_ACCOUNT |
ID da conta AWS |
SECRET_NAME |
Nome do secret no Secrets Manager |
dynamo.py
- Instancia o cliente
dynamodb(boto3) usandoREGION get_secret()— busca credenciais do Langfuse no Secrets Manager- Inicializa o objeto
langfusena carga do módulo get_contexto(dashboard: str) -> dict— carrega contexto, filtro e itens disponíveis do DynamoDB para o dashboard informado
tools.py
Define a classe ReportTools, instanciada por requisição com o mapeamento de IDs local → real.
ReportTools(id_mapping: dict[str, str])
├── get_variable_value(id, variable) — busca uma variável no DynamoDB
├── get_variables_list(id) — lista as variáveis disponíveis para um ID
└── as_tools() -> list[StructuredTool] — retorna as tools prontas para o agente
| Tool (nome exposto ao LLM) | Método | Descrição |
|---|---|---|
get_variable_value |
get_variable_value(id, variable) |
Busca o valor de uma variável no DynamoDB para o ID informado |
get_variable_list |
get_variables_list(id) |
Lista as variáveis disponíveis para o ID informado |
Os IDs expostos ao LLM são locais (id_1, id_2, …). Internamente cada método converte o ID local para o ID real do DynamoDB via self.id_mapping. Por usar estado de instância em vez de variável global, múltiplas requisições simultâneas ficam completamente isoladas.
agent_bedrock.py
AgentState— TypedDict commessagesecurrent_stepcreate_bedrock_llm(model_id, region, tools)— instanciaChatBedrockConversee vincula as tools viabind_toolscall_model(state, llm)— nó do grafo: invoca o LLMcall_tools(state, tools_map)— nó do grafo: executa as tool calls usando otools_mapda requisiçãoshould_continue(state)— roteador:"tools"se há tool_calls,"end"se nãocreate_agent(inference_profile_arn, region, tools)— constróitools_map = {t.name: t for t in tools}, monta e compila oStateGraph
Fluxo do Grafo:
SystemMessage + HumanMessage
│
▼
┌─────────┐
│ model │ ◄── LLM via Bedrock
└────┬────┘
│
should_continue?
├── tool_calls → ┌───────┐
│ │ tools │ → executa tools → volta ao model
│ └───────┘
└── (fim) → [END]
orquestrador.py
Ponto de entrada da lógica de negócio. A função main(user_query, history, model, base):
- Chama
get_contexto(base)para carregar o contexto do dashboard - Constrói
id_mapping(id_1,id_2, … → IDs reais do DynamoDB) elocal_items(IDs locais → descrições) - Instancia
ReportTools(id_mapping)com o mapeamento isolado da requisição - Monta o
SYSTEM_PROMPTdinamicamente com contexto, regras de filtro,local_itemse histórico - Cria o agente via
create_agent(model, REGION, tools=report_tools.as_tools()) - Invoca o agente com o estado inicial
- Agrega tokens de todos os
AIMessagedo estado final - Retorna
response,input_tokens,output_tokens,total_tokens
Interfaces
front.py — Streamlit (porta 8501)
- Importa
from backend import orquestrador - Lista bases disponíveis consultando DynamoDB (
item_type_index,item_type = "contexto") - Seleção de modelo LLM e base via
st.selectbox - Histórico de conversas em
session_state - Efeito de digitação caractere a caractere
- Exibe consumo de tokens por resposta
api.py — FastAPI (porta 8000)
- Importa
from .backend import orquestrador GET /— health checkPOST /agent— recebeQueryRequest, chamaorquestrador.main(), retornaQueryResponse
Modelos LLM Suportados
| Modelo | Provider | Prefixo de Rota |
|---|---|---|
anthropic.claude-haiku-4-5-20251001-v1:0 |
Anthropic | us |
anthropic.claude-sonnet-4-5-20250929-v1:0 |
Anthropic | global |
meta.llama4-maverick-17b-instruct-v1:0 |
Meta | us |
meta.llama4-scout-17b-instruct-v1:0 |
Meta | us |
amazon.nova-lite-v1:0 |
Amazon | us |
amazon.nova-pro-v1:0 |
Amazon | us |
amazon.nova-2-lite-v1:0 |
Amazon | global |
Todos acessados via AWS Bedrock inference profiles cross-region. O ARN é construído dinamicamente com REGION e AWS_ACCOUNT.