backend/docs/ai/configuration.md
Rodrigo Verdiani 90ee74b3b9 docs: add AI module documentation and AGENTS.md
Comprehensive documentation for the AI module covering architecture,
API design, data model, RAG pipeline, configuration, integration points,
and frontend integration guide. Includes IDA5 extraction points reference
and AGENTS.md with project conventions and coding standards.
2026-06-08 20:13:21 -03:00

11 KiB

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 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

# Linux
curl -fsSL https://ollama.com/install.sh | sh

# Verificar se está rodando
ollama --version
curl http://localhost:11434/api/tags

Download dos Modelos

# 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:

# 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):

# 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):

# ============================================================
# 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:

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:

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:

<dependency>
  <groupId>me.paulschwarz</groupId>
  <artifactId>spring-dotenv</artifactId>
  <version>4.0.0</version>
</dependency>

Suporta interpolação de variáveis e convenção .env padrão.

Opção C: Export manual (desenvolvimento)

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

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)

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:

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

# 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

# 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

# Verificar se está rodando
systemctl status ollama
# ou
ps aux | grep ollama

# Reiniciar se necessário
systemctl restart ollama

Erro: "model not found"

# 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)