向量、检索与 RAG:一套「照着资料说话」的搜索系统是怎么搭起来的
一、字面 vs 意思:老式搜索输在哪
传统的站内搜索、政府门户的检索框,绝大多数是关键词检索:把你的问句拆成词,去文档里找「包含相同字词」的条目。它的死穴是——用户说话的方式,和文档写字的方式,几乎从不一致。
你问「东西弄坏了要赔多少」,法律文档写的是「损害赔偿」「侵权责任」——一个字都对不上。关键词检索于是漏掉了最该命中的两篇,反而因为「赔偿」二字命中了一篇《赔偿金计算器使用说明》,答非所问。

语义检索换了个问法。它不问「有没有相同的字」,改问「两段话的意思像不像」。同义改写、跨语言、旧式表述,只要意思一致,它都能捞回来。这不是玄学,背后是一套很硬的数学,核心叫 embedding。
二、Embedding:把每段文字放进一张「意思地图」
一个 embedding 模型,做的事情是把任意一段文字,压成一串固定长度的数字——比如 1024 个数。这串数字不是随机的,它是这段话在一个 1024 维空间里的坐标。
模型经过海量训练,学会了一件事:意思相近的文字,坐标点靠得近;意思无关的,离得远。于是「损害赔偿」和「侵权责任」这两个点在地图上挤成一团,「红烧肉」「火候」则落在遥远的另一片区。

到这一步,「搜索」就被翻译成了一道几何题:把用户问句也变成一个坐标点,然后量它离哪些文档坐标最近。近的就是相关的。字面对不对得上,从此无关紧要。
好的 embedding 模型还是双语的(比如 bge-m3),中文问句和英文文档能落在同一片区——这意味着中文提问也能召回英文资料,这是关键词检索永远做不到的。
三、RAG:让大模型「照着资料说话」
光有检索还不够。用户要的不是一堆文档链接,是一个直接的答案。但你又不能让大模型自由发挥——它会一本正经地编造事实(幻觉)。RAG(检索增强生成)就是把「检索」和「大模型」焊在一起的方案:先检索出真实资料,再逼着模型只能照着这些资料回答。
整条链路分两段:一段离线建库,一段在线问答。

离线段(内容更新时才跑一次):原始资料 → 清洗切块 → 每块 embed 成向量 → 连同「出处」一起存进向量库。这一段是重活,但不用天天做。
在线段(每次提问都跑):问句 embed → 向量库召回最相关的几段 → 把这几段原文塞进提示词当「依据」→ 大模型照着依据流式作答 → 附上来源链接。
这里藏着零幻觉的关键设计:来源链接是「检索结果」直接给出的,不经过大模型。模型只负责把话说得像人,不负责报出处——所以它编不出一个指向不存在文章的链接。这一条分工,是「AI 客服敢挂在专业场景上」的底气:答错一句可能有责任的行业(律所、医疗、政务),靠的就是「每句话都能点回原文」。
一句话概括:检索负责「找对料」,大模型负责「说人话」,两件事拆开,各司其职,才既准又像人。
四、向量数据库在算什么:量角度、排序、卡门槛
「向量库召回」这一步,听着神秘,拆开只有三个动作。
相似度用的是余弦相似度——只看两个向量的方向像不像,不管它们多长。方向完全一致是 1,毫不相干是 0。为什么用角度不用长度?因为这样长文档和短文档能公平比,不会因为一篇文章字多就占便宜。

拿到所有候选的相似度后,再过两道关:
| 关卡 | 做什么 | 为什么 |
|---|---|---|
| topK = 6 | 按相似度从高到低排,最多只取前 6 段 | 控制喂给模型的量:太多会让噪音淹没重点,也费钱 |
| 阈值 0.35 | 低于这个相似度的,一律丢弃 | 宁可回答「资料里没有」,也不硬凑不相关的段来充数 |
这两个数字(6 和 0.35)是可调的旋钮。调高阈值 → 答得更保守但可能漏;调低 → 召回更多但可能带进噪音。这是每个 RAG 系统都要根据自己语料去磨的手感。
五、系统架构:一套内核,两副「手」
原理讲完,看工程。一个真正跑在生产上的这类系统,最值钱的架构决策是:让核心逻辑彻底不认得自己跑在哪。
做法叫依赖注入 + 接口抽象。核心内核(core)是一堆纯函数——页面渲染、RAG 编排、表单处理——它们不直接调用任何具体的云服务,只对着三个抽象接口编程:AI 模型、向量库、存档。至于这三个接口背后是谁在实现,由部署时注入的「手」决定。

