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.