Generative AI and Prompt Engineering

Concepts, mechanics, and a computational treatment of prompt design

Author

Nivedita

Published

August 4, 2026

“Summarizethis resultin plainlanguage”BARE PROMPT+ persona+ context+ example+ formatLLMtoken bytokenp = 0.87sharper outputdistribution
A weak instruction and an engineered one reach the same model, but persona, context, example, and output format push the engineered version toward a single high-probability answer instead of a diffuse guess.

1 Introduction

Generative AI denotes a class of systems that produce new content — text, images, audio, video, or code — rather than only classifying or scoring existing data. A model learns the statistical structure of a training corpus and then samples new instances consistent with that structure, as opposed to mapping fixed inputs onto a fixed set of output labels.

This tutorial covers the material in three layers. First, the conceptual layer: what generative models are, how large language models (LLMs) are trained, and how this differs from conventional machine learning. Second, the mechanical layer: how a prompt actually becomes an output, via token-level sampling — treated computationally, in R, using a toy model, so the abstraction is not left as a black box. Third, the applied layer: prompt engineering as a design discipline, common prompting strategies, and a survey of the current tool landscape, closing with practical guidance and known limitations.

Model and product names change quickly in this field. Where a specific product is named below, the description reflects its status as of mid-2026; several products referenced in earlier training material on this topic (GPT-3, GPT-4, Google Bard, DALL-E, Amazon CodeWhisperer) have since been superseded or renamed, and this is noted explicitly where relevant.

2 What Generative AI Produces

Three domains illustrate the breadth of the category:

Text. Current-generation LLMs — OpenAI’s GPT-5 family, Anthropic’s Claude models, Google’s Gemini, and Meta’s open-weight Llama models — generate essays, code, and dialogue conditioned on a prompt.

Images. Diffusion and autoregressive image models (Midjourney, Stable Diffusion, OpenAI’s GPT Image line, Adobe Firefly) convert a text description into a corresponding image.

Audio and video. Tools such as Suno (music), ElevenLabs (voice), and Runway (video) apply the same generate-from-description paradigm to other modalities.

The common thread is not the modality but the training objective: the model is optimized to produce plausible continuations or reconstructions of its training distribution, not to output a predetermined answer.

3 Generative AI versus Conventional Machine Learning

The distinction is best drawn along five axes rather than treated as a single sharp boundary — a fraud-detection classifier and an LLM are both “machine learning” in the broad sense, but they differ systematically in what they are built to do.

ml_vs_genai <- data.frame(
  aspect       = c("Objective", "Typical output", "Typical training data",
                    "Dominant learning paradigm", "Common architectures", "Example task"),
  machine_learning = c("Predict a label or value from input features",
                        "Class label, score, or continuous value",
                        "Structured / tabular",
                        "Supervised (labeled data)",
                        "Linear/logistic regression, tree ensembles, SVM",
                        "Flagging a fraudulent transaction"),
  generative_ai = c("Produce a new instance consistent with a learned distribution",
                     "Text, image, audio, or video",
                     "Large unstructured corpora (text, image, audio)",
                     "Self-supervised pretraining, often followed by fine-tuning",
                     "Transformer-based architectures (decoder-only LLMs, diffusion models)",
                     "Drafting a paragraph explaining a result"),
  stringsAsFactors = FALSE
)

print(ml_vs_genai, row.names = FALSE)
                     aspect                                machine_learning
                  Objective    Predict a label or value from input features
             Typical output         Class label, score, or continuous value
      Typical training data                            Structured / tabular
 Dominant learning paradigm                       Supervised (labeled data)
       Common architectures Linear/logistic regression, tree ensembles, SVM
               Example task               Flagging a fraudulent transaction
                                                         generative_ai
         Produce a new instance consistent with a learned distribution
                                          Text, image, audio, or video
                       Large unstructured corpora (text, image, audio)
            Self-supervised pretraining, often followed by fine-tuning
 Transformer-based architectures (decoder-only LLMs, diffusion models)
                              Drafting a paragraph explaining a result

