Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 43

Generating MariaDB Migration Scripts

Recommended resources

Olá! Bem-vindo de volta.

Na lição anterior, estabelecemos os princípios das migrações de esquema de banco de dados, entendendo por que elas são essenciais para a evolução segura e controlada de uma aplicação. Vimos que tratar as alterações de banco de dados como código versionado, integrado ao pipeline de CI/CD, é a prática padrão em ambientes de desenvolvimento modernos.

Hoje, vamos dar o passo seguinte e nos concentrar em como fazer com que um agente de IA execute uma parte crucial desse processo. Esta lição aborda o resultado de aprendizagem: Instruir o agente a gerar um script de migração de banco de dados MariaDB (DDL) com base nos requisitos da tarefa.

Isso nos aproxima diretamente do seu objetivo, pois a capacidade de gerar scripts de migração corretos a partir de uma tarefa do Jira é uma das funcionalidades centrais do agente de código que você planeja construir.

1. O Desafio: De Linguagem Natural para DDL

Gerar SQL a partir de linguagem natural (um campo conhecido como NL2SQL ou Text-to-SQL) é uma tarefa complexa para os LLMs. Gerar Data Definition Language (DDL), como CREATE TABLE ou ALTER TABLE, para migrações não é exceção.

Para entender por que isso é desafiador e por que um prompt simples como "adicione uma coluna X" pode falhar, é útil conhecer os obstáculos.

Enterprise-grade natural language to SQL generation using LLMs

Este artigo da AWS, embora focado em gerar consultas (DQL), descreve desafios que são igualmente relevantes para a geração de DDL. Ele fornecerá a base teórica para entendermos por que a engenharia de prompts é tão crucial aqui.

Leia as seções 'Specific challenges for enterprise-scale NL2SQL' e 'Solution design and methodology'. Preste atenção nos seguintes pontos: Complex schemas: Os LLMs podem ter dificuldade em entender os relacionamentos em um esquema de banco de dados do mundo real. LLM knowledge gap: O modelo não conhece a semântica específica do seu negócio ou as regras implícitas no seu esquema. Solution design: A solução proposta envolve 'quebrar o problema' e 'restringir o escopo', que são exatamente as estratégias que usaremos para instruir nosso agente.

Essencialmente, para que o agente gere um DDL de migração correto, ele precisa de um contexto rico e inequívoco. Ele não pode adivinhar. Precisamos fornecer a ele:

  1. O estado atual do esquema.
  2. A tarefa específica a ser realizada.
  3. As regras e restrições que ele deve seguir (como o dialeto SQL e as melhores práticas).

2. Construindo o Prompt Perfeito: Contexto é Tudo

Vamos agora estruturar um prompt que forneça todo o contexto necessário para o agente. Sua experiência como desenvolvedor será útil aqui, pois veremos que um prompt bem estruturado se assemelha a uma especificação de API bem definida.

2.1. Fornecendo o Esquema Atual

O agente não pode alterar algo que não conhece. Portanto, o primeiro e mais importante pedaço de contexto é a definição (DDL) das tabelas relevantes existentes.

Existem várias maneiras de obter isso:

  • Consulta Dinâmica: O agente pode consultar o banco de dados diretamente. Para MariaDB (e MySQL), o comando SHOW CREATE TABLE nome_da_tabela; é extremamente útil, pois retorna o DDL exato para recriar a tabela.
  • Esquema Codificado: Para cenários mais simples ou para focar o agente, o esquema pode ser fornecido diretamente no prompt.

Build Database Agents That Get Smarter With Every Query (n8n)

Este vídeo demonstra várias abordagens para fornecer contexto de esquema a um agente de banco de dados. Embora use n8n e PostgreSQL, os princípios são universais.

Assista aos trechos de 02:35 a 04:45 e de 16:27 a 17:41. Observe as duas estratégias principais: Obter o esquema dinamicamente: O agente primeiro consulta o banco de dados para obter o esquema e depois usa essa informação para construir a consulta final. Hardcodificar o esquema no prompt do sistema: O esquema é inserido diretamente no prompt, o que simplifica o fluxo e foca a atenção do agente.

