Engenharia de Prompt Avançada: Da Escrita à Gestão Sistemática de Prompts

Evolução da Engenharia de Prompt

A maioria das equipes passa por três fases no desenvolvimento de prompts para sistemas de IA. Na Fase de Exploração Individual, prompts são armazenados em documentos pessoais, notas ou comentários de código. O ajuste é baseado em intuição, sem métricas claras, comum em equipes de 3 a 10 membros. A Fase de Expansão Caótica ocorre com o aumento da complexidade do produto, onde múltiplas versões de prompts são mantidas por diferentes membros, levando a conflitos e efeitos colaterais não monitorados. A Fase de Gestão Sistemática envolve controle de versões, frameworks de teste e quantificação de mudanças, permitindo colaboração sem interferências mútuas. O objetivo é guiar equipes das fases iniciais para a gestão estruturada.

Templates de Prompt com Injeção de Variáveis

Prompts em produção não são strings estáticos; são templates com variáveis dinâmicas. Implementando uma classe para gerenciar templates:

from string import Template
from typing import Dict, Any, List
import jinja2

class ModeloPrompt:
    def __init__(self, modelo_str: str, variaveis_obrigatorias: List[str] = None):
        self.modelo_str = modelo_str
        self.variaveis_obrigatorias = variaveis_obrigatorias or []
        self.ambiente = jinja2.Environment(
            undefined=jinja2.StrictUndefined
        )
        self.modelo = self.ambiente.from_string(modelo_str)

    def renderizar(self, **kwargs) -> str:
        variaveis_faltantes = [v for v in self.variaveis_obrigatorias if v not in kwargs]
        if variaveis_faltantes:
            raise ValueError(f"Variáveis obrigatórias ausentes: {variaveis_faltantes}")
        return self.modelo.render(**kwargs)

    def extrair_variaveis(self) -> List[str]:
        analise = self.ambiente.parse(self.modelo_str)
        return list(jinja2.meta.find_undeclared_variables(analise))

# Exemplo de uso
prompt_suporte = ModeloPrompt(
    modelo_str="""Você é um assistente de suporte. Responda com base nos documentos fornecidos.
Documentos: {% for doc in documentos %}[{{ loop.index }}] {{ doc.conteudo }}{% endfor %}
Pergunta do usuário: {{ pergunta_usuario }}
Requisitos: use apenas informações dos documentos; se insuficiente, declare isso; idioma: {{ idioma | default('pt') }}""",
    variaveis_obrigatorias=["documentos", "pergunta_usuario"]
)

resultado = prompt_suporte.renderizar(
    documentos=[{"conteudo": "Política de reembolso: 7 dias sem motivo"}, {"conteudo": "Tempo de entrega: 3-5 dias úteis"}],
    pergunta_usuario="Posso solicitar reembolso?",
    idioma="pt"
)

Gerenciamento Multilíngue de Prompts

Para produtos interncaionais, prompts precisam de variantes por idioma. Um registro centralizado facilita a manutenção:

REGISTRO_PROMPTS = {
    "suporte_cliente": {
        "pt": "Você é um assistente de suporte. Responda em português...",
        "en": "You are a support assistant. Respond in English...",
        "es": "Eres un asistente de soporte. Responde en español..."
    },
    "revisao_codigo": {
        "pt": "Analise o seguinte código como especialista...",
        "en": "Analyze the code as a specialist..."
    }
}

def obter_prompt(nome_prompt: str, idioma: str = "pt") -> str:
    prompts = REGISTRO_PROMPTS.get(nome_prompt, {})
    return prompts.get(idioma, prompts.get("en", ""))

Controle de Versões de Prompts

Baseado em Git

Tratar prompts como código-fonte, versionando com Git. Estrutura de diretórios:

projeto/
  prompts/
    v1/
      prompt_sistema.txt
      prompt_rag.txt
    v2/
      prompt_sistema.txt
      prompt_rag.txt
    atual -> v2/  # link simbólico para a versão ativa
    changelog.md

Exemplo de changelog em Markdown:

# Registro de Alterações de Prompt