4 Large Language Models

An LLM is trained to predict the next token in a sequence given the tokens that precede it. Applied at scale over a large text corpus, this single objective — next-token prediction — is sufficient to produce a model that captures grammar, factual associations, and long-range discourse structure, without ever being given an explicit label for any of those properties. This is what makes the training self-supervised: the “label” at each position is simply the next token in the existing text, so no separate annotation step is required.

Pretraining establishes the model’s general language competence over a broad corpus. Fine-tuning (and closely related techniques such as instruction tuning and reinforcement learning from human feedback) subsequently adapts a pretrained model toward following instructions reliably or performing well in a narrower domain — for instance, adapting a general-purpose model toward clinical or legal terminology.

Why does the distinction between pretraining and fine-tuning matter practically? A pretrained-only model tends to continue text rather than answer a question — asked “What is the capital of Finland?”, it may generate a plausible-looking follow-up question rather than a direct answer. Instruction tuning is what makes a model behave like an assistant that responds directly to a request, which is the behavior most users interact with in products such as ChatGPT or Claude.

4.1 Why LLMs matter in practice

  • Communication and translation — real-time translation and multilingual content generation, without a separately trained model per language pair.
  • Scalable content production — drafting at a volume and speed not practical for manual writing alone, subject to the fact-checking caveat discussed later.
  • Personalization — tailoring phrasing, reading level, or emphasis to a stated audience.
  • Routine-task automation — drafting emails, summarizing long documents, generating boilerplate code.
  • Accessibility — text-to-speech and speech-to-text pipelines that lower barriers for users with visual or motor impairments.

5 Prompt Engineering as a Design Problem

A prompt can be decomposed into a small number of largely independent components: a persona (the role the model should adopt), the instruction itself, contextual background, optional worked examples, and an output-format specification. Building these programmatically, rather than writing each prompt by hand, makes explicit what changes between an under-specified request and a well-constructed one — and is closer to a controlled comparison, in the experimental-design sense, than to freeform writing.

build_prompt <- function(instruction, persona = NULL, context = NULL,
                          examples = NULL, output_format = NULL) {
  parts <- character(0)
  if (!is.null(persona))       parts <- c(parts, sprintf("Act as %s.", persona))
  if (!is.null(context))       parts <- c(parts, sprintf("Context: %s", context))
  if (!is.null(examples))      parts <- c(parts, sprintf("Examples:\n%s", paste(examples, collapse = "\n")))
  parts <- c(parts, sprintf("Task: %s", instruction))
  if (!is.null(output_format)) parts <- c(parts, sprintf("Respond as: %s", output_format))
  paste(parts, collapse = "\n\n")
}

weak_prompt <- build_prompt(
  instruction = "Explain what a Manhattan plot shows."
)

engineered_prompt <- build_prompt(
  instruction = "Explain what a Manhattan plot shows.",
  persona = "a statistical genetics instructor addressing first-year PhD students",
  context = "The audience has taken introductory statistics but has not yet covered GWAS.",
  output_format = "three short paragraphs, ending with one sentence on how a significance threshold is chosen"
)

cat(weak_prompt, "\n\n---\n\n", engineered_prompt, sep = "")
Task: Explain what a Manhattan plot shows.

---

Act as a statistical genetics instructor addressing first-year PhD students.

Context: The audience has taken introductory statistics but has not yet covered GWAS.

Task: Explain what a Manhattan plot shows.

Respond as: three short paragraphs, ending with one sentence on how a significance threshold is chosen

6 From Prompt to Output: Simulating Token Sampling

Given a fixed prompt, an LLM does not return a single deterministic string. At each position it assigns a score (logit) to every candidate next token, converts these scores into a probability distribution via the softmax function, and samples from that distribution. The temperature parameter rescales the logits before this conversion: low temperature sharpens the distribution toward the highest-scoring token (output closer to deterministic), while high temperature flattens it (more variable output). This is exactly why the same prompt, sent twice, can produce two different — but each individually plausible — responses.