Para o nosso agente, a abordagem dinâmica é a mais robusta. O plano de ação do agente incluiria uma etapa para executar SHOW CREATE TABLE nas tabelas mencionadas na tarefa do Jira.

2.2. Estruturando o Prompt com Tags

Um prompt de texto simples pode se tornar ambíguo. Uma técnica muito eficaz, especialmente para tarefas de geração de código, é usar uma estrutura de tags (como XML) para delinear claramente cada parte do contexto.

Prompt Engineering Master Class for ENGINEERS with Ollama and LLM (Q4 2024 Update)

Este vídeo sobre engenharia de prompts mostra como o uso de uma estrutura XML melhora drasticamente o desempenho do LLM, especialmente para modelos menores ou tarefas complexas.

Assista ao trecho de 07:56 a 12:20. O apresentador transforma um prompt 'ad-hoc' em um 'prompt reutilizável de nível dois' usando tags XML como <purpose>, <instructions> e uma variável para o input. Note como essa estrutura ajuda o modelo a entender melhor a tarefa e a produzir saídas mais precisas e consistentes.

Combinando essas ideias, podemos criar um template de prompt para o nosso agente gerar DDL:

<prompt>
  <role>
    Você é um especialista em administração de banco de dados MariaDB, responsável por gerar scripts de migração (DDL).
  </role>

  <dialect>
    MariaDB 10.6
  </dialect>

  <existing_schema>
    -- O agente inseriria aqui o output de 'SHOW CREATE TABLE ...'
    CREATE TABLE `users` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(255) NOT NULL,
      `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
      PRIMARY KEY (`id`),
      UNIQUE KEY `username` (`username`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  </existing_schema>

  <task_description>
    -- O agente inseriria aqui a descrição da tarefa do Jira
    Adicionar uma nova coluna à tabela 'users' para armazenar o endereço de e-mail do usuário. 
    A coluna deve se chamar 'email', ser uma string de até 255 caracteres,
    e deve ser obrigatória (não nula) e única em toda a tabela.
  </task_description>

  <instructions>
    1. Gere um único e válido statement `ALTER TABLE` para o dialeto MariaDB.
    2. A nova coluna deve ser adicionada após a coluna 'username'.
    3. Responda APENAS com o código SQL. Não inclua explicações.
  </instructions>
</prompt>

Este formato estruturado e rico em contexto aumenta drasticamente a probabilidade de o LLM gerar o DDL correto na primeira tentativa.


3. Garantindo a Segurança e a Robustez: Scripts Idempotentes

Na lição anterior, mencionamos o planejamento de rollback. Uma prática relacionada e igualmente crucial é a idempotência. Um script idempotente pode ser executado várias vezes, mas o resultado final será o mesmo que se tivesse sido executado apenas uma vez.

Isso é vital para a robustez de um pipeline de automação. Se um script de migração falhar no meio e precisar ser executado novamente, ele não deve gerar erros como "a coluna já existe".

Creating Idempotent DDL Scripts for Database Migrations | Redgate

Este artigo da Redgate é uma excelente referência sobre como e por que escrever DDL idempotente. Ele fornece a lógica e exemplos práticos.

Leia as seções 'The uncontrolled hotfix', 'The solution: idempotent SQL migration scripts', 'Idempotency using Guard clauses', e 'Safely altering a column'. Os pontos-chave são: Definição de Idempotência: Entenda que se trata de verificar se uma alteração já foi feita antes de tentar fazê-la. Guard Clauses: O uso de 'cláusulas de guarda' (ex: IF NOT EXISTS) é a técnica principal para alcançar a idempotência. Uso do INFORMATION_SCHEMA: O artigo menciona que MariaDB suporta o INFORMATION_SCHEMA padrão ANSI, que é a forma portável de verificar o estado do esquema (ex: INFORMATION_SCHEMA.COLUMNS para verificar se uma coluna existe).

Embora muitas ferramentas de migração (como Flyway ou o sistema do Entity Framework) garantam que um script de migração seja executado apenas uma vez, ensinar seu agente a gerar scripts inerentemente idempotentes é uma prática de engenharia superior. Isso torna seu sistema mais resiliente a falhas e intervenções manuais.

Para instruir o agente a fazer isso, podemos adicionar uma instrução específica ao nosso prompt:

  <instructions>
    ...
    4. O script deve ser idempotente. Use o INFORMATION_SCHEMA para verificar se a coluna já existe antes de tentar adicioná-la.
  </instructions>

4. Juntando Tudo: Exemplo Completo para o Agente

Vamos simular o processo completo que seu agente seguiria para uma tarefa.

Cenário: Uma tarefa no Jira com a tag db-migration tem a descrição: "O perfil do usuário precisa de um campo bio para uma pequena biografia. Deve ser um campo de texto e opcional."

O fluxo de trabalho do agente, que você projetará, seria:

  1. Analisar a Tarefa: Extrair a intenção: adicionar a coluna bio à tabela users.
  2. Obter Contexto do Esquema: Conectar-se ao banco de dados e executar SHOW CREATE TABLE users;.
  3. Construir o Prompt: Montar o prompt estruturado com todas as informações.
  4. Invocar o LLM: Enviar o prompt para o modelo de IA (por exemplo, um dos modelos da Atlassian).
  5. Receber e Validar o DDL: Receber a resposta e, idealmente, validá-la.
  6. Criar o Arquivo de Migração: Salvar o DDL recebido em um novo arquivo de migração com um nome versionado (ex: V20240905103000__Add_bio_to_users.sql).

Aqui está como o prompt final se pareceria:

<prompt>
  <role>
    Você é um especialista em administração de banco de dados MariaDB, responsável por gerar scripts de migração (DDL).
  </role>

  <dialect>
    MariaDB 10.6
  </dialect>

  <existing_schema>
    CREATE TABLE `users` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(255) NOT NULL,
      `email` varchar(255) NOT NULL,
      `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
      PRIMARY KEY (`id`),
      UNIQUE KEY `username` (`username`),
      UNIQUE KEY `email` (`email`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  </existing_schema>

  <task_description>
    O perfil do usuário precisa de um campo `bio` para uma pequena biografia. Deve ser um campo de texto e opcional.
  </task_description>

  <instructions>
    1. Gere um único e válido statement `ALTER TABLE` para adicionar a coluna `bio` à tabela `users`.
    2. O tipo de dados deve ser `TEXT`.
    3. Como o campo é opcional, a coluna deve ser `NULLABLE`. Isso também garante a compatibilidade com versões anteriores da aplicação, um princípio fundamental das migrações.
    4. Responda APENAS com o código SQL.
  </instructions>
</prompt>

A saída esperada do LLM seria:

ALTER TABLE `users` ADD COLUMN `bio` TEXT NULL DEFAULT NULL;

Essa saída é limpa, correta e pronta para ser salva em um arquivo de migração.


Conclusão

Nesta lição, passamos da teoria para a prática da geração de DDL. Vimos como instruir um agente de IA a criar scripts de migração para MariaDB, uma etapa fundamental para automatizar tarefas de desenvolvimento.

Principais Pontos:

  • Contexto é fundamental: Para gerar DDL preciso, o agente precisa do esquema existente, da descrição da tarefa e de um conjunto claro de regras.
  • Prompts Estruturados: Usar um formato como XML para estruturar os prompts aumenta a confiabilidade e o desempenho do LLM, tratando o prompt como uma especificação.
  • Especificação de Regras: As instruções no prompt são onde codificamos as melhores práticas, como especificar o dialeto SQL (MariaDB) e garantir a compatibilidade com versões anteriores (ex: tornando novas colunas NULLABLE).
  • Idempotência: Projetar scripts que podem ser executados várias vezes sem causar erros é uma prática de engenharia robusta que torna a automação mais resiliente.

Na Próxima Lição

Até agora, aprendemos a gerar código para o backend, para o frontend e, hoje, scripts para o banco de dados. Temos todas as "peças" que o agente pode criar. A próxima etapa é juntar tudo.

Na primeira lição do próximo módulo, Orchestrating the End-to-End Workflow, abordaremos o resultado de aprendizagem: Implementar a lógica de orquestração principal que executa o plano do agente passo a passo. Veremos como criar a sequência de ações que pega uma tarefa do Jira e a leva até um Pull Request completo, com alterações em múltiplos repositórios e a migração de banco de dados correspondente.