1. 从一张白纸开始的DeepSeek学习路线
很多人第一次接触DeepSeek大模型,脑子里冒出来的第一个问题不是"这玩意儿怎么用",而是"我该从哪儿下手"。我特别理解这种感觉——打开官方文档,满屏的API参数、模型版本号、Token计费规则,看两眼就犯困。更别说后面还有Dify工作流、知识库流水线、OCR识别、私有化部署这一大串东西等着你。我当初也是这么过来的,踩了不少坑,也走了不少弯路,所以这篇笔记想做的事情很简单:把DeepSeek大模型从"听说过"到"用起来"再到"用得好"这条路上真正关键的东西,按我自己的理解重新梳理一遍。
先说清楚这篇笔记适合谁看。如果你是完全没碰过大模型API的小白,那前面几章会帮你把基础概念和调用方式理清楚;如果你已经在用DeepSeek做开发,但总觉得效果不稳定、上下文老超长、知识库检索不准,那中间关于Dify工作流和RAG的部分应该能帮到你;如果你正在考虑企业私有化部署,后面关于部署方案和成本估算的内容也值得翻一翻。整篇笔记不会堆砌官方文档里已有的内容,而是重点讲那些文档里不会写、但实际用起来一定会遇到的问题。
DeepSeek这个模型系列,从最早的DeepSeek LLM到后来的DeepSeek-V2、V3,再到推理能力更强的R1系列,迭代速度非常快。它的核心优势在于中文理解能力强、API价格便宜、开源版本可私有化部署。但便宜不等于好用,开源不等于开箱即用。我见过太多人兴冲冲地申请了API Key,写了个"Hello World"式的调用,然后发现输出质量忽高忽低,就开始怀疑是不是模型不行。其实大部分时候问题出在提示词设计、上下文管理、参数配置这些工程细节上,跟模型本身的能力关系不大。
接下来的内容我会按照"基础调用→提示词工程→Dify工作流集成→知识库与OCR→私有化部署→常见故障排查"这条主线展开,每一块都会给出可以直接复现的代码或配置,同时解释清楚为什么这么做。我不喜欢只给结论不给推导过程的写法,因为那样你换个场景就不会用了。好了,废话不多说,直接进入正题。
2. DeepSeek API调用的核心参数与隐藏细节
2.1 申请Key之后第一件事:搞清楚模型版本差异
很多人拿到API Key之后直接复制官方示例代码就跑,结果发现输出效果跟别人说的不一样。问题往往出在模型版本选择上。DeepSeek目前主要提供几个不同的模型标识,每个标识对应的能力、价格、上下文长度都不一样。deepseek-chat指向的是通用对话模型,适合日常问答、文本生成、摘要提取这类任务;deepseek-reasoner指向的是推理增强模型,适合数学推理、代码生成、复杂逻辑分析这类需要"想一步再回答"的场景。
这两个模型最直观的区别在于:deepseek-reasoner在输出最终答案之前会先输出一段思维链内容,这段内容会消耗额外的Token。如果你用推理模型去做简单的文本分类任务,那就是杀鸡用牛刀,不仅浪费钱,响应速度还慢。反过来,如果你用通用对话模型去做复杂的数学证明,它很可能给你一个看起来像模像样但实际上是错的答案。
我自己的经验是:日常80%的任务用deepseek-chat就够了,只有遇到需要多步推理的场景才切换到deepseek-reasoner。而且切换的时候要注意,推理模型的提示词写法跟通用模型不太一样,它更适合"直接给问题"而不是"给一堆示例让它模仿"。
2.2 温度、Top-P、最大长度:三个最容易被忽视的参数
官方文档里对这几个参数都有说明,但很多人看完就忘了,直接用默认值。默认值不是不能用,而是它针对的是"通用场景",你的具体场景很可能需要调整。
温度(temperature)控制输出的随机性。值越低(接近0),输出越确定、越保守;值越高(接近2),输出越发散、越有创意。做数据提取、格式转换这类任务时,我一般把温度设成0.1甚至0,保证每次输出格式一致。做文案生成、头脑风暴时,会调到0.8到1.2之间。这里有个坑:温度设成0并不代表完全确定性输出,因为底层还有并行计算带来的浮点误差,只是说波动范围会小很多。
Top-P(核采样)是另一种控制输出多样性的方式。它跟温度的区别在于,温度是调整概率分布的平滑程度,Top-P是直接截断概率分布,只保留累积概率达到P的那些Token。实践中我一般只调其中一个,不同时调两个,否则效果很难预测。如果非要同时调,建议温度设低一点、Top-P设高一点,或者反过来。
最大长度(max_tokens)这个参数特别重要,但特别容易被忽略。它限制的是模型单次输出的最大Token数,不是输入加输出的总长度。如果你不设置,模型可能会在回答到一半的时候突然截断,尤其是让它写长文的时候。我的习惯是根据任务类型预设一个合理值:短问答设256,中等长度回答设1024,长文生成设4096。设太小会导致回答不完整,设太大又浪费额度,因为很多API是按实际输出Token计费的。
2.3 流式输出与超时处理:生产环境必须考虑的事
开发阶段用非流式调用没问题,等个几秒钟拿到完整结果就行。但到了生产环境,尤其是做对话类应用的时候,非流式调用的体验非常差——用户问一个问题,界面转圈转五六秒才出结果,很多人等三秒就关掉了。
流式输出(streaming)的原理是让模型每生成一个Token就立刻返回,前端可以逐字显示。DeepSeek的API支持SSE(Server-Sent Events)方式的流式输出,用Python的requests库或者openai库都能实现。这里要注意的是,流式模式下错误处理会更复杂,因为连接可能在传输过程中断开,你需要做好重试和断点续传的逻辑。
超时设置也是必须的。DeepSeek官方API的响应时间受负载影响,高峰期偶尔会出现十几秒才返回第一个Token的情况。我一般把连接超时设成10秒,读取超时设成60秒。如果超过这个时间还没响应,就触发重试。重试策略建议用指数退避,第一次等1秒,第二次等2秒,第三次等4秒,最多重试三次。不要用固定间隔重试,那样在服务端压力大的时候会加剧拥堵。
import openai import time client = openai.OpenAI( api_key="your-api-key", base_url="https://api.deepseek.com" ) def call_with_retry(messages, model="deepseek-chat", max_retries=3): for attempt in range(max_retries): try: response = client.chat.completions.create( model=model, messages=messages, temperature=0.3, max_tokens=2048, stream=False, timeout=60 ) return response.choices[0].message.content except Exception as e: if attempt == max_retries - 1: raise e wait = 2 ** attempt time.sleep(wait)上面这段代码是我自己在用的重试封装,核心逻辑就是指数退避加最大重试次数限制。注意timeout参数在openai库的不同版本里位置可能不一样,有的版本是放在create方法里,有的版本是初始化客户端时设置,用之前最好确认一下版本。
3. 提示词工程:让DeepSeek输出稳定结果的实战方法
3.1 系统提示词不是越长越好
我见过不少人在系统提示词里写上千字,把能想到的规则全塞进去,结果模型反而抓不住重点。DeepSeek的上下文窗口虽然大,但注意力机制对长文本的处理是有衰减的——放在中间位置的指令,被遵循的概率明显低于开头和结尾。
我的做法是把系统提示词控制在300字以内,只放最核心的角色定义、输出格式要求、禁止事项。具体的任务指令放在用户消息里,因为用户消息离模型生成的位置更近,遵循度更高。如果确实有很多规则要写,我会用结构化格式,比如用编号列表而不是大段段落,这样模型更容易逐条对应。
还有一个技巧:把最重要的规则放在系统提示词的最后一句。因为模型生成时对最近的内容注意力权重更高,最后一句往往是最容易被记住的。
3.2 少样本示例的正确用法
少样本(few-shot)示例是提升输出稳定性的利器,但很多人用错了。最常见的错误是给了一堆示例,但示例之间的格式不一致,或者示例跟实际任务有偏差。模型会从示例中学习模式,如果示例本身就有问题,输出自然好不到哪去。
我的经验是:示例数量控制在2到5个之间,每个示例的格式必须完全一致,包括标点符号、换行方式、字段顺序。如果任务是分类,示例要覆盖所有类别;如果任务是提取,示例要覆盖所有字段。另外,示例的顺序也有讲究——把最典型的示例放在最后,因为模型对最后一个示例的印象最深。
举个例子,如果你要让DeepSeek从合同文本里提取甲方、乙方、金额、签订日期这四个字段,示例应该长这样:
输入:甲方:某某科技有限公司,乙方:张三,合同金额:人民币伍万元整,签订于2024年3月15日。 输出:{"甲方": "某某科技有限公司", "乙方": "张三", "金额": "50000", "日期": "2024-03-15"} 输入:本合同由甲方李四与乙方王五于2024年1月1日签订,涉及金额100000元。 输出:{"甲方": "李四", "乙方": "王五", "金额": "100000", "日期": "2024-01-01"}注意第二个示例里字段顺序跟第一个不一样,但输出格式完全一致。这样模型学到的是"不管输入怎么变,输出都按这个JSON格式来",而不是死记硬背输入输出的对应关系。
3.3 思维链提示在DeepSeek上的特殊表现
思维链(Chain of Thought)提示在DeepSeek的推理模型上效果很好,但在通用对话模型上要慎用。原因是通用模型没有专门的推理训练,你让它"一步一步想",它可能会编造出看似合理但实际错误的推理步骤,最后得出一个错误答案,而且因为有了推理过程,你反而更难发现错误。
在deepseek-reasoner上,思维链是内置的,你不需要在提示词里写"让我们一步一步思考",它自己就会这么做。你要做的是把问题描述清楚,给它足够的上下文信息,然后等它输出。如果它的推理过程跑偏了,可以在后续对话中纠正,但不要试图在第一次调用时就通过提示词控制它的推理路径,那样反而会干扰它。
在deepseek-chat上,如果任务确实需要多步推理,我建议用"分步提问"的方式:先让它输出第一步的结果,确认无误后再把第一步结果作为输入,问第二步。这样虽然多了一次API调用,但准确率比一次性让它推理要高得多。
4. Dify工作流集成:从单次调用到自动化流水线
4.1 Dify解决了什么问题
直接用API调用DeepSeek,适合做单次任务。但如果你要做一个完整的应用,比如智能客服、文档问答、内容审核,就需要把多个步骤串起来:先做意图识别,再检索知识库,然后生成回答,最后做敏感词过滤。这些步骤如果全写在代码里,维护起来非常痛苦,改一个环节就要重新部署。
Dify这类LLM应用开发平台的核心价值就是把"提示词编排"和"流程控制"可视化。你可以在界面上拖拽节点,把DeepSeek的调用、条件判断、变量聚合、知识库检索这些操作连成一条流水线。改流程不需要改代码,改完立刻生效。
但Dify不是银弹。我见过很多人把Dify当成万能工具,什么逻辑都往工作流里塞,结果工作流复杂到连自己都看不懂。我的建议是:简单的线性流程用Dify没问题,但如果涉及复杂的循环、递归、动态分支,还是老老实实写代码更靠谱。Dify适合做"80%的常规流程",剩下20%的特殊逻辑用代码节点补充。
4.2 工作流中上下文超长的处理策略
"Dify工作流 上下文超长"是一个被频繁搜索的问题,说明很多人遇到了。上下文超长的原因通常有两个:一是知识库检索返回的文档片段太多,二是多轮对话的历史消息没有做截断。
对于知识库检索,Dify默认会返回Top-K个片段,K值设大了就会导致上下文膨胀。我的做法是把K值控制在3到5之间,同时开启重排序(Rerank)功能,让最相关的片段排在前面。如果还是超长,就在检索节点后面加一个"文本截断"节点,限制每个片段的字符数。
对于多轮对话,Dify有"对话历史"变量,默认会带上最近几轮的消息。如果对话轮次多了,历史消息会占用大量Token。我一般设置只保留最近3轮对话,更早的历史要么丢弃,要么用摘要的方式压缩成一句话。摘要可以用DeepSeek自己来做:把前几轮对话丢给模型,让它生成一段50字以内的摘要,然后把摘要作为上下文传下去。
4.3 变量聚合器的实际使用场景
Dify的变量聚合器(Variable Aggregator)是一个很容易被忽视但非常有用的节点。它的作用是把多个分支的输出合并成一个变量,供后续节点使用。
举个实际例子:我做了一个合同审核工作流,先判断合同类型是"采购合同"还是"销售合同",然后走不同的提取分支。采购合同提取"供应商、采购金额、交货日期",销售合同提取"客户、销售金额、收款日期"。两个分支的输出字段名不一样,但后续的审核节点需要统一的输入格式。这时候就用变量聚合器,把两个分支的输出映射到统一的字段上,后续节点就不用关心前面走的是哪个分支了。
使用变量聚合器时要注意:每个分支的输出类型必须一致,不能一个分支输出字符串、另一个分支输出对象。如果类型不一致,聚合器会报错。另外,聚合器的默认值要设置好,防止某个分支没有执行时后续节点拿到空值。
4.4 Dify SSL错误与凭证校验失败的排查
"Dify SSL错误"和"Dify an error occurred during credentials validation"这两个报错我都遇到过,原因不太一样,分开说。
SSL错误通常出现在Dify连接外部服务的时候,比如连接DeepSeek API、连接向量数据库、连接OCR服务。最常见的原因是Dify部署环境的CA证书不全,或者系统时间不对导致证书校验失败。排查步骤是:先在Dify容器里用curl命令测试目标地址能不能通,如果curl也报SSL错误,那就是环境问题;如果curl正常但Dify报错,那就是Dify的HTTP客户端配置问题。解决办法通常是更新CA证书包,或者在Dify的环境变量里加上跳过SSL校验的配置(仅限内网环境使用,公网环境不要这么做)。
凭证校验失败通常出现在配置模型供应商的时候。Dify需要你填入API Key和Base URL,然后它会发一个测试请求验证凭证是否有效。如果报这个错,先检查API Key有没有多余的空格,再检查Base URL是不是完整的(要包含https://和结尾的/v1)。还有一个容易被忽略的点:某些网络环境下Dify容器无法直接访问外网,需要在Dify的配置里设置代理,但代理配置的格式要对,否则也会导致校验失败。
5. 知识库与OCR:让DeepSeek读懂你的文档
5.1 知识库流水线的分段策略
Dify的知识库功能本质上是一个RAG(检索增强生成)系统。文档上传后会被切分成片段,然后向量化存储,检索时根据相似度返回最相关的片段。分段策略直接决定了检索质量,但很多人直接用默认设置,结果检索出来的内容驴唇不对马嘴。
我的分段经验是这样的:技术文档按标题层级切分,每个二级标题下的内容作为一个片段,这样能保证语义完整性;合同类文档按条款切分,每条作为一个片段;FAQ类文档按问答对切分,一问一答作为一个片段。片段长度控制在300到500字之间,太短了语义不完整,太长了检索精度下降。
重叠长度也很关键。默认的重叠是50字,对于技术文档来说太少了,因为技术概念往往跨段落出现。我一般设成100到150字的重叠,保证片段之间的衔接处不会丢失信息。但重叠也不能太大,否则会导致检索结果重复,浪费上下文窗口。
5.2 OCR识别在知识库中的应用
很多企业的文档是扫描件或者图片格式的PDF,直接上传到知识库是没法检索的,需要先做OCR识别。OCR这块我踩过的坑比较多,展开说说。
第一个坑是OCR引擎的选择。免费的开源OCR(比如Tesseract)对中文的识别率勉强能用,但对表格、公式、手写体的识别率很低。百度的OCR API识别率高,但按调用次数收费,量大了一笔不小的开销。PaddleOCR是折中方案,识别率不错,可以本地部署,但部署环境比较重,对GPU有要求。
第二个坑是OCR后的文本清洗。OCR识别出来的文本往往带有大量噪声:多余的空格、错误的换行、识别错的字符。如果直接拿去做向量化,检索效果会很差。我一般会做几步清洗:去掉连续空格、合并被错误换行的段落、用规则修正常见错别字(比如"0"和"O"混淆、"1"和"l"混淆)。
第三个坑是版面分析。合同、报表这类文档有复杂的版面结构,简单的OCR会把所有文字按阅读顺序输出,丢失表格的行列关系。对于表格,需要用专门的表格识别工具,或者用OCR返回的坐标信息重建表格结构。这块如果做不好,提取出来的数据基本没法用。
from paddlex import create_pipeline pipeline = create_pipeline("OCR") result = pipeline.predict("contract.pdf") for res in result: # 获取识别文本 texts = res["rec_texts"] # 获取文本坐标 boxes = res["rec_boxes"] # 按纵坐标排序,重建阅读顺序 sorted_items = sorted(zip(boxes, texts), key=lambda x: (x[0][1], x[0][0])) for box, text in sorted_items: print(text)上面这段代码演示了用PaddleOCR做基础识别并按坐标排序的基本思路。实际使用中还要处理表格重建、多栏排版等问题,代码会复杂很多。如果识别不了韩文,大概率是模型没有加载对应的语言包,需要下载韩文识别模型。
5.3 检索增强生成的调优技巧
知识库建好之后,检索效果不理想是常态。我总结了几条调优经验:
第一,查询改写。用户的问题往往很口语化,直接拿去做向量检索效果不好。可以先用DeepSeek把用户问题改写成更适合检索的形式。比如用户问"这个合同啥时候到期",改写成"合同到期日期 终止日期 有效期",检索命中率会高很多。
第二,混合检索。纯向量检索对语义相似但用词不同的情况效果好,但对精确匹配(比如合同编号、人名)效果差。Dify支持向量检索和关键词检索的混合模式,我一般把权重设成向量0.7、关键词0.3,兼顾语义和精确匹配。
第三,重排序。检索返回的Top-K片段顺序不一定准确,用重排序模型重新打分可以显著提升精度。Dify内置了重排序功能,开启后检索质量提升很明显,代价是多一次模型调用,响应时间会增加几百毫秒。
第四,引用溯源。让DeepSeek在回答时标注引用了哪个片段,这样用户可以看到答案的依据,也方便你排查检索错误。Dify的知识库节点支持返回引用信息,在提示词里要求模型标注来源即可。
6. 私有化部署:成本、硬件与踩坑记录
6.1 什么情况下需要私有化部署
私有化部署DeepSeek的动机通常有三个:数据不能出内网、API调用量太大想省成本、需要定制化微调。但私有化部署不是没有代价的,硬件成本、运维成本、模型更新成本都要考虑。
我帮几个团队做过私有化部署的方案评估,结论是:如果日均Token消耗在100万以内,用官方API更划算;如果超过500万,且对数据安全有硬性要求,才值得考虑私有化。中间这个区间要看具体情况,比如是否有突发流量、是否能接受API偶尔的不稳定。
硬件方面,DeepSeek-V2的推理至少需要一张24G显存的显卡(比如4090),量化后可以跑在更低的配置上,但输出质量会下降。如果要跑满血版或者做微调,需要多卡A100/H100级别的配置,成本就上去了。我的建议是先用量化版本验证效果,确认能满足业务需求再考虑上满血版。
6.2 部署方案选型:vLLM vs Ollama vs 其他
部署DeepSeek的推理服务,常见的选择有vLLM、Ollama、TGI等。我实际用过的组合是vLLM加OpenAI兼容接口,原因是vLLM的吞吐量高、支持连续批处理、社区活跃。
Ollama的优势是安装简单,一条命令就能跑起来,适合个人开发者做实验。但它的并发能力弱,多人同时调用时响应会明显变慢。如果只是自己用或者小团队内部用,Ollama够用了;如果要对外提供服务,还是上vLLM。
部署时最容易踩的坑是显存分配。模型权重、KV Cache、中间激活值都要占显存,如果只按模型大小来估算显存,跑起来一定会OOM。我的经验是:模型权重占用的显存乘以1.5到2倍,才是实际需要的显存量。比如一个14G的模型,实际部署需要准备24G到28G的显存。
另一个坑是模型格式。DeepSeek官方发布的权重是safetensors格式,vLLM可以直接加载。但如果你下载的是别人转换过的GGUF格式,vLLM是不支持的,需要用llama.cpp或者Ollama来跑。下载模型之前一定要确认格式跟推理框架匹配。
6.3 私有化部署后的性能监控
部署完不是就没事了,性能监控必须做。我一般关注这几个指标:首Token延迟(TTFT)、每秒输出Token数(TPOT)、并发请求数、显存占用率、GPU利用率。
首Token延迟反映的是用户等待时间,超过2秒体验就明显下降。如果TTFT变长,可能是KV Cache满了,需要调整max_model_len参数或者增加显存。每秒输出Token数反映的是生成速度,低于20 tokens/s用户会觉得卡顿。并发请求数上不去,通常是批处理大小设得太保守,可以适当调大max_num_seqs参数。
监控工具我用的是Prometheus加Grafana,vLLM自带Prometheus指标接口,配置一下就能采集。如果没有监控系统,至少也要写个定时脚本,每隔几分钟记录一次关键指标,出问题的时候有数据可查。
7. 那些文档里不会写的故障排查经验
7.1 "LLM request failed: provider rejected the request schema or tool payload"
这个报错我遇到过好几次,每次原因都不一样。第一次是因为消息列表里混入了空消息,DeepSeek的API不接受content为空字符串的消息。第二次是因为tools参数格式不对,函数调用的JSON Schema写错了字段类型。第三次是因为消息角色顺序不对,assistant消息后面直接跟了system消息。
排查这类问题的通用方法是:把请求体完整打印出来,逐字段对照官方文档检查。特别注意messages数组里每个对象的role和content字段,role只能是system、user、assistant、tool这几种,content不能为null(除非是带tool_calls的assistant消息)。
还有一个隐蔽的坑:如果你用了OpenAI的SDK来调用DeepSeek,SDK会自动添加一些DeepSeek不支持的字段,比如logprobs、top_logprobs。这些字段在OpenAI API里是合法的,但DeepSeek可能不支持,导致请求被拒绝。解决办法是显式设置这些字段为None,或者直接用requests库发原始HTTP请求。
7.2 输出被截断的几种可能原因
输出被截断是最让人头疼的问题之一,因为你不知道是模型的问题还是配置的问题。我总结了几种常见原因:
第一种,max_tokens设得太小。这个最直接,调大就行。但要注意,max_tokens是输出限制,不是输入加输出的总限制,别跟上下文窗口搞混了。
第二种,触发了内容过滤。DeepSeek有内容安全机制,如果检测到输出内容涉及敏感信息,会在中途截断。这种情况通常会在返回结果里看到finish_reason是content_filter而不是stop。
第三种,流式传输中断。流式模式下网络波动会导致连接断开,前端收到的内容不完整。解决办法是在前端做拼接,检测到finish_reason为stop才认为输出完整,否则提示用户重试。
第四种,上下文窗口满了。如果输入本身就很长,留给输出的空间就不多了。DeepSeek的上下文窗口是64K Token,输入占了60K,输出最多只能有4K。这种情况需要精简输入,或者用摘要的方式压缩历史对话。
7.3 模型"胡说八道"的抑制方法
大模型的幻觉问题没法完全消除,但可以抑制。我的做法有这么几个:
第一,在系统提示词里明确要求"如果不知道就说不知道,不要编造"。这句话看起来简单,但确实能减少一部分幻觉。
第二,提供参考资料。如果是知识库问答,把检索到的片段放在提示词里,要求模型"仅根据以下资料回答"。这样模型有了依据,编造的概率会降低。
第三,要求模型标注来源。让模型在回答时引用具体的资料片段编号,这样你可以验证它的回答是否有依据。如果它引用了不存在的编号,说明它在编造。
第四,降低温度。温度越低,模型越倾向于选择概率最高的Token,而概率最高的Token往往是训练数据中出现频率最高的,也就是更"保守"的回答。做事实性问答时,温度设成0.1以下。
第五,后置校验。对于关键信息(比如金额、日期、人名),用规则或者另一个模型调用做二次校验。比如提取出来的金额,用正则表达式验证格式是否正确;提取出来的日期,验证是否在合理范围内。
8. 我个人的一些使用体会
写了这么多,最后分享几个我在实际使用中总结的小经验,不一定对所有人都适用,但至少在我自己的场景里验证过有效。
关于模型选择,我现在基本固定用deepseek-chat处理日常任务,只有遇到需要多步推理的复杂问题才切到deepseek-reasoner。切换的时候会把之前的对话历史清空,因为两个模型的提示词风格不一样,混在一起容易让模型困惑。
关于提示词,我习惯把常用的提示词模板存成文件,用的时候直接读取。这样一方面避免每次手写出错,另一方面方便版本管理,改了哪个版本效果变好或变差都有记录可查。
关于Dify工作流,我的原则是"能简单就不复杂"。一个工作流如果超过10个节点,我就会考虑拆成多个子工作流,或者把一部分逻辑挪到代码里。工作流太复杂的时候,调试成本会指数级上升。
关于知识库,我定期会做检索质量评估。方法是准备一批测试问题,人工标注正确答案,然后跑一遍检索,看Top-3的命中率。如果命中率低于80%,就需要调整分段策略或者检索参数。这个评估我一般一个月做一次,因为文档更新后检索效果会变化。
关于私有化部署,我的建议是先用API验证业务逻辑,确认可行之后再考虑部署。很多人一上来就折腾部署,结果发现业务逻辑本身就有问题,白白浪费了硬件和运维成本。API调用虽然单价看起来高,但省下来的时间和精力更值钱。
还有一个关于OCR的经验:如果文档质量差(扫描歪斜、字迹模糊、背景噪声大),再好的OCR引擎识别率也上不去。这种情况下,与其在OCR上调参数,不如先做图像预处理——去噪、纠偏、二值化,把图像质量提上去,OCR的识别率自然就高了。这个思路跟做数据清洗是一样的:垃圾进,垃圾出,先把原料处理好,后面的环节才有效率。