Control Response Length

Su Suriya Ravichandran Updated 10 Nov 2026
9 min read ·Lesson 38 of 200

What Controlling Length Means

Response length is how much Claude writes: a one-word label, a two-sentence answer, a 300-word explanation, or a 3,000-word guide. The right length depends on where the text is going: a phone notification, a chat window, a report, or documentation.

There are two very different tools for length, and confusing them is one of the most common mistakes:

ToolWhat it doesEffect on the answer
Instructions in the promptTell Claude how long the answer should beClaude plans an answer of that length, so it is complete and well-formed
max_tokensA hard ceiling on generated tokens, including thinkingGeneration simply stops at the limit, often mid-sentence (Lesson 13)

Rule: use instructions to control length, and max_tokens as a safety ceiling with enough room for the answer you asked for, plus any thinking.


Current Models Are Concise by Default

Anthropic's prompting guidance notes that current Claude models have a more concise, direct, and natural communication style than earlier models. In practice:

  • if you want short answers, Claude often already writes compactly, but an explicit limit makes it predictable;
  • if you want long, detailed answers, ask for them explicitly. Do not assume Claude will expand on its own.

The same guidance notes that changing the effort setting does not reliably change the visible length of the response. Effort mainly controls how much Claude thinks. To change how much it writes, prompt for it.


Be Specific About Length

Vague length words are interpreted differently in different contexts. Concrete units are reliable:

VagueSpecific
"Keep it short.""Answer in at most 2 sentences."
"A brief summary.""Summarize in 50 words or fewer."
"Give some examples.""Give exactly 3 examples."
"Explain in detail.""Explain in about 600 words, with a code example for each concept."
"A few bullet points.""Use 4 bullet points, each under 15 words."

Choosing a Unit

UnitPrecisionBest for
Number of items ("3 bullet points", "5 ideas")Very highLists, options, examples
SentencesHighShort answers, summaries
ParagraphsMediumExplanations, articles
WordsApproximateSummaries and articles with a target size
CharactersApproximateStrict UI or platform limits, such as tweets or SMS

Models do not count words or characters exactly while writing, so word and character targets are approximate. When a limit is strict, for example a database column or a platform's character limit, verify it in code (see the practical example).


Explain Why the Length Matters

As with other instructions (Lesson 31), giving the reason helps Claude make good trade-offs:

Answer in at most 2 sentences. The answer is shown in a small notification on a phone,
so put the most important information first.

The reason ("small notification") tells Claude not only to be short, but also how to be short: lead with the key point.


Describe the Desired Shape, Not Just the Size

Length is closely tied to structure. Describe both:

Write a quick-start guide:
- a one-sentence description of the tool,
- installation in one command,
- three numbered steps to create the first project,
- no introduction or conclusion.

This produces a predictable, compact answer, because every part has a defined size and nothing else is requested.

To make answers longer and richer, describe what the extra length should contain:

Explain Python decorators in depth for intermediate developers. Cover: what they are,
how they work internally, decorators with arguments, functools.wraps, and two real-world
use cases. Include a code example and its output for each topic.

"In depth" alone is vague. The list of topics defines what the extra length should be spent on.


Setting Length for a Whole Application

Put the default length rule in the system prompt, so it applies to every answer:

SYSTEM = (
    "You are a support assistant inside a mobile app. Keep answers under 80 words, "
    "because they are displayed on small screens. If the user asks for more detail, "
    "you may write up to 250 words."
)

This defines a default and a rule for exceptions, so users who explicitly ask for detail still get it.

Per-Request Overrides

A specific request can override the default:

messages = [{"role": "user", "content": "Explain how HTTPS works. Detailed answer, please."}]

Or your application can add a length instruction based on context, for example a "brief" or "detailed" toggle in the interface:

LENGTH_RULES = {
    "brief": "Answer in at most 3 sentences.",
    "standard": "Answer in about 150 words.",
    "detailed": "Answer in about 500 words, with examples.",
}

content = f"{question}\n\n{LENGTH_RULES[user_choice]}"

Examples Set Length Too

Examples (Lesson 35) demonstrate length implicitly. If every example answer is one short sentence, Claude tends to answer in one short sentence. If your examples are longer than the length you ask for, the examples and the instruction conflict. Keep them consistent.


max_tokens: Leave Room

After you have asked for a length, set max_tokens high enough for that length plus thinking:

Requested lengthApproximate tokens for the textReasonable max_tokens
1–3 sentencesUnder 1001,024
~150 words~200–3002,048
~500 words~700–1,0004,096
~2,000 words~3,000–4,0008,192+, with streaming

The extra headroom is for thinking, which counts toward max_tokens (Lesson 13). You pay only for tokens actually generated, so a generous ceiling costs nothing extra.


Practical Example: A Length-Controlled Summarizer

This summarizer requests a word limit, measures the result in code, and makes one targeted correction if the summary is too long. It shows the pattern for strict limits: instruct, verify, correct.

"""length_summarizer.py: summarize text within a word limit, verified in code."""

from anthropic import Anthropic
from anthropic.types import Message

