Add Context to Prompts

Su Suriya Ravichandran Updated 10 Nov 2026
11 min read ·Lesson 33 of 200

What Context Is

Context is the background information Claude needs to produce the answer you want, rather than a generic one. It answers questions such as:

  • Who is this for?
  • Why is it needed, and what will it be used for?
  • What facts, documents, or data should the answer be based on?
  • What constraints or conventions apply?

Claude knows a great deal in general, but nothing about your specific situation: your users, your product, your codebase, your policies, or today's events. Anthropic's guidance compares Claude to a brilliant but new team member who lacks context on your norms and workflows. Context closes that gap.

Without context:  Write a welcome message.

With context:     Write a welcome message for students who just enrolled in our free
                  8-week Python internship program. Most are final-year college students
                  in India. The message will be sent by email, so it must work as plain text.
                  Mention that the first live session is on Monday at 7 PM IST.

The second prompt produces a message that fits the actual audience, channel, and facts. The first can only produce a guess.


Why Context Improves Answers

Without context, Claude must…With context, Claude can…
Guess the audience's levelPitch explanations at the right level
Use general conventionsFollow your conventions
Invent plausible detailsUse your actual facts
Choose an arbitrary formatMatch the destination (email, chat, documentation)
Interpret instructions literallyUnderstand the goal and adapt sensibly

The last row is important. When you explain why, Claude can generalize. For example, telling Claude that output will be read aloud by a text-to-speech system lets it avoid many things that do not work in speech, not just the one thing you thought to mention.


Types of Context

TypeExamplesWhere to put it
Purpose"This summary will be used by managers to decide whether to read the full report."System prompt or user message
Audience"Readers are beginner programmers."System prompt
Domain knowledgeProduct details, policies, course structureSystem prompt, or retrieved per request
Reference materialDocuments, articles, code, transcriptsUser message, in tags, before the question
SituationToday's date, the user's plan, recent activityEnd of the system prompt, or the user message
Constraints"Must work in Python 3.10", "Under 280 characters for social media"With the task

Adding Purpose and Audience

These are the cheapest and most effective additions, often one sentence each:

system = (
    "You explain programming concepts to final-year college students preparing for "
    "technical interviews. They know basic Python but have not studied algorithms formally. "
    "Your explanations will be used as revision notes, so favor clear structure and short examples."
)

Why it works: "preparing for technical interviews" tells Claude what matters (common questions, complexity, trade-offs). "Know basic Python" sets the level. "Revision notes" defines the format: structured, concise, and example-based.


Adding Documents and Data

When Claude should base its answer on specific material, include the material in the prompt. Three guidelines matter.

1. Wrap Each Document in Tags with Metadata

For multiple documents, a consistent structure helps Claude keep them apart and cite them:

documents_xml = """<documents>
  <document index="1">
    <source>refund_policy.md</source>
    <document_content>
Refunds are available within 14 days of purchase if less than 30% of the course is completed.
    </document_content>
  </document>
  <document index="2">
    <source>certificates.md</source>
    <document_content>
Certificates are issued within 24 hours after the final quiz is passed.
    </document_content>
  </document>
</documents>"""

The <source> tag tells Claude where each piece came from, which is useful when you ask it to cite sources. The index attribute gives each document a short reference.

2. Put Long Material First, the Question Last

Anthropic's guidance for long inputs is to place long documents and data near the top of the prompt, above the instructions and the question. Queries at the end tend to produce better answers, especially with large inputs.

user_content = f"""{documents_xml}

Using only the documents above, answer the student's question.
<question>Can I get a refund? I bought the course 10 days ago and finished 40% of it.</question>"""

3. Ask Claude to Ground Its Answer

For document-based tasks, especially long ones, ask Claude to identify the relevant passages before answering. Quoting first focuses attention on the material that matters:

First, quote the sentences from the documents that are relevant to the question inside
<quotes> tags. Then answer the question inside <answer> tags, based only on those quotes.
If the documents do not contain the answer, say so.

Why grounding helps: the answer is tied to specific evidence, which reduces answers based on assumptions. The quotes also let you, or your code, verify where the answer came from. Lesson 157 covers the API's built-in citations feature.


Adding Situational Context

Claude does not know the current date, the user's account status, or what happened recently unless you provide it:

