news 2026/10/18 17:13:22

vLLM + DeepSeek + Milvus 本地知识库问答实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
vLLM + DeepSeek + Milvus 本地知识库问答实战

前阵子我接到一个挺实际的需求:公司内部的一堆制度文档、项目总结和操作手册散落在共享盘里,大家想做一个能"问人话"的检索入口,而不是继续在几十个目录里翻文件。一开始的方案是接在线大模型的服务做 RAG,结果数据安全负责人一口否决:核心资料不允许离开内网。于是我把方案改成了纯本地链路——用 vLLM 部署 DeepSeek 开源模型,配合 Milvus 构建本地向量库,文档切片后向量化入库,检索时先语义召回再让模型生成答案。从搭环境到跑通完整问答,加起来大概一周,现在这套东西已经稳定跑在我们自己的服务器上。如果你也打算做私有化知识库、给内部系统加语义检索,或者单纯想研究 vLLM、DeepSeek、Milvus 这套组合怎么落地,这篇文章应该能帮你把大部分坑提前趟平。我会按"为什么这么选型"、"环境与部署"、"入库与检索"、"调优与排错"四个方向来讲,代码全部可复现。

1. 为什么是"本地向量库":需求边界与组件分工

1.1 本地化解决的三个现实问题

做本地向量库最直接的理由不是"技术更炫",而是"数据不能出去"。企业内部的知识库往往包含未公开的项目细节、财务制度、人事规范,接第三方 API 意味着把内容交给别人保管,这在大多数公司都过不了安全评审。数据留在内网之后,权限、审计、备份都是自己说了算,这是一个硬约束,不是偏好问题。

第二个是可用性。内网环境不一定有稳定的出网带宽,在线接口的延迟和限流也会影响体验。本地部署的 vLLM 服务跑在同一台服务器或同一个机房,调用开销是毫秒级的,不依赖外网状态。

第三个是成本模型。在线大模型按 token 计费,知识库一旦被高频查询,单月账单很容易失控;本地部署是一次性硬件投入加电费,长期跑下来反而可预测。对于数据量中等、查询频率稳定的内部场景,这笔账算得过来。

1.2 vLLM、DeepSeek、Milvus 各干哪一摊活

这套链路的角色划分非常清晰:

  • vLLM负责把模型"服务化"。它把模型权重加载进显存,对外提供 OpenAI 兼容的 HTTP 接口,自带高吞吐推理和显存管理,不用自己写推理代码。
  • DeepSeek是模型本身。在这个项目里它同时承担两个任务:一是把文本变成向量(向量化),二是根据检索结果生成回答。开源权重直接下载到本地,不依赖任何在线服务。
  • Milvus负责向量数据的存储和检索。它是真正的数据库,有集合、字段、索引、标量过滤的概念,能支撑后续按部门、按时间过滤查询,而不是一个简单的向量数组。

整个流程可以这样理解:文档先被切成小片段,每段文本交给 vLLM 里的 DeepSeek 模型转成向量,向量连同原文和来源信息一起写进 Milvus;查询的时候,用户问题被同一个模型转成向量,Milvus 在索引里快速找出最相似的几个片段,最后把片段拼进 prompt,交给生成模型产出回答。中间没有一个环节需要把数据送出内网。

1.3 候选方案对比:为什么最后留下 Milvus

选型时我也对比过几个主流方案,整理成表格就一目了然了:

方案优势短板适合场景
Elasticsearch生态成熟,全文检索强向量能力是后加的,调优复杂,资源占用大以关键词检索为主的老系统
Faiss轻量、算法全、速度快只是计算库,没有持久化、过滤、权限、API离线实验、单机小批量
Chroma上手快,几行代码就能跑数据量一上去性能就掉,不适合多并发原型验证、千条级数据
Milvus完整的向量数据库,索引类型多、过滤能力强要单独部署,多一个运维组件面向生产的本地向量库

