# Desenvolvimento ## Estrutura do Projeto ``` agente-bd/ ├── code/ # Código da aplicação │ ├── app/ │ │ ├── api.py # FastAPI — endpoints REST │ │ ├── front.py # Streamlit — interface web │ │ └── backend/ │ │ ├── __init__.py # Marca o diretório como pacote Python │ │ ├── config.py # Variáveis de ambiente │ │ ├── dynamo.py # DynamoDB, Langfuse, get_contexto │ │ ├── tools.py # ReportTools: get_variable_value, get_variables_list │ │ ├── agent_bedrock.py # LLM Bedrock, grafo LangGraph │ │ └── orquestrador.py # main() — ponto de entrada │ ├── utils/ │ │ └── dynamodb_read_table.py # Utilitários DynamoDB │ ├── main.py # Entry point │ ├── Dockerfile # Imagem Docker │ ├── entrypoint.sh # Script de inicialização │ └── requirements.txt # Dependências Python ├── infra/ # Infraestrutura como Código │ ├── ecr/ # Stack ECR │ ├── ecs_alb/ # Stack ECS + ALB │ └── langfuse/ # Stack Langfuse ├── docs/ # Esta documentação └── Makefile # Automação de build e deploy ``` ## Responsabilidades dos Módulos do Backend ### `config.py` Lê todas as variáveis de ambiente obrigatórias na carga do módulo e as exporta como constantes. Qualquer módulo que precise de configuração importa daqui. ### `dynamo.py` - Instancia o cliente `dynamodb` e o objeto `langfuse` na carga do módulo - `get_secret()` — busca as credenciais do Langfuse no AWS Secrets Manager - `get_contexto(dashboard: str) -> dict` — retorna `contexto`, `filter` e `items_disponiveis` para o dashboard informado ### `tools.py` Define a classe `ReportTools` com as ferramentas do agente: - `ReportTools(id_mapping)` — instanciada por requisição; `id_mapping` converte IDs locais (`id_1`, `id_2`, …) para os IDs reais do DynamoDB - `get_variable_value(id, variable)` — busca o valor de uma variável no DynamoDB - `get_variables_list(id)` — lista as variáveis disponíveis para um ID - `as_tools()` — retorna a lista de `StructuredTool` com nomes `get_variable_value` e `get_variable_list` ### `agent_bedrock.py` - `AgentState` — TypedDict com `messages` e `current_step` - `create_bedrock_llm(model_id, region, tools)` — instancia `ChatBedrockConverse` e vincula as tools - `call_model(state, llm)`, `call_tools(state, tools_map)`, `should_continue(state)` — nós e roteador do grafo LangGraph - `create_agent(inference_profile_arn, region, tools)` — monta o `tools_map` e compila o `StateGraph` ### `orquestrador.py` Função `main(user_query, history, model, base)`: - Carrega contexto via `get_contexto(base)` - Constrói `id_mapping` e `local_items` para isolar IDs reais do LLM - Instancia `ReportTools(id_mapping)` e passa as tools ao agente - Monta o system prompt com `local_items` no lugar dos IDs reais - Cria e invoca o agente - Retorna resposta e contagem de tokens ## Cadeia de Imports ``` config.py ↑ dynamo.py ←── config ↑ tools.py ←── config, dynamo ↑ agent_bedrock.py ←── config ↑ orquestrador.py ←── config, dynamo, agent_bedrock, tools ↑ api.py / front.py ←── orquestrador (via pacote backend) ``` ## Dependências Principais | Pacote | Uso | |--------|-----| | `boto3` | SDK AWS (DynamoDB, Secrets Manager) | | `langchain` | Framework de orquestração LLM | | `langchain-aws` | Integração LangChain + AWS Bedrock | | `langgraph` | Framework de agentes baseado em grafos | | `streamlit` | Interface web interativa | | `fastapi` | Framework de API REST | | `uvicorn` | Servidor ASGI | | `langfuse` | Observabilidade e tracing de LLMs | ## Fluxo de Desenvolvimento 1. **Fazer alterações** — Editar os arquivos em `code/app/` 3. **Testar localmente** — Rodar FastAPI + Streamlit ou via Docker 4. **Validar** — Executar scripts de teste em `scripts/` 5. **Build e deploy** — Seguir o [guia de deploy](deployment.md) ## Adicionando uma Nova Ferramenta ao Agente Todas as ferramentas vivem na classe `ReportTools` em `tools.py`. Basta: 1. Adicionar o método à classe: ```python def minha_nova_tool(self, param: str) -> str: """Descrição da tool para o LLM.""" real_id = self.id_mapping.get(param, param) # se precisar resolver ID # implementação return resultado ``` 2. Registrá-lo em `as_tools()`: ```python def as_tools(self) -> list: return [ ..., StructuredTool.from_function( self.minha_nova_tool, name="minha_nova_tool", description="Descrição da tool para o LLM.", ), ] ``` Não é necessário alterar `agent_bedrock.py` — o `tools_map` é construído dinamicamente a partir da lista retornada por `as_tools()`. ## Adicionando um Novo Modelo LLM Em `agent_bedrock.py`, adicionar o novo modelo aos três dicionários em `create_bedrock_llm()`: - `MODEL_ARNS` — ARN do inference profile - `PROVIDER` — provider (`anthropic`, `meta`, `amazon`) - `prefix` — prefixo de rota (`us` ou `global`) E adicionar o model ID à lista `MODELS` em `front.py`.