generative-ai-for-beginners 实战:使用文本嵌入(Embeddings)与余弦相似度构建语义视频搜索应用
2026/9/11 16:37:58 网站建设 项目流程

generative-ai-for-beginners 实战:使用文本嵌入(Embeddings)与余弦相似度构建语义视频搜索应用

【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners

本教程基于开源课程仓库 generative-ai-for-beginners 第 8 课「构建搜索应用」,完整讲解如何利用 OpenAI 文本嵌入模型将 YouTube 视频字幕转化为可检索的 Embedding 索引,并据此构建一个能理解自然语言问题、返回相关视频以及精确答案时间点的语义搜索应用。学完后你将掌握语义搜索与关键词搜索的区别、文本嵌入的原理与生成方式、嵌入索引的构建流水线,以及用 Pandas + 余弦相似度实现搜索应用的完整技能。

为什么需要构建搜索应用

大语言模型(LLM)的能力远不止聊天机器人和文本生成,借助Embeddings(文本嵌入)同样可以构建搜索应用。嵌入是数据的数值化表示,也叫向量,可用于对数据进行语义搜索。

本课的应用场景来自一个教育创业公司:这是一家非营利组织,为发展中国家的学生提供免费 AI 教育,拥有大量 YouTube 教学视频。公司希望构建一个搜索应用,让学生通过输入一个问题来搜索相关视频。例如学生输入 "What are Jupyter Notebooks?" 或 "What is Azure ML",应用不仅会返回与问题相关的视频列表,更能返回视频中答案所在位置的精确链接(带时间戳)

课程的素材是微软 AI Show YouTube 频道的字幕嵌入索引,该索引覆盖截至 2023 年 10 月的所有视频字幕。下图展示了对 "can you use rstudio with azure ml?" 进行语义查询的结果,注意 YouTube URL 中带有时间戳,可直接跳到答案所在位置:

语义搜索与关键词搜索

语义搜索是一种利用查询词中词语的语义(含义)来返回相关结果的搜索技术。例如你想买车,搜索 "my dream car",语义搜索会理解你并不是在"做梦(dreaming)"关于一辆车,而是想购买你的"理想(ideal)"汽车——它理解你的意图并返回相关结果。而关键词搜索则字面地搜索关于汽车的"梦",往往会返回不相关的结果。

这正是向量检索的核心价值:即使查询文本与文档文本没有相同的字面词汇,只要语义相近,也能被检索命中。

什么是文本嵌入

文本嵌入(Text Embeddings)是自然语言处理(NLP)中的文本表示技术,是文本的语义数值表示,用机器易于理解的方式表示数据。构建文本嵌入的模型有很多,本课聚焦于OpenAI Embedding 模型

以一个 AI Show 字幕片段为例:

Today we are going to learn about Azure Machine Learning.

将该文本传入 OpenAI Embedding API,会返回一个由1536 个数字组成的嵌入(即向量),向量中的每个数字代表文本的不同语义方面。为简洁起见,这里展示前 10 个数字:

[-0.006655829958617687, 0.0026128944009542465, 0.008792596869170666, -0.02446001023054123, -0.008540431968867779, 0.022071078419685364, -0.010703742504119873, 0.003311325330287218, -0.011632772162556648, -0.02187200076878071, ...]

可以这样理解:语义相近的文本,其向量在 1536 维空间中彼此靠近(夹角更小);语义无关的文本则相距较远。这正是后续一切检索计算的基础。

嵌入索引是如何创建的

本课的嵌入索引由一系列 Python 脚本构建,脚本与说明位于 08-building-search-applications/scripts/README.md。完成课程不需要运行这些脚本,因为索引文件已随仓库提供(即 embedding_index_3m.json)。但理解流水线对生产实践至关重要。

