如何缓存高开销节点¶
节点缓存对于避免重复操作非常有用,例如当您执行一些高开销(无论是时间还是成本)的操作时。LangGraph 允许您为图中的节点添加个性化的缓存策略。
要配置缓存策略,请将 cachePolicy
参数传递给 addNode
方法。在下面的示例中,我们指定了一个缓存策略,其存活时间 (TTL) 为 120 秒,并使用默认的键序列化函数。然后,要为图启用节点级缓存,请在编译图时设置 cache
参数。下面的示例使用 InMemoryCache
设置了一个带有内存缓存的图。
import { StateGraph, Annotation, START } from "@langchain/langgraph";
import { InMemoryCache } from "@langchain/langgraph-checkpoint";
const StateAnnotation = Annotation.Root({
items: Annotation<string[]>({
default: () => [],
reducer: (acc, item) => [...acc, ...item],
}),
});
const cache = new InMemoryCache();
const graph = new StateGraph(StateAnnotation)
.addNode(
"node",
async () => {
// Simulate an expensive operation
await new Promise((resolve) => setTimeout(resolve, 3000));
return { items: ["Hello, how are you?"] };
},
{ cachePolicy: { ttl: 120 } }
)
.addEdge(START, "node")
.compile({ cache });
由于缓存为空,首次运行将耗时 3 秒。后续使用相同输入的运行将被缓存并立即返回。
console.time("First run");
await graph.invoke({ items: ["Hello!"] });
console.timeEnd("First run");
console.time("Second run");
await graph.invoke({ items: ["Hello!"] });
console.timeEnd("Second run");
cachePolicy
参数传递自定义的键序列化函数。这可用于跳过序列化中的某些字段,例如消息 ID,这些 ID 可能在每次运行时是随机的。
import { StateGraph, MessagesAnnotation, START } from "@langchain/langgraph";
import { InMemoryCache } from "@langchain/langgraph-checkpoint";
import { BaseMessage } from "@langchain/core/messages";
const cache = new InMemoryCache();
const graph = new StateGraph(MessagesAnnotation)
.addNode(
"node",
async () => {
await new Promise((resolve) => setTimeout(resolve, 3000));
return { messages: [{ type: "ai", content: "Hello, how are you?" }] };
},
{
cachePolicy: {
ttl: 120,
keyFunc([{ messages }]: [{ messages: BaseMessage[] }]) {
// Cache based on the content and relative position of the messages
return JSON.stringify(messages.map((m, idx) => [idx, m.content]));
},
},
}
)
.addEdge(START, "node")
.compile({ cache });
// First run will take 3 seconds
console.time("First run");
await graph.invoke({ messages: [{ type: "human", content: "Hello!" }] });
console.timeEnd("First run");
// Second run will be cached and yield immediately
console.time("Second run");
await graph.invoke({ messages: [{ type: "human", content: "Hello!" }] });
console.timeEnd("Second run");