选 Milvus 还有一个原因:它是"数据库"而不是"索引库"。企业内部的知识库一定会遇到按文档类型、所属部门过滤的场景,也会遇到数据增删改的问题,这些能力 Faiss 里都得自己重新造轮子,而 Milvus 原生就支持。对于"先跑通再扩到全公司"的路径来说,一步到位用 Milvus 反而省事。

2. 先把地基打好:硬件估算、软件安装与模型权重

2.1 先算显存账:你的卡能跑多大的模型

这一步是后面所有环节的前提。模型权重在 FP16 精度下大约等于参数量的两倍字节数:1.5B 参数的模型约 3GB,7B 约 14GB,32B 约 64GB。但显存不光是装权重,KV Cache 和计算过程中的激活值同样要吃显存,所以实际需求要预留 20% 到 30% 的余量。

模型规模权重大小(FP16)建议显存推荐用途
DeepSeek-R1-Distill-Qwen-1.5B约 3GB8GB 可跑向量化、低资源设备
DeepSeek-R1-Distill-Qwen-7B约 14GB24GB生成、日常内部问答
DeepSeek-R1-Distill-Qwen-32B约 64GB80GB 或双卡复杂推理、高质量生成

我自己的环境是一张 24GB 显存的显卡,最终采用了"7B 做生成 + 1.5B 做向量化"的组合,两个模型加起来大约 17GB 权重,给 KV Cache 留了充足空间。磁盘方面也不能忽略,一百万条 1536 维向量的裸数据就要 6GB 左右,加上索引和 Milvus 自身的开销,建议预留至少 100GB 磁盘。

2.2 vLLM 安装:版本、Python 环境和第一个探针

vLLM 对 Python 版本有要求,我建议直接用 conda 建一个干净环境,避免和系统 Python 打架:

conda create -n kb python=3.11 -y conda activate kb pip install vllm

装完之后先别急着拉模型,跑两条命令确认环境正常:

python -c "import torch; print(torch.__version__, torch.cuda.is_available())" nvidia-smi

torch.cuda.is_available()必须是 True。如果显示 False,基本可以断定是 CUDA 版本和 PyTorch 不匹配,重装对应版本的 PyTorch 再回来。这里有个经验:vLLM 迭代很快,不同版本的参数名可能微调,遇到陌生参数别硬猜,直接vllm serve --help看看当前版本的说明。

2.3 Milvus 单机部署:一条命令和两个检查

Milvus 的部署方式很多,单机场景用官方脚本最省心。它会自动拉起 etcd、MinIO 和 standalone 三个容器,把依赖关系处理好:

curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/v2.4.0/scripts/standalone_embed.sh -o standalone_embed.sh bash standalone_embed.sh

等十几秒后检查两个地方,一个是 Milvus 健康状态,一个是 Python 客户端能不能连上:

curl -s http://localhost:19530/health pip install pymilvus openai python -c "from pymilvus import MilvusClient; MilvusClient(uri='http://localhost:19530'); print('ok')"

健康检查返回{"status":"OK"}、Python 客户端不报错,就说明数据库已经就绪。

提示:standalone_embed.sh 启动的数据默认落在 Docker volume 里。容器重建之前一定要确认 volume 还在,否则向量库说没就没。我从一开始就把数据目录映射到宿主机独立目录,后面会专门讲持久化的坑。

2.4 DeepSeek 权重落地:两条下载路径和 config.json 检查

DeepSeek 的开源权重在 HuggingFace 和 ModelScope 上都有分发。如果下载速度不理想,可以换 ModelScope 的仓库:

# HuggingFace 方式 huggingface-cli download deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --local-dir /data/models/deepseek-r1-1.5b # ModelScope 方式 modelscope download --model deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --local_dir /data/models/deepseek-r1-1.5b

权重下载完,记得打开模型目录里的config.json看一眼两个字段:hidden_size和max_position_embeddings。前者决定向量维度,后者决定模型能处理的最大序列长度。DeepSeek-R1-Distill-Qwen-1.5B 的 hidden_size 是 1536,这个数字后面要原封不动写进 Milvus 的字段定义里,写错就插不进去数据。

