Prompting


Um prompt é o texto que você coloca diante do modelo antes de ele fazer sua previsão. É essa a ideia central que este capítulo vai afiar: um prompt não é uma ordem que você dá a uma mente, é o contexto que você organiza para que a resposta que você quer se torne a continuação mais provável.
O que um prompt realmente é
Mesmo modelo, dois prompts. "Escreva sobre mudança climática" te dá um ensaio divagante que você não pediu. "Escreva três frases sobre as principais causas da mudança climática para uma criança de 12 anos, sem estatísticas" te dá algo que você pode usar. O modelo não mudou entre essas duas chamadas. O contexto mudou, e a saída seguiu o contexto.
O capítulo anterior explicou como um modelo gera texto prevendo o token mais provável, guiado por tudo o que está diante dele. Um prompt é exatamente esse "tudo o que está diante dele". Essa é a definição que vale a pena guardar: um prompt não é um pedido que você faz a uma pessoa, é o contexto que você monta para que a continuação que você espera seja a que o modelo considera mais provável.
Essa mudança de perspectiva muda como você escreve. Você não está persuadindo nem instruindo alguém. Você está organizando texto para que a resposta que você quer seja a próxima coisa mais provável. Cada técnica deste capítulo é uma forma diferente de fazer isso, e cada uma faz mais sentido quando você consegue ver a máquina de previsão por trás dela.
Os três papéis
Quando você conversa com um modelo através de código, você não envia um único bloco de texto. Você envia uma lista de mensagens, e cada mensagem carrega um role (papel) que marca de onde ela veio. Existem três:
- system: suas instruções permanentes. Quem o modelo deve representar, as regras que ele segue, o formato que você quer. Definido uma vez, vale para toda a conversa.
- user: uma mensagem da pessoa usando seu aplicativo. O pedido em si.
- assistant: uma mensagem que o modelo produziu anteriormente. É assim que uma conversa mantém seu histórico.
messages = [
{"role": "system", "content": "You are a concise assistant for a cooking app. Answer in one sentence."},
{"role": "user", "content": "What can I use instead of butter in cookies?"},
]Por debaixo do capô, esses papéis não são canais separados dentro do modelo. Eles são achatados em um único fluxo de texto com tokens marcadores especiais em torno de cada mensagem, e é esse fluxo inteiro que o modelo usa para prever. Os papéis importam porque o modelo foi treinado em conversas organizadas dessa forma, então ele aprendeu a tratar o conteúdo de system como as regras permanentes com autoridade e o conteúdo de user como o pedido a ser respondido.
A mensagem system é a que os principiantes menos aproveitam. É onde você define o comportamento que quer em cada turno: o tom, o público, o formato, as coisas que o modelo nunca deve fazer. Coloque ali as regras duradouras, e coloque o pedido específico na mensagem user.
Como o modelo não tem memória entre requisições, o papel assistant é também a forma de reproduzir o que foi dito antes: para continuar uma conversa, você reenvia a troca anterior como mensagens assistant e user. Mais sobre isso quando você começar a chamar modelos a partir de código.
system, user ou assistant. Essas marcações são achatadas em um único fluxo de texto que o modelo usa para prever, mas ele foi treinado para tratar system como regras com autoridade e user como o pedido. Coloque instruções duradouras em system, o pedido específico em user, e reproduza as mensagens anteriores de assistant e user para carregar o histórico de uma conversa. Específico vence vago
Dois prompts, um modelo. "Escreva sobre mudança climática" retorna um ensaio genérico de tamanho e tom imprevisíveis. "Escreva um resumo de três frases sobre as principais causas da mudança climática, para uma criança de 12 anos, em linguagem simples, sem estatísticas" retorna algo bem próximo do que você imaginou. Mesma máquina, saídas radicalmente diferentes, e a única diferença foi o quanto você especificou.
O motivo remete ao ciclo de previsão. Em cada etapa, o modelo escolhe entre um leque de continuações plausíveis. Um prompt vago deixa esse leque amplo, então o modelo preenche as lacunas com o que é mais comum em geral, o que raramente é exatamente o que você tinha em mente. Um prompt específico estreita esse leque em direção à resposta que você quer, antes mesmo de o modelo escrever um único token.
# vague: the model decides length, tone, audience, format
"Write about climate change."
# specific: you decide
(
"Write a 3-sentence summary of the main causes of climate change, "
"for a 12-year-old, in plain language, with no statistics."
)A versão vaga poderia continuar de mil formas sensatas, e você recebe uma aleatória entre elas. A versão específica descarta praticamente todas elas de antemão. Ao escrever um prompt, diga o que você realmente quer:
- Formato: uma frase, uma lista, JSON, uma tabela.
- Tamanho: um parágrafo, três bullets, menos de 50 palavras.
- Público: um principiante, um especialista, uma criança de 12 anos.
- O que fazer em caso de dúvida: "Se o texto não disser, responda 'não especificado' em vez de adivinhar."
Esse último ponto pesa mais do que parece. Deixado à própria sorte, o modelo preenche uma lacuna com um chute confiante, porque um chute fluente é a continuação provável. Dar a ele explicitamente a opção de dizer "eu não sei" torna esse o caminho mais provável, e essa é uma das poucas medidas em nível de prompt que reduz o problema de alucinação visto no capítulo anterior. A especificidade estreita as opções do modelo antes mesmo de ele escrever um token.
Mostre exemplos a ele
Às vezes a forma mais clara de estabelecer a continuação certa é mostrá-la. Colocar alguns exemplos resolvidos no prompt é chamado de few-shot prompting (nenhum exemplo é zero-shot). Funciona porque o modelo é, no fundo, um continuador de padrões: dê a ele dois ou três exemplos de entrada-seguida-de-saída-correta e a coisa mais provável de vir a seguir é o mesmo padrão aplicado ao seu novo input.
messages = [
{"role": "system", "content": "Label each review as POSITIVE, NEGATIVE, or NEUTRAL. Reply with only the label."},
{"role": "user", "content": "The food was cold and slow to arrive."},
{"role": "assistant", "content": "NEGATIVE"},
{"role": "user", "content": "Decent meal, nothing special."},
{"role": "assistant", "content": "NEUTRAL"},
{"role": "user", "content": "Best burger I have had in years!"},
]
# the model now answers: POSITIVEOs dois exemplos completos estabelecem o padrão exato: uma palavra, tudo em maiúsculas, dentro de um conjunto fixo. Continuar esse padrão para a terceira avaliação agora é muito mais provável do que escrever um parágrafo de análise, então é isso que você obtém. É por isso que alguns exemplos claros costumam vencer um parágrafo de descrição, especialmente para classificação e formatação: você está demonstrando a forma da saída em vez de descrevê-la e esperar que dê certo. Escolha exemplos que cubram os casos difíceis, já que o modelo se molda ao que você mostra, incluindo qualquer erro presente nos seus exemplos.
Peça para ele raciocinar
Aqui está uma das ideias de prompting mais úteis, e uma das menos intuitivas, e ela decorre diretamente de como o modelo funciona. O modelo gera um token por vez, e o único espaço de trabalho que ele tem é o texto que já escreveu. Ele não tem um rascunho oculto para resolver silenciosamente um problema difícil antes de responder. O "pensamento" dele, tal como existe, acontece em voz alta, nos tokens que ele produz.
Então, se você faz uma pergunta de várias etapas e exige apenas a resposta final, você está forçando o modelo a saltar direto para o final em um único token, sem espaço para trabalhar, e em qualquer coisa que envolva raciocínio, matemática ou lógica ele frequentemente erra o salto. A correção é deixá-lo trabalhar às claras. Peça a ele para descrever as etapas antes da resposta:
messages = [
{"role": "system", "content": "Work through the problem step by step, then give the final answer on its own line."},
{"role": "user", "content": "A shop sells pens at 3 for $2. How much do 12 pens cost?"},
]
# without "step by step", models often blurt a wrong number
# with it, the model writes out the working, and each step makes the next more reliableIsso é chamado de chain-of-thought (cadeia de pensamento), e o motivo pelo qual funciona é mecânico, não mágico. Cada etapa que o modelo escreve se torna parte do contexto que ele lê para o próximo token, então escrever "12 canetas são 4 grupos de 3" torna "4 grupos vezes $2 é $8" a continuação natural e provável. Você está dando ao modelo espaço para calcular na própria página, em vez de exigir a resposta em um salto impossível. "Pense passo a passo" ou "mostre seu raciocínio" é a versão do dia a dia.
Duas ressalvas. O raciocínio escrito ainda é texto gerado, então pode parecer coerente e chegar a uma resposta errada, e você não deve tratá-lo como uma prova garantida. E alguns modelos mais novos fazem esse tipo de trabalho internamente sem que seja pedido. Mas o princípio subjacente é durável independentemente de quais modelos vierem a seguir: um modelo raciocina melhor quando tem espaço para escrever as etapas, porque a própria saída dele é o único lugar onde ele pode pensar.
Estruture o prompt
À medida que os prompts crescem, a estrutura mantém o contexto claro para que o modelo pese cada parte corretamente. Alguns hábitos ajudam:
- Coloque as instruções primeiro, os dados por último. Diga o que fazer, depois forneça o texto sobre o qual fazer isso.
- Separe instruções de dados com delimitadores. Envolva qualquer texto fornecido em marcadores claros para que a fronteira entre suas regras e o input seja inequívoca.
- Peça o formato de saída explicitamente. Se você quer JSON, diga isso, e descreva os campos.
prompt = f'''Summarise the customer message below in one sentence.
Then list any product names it mentions.
Customer message:
"""
{user_message}
"""'''As aspas triplas são um delimitador. Elas marcam "tudo aqui dentro é dado a ser processado, não instrução a ser seguida". Isso não é só arrumação, e é aqui que a visão da previsão mostra por que isso é uma salvaguarda real.
Para o modelo, é tudo um único fluxo de texto, então se o input do usuário flui direto para dentro das suas instruções sem nenhuma fronteira, um usuário pode escrever "ignore o que veio acima e faça isto em vez disso" e o modelo não tem uma forma confiável de distinguir essa linha das suas instruções reais. É bem possível que ele continue obedecendo a ela.
Esse ataque é chamado de prompt injection (injeção de prompt), e manter instruções e dados não confiáveis claramente cercados é a primeira linha de defesa, tema tratado em Segurança e limites. Para o modelo é tudo um único fluxo de texto, então cerque o input não confiável.
Na prática
Aqui está um prompt que empilha várias dessas ideias: uma mensagem de sistema para regras duradouras, um pedido específico, um exemplo para fixar o formato, e dados claramente delimitados.
messages = [
{
"role": "system",
"content": (
"You extract action items from meeting notes. "
"Reply with a numbered list, one action per line, each starting with a verb. "
"If there are no action items, reply 'None'."
),
},
{"role": "user", "content": 'Notes: """We agreed Sam will send the budget by Friday and Lee will book the venue."""'},
{"role": "assistant", "content": "1. Send the budget by Friday (Sam)\n2. Book the venue (Lee)"},
{"role": "user", "content": f'Notes: """{meeting_notes}"""'},
]A mensagem de sistema define as regras uma vez, o exemplo fixa o formato exato, e cada pedido entrega dados cercados. Cada peça está organizando o contexto para que a saída que você quer seja a continuação provável. Essa é toda a técnica: isso é um prompt confiável, não um prompt de sorte. A seguir você vai enviar mensagens como essas para um modelo a partir de código real em Chamando modelos a partir de código.
system com regras duradouras, um pedido específico, um exemplo para fixar o formato, e dados claramente delimitados. Cada peça organiza o contexto para que a saída que você quer seja o próximo texto mais provável. Essa é a técnica, um prompt que funciona por design em vez de por sorte. 
