为什么结构化输出之后要学 Embedding
路线12章中的位置
本章目录
阅读过程中可按 Ctrl + Z 快速返回当前页面的本章目录;也可以点击右下角按钮。
本章思维导图
知识流向:先完成左侧基础,再进入中间机制,最后用右侧工程控制把它变成可上线能力。节点可直接点击跳转。
Embedding基础
按照本模块顺序完成以下知识点,再进入下一模块。
E00在线语义检索的组件链路
用户问“鞋子不合适怎么退钱”时,常见 RAG 查询包含两类不同模型调用,职责不能混淆。
问题→向量
找相似片段
资料+问题→答案
校验并展示引用
| 组件 | 输入 | 输出 | 不会做什么 |
|---|---|---|---|
| Embedding 模型 | 问题或文档片段 | 固定长度数字数组 | 不回答问题、不判断政策是否生效 |
| 向量数据库 | 查询向量和过滤条件 | Top-k 候选片段 | 不写最终回答、不保证候选一定正确 |
| 聊天模型 | 问题、规则、召回原文 | 给用户阅读的回答 | 不能获得没放进上下文的公司资料 |
离线与在线:文档上传时批量做一次 Embedding;用户每次提问时只给“问题”做 Embedding。不是每次提问都重新向量化整套知识库。
E01Embedding 解决的核心问题
知识库里有一句:“商品签收后七日内可以申请退款。”用户却问:“东西不合适,怎么把钱退回来?”传统关键词搜索可能找不到,因为用户没有输入“申请退款”;但人知道“把钱退回来”和“退款”意思接近。
申请退款
文字变数字坐标
把钱退回来
发现语义接近
核心:Embedding不是生成答案,而是给文字制作“语义坐标”,让程序可以用数学方式比较两段文字是否接近。
E02Embedding在系统哪里、由谁调用
Embedding通常是一个专门的模型API。开发者的后端程序把文本发给Embedding模型,模型返回固定长度的数字数组。
embedding_response = Embedding客户端.创建(
model = "某个 embedding 模型",
input = "商品签收后七日内可以申请退款"
)
vector = embedding_response.vector| 问题 | 答案 |
|---|---|
| 谁调用? | AI应用的后端程序 |
| 在哪里调用? | 文档入库时,以及用户搜索时 |
| 输入是什么? | 一段文字,有些模型也支持其他内容 |
| 输出是什么? | 固定长度的浮点数数组,也叫向量 |
| 它会回答问题吗? | 不会。它只把内容编码成坐标 |
E02-AEmbedding 模型的工作对象
它是经过训练的神经网络模型,但任务与聊天模型不同:聊天模型接收文字后生成文字;Embedding模型接收文字后输出固定数量的小数。
聊天模型
输入:退款多久到账? 输出:通常三个工作日内到账。
Embedding模型
输入:退款多久到账? 输出:[0.018, -0.227, 0.641, ...]
训练时,系统用大量相关和不相关文本调整网络参数,让意思相关的文本向量靠近,让不相关文本向量远离。这类思路常称为对比学习或相似度学习。
需要懂多深?高级AI应用工程师必须会选模型、调用、批处理、理解维度和相似度、保持文档与查询模型一致、做召回评测和处理迁移。初期不必推导全部矩阵公式,也不必从零训练模型。
E02-BEmbedding 调用过程
// 通用伪代码,实际名称按厂商SDK为准 client = 创建AI客户端(api_key = 服务器密钥) result = client.embeddings.create( model = "某个embedding模型", input = ["退款将在三个工作日内返回", "七日内可申请退货"] ) vector_1 = result.data[0].embedding
入库几万片段时通常批量调用。超时或429要有限重试和退避;文本过长先切块;批量任务要记录每批成功/失败并支持续跑。
E03向量的数据形态
[0.018, -0.227, 0.641, 0.093, -0.412, ...]
这串数字就是向量。真实Embedding可能有几百、上千甚至更多个数字。数字的个数叫“维度”。
二维坐标
地图上的商店可以用经度、纬度两个数字定位,所以是二维。
高维语义坐标
语言包含主题、意图、对象、语气、关系等大量特征,需要许多数字共同定位。
不要逐位翻译:通常不能简单说第1个数字代表“退款”、第2个代表“情绪”。语义由整个高维向量的组合、方向和相对位置共同表达。
E04用二维地图想象高维空间
图中意思相近的句子落在相近区域。真实空间不是二维平面,而是人无法直接画出的高维空间;二维图只是帮助形成直觉。
相似度检索
按照本模块顺序完成以下知识点,再进入下一模块。
E05文档和问题必须各做一次Embedding
文档入库阶段
存入数据库
通常在文档新增或变化时执行,不必每次搜索都重算全部文档。
用户查询阶段
每次新问题到来时生成,再去数据库寻找相近文档向量。
先把“书”放到地图上 → 再把“问题”放到同一张地图 → 寻找附近的书
E06Embedding 模型兼容性
假设文档用模型A生成向量,查询却改用模型B。两种模型建立的坐标系可能完全不同,就像一个人使用北京地铁图,另一个人却拿纽约地铁坐标找站点。
文档向量:模型 A 查询向量:模型 B 直接比较
维度可能不同;即使维度相同,空间含义也可能不同。
文档向量:模型 A 查询向量:模型 A 在同一向量空间比较
升级Embedding模型时,通常需要给文档重新生成向量并重建索引。
E07向量相似度计算
最常见的方式之一是余弦相似度。它重点比较两个向量的“方向是否接近”,而不只是比较长度。
文档向量 A = [0.2, 0.8, 0.1, ...] 查询向量 B = [0.18, 0.76, 0.12, ...] cosine_similarity(A, B) → 0.93
分数越高通常代表语义越接近,但具体范围、距离定义和阈值要看Embedding模型与向量数据库配置。
余弦相似度
比较方向,语义检索中很常见。
点积
计算快,部分经过训练或归一化的模型推荐使用。
欧氏距离
比较空间中的直线距离,数值越小通常越近。
选择原则
遵循Embedding模型和向量数据库的官方建议,不要随意混用。
E08从相似度到Top-k结果
向量数据库会给大量文档片段计算近邻,取最相似的前k条。top_k=3表示最多先取3个候选,不代表这3个一定正确。
| 排名 | 候选片段 | 示意相似度 |
|---|---|---|
| 1 | 退款将在三个工作日内原路退回 | 0.91 |
| 2 | 签收七日内可提交退货申请 | 0.86 |
| 3 | 退款失败时请联系人工客服 | 0.79 |
相似度分数不是正确率。0.91不等于“91%肯定能回答”,也不能跨模型、跨数据集机械使用同一个阈值。
E09关键词检索与语义检索
| 关键词检索 | 语义向量检索 | |
|---|---|---|
| 擅长 | 精确词、订单号、型号、专有名词 | 同义表达、口语改写、意思接近 |
| 例子 | 精确寻找“A10086” | “退钱”找到“退款政策” |
| 弱点 | 文字不同可能漏掉 | 精确编号可能被语义稀释 |
| 常用方案 | 混合检索:关键词和向量各自找候选,再合并与重排序 | |
高级RAG通常不会迷信单一路线。订单号用关键词非常可靠,而自然语言问题适合语义检索,两者结合更稳。
数据库与工程边界
按照本模块顺序完成以下知识点,再进入下一模块。
E10相似不等于正确
可能过期
旧退款政策和新政策语义都很接近。
可能越权
另一个部门的机密文档也可能很相似。
可能只沾边
“退款时间”与“退货条件”相关,却不是同一答案。
可能没有答案
最相似的候选只是“最不差”,并不代表足够回答。
E10-A新旧政策不会由Embedding自动判断
新旧政策措辞通常很接近,所以向量也很接近。Embedding不知道今天日期、哪个版本已作废,也没有权限替公司决定使用哪份。
旧政策:退款7天到账 新政策:退款3个工作日到账 → 两份一起检索,让大模型自己选
先按metadata过滤有效版本 → 只在当前有效且有权限的资料中 进行向量搜索
{
"policy_id": "refund-policy",
"version": 3,
"status": "active",
"effective_at": "2026-09-01",
"expires_at": null,
"tenant_id": "company-a"
}查询时先固定过滤:租户等于当前用户所属公司、状态为active、生效时间不晚于现在、失效时间为空或晚于现在;满足后才进行Top-k。
版本和有效期
冲突保护:过滤后如果同一政策仍有两个有效版本或内容冲突,停止自动回答并报警/转人工,不能让模型猜。
E10-B检索与回答错误的处理
| 现象 | 检查 | 修复 |
|---|---|---|
| 召回旧政策 | 版本、status、有效期 | 停用旧向量,修metadata与过滤 |
| 有效政策没召回 | 解析、切块、入库、Top-k | 重切块、补入库、调召回 |
| 正确资料排得低 | 融合排序和Rerank | 调整权重或重排序 |
| 资料正确但答案错 | Prompt和生成模型 | 强化引用、拒答和生成约束 |
日志保存request_id、问题、Embedding模型版本、过滤条件、召回片段和政策版本、相似度、Rerank分数、最终引用与答案。修复后把错误案例永久加入评测集。
E10-C向量记录与 Metadata 的存储权衡
准确说法是:每个可检索文档片段通常是一条数据库记录,里面有一个向量和少量必要字段。不是向量里的每个小数都附一份信息,也不是每个片段复制整份原始文档。
{
"chunk_id": "refund-v3-002",
"vector": [0.018, -0.227, 0.641, ...],
"text": "退款通常在三个工作日内原路返回。",
"policy_id": "refund-policy",
"version": 3,
"status": "active",
"tenant_id": "company-a",
"source": "refund-policy.pdf#page=2"
}向量
负责语义距离,通常是记录中占空间较大的部分。
片段文本
找到后交给大模型;也可只存文本ID,再去文档库读取。
Metadata
少量字段,用于权限、版本、有效期和来源过滤。
原始文档
通常独立保存,不在每条向量中复制整个PDF。
举例:1536维向量如果每个数字按4字节保存,向量本体约6KB;几项短metadata常只是几百字节量级。这里只是帮助理解,真实大小取决于维度、数据类型、文本、索引和压缩。
1536 × 4字节 ≈ 6KB | 必要metadata通常只是额外的一小部分
为什么过滤还可能更快
索引快速过滤
有效的10万条
做向量搜索
常用metadata字段会建立标量索引或倒排索引,程序不是逐条读取再判断。预过滤先快速缩小范围,通常同时提升安全性、准确率和速度;不同数据库也可能采用搜索中融合过滤或搜索后过滤,需要真实压测。
| 应该保存 | 不应随便重复保存 |
|---|---|
| tenant_id、权限标签、status、版本、有效期、source、chunk_id | 整份PDF、巨大无用对象、从不查询的重复说明、敏感信息副本 |
真正的权衡:metadata不是越多越好;只保存过滤、追踪和审计所需字段,也只给经常过滤的字段建索引,因为索引会占空间并增加写入成本。
E10-D这是行业常规吗:不同数据库只是叫法不同
是主流做法,但不应说成“每个向量必须有一段说明”。更准确的数据模型是:一条记录有唯一ID、一个或多个向量,以及可选的结构化附加字段。
| 数据库 | 记录名称 | 附加信息名称 |
|---|---|---|
| Qdrant | Point | Payload |
| Milvus | Entity | Scalar fields / JSON field |
| Pinecone | Record | Metadata |
| Weaviate | Object | Properties |
唯一ID 向量(相似度搜索) 可选字段(过滤、展示、追踪或回查原文)
附加字段并非强制都有。纯图片相似搜索可以只存image_id和vector;企业RAG通常需要租户、权限、来源和版本,否则难以安全上线。
向量库同时存片段文字
一次查询直接取得原文,实现简单,适合常见RAG。
向量库只存引用ID
先返回chunk_id,再去文档数据库取正文,减少复制但多一次读取。
没有绝对统一:正文同库存还是外部存,要看规模、一致性、延迟、权限和数据库能力;但“向量记录关联ID及必要业务字段”是常规设计。
官方参考:Qdrant · Milvus · Pinecone · Weaviate
E10-E文档数据库的职责与选型
先纠正:向量数据库和文档存储不一定分开。“文档数据库”在这里是泛称,指保存原始文件、正文片段、版本和权限等权威内容的地方,不是说必须使用某个名叫“文档数据库”的产品。
对象存储:S3 / MinIO等
适合保存原始PDF、Word、图片和网页快照。便宜、容量大,但不适合直接做复杂字段查询。
关系数据库:PostgreSQL等
适合保存document、chunk、版本、权限、状态和更新时间;事务与一致性强。加pgvector后还能同时存向量。
文档型数据库:MongoDB等
适合保存结构变化较多的JSON文档、解析结果和metadata。
搜索引擎:Elasticsearch / OpenSearch
适合全文关键词、筛选、聚合和混合搜索,也可具备向量搜索能力。
最容易理解的分工
对象存储
PostgreSQL/MongoDB
向量数据库
把它们关联起来
documents表: document_id, 文件名, 原始文件地址, 版本, 状态, 权限 chunks表: chunk_id, document_id, 片段正文, 页码, 标题 向量记录: chunk_id, vector, tenant_id, status
也可以完全不分开
| 架构 | 适用场景 | 例子 |
|---|---|---|
| 一个数据库全放 | 小中型系统、团队希望简单维护 | PostgreSQL保存正文和metadata,pgvector保存向量 |
| 向量库带正文 | 普通RAG、查询后希望直接返回片段 | 向量记录的payload/properties中保存chunk文本 |
| 原文与向量分开 | 大量原始文件、复杂版本权限、多个检索系统共享正文 | S3+PostgreSQL+专用向量数据库 |
为什么分开?不是因为技术规定,而是不同存储擅长不同任务:对象存储擅长放大文件,关系数据库擅长管理版本权限和事务,向量数据库擅长近邻搜索。
分开的代价:必须保证同步一致。删除文档时要同时处理原文件、片段和向量;因此需要稳定的document_id/chunk_id、任务状态、重试和对账。初学项目会优先使用较简单的一体化方案,理解后再拆分。
E10-F向量数据库的类型
“向量数据库”不是只有一种产品。以下分类比死记品牌更重要,因为同一个产品可能同时跨越两类。
① 关系数据库加向量扩展
代表:PostgreSQL + pgvector。在原有PostgreSQL表里增加vector字段,正文、权限、版本和向量可以一起管理。
② 专用向量数据库
代表:Qdrant、Milvus、Weaviate。从设计上重点解决大量向量的存储、索引、过滤和近邻搜索。
③ 全托管向量服务
代表:Pinecone,以及各产品的Cloud版本。服务商负责服务器、扩缩容和维护,应用通过API使用。
E10-G常见向量数据库产品
| 产品 | 它到底是什么 | 适合什么情况 | 主要代价 |
|---|---|---|---|
| pgvector | PostgreSQL扩展,不是独立数据库;支持精确和近似向量搜索,以及HNSW、IVFFlat等索引 | 团队已经使用PostgreSQL;数据规模中小;希望正文、权限、事务和向量放一起 | 极大规模和复杂向量专用调优通常不如专门系统直接;需要自己管理PostgreSQL性能 |
| Qdrant | 专用向量数据库;记录叫Point,附加信息叫Payload;支持Payload过滤、密集/稀疏/多向量 | 企业RAG、权限过滤、希望API直观;可自建也可使用Cloud | 比复用现有数据库多维护一个系统;索引和资源仍需规划 |
| Milvus | 面向高性能和大规模的开源向量数据库;有Lite、Standalone、Distributed多种部署形态 | 向量数量非常大、吞吐高、多租户、需要分布式扩展和多种索引 | 分布式形态组件多、运维复杂;小项目一开始可能过重 |
| Weaviate | 对象+Properties+向量的数据模型;可集成向量化模块,支持关键词、向量和混合搜索 | 想要一体化语义搜索、混合搜索、对象属性和较完整开发体验 | 需要理解其集合、模块、向量化和部署方式;可能产生平台绑定 |
| Pinecone | 面向开发者的托管向量服务,通过API管理Record、向量和Metadata | 不想维护集群,希望快速上线并让服务商负责扩缩容 | 持续云费用、网络依赖、数据合规和厂商锁定需要评估 |
| Elasticsearch / OpenSearch | 全文搜索引擎,同时支持向量字段、KNN和混合检索 | 关键词、编号、筛选、聚合很重要;公司已经有搜索集群 | 部署和调优并不轻;只做简单向量搜索时可能显得复杂 |
| Redis | 高速数据平台,Redis Search可以在Hash/JSON中索引向量和Metadata | 低延迟、实时数据、语义缓存、Agent记忆,或团队已有Redis | 内存成本与持久化设计要认真考虑;不一定适合作为所有文档的唯一权威存储 |
E10-H企业客服数据库选型
选型不是“谁最火” = 现有技术栈 + 数据规模 + 检索类型 + 权限过滤 + 运维能力 + 成本合规
E10-I用一份退款政策对比实际存法
PostgreSQL + pgvector
knowledge_chunks表: chunk_id text tenant_id version status embedding vector
一张表直接过滤和向量排序,结构最容易理解。
Qdrant
Point:
id = chunk_id
vector = embedding
payload = {
text, tenant_id,
version, status
}Point里的Payload负责过滤和返回正文。
Elasticsearch
Document: text 字段做关键词搜索 dense_vector 做向量搜索 tenant/status 做过滤
适合把关键词与向量结果融合。
向量与正文分离
向量库:chunk_id + vector PostgreSQL:chunk_id + text 对象存储:原始PDF
职责清晰,但必须维护三处数据一致。
我们的学习顺序:不会一上来同时搭七种数据库。先用一体化方案完成RAG全链路,再选择Qdrant做一次专用向量库迁移对比;这样既掌握原理,也能看懂不同产品。
官方参考:pgvector · Qdrant · Milvus · Weaviate · Elasticsearch · Redis
E10-JRedis 的定位与适用场景
Redis不是AI模型,也不是只为向量设计的数据库。它通常作为一个独立运行的高速数据服务,数据主要在内存中处理,所以读写很快。多台后端程序都可以通过Redis客户端访问同一份临时或热点数据。
高速读写
权威数据库/API
最基础的Key-Value理解
写入: SET session:user-10086 "logged-in" 读取: GET session:user-10086 设置10分钟后自动过期: SET verification:138xxxx "482913" EX 600
Key像储物柜编号,Value是柜子中的数据。TTL表示到期自动删除,适合验证码、临时会话和缓存。
① 缓存
把刚查询过的商品、配置或模型结果临时保存。下次相同请求直接读取Redis,减少数据库或模型调用。
② 登录会话
保存session_id对应的用户身份和过期时间,让多台服务器都知道用户是否登录。
③ 限流计数
记录某用户一分钟请求次数,超过上限返回429,保护模型额度和后端服务。
④ 任务状态
长时间AI任务保存queued/running/succeeded/failed以及进度,前端可以轮询查看。
⑤ 队列与消息
把“待生成Embedding”“待处理文档”等任务交给后台工作进程,避免用户一直等待。
⑥ 分布式协调
多台服务器共同工作时,用计数、锁或原子操作避免同一任务被重复执行。
Redis在AI客服里的位置
用户请求 ├─ 限流:一分钟最多请求多少次 ├─ 会话:当前对话ID和临时上下文 ├─ 普通缓存:同一政策查询结果 ├─ 语义缓存:意思相近的问题复用结果 ├─ 任务状态:文档解析/Embedding进度 ├─ Agent临时状态:工具执行到哪一步 └─ 向量搜索:可选能力,不是Redis唯一用途
普通缓存与语义缓存
普通缓存
问题文字完全相同或缓存Key相同时命中。
“退款多久到账?” = 完全相同 → 复用答案
语义缓存
先做Embedding,意思足够接近时考虑复用。
“退款多久到账?” ≈ “钱什么时候退回来?” → 可能复用
语义缓存有风险:用户身份、订单、政策版本或时间不同,即使问题相似也不能直接复用。缓存Key或过滤条件必须带tenant、权限、政策版本等信息;高风险个性化答案通常不应盲目缓存。
Redis会不会断电丢数据
Redis可以配置快照或追加日志做持久化,也能做复制和高可用,但它的核心优势仍是速度。是否会丢、能丢多少、恢复多快取决于持久化和集群配置。订单、余额等权威事实通常仍放PostgreSQL/MySQL等主数据库,Redis只保存缓存或可恢复状态。
| 适合放Redis | 不应只放Redis |
|---|---|
| 缓存、会话、限流计数、临时任务状态、可重建向量、短期记忆 | 唯一订单记录、唯一账户余额、不可重建的核心业务事实(除非经过专门持久化架构设计) |
Redis = 高速共享工作台 | 主数据库 = 权威档案室
缓存失效:政策更新后必须删除或更换旧缓存版本,否则即使RAG知识库已经更新,Redis仍可能返回旧答案。真实系统通常使用TTL、版本号和主动失效共同控制。
E11Embedding 模型选型
不能只看排行榜:最终要用自己的文档、用户问法和正确答案做召回评测。通用排行榜高,不保证在你的公司缩写和业务术语上最好。
E12完整语义检索链路
文档侧: 文档 → 切成片段 → 调Embedding API → 得到向量 → 保存原文、向量、metadata 查询侧: 用户问题 → 调同类Embedding API → 查询向量 → 向量数据库近邻搜索 → 权限/版本过滤 → Top-k候选 → Rerank → 交给大模型回答并引用
Embedding负责做坐标 | 向量数据库负责找附近 | Rerank负责精排 | LLM负责阅读候选并回答
本章先建立坐标与检索直觉;下一章会把真实文档怎样采集、解析、切块、写入向量数据库和持续更新完整串起来。
本章总结:从哪里来,解决什么,为什么继续
下一章
第04课:RAG数据工程
从原始PDF、网页和数据库开始,详细讲文档采集、解析、清洗、切块、metadata设计、向量入库、增量更新、删除和版本管理。
专题Embedding 模型与 Milvus 实战
如果你想继续弄清“具体有哪些 Embedding 模型、Milvus 内部结构、Windows 如何部署、怎样用 Python 建库和带权限检索”,请先阅读这个专题,再进入第04章。