This mechanism can be simulated directly with a toy vocabulary, without calling any external model.

softmax <- function(logits, temperature = 1) {
  scaled <- logits / temperature
  exp_scaled <- exp(scaled - max(scaled))  # numerically stable
  exp_scaled / sum(exp_scaled)
}

vocab  <- c("significant", "suggestive", "negligible", "confounded", "spurious")
logits <- c(4.2, 3.1, 0.8, 0.5, 0.2)

temperatures <- c(0.2, 0.7, 1.0, 1.5)
prob_table <- sapply(temperatures, function(t) softmax(logits, t))
colnames(prob_table) <- paste0("T=", temperatures)
rownames(prob_table) <- vocab

round(prob_table, 3)
A matrix: 5 × 4 of type dbl
T=0.2 T=0.7 T=1 T=1.5
significant 0.996 0.817 0.710 0.575
suggestive 0.004 0.170 0.236 0.276
negligible 0.000 0.006 0.024 0.060
confounded 0.000 0.004 0.018 0.049
spurious 0.000 0.003 0.013 0.040

The entropy of each distribution quantifies this concentration effect directly: low temperature yields low entropy (the model is close to deterministic), and high temperature moves the distribution toward uniform over the vocabulary.

entropy <- function(p) -sum(p * log(p))

data.frame(
  temperature = temperatures,
  entropy     = round(apply(prob_table, 2, entropy), 3),
  top_token   = vocab[apply(prob_table, 2, which.max)]
)
A data.frame: 4 × 3
temperature entropy top_token
<dbl> <dbl> <chr>
T=0.2 0.2 0.026 significant
T=0.7 0.7 0.537 significant
T=1 1.0 0.800 significant
T=1.5 1.5 1.118 significant

7 Zero-Shot, Few-Shot, and Chain-of-Thought Prompting

The three standard prompting strategies differ in how much structure is supplied before the task itself.

Zero-shot prompting — the model performs the task with no worked examples, relying entirely on knowledge acquired during training. Well suited to translation, general Q&A, and straightforward classification.

Few-shot prompting — the prompt includes several input–output examples before the actual task, which anchors the model to a specific desired format or style. Useful when the output must follow a particular structure — consistent-style content generation, pattern-based classification, structured summarization.

Chain-of-thought (CoT) prompting — the model is guided through explicit intermediate reasoning steps before producing a final answer. This is the most reliable strategy for multi-step arithmetic, logic, and other tasks where an unstructured single-shot answer is prone to skipping a step.

These can be built as three thin wrappers around the same build_prompt() function defined above, which makes the structural difference between the strategies explicit rather than a matter of writing style.

zero_shot <- build_prompt(
  instruction = "Classify the following variant consequence as high, moderate, or low impact: stop_gained"
)

few_shot <- build_prompt(
  instruction = "Classify the following variant consequence as high, moderate, or low impact: stop_gained",
  examples = c(
    "missense_variant -> moderate impact",
    "synonymous_variant -> low impact",
    "frameshift_variant -> high impact"
  )
)

chain_of_thought <- build_prompt(
  instruction = "Classify the following variant consequence as high, moderate, or low impact: stop_gained",
  context = paste(
    "Reason step by step: (1) identify what the consequence term means at the",
    "protein level, (2) assess whether it truncates or disrupts the reading frame,",
    "(3) map that assessment to an impact category, (4) state the final classification."
  )
)

cat("ZERO-SHOT\n", zero_shot, "\n\n",
    "FEW-SHOT\n", few_shot, "\n\n",
    "CHAIN-OF-THOUGHT\n", chain_of_thought, sep = "")
ZERO-SHOT
Task: Classify the following variant consequence as high, moderate, or low impact: stop_gained

FEW-SHOT
Examples:
missense_variant -> moderate impact
synonymous_variant -> low impact
frameshift_variant -> high impact