整个流水线由 prepare_transcripts_ai_show.sh 编排,依次执行以下 6 步:

  1. 下载字幕:transcript_download.py 通过 YouTube Data API(v3)分页拉取播放列表中的视频元数据,并使用youtube_transcript_api下载每段字幕,保存为.json.vtt文件;脚本用 40 个线程并发处理队列,提高大批量下载效率。
  2. 提取演讲者:transcript_enrich_speaker.py 利用 OpenAI Functions(函数调用)从视频标题、描述和前 3 分钟字幕中提取演讲者姓名。源码中定义了一个名为get_speaker_name的函数工具,要求模型返回逗号分隔的演讲者列表,并通过temperature=0.0保证提取的确定性,结果写入每个视频的元数据。
  3. 按 3 分钟分块:transcript_enrich_bucket.py 将字幕切分为3 分钟的文本段(segment)。每个分段会从下一个分段重叠约 20 个词,目的是确保分段的嵌入不被截断,并提供更好的检索上下文。源码还用tiktoken统计 token 数(MAX_TOKENS=2048),为下一步摘要预留空间;每个分段记录start(形如00:00:00的时间字符串)和seconds(秒数)字段,这正是应用能生成时间戳链接的关键。
  4. 生成摘要:transcript_enrich_summaries.py 将每个分段文本传给 OpenAI Chat API,生成约 60 词的权威摘要(系统提示要求避免以 "This video" 开头),摘要同样存入索引。
  5. 生成嵌入:transcript_enrich_embeddings.py 将分段文本传给 OpenAI Embedding API(部署名为text-embedding-ada-002),返回 1536 维向量并存入分段记录的ada_v2字段。脚本先对文本做归一化(去除多余空格、换行、..等噪声),并用tiktokencl100k_base编码器跳过超过 8191 token 的超长文本。
  6. 生成精简索引:transcript_enrich_lite.py 从富化结果中移除textdescription字段,得到体积更小的索引文件,最终由 shell 脚本重命名为embedding_index_3m.json

最终索引中每条记录的结构如下(来自仓库内 embedding_index_3m.json 的实际数据):

{ "speaker": "Seth Juarez, Josh Lovejoy, Sarah Bird", "title": "You're Not Solving the Problem You Think You're Solving", "videoId": "-tJQm4mSh1s", "start": "00:00:00", "seconds": 0, "summary": "Join Seth Juarez as he discusses ethical concerns with AI...", "ada_v2": [0.0043573323637247086, -0.02840915322303772, ...] }

向量数据库

为简化课程,嵌入索引存储为 JSON 文件并加载到 Pandas DataFrame 中。但在生产环境中,嵌入索引应存储在向量数据库中,例如 Azure Cognitive Search、Redis、Pinecone、Weaviate 等,以便在海量向量上提供高性能的相似度检索与持久化管理。

理解余弦相似度

知道文本嵌入之后,下一步是学会用嵌入搜索数据:即用余弦相似度找出与给定查询最相似的嵌入。

余弦相似度是衡量两个向量相似度的指标,也常被称为最近邻搜索(nearest neighbor search)。执行余弦相似度搜索的步骤是:

  1. 用 OpenAI Embedding API 对查询文本进行向量化;
  2. 计算查询向量与索引中每个向量(索引中每个 YouTube 字幕分段都有一个向量)之间的余弦相似度;
  3. 按余弦相似度排序,相似度最高的文本分段即与查询最相似。

从数学角度看,余弦相似度度量的是投影在多维空间中的两个向量之间夹角的余弦。这一度量很有价值:如果两个文档因规模(长度)原因在欧氏距离上相距很远,它们之间的夹角仍可能很小,从而获得更高的余弦相似度——也就是说,它关注的是"方向"而非"距离"。

构建你的第一个搜索应用

现在正式构建搜索应用:允许学生输入问题来搜索视频,返回相关问题视频列表,并给出答案所在位置的视频链接。

该解决方案已在 Windows 11、macOS 和 Ubuntu 22.04 上使用Python 3.10 或更高版本构建并测试通过。

任务:创建 Azure OpenAI 服务

构建搜索应用需要 Azure OpenAI 服务,首先在Azure Cloud Shell中完成资源创建(需要 Azure 订阅):

  1. 登录 Azure 门户,点击右上角的 Cloud Shell 图标,选择Bash环境类型。

  2. 创建资源组(本课使用 East US 的semantic-video-search;可改名,但更换资源位置时需查询模型可用性表):

az group create --name semantic-video-search --location eastus
  1. 创建 Azure OpenAI Service 资源
az cognitiveservices account create --name semantic-video-openai --resource-group semantic-video-search \ --location eastus --kind OpenAI --sku s0
  1. 获取端点与密钥(供应用配置使用):
az cognitiveservices account show --name semantic-video-openai \ --resource-group semantic-video-search | jq -r .properties.endpoint az cognitiveservices account keys list --name semantic-video-openai \ --resource-group semantic-video-search | jq -r .key1
  1. 部署 OpenAI Embedding 模型(部署名text-embedding-ada-002,版本 2):
az cognitiveservices account deployment create \ --name semantic-video-openai \ --resource-group semantic-video-search \ --deployment-name text-embedding-ada-002 \ --model-name text-embedding-ada-002 \ --model-version "2" \ --model-format OpenAI \ --sku-capacity 100 --sku-name "Standard"