3. 用 vLLM 把 DeepSeek 拉起来:启动参数背后的权衡

3.1 生成和向量化各占一个端口

vLLM 一个进程只能绑定一种任务类型:generate模式对外提供/v1/chat/completions,embedding模式对外提供/v1/embeddings。所以我把两个实例分开跑,互不干扰:

# 生成实例:端口 8000 vllm serve /data/models/deepseek-r1-7b \ --host 0.0.0.0 \ --port 8000 \ --task generate \ --gpu-memory-utilization 0.6 \ --max-model-len 8192 \ --served-model-name deepseek-chat
# 向量实例:端口 8001 vllm serve /data/models/deepseek-r1-1.5b \ --host 0.0.0.0 \ --port 8001 \ --task embedding \ --gpu-memory-utilization 0.3 \ --max-model-len 4096 \ --served-model-name deepseek-embed

几个参数说清楚:

  • --task指定模型用途,generate 和 embedding 不能写混,否则接口直接 404。
  • --served-model-name是对外暴露的名字,可以随便起。它只影响 API 调用时传的 model 字段,不影响模型权重本身。
  • --gpu-memory-utilization写成小数,表示该实例最多能吃掉多少比例的显存。两张卡共 24GB 时,0.6 + 0.3 合适,剩下 0.1 留给 CUDA context 和系统开销。千万不要两个实例都写 0.9,第二次启动直接 OOM。
  • --max-model-len不是越大越好。它决定 KV Cache 的预留规模,模型加载时 vLLM 会按这个长度估算显存,设得过大模型都加载不出来。1.5B 向量实例用 4096 足够,因为切片本身不会太长。

3.2 让生成模型"兼职"向量化:补一个池化配置

这里是我踩过的第一个硬坑。DeepSeek 的官方权重是为生成任务训练的,模型配置里没有池化层,直接带--task embedding启动会报"模型不支持嵌入任务"之类的错误。vLLM 要求嵌入模型在 config.json 里显式声明pooling_config,解决办法是在模型目录的 config.json 顶层补一个配置块:

{ "pooling_config": { "pool_type": "last", "normalize": true } }

pool_type: last表示取最后一个 token 的隐藏状态作为整段文本的向量,normalize: true表示对向量做归一化,这样后面用 COSINE 相似度时打分才准确。补完配置后重新启动向量实例,确认/v1/models里能看到这个模型,就算成功。

提示:如果你不想动模型文件,或者试了几天还启动不起来,直接换一个原生支持嵌入的模型(比如 BGE-M3 系列)是最省事的。代码只需要改模型名和维度,其他逻辑完全不变。拿 DeepSeek 硬凑 embedding 是为了少维护一个模型,如果折腾成本超过收益,果断换。

3.3 接口自检三步:models、chat、embeddings

服务起来之后,别急着写业务代码,先用 curl 把三个接口都验一遍:

# 1. 看看模型加载好没有 curl -s http://localhost:8000/v1/models | head # 2. 生成接口 curl -s http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model": "deepseek-chat", "messages": [{"role": "user", "content": "你好"}], "max_tokens": 64}' # 3. 向量接口 curl -s http://localhost:8001/v1/embeddings \ -H "Content-Type: application/json" \ -d '{"model": "deepseek-embed", "input": "你好"}'

向量接口返回的embedding数组长度必须是 1536,和前面 config.json 里的 hidden_size 对应。有两个时间点很容易误判:模型刚启动时 curl 返回 503 是正常的,vLLM 要先把权重全部加载进显存,这个过程可能要好几分钟,用/v1/models轮询,看到served-model-name才说明就绪;另一个是端口和任务类型对应关系,生成实例没有/v1/embeddings,向量实例也没有/v1/chat/completions,这两个实例不能混着用。

