Day9 学习日志:Embedding 与向量数据库

0 阅读5分钟

Day9 学习日志:Embedding 与向量数据库

📅 日期:2026-03-25
📌 定位:在「三国演义」语料上跑通 本地 Word2VecDashScope 文本向量 API 两条链路,理解 词级 vs 段级 表示,以及 Embedding 与向量索引在 RAG 链路中的位置;能把 问句 接到各自的检索方式上,并复盘 切块与额度 等工程坑。


一、语料与目录约定(和 PathLineSentences 的关系)

  • 原文data/课程练习/source/{语料名}/ 下各文件。
  • 分词结果:写在 segmented/{语料名}/,与 source 同级(不要放在 source/.../segmented),避免 PathLineSentences 把未分词正文和分词行混在一起读。
  • Word2Vec 模型vectorModels/{语料名}/{语料名}_word2vec.model
  • Gensim model.save:参数必须是 字符串路径 或带 write 的文件对象;传 pathlib.Path 会在内部 .endswith 等处报错。

二、Word2Vec:词表、most_similar 与「句子查询」

  • wv.most_similar("曹操"):只接受 词表里存在的 token;不能把整句当作一个词 key(会 KeyError)。
  • 想用「句子 / 问句」在词向量空间里找近邻词jieba 分词 → 过滤 OOV → 对剩余词向量 取平均wv.similar_by_vector。练习里封装为 similar_words_for_sentence
  • 局限:得到的是与句向量方向接近的 ,不是「另一段原文句子」排序;句对段 检索更适合下面的 API 向量库或 Doc2Vec。

类比任务demo_query_changban_adou_similarity 与 API 侧同名函数使用同一问句 「谁在长坂坡救了阿斗?」,便于两条路线对照(默认不在 __main__ 里自动调用)。


三、DashScope Text Embedding:批量建库、本地复用与 TopK

  • 建库:枚举语料目录下文件 → 长文按字符上限 切块 → 分批 TextEmbedding.call → 默认 pickle 写入 vectorModels/{语料名}/{语料名}_API.model(脚本:embedding_API_pickle.py)。
  • embeddings 结构output["embeddings"]列表,每项含 embedding(浮点向量)text_index;取单条输入的向量用 [0]["embedding"]
  • skip_if_exists:本地已有 *_API.model跳过重新编码,省 API;但对 新问句 做相似度仍要对 query 再调一次 Embedding(除非自行传入已算好的 query_vector)。
  • 检索:对 query 与库中各块向量算 余弦相似度,取 TopK;条目里可带 snippet 便于肉眼扫结果。

额度(403 / AllocationQuota.FreeTierOnly:免费额度用尽时需在控制台关闭「仅使用免费额度」或开通按量付费;脚本可对失败信息做 中文说明,并用 本地第一条语料向量离线 TopK 演示(不调 API)。开发阶段应 避免对同一语料反复全量重算,优先复用本地 *.model / *.faiss已有本地模型时务必 skip_if_exists=True 以免无谓请求。


四、从 Pickle 到 FAISS:索引与元数据分工

  • 直观理解:Embedding 把语义压进高维向量;检索是在向量空间里找「近邻」,再靠 id 找回原文。LLM 负责理解与生成;向量库 + 元数据负责「索引 → 查 id → 拼进上下文」。
  • 练习中的落盘形态
    • Pickle{语料名}_API.model(向量与条目一锅端,便于起步)。
    • FAISS{语料名}_API_FAISS.faiss(二进制索引)+ {语料名}_API_FAISS.meta.jsonfile / chunk_index / snippet 等,不含向量);可从 pickle 迁移建索引,无需再调 Embedding。
    • FaissVectorStorefaiss_vector_store.py):封装 索引 + 与 id 对齐的 items,提供 save / load / search
  • 工程上常见组合FAISS(或同类 ANN)管快速近邻JSON / SQLite 管 id → 原文与业务字段

五、检索踩坑与参数教训(与切块强相关)

5.1 语义稀释(chunk 过大)

  • 现象max_chars_per_chunk 很大(例如 3500)时,搜「桃园结义」可能排到与主题无关的段落(核心情节被同块里的序言、史论等 冲淡)。
  • 理解:一块里信息太多时,单条向量更像整块的「平均语义」,难以对齐短查询的「特写」。
  • 做法:把单块 缩小(练习中曾调到约 500 字量级)可显著改善「对准某一情节」的召回;代价是 块数变多、建库 API 次数与存储增加,需在成本与效果间平衡。

5.2 语义断层与「强行匹配」

  • 现象:搜「谁在长坂坡救了阿斗」却排到 姜维 等段落。
  • 理解:若 语料里根本没有对应回目(节选、删节),RAG 无法召回到不存在的内容;此时向量检索仍会返回 相对最近 的块(例如同样有「救人」「落马」等表面相近叙述),容易 误导
  • 做法:生产上宜设 相似度阈值,分数过低时宁可回答 未知,并保证 语料覆盖 与问题域一致;可再叠加 关键词 / 混合检索 稳住专名。

5.3 查询太短

  • 只输入 「赵云」 等极短查询时,向量方向 含糊,TopK 容易飘到泛化的「武将、征战」段落;完整问句 通常更稳。

六、两条路线怎么选(心里要有数)

维度Word2Vec(本地)文本 Embedding API
粒度整段 / 切块文本
典型查询单词近邻、加减类比问句 → 与语料块相似度
依赖分词语料、训练时间网络、Key、配额
离线训练后可完全本地库可离线读;新 query 一般仍要联网

七、遗留与后续可做

  • Word2Vec 句向量 仅用平均词向量是基线;可了解 加权(TF-IDF)Doc2Vec、或多语言 句向量模型 与 RAG 里 chunk / overlap 策略。
  • API 侧 text_type(query / document)、切块与 overlap 对排序的影响,可在有额度时做小实验。
  • 数据:用更完整、对齐问题域的文本测全量检索与压力。
  • Query:白话问句 改写为古籍高频关键词(可借助 LLM)以提升专名召回。
  • Rerank:引入重排序,缓解仅向量相似带来的 表面字词或场景混淆

八、相关文件(便于回跳)

  • data/课程练习/Embeddings和向量数据库/embedding_Word2Vec.py
  • data/课程练习/Embeddings和向量数据库/embedding_API_pickle.py(原 pickle 建库与 TopK)
  • data/课程练习/Embeddings和向量数据库/embedding_API_FAISS.py(FAISS 建库 / 检索)
  • data/课程练习/Embeddings和向量数据库/faiss_vector_store.py(FAISS + 元数据封装类)
  • 语料与产物:source/segmented/vectorModels/(含 *.model*.faiss*.meta.json 等,均在 data/课程练习/ 下)

九、小结

前端往往追求 像素级确定;检索与生成链路更多是在 概率与阈值 上做权衡——同一套代码,换 chunk 大小或语料覆盖,结果可从「看似胡扯」变为「基本可用」。Day9 把这条因果链从目录结构一直拉到了 额度、本地复用与 FAISS 落盘,便于以后接正式向量库与 RAG 时少踩重复坑。