from datetime import date

situation = f"""<situation>
Today's date: {date.today().isoformat()}
Student plan: Free
Courses completed: Python Basics
</situation>"""

Place changing details like these at the end of the system prompt or in the user message. That keeps the stable part of the prompt identical across requests, which suits prompt caching (Lesson 32).


How Much Context Is Enough?

More context is not always better:

Too littleRight amountToo much
Generic or wrong answersAnswers fit the situationHigher cost and latency
Invented detailsAnswers based on your factsRelevant facts buried among irrelevant ones
Wrong format or levelCorrect format and levelConflicting information confuses the answer

Guideline: include what a knowledgeable new colleague would need for this particular task. For large knowledge bases, do not send everything. Select the relevant parts for each request, as shown in the practical example.


Practical Example: Selecting Context from a Knowledge Base

Real applications often have more reference material than should be sent with every request. This example keeps a small knowledge base, selects the most relevant entries for each question using simple keyword matching, and sends only those as context. This is the basic idea behind retrieval-augmented generation (RAG).

"""context_answers.py: answer questions using selected knowledge-base context."""

import re

from anthropic import Anthropic
from anthropic.types import Message

KNOWLEDGE_BASE = [
    ("refund_policy.md", "Refunds are available within 14 days of purchase if less than 30% of the course is completed."),
    ("certificates.md", "Certificates are issued within 24 hours after the final quiz is passed. They can be downloaded from the Profile page."),
    ("live_sessions.md", "Live sessions run every Monday and Thursday at 7 PM IST. Recordings are available within 2 hours."),
    ("password_reset.md", "To reset a password, use 'Forgot password' on the login page. The reset link expires after 30 minutes."),
    ("internship.md", "The free internship program lasts 8 weeks. Interns must submit a project every 2 weeks."),
]

SYSTEM = (
    "You are the support assistant for an online Python course platform. "
    "Answer only from the provided documents. If they do not contain the answer, say you do not know "
    "and suggest contacting support@example.com. Keep answers under 80 words."
)

STOPWORDS = {"the", "a", "an", "is", "are", "i", "my", "to", "of", "and", "can", "how", "do", "what", "when", "for", "in", "it"}
MIN_SCORE = 2   # A document must share at least this many meaningful words with the question


def words(text: str) -> set[str]:
    return {w for w in re.findall(r"[a-z0-9]+", text.lower()) if w not in STOPWORDS}


def select_context(question: str, limit: int = 2) -> list[tuple[str, str]]:
    question_words = words(question)
    scored = [(len(question_words & words(f"{source} {content}")), source, content)
              for source, content in KNOWLEDGE_BASE]
    scored.sort(reverse=True)
    return [(source, content) for score, source, content in scored[:limit] if score >= MIN_SCORE]


def build_prompt(question: str) -> str:
    docs = select_context(question)
    rendered = "\n".join(
        f'  <document index="{i}">\n    <source>{source}</source>\n'
        f"    <document_content>{content}</document_content>\n  </document>"
        for i, (source, content) in enumerate(docs, start=1)
    )
    return f"<documents>\n{rendered}\n</documents>\n\nAnswer the question using the documents above.\n<question>{question}</question>"


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


if __name__ == "__main__":
    client = Anthropic()
    for question in [
        "When are the live sessions, and can I watch recordings?",
        "Can I get a refund after 10 days if I finished 40% of the course?",
        "Do you offer a Java course?",
    ]:
        prompt = build_prompt(question)
        reply = client.messages.create(
            model="claude-opus-5-5", max_tokens=1024, system=SYSTEM,
            messages=[{"role": "user", "content": prompt}],
        )
        sources = [source for source, _ in select_context(question)]
        print(f"Q: {question}\n   context: {sources or 'none'}\nA: {get_text(reply)}\n")

Example output (wording varies):

Q: When are the live sessions, and can I watch recordings?
   context: ['live_sessions.md']
A: Live sessions run every Monday and Thursday at 7 PM IST, and recordings are available within 2 hours.

Q: Can I get a refund after 10 days if I finished 40% of the course?
   context: ['refund_policy.md']
A: Unfortunately not. Refunds require purchase within 14 days and less than 30% completion; you've completed 40%. For other options, contact support@example.com.

Q: Do you offer a Java course?
   context: none
