2026/6/20 9:01:08
网站建设
项目流程
php网站开发入门,青岛 公司 网站建设,惠州城乡住房建设厅网站,昆山网站建设河北各位同仁#xff0c;各位对人工智能充满热情的开发者们#xff0c;大家上午好#xff01;今天#xff0c;我将带领大家深入探讨一个在大型语言模型#xff08;LLM#xff09;时代日益重要的技术#xff1a;Few-shot Prompting 中的动态采样 (Dynamic Sampling in Few-sh…各位同仁各位对人工智能充满热情的开发者们大家上午好今天我将带领大家深入探讨一个在大型语言模型LLM时代日益重要的技术Few-shot Prompting 中的动态采样 (Dynamic Sampling in Few-shot Prompting)。具体来说我们将聚焦于如何利用强大的向量索引 (Vector Indexes)技术为每一个特定的问题智能地匹配并检索出最相关的示例从而显著提升我们与LLM交互的效率和效果。在过去几年里LLM展现出了令人惊叹的语言理解和生成能力。从文本摘要到代码生成从情感分析到复杂推理它们的应用场景几乎无所不包。然而要让这些模型在特定任务上发挥最佳性能仅仅提供一个简单的指令往往是不够的。这就是 Few-shot Prompting 登场的原因。第一章Few-shot Prompting 的基石与挑战1.1 Few-shot Prompting 概述Few-shot Prompting顾名思义是指在向大型语言模型发出请求时除了提供任务指令和待处理的查询Query之外还会附带少量few相关的输入-输出示例。这些示例作为“情境学习”In-context Learning的载体能够极大地指导LLM理解任务的意图、期望的输出格式以及潜在的约束条件。其基本结构通常如下[任务指令] [示例1的输入] [示例1的输出] [示例2的输入] [示例2的输出] ... [示例N的输入] [示例N的输出] [待处理查询的输入]为什么 Few-shot Prompting 如此有效情境学习In-context Learning:LLM在大量数据上预训练后已经具备了强大的模式识别能力。通过提供少量示例模型能够快速识别出当前任务的模式并将其泛化到新的查询上而无需进行参数微调。降低歧义性:明确的示例能够消除指令中可能存在的歧义确保模型理解任务的精确要求。引导输出格式:如果我们希望模型以特定的JSON格式、代码结构或摘要风格输出示例是最佳的教学工具。适应特定领域/风格:对于专业术语、特定行业规范或独特写作风格的任务示例能够帮助模型快速适应。1.2 示例选择的困境从静态到动态的需求尽管 Few-shot Prompting 威力巨大但其效果却高度依赖于所选示例的质量和相关性。一个不相关的示例不仅不会帮助模型反而可能引入噪声导致模型产生错误或次优的输出。早期或简单的 Few-shot Prompting 策略通常面临以下问题静态示例集:开发者为所有查询都使用一组固定的示例。优点:简单易实现。缺点:缺乏通用性。对于多样化的查询固定的示例集很难做到对所有情况都相关。例如一个关于法律文件的示例对技术文档摘要的查询可能毫无帮助。随机示例选择:从一个大型示例库中随机抽取 N 个示例。优点:避免了静态示例的局限性在一定程度上引入了多样性。缺点:效率低下。随机选择的示例很可能与当前查询毫不相关导致LLM“迷失方向”甚至产生负面影响Negative Prompting。这些方法都未能解决核心问题如何为当前的具体问题找到语义上最贴近、信息上最互补的“情境学习”材料答案就是动态采样 (Dynamic Sampling)。我们需要的不是一劳永逸的示例集也不是盲目的随机选择而是一个能够根据每个新查询的上下文智能地从一个更大的示例库中筛选出最相关、最有助于模型理解和解决当前问题的示例的机制。这正是我们今天讲座的核心利用向量索引实现 Few-shot Prompting 的动态采样。第二章向量嵌入文本的数学指纹要实现动态采样我们首先需要一种方法来量化文本之间的“相关性”。自然语言文本是离散的符号序列计算机难以直接处理其语义。而向量嵌入 (Vector Embeddings)技术正是解决这个问题的关键。2.1 什么是向量嵌入向量嵌入是将文本单词、短语、句子、段落甚至整个文档转换成高维实数向量的技术。这些向量捕捉了文本的语义信息使得语义上相似的文本在向量空间中也彼此靠近而语义上不相关的文本则距离较远。例如在某个嵌入空间中“苹果公司”和“微软”的向量会比“苹果公司”和“香蕉”的向量更接近。“编程”和“软件开发”的向量会比“编程”和“烹饪”的向量更接近。2.2 向量嵌入的生成生成向量嵌入的技术多种多样但核心思想都是利用深度学习模型特别是Transformer架构的模型如BERT、RoBERTa、GPT等在海量文本数据上进行预训练。这些模型学习如何将文本映射到稠密的向量空间。常用的嵌入模型包括Sentence-BERT (SBERT) 系列:专门为句子和短语嵌入优化能够高效地生成高质量的句子向量。例如all-MiniLM-L6-v2、paraphrase-MiniLM-L6-v2等。OpenAI Embeddings API:OpenAI 提供了强大的嵌入模型如text-embedding-ada-002通过API调用即可生成高质量的文本嵌入。其他专有或开源模型:许多公司和研究机构都发布了各自的嵌入模型有些针对特定领域进行了优化。代码示例使用 Sentence-BERT 生成文本嵌入我们将使用sentence-transformers库它封装了多种预训练的 SBERT 模型使用起来非常方便。首先确保你已经安装了必要的库pip install sentence-transformers numpy然后我们可以编写 Python 代码来生成文本嵌入from sentence_transformers import SentenceTransformer import numpy as np # 1. 加载预训练的 Sentence-BERT 模型 # all-MiniLM-L6-v2 是一个轻量级但性能良好的通用模型 model_name all-MiniLM-L6-v2 print(f正在加载 Sentence-BERT 模型: {model_name}...) model SentenceTransformer(model_name) print(模型加载完成。) # 2. 准备一些文本 texts [ 如何使用Python编写一个REST API?, 使用Flask框架构建Web服务的最佳实践。, 学习JavaScript的入门教程。, 关于人工智能的最新发展趋势。, 给我一份关于深度学习的报告。, 制作一道美味的意大利面。, 如何用Python和Django开发一个电子商务网站? ] # 3. 生成文本嵌入 print(f正在生成 {len(texts)} 段文本的嵌入向量...) embeddings model.encode(texts) print(f嵌入向量生成完成。形状: {embeddings.shape}) # embeddings.shape 会是 (num_texts, embedding_dimension) # 例如(7, 384) 表示有 7 个文本每个文本被映射到 384 维的向量 # 4. 打印一些示例嵌入为了演示只打印前5个维度 print(n部分文本及其对应的嵌入向量前5维:) for i, text in enumerate(texts): print(f文本: {text}) print(f嵌入: {embeddings[i][:5]}...) print(- * 30) # 5. 计算两个文本之间的相似度例如余弦相似度 # 语义相似的文本向量在向量空间中距离更近 # 如何使用Python编写一个REST API? vs 如何用Python和Django开发一个电子商务网站? # 如何使用Python编写一个REST API? vs 制作一道美味的意大利面。 from sklearn.metrics.pairwise import cosine_similarity # 提取相关文本的嵌入 embedding_query_1 embeddings[0] # 如何使用Python编写一个REST API? embedding_query_2 embeddings[6] # 如何用Python和Django开发一个电子商务网站? embedding_irrelevant embeddings[5] # 制作一道美味的意大利面。 # 计算相似度 similarity_1_2 cosine_similarity(embedding_query_1.reshape(1, -1), embedding_query_2.reshape(1, -1))[0][0] similarity_1_irrelevant cosine_similarity(embedding_query_1.reshape(1, -1), embedding_irrelevant.reshape(1, -1))[0][0] print(fn相似度计算:) print(f{texts[0]} 和 {texts[6]} 的余弦相似度: {similarity_1_2:.4f}) print(f{texts[0]} 和 {texts[5]} 的余弦相似度: {similarity_1_irrelevant:.4f}) # 预期结果相似度1_2会显著高于相似度1_irrelevant证明了嵌入向量捕捉语义的能力。输出示例 (部分):正在加载 Sentence-BERT 模型: all-MiniLM-L6-v2... 模型加载完成。 正在生成 7 段文本的嵌入向量... 嵌入向量生成完成。形状: (7, 384) 部分文本及其对应的嵌入向量前5维: 文本: 如何使用Python编写一个REST API? 嵌入: [ 0.00762145 -0.01217596 0.03859744 -0.04780517 -0.01633519]... ------------------------------ 文本: 使用Flask框架构建Web服务的最佳实践。 嵌入: [ 0.00754876 -0.02107474 0.05267864 -0.03923912 -0.02434526]... ------------------------------ ... 相似度计算: 如何使用Python编写一个REST API? 和 如何用Python和Django开发一个电子商务网站? 的余弦相似度: 0.7631 如何使用Python编写一个REST API? 和 制作一道美味的意大利面。 的余弦相似度: 0.0658从输出中我们可以清晰地看到关于Python编程的两个查询之间的相似度0.7631远高于一个编程查询与一个烹饪查询之间的相似度0.0658。这正是我们利用向量嵌入来衡量文本相关性的基础。第三章向量索引高效检索的利器当我们拥有了文本的向量表示后下一步就是如何高效地找到与给定查询向量最相似的那些示例向量。对于一个只有几十个或几百个示例的小型库我们可以直接进行暴力Brute-force搜索即计算查询向量与所有示例向量的相似度然后排序取前 K 个。然而在实际应用中我们的示例库可能包含数千、数万甚至数百万个示例。此时暴力搜索的计算成本将变得不可接受。这就是向量索引 (Vector Index)发挥作用的地方。向量索引是一种专门设计用于加速高维向量相似度搜索的数据结构和算法。3.1 暴力搜索的局限性假设我们有 $N$ 个示例每个示例对应一个 $D$ 维向量。对于一个查询向量我们需要计算它与这 $N$ 个向量的相似度。如果使用余弦相似度每次计算需要 $O(D)$ 的复杂度。那么总复杂度就是 $O(N cdot D)$。当 $N 10^6$ (一百万个示例)$D 384$ (Sentence-BERT 的维度)每次查询需要 $10^6 times 384 approx 3.8 times 10^8$ 次浮点运算。这在实时应用中是无法接受的。3.2 近似最近邻 (Approximate Nearest Neighbors, ANN) 算法为了解决暴力搜索的效率问题研究者们开发了各种近似最近邻 (ANN)搜索算法。ANN 算法的核心思想是在可接受的精度损失下显著提高搜索速度。它们不保证找到绝对的 K 个最近邻但通常能找到非常接近真实最近邻的 K 个向量。常见的 ANN 算法和库包括FAISS (Facebook AI Similarity Search):Facebook AI 开发的库提供了多种高效的 ANN 算法实现包括 IVFFlat、HNSW 等。广泛应用于工业界。Annoy (Approximate Nearest Neighbors Oh Yeah):Spotify 开发的库基于随机投影树。HNSW (Hierarchical Navigable Small World):一种基于图的 ANN 算法提供了非常好的速度与召回率平衡。ScaNN (Scalable Nearest Neighbors):Google 开发的库针对高维向量进行了优化。这些算法通过不同的策略来减少搜索空间例如量化 (Quantization):将高维向量压缩成更小的表示减少存储和计算成本。树结构 (Tree-based):构建树形结构来划分向量空间加速搜索。图结构 (Graph-based):构建一个图其中节点是向量边表示相似性通过图遍历来查找最近邻。3.3 FAISS 快速入门与使用在本讲座中我们将重点介绍 FAISS因为它功能强大易于使用并且在生产环境中表现出色。FAISS 的基本使用流程准备数据:将所有示例的嵌入向量组织成一个 NumPy 数组。选择索引类型:根据数据规模、精度要求和性能目标选择合适的 FAISS 索引。构建索引:将示例向量添加到索引中。搜索:使用查询向量在索引中查找最近邻。FAISS 索引类型概览 (简化版):索引类型描述优点缺点适用场景IndexFlatL2/IP暴力搜索精确最近邻分别使用 L2 距离和内积余弦相似度。100% 准确率实现简单。速度慢不适合大数据集。小规模数据集10k 向量IndexIVFFlat倒排文件索引 (Inverted File Index)将向量空间划分为多个聚类。速度快内存效率高可扩展。精度略有下降近似需要训练阶段。中大型数据集10k – 10M 向量IndexHNSWFlat分层可导航小世界图 (Hierarchical Navigable Small World)。搜索速度极快召回率高。索引构建时间较长内存占用相对较高。对速度和精度要求高的大型数据集1M 向量IndexPQ/IndexSQ乘积量化 (Product Quantization) / 标量量化 (Scalar Quantization)。大幅度压缩向量节省内存。精度损失较大。极大规模数据集内存受限场景对于大多数 Few-shot Prompting 的动态采样场景IndexIVFFlat或IndexHNSWFlat是非常好的选择。我们先从IndexFlatL2开始因为它最直观然后过渡到IndexIVFFlat。代码示例使用 FAISS 构建索引并搜索我们将扩展之前的代码使用 FAISS 来管理和搜索我们的示例嵌入。import faiss from sentence_transformers import SentenceTransformer import numpy as np from sklearn.metrics.pairwise import cosine_similarity # 1. 加载预训练的 Sentence-BERT 模型 model_name all-MiniLM-L6-v2 model SentenceTransformer(model_name) embedding_dimension model.get_sentence_embedding_dimension() # 2. 准备一个更大、更真实的示例语料库 example_texts [ 如何用Python和Flask构建一个RESTful API?, 使用Django框架开发一个功能完善的电商网站。, 学习ReactJS前端框架的基本概念。, Vue.js组件化开发的最佳实践。, 关于机器学习模型在医疗领域的应用。, 深度学习在自然语言处理中的最新进展。, 如何优化SQL查询性能?, PostgreSQL数据库的索引类型及其选择。, Kubernetes集群的部署与管理。, Docker容器化技术的核心概念。, 编写高效Go语言并发程序。, Rust语言的内存安全特性探讨。, 如何使用AWS Lambda构建无服务器应用?, Azure云平台上的微服务架构设计。, Python数据分析库Pandas的进阶用法。, Numpy在科学计算中的应用示例。, 理解HTTP协议的工作原理。, Websocket与传统HTTP请求的区别。, Git版本控制的高级操作技巧。, CI/CD流程在软件开发中的重要性。, 如何调试Java应用程序, JVM内存模型深度解析。, 使用TensorFlow构建一个图像识别模型。, PyTorch深度学习框架的入门教程。, 区块链技术的工作原理。, 智能合约在以太坊上的实现。, 云计算服务的种类和优势。, 边缘计算与物联网的结合。, 如何进行有效的软件测试, 敏捷开发方法论的核心原则。 ] # 3. 生成示例文本的嵌入向量 print(f正在生成 {len(example_texts)} 个示例的嵌入向量...) example_embeddings model.encode(example_texts) print(f嵌入向量生成完成。形状: {example_embeddings.shape}) # 4. 构建 FAISS 索引 # 我们先使用 IndexFlatL2 (暴力搜索但精确) 来演示 # L2 距离 (欧氏距离) 和余弦相似度是负相关的L2 距离越小余弦相似度越大 # 为了直接使用余弦相似度通常我们将向量归一化到单位长度然后使用内积 (IndexFlatIP) 或 L2 距离。 # 在单位向量情况下内积就是余弦相似度。 # 让我们先对向量进行归一化这样 L2 距离和余弦相似度就能更好地对应起来 faiss.normalize_L2(example_embeddings) # 创建一个 IndexFlatL2 索引维度为 embedding_dimension index_flat faiss.IndexFlatL2(embedding_dimension) print(fIndexFlatL2 索引是否训练: {index_flat.is_trained}) # 向索引中添加向量 index_flat.add(example_embeddings) print(fIndexFlatL2 索引中的向量数量: {index_flat.ntotal}) # 5. 准备一个查询 query_text 我需要一些关于深度学习在图像处理方面应用的示例。 print(fn查询文本: {query_text}) # 6. 生成查询文本的嵌入向量 query_embedding model.encode([query_text])[0] faiss.normalize_L2(query_embedding.reshape(1, -1)) # 同样进行归一化 # 7. 在索引中搜索 K 个最近邻 k 3 # 我们希望找到 3 个最相关的示例 print(f正在搜索 {k} 个最相似的示例...) distances, indices index_flat.search(query_embedding.reshape(1, -1), k) # distances 是 L2 距离越小越相似 # indices 是原始 example_texts 数组中的索引 print(n搜索结果:) for i in range(k): idx indices[0][i] dist distances[0][i] # 计算余弦相似度 (对于L2归一化向量余弦相似度 1 - 0.5 * L2_distance^2) # 或者直接用sklearn计算更直观 cos_sim cosine_similarity(query_embedding.reshape(1, -1), example_embeddings[idx].reshape(1, -1))[0][0] print(f 排名 {i1}:) print(f 原始文本: {example_texts[idx]}) print(f L2 距离: {dist:.4f}) print(f 余弦相似度: {cos_sim:.4f}) print(- * 20) # --- 现在切换到 IndexIVFFlat 来演示 ANN 的使用 --- # IndexIVFFlat 需要一个训练阶段来创建聚类中心 nlist 100 # 聚类中心的数量通常是 sqrt(N) 或 4*sqrt(N) quantizer faiss.IndexFlatL2(embedding_dimension) # 基础量化器这里用L2 index_ivf faiss.IndexIVFFlat(quantizer, embedding_dimension, nlist, faiss.METRIC_L2) print(fn正在训练 IndexIVFFlat 索引 (nlist{nlist})...) index_ivf.train(example_embeddings) # 使用示例向量训练索引 print(fIndexIVFFlat 索引是否训练: {index_ivf.is_trained}) index_ivf.add(example_embeddings) print(fIndexIVFFlat 索引中的向量数量: {index_ivf.ntotal}) # 设置 nprobe 参数它决定了搜索时检查多少个聚类。 # nprobe 越大精度越高但速度越慢。 index_ivf.nprobe 10 # 检查 10 个最近的聚类 print(fn使用 IndexIVFFlat 搜索 {k} 个最相似的示例 (nprobe{index_ivf.nprobe})...) distances_ivf, indices_ivf index_ivf.search(query_embedding.reshape(1, -1), k) print(nIndexIVFFlat 搜索结果:) for i in range(k): idx indices_ivf[0][i] dist distances_ivf[0][i] cos_sim cosine_similarity(query_embedding.reshape(1, -1), example_embeddings[idx].reshape(1, -1))[0][0] print(f 排名 {i1}:) print(f 原始文本: {example_texts[idx]}) print(f L2 距离: {dist:.4f}) print(f 余弦相似度: {cos_sim:.4f}) print(- * 20)输出示例 (部分):... 查询文本: 我需要一些关于深度学习在图像处理方面应用的示例。 正在搜索 3 个最相似的示例... 搜索结果: 排名 1: 原始文本: 使用TensorFlow构建一个图像识别模型。 L2 距离: 0.4418 余弦相似度: 0.9023 -------------------- 排名 2: 原始文本: PyTorch深度学习框架的入门教程。 L2 距离: 0.6974 余弦相似度: 0.7570 -------------------- 排名 3: 原始文本: 深度学习在自然语言处理中的最新进展。 L2 距离: 0.8142 余弦相似度: 0.6677 -------------------- 正在训练 IndexIVFFlat 索引 (nlist100)... IndexIVFFlat 索引是否训练: True IndexIVFFlat 索引中的向量数量: 30 使用 IndexIVFFlat 搜索 3 个最相似的示例 (nprobe10)... IndexIVFFlat 搜索结果: 排名 1: 原始文本: 使用TensorFlow构建一个图像识别模型。 L2 距离: 0.4418 余弦相似度: 0.9023 -------------------- 排名 2: 原始文本: PyTorch深度学习框架的入门教程。 L2 距离: 0.6974 余弦相似度: 0.7570 -------------------- 排名 3: 原始文本: 深度学习在自然语言处理中的最新进展。 L2 距离: 0.8142 余弦相似度: 0.6677 --------------------可以看到无论是IndexFlatL2还是IndexIVFFlat都能准确地找到与查询“深度学习在图像处理”相关的示例如“TensorFlow构建图像识别模型”和“PyTorch深度学习框架”。这证明了向量索引在语义搜索中的有效性。第四章Few-shot Prompting 中的动态采样端到端工作流现在我们已经掌握了向量嵌入和向量索引这两个核心技术是时候将它们整合起来构建 Few-shot Prompting 的动态采样系统了。4.1 动态采样的完整工作流整个过程可以概括为以下步骤构建示例语料库 (Example Corpus):收集大量高质量的、覆盖任务多样性的输入-输出示例对。这些示例是LLM学习的“知识库”。生成示例嵌入 (Embed Examples):使用预训练的嵌入模型将语料库中每个示例的输入部分或整个示例转换为高维向量。构建向量索引 (Build Vector Index):使用 FAISS 等库基于生成的示例嵌入构建一个高效的向量索引。这个索引将用于快速查找相似示例。接收用户查询 (Receive User Query):当用户提交一个新的问题或任务时。生成查询嵌入 (Embed Query):使用与示例嵌入相同的模型将用户查询转换为高维向量。检索最相关示例 (Retrieve Relevant Examples):利用查询嵌入在预先构建的向量索引中搜索 K 个例如3到5个与查询最相似的示例向量。构造动态 Prompt (Construct Dynamic Prompt):将任务指令、检索到的 K 个示例及其对应的输出以及用户查询按照 Few-shot Prompting 的格式组装成一个完整的 Prompt 字符串。调用 LLM (Call LLM):将构造好的 Prompt 发送给大型语言模型获取最终的响应。这个工作流的核心优势在于对于每一个新的用户查询系统都会“智能地”挑选出最能帮助LLM理解当前任务并给出高质量回答的示例。4.2 端到端代码示例文本分类任务让我们通过一个具体的文本分类任务来演示这个端到端的工作流。假设我们的任务是判断一段文本的情感正面、负面、中立。import faiss from sentence_transformers import SentenceTransformer import numpy as np import os # 模拟一个 LLM API 调用实际中会替换为 OpenAI, Anthropic, Google 等的 SDK def mock_llm_call(prompt: str) - str: print(n--- 模拟 LLM 调用 ---) print(发送到 LLM 的 Prompt:) print( * 50) print(prompt) print( * 50) # 实际场景中这里会调用 LLM API并返回其响应 # 例如 # from openai import OpenAI # client OpenAI(api_keyos.environ.get(OPENAI_API_KEY)) # response client.chat.completions.create( # modelgpt-4o-mini, # messages[{role: user, content: prompt}], # temperature0.7 # ) # return response.choices[0].message.content return LLM 成功处理了动态 Prompt并根据示例给出了响应。 # 模拟响应 # 1. 加载预训练的 Sentence-BERT 模型 model_name all-MiniLM-L6-v2 print(f正在加载 Sentence-BERT 模型: {model_name}...) embedding_model SentenceTransformer(model_name) embedding_dimension embedding_model.get_sentence_embedding_dimension() print(模型加载完成。) # 2. 构建示例语料库 # 每个示例包含 input (文本) 和 output (情感标签) # 真实场景中这些示例会存储在数据库或文件中 example_data [ {input: 这电影真是太棒了我看了两遍, output: 情感: 正面}, {input: 服务很差食物也很冷一次糟糕的体验。, output: 情感: 负面}, {input: 这家餐厅的环境不错菜品中规中矩。, output: 情感: 中立}, {input: 新产品发布会非常成功市场反响热烈。, output: 情感: 正面}, {input: 等待时间太长了效率低下令人失望。, output: 情感: 负面}, {input: 报告详细且全面数据分析准确。, output: 情感: 正面}, {input: 我对这次的购买体验感到非常满意。, output: 情感: 正面}, {input: 这手机电池续航太短了很不方便。, output: 情感: 负面}, {input: 这本书的故事情节平淡没有太多亮点。, output: 情感: 负面}, {input: 会议内容丰富但时间安排有点紧凑。, output: 情感: 中立}, {input: 尽管有些小瑕疵但总体来说还算可以。, output: 情感: 中立}, {input: 这个软件的界面设计很简洁功能强大。, output: 情感: 正面}, {input: 客服响应速度慢问题没能得到解决。, output: 情感: 负面}, {input: 今天天气晴朗适合外出游玩。, output: 情感: 中立}, # 中立示例但可能被误判 {input: 这个方案听起来很有前景值得尝试。, output: 情感: 正面}, {input: 我不确定这个决定是否正确。, output: 情感: 中立}, ] # 提取示例输入文本用于嵌入 example_inputs [item[input] for item in example_data] # 3. 生成示例嵌入 print(f正在生成 {len(example_inputs)} 个示例的嵌入向量...) example_embeddings embedding_model.encode(example_inputs) faiss.normalize_L2(example_embeddings) # 归一化 print(f嵌入向量生成完成。形状: {example_embeddings.shape}) # 4. 构建向量索引 (使用 IndexIVFFlat更适合大规模数据) nlist min(len(example_data) // 5, 100) # 聚类中心数量至少为1不超过数据量的1/5上限100 if nlist 1: nlist 1 quantizer faiss.IndexFlatL2(embedding_dimension) vector_index faiss.IndexIVFFlat(quantizer, embedding_dimension, nlist, faiss.METRIC_L2) print(fn正在训练 FAISS IndexIVFFlat 索引 (nlist{nlist})...) vector_index.train(example_embeddings) vector_index.add(example_embeddings) vector_index.nprobe min(nlist, 5) # 搜索时检查的聚类数量不超过 nlist 或 5 print(fFAISS 索引构建完成。包含 {vector_index.ntotal} 个向量。) # 5. 定义任务指令 instruction ( 你是一个情感分析专家。请根据提供的文本判断其情感是 正面, 负面, 还是 中立。n 请严格按照 情感: [标签] 的格式输出。 ) # 6. 动态采样与 Prompt 构建函数 def get_dynamic_prompt(query: str, num_examples: int 3) - str: # 生成查询嵌入 query_embedding embedding_model.encode([query])[0] faiss.normalize_L2(query_embedding.reshape(1, -1)) # 在索引中搜索最相关的示例 _, indices vector_index.search(query_embedding.reshape(1, -1), num_examples) # 提取完整的示例对 selected_examples [example_data[idx] for idx in indices[0]] # 构造 Prompt prompt_parts [instruction] for ex in selected_examples: prompt_parts.append(fn输入: {ex[input]}n{ex[output]}) prompt_parts.append(fn输入: {query}n) # 加上待处理的查询 return .join(prompt_parts) # 7. 演示动态采样和 LLM 调用 test_queries [ 这家酒店的设施非常陈旧Wi-Fi信号也不好。, # 负面 新发布的手机功能强大设计时尚我很喜欢。, # 正面 这个报告只是对现有信息的总结没有新的见解。, # 中立 昨晚的演唱会气氛热烈歌手表现出色, # 正面 快递送货慢包裹还破损了非常不满意。, # 负面 ] for i, query in enumerate(test_queries): print(fn--- 处理查询 {i1}: {query} ---) dynamic_prompt get_dynamic_prompt(query, num_examples3) llm_response mock_llm_call(dynamic_prompt) print(fLLM 模拟响应: {llm_response})代码输出示例 (部分):正在加载 Sentence-BERT 模型: all-MiniLM-L6-v2... 模型加载完成。 正在生成 16 个示例的嵌入向量... 嵌入向量生成完成。形状: (16, 384) 正在训练 FAISS IndexIVFFlat 索引 (nlist3)... FAISS 索引构建完成。包含 16 个向量。 --- 处理查询 1: 这家酒店的设施非常陈旧Wi-Fi信号也不好。 --- --- 模拟 LLM 调用 --- 发送到 LLM 的 Prompt: 你是一个情感分析专家。请根据提供的文本判断其情感是 正面, 负面, 还是 中立。 请严格按照 情感: [标签] 的格式输出。 输入: 服务很差食物也很冷一次糟糕的体验。 情感: 负面 输入: 这手机电池续航太短了很不方便。 情感: 负面 输入: 快递送货慢包裹还破损了非常不满意。 情感: 负面 输入: 这家酒店的设施非常陈旧Wi-Fi信号也不好。 LLM 模拟响应: LLM 成功处理了动态 Prompt并根据示例给出了响应。 --- 处理查询 2: 新发布的手机功能强大设计时尚我很喜欢。 --- --- 模拟 LLM 调用 --- 发送到 LLM 的 Prompt: 你是一个情感分析专家。请根据提供的文本判断其情感是 正面, 负面, 还是 中立。 请严格按照 情感: [标签] 的格式输出。 输入: 新产品发布会非常成功市场反响热烈。 情感: 正面 输入: 这个软件的界面设计很简洁功能强大。 情感: 正面 输入: 这电影真是太棒了我看了两遍 情感: 正面 输入: 新发布的手机功能强大设计时尚我很喜欢。 LLM 模拟响应: LLM 成功处理了动态 Prompt并根据示例给出了响应。 ...从这些模拟输出中我们可以清晰地看到对于每一个新的查询get_dynamic_prompt函数都根据其语义内容从示例库中检索出了3个最相关的示例。例如对于负面评价的酒店查询它检索到了其他负面评价的示例。这种根据上下文动态调整 Prompt 内容的能力正是 Few-shot Prompting 动态采样的核心价值。第五章高级考量与最佳实践动态采样并非一劳永逸其效果和效率还会受到多种因素的影响。5.1 嵌入模型的选择通用性与领域专用性:all-MiniLM-L6-v2这样的模型在通用领域表现良好。但如果你的任务涉及高度专业的领域如医学、法律、金融考虑使用在该领域数据上训练过的模型或者对现有模型进行微调。维度与性能:嵌入维度越高通常能捕获更多信息但也意味着更大的存储和计算开销。权衡好维度与实际需求。模型更新:嵌入模型也在不断发展定期评估和更新你的嵌入模型可能带来性能提升。5.2 示例数量 (K值) 的选择num_examples(K) 的选择至关重要太少:可能无法提供足够的上下文LLM难以学习模式。太多:上下文窗口限制:LLM有最大输入Token限制过多的示例可能导致 Prompt 过长。成本增加:LLM通常按Token计费长Prompt意味着更高的成本。性能下降:过长的Prompt可能稀释有效信息甚至导致模型注意力分散效果不升反降lost in the middle 效应。最佳 K 值通常需要通过实验来确定一般在 3 到 8 之间。5.3 示例多样性与相关性纯粹的相关性有时可能不够。例如如果所有最相关的示例都非常相似它们可能无法覆盖任务的完整范围。可以考虑引入最大边际相关性 (Maximal Marginal Relevance, MMR)策略MMR:优先选择与查询相关性高同时与已选示例的相似性低的示例。这有助于确保选出的示例既相关又具有多样性。实现 MMR 的思路:首先找到与查询最相似的 TOP N 个示例。从这 N 个中选择第一个最相似的示例。然后在剩余的 N-1 个示例中选择一个与查询高度相似但与已选示例例如第一个差异最大的示例。重复此过程直到选出 K 个示例。5.4 向量索引的优化与维护索引类型选择:根据示例库的规模和查询延迟要求选择合适的 FAISS 索引类型如前所述。索引参数调优:对于IndexIVFFlatnlist(聚类中心数) 和nprobe(搜索时检查的聚类数) 是关键参数需要根据实际数据进行调优。索引更新:当示例库发生变化时添加、删除、修改示例需要更新或重建索引。对于大规模数据这可能需要增量更新或定期全量重建的策略。持久化:索引需要持久化到磁盘以便在应用重启后快速加载。FAISS 提供了faiss.write_index()和faiss.read_index()函数。# 示例保存和加载 FAISS 索引 # 保存索引 faiss.write_index(vector_index, sentiment_examples.faiss) # 重新加载索引 loaded_index faiss.read_index(sentiment_examples.faiss) print(f加载的索引包含 {loaded_index.ntotal} 个向量。)5.5 性能与可伸缩性嵌入生成速度:批量生成嵌入比逐个生成更高效。向量数据库:对于超大规模的示例库数千万甚至上亿可以考虑使用专门的向量数据库如 Milvus, Pinecone, Weaviate, Qdrant。它们提供了分布式存储、高可用性、实时索引更新和更复杂的查询功能。缓存:对于重复的查询可以缓存其生成的 Prompt 或 LLM 响应。5.6 成本考量嵌入成本:每次生成嵌入向量都会产生计算资源或 API 调用成本。LLM 调用成本:LLM 通常按 Token 计费动态采样的目标之一就是通过选择最相关的短示例在保证效果的前提下尽量减少 Prompt 的总 Token 数从而降低成本。第六章实际应用场景动态采样在 Few-shot Prompting 中具有广泛的应用前景智能客服与问答系统:根据用户问题从海量 FAQ、历史对话记录或知识库中检索最相关的问答对作为LLM的上下文生成更准确、个性化的回复。代码助手与自动化编程:当开发者提出一个编程问题时匹配相似的代码片段、文档示例或错误解决方案帮助LLM生成正确的代码或调试建议。数据提取与信息抽取:提供不同格式的文本和对应的抽取结果作为示例LLM可以更准确地从新文本中提取实体、关系或结构化数据。文本摘要与改写:匹配相似主题或风格的原文与摘要/改写示例指导LLM生成高质量的摘要或进行风格转换。法律与医疗助手:在特定法律条款或医疗案例中匹配相似的案例或法规条文帮助LLM进行推理和提供建议。多语言翻译与本地化:提供特定领域或术语的源语言与目标语言的翻译示例提高LLM在专业翻译任务上的准确性。结语我们今天深入探讨了 Few-shot Prompting 中动态采样的强大潜力以及如何通过向量嵌入和向量索引这两个核心技术来将其变为现实。通过为LLM智能地匹配最相关的上下文示例我们不仅能够显著提升其在特定任务上的性能还能优化资源利用为构建更加智能、高效的AI应用奠定坚实基础。这项技术是连接大规模预训练模型与特定业务场景的桥梁也是未来AI应用开发中不可或缺的一环。希望今天的讲座能为大家带来启发期待大家在各自的项目中实践并创新