4. 让 Milvus 把数据接住:Schema、切片和索引的真实选择

4.1 先设计 Schema:维度写错满盘皆输

Milvus 是强 Schema 的数据库,建集合之前必须把字段定义清楚。我这个项目用到四个字段:

字段名类型说明
idINT64主键,自己管理自增
contentVARCHAR(4096)切片原文
sourceVARCHAR(256)来源文件路径或章节
embeddingFLOAT_VECTOR向量数据,维度 1536

建集合的代码用 pymilvus 的 MilvusClient 写起来很直观:

from pymilvus import MilvusClient, DataType mc = MilvusClient(uri="http://localhost:19530") # 重新建库,避免多次运行脚本时 schema 冲突 mc.drop_collection("doc_kb") schema = mc.create_schema(auto_id=False) schema.add_field("id", DataType.INT64, is_primary=True) schema.add_field("content", DataType.VARCHAR, max_length=4096) schema.add_field("source", DataType.VARCHAR, max_length=256) schema.add_field("embedding", DataType.FLOAT_VECTOR, dim=1536) index_params = mc.prepare_index_params() index_params.add_index( field_name="embedding", index_type="HNSW", metric_type="COSINE", params={"M": 16, "efConstruction": 200}, ) mc.create_collection("doc_kb", schema=schema, index_params=index_params)

dim=1536就是前面反复强调的维度,必须和向量模型输出严格一致。我一开始用 BGE-M3 测过一版,后来切回 DeepSeek 时忘了改维度,insert 阶段报错才发现。这个错误信息很直白,但定位起来要绕一圈,建议把维度写进一个常量,换模型时全局搜索就行。

4.2 切片方式直接影响召回上限

向量库的检索质量,一半取决于切片。切片太长,一句话的关键信息会被淹没在无关内容里;切片太短,语义又不够完整。我的做法是先按 Markdown 的段落切,段落超长再按字符数补一刀,同时保留重叠区:

import re def chunk_markdown(text, max_chars=800, overlap=100): blocks = [] for para in re.split(r"\n\s*\n", text): if len(para) <= max_chars: blocks.append(para) else: start = 0 while start < len(para): blocks.append(para[start:start + max_chars]) start += max_chars - overlap return blocks

800 字、重叠 100 字是中文文档一个比较稳的起步配置。重叠的意义在于:如果关键信息恰好落在切片边界上,两个切片都能覆盖到它,检索时不容易漏。说实话,切片属于"看起来简单、实际要反复试"的参数,我建议先用默认值跑通链路,再针对你自己的语料风格去调。

4.3 批量向量化写入:限流与进度打印

入库脚本的逻辑不复杂:读文件、切片、调向量接口、写入 Milvus。但有两个细节值得注意:一是向量化请求要控制并发,vLLM 默认支持一定并发,但你要是一口气丢几百个请求进去,某些版本会开始排队甚至报错;二是写入 Milvus 时用批量 insert,减少网络往返次数。我的完整脚本结构如下:

import glob from openai import OpenAI from pymilvus import MilvusClient EMBED_BASE = "http://localhost:8001/v1" EMBED_MODEL = "deepseek-embed" client = OpenAI(api_key="EMPTY", base_url=EMBED_BASE) mc = MilvusClient(uri="http://localhost:19530") rows = [] idx = 0 for path in glob.glob("corpus/**/*.md", recursive=True): with open(path, encoding="utf-8") as f: text = f.read() for chunk in chunk_markdown(text): vec = client.embeddings.create( model=EMBED_MODEL, input=chunk ).data[0].embedding rows.append({"id": idx, "content": chunk, "source": path, "embedding": vec}) idx += 1 # 每 50 条批量写一次,方便观察进度 if len(rows) % 50 == 0: mc.insert("doc_kb", rows) rows = [] if rows: mc.insert("doc_kb", rows) print("total:", mc.query("doc_kb", output_fields=["count(*)"]))

