<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>ChromaDB on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/chromadb/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Tue, 10 Feb 2026 11:00:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/chromadb/index.xml" rel="self" type="application/rss+xml" /><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>
    
  </channel>
</rss>
