Search results
Enable natural citations for RAG applications by providing search results with source attribution
Search result content blocks let Claude cite your own content the same way it cites web search results: each citation carries the source and title you provided. Use them in RAG (Retrieval-Augmented Generation) applications where Claude needs to attribute answers to your documents.
All active models support search results with citations, with the exception of Claude Haiku 3. No beta header is required: search results are part of the standard Messages API.
How it works
Search results can be provided in two ways:
- From tool calls: Your custom tools return search results, enabling dynamic RAG applications
- As top-level content: You provide search results directly in user messages for pre-fetched or cached content
In both cases, Claude cites the search results automatically when citations are enabled. No special prompting is needed: ask your question, and citations appear on the text blocks that draw on your content.
Search result schema
Search results use the following structure:
{
"type": "search_result",
"source": "https://example.com/article", // Required: Source URL or identifier
"title": "Article Title", // Required: Title of the result
"content": [
// Required: Array of text blocks
{
"type": "text",
"text": "The actual content of the search result..."
}
],
"citations": {
// Optional: Citation configuration
"enabled": true // Enable/disable citations for this result
}
}Required fields
| Field | Type | Description |
|---|---|---|
type | string | Must be "search_result" |
source | string | The source of the content. Any stable string works: a URL, or an internal identifier such as kb://article-1234 |
title | string | A descriptive title for the search result |
content | array | An array of text blocks containing the actual content |
Optional fields
| Field | Type | Description |
|---|---|---|
citations | object | Citation configuration with enabled Boolean field. Citations are disabled by default; every example on this page sets "enabled": true explicitly. All search results in a request must use the same setting (see Citation control) |
cache_control | object | Cache control settings (for example, {"type": "ephemeral"}) |
Each item in the content array must be a text block with:
type: Must be"text"text: The actual text content (non-empty string)
Search results hold text only. Images and other media are not supported inside the content array.
Method 1: Search results from tool calls
Returning search results from your custom tools enables dynamic RAG applications: tools fetch content at runtime, and Claude cites it in the response. The following example forces the tool call with tool_choice, so the retrieval step runs every time.
Example: Knowledge base tool
from anthropic.types import (
MessageParam,
TextBlockParam,
SearchResultBlockParam,
ToolResultBlockParam,
)
client = Anthropic()
# Define a knowledge base search tool
knowledge_base_tool = {
"name": "search_knowledge_base",
"description": "Search the company knowledge base for information",
"input_schema": {
"type": "object",
"properties": {"query": {"type": "string", "description": "The search query"}},
"required": ["query"],
},
}
# Function to handle the tool call
def search_knowledge_base(query):
# Your search logic here
# Returns search results in the correct format
return [
SearchResultBlockParam(
type="search_result",
source="https://docs.company.com/product-guide",
title="Product Configuration Guide",
content=[
TextBlockParam(
type="text",
text="To configure the product, navigate to Settings > Configuration. The default timeout is 30 seconds, but can be adjusted between 10-120 seconds based on your needs.",
)
],
citations={"enabled": True},
),
SearchResultBlockParam(
type="search_result",
source="https://docs.company.com/troubleshooting",
title="Troubleshooting Guide",
content=[
TextBlockParam(
type="text",
text="If you encounter timeout errors, first check the configuration settings. Common causes include network latency and incorrect timeout values.",
)
],
citations={"enabled": True},
),
]
# Build up the conversation in a list, starting with the user's question
messages = [
MessageParam(role="user", content="How do I configure the timeout settings?")
]
# Create a message with the tool
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
tools=[knowledge_base_tool],
tool_choice={"type": "tool", "name": "search_knowledge_base"},
messages=messages,
)
# When Claude calls the tool, provide the search results.
# The tool_use block is not always first: iterate to find it.
tool_use = next((block for block in response.content if block.type == "tool_use"), None)
if tool_use is not None:
tool_result = search_knowledge_base(tool_use.input["query"])
# Append Claude's turn, then the tool result, to the running conversation
messages.append(MessageParam(role="assistant", content=response.content))
messages.append(
MessageParam(
role="user",
content=[
ToolResultBlockParam(
type="tool_result",
tool_use_id=tool_use.id,
content=tool_result, # Search results go here
)
],
)
)
# Send the tool result back
final_response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=messages,
)
print(final_response)Method 2: Search results as top-level content
You can also provide search results directly in user messages. This is useful for: