Prompt Caching with Dynamic Block
Augment the agent-built system prompt with a dynamic per-request block.
These short examples demonstrate cache configuration, not guaranteed cache writes or hits. Sonnet 4.5 requires at least 1,024 tokens in the cached prefix; the dynamic-block example's static prefix is too short. Use representative static content that meets the model's cache minimum, keep it identical across requests, and inspect response.metrics.cache_write_tokens and cache_read_tokens. Cache reuse does not supply conversation history: apply the database setup below for the dependent follow-up question.
"""
Augment the agent-built system prompt with a dynamic per-request block.
The Agent's description + instructions are assembled into the first system
block and cached automatically when cache_system_prompt=True. A
SystemPromptBlock appended after can carry dynamic content without
invalidating the cached prefix, as long as cache=False on the dynamic
block.
Pass system_prompt_blocks as a callable to have it evaluated on every
request — the right pattern when the dynamic text (timestamp, user
identity, session state) must be fresh per call. The callable runs inside
Claude._build_system with no arguments, so close over whatever state you
need.
Docs: https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
"""
from datetime import datetime
from agno.agent import Agent
from agno.models.anthropic import Claude, SystemPromptBlock
def build_request_blocks() -> list[SystemPromptBlock]:
# Evaluated per request: the timestamp (and any other per-request context)
# stays fresh without mutating the model or reinstantiating the agent.
return [
SystemPromptBlock(
text=(
f"Current server time: {datetime.now().isoformat()}. "
"The user is on the Enterprise plan and prefers Python examples."
),
cache=False,
)
]
agent = Agent(
model=Claude(
id="claude-sonnet-4-5-20250929",
cache_system_prompt=True,
system_prompt_blocks=build_request_blocks,
),
description=(
"You are an expert software architect who gives concise, opinionated "
"advice grounded in real-world experience. You prefer battle-tested "
"patterns over trendy abstractions."
),
instructions=[
"Answer in two to four paragraphs.",
"When comparing options, list the trade-offs honestly.",
"If you do not know the answer, say so plainly.",
],
markdown=True,
)
# First run writes the cache on the agent-built system block
response = agent.run("How should I structure a large FastAPI application?")
if response and response.metrics:
print(
f"Run 1 - cache write: {response.metrics.cache_write_tokens}, "
f"cache read: {response.metrics.cache_read_tokens}"
)
# Second run reads the cached prefix. build_request_blocks runs again so the
# dynamic timestamp refreshes, but because that block is cache=False the
# prefix before it stays stable and cache-hot.
response = agent.run("How should I handle background jobs in that setup?")
if response and response.metrics:
print(
f"Run 2 - cache write: {response.metrics.cache_write_tokens}, "
f"cache read: {response.metrics.cache_read_tokens}"
)Run the Example
Set up your virtual environment
uv venv --python 3.12
source .venv/bin/activateInstall dependencies
uv pip install -U agno anthropicExport your Anthropic API key
export ANTHROPIC_API_KEY="your_anthropic_api_key_here"Retain the conversation for the follow-up
Add from agno.db.in_memory import InMemoryDb to your imports, then add db=InMemoryDb(), and add_history_to_context=True, inside Agent(...). Keep both calls on the same agent and session. The history lasts for this process only.
Run the example
Save the code above as prompt_caching_with_dynamic_block.py, then run:
python prompt_caching_with_dynamic_block.pyFull source: cookbook/90_models/anthropic/prompt_caching_with_dynamic_block.py