个人主页 for_ever_love__ 欢迎各位大佬莅临其他栏目: 大模型开发从0到1 其他栏目: iOS项目总结大全 其他栏目: 我想学python了 其他栏目: iOS UI 文章目录LangChain 缓存同样的请求别反复花钱一、两种缓存二、精确缓存四种后端2.1 怎么选2.2 Redis 缓存要装依赖三、缓存的边界什么会被缓存四、语义缓存意思相近就命中4.1 score_threshold 怎么定4.2 语义缓存的风险五、哪些请求不该缓存六、手动管理缓存6.1 清空6.2 查看是否命中6.3 缓存过期七、缓存之外的省钱招八、开发期的小技巧九、常见坑十、小结LangChain 缓存同样的请求别反复花钱开发时反复调试同一条 prompt每次都真调 API——一天下来账单不难看才怪。缓存是成本优化里投入产出比最高的一招几行代码可能省掉 30%~60% 的调用。一、两种缓存类型原理省钱适合精确缓存prompt 完全一样才命中中调试、重复问题语义缓存意思相近就命中高客服 FAQ、相似提问先上精确缓存简单可靠有余力再上语义缓存。二、精确缓存四种后端fromlangchain_core.cachesimportInMemoryCachefromlangchain_community.cacheimportSQLiteCache,RedisCachefromlangchain_core.globalsimportset_llm_cache# 1. 内存进程内重启即丢set_llm_cache(InMemoryCache())# 2. SQLite单机持久化set_llm_cache(SQLiteCache(database_path.langchain.db))# 3. Redis分布式生产首选set_llm_cache(RedisCache(redis_urlredis://localhost:6379))设完之后什么都不用改所有 LLM 调用自动走缓存llm.invoke(你好)# 真调用耗时 2sllm.invoke(你好)# 命中缓存瞬间返回2.1 怎么选场景选哪个本地开发调试SQLiteCache重启还在省事单机服务SQLiteCache多实例 / 生产RedisCache共享缓存临时脚本InMemoryCache多实例部署一定要用 Redis否则每个实例各缓存一份命中率被实例数摊薄。2.2 Redis 缓存要装依赖pipinstallredisfromlangchain_community.cacheimportRedisCachefromlangchain_core.globalsimportset_llm_cacheimportredis set_llm_cache(RedisCache(redis_redis.Redis(hostlocalhost,port6379,db0)))三、缓存的边界什么会被缓存缓存 key 模型 完整 prompt 参数temperature 等。所以llm.invoke(今天天气如何)# 调用 Allm.invoke(今天天气如何 )# 多了个空格 → 不命中llm.invoke(今天天气如何)# 多了个问号 → 不命中llm2ChatOpenAI(temperature0.7)llm2.invoke(今天天气如何)# temperature 不同 → 不命中这就是精确缓存命中率不高的原因——用户的提问千变万化完全一样的很少。四、语义缓存意思相近就命中pipinstallfaiss-cpufromlangchain_community.cacheimportRedisSemanticCachefromlangchain_openaiimportOpenAIEmbeddingsimportredis set_llm_cache(RedisSemanticCache(redis_urlredis://localhost:6379,embeddingOpenAIEmbeddings(modeltext-embedding-3-small),score_threshold0.2,# 距离阈值越小越严格))原理1. 把新请求 embedding 成向量 2. 在缓存里找最相似的已有请求 3. 距离 阈值 → 命中直接返回旧答案 4. 否则真调用并把 (请求, 答案) 存进缓存4.1 score_threshold 怎么定这是语义缓存唯一的、也是最重要的参数。阈值行为风险0.1很严格几乎要一模一样命中率低省钱少0.2推荐起点平衡0.3很宽松会串答案“退款多久到账命中退款流程是什么”务必用你的真实问题测一批再定。拿 20 个问题试试看有没有明显答非所问的误命中。4.2 语义缓存的风险它会让不同的问题返回同一个答案。这在以下场景是灾难需要精确数字的场景“北京多少度” vs “上海多少度”需要时效性的场景“今天汇率”个性化场景不同用户同一问题应有不同答案。安全做法只给确定性的知识问答开语义缓存FAQ、产品介绍个性化和实时类请求直接跳过。fromlangchain_core.globalsimportget_llm_cachedefanswer(question:str,user_id:str,use_semantic_cache:bool):llmChatOpenAI(modelgpt-4o-mini,cacheuse_semantic_cache)returnllm.invoke(question)注意cache是模型级参数可以给某些实例关掉。五、哪些请求不该缓存llm_no_cacheChatOpenAI(modelgpt-4o-mini,cacheFalse)这几类要关掉场景原因含时间戳/随机数的 prompt每次都不一样缓存白占空间实时数据查询答案会变创意生成每次要不同命中缓存就失去多样性了需要 tracing 的调试命中缓存拿不到真实调用六、手动管理缓存6.1 清空fromlangchain_core.globalsimportget_llm_cache get_llm_cache().clear()6.2 查看是否命中importtime t0time.time()llm.invoke(一个很长的问题……)elapsedtime.time()-t0print(命中缓存ifelapsed0.1else真实调用)更可靠的方式是看 callbackfromlangchain_core.callbacksimportBaseCallbackHandlerclassCacheWatcher(BaseCallbackHandler):defon_llm_start(self,serialized,prompts,**kwargs):print(真实调用:,prompts[0][:50])llm.invoke(...,config{callbacks:[CacheWatcher()]})命中缓存时on_llm_start不会触发——这就是判断依据。6.3 缓存过期Redis 缓存可以设置 TTLRedisCache(redis_redis_client,ttl3600)# 1 小时过期生产建议设 TTL否则缓存无限增长Redis 内存会爆。七、缓存之外的省钱招缓存只是其中一招按性价比排序招数省多少难度缓存30%~60%⭐便宜模型处理简单任务50%⭐⭐缩短 prompt去掉废话10%~30%⭐限制max_tokens10%~20%⭐批量请求batch API50%部分供应商支持⭐⭐蒸馏/微调小模型80%⭐⭐⭐⭐先做缓存和限制 max_tokens这两个是零风险的。八、开发期的小技巧调试时不想每次真调又不想开缓存怕拿到旧答案可以用Fake LLM后面测试那篇会细讲fromlangchain_community.llms.fakeimportFakeListLLM llmFakeListLLM(responses[答案1,答案2])但要验证真实效果时记得关掉它——我见过调试完忘记换回来上线后所有请求返回固定字符串的事故。九、常见坑现象原因解法设了缓存没生效在set_llm_cache之前就创建了 llm先设缓存再建模型或全局设置后再 import多实例命中率低用了 SQLite/内存换 Redis答案串了语义缓存阈值太松降到 0.15或只给 FAQ 用Redis 内存涨没设 TTL加ttl改了 prompt 还拿旧答案缓存命中清缓存或开发期关掉每次都不同的输出变成一样了创意任务开了缓存cacheFalse十、小结精确缓存三选一SQLite单机/开发、Redis生产/多实例、InMemory临时缓存 key 包含模型 完整 prompt 参数一个空格不同就不命中语义缓存命中率高但有串答案风险score_threshold从0.2起步必须用真实问题测一批实时、个性化、创意类请求要关缓存cacheFalseRedis 缓存必须设 TTL否则内存无限涨判断命中的方法命中时on_llm_start不触发。下一篇讲 Token 计数与成本控制——知道钱花在哪。