Repetition Penalties

Intermediate4 min

`frequency_penalty` scales with how often a token has appeared and `presence_penalty` does not, so they answer different complaints. Both usually treat a symptom whose cause is an ambiguous prompt, a degrading context, or an agent with no stopping condition.

#sampling

Two parameters, and they are not the same one

Sampling parameters covers temperature and the truncation family. Penalties are the other group, and OpenAI exposes two that get used interchangeably and do different things.

frequency_penalty, from -2.0 to 2.0: "Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim."

presence_penalty, same range: "Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics."

Read the two definitions against each other. Frequency scales with how often a token has appeared, so it pushes back harder on the word you have used ten times than on the one you used once. Presence does not care about the count: a token that appeared at all takes the full penalty.

So they answer different complaints. "It keeps repeating the same phrase" is frequency. "It will not move on to a new subject" is presence.

Local runtimes often expose a single repetition_penalty instead, which is a multiplicative version of the same idea. It is not interchangeable with either OpenAI parameter, so a value copied across will not behave the same way.

Negative values exist, and they are the interesting half

The range runs below zero, which is easy to miss. A negative penalty makes repetition more likely.

That has real uses. Generating structured output where the same field names must recur, extracting terms that legitimately repeat, or producing text that should stay on one narrow subject are all cases where the default pull toward novelty works against you.

If you have ever seen a model start substituting synonyms for a term you needed verbatim, this is the dial that caused it.

Why they are usually the wrong fix

The loop you are trying to stop is rarely a sampling problem.

A model repeating itself is most often a symptom of something upstream:

The prompt is ambiguous, so the model restates rather than progresses. A clearer instruction fixes it and a penalty papers over it.

The context is degrading. Context failure modes names this one directly: distraction, where a long history leads a model to repeat earlier actions rather than synthesise new ones. Gemini 2.5 Pro shows it beyond 100k tokens, and one study found Llama 3.1 405b's correctness falling from around 32k. No penalty setting addresses a context that is too long.

An agent is looping because it has no stopping condition or no way to tell progress from motion, which agent use cases covers.

Temperature is too low, collapsing the distribution onto the same continuation. That is a sampling parameters problem and a different one.

Reaching for a penalty first treats the output rather than the cause, and a penalty strong enough to suppress a real loop is usually strong enough to damage the text.

When to use one anyway

Two cases where a penalty is the right instrument.

Long-form generation that drifts into repetition toward the end, where the prompt is fine and the content is fine and the last paragraph circles. A small positive frequency_penalty is a reasonable fix.

Encouraging coverage in something like brainstorming, where you want the output to keep reaching for new ground. That is presence_penalty doing what it was described for.

Move in small steps and read the output. These parameters interact with temperature, so changing both at once tells you nothing about either, and a value that worked on one model is not evidence about the next.

Checking whether they are even available

Not every provider exposes them, and reasoning models in particular restrict the sampling surface. Anthropic's API does not offer these two, so a settings object carried across providers will have fields that are silently ignored, which OpenAI-compatible APIs warns is the normal failure rather than an error.

Check what the model you are calling accepts before tuning something that is not being read.

Further reading

Knowledge check

Question 1 of 3

The model keeps reusing the same phrase. Which parameter addresses that?

Sign in to save your progress and pick up where you left off.