A: I don't know. The information I have doesn't mention a Java course. Please contact support@example.com.

How It Works

  1. words() lowercases the text, extracts words with a regular expression, and removes common stopwords that carry little meaning, such as "the" or "how".
  2. select_context() scores each document by how many meaningful words it shares with the question, using set intersection (&). It sorts the documents from highest to lowest score and keeps up to limit of them.
  3. MIN_SCORE filters out weak matches. Without it, a single shared common word, such as "after" or "course", would be enough to include an unrelated document. For example, the refund question shares only the word "after" with password_reset.md, and the Java question shares only "course" with refund_policy.md. Requiring at least two shared words keeps only genuinely relevant documents.
  4. build_prompt() renders the selected documents in the recommended <documents> structure, with the documents first and the question last.
  5. The system prompt requires answers from the documents only, and defines what to do when the answer is missing. The Java question shows this working: with no relevant context, Claude says it does not know instead of inventing a course.
  6. Only relevant context is sent, which keeps requests small and focused even if the knowledge base grows to hundreds of entries.

Note: Keyword matching is simple and works for small knowledge bases, but a fixed threshold like MIN_SCORE needs tuning, and it misses passages that use different words with the same meaning. Production systems usually use embeddings and vector search to find relevant passages by meaning rather than exact words. The prompt structure stays the same.


Common Mistakes

Assuming Claude Knows Your Situation

What happens: answers follow general practice instead of your product, policies, or audience.

Fix: state the purpose, audience, and relevant facts.

Putting the Question Before Long Documents

What happens: answer quality drops on large inputs.

Fix: place long material first and the question last.

Mixing Documents Without Structure

What happens: Claude confuses which information came from which source.

Fix: wrap each document in tags with its source.

Sending Everything "Just in Case"

What happens: higher cost and latency, and relevant facts are diluted by irrelevant ones.

Fix: select the context that matters for each request, and filter out weak matches.

Not Defining Behavior When Context Is Missing

What happens: Claude fills gaps with plausible but unsupported answers.

Fix: instruct Claude to say when the provided material does not contain the answer.


Best Practices

  • State purpose and audience in every important prompt; one sentence each is often enough.
  • Explain why constraints exist, so Claude can generalize.
  • Structure reference material in tags with source metadata.
  • Put long documents first and questions last.
  • Ask for quotes before answers in document-heavy tasks.
  • Provide situational facts such as the date and user details, placed at the end.
  • Select relevant context per request instead of sending entire knowledge bases.
  • Define the fallback when the answer is not in the context.

Exercise

  1. Write a prompt, without context, asking Claude to "write release notes", and then a version with purpose, audience, and three real changes. Compare the outputs.
  2. Add two entries to KNOWLEDGE_BASE and test questions that should select them. Try changing MIN_SCORE to 1 and observe which extra documents are selected.
  3. Modify build_prompt() to ask Claude to quote relevant sentences in <quotes> tags before answering in <answer> tags. Then extract and print only the <answer> part.
  4. Explain why the Java question correctly produced "I don't know" and what would happen without the system prompt's instruction.
Show answers for steps 2–4

Step 2: with MIN_SCORE = 1, the refund question also selects password_reset.md (both contain "after"), and the Java question selects refund_policy.md (both contain "course"). The extra documents are harmless here, but in larger knowledge bases weak matches add cost and can distract from the relevant material.

Step 3: change the instruction in build_prompt():

instruction = (
    "First, quote the relevant sentences from the documents above inside <quotes> tags. "
    "Then answer the question inside <answer> tags, using only those quotes."
)

Extract the answer with a regular expression:

import re

match = re.search(r"<answer>(.*?)</answer>", get_text(reply), re.DOTALL)
answer = match.group(1).strip() if match else get_text(reply)

re.DOTALL lets . match line breaks, so multi-line answers are captured. The fallback returns the full text if the tags are missing.

Step 4: no document shares enough words with the Java question to pass MIN_SCORE, so select_context() returns nothing, and the system prompt tells Claude to answer only from the documents and to say when it does not know. Without that instruction, Claude might answer from general knowledge, for example by describing what a Java course typically includes. Users could then believe the platform offers a course that does not exist.

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 Add Context to Prompts and get answers drawn from it.

Signed-in readers only.