ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LLM Zoomcamp 2025 向量搜索作业详解:用 fastembed 与 Qdrant 从零实现嵌入、余弦排序与向量检索

LLM Zoomcamp 2025 向量搜索作业详解:用 fastembed 与 Qdrant 从零实现嵌入、余弦排序与向量检索 LLM Zoomcamp 2025 向量搜索作业详解用 fastembed 与 Qdrant 从零实现嵌入、余弦排序与向量检索【免费下载链接】llm-zoomcampLLM Zoomcamp - a free online course about real-life applications of LLMs. In 10 weeks you will learn how to build an AI system that answers questions about your knowledge base. Register here 项目地址: https://gitcode.com/GitHub_Trending/ll/llm-zoomcamp本文以 LLM Zoomcamp 2025 版第 2 周作业Vector Search为主体完整讲解如何用 fastembed 生成文本嵌入、用点积计算余弦相似度、在本地实现基于余弦相似度的文档排序并进一步把文档索引进 Qdrant 完成端到端的向量检索。读完后你将能够独立完成从文本向量化到向量库检索的全链路操作并理解嵌入模型维度、归一化向量与距离度量选择之间的内在关系。1. 作业背景与整体技术栈该作业位于 2025 年课程的第 2 周模块Vector Search中完整题目见 homework.md。它与模块主线保持一致使用 Qdrant 作为向量数据库使用 fastembed 作为本地嵌入库。官方解答 notebook 位于 homework_solution.ipynb模块主 notebook 为 sematic_search.ipynb文件名中的拼写沿用仓库原始命名。作业原文中特别提示Its possible that your answers wont match exactly. If its the case, select the closest one.也就是说由于浮点精度、模型版本等差异你的运行结果可能和标准答案有微小偏差选最接近的选项即可。原文还建议如果想深入了解向量搜索的底层原理手动实现检索引擎、hit-rate 评估、Elasticsearch 近似检索等可以对照 2024 年队列第 3 周的作业Q1-Q4。与 2024 版作业相比2025 版有一个明显的技术栈变化2024 版使用sentence_transformers的SentenceTransformer模型multi-qa-distilbert-cos-v1768 维而 2025 版改用轻量的fastembedONNX Runtime 推理CPU 友好。模块 README 中给出的安装与启动方式如下见 README.mdpip install -q qdrant-client[fastembed]1.14.2docker pull qdrant/qdrant docker run -p 6333:6333 -p 6334:6334 \ -v $(pwd)/qdrant_storage:/qdrant/storage:z \ qdrant/qdrant其中 6333 是 REST API 端口6334 是 gRPC 端口-v挂载用于数据持久化。fastembed 版本要求 1.14.2是支持 Qdrant本地推理local inference的前提——即可以直接把文本传给 Qdrant 客户端由 fastembed 在本机完成向量化。安装 fastembed 库本身只需pip install fastembedfrom fastembed import TextEmbedding2. Q1嵌入一条查询Embedding the QueryQ1 的要求是使用jinaai/jina-embeddings-v2-small-en模型嵌入查询语句I just discovered the course. Can I join now?得到一个 512 维的 numpy 数组然后回答该数组的最小值是多少。选项为-0.51 / -0.11 / 0 / 0.51。结合解答 notebook 的实际运行代码标准做法如下from fastembed import TextEmbedding import numpy as np embedder TextEmbedding(model_namejinaai/jina-embeddings-v2-small-en) query I just discovered the course. Can I join now? q, list(embedder.embed(query)) # embed 返回迭代器解包出第一个向量几个值得注意的实现细节embedder.embed()返回的是一个可迭代的向量生成器所以用q, list(...)解包单条查询的向量如果一次嵌入多条文本list(embedder.embed([...]))会返回与输入等长的向量列表。解答 notebook 中 Q3/Q4 批量嵌入时正是利用这一特性直接把 pandas 的 Series 传入list(embedder.embed(df.text))。解答中q.min()的实际输出为np.float64(-0.11726373885183883)因此正确选项是-0.11。模型参数方面jinaai/jina-embeddings-v2-small-en是英文单模态模型512 维约 0.12 GB支持 8192 token 截断这些元数据可通过TextEmbedding.list_supported_models()查到模块 notebook sematic_search.ipynb 中即用此方法筛选了 512 维的候选模型。3. 余弦相似度为什么可以直接用点积作业文档在 Q1 之后专门插入了一个Cosine similarity小节这是理解整个作业的关键前提The vectors that our embedding model returns are already normalized: their length is 1.0.嵌入模型输出的向量已经是归一化的范数为 1.0因此两个向量之间的余弦相似度可以直接用点积计算无需再除以模长。作业给出了验证方法import numpy as np np.linalg.norm(q) # 解答中输出 np.float64(1.0)q.dot(q) # 向量与自身的余弦相似度 1.0解答 notebook 中q.dot(q)的实际输出是np.float64(1.0000000000000002)——浮点误差使其略大于 1这属于正常现象。Q2与另一个向量的余弦相似度。嵌入文档doc Can I still join the course after the start date? d, list(embedder.embed(doc))计算q.dot(d)选项为 0.3 / 0.5 / 0.7 / 0.9。解答中实际输出为np.float64(0.9008528895674547)因此选0.9。这正体现了向量检索的价值查询与文档几乎没有共同的关键词just discovered vs still join after the start date但语义高度一致余弦相似度接近 1.0。4. Q3 与 Q4基于余弦相似度的文档排序Q3/Q4 使用同一组 5 条 FAQ 文档均为data-engineering-zoomcamp的课程相关问答字段结构为text/section/question/course。完整数据直接摘自作业原文也出现在 homework_solution.ipynb 中documents [{text: Yes, even if you dont register, youre still eligible to submit the homeworks.\nBe aware, however, that there will be deadlines for turning in the final projects. So dont leave everything for the last minute., section: General course-related questions, question: Course - Can I still join the course after the start date?, course: data-engineering-zoomcamp}, {text: Yes, we will keep all the materials after the course finishes, so you can follow the course at your own pace after it finishes.\nYou can also continue looking at the homeworks and continue preparing for the next cohort. I guess you can also start working on your final capstone project., section: General course-related questions, question: Course - Can I follow the course after it finishes?, course: data-engineering-zoomcamp}, {text: The purpose of this document is to capture frequently asked technical questions\nThe exact day and hour of the course will be 15th Jan 2024 at 17h00. The course will start with the first “Office Hours live.1\nSubscribe to course public Google Calendar (it works from Desktop only).\nRegister before the course starts using this link.\nJoin the course Telegram channel with announcements.\nDon’t forget to register in DataTalks.Clubs Slack and join the channel., section: General course-related questions, question: Course - When will the course start?, course: data-engineering-zoomcamp}, {text: You can start by installing and setting up all the dependencies and requirements:\nGoogle cloud account\nGoogle Cloud SDK\nPython 3 (installed with Anaconda)\nTerraform\nGit\nLook over the prerequisites and syllabus to see if you are comfortable with these subjects., section: General course-related questions, question: Course - What can I do before the course starts?, course: data-engineering-zoomcamp}, {text: Star the repo! Share it with friends if you find it useful ❣️\nCreate a PR if you see you can improve the text or the structure of the repository., section: General course-related questions, question: How can we contribute to the course?, course: data-engineering-zoomcamp}]4.1 Q3仅对text字段嵌入排序要求计算text字段的嵌入并求查询向量与所有文档的余弦相似度回答相似度最高的文档下标从 0 开始。作业给出的提示是把 5 个向量放进一个二维矩阵V后相似度计算就是一次矩阵乘法V np.array(list(embedder.embed([d[text] for d in documents]))) similarity V.dot(q) similarity.argmax() # 相似度最高者的下标解答 notebook 中这一步的实际输出V_text list(embedder.embed(df.text)) V_text np.array(V_text) similarity V_text.dot(q) # array([0.76296845, 0.81823782, 0.80853974, 0.71330788, 0.73044992]) similarity.argmax() # np.int64(1)可见 5 个相似度分别为约 0.76、0.82、0.81、0.71、0.73Q3 答案是下标 1Can I follow the course after it finishes? 那条文档。4.2 Q4改用question text拼接字段Q4 要求计算一个新字段——question与text的拼接full_text doc[question] doc[text]再嵌入并计算与查询向量的余弦相似度回答得分最高的文档。解答 notebook 的实现V_text list(embedder.embed(df.question df.text)) V_text np.array(V_text) similarity V_text.dot(q) similarity.argmax() # np.int64(0)Q4 答案是下标 0。作业原文追问是否与 Q3 不同为什么——结合输出可以回答不同Q3 是 1Q4 是 0。原因是文档 0 的question字段本身Can I still join the course after the start date?与查询句Can I join now?语义几乎完全重合把问题文本并入嵌入内容后它的相似度被显著拉高并超过了原本仅靠答案文本胜出的文档 1。这个对比恰好说明了**嵌入哪个字段是影响检索效果的核心设计决策**在 Q6 的 Qdrant 索引 以及模块的混合搜索实践见 rag.ipynb 中对question字段使用 3.0 权重 boost中question answer 联合嵌入 / 加权正是课程反复使用的套路。5. Q5选择嵌入模型——fastembed 的最小维度Q5 要求选出 fastembed 支持模型中最小的维度选项为 128 / 256 / 384 / 512并使用其中之一BAAI/bge-small-en。从源码结构看fastembed 把模型目录暴露为类方法TextEmbedding.list_supported_models()返回每个模型的model、sources、model_file、license、size_in_GB、dim等字段。作业解答 notebook 中的实际用法import pandas as pd models TextEmbedding.list_supported_models() df_models pd.DataFrame(models) df_models[df_models.dim df_models.dim.min()]筛选出最小维度后的结果包含BAAI/bge-small-en、BAAI/bge-small-en-v1.5、snowflake/snowflake-arctic-embed-xs等dim均为384模型文件约 0.13 GBMIT 许可model_optimized.onnx量化权重。因此Q5 答案是 384后续 Q6 使用BAAI/bge-small-en。这里可以归纳出嵌入模型选择的一般权衡模块 notebook 中也有相应讨论维度越高通常语义表达越强但存储与内存开销越大本地 CPU 推理场景下384/512 维的小模型是课程推荐的档位。6. Q6把 FAQ 索引进 Qdrant 并检索2 分Q6 是整份作业的压轴题也是唯一需要使用 Qdrant 的部分。分为三步加载数据、建集索引进、查询取分。6.1 加载 machine-learning-zoomcamp 的 FAQ 数据作业原文给定的加载代码import requests docs_url https://github.com/alexeygrigorev/llm-rag-workshop/raw/main/notebooks/documents.json docs_response requests.get(docs_url) documents_raw docs_response.json() documents [] for course in documents_raw: course_name course[course] if course_name ! machine-learning-zoomcamp: continue for doc in course[documents]: doc[course] course_name documents.append(doc)注意两个细节documents_raw是按课程分组的外层列表每条doc上手动写入了course字段这与 sematic_search.ipynb 中把course存为 payload 元数据、用于后续过滤的设计一脉相承。6.2 创建集合与写入点按照 Q5 选定的模型解答 notebook 中的关键配置from qdrant_client import QdrantClient, models qd_client QdrantClient(http://localhost:6333) EMBEDDING_DIMENSIONALITY 384 model_handle BAAI/bge-small-en collection_name llmzoomcamp-homework qd_client.delete_collection(collection_namecollection_name) qd_client.create_collection( collection_namecollection_name, vectors_configmodels.VectorParams( sizeEMBEDDING_DIMENSIONALITY, distancemodels.Distance.COSINE ) )三个配置项的对应关系值得记住size必须与模型输出维度一致384distance选择COSINE与嵌入模型按余弦相似度训练的假设一致与第 3 节中点积即余弦的原理呼应。写入点时使用 Qdrant 客户端的本地嵌入能力——vector参数不传向量本身而是传一个models.Document(text..., model...)描述符客户端会在本机调用 fastembed 完成向量化points [] for i, doc in enumerate(documents): text doc[question] doc[text] vector models.Document(texttext, modelmodel_handle) point models.PointStruct( idi, vectorvector, payloaddoc ) points.append(point) qd_client.upsert( collection_namecollection_name, pointspoints )这里再次体现了 Q4 的结论索引用的是question text拼接文本作业明确要求 use both question and answer fields而不是单独的答案文本。payloaddoc则把整条 FAQ 记录作为元数据存储检索时可随结果一并返回。首次运行时 fastembed 会自动下载模型文件到本地缓存目录解答 notebook 的输出中可见 Fetching 5 files 与model_optimized.onnx约 133 MB 的下载进度。6.3 查询并读取得分用 Q1 的查询句对集合发起检索question I just discovered the course. Can I join now? query_points qd_client.query_points( collection_namecollection_name, querymodels.Document( textquestion, modelmodel_handle ), limit5, with_payloadTrue )with_payloadTrue让结果携带 payload 元数据。解答 notebook 中第一条结果query_points.points[0]的实际输出ScoredPoint(id14, score0.87031734, payload{question: The course has already started. Can I still join it?, text: Yes, you can. You won’t be able to submit some of the homeworks, ..., course: machine-learning-zoomcamp, ...})首条结果的score为 0.87031734因此Q6 答案是 0.87。命中的文档id14The course has already started. Can I still join it?与查询语义完全对应验证了question text 联合嵌入对课程 FAQ 类数据的检索效果。7. 答案速查与扩展学习题目考察点答案Q1jina-v2-small-en 嵌入的最小值-0.11实测 -0.11726Q2查询与文档的余弦相似度点积0.9实测 0.90085Q3仅嵌入text字段的最高相似度下标1Q4嵌入question text拼接后的最高下标0因 question 字段与查询高度同义排名变化Q5fastembed 支持模型的最小维度384如 BAAI/bge-small-enQ6Qdrant 检索首条结果得分0.87实测 0.87031734结果可能因模型文件版本与浮点精度略有出入作业时选取最接近的选项即可。进一步学习路径均可在本仓库内找到对应材料完整模块主线Docker 启动 Qdrant、fastembed 选模型、建集合、本地嵌入写入、相似度检索与must过滤的完整演示见 sematic_search.ipynb混合检索关键词 向量与字段 boost 的实践见 hybrid_search.ipynb 与 rag.ipynb想手动实现检索引擎并理解 hit-rate、精确检索与近似检索ANN的差异见 2024 年队列第 3 周作业及其解答 homework_solution.ipynb其中给出了VectorSearchEngine的embeddings.dot(v_query)np.argsort(-scores)极简实现课程整体结构与后续作业入口见 2025 队列 README。完成本作业后你应该已经掌握了向量检索的完整闭环选择与数据规模匹配的嵌入模型、验证向量归一化特性、用矩阵乘法批量计算余弦排序、理解嵌入哪个字段对结果的影响以及把这套逻辑落到 Qdrant 这类生产级向量库上的标准操作建集合、本地嵌入 upsert、query_points检索取分。这正是后续 RAG、混合搜索与评估模块2025 队列 Module 3的直接基础。【免费下载链接】llm-zoomcampLLM Zoomcamp - a free online course about real-life applications of LLMs. In 10 weeks you will learn how to build an AI system that answers questions about your knowledge base. Register here 项目地址: https://gitcode.com/GitHub_Trending/ll/llm-zoomcamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表