ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Milvus给大模型建座图书馆:从零搭建AI长期记忆与RAG系统

用Milvus给大模型建座图书馆:从零搭建AI长期记忆与RAG系统 给金鱼建图书馆这个项目名其实是我自己在折腾 AI 应用时的一个比喻。上一期我们解决了怎么把知识喂给 AI的问题也就是让金鱼大模型能读到你扔进去的小纸条但很快你就会发现一个尴尬的局面每次对话结束金鱼就把纸条全忘了。哪怕你昨天刚跟它详细聊过你的项目背景、代码规范、个人偏好今天重新开个会话它又是一条全新的鱼。这就是大模型的短期记忆瓶颈——上下文窗口再大也装不下你和 AI 之间长期积累的所有信息。这一期要聊的就是给这条金鱼修一座真正的图书馆把那些散落的知识、对话记录、文档片段全部以向量化的方式存进一个专用的数据库里让 AI 在每次回答前先去翻书再组织语言。这座图书馆的承重墙就是 Milvus 向量数据库。它要解决的核心问题有三个海量向量怎么存、相似内容怎么快速检索、以及怎么跟现成的 LLM 应用框架无缝衔接。如果你正在做 RAG 应用、AI Agent、或者想让自己的聊天机器人记得住你是谁这篇文章就是为你准备的。我会从为什么非要专用向量数据库讲起到 Milvus 单机版部署、Python 实测写入和检索、再接入一个简单的 RAG 流程最后把我在 Windows 和 Docker 环境下踩过的坑一并倒出来。保证你看完能直接照着搭一套属于自己的图书馆。1. 项目整体设计与方案选型1.1 为什么不能用普通数据库存记忆在选型之前得先搞清楚向量数据库到底解决的是什么问题。传统的关系型数据库MySQL、PostgreSQL擅长的是精确匹配给你一个用户 ID一秒内返回它的名字。但如果给你一句我今天心情不太好想找点轻松的内容你没法用 WHERE 语句去匹配心情和轻松这两个词——因为它们不是精确值是语义。向量数据库干的事情就是把文字、图片、音频这些非结构化数据通过 embedding 模型变成一组浮点数通常是几百到几千维的向量然后在这些向量上做最近邻搜索。用生活化的类比来说普通数据库是一本按拼音排序的通讯录你得知道对方全名才能查到电话向量数据库是一个按长相相似度排列的照片墙你拿一张模糊的照片进去它能给你找出最像的那几张。有人会说那我把向量塞进 PostgreSQL 的 pgvector 扩展里不也行吗确实可以但这里有个量和速度的取舍。pgvector 在小规模数据几万条下表现尚可一旦你的知识库涨到百万级、千万级纯暴力扫描或者简单的 HNSW 索引就会让查询延迟飙升。Milvus 这类专用向量数据库从底层就是为大规模向量检索设计的支持分片、索引、混合查询还配套了监控和运维工具。简单说玩具项目用什么都能跑但如果你想认真做产品专用库省心得多。1.2 为什么是 Milvus 而不是 Qdrant、Chroma 或 Weaviate选型时我其实对比过好几款主流向量数据库。Chroma 最轻量pip install 就能用适合本地原型验证但它的分布式能力和数据量上限都偏弱数据一多就吃力。Qdrant 性能不错Rust 写的查询速度很快文档也友好但它的生态和周边工具比 Milvus 略逊一筹。Weaviate 有内置的模块化功能比如自动做 embedding 和向量化用起来很爽但这也意味着你在某些环节上被它绑定了调试和定制没那么灵活。最终让我定下 Milvus 的原因有三点第一它支持 Standalone 和 Distributed 两种部署模式从单机开发到集群生产都能平滑过渡第二它提供了 Attu 这个可视化管理界面排查数据、调试索引非常直观第三它的 Python SDKpymilvus在社区里非常成熟配合 LangChain、LlamaIndex 这些主流框架都有现成的集成组件。用一句行话来说Milvus 的上限足够高不至于让你在项目长到一半时被迫换底座。1.3 整条 RAG 链路是怎么串起来的在动手部署之前先把这条记忆链路的整体蓝图理清楚。整个系统分成五个环节文档加载与清洗把 PDF、Markdown、TXT 里的原始文本抽出来去掉格式噪点。文本切分把长文档按段落、句子或者固定 chunk size 切成小块。切得太大会导致检索粒度粗糙太小又会丢失上下文。Embedding 向量化用一个 embedding 模型把每一块文本变成向量。这一步是语义理解的关键模型选得好不好直接影响检索质量。写入向量库把向量和原文 metadata来源、时间、标题等一起存进 Milvus。查询与生成用户提问时先把问题向量化去 Milvus 里找最相似的 Top-K 条记录再把它们拼进 prompt 里丢给大模型。这五个环节里向量数据库是图书馆的仓库和检索系统embedding 模型是图书管理员的编码能力而大模型则是一个知识运用者——它自己不记东西但它非常擅长从翻到的资料里总结并组织语言。2. Milvus 环境搭建与核心概念2.1 单机版部署Docker 是最快路径Milvus 官方提供了多种安装方式源码编译不推荐太痛苦、Docker Compose推荐给大多数场景、以及 Kubernetes Helm Chart给生产集群用。除非你有特殊的网络环境限制否则直接用 Docker 起步是最省事的。注意这里说的单机版是 Milvus Standalone不是轻量版。它仍然由 etcd、MinIO、milvus 三个组件组成只是全部跑在同一台机器上。这套架构已经能支撑千万级向量的检索个人项目和中小团队完全够用。准备一个docker-compose.yml内容大致长这样version: 3.5 services: etcd: container_name: milvus-etcd image: quay.io/coreos/etcd:v3.5.5 environment: - ETCD_AUTO_COMPACTION_MODErevision - ETCD_AUTO_COMPACTION_RETENTION1000 - ETCD_QUOTA_BACKEND_BYTES4294967296 - ETCD_SNAPSHOT_COUNT50000 volumes: - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd command: etcd -advertise-client-urlshttp://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd minio: container_name: milvus-minio image: minio/minio:RELEASE.2023-03-20T20-16-18Z environment: MINIO_ACCESS_KEY: minioadmin MINIO_SECRET_KEY: minioadmin volumes: - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data command: minio server /minio_data healthcheck: test: [CMD, curl, -f, http://localhost:9000/minio/health/live] interval: 30s timeout: 20s retries: 3 standalone: container_name: milvus-standalone image: milvusdb/milvus:v2.3.4 command: [milvus, run, standalone] environment: ETCD_ENDPOINTS: etcd:2379 MINIO_ADDRESS: minio:9000 volumes: - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus ports: - 19530:19530 - 9091:9091 depends_on: - etcd - minio networks: default: name: milvus-network启动命令也很简单docker-compose up -d启动后检查三个容器是否健康再确认 19530 端口通了就行。Milvus 默认的 gRPC 端口是 19530RESTful API 则在 9091。如果你需要可视化界面再单独拉一个 Attudocker run -p 8000:3000 -e MILVUS_URLhost.docker.internal:19530 zilliz/attu:latest然后浏览器打开http://localhost:8000就能看到 Milvus 里的 collections、indexes 和所有数据。这一步强烈建议做调试效率能提升一个档次。2.2 核心概念速览Collection、Field、IndexMilvus 里最核心的几个概念理解它们之后写代码基本没有障碍。Collection集合对标关系型数据库的表是一个向量的容器。Collection 里有一个主键字段Primary Key和一个向量字段Vector其余可以自定义标量字段用于过滤。Field字段就是 Collection 的列每个字段有特定的数据类型。Index索引是加速检索的关键Milvus 支持多种索引类型最常用的是 HNSW 和 IVF_FLAT。这里要特别说一下 HNSW 索引。它是一种基于图的近似最近邻搜索算法核心思想是用多层图结构组织向量检索时从顶层开始快速下探到目标区域再在底层精细搜索。它的参数主要有三个M每个节点的最大连接数默认 16、efConstruction构建时动态列表大小默认 200、efSearch查询时动态列表大小默认 64。简单记M 越大图越稠密召回率高但占内存efSearch 越大查询越准但越慢。向量维度的选择取决于你用的 embedding 模型。常见的有OpenAI text-embedding-ada-0021536 维收费但质量稳定。BGE-large-zh1024 维开源免费中文效果不错。sentence-transformers 系列384~768 维不等适合本地部署。维度一旦建好之后Collection 就不能改了所以要根据 embedding 模型提前想清楚不要建完再后悔。2.3 索引参数和相似度度量方式怎么选Milvus 支持三种向量相似度度量方式内积IP、欧氏距离L2、余弦相似度COSINE。选择依据很简单如果你的 embedding 模型本身做了 L2 归一化比如 OpenAI 的 ada-002 推荐用内积计算点积那选 IP 效率最高如果是自训练的模型没做归一化用 COSINE 更稳妥L2 多用于图像检索场景文本检索里用得少。这里有个实际经验无论选哪种度量方式线上检索质量的好坏60% 取决于 embedding 模型本身30% 取决于文本切分策略只有 10% 取决于索引参数。很多人一上来就死磕 HNSW 的参数其实不如把功夫花在第 3 节的切分逻辑上收益大得多。3. Python 实操给金鱼建图书馆3.1 安装 pymilvus 并建立连接环境准备好之后就开始写 Python 代码。首先安装依赖pip install pymilvus sentence-transformerspymilvus 是 Milvus 的官方 Python SDKsentence-transformers 是用来做本地 embedding 的工具库。我建议你先用本地模型跑通整个流程等确认没毛病了再替换成更贵的模型或者换个 API 接口。连接服务的代码非常简洁from pymilvus import connections, utility # 建立连接 connections.connect(aliasdefault, hostlocalhost, port19530) # 检查服务状态 print(utility.get_server_version()) # 输出: v2.3.4这一步通常不会出问题除非你的 19530 端口没开或者 Docker 容器没起来。有个小坑如果你本机也装了别的服务占用了 19530连接会直接超时验证端口占用是第一优先级。3.2 创建 Collection 和索引接着就是建图书馆书架。我用一个双向的比喻这个 Collection 就是一排书架每个向量就是书架上的一本书标量字段是贴在书脊上的标签。下面这段代码建了一个简单的 Collectionfrom pymilvus import ( CollectionSchema, FieldSchema, DataType, Collection, utility ) # 定义字段 fields [ FieldSchema(nameid, dtypeDataType.INT64, is_primaryTrue, auto_idTrue), FieldSchema(nametext, dtypeDataType.VARCHAR, max_length2000), FieldSchema(namesource, dtypeDataType.VARCHAR, max_length500), FieldSchema(namecreated_at, dtypeDataType.INT64), FieldSchema(nameembedding, dtypeDataType.FLOAT_VECTOR, dim384) ] # 构建 Schema 并创建 Collection schema CollectionSchema( fieldsfields, descriptionAI long-term memory library ) collection Collection(namememory_library, schemaschema)注意FieldSchema里dtypeDataType.FLOAT_VECTOR的dim参数这里设成了 384因为我下面会用sentence-transformers/paraphrase-MiniLM-L6-v2这个模型它的输出维度正好是 384。如果你的模型输出是 1024 或者 1536这里必须跟着改。然后创建索引from pymilvus import IndexType, MetricType index_params { index_type: IndexType.HNSW, metric_type: MetricType.COSINE, params: {M: 16, efConstruction: 200} } collection.create_index(field_nameembedding, index_paramsindex_params)创建成功后可以用 Attu 界面查看 Collection 的 schema 和索引信息确认一切就位。这一步是书架搭好了但还没有书放进去。3.3 文本切分切得好不好直接影响检索效果这是整个流程里最容易被忽视、但影响最大的环节。我一开始图省事直接把整个文档丢进去做 embedding结果检索出来的片段经常是大杂烩前后文毫无关联因为一段 5000 字的文本被平均化成了一个向量语义信息都被冲淡了。后来改成基于语义切分用段落作为天然边界再配合固定 chunk size 和 overlap。简单粗暴但有效的做法是chunk_size 设 500 个字符中文overlap 设 50 个字符。切分时优先在句号、换行符处断开不要硬切词。如果一段文本实在太长硬切完也要保留前后文的 50 字作为上下文缓冲。这样做的逻辑是检索时我们返回的是一个块这个块要足够聚焦才能让大模型直接用。切太碎上下文不完整切太大语义浑浊。用 LangChain 的RecursiveCharacterTextSplitter是最省事的from langchain.text_splitter import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , , ] ) chunks splitter.split_text(long_text) print(f切分得到 {len(chunks)} 个文本块)separators的优先级顺序很重要它会先尝试按段落切不行再按句子切最后才按字符硬切。这个策略保证了 chunk 的完整性。3.4 向量化并写入 Milvus文本切好之后下一步是 embedding 和写入。这里我用sentence-transformers做本地向量化整个模型在 CPU 上跑也很快几千条文本几分钟就能处理完from sentence_transformers import SentenceTransformer import time # 加载本地 embedding 模型 model SentenceTransformer(sentence-transformers/paraphrase-MiniLM-L6-v2) # 对 chunk 列表批量向量化 embeddings model.encode(chunks, show_progress_barTrue).tolist() # 构造插入数据 data_rows [] for i, (chunk, emb) in enumerate(zip(chunks, embeddings)): data_rows.append({ text: chunk, source: my_document.md, created_at: int(time.time()), embedding: emb }) # 插入 Collection collection.insert(data_rows) print(f已写入 {len(data_rows)} 条记录) # 数据写入后必须 flush 才能被索引和检索 collection.flush() print(f当前实体数量: {collection.num_entities})这里有几个非常隐蔽但关键的细节第一collection.insert()之后不是立刻就能查到。Milvus 的写入是异步落盘的必须调用flush()强制落盘否则后续检索可能查不到刚插入的数据。第二collection.num_entities在数据量大时可能有延迟统计不要拿它当强一致性的依据。第三如果插入失败要先检查 schema 里的字段类型和 Python 字典里的数据类型是否完全匹配比如INT64对应的就是 Python 的 int别传字符串进去。3.5 检索让金鱼学会翻书数据写进去了接下来是最重头的查询环节。Milvus 的查询语法很接近关系型数据库但它执行的是向量相似度搜索from pymilvus import Collection collection Collection(memory_library) collection.load() # 加载到内存之后才能查询 query_text 昨天讨论的项目部署方案是什么来着 query_embedding model.encode([query_text]).tolist() results collection.search( dataquery_embedding, anns_fieldembedding, param{metric_type: COSINE, params: {efSearch: 64}}, limit3, output_fields[text, source, created_at] ) for hit in results[0]: print(f距离: {hit.distance:.4f}) print(f来源: {hit.entity.get(source)}) print(f文本内容: {hit.entity.get(text)[:100]}...) print(- * 60)这里有一个容易搞混的点results的返回结构是一个二维列表——外层对应你输入的多条 query 向量内层是每条 query 的 top-k 结果。哪怕你只查一条也要用results[0]去遍历。limit决定了返回几条最相似的记录这个值也是后面 RAG 流程里拼 prompt 的重要参数。经验值一般是 3~8 条之间。太多会把上下文撑爆且引入噪音太少可能漏掉关键信息。到这里图书馆的核心功能已经跑通了建库、写入、索引、检索四步走完金鱼已经有书可翻了。4. 把 Milvus 接入 AI让长期记忆真正生效4.1 从检索到回答一个最小可用的 RAG 流程有了向量库接下来就是把检索结果喂给大模型做回答。这才是整个项目真正产生价值的一步金鱼不仅翻书了还能书里找到答案。我用一个极简的流程来演示不依赖任何重型框架方便你看到每一环节到底发生什么。假设你手里已经有一个 OpenAI 兼容的 API或者本地跑了一个开源模型代码如下from openai import OpenAI client OpenAI(base_urlhttp://localhost:11434/v1, api_keyollama) def rag_answer(question: str, top_k: int 5) - str: # Step 1: 将问题向量化 question_emb model.encode([question]).tolist() # Step 2: 从 Milvus 检索相似片段 collection.load() results collection.search( dataquestion_emb, anns_fieldembedding, param{metric_type: COSINE, params: {efSearch: 128}}, limittop_k, output_fields[text, source] ) # Step 3: 拼装上下文 prompt context_chunks [] for hit in results[0]: context_chunks.append(hit.entity.get(text)) context \n\n.join(context_chunks) prompt f请基于以下参考资料回答用户的问题。如果资料里没有相关信息就老实说不知道不要编造。 参考资料 {context} 用户问题{question} # Step 4: 调用大模型生成回答 resp client.chat.completions.create( modelqwen2.5:7b, messages[{role: user, content: prompt}] ) return resp.choices[0].message.content print(rag_answer(我之前提到过项目部署时的注意事项有哪些))这个流程里prompt 的组织方式对回答质量影响极大。我的经验是一定要在 prompt 里明确告诉模型只能依据参考资料回答资料中没有就说不知道否则模型会自作聪明地补全答案产出幻觉内容。这就是 RAG 的边界感。4.2 会话记忆链跨对话的长期记忆到底怎么存所谓给金鱼建图书馆本质上是让 AI 的记忆从会话级升维到持久级。这里我推荐一种分层记忆架构第一层是业务知识库存的是文档、手册、FAQ这类数据基本不变写入一次长期使用。第二层是用户偏好库存的是用户过往对话中提取出来的偏好信息比如这个项目的客户喜欢简洁的回复风格、部署环境是 Windows 而非 Linux。第三层是短期对话上下文这个可以继续用传统的方式放在会话里不需要落到向量库。实现上第二层用户偏好库通常这样做每个用户分配一个固定的 partition key检索时用布尔表达式过滤只搜该用户的数据。Milvus 的标量字段过滤在这里非常有用results collection.search( dataquestion_emb, anns_fieldembedding, param{metric_type: COSINE, params: {efSearch: 128}}, limit5, expruser_id u_12345, # 只检索这个用户的记忆片段 output_fields[text, source] )expr就是 Milvus 的过滤表达式语法和 SQL 的 WHERE 很像。用这种方式你可以实现只翻某个人的书架而不是每次都在整座图书馆里大海捞针。这是我在实际项目中最常用的优化手段——数据量一旦上来不加过滤条件检索延迟和结果相关性都会明显退化。4.3 数据更新和删除图书馆的日常维护长期记忆不是写死的它需要不断更新。用户今天说我改主意了不用 Redis 了改用 MongoDB昨天的记忆就不能再让它生效。Milvus 的删除操作和关系型数据库差别很大需要特别注意from pymilvus import Collection collection Collection(memory_library) # 按主键删除 collection.delete(exprid in [1, 2, 3]) # 按表达式删除 collection.delete(exprsource outdated_doc.md)删除后同样需要 flush。但对于修改Milvus 没有直接的 update 操作惯用的做法是 delete 旧数据再 insert 新数据。这不是 bug是设计如此——向量库天然偏追加。关于数据过期还有两种策略很常用。一种是 TTL 自动过期Milvus 支持在 Collection 上设置 TTL超时的数据会自动清理。另一种是业务层面做版本号每次写入新的记忆时带上 version 字段检索时只取最新版本。前者适合日志型数据后者适合需要保留历史轨迹的场景。5. 常见问题与避坑实录5.1 Windows 部署Docker Desktop 是唯一的亲儿子先直接说结论在 Windows 上安装 Milvus不用折腾本地二进制或 WSL 里的手动编译直接用 Docker Desktop 是最省心的路。原因有二一是 Milvus 的官方安装包本身就以容器为第一公民二是 WSL2 环境下的网络映射和端口转发问题能让你浪费一整天。但我实测下来Docker Desktop 也有几个必须提前处理的坑内存分配至少要给 8GB。Milvus standalone 加 etcd 加 MinIO 三个容器同时跑吃内存很凶给少了直接 OOM容器反复重启。启动顺序有讲究。虽然docker-compose up -d会自动处理依赖但 etcd 和 MinIO 的healthcheck不一定能准时就绪。如果 standalone 容器一直报连接 etcd 失败别急着删镜像先docker logs milvus-etcd看看是否健康。端口冲突是高频事故。尤其 19530很多开发工具喜欢占这个端口。启动前先netstat -ano | findstr 19530查一遍。还有一点Windows 的 Docker 默认磁盘镜像格式是 vhdx时间久了体积会膨胀得可怕。建议在 Docker Desktop 的 Settings 里调整磁盘上限或者定期用docker system prune清理无用镜像否则你的 C 盘迟早告急。5.2 检索效果差先别调索引先看这三点很多人跑通检索后发现结果不相关第一反应是动手调 HNSW 参数。但根据我的经验80% 的情况问题根本不在索引而在更上游的三个环节。第一是 embedding 模型选型问题。中文场景如果直接用英文预训练的模型检索质量会非常感人。务必换用中文优化的模型比如BAAI/bge-large-zh-v1.5或者至少是多语言模型paraphrase-multilingual-MiniLM-L12-v2。换个模型检索效果立竿见影。第二是文本切分粒度过大。如果你的 chunk 是 1000 字的一段里面讲了三件事那这一段的向量就是三个主题的平均值什么都是也就什么都不是。把 chunk_size 降到 300~500同时把 overlap 控制在 50 左右效果通常改善明显。第三是查询改写缺失。用户的提问往往是口语化的比如上次说的那个问题后来怎么解决的这种问题直接做 embedding和知识库里的标题式文本相似度很低。解法是在检索之前让大模型先把用户提问改写成一个独立的、信息完整的查询语句再用改写后的文本去检索。5.3 数据量激增后检索变慢合理的分区和索引策略当你把几万条记忆灌进去之后检索延迟可能会从几毫秒涨到几十毫秒这是正常现象但如果增长到几百毫秒就该检查策略了。第一个优化方向是合理分区。如果你的业务天然有租户维度比如多用户用 Partition 按用户划分检索时只查指定 partition速度能快一个量级。Milvus 的 partition 逻辑就是逻辑分片配合partition_names参数使用。第二个方向是索引重建。HNSW 索引在持续高频写入后图结构会逐渐退化。Milvus 提供了 compaction 机制条件允许时定期执行collection.compact()可以重建索引提升查询性能。注意 compaction 也需要在数据量稳定时执行否则会和写入互相争抢系统资源。第三个方向是索引和查询分离。Milvus 支持在同一 Collection 上创建多个索引不同查询场景可以用不同索引参数。比如线上高频检索用 efSearch64 的低延迟配置离线分析用 efSearch256 的高召回配置。这个特性特别适合知识库这种线上服务 离线调优并存的场景。5.4 pymilvus 版本不一致导致的兼容性坑pymilvus 的版本和 Milvus 服务端的版本必须匹配否则会出现各种莫名其妙的问题比如连接成功但创建 Collection 失败、或者检索时报Index not found。最典型的坑是你在本地 pip install pymilvus 装到的是 2.4.x但 Docker 镜像里跑的是 Milvus v2.3.x两边 gRPC 协议不兼容导致高频调用时报各种隐藏错误。我的建议是锁版本别整最新版。用下面这组搭配跑了一整个季度稳如老狗组件版本milvusdb/milvusv2.3.4pymilvus2.3.6langchain0.1.xsentence-transformers2.2.2安装时直接指定版本号pip install pymilvus2.3.6换版本之前先查一下官方文档里的 compatibility 列表。这是老鸟和新手最大的区别新手图新鲜啥都装最新版老鸟先确认兼容性再动手。5.5 兜底方案数据备份与恢复最后说一个很多人会忽略的问题向量数据库里的数据几乎都是不可再生的。你的原始文档可能还在但整批 embedding 向量一旦丢失重新向量化的成本极高不仅要重新跑模型而且可能因为模型升级导致向量无法直接对比。我吃过一次大亏手滑删了 Docker volume整个知识库灰飞烟灭。后来学乖了每周用 Milvus 的backup工具做一次全量备份。Milvus 官方提供了milvus-backup命令行工具用法非常简单# 备份 ./milvus-backup create --name backup_20240101 # 恢复 ./milvus-backup restore --name backup_20240101如果你不想引入额外的工具也可以直接用 Docker 的 volume 快照docker run --rm -v milvus_volumes:/data -v $(pwd):/backup alpine tar czf /backup/milvus_backup.tar.gz -C /data .恢复时把 tar 包解压回 volume 目录即可。备份不重要日常不落灰出事故才知道它救命。最后分享两个我实测出来的小技巧第一件事关于 embedding 模型的批量处理。当你的知识库有上万条文本时不要一条条循环 encode那样 CPU 会跑几十个小时。SentenceTransformer是支持 batch 的把 batch_size 调成 32 或 64速度能提升 5 倍以上embeddings model.encode(chunks, batch_size64, show_progress_barTrue)而且实测下来batch 模式的推理结果和单条模式几乎无差别不用担心量化损失。第二件事关于记忆和知识的边界。我做了好几轮项目之后才意识到向量数据库适合存的是变化慢的知识比如文档、FAQ、产品说明。而对于用户当下正在想什么这类短期意图直接放会话上下文里更高效没必要每次都去翻库。把这个边界划清楚你的系统会简洁得多——金鱼不需要把所有东西都搬进图书馆它只需要知道不知道的东西去哪查。这两点经验希望你能在项目里用上。如果部署过程中遇到什么奇怪的问题欢迎回来交流。
返回列表