Use Stop Sequences

Su Suriya Ravichandran Updated 10 Nov 2026
8 min read ·Lesson 48 of 200

What a Stop Sequence Is

A stop sequence is a piece of text that tells Claude to stop generating as soon as it produces that text. You pass one or more stop sequences with the stop_sequences parameter:

from anthropic import Anthropic

client = Anthropic()

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    stop_sequences=["END"],
    messages=[{"role": "user", "content": "Write one sentence about Python, then write END, then a second sentence."}],
)

print(message.stop_reason)     # stop_sequence
print(message.stop_sequence)   # END
print("".join(b.text for b in message.content if b.type == "text"))
stop_sequence
END
Python is a versatile, readable programming language.

Generation stopped exactly where END would have appeared. The second sentence was never generated.


How Stop Sequences Behave

BehaviorDetail
Exact text matchGeneration stops when the generated text contains one of the sequences exactly. Matching is case-sensitive: END does not match end.
The match is not includedThe stop sequence itself is not part of the returned text.
stop_reason is "stop_sequence"This is a normal, intentional ending (Lesson 20).
stop_sequence tells you which one matchedWhen you pass several sequences, message.stop_sequence contains the one that ended generation. Otherwise it is None.
You only pay for what was generatedStopping early reduces output tokens.

If generation ends for any other reason, for example naturally (end_turn) or at the limit (max_tokens), stop_sequence is None, and the full text is returned as usual.


Why Use Stop Sequences

Use caseHow a stop sequence helps
Get only the first part of a structured answerStop at the marker that begins the next part
Prevent the model from writing the other side of a dialogueStop at the other speaker's label, such as "Candidate:"
End at a closing delimiterStop at a closing tag, such as "</answer>"
Limit the number of itemsStop when the next item number would begin
Save output tokensNothing after the stop point is generated

Stop sequences work best when your prompt establishes a format with clear markers, so the stop point is predictable.


Example: Stop at a Closing Tag

When you ask for an answer inside tags, stopping at the closing tag removes anything Claude might add after it:

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    stop_sequences=["</answer>"],
    messages=[{
        "role": "user",
        "content": "What is the capital of Japan? Write your answer inside <answer></answer> tags.",
    }],
)

text = "".join(b.text for b in message.content if b.type == "text")
answer = text.split("<answer>", 1)[-1].strip()
print(answer)   # Tokyo

Because the closing tag is the stop sequence, the text ends with <answer>Tokyo. Splitting on the opening tag and taking the last part extracts the answer.


Example: Limit the Number of Items

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    stop_sequences=["4."],
    messages=[{"role": "user", "content": "List Python web frameworks as a numbered list, one per line."}],
)
print("".join(b.text for b in message.content if b.type == "text").strip())
1. Django
2. Flask
3. FastAPI

Generation stops when Claude starts the fourth item. However, "4." would also match text such as "Python 3.4." inside an item. Choose stop sequences that cannot appear in normal content, for example "\n4.", which only matches at the start of a line.

Tip: if you simply want three items, asking for exactly three items is often the better approach (Lesson 38). Use stop sequences when the format is fixed and you want a hard guarantee.


Example: Prevent the Model from Speaking for Others

In dialogue formats, a model can continue writing both sides of a conversation. A stop sequence ends its turn where the other speaker would begin:

system = (
    "You are an interviewer for a junior Python developer role. Ask one question per turn. "
    "Format each turn as 'Interviewer: <question>'."
)

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    system=system,
    stop_sequences=["Candidate:"],
    messages=[{"role": "user", "content": "Start the interview."}],
)

Even if the model began to write a candidate's answer, generation would stop at Candidate:, so your application controls who speaks next.


Choosing Good Stop Sequences

GuidelineWhy
Use markers that cannot appear in normal contentPrevents stopping too early inside the real answer
Establish the marker in the prompt or system promptClaude produces the marker reliably when the format is clear
Include line breaks when position matters"\n4." only matches at the start of a line
Keep the list shortEach sequence is another way generation can end unexpectedly
Test with real inputsInputs that contain your markers can trigger early stops

Stop Sequences vs. Other Tools

GoalBetter tool
Shorter answers in generalLength instructions (Lesson 38)
Guaranteed machine-readable dataStructured outputs (Lesson 36)
A hard ceiling on output sizemax_tokens (Lesson 13)
Stopping at a specific point in a known formatStop sequences

Practical Example: A Section Extractor

This example asks Claude to write a structured lesson outline, but uses stop sequences to generate only the section the user asked for. Every section after it is never generated, which saves output tokens.

"""section_extractor.py: generate only the requested section of a structured answer."""

from anthropic import Anthropic
from anthropic.types import Message

client = Anthropic()

