langchain rag deepseek api

接入与开发

用 LangChain 把 DeepSeek 接口接进检索问答时的工程做法清单:超时重试、并发分批、降级、日志与离线评测怎么落地。

模型接口能调通、向量库也塞好了,但一到真实流量就出问题:检索慢、拼装长、并发一高就报错,答案还时好时坏。这篇不重复讲 RAG 原理和协议兼容,只给一个能照着配的工程清单——链路每个环节该设什么、先查什么、什么情况下这套做法不适用。

模型接口能调通、向量库也塞好了,但一到真实流量就出问题:检索慢、拼装长、并发一高就报错,答案还时好时坏。这篇不重复 RAG 原理,也不讲协议兼容,只给一份能照着配的工程清单——链路每个环节该设什么、先查什么、什么情况下这套做法不适用。

LangChain 在这里的角色是「胶水」:它把文档加载、切分、Embedding、向量库检索、提示组装和 DeepSeek 对话接口串成一条链。胶水层最容易出问题的地方恰恰在超时、并发、降级和可观测这四块,因为它们不在任何单个组件的文档里,只能你自己在链路上定义。

把链路拆成可单独计时的段,再谈超时

别一上来就设一个全局超时。先按「向量化 → 检索 → 重排 → 拼装 → 生成」在 LangChain 的 chain 或自定义 Runnable 里分段埋点,每段单独记耗时。只记一个总耗时,线上出问题时你分不清是向量库慢还是模型侧排队。

链路环节超时口径建议重试要不要加
向量化可用较短固定超时,失败快速放行仅限幂等单条,批量灌库另说
向量库检索本地或自建通常给短超时可以重试,检索是幂等的
重排短超时,超时就跳过可重试一次,失败降级跳过
提示拼装纯内存操作,给宽松值只为兜底不加,避免重复拼装
模型生成按模型侧队列情况放宽只重试单次生成,别和写库混在一起
  • 重试只加在幂等段,检索和单次生成可以重来,拼装、写库、发通知这类有副作用的步骤不要自动重试;
  • 流式返回的超时口径完全不同,首字延迟和后续 chunk 间隔要分开统计,别一个超时值套到底;
  • 超时值别凭感觉定,先到站内 /tools/speed-test 量一遍你自己环境到接口的基线,再往上留余量;
  • 检索层和生成层用两个独立的超时配置对象,方便后续单独调,不要共用一个全局常量。

并发与分批:先定上限,再定节奏

并发问题的根源通常不是模型侧扛不住,而是你把灌库和问答两种负载塞进了同一套并发控制。灌库是短时间高吞吐、允许失败重跑;问答是长尾延迟敏感、要求稳定。两者对并发的要求方向相反。

  1. 先给模型调用层设独立并发上限用信号量或限流器单独控制调 DeepSeek 的那一层,不要和向量库检索共用一个池子,否则向量库连接会先被拖死,表现为检索超时而不是模型报错。
  2. 灌库走批量+断点续跑批量写入时记录已处理文档的偏移或 id,进程中断后能接着跑;每次批量大小固定,不要依赖内存里攒够多少条才提交。
  3. 问答走排队+单请求并发限制用户请求进来先入队,限制同时处理的请求数,超出部分明确返回排队状态。单请求内部的并发(比如一次检索多路召回)也要设上限,不然一个用户就能占满配额。
  4. 限流用指数退避加抖动遇到限流按指数退避,退避上限要有天花板,并加随机抖动,避免大量请求在同一时刻集中重试形成二次冲击。

失败时的降级顺序,别只有一个兜底

只有一个兜底等于没有降级。链路里每一段都可能失败,而且失败原因不同,处理方式必须不同。判断顺序是:先看是模型侧不可用、检索侧没命中,还是拼装后超出上下文长度。

  • 第一级:换更小的模型或更短的提示词,保住能出答案;
  • 第二级:跳过重排,只用向量召回的结果直接拼装,牺牲排序质量换响应;
  • 第三级:返回原始文档片段并明确提示检索失败,把判断权交还给用户;
  • 检索命中为空时不要硬让模型答,明确回「资料里没有」,比编一个答案便宜得多;
  • 降级触发条件必须写进日志,否则线上你分不清是模型变差还是降级长期生效。

降级不是无限的。如果降级频繁触发,说明你的检索质量或分块策略本身有问题,这时该回到离线评测而不是继续加兜底分支。判断标准是:连续一段时间大部分请求都走到第二级以下,就先停掉降级开关,按正常路径复现问题。

日志记什么,拿什么做离线评测

答案时好时坏,八成是因为你只存了最终输出。定位不了是检索没召回到,还是召回对了但模型没用好。每次请求至少留下面这些字段,缺一项都会让排查变猜谜。

记录项为什么必须留
请求 id 与时间戳串联一次请求里所有子步骤的日志
各段耗时区分检索慢还是生成慢
召回条数与得分判断检索是否命中,以及重排有没有起作用
拼装后上下文 token 量判断是否逼近上下文上限导致截断
是否触发降级及级别确认降级有没有在长期生效
模型侧返回状态区分是网络问题还是接口侧拒绝

离线评测要固定一批问题和期望命中的资料条目,改分块、改重排、改提示词后都跑同一批,对比命中率和答案是否引用到正确片段。模型或接口换代后先跑评测再上量,接口侧的规格和限制到站内 /models 和 /official-api/providers/deepseek 核对当时的数字。

下一步把上面这份清单照着配一遍,再去加速测试页量一下你自己环境的基线,用真实数字替换掉超时和并发里的凭感觉值。

常见问题

检索能跑,但整体响应很慢,先查哪一段?

先分段计时,不要凭感觉。多数情况是生成段排队或拼装上下文过长导致,把召回条数砍一半、把长文档截断,再看耗时变化。如果只有首字慢、后续正常,那是流式的问题,不是检索的问题。

并发一上来就报错,是接口限制还是我的代码问题?

先看报错码:限流类通常是模型侧额度问题,连接类错误更像是本地并发没做上限。做法是给模型调用层单独设并发上限并加退避,具体额度口径到 /official-api/providers/deepseek 核对当时的限制说明,别硬扛。

怎么判断问答变差是检索的锅还是模型的锅?

把召回片段单独打印出来看:片段里本来就没有答案,那是分块和检索的问题;片段里有答案但模型答偏,那是提示词和拼装的问题。两种的修法完全不同,先把这一步做掉再谈调参。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。