OpenAI 客户端的api_key随便填一个非空字符串就行,vLLM 不校验它。并发方面我实测 4 到 8 个并发请求是安全的,具体数值取决于你的显卡和处理能力,稳妥起见可以先串行跑一遍,确认吞吐量后再说。

4.4 索引选型:HNSW 为什么是中等规模的首选

Milvus 支持很多索引类型,选型逻辑其实不复杂。数据量决定索引类型,查询规模决定索引参数:

索引类型内存占用检索精度构建速度建议场景
FLAT高100%不需要构建一万条以下暴力搜索
IVF_FLAT中中快百万级,对查询速度要求不高
HNSW高高慢一点十万到千万级,在线低延迟查询
DISKANN低中慢亿级,数据放磁盘

HNSW 是目前中等规模向量库的主力选择,它的思路是构建一张多层图,检索时从顶层快速向下逼近目标节点。M=16表示每个节点最多连 16 个邻居,图越密召回越高,内存也越大;efConstruction=200是构图时的搜索宽度,会影响建索引的耗时和索引质量。这两个参数对十万到百万条数据来说是很常见的配置,不需要一上来就用极端值。

5. 检索链路与"搜得准"的调优方法

5.1 一次完整的检索:向量化、召回、生成

链路跑通的标志是能完成一次完整的"提问到回答"。查询阶段和入库阶段对称:先把问题向量化,再用同样的向量去 Milvus 里搜索,最后把命中的片段交给生成模型:

from openai import OpenAI query = "发票报销需要走什么流程" # 1. 问题向量化(走向量实例) qvec = client.embeddings.create( model=EMBED_MODEL, input=query ).data[0].embedding # 2. Milvus 召回 top5 res = mc.search( collection_name="doc_kb", data=[qvec], limit=5, output_fields=["content", "source"], search_params={"metric_type": "COSINE", "params": {"ef": 64}}, ) # 3. 组装上下文,交给生成实例 gen = OpenAI(api_key="EMPTY", base_url="http://localhost:8000/v1") context = "\n".join( f"[{item['entity']['source']}]\n{item['entity']['content']}" for item in res[0] ) resp = gen.chat.completions.create( model="deepseek-chat", messages=[ {"role": "system", "content": "你是内部知识库助手,只能依据给定资料回答,资料不足时直接说明不知道。"}, {"role": "user", "content": f"资料:\n{context}\n\n问题:{query}"}, ], max_tokens=512, ) print(resp.choices[0].message.content)

这个 prompt 里的 system 消息值得多说一句:明确告诉模型"只能依据资料回答、资料不足就直说",能显著减少幻觉。RAG 最常见的翻车现场就是模型在资料没有答案时自己编一个,这句话能把这个风险压下去大半。

5.2 相似度算法与打分阈值

Milvus 支持的相似度度量主要有三种:内积(IP)、余弦(COSINE)、欧氏距离(L2)。文本语义检索场景推荐 COSINE,它衡量的是方向而不是长度,对文本向量的量级差异不敏感。前提是向量做过归一化,恰好我前面在 pooling_config 里开了normalize: true,两者是配套的。

检索结果的distance字段,对 COSINE 来说越大表示越相似,理论范围是 -1 到 1。我跑了一段时间的经验区间是:0.75 以上基本可靠,0.6 到 0.75 需要人工看一眼,0.6 以下大概率是误召回。但注意这是经验值,不同模型的分值分布差异很大,建议你入库后抽几条查询自己观察一遍再定阈值。

5.3 用 ef 参数换速度与召回:一张实测表

HNSW 检索时最关键的是ef参数,它表示搜索时遍历的候选范围。ef 越大召回越准,延迟也越高。在我 60 万条、1536 维向量、单张 24G 显卡的压力测试下,大致是这样的关系:

ef 值单条查询延迟召回相对水平适用场景
16约 10ms85%快速预览,检索频率极高
64约 35ms95%日常内部问答,默认推荐
256约 120ms99%以上离线评测、高精度场景

