Skip to content

Brand-Voice Prompts That Survive Forty Turns

12 min read · updated August 4, 2026

“Friendly but professional, approachable yet authoritative” instructs nothing, because no output can be checked against it. Voice that survives a long conversation is written as constraints a script can verify, and it is maintained by keeping drifted turns out of the history rather than by asking harder.

Voice as constraints

The test for a voice instruction: could two people, given an output, disagree about whether it complies? If yes, the model can also disagree, and it will — differently on different turns.

AdjectiveDescription
friendlyReplace with: contractions allowed; second person; no exclamation marks; no more than one apology per conversation.
professionalReplace with: no slang list; no emoji; hedging capped at one per paragraph; every number carries its unit and period.
conciseReplace with: median sentence under 18 words; never two consecutive sentences over 25 words; no sentence that only restates the previous one.
confidentReplace with: no opening with a question; no sentence beginning with a hedge; say the answer before the caveat; a banned-hedge word list.
approachableReplace with: no unexplained jargon on first use; address the reader directly; never write ‘the user’.

Two things happen once voice is written this way. The model complies more reliably, because each item is a check it can perform rather than a feeling it must approximate. And you can measure compliance with a script, which is the whole basis of the monitoring below.

The voice block

<voice>
Sentence length: median under 18 words. Never two consecutive sentences over
  25 words.
Person: second person for the reader ("you"), first person plural for us
  ("we"). Never "the user", never "one".
Contractions: use them. "don't", "we'll", "you're", "it's".
Numbers: always with the unit and the period. "12 EUR a month", never
  "affordable"; "under 200 ms", never "fast".
Hedging: at most one hedge per paragraph. Hedges are: often, usually, may,
  might, can, generally, typically, tends to.
Banned words: seamless, effortless, leverage, utilise, empower, robust,
  revolutionary, cutting-edge, delve, unlock, elevate, in today's.
Banned openings: any question; "Great question"; "Absolutely"; "I'd be happy
  to"; "Sure thing"; restating what the reader just asked.
Exclamation marks: none.
Apologies: at most one per conversation, and none at all when the answer is
  useful.
Uncertainty: say "I don't know" plainly. Do not soften it, do not pad it with
  an explanation of why you do not know.
Structure: answer first, then the reason, then the caveat. Never the reverse.
</voice>

The banned-word list is the highest-yield part and the part that needs maintaining. Add whatever your model keeps producing that your editors keep removing. Naming the words works considerably better than an abstract instruction to avoid marketing language, for the same reason set out in why a negative instruction works better when it names the thing.

Keep the block under about 200 words. It sits in every request, it competes with your task instructions, and past that length the items at its centre are the ones that stop being applied.

Why it decays over a long conversation

At turn 3 the voice block is a substantial fraction of the context and the only style evidence in it. At turn 40 the context also contains twenty of the assistant’s own previous replies, and those are far more specific style evidence than any description: they are the actual register, in the actual format, on the actual subject.

A model continuing a conversation is continuing a document, and the strongest signal about how the next assistant turn should read is how the previous ones read. That is not a defect; it is what makes a conversation coherent. It has one consequence that matters here:

One drifted turn becomes the model for every turn after it. If turn 12 opens with “Great question!”, then at turn 13 the context contains an instruction not to and an example of doing it — and the example is nearer, more concrete and in the target format. Drift is therefore not gradual erosion; it is a step change at whichever turn first slipped, which is why it appears suddenly and persists.

This is a mechanical account of why the failure has the shape it has, derived from what is in the context and how a continuation is produced. Nobody here has run a forty-turn study, and the size of the effect will depend on your model, your turn lengths and how much of the history you keep. What follows from the account regardless is the fix in the next section: prevent the first bad turn from being recorded.

Two fixes, and what each costs

Fix one: re-assert the voice after the history

Put a short version of the voice block after the conversation history and immediately before the current user turn, so it occupies the end-of-context position alongside the drifted examples rather than being buried at the start.