说明:若要自行重跑字幕数据准备流水线,还需额外部署gpt-4o-mini(用于演讲者提取与摘要生成),并配置AZURE_OPENAI_API_KEYAZURE_OPENAI_ENDPOINTAZURE_OPENAI_MODEL_DEPLOYMENT_NAMEGOOGLE_DEVELOPER_API_KEY四个环境变量,详见 08-building-search-applications/scripts/README.md。

解决方案:语义搜索 notebook

打开解决方案 notebook 08-building-search-applications/python/aoai-solution.ipynb,在 GitHub Codespaces 中按 Jupyter Notebook 指引运行。运行时需要.env中配置好AZURE_OPENAI_API_KEYAZURE_OPENAI_ENDPOINTAZURE_OPENAI_EMBEDDINGS_DEPLOYMENT,依赖库见 08-building-search-applications/python/requirements.txt。

notebook 的核心代码逻辑如下:

1. 加载嵌入索引到 Pandas DataFrame,并丢弃体积较大的text字段:

def load_dataset(source: str) -> pd.core.frame.DataFrame: # Load the video session index pd_vectors = pd.read_json(source) return pd_vectors.drop(columns=["text"], errors="ignore").fillna("")

2. 定义余弦相似度函数与搜索函数get_videos,执行流程为:复制索引 → 用 Embedding API 计算查询向量 → 新增similarity列(每行分段的余弦相似度)→ 按阈值0.75过滤 → 按相似度降序排序并返回前 5 条:

SIMILARITIES_RESULTS_THRESHOLD = 0.75 DATASET_NAME = "../embedding_index_3m.json" def cosine_similarity(a, b): if len(a) > len(b): b = np.pad(b, (0, len(a) - len(b)), 'constant') elif len(b) > len(a): a = np.pad(a, (0, len(b) - len(a)), 'constant') return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)) def get_videos(query: str, dataset: pd.core.frame.DataFrame, rows: int) -> pd.core.frame.DataFrame: # create a copy of the dataset video_vectors = dataset.copy() # get the embeddings for the query query_embeddings = client.embeddings.create(input=query, model=model).data[0].embedding # create a new column with the calculated similarity for each row video_vectors["similarity"] = video_vectors["ada_v2"].apply( lambda x: cosine_similarity(np.array(query_embeddings), np.array(x)) ) # filter the videos by similarity mask = video_vectors["similarity"] >= SIMILARITIES_RESULTS_THRESHOLD video_vectors = video_vectors[mask].copy() # sort the videos by similarity video_vectors = video_vectors.sort_values(by="similarity", ascending=False).head(rows) # return the top rows return video_vectors.head(rows)

3. 展示结果display_results使用记录中的videoIdseconds字段拼接https://youtu.be/{video_id}?t={seconds}形式的带时间戳链接,并打印标题、摘要前 15 个词、相似度分数与演讲者:

def display_results(videos: pd.core.frame.DataFrame, query: str): def _gen_yt_url(video_id: str, seconds: int) -> str: return f"https://youtu.be/{video_id}?t={seconds}" print(f"\nVideos similar to '{query}':") for _, row in videos.iterrows(): youtube_url = _gen_yt_url(row["videoId"], row["seconds"]) print(f" - {row['title']}") print(f" Summary: {' '.join(row['summary'].split()[:15])}...") print(f" YouTube: {youtube_url}") print(f" Similarity: {row['similarity']}") print(f" Speakers: {row['speaker']}")

4. 交互查询循环:加载索引后反复提示用户输入查询,输入exit退出:

pd_vectors = load_dataset(DATASET_NAME) while True: query = input("Enter a query: ") if query == "exit": break videos = get_videos(query, pd_vectors, 5) display_results(videos, query)

运行 notebook 后会出现查询输入框:

可以尝试以下示例查询:

  • What is Azure Machine Learning?
  • How do convolutional neural networks work?
  • What is a neural network?
  • Can I use Jupyter Notebooks with Azure Machine Learning?
  • What is ONNX?

小结:从视频到可检索的知识

本课完成了从"视频字幕"到"可语义检索知识库"的完整闭环:通过 3 分钟分段 + 重叠词 + 摘要 +text-embedding-ada-002嵌入构建了 embedding_index_3m.json 索引;搜索端则利用 Pandas 与余弦相似度实现语义查询,并借助seconds字段生成直达答案位置的时间戳链接。这套"嵌入索引 + 相似度检索"的模式,正是 RAG(检索增强生成)、企业知识库搜索等生产级 AI 应用的核心基石,区别仅在于生产环境会将 JSON 索引替换为 Redis、Pinecone、Weaviate 或 Azure Cognitive Search 等向量数据库。

继续学习可前往下一课 构建图像生成应用,掌握多模态生成能力。

【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询