Task: Classify the following variant consequence as high, moderate, or low impact: stop_gained

CHAIN-OF-THOUGHT
Context: Reason step by step: (1) identify what the consequence term means at the protein level, (2) assess whether it truncates or disrupts the reading frame, (3) map that assessment to an impact category, (4) state the final classification.

Task: Classify the following variant consequence as high, moderate, or low impact: stop_gained

8 A Heuristic for Prompt Specificity

The qualitative distinction between a “weak” and a “well-engineered” prompt can be given a rough quantitative proxy: count the structural elements present — an explicit role, contextual background, at least one worked example, and an explicit output format. This is not a validated metric, but it makes concrete what “well-engineered” is standing in for, and gives a way to compare prompts before sending either to a model.

specificity_score <- function(prompt) {
  has_role    <- grepl("^Act as", prompt)
  has_context <- grepl("Context:|Reason step by step", prompt)
  has_example <- grepl("Examples:|->", prompt)
  has_format  <- grepl("Respond as:", prompt)
  word_count  <- lengths(strsplit(prompt, "\\s+"))

  data.frame(
    role = has_role, context = has_context,
    example = has_example, output_format = has_format,
    word_count = word_count,
    structure_score = has_role + has_context + has_example + has_format
  )
}

prompts <- list(weak = weak_prompt, engineered = engineered_prompt,
                 zero_shot = zero_shot, few_shot = few_shot, cot = chain_of_thought)

do.call(rbind, lapply(prompts, specificity_score))
A data.frame: 5 × 6
role context example output_format word_count structure_score
<lgl> <lgl> <lgl> <lgl> <int> <int>
weak FALSE FALSE FALSE FALSE 7 0
engineered TRUE TRUE FALSE TRUE 46 3
zero_shot FALSE FALSE FALSE FALSE 13 0
few_shot FALSE FALSE TRUE FALSE 26 1
cot FALSE TRUE FALSE FALSE 52 1

The structure_score column separates the five prompts cleanly: the weak prompt scores zero, the engineered version scores three, and the three named strategies each add exactly one structural element beyond a bare instruction — context for chain-of-thought, worked examples for few-shot, nothing beyond the instruction itself for zero-shot.

9 Applying LLMs to Academic and Professional Tasks

Current general-purpose LLMs support four broad capabilities relevant to this kind of work: natural language understanding (following multi-part instructions), text generation (drafting essays, reports, and code), information retrieval across general topics (subject to the currency limitations discussed later), and step-by-step problem solving.

Applied by subject, three patterns recur:

  • Quantitative subjects (mathematics, statistics) — worked, stepwise solutions and clarification of terminology; chain-of-thought prompting is particularly effective here.
  • Conceptual subjects (natural sciences) — explanation at a specified level of background knowledge, and generation of illustrative examples or experiment ideas.
  • Interpretive subjects (literature, argumentation) — thematic analysis and drafting assistance, where the underlying claims still require the user’s own verification and judgment.

At the workflow level rather than the subject level, three uses account for most practical value: simplifying research (summarizing long material into key points), generating ideas (structured brainstorming and outlining), and producing explanations calibrated to a stated audience (via analogy or simplification).

9.1 A worked example: reusing build_prompt() for a recurring task

A common pattern in practice is to fix most of a prompt’s structure in advance and defer one piece of task-specific data to a follow-up turn. This reuses the same build_prompt() constructor already defined, applied to a resume-drafting task with an explicit “wait for further input” instruction.

resume_prompt <- build_prompt(
  instruction = paste(
    "Draft a resume for a Data Science role with 4 years of experience across",
    "two prior positions. Use standard sections: Contact Information,",
    "Professional Summary, Work Experience, Education, Skills, Certifications.",
    "Wait for a job description to be supplied before finalizing content."
  ),
  persona = "a resume writer specializing in data science roles",
  context = "The candidate has 4 years of experience across 2 companies.",
  output_format = "a standard resume layout with the sections listed above"
)