The cost is a cache boundary. A repeated block placed after the variable history cannot be part of a stable prefix, so those tokens are uncached on every turn. For a 60-token reminder that is small; for the full 200-word block it is not, and it is the reason the reminder should be a shortened version — the three or four rules that actually drift, not all twelve.

Fix two: keep the drifted turn out of the history

This is the stronger fix and it follows directly from the mechanism. Run the drift report on each assistant turn before appending it to the conversation. On failure, regenerate once with the failing items named. If the second attempt also fails, append it anyway and log — but the first attempt catches most of them, and a transcript that contains no example of the wrong voice cannot teach the wrong voice.

def next_turn(history, user_message):
    reply = model(history + [user_message])
    report = voice_report(reply)
    if report["violations"]:
        reply = model(
            history + [user_message],
            correction=("Your draft broke these voice rules: "
                        + ", ".join(report["violations"])
                        + ". Rewrite it. Change nothing about the content."),
        )
    history.append(user_message)
    history.append(reply)          # only ever a turn that passed, or one retry
    return reply

The correction instruction says to change nothing about the content on purpose. A regeneration that is allowed to rethink the answer will rethink the answer, and you will have traded a style problem for a correctness one.

The drift report

Deterministic, no model call, fast enough to run on every turn.

import re, statistics

BANNED = {"seamless", "effortless", "leverage", "utilise", "utilize", "empower",
          "robust", "revolutionary", "delve", "unlock", "elevate"}
HEDGES = {"often", "usually", "may", "might", "can", "generally", "typically"}
BANNED_OPENINGS = ("great question", "absolutely", "sure thing",
                   "i'd be happy to", "certainly")

def sentences(text):
    return [s.strip() for s in re.split(r"(?<=[.!?])\s+", text.strip()) if s.strip()]

def voice_report(text: str) -> dict:
    sents = sentences(text)
    lens = [len(s.split()) for s in sents] or [0]
    words = set(re.findall(r"[a-z']+", text.lower()))
    lower = text.lower().lstrip()

    long_pairs = sum(1 for a, b in zip(lens, lens[1:]) if a > 25 and b > 25)
    paragraphs = [p for p in text.split("\n\n") if p.strip()]
    worst_hedges = max(
        (len([w for w in re.findall(r"[a-z']+", p.lower()) if w in HEDGES])
         for p in paragraphs), default=0)

    v = []
    if statistics.median(lens) >= 18:            v.append("median sentence length")
    if long_pairs:                               v.append("consecutive long sentences")
    if BANNED & words:                           v.append("banned words: " + ", ".join(sorted(BANNED & words)))
    if "!" in text:                              v.append("exclamation mark")
    if sents and sents[0].endswith("?"):         v.append("opens with a question")
    if lower.startswith(BANNED_OPENINGS):        v.append("banned opening")
    if "the user" in text.lower():               v.append("says 'the user'")
    if worst_hedges > 1:                         v.append("hedges in one paragraph")

    return {"violations": v,
            "median_sentence_words": statistics.median(lens),
            "sentences": len(sents),
            "hedges_worst_paragraph": worst_hedges}

What it cannot check is the interesting limit and it is worth stating. Whether the tone is right, whether the answer sounds like your company, whether a metaphor is off — none of that is in here, and a script will never get it. The report catches the mechanical half, which is the half that drifts first and the half that a reader notices as “this doesn’t sound like us” before they can say why.

Log the numeric fields, not only the violations. Median sentence length creeping from 14 to 17 over a conversation is drift that has not yet crossed a threshold, and it is the earliest warning available.

When it stops working

  • Violations cluster after a particular turn index. Plot violations against turn number across many conversations. A step rather than a slope tells you the history is teaching the drift, and that the retry gate is not running or not passing its result back.
  • The retry rate rises. Usually the voice block and the task have come into conflict — a task that requires long qualified sentences will fight a median-length rule. Fix by relaxing the rule for that task, not by removing the gate.
  • Median sentence length creeps up with no violations. The threshold is doing nothing. Either it is set above your normal output, in which case tighten it, or the conversation type has changed.
  • Editors keep removing a word the list does not contain. Add it. The list is the artefact this whole recipe accumulates, and it is the part worth carrying between projects.