调优路径我建议是先固定 ef=128,确认召回质量满足要求,再把 ef 往下调,找到准确率不掉、延迟明显下降的拐点。不要一上来追求 99% 的召回,企业内部问答对两三个百分点的差距没那么敏感,但延迟体感差异很大。

5.4 让检索更准:标量过滤、混合检索与重排

当知识库数据量大起来之后,单靠向量相似度不够,还要引入三个进阶手段。

第一个是标量过滤。Milvus 允许在 search 时加 filter 条件,比如只查某个部门的文档,或者排除某些文件类型:

res = mc.search( collection_name="doc_kb", data=[qvec], limit=5, filter='source like "%finance%"', search_params={"metric_type": "COSINE", "params": {"ef": 64}}, )

这样能避免不同部门的资料互相污染答案,在内部知识库场景几乎是刚需。

第二个是混合检索。向量检索擅长语义相似,但遇到"用户问法跟文档用词完全不一样"时依然可能漏。Milvus 支持稀疏向量,把传统的 BM25 关键词能力也引进来,用SPARSE_INVERTED_INDEX建索引,查询时做稠密和稀疏向量的加权融合,能同时照顾语义和关键词两个维度。这个属于进阶玩法,第一版先不做。

第三个是重排。如果 top5 里混入了不相关的片段,可以让生成模型对候选片段做一个二次判定:把 top10 的内容和问题一起发给 DeepSeek,让它挑出最相关的两三个片段。效果不错但成本高,适合对回答质量要求特别严的场景。我自己平时先用打分过滤,命中率低到不能忍才上重排。

6. 踩坑实录:五类问题从现象到根因的完整排查

6.1 curl 一直 503:是没加载完,不是服务挂了

问题现象:vLLM 启动命令执行后,curl 接口一直返回 503 Service Temporarily Unavailable,等了半分钟还是不行,感觉像服务坏了。排查链路是这样的:先看 vLLM 进程是不是活着,再用/v1/models轮询,同时观察nvidia-smi里的显存占用。vLLM 加载权重、做模型 profiling 需要几分钟,这段时间内接口就是 503。如果显存占用在持续上升,说明还在加载,继续等;如果显存已经占了 95% 以上但日志反复报错退出,那就是真正的 OOM,需要调小gpu-memory-utilization或者max-model-len。

6.2 404:task 不对,接口不存在

很多人(包括我)第一次都会犯这个错:对着 8000 端口的生成实例发/v1/embeddings,或者对着 8001 端口的向量实例发/v1/chat/completions,结果全是 404。vLLM 的 HTTP 路由是按任务类型注册的,generate 实例压根没有 embeddings 路由,embedding 实例也没有 chat 路由。解决办法不是找什么"兼容模式",而是确认你调用的端口对应的是哪个 task,换到正确的端口就行。

6.3 建集合报错:维度不一致和重复创建

入库脚本跑第二次的时候,大概率在create_collection阶段报两个错。一个是 "collection already exists",因为我脚本开头有drop_collection,第一次把集合删掉又重建就好了;另一个是维度不一致,报错类似 "dimension is not aligned with field schema",这时去看 config.json 的 hidden_size 和代码里的 dim 是不是同一个数字。换模型是最容易触发这个问题的操作,建议把维度常量放在脚本最顶部,并在日志里打印出来。

还有一个隐蔽问题:数据入库后第一次 search,报 "collection not loaded"。Milvus 的集合默认需要加载到内存才能检索,MilvusClient 部分操作会自动加载,但某些版本不会。遇到就手动执行:

mc.load_collection("doc_kb")

这个坑的特点是"数据明明在,查不到",极具迷惑性。

6.4 检索结果"看着像又不像":切片、阈值和过滤的联合调试