cat(resume_prompt)
Act as a resume writer specializing in data science roles.

Context: The candidate has 4 years of experience across 2 companies.

Task: Draft a resume for a Data Science role with 4 years of experience across two prior positions. Use standard sections: Contact Information, Professional Summary, Work Experience, Education, Skills, Certifications. Wait for a job description to be supplied before finalizing content.

Respond as: a standard resume layout with the sections listed above

This pattern — templating the reusable structure while leaving the variable input (here, the job description) to be supplied afterward — generalizes to any workflow where the same task recurs with different data each time, for example generating a plain-language summary of a coloc.abf result for different gene–trait pairs.

10 The Generative AI Tool Landscape

The tool landscape in this field moves quickly, so this section is organized by category, with model or product names given as illustrative examples current as of mid-2026 rather than a fixed catalog. A few notable changes relative to material from a year or two prior: Google’s Bard was renamed Gemini in February 2024; Amazon’s CodeWhisperer was rebranded as Amazon Q Developer in April 2024; OpenAI retired the DALL-E brand in 2026, consolidating image generation under the GPT Image line; and video models such as Runway have moved through several major generations (Gen-2 → Gen-4.5) since earlier overviews of this space were written.

tool_landscape <- data.frame(
  category = c(
    "Text generation", "Text generation", "Text generation", "Text generation",
    "Image generation", "Image generation", "Image generation",
    "Code generation", "Code generation", "Code generation",
    "Audio & music", "Audio & music",
    "Video generation", "Video generation",
    "Multimodal", "Multimodal",
    "Open-weight / local"
  ),
  example_tool = c(
    "ChatGPT (OpenAI)", "Claude (Anthropic)", "Gemini (Google)", "Llama (Meta, open-weight)",
    "Midjourney", "Stable Diffusion (Stability AI)", "GPT Image (OpenAI)",
    "GitHub Copilot", "Amazon Q Developer", "StarCoder (Hugging Face / BigCode)",
    "Suno (music)", "ElevenLabs (voice)",
    "Runway", "Synthesia",
    "Claude / GPT / Gemini (vision-enabled)", "Multimodal open models (e.g. IDEFICS-style)",
    "Ollama / LM Studio for local inference"
  ),
  primary_use = c(
    "General-purpose conversational assistant", "General-purpose assistant, long-document handling",
    "Conversational assistant integrated with Google services", "Open-weight models for self-hosted or fine-tuned use",
    "Stylized, artistic image generation", "Open-source, locally runnable image generation",
    "Native image generation integrated into a chat assistant",
    "In-editor code completion and generation", "AWS-integrated coding and cloud-resource assistant",
    "Open-source code-focused language model",
    "Text-to-song generation", "Realistic voice synthesis and cloning",
    "Text- and image-conditioned video generation", "Script-to-video with avatar presenters",
    "Combined text, image, and document reasoning", "Open research models combining vision and language",
    "Running open-weight LLMs on local hardware"
  ),
  stringsAsFactors = FALSE
)

print(tool_landscape, row.names = FALSE)
            category                                example_tool
     Text generation                            ChatGPT (OpenAI)
     Text generation                          Claude (Anthropic)
     Text generation                             Gemini (Google)
     Text generation                   Llama (Meta, open-weight)
    Image generation                                  Midjourney
    Image generation             Stable Diffusion (Stability AI)
    Image generation                          GPT Image (OpenAI)
     Code generation                              GitHub Copilot
     Code generation                          Amazon Q Developer
     Code generation          StarCoder (Hugging Face / BigCode)
       Audio & music                                Suno (music)
       Audio & music                          ElevenLabs (voice)
    Video generation                                      Runway
    Video generation                                   Synthesia
          Multimodal      Claude / GPT / Gemini (vision-enabled)
          Multimodal Multimodal open models (e.g. IDEFICS-style)
 Open-weight / local      Ollama / LM Studio for local inference
                                              primary_use
                 General-purpose conversational assistant
        General-purpose assistant, long-document handling
 Conversational assistant integrated with Google services
     Open-weight models for self-hosted or fine-tuned use
                      Stylized, artistic image generation
           Open-source, locally runnable image generation
 Native image generation integrated into a chat assistant
                 In-editor code completion and generation
       AWS-integrated coding and cloud-resource assistant
                  Open-source code-focused language model
                                  Text-to-song generation
                    Realistic voice synthesis and cloning
             Text- and image-conditioned video generation
                   Script-to-video with avatar presenters
             Combined text, image, and document reasoning
       Open research models combining vision and language
               Running open-weight LLMs on local hardware