于是同一份代码,能落在两种完全不同的地基上:
| 手 A · 云托管(Cloudflare) | 手 B · 自托管(Node / VPS) | |
|---|---|---|
| AI 模型 | Workers AI(平台内置) | 任意 OpenAI 兼容 API(DeepSeek/自建 vLLM) |
| 向量库 | Vectorize(托管服务) | sqlite-vec(本地文件) |
| 存档 | D1(托管 SQL) | SQLite 文件 |
| 运维 | 零运维,全球边缘,按量计费 | 自己管一台机器 |
| 身份面 | 三个服务都挂在同一个云账户下,集中 | 不绑云账户,数据在自己机器上,可换非实名主机 |
| 切换方式 | deploy --target=cf | deploy --target=node |
换客户站,只改一张租户配置表(域名/品牌/知识库来源/系统提示词);换地基,只换一副适配器。核心 core 一个字不用动。这就是「可移植」的全部含义——你的系统不再是某一家云的人质。
实测更正一笔:此前项目内部文档一直写着「Node 适配器本地跑不了」。2026-07-13 我实际把它跑起来验证了:
TENANT=demo node server.js零安装依赖直接起,首页/检索/搜索/健康检查全部 200。文档那句是旧 note,已订正。真实AI_API_KEY下的端到端问答、sqlite-vec 在真实 VPS 上的编译、以及带 TLS/进程守护的正式部署,这三项还没验证——诚实标注,不吹成「已完成」。
六、优雅降级:小体量根本不需要重装备
这是整套设计里我最欣赏的一处工程克制,也是性价比的题眼。
「向量数据库」听起来是个必须专门部署的重家伙(Pinecone、Weaviate 那一档)。但自托管这副手做了件聪明事:启动时先试着装专业向量引擎(sqlite-vec);装不上,就自动降级——把所有向量读进内存,每次查询挨个算余弦。

