Skip to content

Commit 096db13

Browse files
committed
Improve documentation & revert protocol
1 parent 940eb1b commit 096db13

File tree

7 files changed

+119
-92
lines changed

7 files changed

+119
-92
lines changed

python/packages/autogen-core/docs/src/user-guide/core-user-guide/framework/model-clients.ipynb

+49-53
Original file line numberDiff line numberDiff line change
@@ -180,58 +180,6 @@
180180
"**NB the default usage response is to return zero values**"
181181
]
182182
},
183-
{
184-
"cell_type": "markdown",
185-
"metadata": {},
186-
"source": [
187-
"## Caching Wrapper\n",
188-
"\n",
189-
"`autogen_core` implements a {py:class}`~autogen_core.models.ChatCompletionCache` that can wrap any {py:class}`~autogen_core.models.ChatCompletionClient`. Using this wrapper avoids incurring token usage when querying the underlying client with the same prompt multiple times. \n",
190-
"\n",
191-
"{py:class}`~autogen_core.models.ChatCompletionCache` uses a {py:class}`~autogen_core.CacheStore` protocol to allow duck-typing any storage object that has a pair of `get` & `set` methods (such as `redis.Redis` or `diskcache.Cache`)."
192-
]
193-
},
194-
{
195-
"cell_type": "code",
196-
"execution_count": null,
197-
"metadata": {},
198-
"outputs": [],
199-
"source": [
200-
"from typing import Any, Dict, Optional\n",
201-
"\n",
202-
"from autogen_core import CacheStore\n",
203-
"from autogen_core.models import CHAT_CACHE_VALUE_TYPE, ChatCompletionCache\n",
204-
"\n",
205-
"\n",
206-
"# Simple CacheStore implementation using in-memory dict,\n",
207-
"# you can also use redis.Redis or diskcache.Cache\n",
208-
"class DictStore(CacheStore[CHAT_CACHE_VALUE_TYPE]):\n",
209-
" def __init__(self) -> None:\n",
210-
" self._store: dict[str, CHAT_CACHE_VALUE_TYPE] = {}\n",
211-
"\n",
212-
" def get(self, key: str, default: Optional[CHAT_CACHE_VALUE_TYPE] = None) -> Optional[CHAT_CACHE_VALUE_TYPE]:\n",
213-
" return self._store.get(key, default)\n",
214-
"\n",
215-
" def set(self, key: str, value: CHAT_CACHE_VALUE_TYPE) -> None:\n",
216-
" self._store[key] = value\n",
217-
"\n",
218-
"\n",
219-
"cached_client = ChatCompletionCache(model_client, DictStore())\n",
220-
"response = await cached_client.create(messages=messages)\n",
221-
"\n",
222-
"cached_response = await cached_client.create(messages=messages)\n",
223-
"print(cached_response.cached)"
224-
]
225-
},
226-
{
227-
"cell_type": "markdown",
228-
"metadata": {},
229-
"source": [
230-
"Inspecting `cached_client.total_usage()` (or `model_client.total_usage()`) before and after a cached response should yield idential counts.\n",
231-
"\n",
232-
"Note that the caching is sensitive to the exact arguments provided to `cached_client.create` or `cached_client.create_stream`, so changing `tools` or `json_output` arguments might lead to a cache miss."
233-
]
234-
},
235183
{
236184
"cell_type": "markdown",
237185
"metadata": {},
@@ -373,6 +321,54 @@
373321
"```"
374322
]
375323
},
324+
{
325+
"cell_type": "markdown",
326+
"metadata": {},
327+
"source": [
328+
"## Caching Wrapper\n",
329+
"\n",
330+
"`autogen_core` implements a {py:class}`~autogen_core.models.ChatCompletionCache` that can wrap any {py:class}`~autogen_core.models.ChatCompletionClient`. Using this wrapper avoids incurring token usage when querying the underlying client with the same prompt multiple times. \n",
331+
"\n",
332+
"{py:class}`~autogen_core.models.ChatCompletionCache` uses a {py:class}`~autogen_core.CacheStore` protocol to allow duck-typing any storage object that has a pair of `get` & `set` methods (such as `redis.Redis` or `diskcache.Cache`). Here's an example of using `diskcache` for local caching:"
333+
]
334+
},
335+
{
336+
"cell_type": "code",
337+
"execution_count": null,
338+
"metadata": {},
339+
"outputs": [
340+
{
341+
"name": "stdout",
342+
"output_type": "stream",
343+
"text": [
344+
"True\n"
345+
]
346+
}
347+
],
348+
"source": [
349+
"from typing import Any, Dict, Optional\n",
350+
"\n",
351+
"from autogen_core.models import ChatCompletionCache\n",
352+
"from diskcache import Cache\n",
353+
"\n",
354+
"diskcache_client = Cache(\"/tmp/diskcache\")\n",
355+
"\n",
356+
"cached_client = ChatCompletionCache(model_client, diskcache_client)\n",
357+
"response = await cached_client.create(messages=messages)\n",
358+
"\n",
359+
"cached_response = await cached_client.create(messages=messages)\n",
360+
"print(cached_response.cached)"
361+
]
362+
},
363+
{
364+
"cell_type": "markdown",
365+
"metadata": {},
366+
"source": [
367+
"Inspecting `cached_client.total_usage()` (or `model_client.total_usage()`) before and after a cached response should yield idential counts.\n",
368+
"\n",
369+
"Note that the caching is sensitive to the exact arguments provided to `cached_client.create` or `cached_client.create_stream`, so changing `tools` or `json_output` arguments might lead to a cache miss."
370+
]
371+
},
376372
{
377373
"cell_type": "markdown",
378374
"metadata": {},
@@ -673,7 +669,7 @@
673669
"name": "python",
674670
"nbconvert_exporter": "python",
675671
"pygments_lexer": "ipython3",
676-
"version": "3.12.7"
672+
"version": "3.12.1"
677673
}
678674
},
679675
"nbformat": 4,

