Conversation
|
How about making this part of the language model (engine), e.g. as a wrapper?
Also, it would be nice to have a verification that only cached queries are made, and in the right order. |
|
Checks that query match are already there. I wanted to create a ReplayModel but it has some caveats:
|
|
do I understand correctly that
are two independent things @spirali? |
| prompt: str | FormatStr, | ||
| kwargs: dict = None, | ||
| with_context=True, | ||
| replay: Replay = None, |
There was a problem hiding this comment.
typing should be Optional[Replay] or Replay | None
| class Replay: | ||
| def __init__(self, context: Context): | ||
| self.replays = {} | ||
| for context in context.find_contexts(lambda ctx: ctx.kind == "query"): |
There was a problem hiding this comment.
might be good to extract string constants like "query", "conf", "prompt" etc into a constants module. it can reduce the risk of bugs from typos. it can also signal to future devs that these are keys which more than one module relies on
| self.replays.setdefault(key, []) | ||
| self.replays[key].append(context.result) | ||
| for replay in self.replays.values(): | ||
| replay.reverse() |
There was a problem hiding this comment.
the logic here assumes that future implementations of StorageBase.list adhere to a certain order of listing contexts. This should be specified in the doc string of StorageBase.list and tested in a unit test (if not there already)
|
|
||
|
|
||
| @patch("interlab.lang_models.openai._make_openai_chat_query") | ||
| def test_replay_model(_make_openai_chat_query): |
|
returning to this point by @gavento
calls to What are your thoughts about making replay easily available consistently across all methods which rely on LLM calls @spirali? PS: also wanted to say that I find the current implementation very clean and readable! just not sure what the best design will be in the longer run |
|
Major thought why not: separation of concerns.
I am against adding more functionality to it - I think it is bad design, and the functionality does not seem core to me (or, at least, I am not convinced it is the right way to do it), and bloating one function for it seems bad design for any future.
Prevalence of
So how about adding it as a wrapper around LLMs individually?
|
|
I am rewriting replay functionality from scratch. I want to make this functionality completely generic (any function / method call can be replayed, not necessarily only LLMs). I have some PoC but I would like to sanity check of the idea before finishing it. Here is how it should look at the end: def my_function(x, y):
return x + y
replay = Replay("my-replay-stream-name")
# Storing replay
with Context("root") as root:
replay(my_function)(1, 2)
# Using replay
replay = Replay("my-replay-stream-name", context=root)
with Context("root") as root:
replay(my_function)(2, 3) # Call my_function as it is not in cache
replay(my_function)(1, 2) # Recalls from cache
replay(my_function)(1, 2) # Call my_function as it is not in cache (2nd call)
# Wrapping any object, in replay log is stored also "self"
from langchain.llms import OpenAI
llm = replay(OpenAI(...))
llm.generate(["Tell me a joke."])
# Partial matching
replay(my_function, ignore_args=["y"])(2, 3) # Ignores argument "y" when trying to find matching call in cacheAny comments? |
|
Thanks! Three comments:
|
|
I also want to pitch games/situations with storable state (pickle is fine) and meaningful steps where the state can be stored/restored ;-) |
|
Simple query caching
Fixes #40