更头疼的是"没报错但结果不对":distance 0.83 很高,但返回的文本就是没回答到点子上。我遇到过三次这种情况,根因各不相同。第一次是切片把关键信息切断了,前半段是背景,后半段才是结论,问题命中在结论上但上下文不完整;第二次是 query 写得太口语化,文档里用词很正式,语义检索没能匹配上;第三次是没有加部门过滤,另外一个团队的同名制度文档干扰了排序。调试方法很朴素:把 top10 的 distance 和内容摘要全部打印出来,一行一行肉眼比对,然后只改一个变量重新查。千万不要同时改切片、阈值和过滤条件,那样永远定位不了问题。

6.5 显存不够与数据持久化:上生产前最后处理

如果你的显卡只有 16G,不要试图硬跑 7B 生成加 1.5B 向量两个实例,权重都装不下。这时候要么只跑 1.5B 生成实例,向量模型换成更小的专用嵌入模型;要么把 7B 换成 4 位量化版本,但量化会损失生成质量,内部问答能接受才用。

数据持久化这块,我吃过一次亏。当时以为数据进了 Milvus 就万事大吉,结果容器重建后集合还在、数据全空。原因是 Milvus 的数据实际写在 etcd 和 MinIO 里,而这两个组件的数据落在 Docker volume,容器删除时 volume 如果没保留,数据就没了。建议启动 Milvus 前先把 compose 文件里的 volume 显式映射到宿主机目录,并定期执行 compact 清理删除标记:

mc.compact("doc_kb")

安全方面也提一句:vLLM 的两个实例如果绑定了0.0.0.0,请确保它们只暴露在内网,别把端口映射到公网。Milvus 默认没有鉴权,多人内网使用时最好设置 root 密码或者用独立网段隔离。

最后说一点我自己的体会。整套链路里真正决定效果上限的,不是 vLLM 也不是 Milvus,而是你喂给它的语料和切片质量——数据脏、切片碎,再好的索引也救不回来。所以如果你时间有限,先把精力放在清理语料和设计切片规则上,把 demo 跑通后再逐步加 filter、混合检索和重排。我自己是从"1.5B 向量 + 7B 生成"这套组合上车的,等数据增长到百万级之后,再考虑把生成实例换成本地集群并引入更完整的权限体系。希望这篇总结能让你少走一点弯路,也欢迎你在评论区分享自己的踩坑经历。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 17:11:54

H743飞控接口全解析:UART、SPI、I2C、CAN引脚分配与调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 17:10:36

安全审计不是扫漏洞,而是构建可传承的审计能力

1. 这不是“打补丁”&#xff0c;而是给系统做一次全科体检“security-audit-skill”这个标题乍看像一个工具名&#xff0c;甚至有人第一反应是某个新出的CLI命令——但其实它根本不是软件&#xff0c;而是一套可复用、可验证、可传承的安全审计能力模型。我带过七支不同行业的…

作者头像 李华
网站建设 2026/10/18 17:06:18

采矿学PPT教学软件拆解:从文件结构到知识库构建

简介&#xff1a;这份采矿学电子教学课件面向矿业工程、采矿工程等专业的学生与技术人员&#xff0c;系统讲解金属矿床露天开采的核心知识&#xff0c;帮助学习者建立从基础理论到工艺设计的完整认知框架。资源包共1个文件&#xff0c;为PPT演示文稿&#xff0c;大小约3.11MB&a…

作者头像 李华
网站建设 2026/10/18 17:06:02

零样本学习原理与嵌入式对齐实战指南

简介&#xff1a;本资源是一份面向人工智能方向研究者与进阶学习者的零样本学习&#xff08;Zero-Shot Learning&#xff09;实践复现包&#xff0c;聚焦于算法原理理解与PyTorch工程落地&#xff0c;适用于计算机视觉、跨模态语义建模等场景。资源共11个文件&#xff0c;涵盖6…

作者头像 李华
网站建设 2026/10/18 17:04:39

开发板待机功耗超标排查:从芯片睡眠到系统级漏电归因

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 17:02:26

ASIC芯片选型指南:从AI推理的能效比到落地成本权衡

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华