A caution about tool inventories in a fast-moving field. Any fixed list like the one above is a snapshot, not a durable reference — model names, ownership, and even entire product lines (DALL-E being the clearest recent example) change on a timescale of months. Treat categories as more stable than the specific example filling each row, and verify current status before citing a specific tool in published material.

11 Best Practices

The techniques covered above condense into a short set of practical habits:

  1. State the task precisely rather than open-endedly — specificity is the single largest lever on output quality.
  2. Assign a persona when the task benefits from a particular voice or expertise framing.
  3. Supply context the model cannot otherwise infer (audience, constraints, prior decisions).
  4. Treat the first response as a draft — iterative refinement is standard practice, not a sign of a failed first attempt.
  5. Verify factual claims in the output against a primary source before relying on them.
  6. Match the tool to the modality of the task — a text model is not the right tool for an image-generation request, and vice versa.
  7. Avoid placing sensitive personal or proprietary information into a prompt sent to a third-party service.
  8. Save prompt templates that work well for recurring tasks, following the reusable-constructor pattern demonstrated above.

12 Limitations of Current Generative AI Systems

  • Fluency is not the same as correctness. A model can produce confident, well-formatted, and factually wrong output; the sampling mechanism described above optimizes for plausibility given training data, not for truth.
  • No grounded fact-checking by default. Absent a retrieval or search step, a response reflects patterns learned during training rather than a verified lookup.
  • Bias inheritance. Systematic patterns present in training data can be reproduced in output, including underrepresentation or skewed framing of certain groups or viewpoints.
  • Knowledge currency. A model’s default knowledge is bounded by its training cutoff; anything after that date requires an explicit retrieval or search capability, not the base model alone.
  • Miscalibrated confidence. Language models are not reliably self-aware of their own uncertainty; a wrong answer is often phrased with the same confidence as a correct one.
  • Data handling. Prompts submitted to a hosted service may be logged or used according to that provider’s data policy; sensitive data warrants caution.
  • Not a substitute for domain judgment. These systems are best used as a drafting and exploration aid, with a domain expert retaining responsibility for the final claim or decision.

13 Summary

Generative AI is distinguished from conventional machine learning by its objective (producing new content consistent with a learned distribution, rather than predicting a label) and by its typical training regime (self-supervised pretraining on large unstructured corpora, often followed by instruction fine-tuning). LLMs are the text-generation instance of this category, and the process by which a fixed prompt becomes a specific output is governed by token-level sampling — softmax over logits, tuned by temperature — which is directly simulable and was demonstrated above without reference to any specific vendor’s model.

Prompt engineering is best treated as a compositional design problem: persona, instruction, context, examples, and output format are largely independent factors that can be manipulated and combined programmatically, and zero-shot, few-shot, and chain-of-thought prompting are three points along a single axis of increasing structural scaffolding rather than unrelated techniques. This gives a concrete basis — the build_prompt() constructor and the specificity_score() heuristic developed in this notebook — for evaluating and improving a prompt before sending it to any model, current or future.

