Tool Result Caching#
cached_tool memoises the return value of a tool’s Python callable in
Redis. The OpenAI Agents SDK does not route tool execution through the
Model interface, so tool caching is a separate primitive from the
AgentMiddleware layer - you apply @cached_tool to the callable
inside @function_tool.
When to use#
Deterministic reads: API lookups, database queries, embeddings.
Expensive computations that tolerate staleness.
When not to use#
Tools with side effects (send_, delete_, create_, …).
Tools whose output must reflect real-time state.
Basic usage#
from agents import function_tool
from redis_openai_agents import cached_tool
@function_tool
@cached_tool(
name="lookup_company",
redis_url="redis://localhost:6379",
ttl=3600,
)
def lookup_company(ticker: str) -> str:
return _hit_paid_api(ticker)
Stacking order matters: @cached_tool must be inside @function_tool
so the cache sees the raw callable before the SDK wraps it.
Volatile arguments#
Arguments whose name is in volatile_arg_names bypass the cache entirely.
Useful for tools that accept a timestamp or trace ID that genuinely changes
the semantics per call.
@cached_tool(
name="forecast",
volatile_arg_names={"timestamp", "now"},
)
def forecast(city: str, timestamp: float) -> str:
...
Defaults: {"timestamp", "current_time", "now", "date", "today", "current_date", "current_timestamp"}.
Ignored arguments#
Arguments in ignored_arg_names are stripped from the cache key before
hashing. Use for values that change every call but don’t affect the result.
@cached_tool(name="search", ignored_arg_names={"trace_id", "request_id"})
def search(query: str, trace_id: str) -> list[str]:
...
Side-effecting tool names#
Tools whose name starts with a side-effect prefix are never cached:
send_, delete_, create_, update_, remove_, write_, post_,
put_, patch_. Override via side_effect_prefixes=(...).
Async tools#
cached_tool works transparently with both sync and async callables.
@function_tool
@cached_tool(name="fetch_user", redis_url="redis://localhost:6379")
async def fetch_user(user_id: int) -> dict:
return await _db.users.get(user_id)
See examples/17-tool-caching.ipynb for a runnable walkthrough.