关键在于规模拐点:
- 几十到几百条向量:内存暴力算,快得和专业向量库没区别。今天实测的 demo 站就走这条路,零依赖,照跑不误。
- 上万条起:暴力算开始线性变慢,这时才真正需要 ANN(近似最近邻)索引跳过大部分候选。
大多数现实场景落在左区。一个县志馆、一份地方报的历史存量、一本杂志的全部往期、一家咨询公司的案例库——通常就是几百到几千篇。为一个你永远到不了的规模,提前扛来一套分布式向量集群,是典型的过度工程。这套「装得上就用好的,装不上照样跑」的降级设计,把「你现在到底需要多重的装备」这个判断,交还给了真实的数据量,而不是交给焦虑。
七、撞墙之后:性能墙与精度墙怎么补
第六节讲了小体量根本不用重装备。可万一体量真涨上去(第六节那个拐点的右侧),或者内容天生就精确、答错有后果,怎么办?这里有两堵墙,性质截然不同——性能墙是纯工程问题,成熟套路一堆,且本架构自带解药;精度墙是「生成 + 近似」的固有属性,只能重压,不能根治。
性能墙:向量涨到十万、百万后怎么办
按性价比从高到低排,这些都是业界跑熟的标准手段:
| 方案 | 做什么 | 代价 / 在本架构里 |
|---|---|---|
| ① 分区 / 分租户预过滤 | 只搜相关分区(租户/品类/年款),不搜全库 | 几乎零成本;本架构天生分租户,等于白送——最先该用 |
| ② 换 ANN 索引(HNSW / IVF) | 把「挨个算」换成「跳着找」,百万向量也能亚 10ms | 约 95–99% 召回率;手 A(CF Vectorize)就是托管 ANN,core 一字不动直接毕业 |
| ③ 量化压缩(PQ / 二值化) | 向量瘦身:1024 维 float32=4KB,二值化砍到 128B(32×),距离算得飞快 | 精度略降,配「粗筛→精排」补回 |
| ④ 两段式检索 | 廉价粗筛(量化 / 低维 / ANN)选出前几百,再全精度精排 | 复杂度上升一层 |
| ⑤ 降维 / Matryoshka | 支持嵌套表示的模型可把 1024 维截到 256 维做首轮 | 召回略降,视 embedding 模型而定 |
| ⑥ 查询 / 语义缓存 | 高频问题缓存召回结果或整答案 | 省钱又降延迟 |
一条诚实提醒:自托管路径若用 sqlite-vec,它走的是精确暴力扫描(据我所知 2026 年仍无 ANN 索引,以最新版为准),规模天花板约在百万级、可接受延迟内;要再往上,得在 Node 侧换 pgvector(HNSW) / Qdrant / Milvus。换句话说,性能墙对本系统的标准解法就一句:单机扛不住时切到 CF 手 A——这正是双运行时设计的红利。
精度墙:别拿向量干精确活
关键认知——精度墙不是靠把向量做得更好来补的,而是「把精确的交给精确手段,把语义的交给语义」:
| 补法 | 做什么 | 专治 |
|---|---|---|
| ① 混合检索(向量 + BM25,RRF 融合) | 语义路捞「意思」,关键词路捞「M8×1.25」「第 47 条」这种一字不差的词 | 型号 / 编号 / 法条 / 药名 精确命中 |
| ② 结构化路由(表格不进向量库) | 建库时把规格表 / 参数抽进 SQL,查「扭矩多少」直接查表取精确值 | 数值 / 参数 / 规格 |
| ③ 交叉编码重排(bge-reranker 类) | 向量粗召 top-20,再用重排器把 query+段落一起读、精打分 | 压「召回了近义但错的段」 |
| ④ 抽取式回答 + 强制引用 | 逼模型原样引出那句 / 那个数并标源,答案里的数字须逐字出现于召回块,否则拒答 | 堵「检索对了、生成时把数字改写错」 |
| ⑤ 元数据过滤 | chunk 挂上车型 / 年款 / 章节标签,先过滤再检索 | 防「2021 款问出 2019 规格」 |
| ⑥ 结构感知切块 | 别把一张规格表拦腰切开,按标题 / 表边界切 | 保住表格上下文完整 |
| ⑦ 图表专门处理 | 图纸 / 爆炸图 → OCR+图注,或直接返回原图指向标号,不硬合成 | 诚实处理「看图才能答」的部分 |
但这里有条画不掉的设计边界:对真正安全关键的精确查询(扭矩、药物剂量、法条),上面全套压下来也无法保证「一个会改写文字的生成模型永远不出错」。终极正解不是让 RAG 生成那个数字,而是让它检索并原样呈现出处——把「说人话」降级为「精准找到并高亮」,把最终判断交还给人。这是设计边界,不是待修的 bug。
八、算总账:这套方案的性价比到底体现在哪
把技术架构翻译成钱和人力,分四个维度看。
| 维度 | 传统机构方案(Java + Oracle + Elasticsearch 集群) | 这套 RAG-on-edge 方案 |
|---|---|---|
| 初期开发 | 采购+集成多个系统,人月起步 | 一套内核 + 一张配置表,新站是「填表」不是「重写」 |
| 运维 | 专人管数据库/搜索集群/服务器 | 云托管路径近乎零运维;自托管也只有一台机器一个进程 |
| 扩展成本 | 加一个客户站 = 又一套部署 | 加一个客户站 = 加一个租户配置(多租户复用同一份 core) |
| 规模适配 | 起步就是重架构,小项目严重浪费 | 降级路径让小体量零额外成本,规模到了再上重装备 |
| 供应商锁定 | 绑死数据库/中间件厂商 | 双运行时:云账户和自建机器之间可迁移,不被单一云绑架 |
真正稀缺的不是其中任何单项——聊天机器人有更精致的 SaaS(Chatbase),静态站有更成熟的生态(Astro),法律语料有更深的垂类玩家(Harvey AI)。稀缺的是把「零依赖 + RAG 原生 + 双语 + 构建期清洗」这四件事,以近乎零边际成本捏在一起。这是大厂懒得做(体量太小不值当)、小工具懒得做(每项都要重新集成好几个 SaaS)的中间地带。
但要诚实说一句反面:这门生意的规模天花板不是技术决定的,是商业模式决定的。「代客户建站+运营、不做自助编辑后台」意味着每个客户都要真人投入一次——能服务的客户数是线性增长,不是 SaaS 那种边际成本趋零的指数曲线。技术再漂亮,也改不掉这条。
尾声:什么场景适合,什么不适合
一套系统的边界,比它的能力更值得说清楚。而画这条边界,第一件事是拆穿一个被反复误传的数字。