14 References

  • Vaswani et al., “Attention Is All You Need” (2017) — arXiv:1706.03762
  • Brown et al., “Language Models are Few-Shot Learners” (2020) — arXiv:2005.14165
  • Ouyang et al., “Training Language Models to Follow Instructions” (2022) — arXiv:2203.02155
  • “A Survey of Prompt Engineering Techniques” (2023) — arXiv:2302.11382
  • “An Overview of Large Language Models” (2023) — arXiv:2303.18223
  • Wei et al., “Chain-of-Thought Prompting Elicits Reasoning in LLMs” (2022) — arXiv:2201.11903

15 Try It Yourself

  1. Extend specificity_score() to also flag prompts that specify a maximum output length, and re-score the five example prompts from earlier in this notebook.
  2. Modify the toy vocabulary and logits in the sampling section to model a near-tied scenario between two tokens, and compare the resulting entropy curve across temperatures.
  3. Write a build_prompt() call for a task from your own tutorial pipeline — for example, a plain-language summary of a coloc.abf result for a general audience — and score it before and after adding context and an output format.
  4. Pick one row of the tool landscape table and verify its current status against the vendor’s own documentation; note anything that has changed since this notebook was written.

16 Solutions

The four exercises above are worked below, reusing the functions and objects already defined earlier in this notebook.

16.1 Solution 1: Extending specificity_score() with a length constraint

The extension follows the same pattern as the existing structural checks: search the prompt text for a marker phrase, here treating any mention of a numeric limit alongside a length-related word (word, sentence, paragraph) as evidence that an output-length constraint was specified.

specificity_score_v2 <- function(prompt) {
  has_role    <- grepl("^Act as", prompt)
  has_context <- grepl("Context:|Reason step by step", prompt)
  has_example <- grepl("Examples:|->", prompt)
  has_format  <- grepl("Respond as:", prompt)
  has_length  <- grepl("\\d+\\s*(word|sentence|paragraph)", prompt, ignore.case = TRUE)
  word_count  <- lengths(strsplit(prompt, "\\s+"))

  data.frame(
    role = has_role, context = has_context,
    example = has_example, output_format = has_format,
    length_constraint = has_length,
    word_count = word_count,
    structure_score = has_role + has_context + has_example + has_format + has_length
  )
}

# Re-score the five prompts already defined earlier in the notebook
do.call(rbind, lapply(prompts, specificity_score_v2))
A data.frame: 5 × 7
role context example output_format length_constraint word_count structure_score
<lgl> <lgl> <lgl> <lgl> <lgl> <int> <int>
weak FALSE FALSE FALSE FALSE FALSE 7 0
engineered TRUE TRUE FALSE TRUE FALSE 46 3
zero_shot FALSE FALSE FALSE FALSE FALSE 13 0
few_shot FALSE FALSE TRUE FALSE FALSE 26 1
cot FALSE TRUE FALSE FALSE FALSE 52 1

None of the five original example prompts specified a numeric output length, so length_constraint is FALSE throughout and the structure_score values are unchanged from the earlier table. Adding a length-constrained prompt confirms the new check actually fires:

length_constrained_prompt <- build_prompt(
  instruction = "Explain what a Manhattan plot shows.",
  output_format = "no more than 3 sentences"
)

specificity_score_v2(length_constrained_prompt)
A data.frame: 1 × 7
role context example output_format length_constraint word_count structure_score
<lgl> <lgl> <lgl> <lgl> <lgl> <int> <int>
FALSE FALSE FALSE TRUE TRUE 14 2

16.2 Solution 2: A near-tied vocabulary and its entropy curve

The original vocabulary had one dominant token (significant, logit 4.2) well ahead of the rest. Here two tokens are given nearly identical logits, which should push entropy higher at every temperature relative to the original, since the distribution can no longer collapse onto a single clear winner even at low temperature.

vocab_tied  <- c("significant", "suggestive", "negligible", "confounded", "spurious")
logits_tied <- c(3.0, 2.9, 0.8, 0.5, 0.2)  # top two logits nearly tied

