# Guia de Configuração — Módulo AI ## Pré-requisitos | Componente | Como obter | Status | |---|---|---| | **Ollama** (host) | `curl -fsSL https://ollama.com/install.sh \| sh` | Local, necessário | | **qwen3-embedding** | `ollama pull qwen3-embedding:latest` | Modelo de embedding | | **gemma4:12b** | `ollama pull gemma4:12b` | LLM para chat local | | **DeepSeek API key** | [platform.deepseek.com](https://platform.deepseek.com) | LLM cloud (opcional) | | **PostgreSQL + pgvector** | `docker compose up -d postgres` | Já configurado | | **RabbitMQ** | `docker compose up -d rabbit-mq` | Já configurado | ## 1. Setup do Ollama (Host) ### Instalação ```bash # Linux curl -fsSL https://ollama.com/install.sh | sh # Verificar se está rodando ollama --version curl http://localhost:11434/api/tags ``` ### Download dos Modelos ```bash # Embedding (4.7 GB) ollama pull qwen3-embedding:latest # Chat local (7.6 GB) ollama pull gemma4:12b # Alternativa menor para máquinas com pouca RAM (9.6 GB, MoE) # ollama pull gemma4:e4b # Verificar modelos instalados ollama list ``` **Hardware recomendado**: | Modelo | RAM mínima | RAM recomendada | GPU VRAM (opcional) | |---|---|---|---| | `qwen3-embedding:latest` (8B) | 8 GB | 16 GB | 6 GB | | `gemma4:12b` | 10 GB | 16 GB | 8 GB | | `gemma4:e4b` | 6 GB | 12 GB | 6 GB | ### Configuração do Ollama Por padrão, o Ollama escuta em `localhost:11434`. Se precisar acessar de outro host: ```bash # Editar /etc/systemd/system/ollama.service ou usar env var export OLLAMA_HOST=0.0.0.0:11434 ``` Para otimizar performance com GPU (se disponível): ```bash # Verificar se GPU está sendo usada ollama run gemma4:12b --verbose # Saída: "total duration: ..." — procure por "eval rate: XX tokens/s" ``` ## 2. Arquivo `.env` Criar na raiz do projeto (`backend/.env`): ```bash # ============================================================ # Decompile-AI — Environment Variables # ============================================================ # --- LLM Providers --- # DeepSeek API Key (obter em https://platform.deepseek.com) DEEPSEEK_API_KEY=sk-your-api-key-here # --- Override de modelos (opcional) --- # Provedor padrão de chat: ollama | deepseek AI_DEFAULT_CHAT_PROVIDER=ollama # Modelo de chat Ollama (padrão: gemma4:12b) # AI_CHAT_MODEL_OLLAMA=gemma4:12b # Modelo de chat DeepSeek (padrão: deepseek-chat) # AI_CHAT_MODEL_DEEPSEEK=deepseek-chat # Modelo de embedding (padrão: qwen3-embedding:latest) # AI_EMBEDDING_MODEL=qwen3-embedding:latest # Dimensão do embedding (padrão: 1024, max 4096 para qwen3) # AI_EMBEDDING_DIMENSION=1024 # --- Database --- # Sobrescrever credenciais do Postgres se necessário # SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/decompile_ai # SPRING_DATASOURCE_USERNAME=decompile_ai # SPRING_DATASOURCE_PASSWORD=decompile_ai ``` **Importante**: Adicione `.env` ao `.gitignore`: ```bash echo ".env" >> .gitignore ``` ## 3. Carregamento do `.env` O Spring Boot precisa saber como carregar o `.env`. Opções: ### Opção A: `spring.config.import` (nativo Spring Boot) Adicionar ao `application.yml`: ```yaml spring: config: import: optional:file:.env[.properties] ``` Isso carrega o `.env` como um arquivo de propriedades. **Limitação**: não suporta substituição de variáveis inline como `${VAR}` dentro de outras variáveis no `.env`, mas funciona bem para definir valores. ### Opção B: Plugin `dotenv` (recomendado para desenvolvimento) Adicionar dependência ao `pom.xml`: ```xml me.paulschwarz spring-dotenv 4.0.0 ``` Suporta interpolação de variáveis e convenção `.env` padrão. ### Opção C: Export manual (desenvolvimento) ```bash set -a && source .env && set +a ./mvnw spring-boot:run ``` ## 4. `application.yml` — Configuração do Módulo AI ### Blocos a adicionar ao arquivo existente ```yaml spring: # ... configurações existentes (datasource, jpa, flyway, rabbitmq) ... ai: ollama: base-url: http://localhost:11434 embedding: options: model: ${AI_EMBEDDING_MODEL:qwen3-embedding:latest} chat: options: model: ${AI_CHAT_MODEL_OLLAMA:gemma4:12b} temperature: 0.3 # respostas determinísticas para análise técnica top-p: 0.95 top-k: 64 openai: base-url: https://api.deepseek.com api-key: ${DEEPSEEK_API_KEY} chat: options: model: ${AI_CHAT_MODEL_DEEPSEEK:deepseek-chat} temperature: 0.3 max-tokens: 4096 app: # ... configurações existentes (storage, rabbitmq, docker, die, engines) ... ai: # Provedor padrão de chat quando a sessão não especifica modelo default-chat-provider: ${AI_DEFAULT_CHAT_PROVIDER:ollama} # --- Configurações de Embedding --- embedding: # Dimensão do vetor (qwen3-embedding suporta 32-4096) # DEVE corresponder à coluna vector(N) na migration V008 dimension: ${AI_EMBEDDING_DIMENSION:1024} # Tamanho máximo do chunk em caracteres chunk-max-chars: 3000 # Quantas funções processar por batch na API de embedding batch-size: 20 # --- Configurações de RAG --- rag: # Quantos chunks retornar na busca semântica top-k: 10 # Similaridade mínima para incluir um chunk (0.0 a 1.0) similarity-threshold: 0.6 # Máximo de tokens de contexto enviados à LLM max-context-tokens: 8000 # --- Configurações de Chat --- chat: # Quantas mensagens de histórico incluir no prompt max-history-messages: 20 # Temperatura padrão para geração temperature: 0.3 ``` ### Configuração completa do `application.yml` (após merge) ```yaml spring: threads: virtual: enabled: true application: name: decompile-ai config: import: optional:file:.env[.properties] datasource: url: jdbc:postgresql://localhost:5432/decompile_ai username: decompile_ai password: decompile_ai jpa: hibernate: ddl-auto: validate flyway: enabled: true rabbitmq: host: localhost port: 5672 username: guest password: guest servlet: multipart: max-file-size: 500MB max-request-size: 500MB ai: ollama: base-url: http://localhost:11434 embedding: options: model: ${AI_EMBEDDING_MODEL:qwen3-embedding:latest} chat: options: model: ${AI_CHAT_MODEL_OLLAMA:gemma4:12b} temperature: 0.3 top-p: 0.95 top-k: 64 openai: base-url: https://api.deepseek.com api-key: ${DEEPSEEK_API_KEY} chat: options: model: ${AI_CHAT_MODEL_DEEPSEEK:deepseek-chat} temperature: 0.3 max-tokens: 4096 app: storage: upload-dir: ./uploads/binaries rabbitmq: exchange: decompile.jobs queue: decompile.jobs.queue routing-key: decompile.jobs.created docker: enabled: true die: image: decompile-ai/diec:latest timeout-seconds: 60 docker-host: unix:///var/run/docker.sock engines: ida5: image: decompile-ai/ida5:latest timeout-seconds: 300 ghidra: image: decompile-ai/ghidra:latest timeout-seconds: 600 ai: default-chat-provider: ${AI_DEFAULT_CHAT_PROVIDER:ollama} embedding: dimension: ${AI_EMBEDDING_DIMENSION:1024} chunk-max-chars: 3000 batch-size: 20 rag: top-k: 10 similarity-threshold: 0.6 max-context-tokens: 8000 chat: max-history-messages: 20 temperature: 0.3 logging: level: org.springframework.modulith: DEBUG ai.decompile.ai: DEBUG # Logs do módulo AI org.springframework.ai: INFO # Logs do Spring AI ``` ## 5. `docker-compose.yml` (sem alterações) O `docker-compose.yml` atual já atende todos os requisitos: ```yaml services: postgres: container_name: decompile-ai-postgres image: pgvector/pgvector:pg18 # PostgreSQL 18 + pgvector nativo environment: - POSTGRES_USER=decompile_ai - POSTGRES_PASSWORD=decompile_ai - POSTGRES_DB=decompile_ai ports: - "5432:5432" volumes: - postgres:/var/lib/postgresql networks: - decompile-ai-network rabbit-mq: container_name: decompile-ai-rabbitmq image: rabbitmq:4-management ports: - "5672:5672" - "15672:15672" networks: - decompile-ai-network networks: decompile-ai-network: driver: bridge volumes: postgres: ``` **Não adicionamos Ollama ao docker-compose** porque ele roda no host. ## 6. Startup ### Ordem de inicialização ```bash # 1. Infraestrutura Docker docker compose up -d postgres rabbit-mq # 2. Verificar Ollama no host ollama list # Deve mostrar: qwen3-embedding:latest, gemma4:12b # 3. Configurar .env cp .env.example .env # Editar com a DEEPSEEK_API_KEY # 4. Iniciar o backend ./mvnw spring-boot:run # 5. Verificar health curl http://localhost:8080/actuator/health ``` ### Verificação de saúde dos componentes AI ```bash # Ollama curl http://localhost:11434/api/tags | jq '.models[].name' # Testar embedding curl http://localhost:11434/api/embed -d '{ "model": "qwen3-embedding:latest", "input": "test" }' | jq '.embeddings[0] | length' # Deve retornar 1024 (ou dimensão configurada) # Testar chat local curl http://localhost:11434/api/chat -d '{ "model": "gemma4:12b", "messages": [{"role": "user", "content": "Hello"}], "stream": false }' | jq '.message.content' ``` ## 7. Troubleshooting ### Ollama não responde ```bash # Verificar se está rodando systemctl status ollama # ou ps aux | grep ollama # Reiniciar se necessário systemctl restart ollama ``` ### Erro: "model not found" ```bash # Listar modelos disponíveis ollama list # Baixar modelo faltante ollama pull qwen3-embedding:latest ollama pull gemma4:12b ``` ### Erro: "DeepSeek API key not configured" - Verificar se `.env` existe e contém `DEEPSEEK_API_KEY=sk-...` - Verificar se `spring.config.import: optional:file:.env[.properties]` está no `application.yml` - Alternativa: `export DEEPSEEK_API_KEY=sk-...` no terminal ### Erro: "relation 'vector_store' does not exist" - Verificar se Flyway rodou a migration V008: `SELECT * FROM flyway_schema_history;` - Rodar manualmente se necessário: `./mvnw flyway:migrate` ### Erro: "column 'embedding' type vector not supported" - Verificar se a extensão pgvector está ativada: `SELECT * FROM pg_extension WHERE extname = 'vector';` - Ativar manualmente: `CREATE EXTENSION IF NOT EXISTS vector;` ### Performance lenta nos embeddings - Reduzir `batch-size` no `application.yml` - Verificar se o Ollama está usando GPU: `ollama run qwen3-embedding --verbose` e checar `eval rate` - Sem GPU, o modelo 8B pode ser lento para centenas de funções (esperar 2-5 minutos) ### Contexto da LLM estourando - Reduzir `max-context-tokens` em `app.ai.rag` - Reduzir `max-history-messages` em `app.ai.chat` - Aumentar `chunk-max-chars` (para incluir menos chunks maiores)