Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cosmosdbnosql: Added Cosmos DB NoSQL Semantic Cache Integration with tests and jupyter notebook #24424

Merged
merged 73 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
80936bf
Added Cosmos DB NoSQL Semantic Cache Integration with tests and jupyt…
gsa9989 Jul 19, 2024
01b7bd1
Merged latest master from upstream and resolved all conflicts
gsa9989 Jul 19, 2024
e891cd9
Removed openai_api_key parameter
gsa9989 Jul 19, 2024
676d762
Removed unnecessary space changes
gsa9989 Jul 19, 2024
7f00b8a
Merge branch 'users/garagundi/cosmosdbnosql' into users/akataria/rebase
aayush3011 Aug 7, 2024
66289ed
Merge pull request #1 from gsa9989/users/akataria/rebase
aayush3011 Aug 7, 2024
bb55a4b
Merge branch 'langchain-ai:master' into users/garagundi/cosmosdbnosql
aayush3011 Aug 7, 2024
2184d8e
Rebase from master
gsa9989 Aug 7, 2024
d9f684b
Merge branch 'users/garagundi/cosmosdbnosql' of https://github.com/gs…
gsa9989 Aug 7, 2024
4701fb7
test updates
gsa9989 Aug 8, 2024
d23bcd6
format
ccurme Aug 27, 2024
043f2bf
Merge branch 'master' into users/garagundi/cosmosdbnosql
ccurme Aug 27, 2024
4f58256
lint
ccurme Aug 27, 2024
cd84f02
Merge branch 'langchain-ai:master' into users/garagundi/cosmosdbnosql
aayush3011 Aug 27, 2024
aa1e846
linting
aayush3011 Aug 27, 2024
636415b
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Aug 27, 2024
cd744f0
linting
aayush3011 Aug 27, 2024
059be6a
Merge branch 'users/garagundi/cosmosdbnosql' of github.com:gsa9989/la…
aayush3011 Aug 27, 2024
c625e7d
linting
aayush3011 Aug 27, 2024
31b7c1b
linting
aayush3011 Aug 27, 2024
98d9d7e
linting
aayush3011 Aug 27, 2024
2c4d2d3
linting
aayush3011 Aug 27, 2024
04ac7ae
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 3, 2024
2c4f281
Linting
aayush3011 Sep 3, 2024
0caa7cd
Linting
aayush3011 Sep 3, 2024
9766154
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 3, 2024
8891976
Linting
aayush3011 Sep 3, 2024
eafbcb8
Merge branch 'users/garagundi/cosmosdbnosql' of github.com:gsa9989/la…
aayush3011 Sep 3, 2024
dbe1504
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 3, 2024
9ffa53f
Linting
aayush3011 Sep 3, 2024
eb1f8bf
Linting
aayush3011 Sep 3, 2024
3599624
Linting
aayush3011 Sep 3, 2024
f18a5d3
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 3, 2024
f2f1ff5
Linting
aayush3011 Sep 3, 2024
1e818da
Linting
aayush3011 Sep 3, 2024
0441131
Linting
aayush3011 Sep 3, 2024
810dd00
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 3, 2024
c3d0917
Linting
aayush3011 Sep 3, 2024
a748a58
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 3, 2024
81887e5
Merge branch 'langchain-ai:master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 25, 2024
860b0c0
Adding notebook sample
aayush3011 Sep 25, 2024
3378365
linting
aayush3011 Sep 25, 2024
fe08580
linting
aayush3011 Sep 25, 2024
cb02b1a
linting
aayush3011 Sep 25, 2024
bc8ee2d
linting
aayush3011 Sep 25, 2024
a5eebd9
linting
aayush3011 Sep 25, 2024
5f2c91f
linting
aayush3011 Sep 26, 2024
cce4959
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 26, 2024
0441fa7
linting
aayush3011 Sep 26, 2024
d003423
Merge branch 'users/garagundi/cosmosdbnosql' of github.com:gsa9989/la…
aayush3011 Sep 26, 2024
05fd438
linting
aayush3011 Sep 26, 2024
9e7838c
linting
aayush3011 Sep 26, 2024
f4250ac
linting
aayush3011 Sep 26, 2024
c13660c
linting
aayush3011 Sep 26, 2024
3f23135
linting
aayush3011 Sep 26, 2024
7fc0f59
Adding support for managed identity for cosmosdb nosql VS
aayush3011 Sep 26, 2024
224393c
linting
aayush3011 Sep 26, 2024
f87f18d
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Sep 26, 2024
cbd6f2b
Adding user agent for vector store
aayush3011 Oct 10, 2024
1ce7bbf
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Oct 10, 2024
9c3bdcb
Resolving comments
aayush3011 Nov 1, 2024
1c1a1e8
Fixing merge conflicts
aayush3011 Nov 1, 2024
6db72c4
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Nov 1, 2024
41474c4
Merge branch 'langchain-ai:master' into users/garagundi/cosmosdbnosql
aayush3011 Dec 5, 2024
ae256f5
Merge branch 'langchain-ai:master' into users/garagundi/cosmosdbnosql
aayush3011 Dec 6, 2024
a4b7d1a
Sample
aayush3011 Dec 6, 2024
3cc98f8
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Dec 6, 2024
d237cd5
linting
aayush3011 Dec 6, 2024
60cf24f
Merge branch 'users/garagundi/cosmosdbnosql' of github.com:gsa9989/la…
aayush3011 Dec 6, 2024
e175d81
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Dec 13, 2024
92ed0ca
Merge branch 'master' into users/garagundi/cosmosdbnosql
aayush3011 Dec 16, 2024
a7a4544
Fixing merge conflicts
aayush3011 Dec 16, 2024
29044fc
fix doc
ccurme Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions docs/docs/integrations/llm_caching.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1854,6 +1854,96 @@
"llm.invoke(\"Tell me a joke\")"
]
},
{
"cell_type": "markdown",
"id": "235ff73bf7143f13",
"metadata": {},
"source": [
"## Azure CosmosDB NoSql Semantic Cache\n",
"\n",
"You can use this integrated [vector database](https://learn.microsoft.com/en-us/azure/cosmos-db/vector-database) for caching."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41fea5aa7b2153ca",
"metadata": {},
"outputs": [],
"source": [
"from typing import Any, Dict\n",
"\n",
"from azure.cosmos import CosmosClient, PartitionKey\n",
"from langchain_community.cache import AzureCosmosDBNoSqlSemanticCache\n",
"from langchain_openai import OpenAIEmbeddings\n",
"\n",
"HOST = \"COSMOS_DB_URI\"\n",
"KEY = \"COSMOS_DB_KEY\"\n",
"\n",
"cosmos_client = CosmosClient(HOST, KEY)\n",
"\n",
"\n",
"def get_vector_indexing_policy() -> dict:\n",
" return {\n",
" \"indexingMode\": \"consistent\",\n",
" \"includedPaths\": [{\"path\": \"/*\"}],\n",
" \"excludedPaths\": [{\"path\": '/\"_etag\"/?'}],\n",
" \"vectorIndexes\": [{\"path\": \"/embedding\", \"type\": \"quantized_flat\"}],\n",
" }\n",
"\n",
"\n",
"def get_vector_embedding_policy() -> dict:\n",
" return {\n",
" \"vectorEmbeddings\": [\n",
" {\n",
" \"path\": \"/embedding\",\n",
" \"dataType\": \"float32\",\n",
" \"dimensions\": 1536,\n",
" \"distanceFunction\": \"cosine\",\n",
" }\n",
" ]\n",
" }\n",
"\n",
"\n",
"cosmos_container_properties_test = {\"partition_key\": PartitionKey(path=\"/id\")}\n",
"cosmos_database_properties_test: Dict[str, Any] = {}\n",
"\n",
"set_llm_cache(\n",
" AzureCosmosDBNoSqlSemanticCache(\n",
" cosmos_client=cosmos_client,\n",
" embedding=OpenAIEmbeddings(),\n",
" vector_embedding_policy=get_vector_indexing_policy(),\n",
" indexing_policy=get_vector_embedding_policy(),\n",
" cosmos_container_properties=cosmos_container_properties_test,\n",
" cosmos_database_properties=cosmos_database_properties_test,\n",
" )\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1e1cd93819921bf6",
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"# The first time, it is not yet in cache, so it should take longer\n",
"llm.invoke(\"Tell me a joke\")"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) Could be worth running these cells to demonstrate the speedup.

]
},
{
"cell_type": "code",
"execution_count": null,
"id": "576ce24c1244812a",
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"# The first time, it is not yet in cache, so it should take longer\n",
"llm.invoke(\"Tell me a joke\")"
]
},
{
"cell_type": "markdown",
"id": "306ff47b",
Expand Down
111 changes: 108 additions & 3 deletions libs/community/langchain_community/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@
from langchain_community.utilities.astradb import (
_AstraDBCollectionEnvironment,
)
from langchain_community.vectorstores import AzureCosmosDBVectorSearch
from langchain_community.vectorstores import (
AzureCosmosDBNoSqlVectorSearch,
AzureCosmosDBVectorSearch,
)
from langchain_community.vectorstores import (
OpenSearchVectorSearch as OpenSearchVectorStore,
)
Expand All @@ -92,6 +95,7 @@
if TYPE_CHECKING:
import momento
from astrapy.db import AstraDB, AsyncAstraDB
from azure.cosmos.cosmos_client import CosmosClient
from cassandra.cluster import Session as CassandraSession


Expand Down Expand Up @@ -2102,7 +2106,7 @@ def __init__(
ef_construction: int = 64,
ef_search: int = 40,
score_threshold: Optional[float] = None,
application_name: str = "LANGCHAIN_CACHING_PYTHON",
application_name: str = "LangChain-CDBNoSQL-SemanticCache-Python",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Couldn't this break user workflows?
  2. What is the motivation for this change? We have AzureCosmosDBSemanticCache and AzureCosmosDBNoSqlSemanticCache separately, but then we are specifying NoSQL here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just a name change, this should not break any workflows. This user agent is being used for tracking purposes only. We want to have it in this pattern, as Azure CosmosDB is integrated in various AI frameworks (microsoft internal and external), and we want to create dashboards to track the usage using these user agents.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but if someone is using the default application_name, after this update the name will change, right? Even if it's just telemetry, I'm not sure we want to change this for users without warning.

It's OK to make such a change if important, but users are already free to specify application_name however they like-- why is it important to change the default here? Let me know if I'm misunderstanding.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we have seen that a lot of users are not specifying the application_name, and we can only see default value in our telemetry. So, that's the reason for this update as we can keep the application_name consistent across all our integrations.

):
"""
Args:
Expand Down Expand Up @@ -2267,14 +2271,115 @@ def clear(self, **kwargs: Any) -> None:
index_name = self._index_name(kwargs["llm_string"])
if index_name in self._cache_dict:
self._cache_dict[index_name].get_collection().delete_many({})
# self._cache_dict[index_name].clear_collection()

@staticmethod
def _validate_enum_value(value: Any, enum_type: Type[Enum]) -> None:
if not isinstance(value, enum_type):
raise ValueError(f"Invalid enum value: {value}. Expected {enum_type}.")


class AzureCosmosDBNoSqlSemanticCache(BaseCache):
"""Cache that uses Cosmos DB NoSQL backend"""

def __init__(
self,
embedding: Embeddings,
cosmos_client: CosmosClient,
database_name: str = "CosmosNoSqlCacheDB",
container_name: str = "CosmosNoSqlCacheContainer",
*,
vector_embedding_policy: Dict[str, Any],
indexing_policy: Dict[str, Any],
cosmos_container_properties: Dict[str, Any],
cosmos_database_properties: Dict[str, Any],
):
self.cosmos_client = cosmos_client
self.database_name = database_name
self.container_name = container_name
self.embedding = embedding
self.vector_embedding_policy = vector_embedding_policy
self.indexing_policy = indexing_policy
self.cosmos_container_properties = cosmos_container_properties
self.cosmos_database_properties = cosmos_database_properties
self._cache_dict: Dict[str, AzureCosmosDBNoSqlVectorSearch] = {}

def _cache_name(self, llm_string: str) -> str:
hashed_index = _hash(llm_string)
return f"cache:{hashed_index}"

def _get_llm_cache(self, llm_string: str) -> AzureCosmosDBNoSqlVectorSearch:
cache_name = self._cache_name(llm_string)

# return vectorstore client for the specific llm string
if cache_name in self._cache_dict:
return self._cache_dict[cache_name]

# create new vectorstore client to create the cache
if self.cosmos_client:
self._cache_dict[cache_name] = AzureCosmosDBNoSqlVectorSearch(
cosmos_client=self.cosmos_client,
embedding=self.embedding,
vector_embedding_policy=self.vector_embedding_policy,
indexing_policy=self.indexing_policy,
cosmos_container_properties=self.cosmos_container_properties,
cosmos_database_properties=self.cosmos_database_properties,
database_name=self.database_name,
container_name=self.container_name,
)

return self._cache_dict[cache_name]

def lookup(self, prompt: str, llm_string: str) -> Optional[RETURN_VAL_TYPE]:
"""Look up based on prompt."""
llm_cache = self._get_llm_cache(llm_string)
generations: List = []
# Read from a Hash
results = llm_cache.similarity_search(
query=prompt,
k=1,
)
if results:
for document in results:
try:
generations.extend(loads(document.metadata["return_val"]))
except Exception:
logger.warning(
"Retrieving a cache value that could not be deserialized "
"properly. This is likely due to the cache being in an "
"older format. Please recreate your cache to avoid this "
"error."
)

generations.extend(
_load_generations_from_json(document.metadata["return_val"])
)
return generations if generations else None

def update(self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE) -> None:
"""Update cache based on prompt and llm_string."""
for gen in return_val:
if not isinstance(gen, Generation):
raise ValueError(
"CosmosDBNoSqlSemanticCache only supports caching of "
f"normal LLM generations, got {type(gen)}"
)
llm_cache = self._get_llm_cache(llm_string)
metadata = {
"llm_string": llm_string,
"prompt": prompt,
"return_val": dumps([g for g in return_val]),
}
llm_cache.add_texts(texts=[prompt], metadatas=[metadata])

def clear(self, **kwargs: Any) -> None:
"""Clear semantic cache for a given llm_string."""
cache_name = self._cache_name(llm_string=kwargs["llm-string"])
if cache_name in self._cache_dict:
container = self._cache_dict["cache_name"].get_container()
for item in container.read_all_items():
container.delete_item(item)


class OpenSearchSemanticCache(BaseCache):
"""Cache that uses OpenSearch vector store backend"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def __init__(
index_name: str = "vectorSearchIndex",
text_key: str = "textContent",
embedding_key: str = "vectorContent",
application_name: str = "LANGCHAIN_PYTHON",
application_name: str = "LangChain-CDBMongoVCore-VectorStore-Python",
):
"""Constructor for AzureCosmosDBVectorSearch

Expand Down Expand Up @@ -119,7 +119,7 @@ def from_connection_string(
connection_string: str,
namespace: str,
embedding: Embeddings,
application_name: str = "LANGCHAIN_PYTHON",
application_name: str = "LangChain-CDBMongoVCore-VectorStore-Python",
**kwargs: Any,
) -> AzureCosmosDBVectorSearch:
"""Creates an Instance of AzureCosmosDBVectorSearch
Expand All @@ -129,6 +129,7 @@ def from_connection_string(
connection_string: The MongoDB vCore instance connection string
namespace: The namespace (database.collection)
embedding: The embedding utility
application_name:
**kwargs: Dynamic keyword arguments

Returns:
Expand Down
Loading
Loading