Skip to content

Commit fc14443

Browse files
Zamoca42jacoblee93
andauthored
feat(community): Add VercelKVcache (#7447)
Co-authored-by: jacoblee93 <[email protected]>
1 parent c132cf9 commit fc14443

File tree

10 files changed

+248
-0
lines changed

10 files changed

+248
-0
lines changed

docs/core_docs/docs/how_to/chat_model_caching.mdx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,64 @@ import RedisCacheExample from "@examples/cache/chat_models/redis.ts";
9898

9999
<CodeBlock language="typescript">{RedisCacheExample}</CodeBlock>
100100

101+
## Caching with Upstash Redis
102+
103+
LangChain provides an Upstash Redis-based cache. Like the Redis-based cache, this cache is useful if you want to share the cache across multiple processes or servers. The Upstash Redis client uses HTTP and supports edge environments. To use it, you'll need to install the `@upstash/redis` package:
104+
105+
```bash npm2yarn
106+
npm install @upstash/redis
107+
```
108+
109+
You'll also need an [Upstash account](https://docs.upstash.com/redis#create-account) and a [Redis database](https://docs.upstash.com/redis#create-a-database) to connect to. Once you've done that, retrieve your REST URL and REST token.
110+
111+
Then, you can pass a `cache` option when you instantiate the LLM. For example:
112+
113+
import UpstashRedisCacheExample from "@examples/cache/chat_models/upstash_redis.ts";
114+
115+
<CodeBlock language="typescript">{UpstashRedisCacheExample}</CodeBlock>
116+
117+
You can also directly pass in a previously created [@upstash/redis](https://docs.upstash.com/redis/sdks/javascriptsdk/overview) client instance:
118+
119+
import AdvancedUpstashRedisCacheExample from "@examples/cache/chat_models/upstash_redis_advanced.ts";
120+
121+
<CodeBlock language="typescript">{AdvancedUpstashRedisCacheExample}</CodeBlock>
122+
123+
## Caching with Vercel KV
124+
125+
LangChain provides an Vercel KV-based cache. Like the Redis-based cache, this cache is useful if you want to share the cache across multiple processes or servers. The Vercel KV client uses HTTP and supports edge environments. To use it, you'll need to install the `@vercel/kv` package:
126+
127+
```bash npm2yarn
128+
npm install @vercel/kv
129+
```
130+
131+
You'll also need an Vercel account and a [KV database](https://vercel.com/docs/storage/vercel-kv/kv-reference) to connect to. Once you've done that, retrieve your REST URL and REST token.
132+
133+
Then, you can pass a `cache` option when you instantiate the LLM. For example:
134+
135+
import VercelKVCacheExample from "@examples/cache/chat_models/vercel_kv.ts";
136+
137+
<CodeBlock language="typescript">{VercelKVCacheExample}</CodeBlock>
138+
139+
## Caching with Cloudflare KV
140+
141+
:::info
142+
This integration is only supported in Cloudflare Workers.
143+
:::
144+
145+
If you're deploying your project as a Cloudflare Worker, you can use LangChain's Cloudflare KV-powered LLM cache.
146+
147+
For information on how to set up KV in Cloudflare, see [the official documentation](https://developers.cloudflare.com/kv/).
148+
149+
**Note:** If you are using TypeScript, you may need to install types if they aren't already present:
150+
151+
```bash npm2yarn
152+
npm install -S @cloudflare/workers-types
153+
```
154+
155+
import CloudflareExample from "@examples/cache/chat_models/cloudflare_kv.ts";
156+
157+
<CodeBlock language="typescript">{CloudflareExample}</CodeBlock>
158+
101159
## Caching on the File System
102160

103161
:::warning

docs/core_docs/docs/how_to/llm_caching.mdx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,22 @@ import AdvancedUpstashRedisCacheExample from "@examples/cache/upstash_redis_adva
161161

162162
<CodeBlock language="typescript">{AdvancedUpstashRedisCacheExample}</CodeBlock>
163163

164+
## Caching with Vercel KV
165+
166+
LangChain provides an Vercel KV-based cache. Like the Redis-based cache, this cache is useful if you want to share the cache across multiple processes or servers. The Vercel KV client uses HTTP and supports edge environments. To use it, you'll need to install the `@vercel/kv` package:
167+
168+
```bash npm2yarn
169+
npm install @vercel/kv
170+
```
171+
172+
You'll also need an Vercel account and a [KV database](https://vercel.com/docs/storage/vercel-kv/kv-reference) to connect to. Once you've done that, retrieve your REST URL and REST token.
173+
174+
Then, you can pass a `cache` option when you instantiate the LLM. For example:
175+
176+
import VercelKVCacheExample from "@examples/cache/vercel_kv.ts";
177+
178+
<CodeBlock language="typescript">{VercelKVCacheExample}</CodeBlock>
179+
164180
## Caching with Cloudflare KV
165181

166182
:::info
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ChatOpenAI } from "@langchain/openai";
2+
import { VercelKVCache } from "@langchain/community/caches/vercel_kv";
3+
import { createClient } from "@vercel/kv";
4+
5+
// See https://vercel.com/docs/storage/vercel-kv/kv-reference#createclient-example for connection options
6+
const cache = new VercelKVCache({
7+
client: createClient({
8+
url: "VERCEL_KV_API_URL",
9+
token: "VERCEL_KV_API_TOKEN",
10+
}),
11+
ttl: 3600,
12+
});
13+
14+
const model = new ChatOpenAI({
15+
model: "gpt-4o-mini",
16+
cache,
17+
});

examples/src/cache/vercel_kv.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { OpenAI } from "@langchain/openai";
2+
import { VercelKVCache } from "@langchain/community/caches/vercel_kv";
3+
import { createClient } from "@vercel/kv";
4+
5+
// See https://vercel.com/docs/storage/vercel-kv/kv-reference#createclient-example for connection options
6+
const cache = new VercelKVCache({
7+
client: createClient({
8+
url: "VERCEL_KV_API_URL",
9+
token: "VERCEL_KV_API_TOKEN",
10+
}),
11+
ttl: 3600,
12+
});
13+
14+
const model = new OpenAI({ cache });

libs/langchain-community/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,10 @@ caches/upstash_redis.cjs
714714
caches/upstash_redis.js
715715
caches/upstash_redis.d.ts
716716
caches/upstash_redis.d.cts
717+
caches/vercel_kv.cjs
718+
caches/vercel_kv.js
719+
caches/vercel_kv.d.ts
720+
caches/vercel_kv.d.cts
717721
graphs/neo4j_graph.cjs
718722
graphs/neo4j_graph.js
719723
graphs/neo4j_graph.d.ts

libs/langchain-community/langchain.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ export const config = {
222222
"caches/ioredis": "caches/ioredis",
223223
"caches/momento": "caches/momento",
224224
"caches/upstash_redis": "caches/upstash_redis",
225+
"caches/vercel_kv": "caches/vercel_kv",
225226
// graphs
226227
"graphs/neo4j_graph": "graphs/neo4j_graph",
227228
"graphs/memgraph_graph": "graphs/memgraph_graph",
@@ -453,9 +454,12 @@ export const config = {
453454
"structured_query/supabase",
454455
"structured_query/vectara",
455456
"retrievers/zep_cloud",
457+
// cache
456458
"cache/cloudflare_kv",
457459
"cache/momento",
458460
"cache/upstash_redis",
461+
"cache/vercel_kv",
462+
//graphs
459463
"graphs/neo4j_graph",
460464
"graphs/memgraph_graph",
461465
// document_compressors

libs/langchain-community/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2334,6 +2334,15 @@
23342334
"import": "./caches/upstash_redis.js",
23352335
"require": "./caches/upstash_redis.cjs"
23362336
},
2337+
"./caches/vercel_kv": {
2338+
"types": {
2339+
"import": "./caches/vercel_kv.d.ts",
2340+
"require": "./caches/vercel_kv.d.cts",
2341+
"default": "./caches/vercel_kv.d.ts"
2342+
},
2343+
"import": "./caches/vercel_kv.js",
2344+
"require": "./caches/vercel_kv.cjs"
2345+
},
23372346
"./graphs/neo4j_graph": {
23382347
"types": {
23392348
"import": "./graphs/neo4j_graph.d.ts",
@@ -3900,6 +3909,10 @@
39003909
"caches/upstash_redis.js",
39013910
"caches/upstash_redis.d.ts",
39023911
"caches/upstash_redis.d.cts",
3912+
"caches/vercel_kv.cjs",
3913+
"caches/vercel_kv.js",
3914+
"caches/vercel_kv.d.ts",
3915+
"caches/vercel_kv.d.cts",
39033916
"graphs/neo4j_graph.cjs",
39043917
"graphs/neo4j_graph.js",
39053918
"graphs/neo4j_graph.d.ts",
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* eslint-disable no-process-env */
2+
import { ChatOpenAI } from "@langchain/openai";
3+
import { createClient } from "@vercel/kv";
4+
import { VercelKVCache } from "../vercel_kv.js";
5+
6+
test("VercelKVCache works with ChatOpenAI", async () => {
7+
if (
8+
!process.env.VERCEL_KV_API_URL ||
9+
!process.env.VERCEL_KV_API_TOKEN ||
10+
!process.env.OPENAI_API_KEY
11+
) {
12+
throw new Error("Missing Vercel KV API URL, token, or OpenAI API key");
13+
}
14+
15+
const vercelKVCache = new VercelKVCache({
16+
client: createClient({
17+
url: process.env.VERCEL_KV_API_URL,
18+
token: process.env.VERCEL_KV_API_TOKEN,
19+
}),
20+
ttl: 60,
21+
});
22+
23+
const chat = new ChatOpenAI({
24+
temperature: 0,
25+
cache: vercelKVCache,
26+
maxTokens: 10,
27+
});
28+
29+
const prompt = "What color is the sky?";
30+
const result1 = await chat.invoke(prompt);
31+
const result2 = await chat.invoke(prompt);
32+
33+
expect(result1).toEqual(result2);
34+
});
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { kv, type VercelKV } from "@vercel/kv";
2+
3+
import { Generation } from "@langchain/core/outputs";
4+
import {
5+
BaseCache,
6+
deserializeStoredGeneration,
7+
getCacheKey,
8+
serializeGeneration,
9+
} from "@langchain/core/caches";
10+
import { StoredGeneration } from "@langchain/core/messages";
11+
12+
export type VercelKVCacheProps = {
13+
/**
14+
* An existing Vercel KV client
15+
*/
16+
client?: VercelKV;
17+
/**
18+
* Time-to-live (TTL) for cached items in seconds
19+
*/
20+
ttl?: number;
21+
};
22+
23+
/**
24+
* A cache that uses Vercel KV as the backing store.
25+
* @example
26+
* ```typescript
27+
* const cache = new VercelKVCache({
28+
* ttl: 3600, // Optional: Cache entries will expire after 1 hour
29+
* });
30+
*
31+
* // Initialize the OpenAI model with Vercel KV cache for caching responses
32+
* const model = new ChatOpenAI({
33+
* cache,
34+
* });
35+
* await model.invoke("How are you today?");
36+
* const cachedValues = await cache.lookup("How are you today?", "llmKey");
37+
* ```
38+
*/
39+
export class VercelKVCache extends BaseCache {
40+
private client: VercelKV;
41+
42+
private ttl?: number;
43+
44+
constructor(props: VercelKVCacheProps) {
45+
super();
46+
const { client, ttl } = props;
47+
this.client = client ?? kv;
48+
this.ttl = ttl;
49+
}
50+
51+
/**
52+
* Lookup LLM generations in cache by prompt and associated LLM key.
53+
*/
54+
public async lookup(prompt: string, llmKey: string) {
55+
let idx = 0;
56+
let key = getCacheKey(prompt, llmKey, String(idx));
57+
let value = await this.client.get<StoredGeneration | null>(key);
58+
const generations: Generation[] = [];
59+
60+
while (value) {
61+
generations.push(deserializeStoredGeneration(value));
62+
idx += 1;
63+
key = getCacheKey(prompt, llmKey, String(idx));
64+
value = await this.client.get<StoredGeneration | null>(key);
65+
}
66+
67+
return generations.length > 0 ? generations : null;
68+
}
69+
70+
/**
71+
* Update the cache with the given generations.
72+
*
73+
* Note this overwrites any existing generations for the given prompt and LLM key.
74+
*/
75+
public async update(prompt: string, llmKey: string, value: Generation[]) {
76+
for (let i = 0; i < value.length; i += 1) {
77+
const key = getCacheKey(prompt, llmKey, String(i));
78+
const serializedValue = JSON.stringify(serializeGeneration(value[i]));
79+
80+
if (this.ttl) {
81+
await this.client.set(key, serializedValue, { ex: this.ttl });
82+
} else {
83+
await this.client.set(key, serializedValue);
84+
}
85+
}
86+
}
87+
}

libs/langchain-community/src/load/import_map.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export * as caches__cloudflare_kv from "../caches/cloudflare_kv.js";
6767
export * as caches__ioredis from "../caches/ioredis.js";
6868
export * as caches__momento from "../caches/momento.js";
6969
export * as caches__upstash_redis from "../caches/upstash_redis.js";
70+
export * as caches__vercel_kv from "../caches/vercel_kv.js";
7071
export * as stores__doc__base from "../stores/doc/base.js";
7172
export * as stores__doc__gcs from "../stores/doc/gcs.js";
7273
export * as stores__doc__in_memory from "../stores/doc/in_memory.js";

0 commit comments

Comments
 (0)