## v2.0 (2026-05-20)
### Mudanças
- prompt_sistema: adicionar restrição "responda de forma concisa" para reduzir respostas verbosas.
- prompt_rag: otimizar formato de referência para lista numerada.
### Efeitos
- Comprimento médio das respostas reduzido em 30%.
- Satisfação do usuário aumentada de 78% para 84% (teste A/B, n=1000).

## v1.5 (2026-05-10)
...

Baseado em Banco de Dados

Para escala, um sistema de versionamento dedicado usando SQLAlchemy:

from sqlalchemy import Column, String, Text, DateTime, Integer, Boolean
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime

Base = declarative_base()

class VersaoPrompt(Base):
    __tablename__ = "versoes_prompts"
    id = Column(Integer, primary_key=True)
    nome_prompt = Column(String(100), nullable=False)
    versao = Column(String(20), nullable=False)
    conteudo = Column(Text, nullable=False)
    descricao = Column(Text)
    autor = Column(String(50))
    criado_em = Column(DateTime, default=datetime.now)
    ativo = Column(Boolean, default=False)
    pontuacao_avaliacao = Column(Float)
    tamanho_amostra_avaliacao = Column(Integer)

class GerenciadorPrompts:
    def __init__(self, sessao_db):
        self.db = sessao_db

    def criar_versao(self, nome: str, versao: str, conteudo: str, descricao: str, autor: str) -> VersaoPrompt:
        nova_versao = VersaoPrompt(
            nome_prompt=nome,
            versao=versao,
            conteudo=conteudo,
            descricao=descricao,
            autor=autor
        )
        self.db.add(nova_versao)
        self.db.commit()
        return nova_versao

    def ativar_versao(self, nome: str, versao: str):
        self.db.query(VersaoPrompt).filter(
            VersaoPrompt.nome_prompt == nome,
            VersaoPrompt.ativo == True
        ).update({"ativo": False})
        self.db.query(VersaoPrompt).filter(
            VersaoPrompt.nome_prompt == nome,
            VersaoPrompt.versao == versao
        ).update({"ativo": True})
        self.db.commit()

    def obter_versao_ativa(self, nome: str) -> str:
        versao = self.db.query(VersaoPrompt).filter(
            VersaoPrompt.nome_prompt == nome,
            VersaoPrompt.ativo == True
        ).first()
        return versao.conteudo if versao else None

Framework de Avaliação de Prompts

Quantificar a qualidade de prompts é essencial. Utilize LLMs para avaliação automática:

import json
from openai import OpenAI

cliente = OpenAI()

class AvaliadorPrompt:
    CRITERIOS = {
        "precisao": "Avaliar se a resposta é correta e consistente com referências.",
        "completude": "Verificar se informações-chave não foram omitidas.",
        "concisao": "Checar se a resposta é direta, sem redundâncias.",
        "relevancia": "Confirmar se a resposta aborda a pergunta real."
    }

    def avaliar_individual(self, pergunta: str, resposta: str, referencia: str = None, criterios: List[str] = None) -> Dict:
        criterios = criterios or list(self.CRITERIOS.keys())
        prompt_avaliacao = f"""
        Avalie a resposta da IA abaixo em uma escala de 1 a 5 (5 = melhor) para cada critério.
        Pergunta: {pergunta}
        Resposta da IA: {resposta}
        {"Referência: " + referencia if referencia else ""}
        Critérios: {chr(10).join([f"- {c}: {self.CRITERIOS[c]}" for c in criterios])}
        Retorne em JSON: {{"precisao": 4, "completude": 3, ...}}.
        """
        resultado = cliente.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": prompt_avaliacao}],
            response_format={"type": "json_object"}
        )
        return json.loads(resultado.choices[0].message.content)

    def avaliar_lote(self, casos_teste: List[Dict], conteudo_prompt: str) -> Dict:
        pontuacoes = []
        for caso in casos_teste:
            resposta = self.gerar_resposta(conteudo_prompt, caso["pergunta"])
            pontuacao = self.avaliar_individual(
                pergunta=caso["pergunta"],
                resposta=resposta,
                referencia=caso.get("resposta_referencia")
            )
            pontuacoes.append(pontuacao)
        return {
            "tamanho_amostra": len(pontuacoes),
            "media_precisao": sum(p["precisao"] for p in pontuacoes) / len(pontuacoes),
            "media_completude": sum(p["completude"] for p in pontuacoes) / len(pontuacoes),
            "media_concisao": sum(p["concisao"] for p in pontuacoes) / len(pontuacoes),
            "media_relevancia": sum(p["relevancia"] for p in pontuacoes) / len(pontuacoes)
        }

