Skip to content

AutoCache/DiskCache key ignores temperature/seed/etc. — calls that only differ in sampling params silently return a stale cached response #2585

Description

@Yashwanth-Kumar-Kotla

What

instructor.cache.make_cache_key — the function documented in
caching.md as computing the "deterministic" key
for every cache= call — only hashes model, messages/contents,
mode, system, and response_model's schema:

https://github.com/567-labs/instructor/blob/main/instructor/cache/__init__.py#L145-L189

It never inspects temperature, top_p, seed, max_tokens, or any other
sampling parameter, even though these are present in the same kwargs dict
(new_kwargs) that the two call sites in patch.py already have in scope:

https://github.com/567-labs/instructor/blob/main/instructor/v2/core/patch.py#L251-L259

Two client.create(...) calls with identical messages/model but different
temperature (or seed, top_p, ...) produce the same cache key. If the
first call is cached, the second silently returns the first call's answer
instead of hitting the provider — no error, no warning.

This is a normal, expected use pattern: sharing one cache= instance across
calls that vary temperature per-request (e.g. deterministic calls at
temperature=0 alongside exploratory calls at higher temperature) is
exactly the kind of thing cache= is documented to support transparently.

Reproduction

from pydantic import BaseModel
from instructor.cache import make_cache_key, AutoCache

class Answer(BaseModel):
    value: int

messages = [{"role": "user", "content": "Roll a random number between 1 and 100"}]

key_a = make_cache_key(messages=messages, model="gpt-4o", response_model=Answer, mode="tool_call")
key_b = make_cache_key(messages=messages, model="gpt-4o", response_model=Answer, mode="tool_call")
# key_a == key_b always, regardless of temperature/seed/etc. -- the function
# has no parameter for them at all, so callers can't distinguish these calls
# no matter what they pass to client.create(...).

cache = AutoCache()
cache.set(key_a, Answer(value=7))
cache.get(key_b).value  # 7 -- a later, differently-sampled call reuses this

Confirmed end-to-end through the real client (not just the key function) via
instructor.from_litellm with a fake completion function that returns a
different value on each call: a temperature=1.9 call after a cached
temperature=0.0 call receives the temperature=0.0 response without the
provider ever being invoked a second time.

Expected behavior

Two calls that differ only in sampling parameters must not collide in the
cache.

Fix

Extend make_cache_key with an optional generation_kwargs component and
populate it at the patch.py cache lookup/store sites from new_kwargs.
PR incoming.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions