<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Embedding on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/embedding/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Fri, 28 Aug 2026 10:00:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/embedding/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>Netflix MAPS 笔记：让推荐模型「看见」素材，冷启动就不冷了</title>
      <link>https://ftmao.com/blog/posts/netflix-maps-multimodal-personalization/</link>
      <pubDate>Fri, 28 Aug 2026 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/netflix-maps-multimodal-personalization/</guid>
      <description>&lt;h1 id=&#34;netflix-maps-笔记让推荐模型看见素材冷启动就不冷了&#34;&gt;Netflix MAPS 笔记：让推荐模型「看见」素材，冷启动就不冷了&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;原文：&lt;a href=&#34;https://netflixtechblog.com/maps-netflixs-multimodal-asset-personalization-at-scale-32f96320785e&#34;&gt;MAPS: Netflix&amp;rsquo;s Multimodal Asset Personalization at Scale&lt;/a&gt;
目标读者：做推荐、搜推广或 AI 应用的工程师，尤其是被冷启动、离线线上不一致折磨过的人。
阅读目标：搞清楚 Netflix 怎么用多模态向量把素材个性化的冷启动问题「绕」过去，以及那套消融实验和代理任务的方法论为什么值得抄。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;问题本身素材是个不透明的-id&#34;&gt;〇、问题本身：素材是个不透明的 ID&lt;/h2&gt;
&lt;p&gt;Netflix 把海报、视频预览这些视觉线索统称为素材（asset），给每个会员挑哪张海报，本身就是一个个性化问题。老模型回答「老标题挑哪张图」回答得很好，但「新标题刚上线怎么办」回答得很差：模型只从历史交互里学习，每张素材在它眼里只是一个不透明的 ID，图里画了什么人、什么色调，它一概看不见。于是新剧上线时素材没有任何历史，只能加大探索流量去「刷数据」，其余时候退回人气启发式——完全不认你的口味。这就是教科书式的冷启动。&lt;/p&gt;
&lt;p&gt;原文的解法一句话：&lt;strong&gt;让模型看见并听见它要推荐的东西&lt;/strong&gt;。新素材一到手就有向量，而向量空间已经承载了会员对相似素材的偏好，所以个性化在接近上线的那一刻就能启动，不用等交互慢慢堆出来。&lt;/p&gt;
&lt;h2 id=&#34;一海报个性化让模型看图&#34;&gt;一、海报个性化：让模型看图&lt;/h2&gt;
&lt;p&gt;做法直接到近乎朴素：用预训练的 CLIP 把每张海报编码成一个 768 维向量，和素材原有的可学习 ID 向量&lt;strong&gt;拼接&lt;/strong&gt;，作为素材的最终表示。就这一个改动。&lt;/p&gt;
&lt;p&gt;效果的关键在于迁移：会员对「某位喜剧演员的脸」「某种配色」的偏好，本来写在图片向量空间里而不是绑死在素材 ID 上，所以新剧海报一编码完，这些偏好立刻生效——哪怕这张图从没给任何人展示过。冷启动从盲区变成了「向量空间对此早有意见」。&lt;/p&gt;
&lt;h2 id=&#34;二五个模型合成一个&#34;&gt;二、五个模型合成一个&lt;/h2&gt;
&lt;p&gt;第二个收益更工程化。同一部剧的海报要铺到五个画布上（billboard、vertical-box、horizontal-panel、short-panel、landscape-panel），裁剪比例各不相同。ID 时代的模型不知道这些裁剪图是同一幕戏，信号无法在画布之间流动，于是历史上每个画布各训一个模型，各自承受各自的冷启动。&lt;/p&gt;
&lt;p&gt;CLIP 向量对裁剪、缩放、宽高比基本不变，同一幕戏的五个版本映射到几乎同一个向量——壁垒没了，五个模型合成一个，高流量画布学到的偏好立刻灌溉稀疏画布。收益最大的恰恰正是数据最少的画布。&lt;/p&gt;
&lt;p&gt;合并带来一个新问题：五个画布的曝光量天差地别，直接按原始计数混训，高流量画布和高频交互类型会淹没一切，本想帮扶的稀疏画布反而最吃亏；手工调权重又换来一堆拍脑袋超参。Netflix 的做法是&lt;strong&gt;奖励加权&lt;/strong&gt;：每条训练样本按其交互类型的长期奖励分（来自 Netflix 既有的长期奖励建模）加权。交互类型在各画布分布不均，按长期价值加权之后，画布配比自动重平衡——画布按「它驱动的交互的长期价值」贡献梯度，而不是按曝光量。没有手工权重，模型优化目标从「最高频的短期动作」换成了「长期会员满意度」。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    IMG[&amp;#34;新海报上线&amp;#34;] --&amp;gt; CLIP[&amp;#34;CLIP 图像编码器&amp;lt;br/&amp;gt;输出 768 维向量&amp;#34;]
    ID[&amp;#34;素材 ID 向量&amp;#34;] --&amp;gt; CONCAT[&amp;#34;拼接成素材表示&amp;#34;]
    CLIP --&amp;gt; CONCAT
    CONCAT --&amp;gt; MODEL[&amp;#34;统一模型&amp;lt;br/&amp;gt;五个画布共享&amp;#34;]
    HOT[&amp;#34;高流量画布&amp;lt;br/&amp;gt;billboard 等&amp;#34;] --&amp;gt;|&amp;#34;交互信号沿向量空间迁移&amp;#34;| MODEL
    MODEL --&amp;gt;|&amp;#34;长期奖励加权混训&amp;#34;| SPARSE[&amp;#34;稀疏画布直接受益&amp;lt;br/&amp;gt;short-panel 等&amp;#34;]
    style MODEL fill:#fff3cd
    style SPARSE fill:#e8f5e9&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h2 id=&#34;三离线评估ips-与探索流量&#34;&gt;三、离线评估：IPS 与探索流量&lt;/h2&gt;
&lt;p&gt;这套结果能信，前提是评估干净。用当前线上策略的日志评估新模型是有偏的：线上策略偏爱某些素材，日志记录的是「策略选了什么」，不是「会员从全集里会选什么」。和线上策略意见不合的新模型会被冤枉——它会挑的曝光在日志里几乎不存在。&lt;/p&gt;
&lt;p&gt;Netflix 用一小股&lt;strong&gt;随机探索流量&lt;/strong&gt;做 IPS（逆倾向评分）：随机策略按已知分布在候选素材里采样，倾向分在服务时刻精确记录，而不是事后估计。每条观测按倾向分的倒数加权，被探索流量压稀的曝光得到相应抬升，得到候选策略的无偏奖励估计。原文有句话值得划线：&lt;strong&gt;倾向分由构造保证已知而非事后建模，是离线数字能跟踪线上结果的最大单一原因。&lt;/strong&gt; 候选模型必须在 IPS（相对线上基线的比值）上先赢，才配拿 A/B 流量。&lt;/p&gt;
&lt;h2 id=&#34;四消融实验两个成分缺一不可&#34;&gt;四、消融实验：两个成分缺一不可&lt;/h2&gt;
&lt;p&gt;「图片向量」和「模型合并」两个想法捆在一起，Netflix 分开消融，对照老的五模型系统：V1 只加图片向量（仍是五个画布模型），V2 只合并（统一模型但纯 ID），V3 两者都要。离线指标上 ±1% 以内不算显著，V1、V2 单独做基本都在噪声带里；线上全平台跑了至少四周的 A/B 给出更清楚的分界线：&lt;strong&gt;V1、V2 双双不显著，只有 V3 拿到统计显著的提升&lt;/strong&gt;——V3 就是今天线上跑的版本。&lt;/p&gt;
&lt;p&gt;原因也讲得透：V1 告诉单画布模型素材长什么样，但稀疏画布样本太少，教不会它怎么用这条信息；V2 数据够了，但全是 ID 信号，新素材没有。V3 两者兼有，成熟画布教会共享模型「CLIP 向量如何映射到会员偏好」，这个映射直接迁移到稀疏画布。效果是相乘不是相加——V3 在 short-panel 上的提升（5.691%）超过 V1 与 V2 之和。原文的教训写得很直白：&lt;strong&gt;下结论「内容特征没用」之前，先找第二个阻塞因子。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;真实考验来自产品侧：Netflix 十年来最大的电视首页改版，让 short-panel 一夜之间成为主战场——即将吃下最多曝光的画布恰好历史数据最少。V3 赶在改版前上线，配合一个月的 holdback A/B，核心发现指标和播放时长双双显著增长，且增幅比稳态消融更大。&lt;/p&gt;
&lt;h2 id=&#34;五查询感知的海报排序&#34;&gt;五、查询感知的海报排序&lt;/h2&gt;
&lt;p&gt;浏览时你的长期口味是对的信号，搜索时不是：搜某个演员时你要的是带他的海报，哪怕你的广义口味另有指向。搜索页的意图写在 query 里，海报应当响应它。&lt;/p&gt;
&lt;p&gt;因为 CLIP 把文本和图像投进了同一个向量空间，这件事近乎白送：直接算 query 的文本向量与素材图像向量的余弦相似度，和原有个性化分数按权重 α（0 到 1，线上 A/B 调）混合。第一项是「我们认为你喜欢什么」，第二项是「你刚开口要什么」。没有任何额外建模——向量本来就在素材表示里，排序时加一个相似度项而已。&lt;/p&gt;
&lt;h2 id=&#34;六视频预览mediafm&#34;&gt;六、视频预览：MediaFM&lt;/h2&gt;
&lt;p&gt;视频预览比静态图难：吸引力来自运动、节奏、对白、配乐，单帧说不清。第一版内容感知方案 SeqCLIP 只取各帧的 CLIP 向量求平均——看得见长相，听不见声音，而对白和音乐恰恰扛着预览片的大半调性。&lt;/p&gt;
&lt;p&gt;补全这块的是 MediaFM，Netflix 第一个自研多模态地基模型，在 8000 万个镜头（shot）上训练，每个镜头融合三路信号成一个向量：视觉走 SeqCLIP，音频走预训练语音音频编码器，文本是字幕经大规模文本模型编码。接入方式和 CLIP 一样：把向量拼进素材表示，不需要新基建。&lt;/p&gt;
&lt;p&gt;离线 IPS 和五周全平台 A/B 给出一致的排序：&lt;strong&gt;MediaFM ＞ SeqCLIP ＞ 纯 ID&lt;/strong&gt;，每加一层内容感知都有收益，TV 端收益最大。音频和定时文本是 SeqCLIP 这类纯视觉编码器够不到的，这部分增量是真的。MediaFM 已作为默认视频预览向量全平台上线。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph FM[&amp;#34;MediaFM 多模态地基模型&amp;lt;br/&amp;gt;8000 万镜头训练&amp;#34;]
        V[&amp;#34;视觉&amp;lt;br/&amp;gt;SeqCLIP 帧向量平均&amp;#34;] --&amp;gt; FUSE[&amp;#34;融合成镜头级向量&amp;#34;]
        A[&amp;#34;音频&amp;lt;br/&amp;gt;预训练语音音频编码器&amp;#34;] --&amp;gt; FUSE
        T[&amp;#34;文本&amp;lt;br/&amp;gt;字幕经大规模文本模型&amp;#34;] --&amp;gt; FUSE
    end
    FUSE --&amp;gt; STORE[&amp;#34;Embedding Store&amp;lt;br/&amp;gt;训练与推理同源 无偏斜&amp;#34;]
    STORE --&amp;gt; PROBE[&amp;#34;线性探针代理任务&amp;lt;br/&amp;gt;仅凭向量预测去偏人气赢家&amp;#34;]
    PROBE --&amp;gt;|&amp;#34;跑赢随机猜测才放行&amp;#34;| AB[&amp;#34;离线 IPS + 线上 A/B&amp;lt;br/&amp;gt;MediaFM ＞ SeqCLIP ＞ 纯 ID&amp;#34;]
    style PROBE fill:#fff3cd&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h2 id=&#34;七便宜地挑向量线性探针&#34;&gt;七、便宜地挑向量：线性探针&lt;/h2&gt;
&lt;p&gt;新向量层出不穷，端到端试验太贵——数据工程、重训、数周 A/B 流量，不可能每个候选都走全程。Netflix 用一个便宜问题把漏斗口收窄：&lt;strong&gt;仅凭内容向量，能不能预测一个朴素无个性化策略下哪张素材会赢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;做法：固定一批标题，用探索数据按倾向分去偏后找出每个标题的人气赢家，打成二值标签；然后只用一个线性探针从素材向量恢复这个标签（标准二值交叉熵），不带标题、演员等任何元数据。保持线性和纯向量是刻意的——它隔离出「人气驱动因子有多少真的编码进了向量」。向量若抓住了人气的语义驱动，线性分类器就该能认出赢家；抓不住，探针就和随机猜测一样，而后者正是它的及格线。&lt;/p&gt;
&lt;p&gt;这个探针先把一大批候选剪到两个决赛选手（SeqCLIP 和最强 MediaFM 变体），再送全程评估。三条信号——探针准确率、离线 IPS、线上 A/B——对两个选手的排序完全一致，所以现在每个 MediaFM 新版本发布前都得先过探针这一关。&lt;/p&gt;
&lt;h2 id=&#34;八embedding-store让一切成立的地基&#34;&gt;八、Embedding Store：让一切成立的地基&lt;/h2&gt;
&lt;p&gt;所有向量——CLIP、SeqCLIP、MediaFM——都活在 Netflix Embedding Store 里（Netflix AI Platform 的组件）。地基模型把原始素材编码成向量只做一次，Store 用同一接口喂给所有下游；关键性质是&lt;strong&gt;训练时和在线推理时服务的是完全相同的向量&lt;/strong&gt;，模型学到的和线上见到的之间没有 skew。&lt;/p&gt;
&lt;p&gt;另一个性质是解耦：新向量（或老向量的新版本）注册、回填、验证全部独立进行，不碰任何消费方的训练和推理代码，下游靠配置即可启用。CLIP 进海报模型、同一批向量撑起查询感知排序、MediaFM 滚进视频预览模型，各自是独立变更而不是跨团队迁移。下一步目标是把 Store 推向图文视频统一的语义空间，做跨模态检索和跨界面统一排序。&lt;/p&gt;
&lt;h2 id=&#34;工程实践联想&#34;&gt;工程实践联想&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;冷启动的最优解常常是换表示，不是加探索。&lt;/strong&gt; 探索流量和人气回退都是在「ID 无知」的框架里打补丁；一旦实体有了内容向量，偏好沿向量空间迁移，问题在表示层就消掉了。做实体冷启动（新商品、新文档、新用户）时先问：这个实体有没有一个下游模型读得懂的内容表示。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;「特征没用」往往是因为别处先堵着。&lt;/strong&gt; V1 的失败不是图片向量没信息，是稀疏画布样本不够教模型用；V2 的失败不是合并不对，是 ID 信号对不上新素材。多因素实验里单变量不显著，先怀疑第二个阻塞因子，别急着枪毙特征。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评估体系的纯度比模型重要。&lt;/strong&gt; IPS 能跟踪线上结果，靠的是倾向分在服务时刻由构造已知——日志里事后估出来的倾向分自带一层建模误差。值得为评估专门留一股随机探索流量，这笔钱花在刀刃上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用廉价代理任务给昂贵实验把关。&lt;/strong&gt; 线性探针 + 随机基线，成本几乎为零，却和端到端 A/B 给出了一致排序。任何「候选方案多、全量验证贵」的场景（选向量、选特征、选模型结构）都该先架一道这样的探针。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;向量服务要当成基础设施来建。&lt;/strong&gt; 训练推理同源、版本注册回填独立、下游配置即用——这三条让「换向量」从跨团队项目降级为一次配置变更。Embedding Store 这类组件才是多模态落地真正的护城河，模型本身反而不是。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;本篇小结&#34;&gt;本篇小结&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;问题&lt;/strong&gt;：素材个性化的冷启动——老模型把素材当不透明 ID，新素材只能靠探索流量和人气启发式硬扛。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;海报&lt;/strong&gt;：CLIP 768 维向量拼接 ID 向量，偏好沿向量空间即时迁移；五个画布模型合并为一个，混训按交互类型的长期奖励分加权，画布按长期价值而非曝光量贡献。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评估&lt;/strong&gt;：专门探索流量 + IPS，倾向分服务时刻已知，离线数字才跟得上线上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消融&lt;/strong&gt;：V1（仅向量）、V2（仅合并）线上均不显著，V3（两者兼有）显著胜出，short-panel 提升 5.691% 且超过 V1+V2 之和；电视首页改版实战中 holdback A/B 证实收益更大。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;搜索&lt;/strong&gt;：query 文本向量与素材图像向量的余弦相似度，按 α 与个性化分数混合，零额外建模。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;视频&lt;/strong&gt;：MediaFM（8000 万镜头，视觉+音频+文本三模态）＞ SeqCLIP ＞ 纯 ID，TV 端收益最大，已全平台默认上线。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;方法论&lt;/strong&gt;：线性探针代理任务廉价筛选向量，三条信号排序一致后成为 MediaFM 发版门禁；Embedding Store 保证训练推理同源、解耦上下游。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://netflixtechblog.com/maps-netflixs-multimodal-asset-personalization-at-scale-32f96320785e&#34;&gt;MAPS: Netflix&amp;rsquo;s Multimodal Asset Personalization at Scale&lt;/a&gt;（原文，Netflix TechBlog）。&lt;/li&gt;
&lt;li&gt;Radford et al., &amp;ldquo;Learning Transferable Visual Models From Natural Language Supervision&amp;rdquo;（CLIP 原始论文，文中海报向量与图文共空间的来源）。&lt;/li&gt;
&lt;li&gt;Netflix TechBlog 关于长期奖励建模（long-term reward modeling）与 Netflix AI Platform / Embedding Store 的相关文章（原文内引用，用于奖励加权与向量基础设施）。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>RAG 本地素材库：从 Embedding 选型到召回调优</title>
      <link>https://ftmao.com/blog/posts/raginftmao/</link>
      <pubDate>Tue, 10 Feb 2026 11:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/raginftmao/</guid>
      <description>&lt;h1 id=&#34;rag-本地素材库从-embedding-选型到召回调优&#34;&gt;RAG 本地素材库：从 Embedding 选型到召回调优&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;在我开发的方糖猫 AI 视频平台中，一个核心能力是「根据文案自动匹配视频素材」。用户的文案可能是「讲一个关于坚持的故事」，系统需要从本地素材库中找到最契合的画面。我们最终用 &lt;strong&gt;RAG（检索增强生成）&lt;/strong&gt; 的思路搭建了本地素材库。这篇文章会完整复盘从 Embedding 选型到召回调优的全过程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一业务背景为什么需要-rag&#34;&gt;一、业务背景：为什么需要 RAG？&lt;/h2&gt;
&lt;p&gt;短视频生成平台里的素材通常有几类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;图片素材：背景图、人物图、概念图&lt;/li&gt;
&lt;li&gt;视频片段：B-roll、转场、动画&lt;/li&gt;
&lt;li&gt;文案片段：金句、案例、开场白&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;早期我们用关键词标签做检索，很快就发现几个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;标签覆盖不全&lt;/strong&gt;。一个海边日落镜头，可能被标注为「海」「日落」「风景」「旅行」，但用户文案写的是「人生低谷后的曙光」，关键词完全对不上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标签质量参差不齐&lt;/strong&gt;。不同运营人员打的标签不一致，导致召回结果波动大。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无法跨模态匹配&lt;/strong&gt;。图片素材没有文字描述，靠文件名搜索基本不可用。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;RAG 的思路是：&lt;strong&gt;用 Embedding 把素材和查询都映射到同一向量空间，通过语义相似度做召回&lt;/strong&gt;。这样即使关键词不同，只要语义接近，就能被检索出来。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二系统设计&#34;&gt;二、系统设计&lt;/h2&gt;
&lt;p&gt;整个 RAG 素材库分为三个核心环节：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph S1[&amp;#34;素材入库&amp;#34;]
        A1[&amp;#34;原始素材&amp;#34;] --&amp;gt; A2[&amp;#34;内容提取&amp;#34;] --&amp;gt; A3[&amp;#34;Embedding&amp;#34;] --&amp;gt; A4[&amp;#34;ChromaDB&amp;#34;]
    end
    subgraph S2[&amp;#34;查询召回&amp;#34;]
        B1[&amp;#34;用户文案&amp;#34;] --&amp;gt; B2[&amp;#34;Embedding&amp;#34;] --&amp;gt; B3[&amp;#34;Top-K 检索&amp;#34;] --&amp;gt; B4[&amp;#34;重排&amp;#34;] --&amp;gt; B5[&amp;#34;返回结果&amp;#34;]
    end
    subgraph S3[&amp;#34;持续更新&amp;#34;]
        C1[&amp;#34;新增素材&amp;#34;] --&amp;gt; C2[&amp;#34;增量 Embedding&amp;#34;] --&amp;gt; C3[&amp;#34;索引更新&amp;#34;]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;21-素材入库流程&#34;&gt;2.1 素材入库流程&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[&amp;#34;图片/视频&amp;#34;] --&amp;gt; B[&amp;#34;抽帧/缩略图&amp;#34;] --&amp;gt; C[&amp;#34;视觉特征提取（CLIP/ResNet）&amp;#34;] --&amp;gt; D[&amp;#34;文本描述生成&amp;#34;] --&amp;gt; E[&amp;#34;Embedding&amp;#34;] --&amp;gt; F[&amp;#34;写入 ChromaDB&amp;#34;]
    G[&amp;#34;文本片段&amp;#34;] --&amp;gt; H[&amp;#34;清洗/分块&amp;#34;] --&amp;gt; I[&amp;#34;Embedding&amp;#34;] --&amp;gt; F&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;对于图片和视频，我们会：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;视频抽帧为关键帧&lt;/li&gt;
&lt;li&gt;用多模态模型生成一句话描述&lt;/li&gt;
&lt;li&gt;同时保存原始文件路径、文件类型、使用次数等元数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;22-查询召回流程&#34;&gt;2.2 查询召回流程&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 简化版召回流程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;retrieve_materials&lt;/span&gt;(query: str, top_k: int &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 1. 查询向量化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    query_embedding &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; embedding_model&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode(query)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 2. 向量库初筛&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    candidates &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; chroma_collection&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;query(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        query_embeddings&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[query_embedding],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        n_results&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;top_k &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,  &lt;span style=&#34;color:#75715e&#34;&gt;# 多召回一些，留给重排&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        where&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;active&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 3. 重排序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ranked &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; reranker&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rerank(query, candidates)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 4. 返回 Top-K&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ranked[:top_k]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;三embedding-选型实测&#34;&gt;三、Embedding 选型实测&lt;/h2&gt;
&lt;p&gt;Embedding 模型的选择直接决定召回质量。我们测试了以下几种：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模型&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;维度&lt;/th&gt;
					&lt;th&gt;中文语义&lt;/th&gt;
					&lt;th&gt;多模态&lt;/th&gt;
					&lt;th&gt;延迟&lt;/th&gt;
					&lt;th&gt;成本&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;text-embedding-ada-002&lt;/td&gt;
					&lt;td&gt;文本&lt;/td&gt;
					&lt;td&gt;1536&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;快&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;text-embedding-3-small&lt;/td&gt;
					&lt;td&gt;文本&lt;/td&gt;
					&lt;td&gt;1536&lt;/td&gt;
					&lt;td&gt;较好&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;快&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BGE-M3&lt;/td&gt;
					&lt;td&gt;文本&lt;/td&gt;
					&lt;td&gt;1024&lt;/td&gt;
					&lt;td&gt;优秀&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
					&lt;td&gt;本地&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OpenAI CLIP&lt;/td&gt;
					&lt;td&gt;多模态&lt;/td&gt;
					&lt;td&gt;512&lt;/td&gt;
					&lt;td&gt;一般&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;中文 CLIP&lt;/td&gt;
					&lt;td&gt;多模态&lt;/td&gt;
					&lt;td&gt;512&lt;/td&gt;
					&lt;td&gt;较好&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;中等&lt;/td&gt;
					&lt;td&gt;本地&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;31-文本-embedding-选型&#34;&gt;3.1 文本 Embedding 选型&lt;/h3&gt;
&lt;p&gt;因为我们的查询主要是中文文案，最终选择了 &lt;strong&gt;BGE-M3&lt;/strong&gt;，原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;中文语义理解能力明显优于 OpenAI 的 Embedding&lt;/li&gt;
&lt;li&gt;支持本地部署，无调用成本&lt;/li&gt;
&lt;li&gt;向量维度 1024，检索速度和存储成本可接受&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;32-多模态-embedding-选型&#34;&gt;3.2 多模态 Embedding 选型&lt;/h3&gt;
&lt;p&gt;对于图片/视频素材，CLIP 系列可以把视觉内容和文本映射到同一空间。但实测发现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通用 CLIP 对中文概念的支持较弱&lt;/li&gt;
&lt;li&gt;视频场景下，关键帧的质量直接影响召回效果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;关键帧用 &lt;strong&gt;中文 CLIP&lt;/strong&gt; 生成视觉 Embedding&lt;/li&gt;
&lt;li&gt;同时用图像描述模型生成一句话中文描述，再用 &lt;strong&gt;BGE-M3&lt;/strong&gt; 生成文本 Embedding&lt;/li&gt;
&lt;li&gt;向量库中同时存储两种 Embedding，查询时分别召回再融合&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四向量库设计&#34;&gt;四、向量库设计&lt;/h2&gt;
&lt;p&gt;我们选用 &lt;strong&gt;ChromaDB&lt;/strong&gt; 作为向量存储，主要考虑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;部署简单，适合小团队&lt;/li&gt;
&lt;li&gt;支持元数据过滤（按项目、类型、状态筛选）&lt;/li&gt;
&lt;li&gt;Python 生态集成好&lt;/li&gt;
&lt;li&gt;支持内存模式和持久化模式，开发方便&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;41-collection-划分&#34;&gt;4.1 Collection 划分&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 按素材类型分 Collection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;image_collection &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; chroma_client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_or_create_collection(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;materials_image&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;video_collection &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; chroma_client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_or_create_collection(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;materials_video&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;text_collection &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; chroma_client&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_or_create_collection(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;materials_text&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;分 Collection 的好处是查询更聚焦，也方便针对不同类型的素材调优。&lt;/p&gt;
&lt;h3 id=&#34;42-文档结构设计&#34;&gt;4.2 文档结构设计&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;documents &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;img_001&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;embedding&amp;#34;&lt;/span&gt;: image_embedding,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;metadata&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;project_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;proj_123&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;海边&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;日落&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;风景&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;file_url&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;oss://ftmao/materials/img_001.jpg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;width&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1920&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;height&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1080&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;active&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;usage_count&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;document&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;海边日落，宁静的风景画面&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# 用于可读性和调试&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;五召回调优实战&#34;&gt;五、召回调优实战&lt;/h2&gt;
&lt;h3 id=&#34;51-评测数据集构建&#34;&gt;5.1 评测数据集构建&lt;/h3&gt;
&lt;p&gt;召回调优的前提是有评测数据。我们标注了 200 条查询-素材对：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;query&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;人生低谷后重新出发&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;relevant&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;img_001&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;img_015&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;vid_008&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;irrelevant&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;img_099&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;vid_045&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;评测指标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Recall@K&lt;/strong&gt;：相关素材在 Top-K 中的占比&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Precision@K&lt;/strong&gt;：Top-K 中相关素材的占比&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MRR&lt;/strong&gt;：第一个相关素材的平均排名倒数&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;52-embedding-调优&#34;&gt;5.2 Embedding 调优&lt;/h3&gt;
&lt;p&gt;通过对比实验，我们发现：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方案&lt;/th&gt;
					&lt;th&gt;Recall@10&lt;/th&gt;
					&lt;th&gt;Precision@10&lt;/th&gt;
					&lt;th&gt;MRR&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;关键词标签&lt;/td&gt;
					&lt;td&gt;42%&lt;/td&gt;
					&lt;td&gt;35%&lt;/td&gt;
					&lt;td&gt;0.18&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BGE-M3 文本 Embedding&lt;/td&gt;
					&lt;td&gt;68%&lt;/td&gt;
					&lt;td&gt;54%&lt;/td&gt;
					&lt;td&gt;0.31&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BGE-M3 + 中文 CLIP 融合&lt;/td&gt;
					&lt;td&gt;79%&lt;/td&gt;
					&lt;td&gt;63%&lt;/td&gt;
					&lt;td&gt;0.40&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;+ 重排序模型&lt;/td&gt;
					&lt;td&gt;86%&lt;/td&gt;
					&lt;td&gt;71%&lt;/td&gt;
					&lt;td&gt;0.48&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;53-查询改写&#34;&gt;5.3 查询改写&lt;/h3&gt;
&lt;p&gt;用户的原始查询往往比较抽象，比如「做一个励志视频」。直接用这个查询做向量检索，召回结果会比较散。&lt;/p&gt;
&lt;p&gt;我们的做法是让 LLM 先对查询做改写和扩展：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;输入：做一个励志视频
输出：
- 核心语义：励志、奋斗、坚持不懈
- 扩展查询：逆境中成长、永不放弃、追逐梦想、突破自我
- 情绪基调：激昂、温暖、希望&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;然后用扩展后的多个查询分别检索，最后合并结果。这个策略让 Recall@10 提升了约 8%。&lt;/p&gt;
&lt;h3 id=&#34;54-重排序模型&#34;&gt;5.4 重排序模型&lt;/h3&gt;
&lt;p&gt;初筛召回 30 个候选后，用轻量级重排序模型做二次排序。我们用的是 &lt;strong&gt;bge-reranker-base&lt;/strong&gt;，原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模型小，CPU 推理足够快&lt;/li&gt;
&lt;li&gt;对中文语义匹配效果好&lt;/li&gt;
&lt;li&gt;可以 fine-tune 适应平台特定素材&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六工程化细节&#34;&gt;六、工程化细节&lt;/h2&gt;
&lt;h3 id=&#34;61-索引更新策略&#34;&gt;6.1 索引更新策略&lt;/h3&gt;
&lt;p&gt;素材库是动态变化的，每天都有新增、删除、状态变更。我们采用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;增量更新&lt;/strong&gt;：新增素材立即 Embedding 入库&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;批量补偿&lt;/strong&gt;：每天晚上全量校验一次，修复漏入/错入&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;软删除&lt;/strong&gt;：素材状态改为 inactive，不立即物理删除，便于恢复和审计&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;62-缓存与去重&#34;&gt;6.2 缓存与去重&lt;/h3&gt;
&lt;p&gt;热门查询的 Embedding 结果会被缓存到 Redis，缓存 key 是查询文本的 hash。同时 TTS 结果也按文案 hash 去重，避免重复调用。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get_cached_or_compute&lt;/span&gt;(query: str):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    key &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rag:query:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;hashlib&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;md5(query&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;encode())&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;hexdigest()&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cached &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; redis&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(key)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; cached:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;loads(cached)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; retrieve_materials(query)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    redis&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;setex(key, &lt;span style=&#34;color:#ae81ff&#34;&gt;3600&lt;/span&gt;, json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps(result))  &lt;span style=&#34;color:#75715e&#34;&gt;# 缓存 1 小时&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;63-多项目隔离&#34;&gt;6.3 多项目隔离&lt;/h3&gt;
&lt;p&gt;同一个平台可能服务多个创作者或项目，不同项目的素材库需要隔离。我们通过 &lt;code&gt;project_id&lt;/code&gt; 元数据过滤实现：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;results &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; collection&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;query(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    query_embeddings&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[embedding],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    n_results&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    where&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;project_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;proj_123&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;active&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;七踩过的坑&#34;&gt;七、踩过的坑&lt;/h2&gt;
&lt;h3 id=&#34;71-向量维度不一致&#34;&gt;7.1 向量维度不一致&lt;/h3&gt;
&lt;p&gt;早期我们同时用了 OpenAI Embedding（1536 维）和 BGE-M3（1024 维），混在一个 Collection 里，结果查询时报维度错误。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：严格按模型维度分 Collection，每个 Collection 只存同一模型产出的向量。&lt;/p&gt;
&lt;h3 id=&#34;72-关键帧质量影响召回&#34;&gt;7.2 关键帧质量影响召回&lt;/h3&gt;
&lt;p&gt;视频素材如果关键帧选得不好（比如黑屏、转场瞬间），CLIP 生成的 Embedding 会偏离视频真实内容。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用场景检测算法选取稳定画面&lt;/li&gt;
&lt;li&gt;一个视频保存多个关键帧，查询时合并召回&lt;/li&gt;
&lt;li&gt;人工抽检低质量素材&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;73-查询过短导致语义漂移&#34;&gt;7.3 查询过短导致语义漂移&lt;/h3&gt;
&lt;p&gt;用户查询只有一个词，比如「奋斗」，召回结果可能包含大量不相关但语义宽泛的素材。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;短查询自动扩展为完整句子&lt;/li&gt;
&lt;li&gt;提高重排序模型的权重&lt;/li&gt;
&lt;li&gt;对短查询增加元数据过滤&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八当前效果与下一步&#34;&gt;八、当前效果与下一步&lt;/h2&gt;
&lt;p&gt;目前这套 RAG 素材库已经支撑方糖猫平台的核心素材检索能力，覆盖了图片、视频片段、文案片段三类素材。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;已验证的收益&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;素材召回质量明显高于关键词检索&lt;/li&gt;
&lt;li&gt;新素材无需人工打标签即可被检索到&lt;/li&gt;
&lt;li&gt;跨项目复用素材变得可行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;下一步计划&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引入用户反馈数据，做在线学习优化&lt;/li&gt;
&lt;li&gt;针对视频内容做更细粒度的时序检索&lt;/li&gt;
&lt;li&gt;探索多模态大模型直接做端到端素材匹配&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九总结&#34;&gt;九、总结&lt;/h2&gt;
&lt;p&gt;RAG 不只是 LLM 应用的一个热门概念，对于内容生成类平台来说，它是&lt;strong&gt;连接用户意图和内容资产的关键基础设施&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;几个关键经验：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Embedding 选型要以业务语言为主&lt;/strong&gt;。中文场景不要迷信 OpenAI，BGE 系列性价比更高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一定要有评测数据集&lt;/strong&gt;。没有数据就没有优化方向。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;召回 pipeline 通常是多阶段的&lt;/strong&gt;：初筛 + 重排 + 业务规则过滤。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工程化比算法更重要&lt;/strong&gt;。索引更新、缓存、隔离、监控，这些决定系统能不能长期稳定运行。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;如果你也在做 RAG 相关的项目，欢迎交流 Embedding 选型和召回调优的经验。&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>生成式AI原理与实战（Part 3）学习笔记：嵌入模型、表示微调与生成模型微调</title>
      <link>https://ftmao.com/blog/posts/llm-interview-notes-part3/</link>
      <pubDate>Sun, 09 Nov 2025 16:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/llm-interview-notes-part3/</guid>
      <description>&lt;h1 id=&#34;生成式ai原理与实战part-3学习笔记嵌入模型表示微调与生成模型微调&#34;&gt;生成式AI原理与实战（Part 3）学习笔记：嵌入模型、表示微调与生成模型微调&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这是《生成式AI原理与实战》学习笔记的第三篇。Part 1 聊了大模型的“底层零件”，Part 2 聊了提示工程、Agent 和 RAG；Part 3 则进入“模型训练与微调”领域：怎么训练一个好的文本嵌入模型、怎么在数据少的情况下微调分类模型、怎么用 LoRA/DPO/PPO 把通用大模型变成业务模型。目标读者仍然是&lt;strong&gt;刚接触 AI 的初中级开发者&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;写在前面为什么开发者要懂微调&#34;&gt;写在前面：为什么开发者要懂微调？&lt;/h2&gt;
&lt;p&gt;调用 API 能解决 80% 的问题，但剩下的 20% 往往需要你接触模型本身：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;公司私有文档的检索效果差，要不要自己训练嵌入模型？&lt;/li&gt;
&lt;li&gt;标注数据只有几百条，能微调分类模型吗？&lt;/li&gt;
&lt;li&gt;想让大模型输出符合公司风格的文案，除了写 prompt 还能做什么？&lt;/li&gt;
&lt;li&gt;排行榜第一的模型，为什么到自己业务里表现一般？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这篇文章会用“概念 + 图 + 工程直觉”来回答这些问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一文本嵌入模型让语义变成可计算的向量&#34;&gt;一、文本嵌入模型：让“语义”变成可计算的向量&lt;/h2&gt;
&lt;p&gt;嵌入模型（Embedding Model）的作用，是把文本变成固定长度的向量。语义相近的文本，向量距离就小；语义不同的文本，向量距离就大。它是 RAG、语义搜索、推荐系统的核心组件。&lt;/p&gt;
&lt;h3 id=&#34;11-为什么对比学习需要负样本&#34;&gt;1.1 为什么对比学习需要负样本？&lt;/h3&gt;
&lt;p&gt;训练嵌入模型时，如果只告诉模型“这两句话很相似，向量要靠近”，模型可能偷懒：把所有文本都编码成同一个向量。这样无论输入什么，相似度都很高，模型就失去了区分能力。&lt;/p&gt;
&lt;p&gt;负样本的作用就是告诉模型：&lt;strong&gt;这些不相似的文本，向量必须拉开&lt;/strong&gt;。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 只有正样本
        P1[A] --&amp;gt; C[中心点]
        P2[B] --&amp;gt; C
        P3[C] --&amp;gt; C
    end

    subgraph 加入负样本
        N1[A] -.-&amp;gt;|拉近| P[正样本对]
        N2[B] -.-&amp;gt;|拉近| P
        N3[C] --&amp;gt;|推远| P
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;高质量训练的关键是&lt;strong&gt;难负样本（Hard Negatives）&lt;/strong&gt;：那些看起来很像正确答案、但实际不对的样本。比如问“北京在哪里”，错误答案“上海是中国城市”就是一个难负样本，它会让模型学会更细粒度的区分。&lt;/p&gt;
&lt;h3 id=&#34;12-双编码器-vs-交叉编码器&#34;&gt;1.2 双编码器 vs 交叉编码器&lt;/h3&gt;
&lt;p&gt;工业界的语义搜索通常分两阶段：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    Q[查询] --&amp;gt; B[双编码器 Bi-Encoder]
    D[文档库] --&amp;gt; B
    B --&amp;gt; C[候选 Top-k]
    C --&amp;gt; X[交叉编码器 Cross-Encoder]
    X --&amp;gt; R[精排结果]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th&gt;双编码器&lt;/th&gt;
					&lt;th&gt;交叉编码器&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;计算方式&lt;/td&gt;
					&lt;td&gt;查询和文档分别编码成向量&lt;/td&gt;
					&lt;td&gt;查询和文档拼接后一起输入模型&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;速度&lt;/td&gt;
					&lt;td&gt;快，文档向量可离线预计算&lt;/td&gt;
					&lt;td&gt;慢，需要实时成对计算&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;精度&lt;/td&gt;
					&lt;td&gt;较低，缺乏细粒度交互&lt;/td&gt;
					&lt;td&gt;高，能捕捉词级关系&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;用途&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;召回阶段&lt;/strong&gt;：从海量文档中快速找候选&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;精排阶段&lt;/strong&gt;：对少量候选做精确排序&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;对初级开发者的建议&lt;/strong&gt;：不要一上来就用交叉编码器处理百万文档，会慢得无法接受。标准做法是“双编码器召回 Top-100 + 交叉编码器精排”。&lt;/p&gt;
&lt;h3 id=&#34;13-训练嵌入模型的损失函数怎么选&#34;&gt;1.3 训练嵌入模型的损失函数怎么选？&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;损失函数&lt;/th&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
					&lt;th&gt;适用场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;MNR（多负例排序）&lt;/td&gt;
					&lt;td&gt;适合对比学习，能利用批量内负样本&lt;/td&gt;
					&lt;td&gt;依赖高质量负样本，计算随负例增加&lt;/td&gt;
					&lt;td&gt;大规模检索、对比预训练&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;余弦相似度损失&lt;/td&gt;
					&lt;td&gt;方向敏感，计算轻量，适合归一化嵌入&lt;/td&gt;
					&lt;td&gt;对难负样本区分度不足&lt;/td&gt;
					&lt;td&gt;文本相似度、资源受限场景&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Softmax 损失&lt;/td&gt;
					&lt;td&gt;直接优化分类，输出有概率意义&lt;/td&gt;
					&lt;td&gt;嵌入通用性差，不适合检索&lt;/td&gt;
					&lt;td&gt;意图识别、明确分类任务&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;14-没标注数据怎么办tsdae-无监督预训练&#34;&gt;1.4 没标注数据怎么办？TSDAE 无监督预训练&lt;/h3&gt;
&lt;p&gt;TSDAE（Transformer-based Sequential Denoising Auto-Encoder）的思路是：把输入文本加噪声（如随机删词、替换），再让模型重建原文。模型为了重建，必须学会抓住句子的全局语义。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    I[原始句子] --&amp;gt; N[加噪声]
    N --&amp;gt; E[Encoder 编码]
    E --&amp;gt; D[Decoder 重建]
    D --&amp;gt; O[还原原始句子]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;TSDAE 用特殊词元（如 &lt;code&gt;[CLS]&lt;/code&gt;）作为句子表征，而不是平均池化。原因是：&lt;code&gt;[CLS]&lt;/code&gt; 在训练中被迫压缩全局信息以重建整个句子，信号更强；而平均池化会被无关词稀释。&lt;/p&gt;
&lt;h3 id=&#34;15-怎么评测嵌入模型&#34;&gt;1.5 怎么评测嵌入模型？&lt;/h3&gt;
&lt;p&gt;MTEB（Massive Text Embedding Benchmark）是比 STS-B 更全面的评测基准，包含 8 类任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;语义文本相似度（STS）&lt;/li&gt;
&lt;li&gt;检索（Retrieval）&lt;/li&gt;
&lt;li&gt;重排序（Reranking）&lt;/li&gt;
&lt;li&gt;分类（Classification）&lt;/li&gt;
&lt;li&gt;聚类（Clustering）&lt;/li&gt;
&lt;li&gt;配对分类（Pair Classification）&lt;/li&gt;
&lt;li&gt;摘要评估（Summarization）&lt;/li&gt;
&lt;li&gt;双语文本挖掘（Bitext Mining）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你做的业务是问答检索，就不要只看 STS 分数，要看 Retrieval 和 Reranking 指标。&lt;/p&gt;
&lt;h3 id=&#34;16-增量学习模型需要与时俱进&#34;&gt;1.6 增量学习：模型需要“与时俱进”&lt;/h3&gt;
&lt;p&gt;世界在变化，新词、新概念不断出现。嵌入模型也需要更新：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[收集新数据] --&amp;gt; B{分布是否变化？}
    B --&amp;gt;|是| C[概念漂移检测]
    B --&amp;gt;|否| D[继续监控]
    C --&amp;gt; E{性能是否退化？}
    E --&amp;gt;|是| F[增量微调]
    E --&amp;gt;|否| D
    F --&amp;gt; G[更新模型]
    G --&amp;gt; A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;检测方法包括：监控 KL 散度、KS 检验、在线评估指标等。更新时可以用小步微调，而不是从头训练。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二表示模型微调把小数据用出大价值&#34;&gt;二、表示模型微调：把小数据用出大价值&lt;/h2&gt;
&lt;p&gt;很多时候我们只有少量标注数据，却想做一个不错的分类或 NER 模型。这就需要“表示微调”的技巧。&lt;/p&gt;
&lt;h3 id=&#34;21-微调时冻结哪些层&#34;&gt;2.1 微调时冻结哪些层？&lt;/h3&gt;
&lt;p&gt;BERT 这类预训练模型，底层学习通用语法和语义，高层学习任务相关特征。微调时可以根据自己的情况决定：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    I[输入] --&amp;gt; L1[低层 Transformer&amp;lt;br/&amp;gt;通用语法语义]
    L1 --&amp;gt; L2[高层 Transformer&amp;lt;br/&amp;gt;任务相关语义]
    L2 --&amp;gt; H[分类头]
    H --&amp;gt; O[输出]

    style L1 fill:#e1f5e1
    style L2 fill:#fff2cc
    style H fill:#f8cecc&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;场景&lt;/th&gt;
					&lt;th&gt;策略&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;数据很少&lt;/td&gt;
					&lt;td&gt;冻结底层，只微调高层 + 分类头&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据较多&lt;/td&gt;
					&lt;td&gt;全模型微调&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;任务与预训练差异大&lt;/td&gt;
					&lt;td&gt;多微调几层&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;资源有限&lt;/td&gt;
					&lt;td&gt;冻结更多层，节省显存&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;22-setfit几百条数据也能做文本分类&#34;&gt;2.2 SetFit：几百条数据也能做文本分类&lt;/h3&gt;
&lt;p&gt;SetFit 是专门做少样本文本分类的框架。它的核心思想是：&lt;strong&gt;先用对比学习微调 Sentence Transformer，再在它生成的向量上训练一个轻量分类器&lt;/strong&gt;。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    S[少量标注样本] --&amp;gt; P[构造正负样本对]
    P --&amp;gt; C[对比学习微调 Encoder]
    C --&amp;gt; E[生成文本嵌入]
    E --&amp;gt; CL[训练分类器&amp;lt;br/&amp;gt;SVM / Logistic Regression]
    CL --&amp;gt; M[最终分类模型]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;为什么有效？因为即使是每类只有 5 条样本，两两组合也能生成很多训练对。对比学习让同类样本靠近、不同类样本远离，相当于学到了一个“任务专属的嵌入空间”。&lt;/p&gt;
&lt;h3 id=&#34;23-继续预训练拿到领域知识但别丢了通用能力&#34;&gt;2.3 继续预训练：拿到领域知识，但别丢了通用能力&lt;/h3&gt;
&lt;p&gt;让通用 BERT 适应医疗、法律等垂直领域，常用做法是继续预训练。但直接在全领域数据上训练，可能让模型忘掉通用语言知识，这叫&lt;strong&gt;灾难性遗忘&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;缓解方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;混合训练&lt;/strong&gt;：领域数据 + 通用数据一起训练。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分阶段训练&lt;/strong&gt;：先用通用数据 warm-up，再逐步增加领域数据，最后再用少量通用数据巩固。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapter / LoRA&lt;/strong&gt;：只训练少量新增参数，保留主干模型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EWC（弹性权重巩固）&lt;/strong&gt;：对重要参数加约束，防止大幅偏离。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;知识蒸馏&lt;/strong&gt;：用原始通用模型当教师，保留其预测分布。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;24-垂直领域分类三种方案对比&#34;&gt;2.4 垂直领域分类：三种方案对比&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方案&lt;/th&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
					&lt;th&gt;适用场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;直接微调通用 BERT&lt;/td&gt;
					&lt;td&gt;成本低、稳定&lt;/td&gt;
					&lt;td&gt;领域术语理解弱&lt;/td&gt;
					&lt;td&gt;快速验证、术语不复杂的任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;继续预训练 BERT 再微调&lt;/td&gt;
					&lt;td&gt;领域适应性强&lt;/td&gt;
					&lt;td&gt;需要大量无标注领域数据&lt;/td&gt;
					&lt;td&gt;有资源、有数据的团队&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;从头预训练领域模型&lt;/td&gt;
					&lt;td&gt;最强领域定制&lt;/td&gt;
					&lt;td&gt;资源消耗巨大、风险高&lt;/td&gt;
					&lt;td&gt;超大规模语料和算力&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对大多数团队来说，&lt;strong&gt;方案（b）是性价比最高的&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;25-ner-中的子词标签对齐&#34;&gt;2.5 NER 中的子词标签对齐&lt;/h3&gt;
&lt;p&gt;BERT 用 WordPiece 分词，会把一个词拆成多个子词。例如 &amp;ldquo;playing&amp;rdquo; → &amp;ldquo;play&amp;rdquo; + &amp;ldquo;##ing&amp;rdquo;。但 NER 标签是按词标注的，这就需要对齐：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只标注第一个子词&lt;/strong&gt;：最简单常用，其余子词不参与损失计算。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标签传播到所有子词&lt;/strong&gt;：每个子词都复制原词标签。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标签传播 + 修复规则&lt;/strong&gt;：第一个子词用原标签，后续子词改成 &lt;code&gt;I-&lt;/code&gt; 或 &lt;code&gt;O&lt;/code&gt;，避免 BIO 格式混乱。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;26-嵌入式设备上的小模型多任务训练&#34;&gt;2.6 嵌入式设备上的小模型多任务训练&lt;/h3&gt;
&lt;p&gt;如果要在手机、IoT 设备上跑模型，需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选轻量模型：MiniLM、TinyBERT、DistilBERT。&lt;/li&gt;
&lt;li&gt;多任务学习：共享一个编码器，接不同任务头。&lt;/li&gt;
&lt;li&gt;模型压缩：量化（INT8）、剪枝、知识蒸馏。&lt;/li&gt;
&lt;li&gt;部署格式：ONNX、TFLite。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    I[输入文本] --&amp;gt; E[Shared Encoder]
    E --&amp;gt; C[分类头]
    E --&amp;gt; N[NER 头]
    E --&amp;gt; V[Embedding 头]
    C --&amp;gt; O1[分类结果]
    N --&amp;gt; O2[实体标签]
    V --&amp;gt; O3[语义向量]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;三生成模型微调让通用模型变成你的模型&#34;&gt;三、生成模型微调：让通用模型变成“你的模型”&lt;/h2&gt;
&lt;h3 id=&#34;31-sft监督微调是最常用的起点&#34;&gt;3.1 SFT：监督微调是最常用的起点&lt;/h3&gt;
&lt;p&gt;SFT（Supervised Fine-Tuning）就是准备好 &lt;code&gt;(prompt, response)&lt;/code&gt; 数据对，继续训练模型。比如你想让模型输出更简洁的微信聊天风格，就准备大量“问题 → 简短回答”的样本。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    D[准备 prompt-response 数据] --&amp;gt; S[SFT 微调]
    S --&amp;gt; E[评估效果]
    E --&amp;gt;|不够好| A[补充/清洗数据]
    A --&amp;gt; D
    E --&amp;gt;|效果好| P[上线部署]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;数据量建议（QA 对）：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模型大小&lt;/th&gt;
					&lt;th&gt;目标&lt;/th&gt;
					&lt;th&gt;推荐数据量&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1B - 7B&lt;/td&gt;
					&lt;td&gt;记住有限文档知识&lt;/td&gt;
					&lt;td&gt;1k - 20k&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;13B - 30B&lt;/td&gt;
					&lt;td&gt;强记忆 + 通用指令&lt;/td&gt;
					&lt;td&gt;10k - 100k&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;70B+&lt;/td&gt;
					&lt;td&gt;企业问答 + 任务泛化&lt;/td&gt;
					&lt;td&gt;50k - 500k&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;32-lora-与-qlora大模型微调的省钱方案&#34;&gt;3.2 LoRA 与 QLoRA：大模型微调的省钱方案&lt;/h3&gt;
&lt;p&gt;全参数微调 70B 模型需要大量 GPU。LoRA 的核心思想是：&lt;strong&gt;不在原始权重上直接更新，而是在每层旁边加两个小矩阵（低秩分解），只训练这两个小矩阵&lt;/strong&gt;。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    X[输入] --&amp;gt; W[原始权重 W]
    W --&amp;gt; O[输出]
    X --&amp;gt; A[低秩矩阵 A]
    A --&amp;gt; B[低秩矩阵 B]
    B --&amp;gt; O&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;LoRA 的参数量大约是全量微调的 &lt;code&gt;1 / (d / 2r)&lt;/code&gt; 倍。例如 d=12288，r=8，参数量减少约 768 倍。&lt;/p&gt;
&lt;p&gt;QLoRA 在此基础上做了&lt;strong&gt;分块量化&lt;/strong&gt;：把权重矩阵切成小块，每块独立量化，保留各自的 scale 和 zero-point。这样比全局量化更精确，能在消费级 GPU 上微调大模型。&lt;/p&gt;
&lt;h3 id=&#34;33-超参数设置与停止训练&#34;&gt;3.3 超参数设置与停止训练&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;超参数&lt;/th&gt;
					&lt;th&gt;推荐范围&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;学习率&lt;/td&gt;
					&lt;td&gt;1e-5 - 2e-4&lt;/td&gt;
					&lt;td&gt;LoRA 可用稍大学习率&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;LoRA rank&lt;/td&gt;
					&lt;td&gt;4 - 64&lt;/td&gt;
					&lt;td&gt;小任务 8/16，复杂任务 32+&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;LoRA alpha&lt;/td&gt;
					&lt;td&gt;rank × 2 - rank × 8&lt;/td&gt;
					&lt;td&gt;控制 LoRA 对主模型的影响强度&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;什么时候停止？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;验证集 loss 连续 N 个 epoch 不下降就停。&lt;/li&gt;
&lt;li&gt;不要只看 loss，还要看具体指标（准确率、F1、BLEU、ROUGE）。&lt;/li&gt;
&lt;li&gt;生成任务最好加人工评估，loss 低不代表回答好。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;34-损失函数应该计算输入部分还是输出部分&#34;&gt;3.4 损失函数应该计算输入部分还是输出部分？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;推荐：只计算输出部分&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;推理时模型只负责生成输出，训练时只对输出优化更符合实际使用场景。&lt;/li&gt;
&lt;li&gt;输入部分是人类写好的 prompt，让模型预测它没有意义，还会引入噪声。&lt;/li&gt;
&lt;li&gt;计算量更小，训练更快。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;35-ppo-与-dpo让模型符合人类偏好&#34;&gt;3.5 PPO 与 DPO：让模型符合人类偏好&lt;/h3&gt;
&lt;p&gt;SFT 让模型“学会回答问题”，但不一定“回答得好”。RLHF（基于人类反馈的强化学习）就是解决这个问题。&lt;/p&gt;
&lt;h4 id=&#34;经典-rlhf-三阶段&#34;&gt;经典 RLHF 三阶段&lt;/h4&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    S[SFT 模型] --&amp;gt; R[训练奖励模型&amp;lt;br/&amp;gt;Reward Model]
    R --&amp;gt; P[PPO 强化学习]
    P --&amp;gt; A[对齐后的模型]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SFT&lt;/strong&gt;：训练模型学会基本对话。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练奖励模型&lt;/strong&gt;：收集人类偏好数据，训练一个打分模型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PPO 强化学习&lt;/strong&gt;：用奖励模型指导策略模型优化。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;ppo-里的四个角色&#34;&gt;PPO 里的四个角色&lt;/h4&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    Prompt --&amp;gt; A[Actor&amp;lt;br/&amp;gt;生成回答]
    A --&amp;gt; C[Critic&amp;lt;br/&amp;gt;评估状态价值]
    A --&amp;gt; R[Reward Model&amp;lt;br/&amp;gt;给回答打分]
    A --&amp;gt; Ref[Reference Model&amp;lt;br/&amp;gt;计算 KL 散度&amp;lt;br/&amp;gt;防止跑偏]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模型&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
					&lt;th&gt;是否训练&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Actor&lt;/td&gt;
					&lt;td&gt;生成回答的主模型&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Critic&lt;/td&gt;
					&lt;td&gt;估计价值，计算优势函数&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Reward Model&lt;/td&gt;
					&lt;td&gt;给回答质量打分&lt;/td&gt;
					&lt;td&gt;否（通常预训练好）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Reference Model&lt;/td&gt;
					&lt;td&gt;计算 KL 散度，防止策略偏离初始模型&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;ppo-vs-dpo&#34;&gt;PPO vs DPO&lt;/h4&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;对比项&lt;/th&gt;
					&lt;th&gt;PPO&lt;/th&gt;
					&lt;th&gt;DPO&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;训练范式&lt;/td&gt;
					&lt;td&gt;强化学习（on-policy）&lt;/td&gt;
					&lt;td&gt;监督学习（off-policy）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;是否需要奖励模型&lt;/td&gt;
					&lt;td&gt;需要&lt;/td&gt;
					&lt;td&gt;不需要&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;实现复杂度&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据利用率&lt;/td&gt;
					&lt;td&gt;低，只能用当前策略生成的数据&lt;/td&gt;
					&lt;td&gt;高，历史偏好数据都能用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;稳定性&lt;/td&gt;
					&lt;td&gt;较敏感，容易 reward hacking&lt;/td&gt;
					&lt;td&gt;更稳定&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;数据少的时候优先用 DPO&lt;/strong&gt;，它只需要 &lt;code&gt;(prompt, chosen, rejected)&lt;/code&gt; 三元组；等数据量和工程能力都上来了，再考虑 PPO。&lt;/p&gt;
&lt;h3 id=&#34;36-dpo-的-beta-参数&#34;&gt;3.6 DPO 的 beta 参数&lt;/h3&gt;
&lt;p&gt;beta 控制模型对偏好差异的敏感程度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;beta 小：偏好信号平滑，训练稳定，但可能学不到足够强的偏好。&lt;/li&gt;
&lt;li&gt;beta 适中（0.5-1.0）：常用默认值。&lt;/li&gt;
&lt;li&gt;beta 大：偏好差异被放大，模型对偏好更敏感，但可能过拟合或不稳定。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;37-把用户行为变成-dpo-数据&#34;&gt;3.7 把用户行为变成 DPO 数据&lt;/h3&gt;
&lt;p&gt;如果你运营一个 ChatGPT 类网站，用户行为天然就是偏好信号：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;用户行为&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
					&lt;th&gt;DPO 用法&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;点赞&lt;/td&gt;
					&lt;td&gt;喜欢这个回答&lt;/td&gt;
					&lt;td&gt;当前回答为 chosen&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;点踩&lt;/td&gt;
					&lt;td&gt;不喜欢&lt;/td&gt;
					&lt;td&gt;当前回答为 rejected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;重新生成&lt;/td&gt;
					&lt;td&gt;否定当前，偏好新的&lt;/td&gt;
					&lt;td&gt;新回答为 chosen，旧的为 rejected&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;复制/分享&lt;/td&gt;
					&lt;td&gt;非常满意&lt;/td&gt;
					&lt;td&gt;当前回答为 chosen&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于小红书这类图文混合平台，停留时长受图片影响大，需要结合点赞、收藏等行为综合判断；知乎这类长文本平台，停留时长、评论互动更能反映内容质量。&lt;/p&gt;
&lt;h3 id=&#34;38-对齐隐私与提示词注入&#34;&gt;3.8 对齐、隐私与提示词注入&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;对齐问题&lt;/strong&gt;：模型目标函数与人类真实意图不一致。解决办法包括 RLHF/DPO、安全微调、拒绝训练、输出审查等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;隐私保护&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;训练前脱敏、移除 PII。&lt;/li&gt;
&lt;li&gt;训练中使用差分隐私优化。&lt;/li&gt;
&lt;li&gt;训练后扫描模型是否记住了敏感信息。&lt;/li&gt;
&lt;li&gt;部署时加输出拦截和 prompt 注入检测。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;通过微调防御提示词注入&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在训练数据里加入大量注入攻击样本，标注正确拒答。&lt;/li&gt;
&lt;li&gt;对抗式微调：生成各种攻击变体让模型学习。&lt;/li&gt;
&lt;li&gt;强化系统角色一致性，让模型坚持原始身份。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四从面试题到工程实践&#34;&gt;四、从面试题到工程实践&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;嵌入模型优先用现成的&lt;/strong&gt;。MTEB 上排名靠前的模型（如 BGE、E5、GTE）通常足够好用，不要自己从头训练。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据少时试试 SetFit&lt;/strong&gt;。几百条标注也能做出不错的分类器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;大模型微调先 LoRA/QLoRA&lt;/strong&gt;。全参数微调太贵，LoRA 是性价比之选。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RLHF 先 DPO 后 PPO&lt;/strong&gt;。DPO 实现简单、数据利用率高，适合起步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不要迷信排行榜&lt;/strong&gt;。榜单分数高不代表业务效果好，要结合实际场景评估。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;评估指标要对齐业务目标&lt;/strong&gt;。分类看 F1，检索看 Recall@K，生成看人工评估，不要只看 loss。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;结语&#34;&gt;结语&lt;/h2&gt;
&lt;p&gt;Part 3 的内容从“怎么训练嵌入模型”讲到“怎么微调分类模型”，再到“怎么对齐生成模型”。对初级开发者来说，重点是理解这些技术的&lt;strong&gt;适用场景和 trade-off&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;嵌入模型：双编码器快但粗，交叉编码器慢但准；负样本决定对比学习效果。&lt;/li&gt;
&lt;li&gt;表示微调：数据少就用 SetFit，数据多就全量微调；领域适配要注意灾难性遗忘。&lt;/li&gt;
&lt;li&gt;生成模型微调：SFT 是起点，LoRA 省钱，DPO/PPO 对齐人类偏好。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;掌握这些，你就能从“会调用模型”进阶到“会根据业务需求选择和调整模型”。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;参考：《生成式AI原理与实战 —— Part 3》&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
  </channel>
</rss>