SECTIONS = ["CONCEPT", "SYNTAX", "EXAMPLE", "MISTAKES"]

SYSTEM = """You write short programming lesson notes in exactly this format:
=== CONCEPT ===
(2-3 sentences)
=== SYNTAX ===
(a code block showing the syntax)
=== EXAMPLE ===
(a short example and its output)
=== MISTAKES ===
(2 common mistakes)
Always include all four sections in this order."""


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


def generate_until(topic: str, section: str) -> tuple[str, Message]:
    """Generate the notes up to and including `section`, and stop before the next one."""
    index = SECTIONS.index(section)
    following = SECTIONS[index + 1:]
    stops = [f"=== {name} ===" for name in following]

    request = {
        "model": "claude-opus-5-5",
        "max_tokens": 2048,
        "system": SYSTEM,
        "messages": [{"role": "user", "content": f"Topic: {topic}"}],
    }
    if stops:
        request["stop_sequences"] = stops

    message = client.messages.create(**request)
    text = get_text(message)
    part = text.split(f"=== {section} ===", 1)[-1].strip()
    return part, message


if __name__ == "__main__":
    part, message = generate_until("Python list comprehensions", "SYNTAX")
    print(part)
    print(f"\n[stop_reason={message.stop_reason}, stop_sequence={message.stop_sequence!r}, "
          f"output_tokens={message.usage.output_tokens}]")

Example output:

```python
[expression for item in iterable if condition]
```

[stop_reason=stop_sequence, stop_sequence='=== EXAMPLE ===', output_tokens=95]

How It Works

  1. The system prompt defines a strict format with unique section markers (=== NAME ===). These markers are unlikely to appear in normal content, which makes them safe stop sequences.
  2. generate_until() builds the stop sequences from the following sections. For SYNTAX, the stops are the EXAMPLE and MISTAKES markers, so generation ends as soon as the next section begins.
  3. Only add stop_sequences when there are any. For the last section, following is empty, and the parameter is left out entirely (Lesson 22).
  4. text.split(f"=== {section} ===", 1)[-1] removes everything before the requested section, including the earlier sections that had to be generated first.
  5. The usage line confirms the saving. Only the sections up to SYNTAX were generated, and stop_sequence shows exactly which marker ended the response.

Note that sections before the requested one are still generated. Stop sequences save tokens only after the stop point. To generate a later section alone, ask for it directly in the prompt.


Common Mistakes

Stop Sequences That Appear in Normal Content

What happens: generation stops too early, for example "." stops after the first sentence, and "4." stops at "version 3.4."

Fix: use distinctive markers, and include line breaks or delimiters where position matters.

Expecting the Stop Sequence in the Output

What happens: code that looks for the closing marker in the text does not find it.

Fix: remember that the matched sequence is excluded. Use message.stop_sequence to see which one matched.

Not Establishing the Marker in the Prompt

What happens: Claude never produces the marker, so the stop sequence never triggers.

Fix: define the format and markers clearly in the prompt or system prompt.

Case or Spacing Mismatches

What happens: "END" does not match "End", and "=== EXAMPLE ===" does not match "===EXAMPLE===".

Fix: use exactly the marker text you specified in the prompt.

Using Stop Sequences Instead of Structured Outputs

What happens: parsing still depends on Claude following a text format.

Fix: use structured outputs when you need guaranteed machine-readable data.


Best Practices

  • Define a clear format with unique markers, and use those markers as stop sequences.
  • Check stop_reason and stop_sequence to know why and where generation ended.
  • Remember that the match is excluded, and add it back if your format needs it.
  • Use line breaks in stop sequences when matches should only occur at the start of a line.
  • Combine stop sequences with a sensible max_tokens as a safety net.
  • Test with inputs that might contain your markers.

Exercise

  1. Use generate_until() for each of the four sections. How do output_tokens change as you request later sections?
  2. Rewrite the numbered-list example to use "\n4." as the stop sequence, and test it with a prompt that might mention "Python 3.4".
  3. Modify the interviewer example to run a 3-question interview in a loop, where your code supplies the candidate's answers as user messages.
  4. Explain why generate_until() cannot avoid generating the sections before the requested one, and how you would change the prompt to generate only the MISTAKES section.
Show answers for steps 1 and 4

Step 1: output tokens increase as later sections are requested, because every earlier section is generated first. Requesting MISTAKES produces roughly the full notes, while requesting CONCEPT stops after the first section.

Step 4: generation always proceeds from the beginning of the response, and stop sequences can only end it early. They cannot skip text that comes first. To generate only the mistakes, ask for them directly, for example: "List 2 common mistakes with Python list comprehensions, in the same style as the MISTAKES section." Use stop sequences to cut off what comes after the part you need.

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 Use Stop Sequences and get answers drawn from it.

Signed-in readers only.