deepseek+本地知识库部署

接入与开发

讲清把 DeepSeek 和本地知识库拼成私有问答服务的工程做法:怎么分块、怎么设超时并发、怎么留日志、怎么在上线前做一轮评测。

你已经选定用 DeepSeek 做生成模型,资料也放在自己机器上,但真正开始拼的时候问题一堆:检索回来的片段太长把上下文挤爆、模型接口偶尔超时整个问答就卡死、多人同时用就撞上并发限制、出了问题翻日志什么都看不出来。这篇不重复讲协议兼容和客户端配置,只给部署落地那一层的做法:分块与拼装、超时与并发、降级与兜底、日志要记什么、上线前怎么小规模评测。

你已经选定用 DeepSeek 做生成模型,资料也放在自己机器上,但真正开始拼的时候问题一堆:检索回来的片段太长把上下文挤爆、模型接口偶尔超时整个问答就卡死、多人同时用就撞上并发限制、出了问题翻日志什么都看不出来。这篇不重复讲协议兼容和客户端配置,只给部署落地那一层的做法:分块与拼装、超时与并发、降级与兜底、日志要记什么、上线前怎么小规模评测。

先说清楚一个前提:私有问答的质量上限不在模型,而在检索。模型再强,喂进去的是错块或者废内容,答案就是编的。所以下面的顺序是先处理资料、再配接口、最后谈评测,别一上来就调提示词。

第一步:把资料变成能检索的块,别急着调模型

资料进库前必须过一遍清洗。同一份文档里的页眉页脚、目录页、重复表格、水印文字,这些如果不删,检索命中的第一段很可能就是它们。扫描件先过 OCR,OCR 质量差的页宁可不入库,也好过入库一堆错字。

  • 先清洗再入库:页眉页脚、目录、重复表格去掉,扫描件先过 OCR,否则检索回来的第一段就可能是废内容
  • 分块按语义切而不是按字数硬切:标题层级、段落、表格各自成块,块之间留一点重叠,块太大就把上下文挤满、块太小就答不全
  • 每块带上来源标记(文件名、章节、页码),后面回答时把出处一起返回,不然用户没法核对
  • 入库前抽十几条真实问题手工试检索,看命中的块对不对;这一步不对,后面换什么模型都救不回来
分块做法好处什么时候别这么干
按标题层级切每块主题明确,引用出处清楚文档没有稳定标题结构时切出来会很碎
按固定字数切实现最简单法规、合同这类跨段含义强的文档容易切断语义
表格单独成块避免表格被拆散后数字对不上表格特别大时还是要按行二次拆
问答对直接入库短问题命中率高原始资料里没有现成问答对时用不上

块的大小没有万能值,但有个判断标准:随便拿几条真实问题去检索,如果命中的块里有一半内容跟问题无关,说明块太大;如果命中的块只讲了半句话,说明块太小。调完再抽一批问题复测,别只看一两条就下结论。

第二步:接口层的超时、并发与排队

超时别只设一个总开关。连接超时管的是网络通不通,单次读取超时管的是模型吐字慢不慢,整条链路的总预算管的是用户等多久会失去耐心。三个分开设、分开计时,出问题才知道是检索慢还是模型慢。

  1. 量基线用站内测速页面量一次本地到模型接口的往返延迟,把中位数和尾部延迟都记下来,再据此定超时值;凭空写一个数字,不是误杀就是等死
  2. 限制并发按自己的账号档位来,别一上来就并发拉满。设一个工作队列,限制同时在跑的请求数,超出的排队等待,而不是直接抛错给用户
  3. 设退避重试只对没产生副作用的读取类请求做重试,退避间隔逐次拉长,重试次数和累计耗时都要有上限,到顶就转降级路径
  4. 验证故意把模型地址指向一个会超时的端点,看链路是按预期走降级,还是整个卡死;这一步能提前暴露大部分兜底逻辑的漏洞

并发数怎么定才合理?先在测试环境压一轮,观察错误率和平均等待时间随并发数的变化曲线,找到错误率开始抬头的那一档,实际部署时压到它之下。具体该按什么档位配,可以到 /tools/speed-test 核对当时的实测数据,别照搬别人的配置。

第三步:坏掉的路径怎么兜底

模型不可用的时候别直接给用户报错。把检索命中的原文片段和出处返回出去,用户自己看也能拿到答案,体验比一个错误页好得多。这个降级路径平时就该写好并测试过,不能等出事再临时加。

  • 模型不可用时降级到「只给检索结果」:返回命中的原文片段和出处,比直接报错有用
  • 回答里区分资料内容和模型推断,前者带出处,后者加提示
  • 长文档问答拆成两跳:先让模型从候选块里挑相关段落,再基于挑出来的内容作答
  • 资料量小、问题范围固定时,别硬套这套链路,直接把资料塞进提示词更省事
兜底不是「出错了怎么办」,而是「出错时用户还能拿到什么」。

第四步:日志记什么,上线前怎么小规模评一遍

日志字段要在写代码的时候就定下来,事后补太痛苦。每次问答至少记:问题原文、召回块的 ID 和分数、最终答案、检索耗时、模型耗时、token 用量、是否走了降级。缺哪一项,对应的那类故障就没法复盘。

失败类型典型表现往哪查
检索没召回对的块答案明显跟资料无关分块策略、embedding 模型、检索条数
召回了但答偏片段里有答案,模型却没用到提示词、上下文拼装顺序、块长度
链路超时用户等到超时也没结果超时设置、并发数、队列积压
降级被触发返回的是原文而不是生成的答案模型接口可用性、重试逻辑

上线前准备一组固定用例,覆盖三类:资料里有答案的、资料里没有的、问法模糊的。每次改分块策略或提示词就跑一遍对比,重点看两类失败——检索没召回对的块,和召回了但答偏。这两类修法完全不同,混在一起调只会越调越乱。

节奏上建议先小范围试用一段时间,收集真实失败样本,再决定要不要放开。私有问答的价值在于可控,出问题能立刻定位,比一上线就全量开放要稳得多。至于模型选型和部署方式的差异,可以到 /sites 对照当时的资料再决定。

下一步把你现在的分块方案和超时配置拿去对照站内的部署参考,先把检索命中率跑通,再谈生成质量。

常见问题

本地知识库一定要用向量数据库吗?

不一定。资料量在几百份以内时,先用关键词或全文检索加上少量人工规则就能跑起来,省掉一整套向量库运维。等资料规模、问题类型明显撑不住了,再换成向量检索或混合检索,迁移成本可控。

DeepSeek 和本地模型能混着用吗?

可以,常见做法是检索和生成走不同后端。但要先确认两边的接口形态是否一致,否则调用层要写两套适配。判断标准和接入方式可以先到站内的兼容接口相关资料对照一遍,再决定要不要混用。

为什么回答总是不带出处?

多半是拼装提示词时没把块的来源一起传进去,或者模型被要求「简洁回答」时把出处丢了。把出处作为必须输出的字段写进格式要求,并在解析层校验,缺了就重试一次,通常就能稳定下来。

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