python/packages/autogen-core/pyproject.toml

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ dev = [
7272
"autogen_ext==0.4.3",
7373

7474
# Documentation tooling
75+
"diskcache",
76+
"redis",
7577
"sphinx-autobuild",
7678
]
7779

python/packages/autogen-core/src/autogen_core/_cache_store.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
from typing import Generic, Optional, Protocol, TypeVar
1+
from typing import Any, Optional, Protocol
22

3-
T = TypeVar("T")
43

5-
6-
class CacheStore(Protocol, Generic[T]):
4+
class CacheStore(Protocol):
75
"""
86
This protocol defines the basic interface for store/cache operations.
97
108
Allows duck-typing with any object that implements the get and set methods,
119
such as redis or diskcache interfaces.
1210
"""
1311

14-
def get(self, key: str, default: Optional[T] = None) -> Optional[T]:
12+
def get(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
1513
"""
1614
Retrieve an item from the store.
1715
@@ -25,7 +23,7 @@ def get(self, key: str, default: Optional[T] = None) -> Optional[T]:
2523
"""
2624
...
2725

28-
def set(self, key: str, value: T) -> None:
26+
def set(self, key: str, value: Any) -> Optional[Any]:
2927
"""
3028
Set an item in the store.
3129

python/packages/autogen-core/src/autogen_core/models/__init__.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from ._cache import CHAT_CACHE_VALUE_TYPE, ChatCompletionCache
1+
from ._cache import ChatCompletionCache
22
from ._model_client import ChatCompletionClient, ModelCapabilities, ModelFamily, ModelInfo # type: ignore
33
from ._replay_chat_completion_client import ReplayChatCompletionClient
44
from ._types import (
@@ -17,7 +17,6 @@
1717

1818
__all__ = [
1919
"ModelCapabilities",
20-
"CHAT_CACHE_VALUE_TYPE",
2120
"ChatCompletionCache",
2221
"ChatCompletionClient",
2322
"SystemMessage",

python/packages/autogen-core/src/autogen_core/models/_cache.py

+32-25
Original file line numberDiff line numberDiff line change
@@ -17,47 +17,54 @@
1717
RequestUsage,
1818
)
1919

20-
CHAT_CACHE_VALUE_TYPE = Union[CreateResult, List[Union[str, CreateResult]]]
21-
2220

2321
class ChatCompletionCache(ChatCompletionClient):
2422
"""
2523
A wrapper around a ChatCompletionClient that caches creation results from an underlying client.
2624
Cache hits do not contribute to token usage of the original client.
27-
"""
2825
29-
def __init__(self, client: ChatCompletionClient, store: CacheStore[CHAT_CACHE_VALUE_TYPE]):
30-
"""
31-
Initialize a new ChatCompletionCache.
26+
Typical Usage:
3227
33-
First initialize (for eg) a Redis store:
28+
Lets use caching with `openai` as an example:
3429
35-
```python
36-
import redis
30+
.. code-block:: bash
3731
38-
redis_client = redis.Redis(host="localhost", port=6379, db=0)
39-
```
32+
pip install "autogen-ext[openai]==0.4.0.dev13"
4033
41-
or diskcache store:
34+
And use it as:
4235
43-
```python
44-
from diskcache import Cache
36+
.. code-block:: python
37+
38+
# Initialize the original client
39+
from autogen_ext.models.openai import OpenAIChatCompletionClient
40+
41+
openai_client = OpenAIChatCompletionClient(
42+
model="gpt-4o-2024-08-06",
43+
# api_key="sk-...", # Optional if you have an OPENAI_API_KEY environment variable set.
44+
)
4545
46-
diskcache_client = Cache("/tmp/diskcache")
47-
```
46+
# Then initialize the CacheStore. Either a Redis store:
47+
import redis
4848
49-
Then initialize the ChatCompletionCache with the store:
49+
redis_client = redis.Redis(host="localhost", port=6379, db=0)
5050
51-
```python
52-
from autogen_core.models import ChatCompletionCache
53-
from autogen_ext.models import OpenAIChatCompletionClient
51+
# or diskcache:
52+
from diskcache import Cache
5453
55-
# Original client
56-
client = OpenAIChatCompletionClient(...)
54+
diskcache_client = Cache("/tmp/diskcache")
5755
58-
# Cached version
59-
cached_client = ChatCompletionCache(client, redis_client)
60-
```
56+
# Then initialize the ChatCompletionCache with the store:
57+
from autogen_core.models import ChatCompletionCache
58+
59+
# Cached client
60+
cached_client = ChatCompletionCache(openai_client, diskcache_client)
61+
62+
You can now use the `cached_client` as you would the original client, but with caching enabled.
63+
"""
64+
65+
def __init__(self, client: ChatCompletionClient, store: CacheStore):
66+
"""
67+
Initialize a new ChatCompletionCache.
6168
6269
Args:
6370
client (ChatCompletionClient): The original ChatCompletionClient to wrap.

python/packages/autogen-core/tests/test_chat_completion_cache.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import copy
2-
from typing import List, Optional, Tuple, Union
2+
from typing import Any, List, Optional, Tuple, Union
33

44
import pytest
55
from autogen_core import CacheStore
66
from autogen_core.models import (
7-
CHAT_CACHE_VALUE_TYPE,
87
ChatCompletionCache,
98
ChatCompletionClient,
109
CreateResult,
@@ -15,15 +14,16 @@
1514
)
1615

1716

18-
class DictStore(CacheStore[CHAT_CACHE_VALUE_TYPE]):
17+
class DictStore(CacheStore):
1918
def __init__(self) -> None:
20-
self._store: dict[str, CHAT_CACHE_VALUE_TYPE] = {}
19+
self._store: dict[str, Any] = {}
2120

22-
def get(self, key: str, default: Optional[CHAT_CACHE_VALUE_TYPE] = None) -> Optional[CHAT_CACHE_VALUE_TYPE]:
21+
def get(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
2322
return self._store.get(key, default)
2423

25-
def set(self, key: str, value: CHAT_CACHE_VALUE_TYPE) -> None:
24+
def set(self, key: str, value: Any) -> Optional[Any]:
2625
self._store[key] = value
26+
return None
2727

2828

2929
def get_test_data() -> Tuple[list[str], list[str], SystemMessage, ChatCompletionClient, ChatCompletionCache]:

python/uv.lock

+25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)