先纠一个错觉:「上千篇」根本不是天花板
坊间总说这类系统「撑死几千篇就到顶」。这句话把篇数当成了标尺,可篇数根本不是系统眼里的单位。系统眼里只有一样东西:向量条数。
一篇文章进库前会被切成若干块(chunk),每块约 300–600 字,各成一个向量。所以真正的标尺是这道换算:
向量条数 ≈ 总字数 ÷ 约 500 字
拿这把尺子量一量常被拿来试探边界的几个例子(字数为量级估算):
| 语料 | 量级字数 | 约合向量数 | 落在哪一档 |
|---|---|---|---|
| 一个博客/公众号全部存量 | 30–100 万字 | 数百–2 千 | 内存暴力算,秒回 |
| 王小波全集 | ~200 万字 | ~4–5 千 | 内存暴力算,秒回 |
| 研究型学者论文全集(两三百篇) | 150–300 万字 | 数千 | 内存暴力算,秒回 |
| 一部县志 / 一本杂志全部往期 | 100–300 万字 | 数千 | 内存暴力算,秒回 |
| 一部车的整套技术手册 | ~150 万字 | ~3–5 千 | 规模上毫无压力(但见下文「精度墙」) |
| 中小律所/咨询所案例+模板库 | 数百–数千篇 | 数千–数万 | 内存或 sqlite-vec,单机够 |
| 大型智库数十年全部报告 | 数千万字,且持续增长 | 十万级并上涨 | 逼近 ANN,且有「时效墙」 |
| 大型电商/新闻站 | 亿级字 + 天天变 | 百万级 | 必须专业向量基建 |
看出门道了:王小波全集、学者论文全集、整部车手册——这些听起来「很大」的东西,其实全挤在最左边那一档,几千个向量,内存里挨个算余弦都是毫秒级。「上千篇天花板」是个心理数字,不是技术数字。
而且技术天花板本身也被低估了。第六节说「上万条起变慢」是保守说法——那是把降级路径当成朴素解释型循环在算。若走 sqlite-vec(C 实现)或向量化内存算,单机扛到十万级向量(约合几千万字、约两百本书的纯文本)都还在可用延迟内。真正逼你上分布式 ANN 的,是百万级向量往上——那已是百科全书、全站新闻库那个量级,中小应用一辈子到不了。
结论一句话:规模这堵墙,对中小语料几乎不存在。 先撞上的从来是另外三堵。
真正先撞的三堵墙
规模够不着天花板,那什么会先劝退?按「先撞到」的顺序排:
| 墙 | 什么时候撞上 | 为什么 RAG 在这儿吃力 |
|---|---|---|
| ① 时效墙 | 内容天天改、要按「最新」排序 | 离线建库是重活,高频重建拖垮;语义相似度不认「谁更新」,新闻/智库/情报这类「新鲜度>相似度」的场景水土不服 |
| ② 精度墙 | 答案是精确数值/流程/表格,答错有后果 | 语义召回是「意思最近」,不是「一字不差」。扭矩规格、药物剂量、税率档位、法条编号——近似召回差一档就是事故。一部车手册规模上完全 OK,却栽在这堵墙:它要的是「螺栓拧多少牛·米」的确切数字和分步图解,不是「大意相近的一段话」 |
| ③ 聚合墙 | 问题要跨全库统计/计算 | RAG 只会「捞回最相关的几段」,不会「读完全部再算总账」。问「这批案例平均赔了多少」「近十年报告里出现最多的政策词」——这类聚合分析型问题,召回几段原文根本答不了 |
三堵墙背后是同一句话:RAG 擅长「在一堆确定的资料里,用人话问出定性的答案」,不擅长「求最新、求精确、求汇总」。(其中性能墙与精度墙怎么补,已在第七节展开;这里只谈「撞不撞得上」。)
横向对照:哪些中小场景天生合拍
把上面几把尺子合起来用(体量小 + 内容稳 + 要定性问答 + 答错不致命),下面这些中小应用几乎是量身定制:
| 场景 | 体量 | 契合点 | 要留神的地方 |
|---|---|---|---|
| 作家/学者全集问答(王小波、某教授论文集) | 几千向量 | 内容永不再改、语义检索正是文学/学术的强项 | 几乎无短板,是「最纯」的适配 |
| 县志/地方报/老杂志历史文库 | 数千向量 | 只增不改、变化极慢、双语加分 | 外部约束小,正文已点名 |
| 中小律所合同模板 / 咨询所案例库 | 数千–数万 | 「照着己方资料答、不许瞎编」刚需 | 责任敏感,须每句可点回原文 |
| 医院科室 SOP / 诊疗指南问答 | 数百–数千 | 内容权威、更新缓慢、问答刚需 | 精度敏感,只答「指南怎么说」不做诊断 |
| 政务办事指南 / 12345 知识库 | 数千 | 稳定、双语、要「照章说话」 | 政策变更时需重建,属可控低频 |
| 中小企业售后/产品知识库 | 数百–数千 | 客服照文档答,降人力 | 产品换代内容会变,属中频,尚可 |
| 企业内部 wiki / 员工手册 / HR 政策 | 数百–数千 | 员工自助问答,省 HR 重复答疑 | 政策会改,需配轻量重建流程 |
| 一门课程全部讲义 / 一套教材 | 数千 | 学生「问教材」,边界清晰 | 版本迭代时重建 |
| 播客/访谈全部转写库 | 随年增长但慢 | 「我记得哪期聊过 X」的模糊召回 | 增长虽持续但低频,长期观察向量数 |
| 经典/宗教文本库 | 数千–数万 | 文本永恒不变,语义检索天然适合 | 几乎无短板 |
而下面这些,不是规模问题,是「用错工具」问题,再漂亮的架构也是空转:
| 场景 | 撞哪堵墙 | 该用什么 |
|---|---|---|
| 一部车/一台设备技术手册的精确查询 | 精度墙 + 结构化 | 结构化检索 + 精确字段查询(表格/编号/图解本就不该塞进语义向量) |
| 新闻站 / 情报日报 / 舆情 | 时效墙 | 时序数据库 + 新鲜度排序 |
| 大型智库实时报告库 | 时效 + 聚合 + 规模 | 专业向量基建 + 时序 + 聚合层混合 |
| 电商/预订/购物车 | 根本不是问答系统 | 交易系统(正文已点名) |
| 「近十年数据统计/趋势」类分析 | 聚合墙 | 数据仓库 + BI,不是 RAG |
| 客户要自助天天发文改文 | 无编辑后台 | 带 CMS 的产品(正文已点名商业模式天花板) |
一句话收尾:语义检索 + RAG 不是万灵药,它把「在一堆确定的资料里,用人话问出准确答案」这件事做到了又准、又便宜、又不被云绑架。天花板不在「几千篇」——中小语料几乎撞不到规模墙;先劝退你的,永远是「内容改不改、答案精不精、要不要算总账」这三问。三问都答『否』,它的性价比碾压老式方案;但凡有一个『是』,再漂亮的架构也是空转。
本文技术判断基于 2026-07-13 对 tryway.cc 背后 Praxis 系统真实生产代码的实测与调研。凡「实测」均已在本机复现;凡「未验证」均如实标注,不以推测充结论。