标准回答
先定位瓶颈
LangChain 应用慢,常见根因有五类:① 同步阻塞——用 .invoke() 串行等待,I/O 期间 CPU 空转;② 多次 LLM 串行调用——一条链里顺序调好几次模型,延迟线性累加;③ 重复 embedding——同样的文本反复向量化,既慢又烧钱;④ 完全无缓存——相同/相似请求每次都重算;⑤ 超长 prompt——塞了过多无关上下文,既增加 token 成本又拖慢推理。先用 LangSmith 把每一步的耗时和 token 量打出来,按数据说话。
异步与并行
把独立的调用并发化是最直接的提速手段。批量请求用 abatch,链内互不依赖的分支用 RunnableParallel 同时跑(如并行检索多源、并行多模型),整体链路改成 async 让 I/O 期间能处理其他请求,吞吐显著提升。
缓存分层
LLM 输出做缓存:完全相同的请求用精确缓存(InMemoryCache / Redis),语义相近的请求用 GPTCache 这类语义缓存命中近似结果;embedding 也加缓存(CacheBackedEmbeddings),同一文档不重复向量化。缓存对高重复流量的降本提速效果最明显。
体感与成本优化
① 流式输出把首字延迟从「等全文」降到「秒出」,体感最直接;② 批处理把多条请求合并,摊薄网络与调度开销;③ 精简 prompt——只放真正相关的上下文、压缩历史、删冗余指令;④ 分级用模型:路由、分类、改写等简单子任务用更小更快的模型,只在最终生成用大模型,省钱又提速。
稳定性与可观测
生产必须加超时防止单次卡死、重试(带指数退避)应对偶发失败、降级兜底(如缓存或备用模型)。全链路接入 LangSmith 做 tracing,持续监控每步延迟、token 消耗与失败率,把优化建立在可观测数据之上而非猜测。
常见误区
⚠️ 常见踩坑
盲目堆缓存却忽视命中率——对话类高变异请求精确缓存几乎不命中,反而要用语义缓存且控制好阈值(太松会返回不相关的旧答案);以为加了 async 就快,结果链里仍有同步阻塞步骤拖累整体;为省钱全程用小模型导致质量崩,或为求质量全程用大模型导致成本失控;不接可观测就凭感觉优化,常优化错地方。
追问
追问 1:语义缓存(如 GPTCache)会带来什么风险,如何控制?
语义缓存按向量相似度命中,风险是「相似但不等价」的问题被错误地返回旧答案,造成事实错误。控制手段:① 调高相似度阈值,宁可不命中也别错命中;② 对时效性强或个性化的请求(带用户上下文、实时数据)直接绕过缓存;③ 给缓存设 TTL 定期失效,并在知识更新时主动清理相关条目;④ 上线前用评测集量化「错误命中率」,在命中率与准确性间找平衡点。
追问 2:一条链里必须多次调用 LLM,如何降低累加延迟?
先看能不能减少调用次数:把多个子任务合并进一次调用(一个 prompt 让模型一并输出多个字段),或用更强模型一步到位替代多步。无法减少时让独立的调用并行(RunnableParallel/abatch),只把真正有依赖的留作串行。还可对中间稳定步骤(如固定的改写、分类)加缓存,并用流式让用户尽早看到最终环节的输出,掩盖前序耗时。
追问 3:如何用 LangSmith 做性能分析并指导优化?
LangSmith 对每次运行生成 trace,逐节点记录开始/结束时间、耗时、输入输出和 token 数。先看瀑布图找最耗时的节点(往往是某次 LLM 调用或检索),判断是延迟问题还是 token 过多问题;再看是否有可并行的串行步骤、是否有重复调用可缓存、prompt 是否过长。结合聚合面板看 P50/P95 延迟、成本与失败率随版本的变化,把每次优化前后做 A/B 对比,确保改动确实有效而非凭感觉。
🔗 相似问题
同一考点的不同问法,面试官可能换着问,一起刷更稳
没找到想看的面试题?把你想看的告诉我们 →
延伸学习
按主题分类的相关资源,便于系统复习