Testes A/B para Prompts

Implementar testes controlados para comparar versões de prompts:

import hashlib

class TesteABPrompts:
    def __init__(self, prompt_controle: str, prompt_tratamento: str, taxa: float = 0.5):
        self.controle = prompt_controle
        self.tratamento = prompt_tratamento
        self.taxa = taxa
        self.resultados = {"controle": [], "tratamento": []}

    def obter_prompt(self, id_usuario: str) -> Tuple[str, str]:
        hash_valor = int(hashlib.md5(id_usuario.encode()).hexdigest(), 16) % 100
        if hash_valor < self.taxa * 100:
            return "tratamento", self.tratamento
        else:
            return "controle", self.controle

    def registrar_feedback(self, id_usuario: str, satisfeito: bool):
        grupo, _ = self.obter_prompt(id_usuario)
        self.resultados[grupo].append(1 if satisfeito else 0)

    def obter_estatisticas(self) -> Dict:
        def calcular_stats(dados):
            n = len(dados)
            if n == 0:
                return {"n": 0, "taxa": None}
            return {"n": n, "taxa": sum(dados) / n}

        stats_controle = calcular_stats(self.resultados["controle"])
        stats_tratamento = calcular_stats(self.resultados["tratamento"])
        return {
            "controle": stats_controle,
            "tratamento": stats_tratamento,
            "melhoria": (stats_tratamento["taxa"] - stats_controle["taxa"]) / stats_controle["taxa"]
            if stats_controle["taxa"] and stats_controle["n"] > 30 and stats_tratamento["n"] > 30 else None
        }

Segurança contra Injeção de Prompts

Proteger prompts em produção contra ataques de injeção:

import re

class SanitizadorPadrao:
    PADROES_INJECAO = [
        r"ignore\s+previous\s+instructions",
        r"forget\s+everything",
        r"you\s+are\s+now",
        r"act\s+as\s+if",
        r"pretend\s+you\s+are",
        r"ignore\s+as\s+instruções\s+anteriores",
        r"você\s+agora\s+é",
        r"finja\s+ser"
    ]

    def eh_seguro(self, entrada_usuario: str) -> bool:
        entrada_minuscula = entrada_usuario.lower()
        for padrao in self.PADROES_INJECAO:
            if re.search(padrao, entrada_minuscula, re.IGNORECASE):
                return False
        return True

    def sanitizar(self, entrada_usuario: str) -> str:
        if not self.eh_seguro(entrada_usuario):
            import logging
            logging.warning(f"Possível injeção de prompt detectada: {entrada_usuario[:100]}")
            return "[Conteúdo filtrado devido a instruções não permitidas]"
        return entrada_usuario

Fluxo de Trabalho para Gestão Sistemática

Integrar prompts em ambientes de desenvolvimento, teste e produção:

  • Ambiente de Desenvolvimento: Escrever prompts com versionamento, revisão por pares.
  • Ambiente de Teste: Executar avaliações automatizadas, comparar com baselines, auditar segurança.
  • Ambiente de Produção: Implementar via testes A/B, monitorar métricas, coletar feedback para iteração.

Este ciclo contínuo assegura que prompts evoluam de forma controlada, com mudanças rastreáveis e efeitos mensuráveis. A transição para uma abordagem baseada em dados transforma prompts em componentes gerenciáveis do produto.

Tags: Prompt-Engineering version-control evaluation-framework safety-auditing multilingual-management

Publicado em 6-7 22:12 por Thomas