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.
What
instructor.cache.make_cache_key— the function documented incaching.md as computing the "deterministic" key
for every
cache=call — only hashesmodel,messages/contents,mode,system, andresponse_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 othersampling parameter, even though these are present in the same
kwargsdict(
new_kwargs) that the two call sites inpatch.pyalready 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 differenttemperature(orseed,top_p, ...) produce the same cache key. If thefirst 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 acrosscalls that vary
temperatureper-request (e.g. deterministic calls attemperature=0alongside exploratory calls at higher temperature) isexactly the kind of thing
cache=is documented to support transparently.Reproduction
Confirmed end-to-end through the real client (not just the key function) via
instructor.from_litellmwith a fake completion function that returns adifferent value on each call: a
temperature=1.9call after a cachedtemperature=0.0call receives thetemperature=0.0response without theprovider 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_keywith an optionalgeneration_kwargscomponent andpopulate it at the
patch.pycache lookup/store sites fromnew_kwargs.PR incoming.