prob_table_tied <- sapply(temperatures, function(t) softmax(logits_tied, t))
colnames(prob_table_tied) <- paste0("T=", temperatures)
rownames(prob_table_tied) <- vocab_tied

round(prob_table_tied, 3)
A matrix: 5 × 4 of type dbl
T=0.2 T=0.7 T=1 T=1.5
significant 0.622 0.511 0.463 0.398
suggestive 0.378 0.443 0.419 0.373
negligible 0.000 0.022 0.051 0.092
confounded 0.000 0.014 0.038 0.075
spurious 0.000 0.009 0.028 0.062
comparison <- data.frame(
  temperature       = temperatures,
  entropy_original  = round(apply(prob_table, 2, entropy), 3),
  entropy_near_tied = round(apply(prob_table_tied, 2, entropy), 3)
)
comparison$entropy_increase <- round(comparison$entropy_near_tied - comparison$entropy_original, 3)
comparison
A data.frame: 4 × 4
temperature entropy_original entropy_near_tied entropy_increase
<dbl> <dbl> <dbl> <dbl>
T=0.2 0.2 0.026 0.663 0.637
T=0.7 0.7 0.537 0.893 0.356
T=1 1.0 0.800 1.098 0.298
T=1.5 1.5 1.118 1.320 0.202

The near-tied vocabulary has strictly higher entropy than the original at every temperature, and the gap is largest at low temperature (T=0.2): with a single dominant token, low temperature nearly always resolves to that token, but with two tokens close in score, even a sharpening transformation cannot fully separate them. As temperature increases, both distributions approach the same uniform-entropy ceiling, so the two curves converge — the effect of a near-tie is strongest exactly where it is least intuitive, at low temperature, not high.

16.3 Solution 3: A coloc.abf summary prompt, before and after engineering

A minimal version of this task and an engineered version, scored with specificity_score() for direct comparison.

coloc_weak <- build_prompt(
  instruction = "Summarize this coloc.abf result in plain language."
)

coloc_engineered <- build_prompt(
  instruction = "Summarize this coloc.abf result in plain language: PP4 = 0.87, PP3 = 0.09, PP0-PP2 negligible.",
  persona = "a genetic epidemiologist writing for a non-specialist collaborator",
  context = paste(
    "PP4 is the posterior probability that the GWAS and eQTL signals share a",
    "single causal variant; PP3 is the probability of two distinct causal",
    "variants at the same locus."
  ),
  output_format = "two sentences, avoiding statistical jargon where possible"
)

rbind(
  specificity_score(coloc_weak),
  specificity_score(coloc_engineered)
)
A data.frame: 2 × 6
role context example output_format word_count structure_score
<lgl> <lgl> <lgl> <lgl> <int> <int>
FALSE FALSE FALSE FALSE 8 0
TRUE TRUE FALSE TRUE 65 3

As with the earlier examples, adding persona, context, and an output-format constraint raises the structure score from 0 to 3; the qualitative difference this makes to an actual model response would be that the weak version leaves both the intended audience and the meaning of PP4/PP3 unstated, while the engineered version fixes both before the request reaches the model.

16.4 Solution 4: Verifying one row of the tool landscape table

Taking the Runway row (Video generation) as the example. The table entry describes Runway generically as a “text- and image-conditioned video generation” tool, without pinning a version number — which was a deliberate choice, since version-specific claims are exactly what goes stale fastest in this space. Checking against Runway’s own release material as of mid-2026:

  • Runway’s current flagship is Gen-4.5, released December 2025, which added native text-to-video generation on top of the image-conditioned workflow introduced in Gen-4 (March 2025).
  • Earlier overviews of this space (including the source material this notebook was built from) describe Runway at the Gen-2 stage, which is now three major generations behind.
  • The general category description in the table — “text- and image-conditioned video generation” — still holds without modification; only a specific version number would need updating.

This illustrates the intended use of the caution note attached to the table: the category-level description was written to survive this kind of check, while any row that had included a specific version number would already need a correction after roughly a year.