MODEL = "claude-opus-5-5"
client = Anthropic()

ARTICLE = """Django 5.2 introduces composite primary keys, letting models use more than one
field as a primary key. It also adds automatic model imports in the shell, simplifies
customizing BoundField rendering, and improves async support in several areas. Several
deprecated features from earlier releases have been removed, so projects should review
the release notes before upgrading. The release is a long-term support version,
which means it will receive security updates for an extended period."""


def get_text(message: Message) -> str:
    return "".join(block.text for block in message.content if block.type == "text").strip()


def word_count(text: str) -> int:
    return len(text.split())


def summarize(text: str, max_words: int) -> str:
    messages = [{
        "role": "user",
        "content": f"<article>\n{text}\n</article>\n\n"
                   f"Summarize the article above in at most {max_words} words. "
                   f"It will be shown in a news feed card, so lead with the most important point. "
                   f"Reply with only the summary.",
    }]
    reply = client.messages.create(model=MODEL, max_tokens=2048, messages=messages)
    summary = get_text(reply)

    if word_count(summary) > max_words:
        messages += [
            {"role": "assistant", "content": reply.content},
            {"role": "user", "content": f"That summary has {word_count(summary)} words. "
                                        f"Shorten it to at most {max_words} words. Reply with only the summary."},
        ]
        reply = client.messages.create(model=MODEL, max_tokens=2048, messages=messages)
        summary = get_text(reply)

    return summary


if __name__ == "__main__":
    for limit in (15, 40):
        result = summarize(ARTICLE, limit)
        print(f"[limit {limit}, got {word_count(result)} words]\n{result}\n")

Example output (wording varies):

[limit 15, got 14 words]
Django 5.2, a long-term support release, adds composite primary keys and removes deprecated features.

[limit 40, got 36 words]
Django 5.2 is a long-term support release that adds composite primary keys, automatic shell imports, and better async support. It also removes deprecated features, so review the release notes before upgrading.

How It Works

  1. The instruction states the limit in words, explains the destination ("news feed card"), and says how to prioritize ("lead with the most important point").
  2. "Reply with only the summary" prevents a preface such as "Here is a summary:", which would add words and break the display.
  3. word_count() measures the result with len(text.split()). That is a simple, consistent definition of a word for checking limits.
  4. The correction turn runs only when the limit is exceeded. It tells Claude the exact count and the target, a targeted, multi-turn correction (Lesson 28). The original reply is appended unchanged as the assistant turn.
  5. max_tokens=2048 leaves ample room for thinking plus a short summary, so the summary is never cut off by the ceiling.

Note: For limits that must never be exceeded, such as a fixed-width database column or an SMS segment, keep a final code-level safeguard as well, for example by cutting at the last complete sentence that fits. Prompting gets you close; code guarantees the hard limit.


Common Mistakes

Using max_tokens to Shorten Answers

What happens: answers end mid-sentence instead of being concise.

Fix: state the length in the prompt, and keep max_tokens generous.

Vague Length Words

What happens: "short" produces one sentence in one case and two paragraphs in another.

Fix: use concrete units: items, sentences, or approximate words.

Expecting Long Answers Without Asking

What happens: current models answer concisely, and detailed explanations are shorter than intended.

Fix: request depth explicitly and list what the answer should cover.

Expecting Effort to Change Visible Length

What happens: lowering or raising effort does not reliably produce shorter or longer text.

Fix: use prompt instructions for length. Use effort for thinking depth, latency, and cost.

Conflicting Length Signals

What happens: the system prompt says "under 80 words", the examples are 200 words long, and the user asks for detail, so the results are inconsistent.

Fix: define a default, a clear rule for exceptions, and examples that match.

Trusting Approximate Limits for Hard Constraints

What happens: a 160-character SMS limit is occasionally exceeded.

Fix: verify length in code, and correct or truncate safely.


Best Practices

  • Control length with instructions, and treat max_tokens as a safety ceiling.
  • Use concrete units, preferring item counts and sentences for precision.
  • Explain where the text will appear, and what to prioritize.
  • Ask explicitly for depth when you need long answers, and list what to cover.
  • Set a default in the system prompt, with rules for exceptions.
  • Keep examples consistent with the requested length.
  • Verify strict limits in code, and correct with a targeted follow-up.

Exercise

  1. Ask Claude to "explain Python virtual environments" three times: with no length instruction, with "in at most 2 sentences", and with "in about 400 words, covering creation, activation, and dependency files". Compare the word counts.
  2. Add a max_chars parameter to the summarizer that checks character length instead of words, for a 160-character SMS.
  3. Write a system prompt for a chat assistant with a default of 100 words and a rule that allows up to 400 words when the user asks for detail. Test both cases.
  4. Add a final safeguard to summarize() that, if the summary is still too long after the correction, cuts it at the last complete sentence within the limit.
Show a possible solution for step 4
import re


def cut_to_word_limit(text: str, max_words: int) -> str:
    sentences = re.split(r"(?<=[.!?])\s+", text)
    result = []
    for sentence in sentences:
        if word_count(" ".join(result + [sentence])) > max_words:
            break
        result.append(sentence)
    if result:
        return " ".join(result)
    return " ".join(text.split()[:max_words])

