你已经选定用 DeepSeek 做生成模型,资料也放在自己机器上,但真正开始拼的时候问题一堆:检索回来的片段太长把上下文挤爆、模型接口偶尔超时整个问答就卡死、多人同时用就撞上并发限制、出了问题翻日志什么都看不出来。这篇不重复讲协议兼容和客户端配置,只给部署落地那一层的做法:分块与拼装、超时与并发、降级与兜底、日志要记什么、上线前怎么小规模评测。
你已经选定用 DeepSeek 做生成模型,资料也放在自己机器上,但真正开始拼的时候问题一堆:检索回来的片段太长把上下文挤爆、模型接口偶尔超时整个问答就卡死、多人同时用就撞上并发限制、出了问题翻日志什么都看不出来。这篇不重复讲协议兼容和客户端配置,只给部署落地那一层的做法:分块与拼装、超时与并发、降级与兜底、日志要记什么、上线前怎么小规模评测。
先说清楚一个前提:私有问答的质量上限不在模型,而在检索。模型再强,喂进去的是错块或者废内容,答案就是编的。所以下面的顺序是先处理资料、再配接口、最后谈评测,别一上来就调提示词。
第一步:把资料变成能检索的块,别急着调模型
资料进库前必须过一遍清洗。同一份文档里的页眉页脚、目录页、重复表格、水印文字,这些如果不删,检索命中的第一段很可能就是它们。扫描件先过 OCR,OCR 质量差的页宁可不入库,也好过入库一堆错字。
- 先清洗再入库:页眉页脚、目录、重复表格去掉,扫描件先过 OCR,否则检索回来的第一段就可能是废内容
- 分块按语义切而不是按字数硬切:标题层级、段落、表格各自成块,块之间留一点重叠,块太大就把上下文挤满、块太小就答不全
- 每块带上来源标记(文件名、章节、页码),后面回答时把出处一起返回,不然用户没法核对
- 入库前抽十几条真实问题手工试检索,看命中的块对不对;这一步不对,后面换什么模型都救不回来
| 分块做法 | 好处 | 什么时候别这么干 |
|---|---|---|
| 按标题层级切 | 每块主题明确,引用出处清楚 | 文档没有稳定标题结构时切出来会很碎 |
| 按固定字数切 | 实现最简单 | 法规、合同这类跨段含义强的文档容易切断语义 |
| 表格单独成块 | 避免表格被拆散后数字对不上 | 表格特别大时还是要按行二次拆 |
| 问答对直接入库 | 短问题命中率高 | 原始资料里没有现成问答对时用不上 |
块的大小没有万能值,但有个判断标准:随便拿几条真实问题去检索,如果命中的块里有一半内容跟问题无关,说明块太大;如果命中的块只讲了半句话,说明块太小。调完再抽一批问题复测,别只看一两条就下结论。
第二步:接口层的超时、并发与排队
超时别只设一个总开关。连接超时管的是网络通不通,单次读取超时管的是模型吐字慢不慢,整条链路的总预算管的是用户等多久会失去耐心。三个分开设、分开计时,出问题才知道是检索慢还是模型慢。
- 量基线用站内测速页面量一次本地到模型接口的往返延迟,把中位数和尾部延迟都记下来,再据此定超时值;凭空写一个数字,不是误杀就是等死
- 限制并发按自己的账号档位来,别一上来就并发拉满。设一个工作队列,限制同时在跑的请求数,超出的排队等待,而不是直接抛错给用户
- 设退避重试只对没产生副作用的读取类请求做重试,退避间隔逐次拉长,重试次数和累计耗时都要有上限,到顶就转降级路径
- 验证故意把模型地址指向一个会超时的端点,看链路是按预期走降级,还是整个卡死;这一步能提前暴露大部分兜底逻辑的漏洞
并发数怎么定才合理?先在测试环境压一轮,观察错误率和平均等待时间随并发数的变化曲线,找到错误率开始抬头的那一档,实际部署时压到它之下。具体该按什么档位配,可以到 /tools/speed-test 核对当时的实测数据,别照搬别人的配置。
第三步:坏掉的路径怎么兜底
模型不可用的时候别直接给用户报错。把检索命中的原文片段和出处返回出去,用户自己看也能拿到答案,体验比一个错误页好得多。这个降级路径平时就该写好并测试过,不能等出事再临时加。
- 模型不可用时降级到「只给检索结果」:返回命中的原文片段和出处,比直接报错有用
- 回答里区分资料内容和模型推断,前者带出处,后者加提示
- 长文档问答拆成两跳:先让模型从候选块里挑相关段落,再基于挑出来的内容作答
- 资料量小、问题范围固定时,别硬套这套链路,直接把资料塞进提示词更省事
兜底不是「出错了怎么办」,而是「出错时用户还能拿到什么」。
第四步:日志记什么,上线前怎么小规模评一遍
日志字段要在写代码的时候就定下来,事后补太痛苦。每次问答至少记:问题原文、召回块的 ID 和分数、最终答案、检索耗时、模型耗时、token 用量、是否走了降级。缺哪一项,对应的那类故障就没法复盘。
| 失败类型 | 典型表现 | 往哪查 |
|---|---|---|
| 检索没召回对的块 | 答案明显跟资料无关 | 分块策略、embedding 模型、检索条数 |
| 召回了但答偏 | 片段里有答案,模型却没用到 | 提示词、上下文拼装顺序、块长度 |
| 链路超时 | 用户等到超时也没结果 | 超时设置、并发数、队列积压 |
| 降级被触发 | 返回的是原文而不是生成的答案 | 模型接口可用性、重试逻辑 |
上线前准备一组固定用例,覆盖三类:资料里有答案的、资料里没有的、问法模糊的。每次改分块策略或提示词就跑一遍对比,重点看两类失败——检索没召回对的块,和召回了但答偏。这两类修法完全不同,混在一起调只会越调越乱。
节奏上建议先小范围试用一段时间,收集真实失败样本,再决定要不要放开。私有问答的价值在于可控,出问题能立刻定位,比一上线就全量开放要稳得多。至于模型选型和部署方式的差异,可以到 /sites 对照当时的资料再决定。
下一步把你现在的分块方案和超时配置拿去对照站内的部署参考,先把检索命中率跑通,再谈生成质量。→常见问题
本地知识库一定要用向量数据库吗?
不一定。资料量在几百份以内时,先用关键词或全文检索加上少量人工规则就能跑起来,省掉一整套向量库运维。等资料规模、问题类型明显撑不住了,再换成向量检索或混合检索,迁移成本可控。
DeepSeek 和本地模型能混着用吗?
可以,常见做法是检索和生成走不同后端。但要先确认两边的接口形态是否一致,否则调用层要写两套适配。判断标准和接入方式可以先到站内的兼容接口相关资料对照一遍,再决定要不要混用。
为什么回答总是不带出处?
多半是拼装提示词时没把块的来源一起传进去,或者模型被要求「简洁回答」时把出处丢了。把出处作为必须输出的字段写进格式要求,并在解析层校验,缺了就重试一次,通常就能稳定下来。