165 lines
9.0 KiB
Markdown
165 lines
9.0 KiB
Markdown
# 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) usando `REGION`
|
|
- `get_secret()` — busca credenciais do Langfuse no Secrets Manager
|
|
- Inicializa o objeto `langfuse` na 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 com `messages` e `current_step`
|
|
- `create_bedrock_llm(model_id, region, tools)` — instancia `ChatBedrockConverse` e vincula as tools via `bind_tools`
|
|
- `call_model(state, llm)` — nó do grafo: invoca o LLM
|
|
- `call_tools(state, tools_map)` — nó do grafo: executa as tool calls usando o `tools_map` da requisição
|
|
- `should_continue(state)` — roteador: `"tools"` se há tool_calls, `"end"` se não
|
|
- `create_agent(inference_profile_arn, region, tools)` — constrói `tools_map = {t.name: t for t in tools}`, monta e compila o `StateGraph`
|
|
|
|
**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)`:
|
|
|
|
1. Chama `get_contexto(base)` para carregar o contexto do dashboard
|
|
2. Constrói `id_mapping` (`id_1`, `id_2`, … → IDs reais do DynamoDB) e `local_items` (IDs locais → descrições)
|
|
3. Instancia `ReportTools(id_mapping)` com o mapeamento isolado da requisição
|
|
4. Monta o `SYSTEM_PROMPT` dinamicamente com contexto, regras de filtro, `local_items` e histórico
|
|
5. Cria o agente via `create_agent(model, REGION, tools=report_tools.as_tools())`
|
|
6. Invoca o agente com o estado inicial
|
|
7. Agrega tokens de todos os `AIMessage` do estado final
|
|
8. 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 check
|
|
- `POST /agent` — recebe `QueryRequest`, chama `orquestrador.main()`, retorna `QueryResponse`
|
|
|
|
## 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`.
|