At the end of summarize(), before return summary:

if word_count(summary) > max_words:
    summary = cut_to_word_limit(summary, max_words)

How it works: re.split(r"(?<=[.!?])\s+", text) splits after sentence-ending punctuation while keeping the punctuation (the (?<=...) lookbehind does not consume it). Sentences are added while the total stays within the limit. If even the first sentence is too long, the function falls back to cutting at the word limit. A complete sentence is preferred, but the hard limit always holds.

0 Comments

Reviewed before they appear

No comments yet.

Anthropic SDK Using Python
Anthropic SDK Intro Claude API Intro SDK Requirements Install Anthropic SDK Upgrade the SDK Create an API Key Set API Keys Use Environment Variables Import Anthropic Create a Client Send Your First Message Choose a Claude Model Set Max Tokens Read a Response Print Response Text Understand Message Blocks Use System Prompts Send User Messages Set Temperature Handle Stop Reasons Messages API Intro Create Messages Use Message Roles Send Conversation History Continue a Conversation Build a Chat Loop Reset Chat History Use Multiple Turns Inspect Message IDs Read Usage Data Write Clear Prompts Set a System Prompt Add Context to Prompts Use Prompt Templates Add Examples to Prompts Request JSON Output Use XML Tags Control Response Length Improve Prompt Quality Avoid Prompt Injection Read Text Blocks Read Content Blocks Check Stop Reasons Count Input Tokens Count Output Tokens Count Tokens Before Sending Limit Output Tokens Use Stop Sequences Read Request IDs Parse API Responses Streaming Intro Stream Text Output Use Stream Events Use Stream Helpers Get Final Messages Stream Async Responses Handle Stream Errors Build a Live Chat Stream Long Responses Close Streams Safely Build a Chatbot Keep Chat History Manage Chat Sessions Add Chat Memory Build a CLI Chatbot Build a Web Chatbot Use Flask with Claude Use FastAPI with Claude Return JSON from an API Add Chat Error Messages Async SDK Intro Create an Async Client Send Async Messages Use asyncio Run Parallel Requests Stream Async Text Handle Async Errors Set Async Timeouts Close Async Clients Choose Sync or Async Tool Use Intro Define a Tool Create Tool Schemas Send Tools to Claude Read Tool Calls Run Python Tools Return Tool Results Continue After Tool Use Control Tool Choice Handle Tool Errors Use the beta_tool Decorator Create a Tool Runner Add Tool Docstrings Validate Tool Inputs Use Multiple Tools Limit Tool Calls Log Tool Activity Build a Weather Tool Build a Search Tool Build a Calculator Tool Structured Output Intro Request JSON Data Validate JSON Output Use Pydantic Models Handle Invalid JSON Extract Fields from Text Generate Typed Data Use Image URLs Send Base64 Images Read PDFs with Claude Use Output Schemas Build Data Extraction Test Structured Responses Send Image Inputs Upload Files Use File IDs Process Text Files Summarize Documents Extract Table Data Handle File Errors Read Cache Usage Reduce Repeated Input Costs Debug Cache Misses Prompt Caching Intro Enable Prompt Caching Cache System Prompts Cache Long Context Test Cache Performance Use Cache Breakpoints Cache Best Practices Message Batches Intro Create a Message Batch Set Batch IDs Check Batch Status List Message Batches Get Batch Results Process Batch Outputs Handle Failed Batch Items Use Batches for Bulk Tasks Compare Batches and Requests Handle API Errors Handle Rate Limits Retry Failed Requests Set Request Timeouts Handle Network Errors Use Exponential Backoff Build Reliable API Calls Use Extended Thinking Log API Errors Track Request IDs Paginate API Results Set Thinking Budgets Read Thinking Blocks Use Tool Search Use Web Search Tools Use Computer Tools Use Citations Use Token Counting Read Raw Responses Set Custom Headers Use Claude on AWS Bedrock Use Claude on Vertex AI Use Claude on Microsoft Foundry Configure Cloud Credentials Choose a Cloud Provider Compare API Integrations Configure Provider Clients Handle Cloud Errors Use Cloud SDK Extras Deploy Cloud Apps Protect API Keys Use a .env File Ignore Secrets in Git Validate User Input Reduce Prompt Injection Limit Tool Permissions Avoid Unsafe Tool Calls Sanitize Tool Results Set Usage Limits Review Security Logs Test SDK Functions Mock API Responses Test Error Handling Test Streaming Code Measure Token Usage Track API Costs Configure Logging Deploy with Docker Deploy a FastAPI App Monitor Production Apps Build a Claude Chatbot Build a Text Summarizer Build a Code Explainer Build a JSON Extractor Build a PDF Assistant Build a Streaming Chat App Build a Tool-Calling Agent Build a Batch Processor Build a Research Assistant Build a Claude API Dashboard
Ask about this post
AI Ask about this post

Ask questions about Control Response Length and get answers drawn from it.

Signed-in readers only.