恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
【三个月 AI Agent 实战学习】Day 37:Embedding 与向量数据库进阶 —— 为长期记忆打造高效检索
首页
资讯中心
/
【三个月 AI Agent 实战学习】Day 37:Embedding 与向量数据库进阶 —— 为长期记忆打造高效检索
【三个月 AI Agent 实战学习】Day 37:Embedding 与向量数据库进阶 —— 为长期记忆打造高效检索
发布时间:2026/10/15 12:41:07
Day 37Embedding 与向量数据库进阶 —— 为长期记忆打造高效检索欢迎来到第三十七天昨天我们设计了带记忆客服 Agent 的架构其中长期记忆的核心是向量数据库 Embedding。虽然我们在 Day 17-18 已经初步使用了 Embedding 和 Chroma但当时只是“能用”。今天我们要深入优化如何选择合适的 Embedding 模型如何设计高效的检索策略如何处理元数据过滤、相似度阈值、MMR 多样性检索这些技术将直接决定你的 Agent 能否在大量记忆中找到最相关的信息。一、今日学习目标理解 Embedding 模型的选择标准维度、语言支持、领域适配、成本与速度。掌握向量数据库的进阶检索功能元数据过滤Metadata Filtering、相似度阈值Similarity Threshold、MMR最大边际相关性。学会为长期记忆设计多级检索策略精确匹配 语义检索 重排序。通过实验对比不同 Embedding 模型和检索策略在“用户记忆检索”场景下的效果。能够根据业务需求为客服 Agent 的长期记忆配置最优的检索方案。二、详细实现步骤步骤 1理解 Embedding 模型的选择标准不同的 Embedding 模型在维度、语言支持、领域适配和成本上差异很大。选择时需要考虑标准说明示例维度维度越高表达能力越强但存储和计算成本也越高768、1024、1536语言支持是否对中文优化智谱 embedding-2、BGE-large-zh、M3E领域适配通用 vs 特定领域医疗、法律、代码通用模型 vs BioBERT成本API 调用费用或本地推理成本智谱 API vs 本地 sentence-transformers速度推理延迟影响检索实时性小模型快大模型慢最大输入长度单次可编码的 Token 数512、8192常见中文 Embedding 模型对比模型维度最大长度提供方特点智谱 embedding-210248192智谱 API中文优化好支持长文本BGE-large-zh1024512本地/API中文语义强开源M3E-base768512本地轻量适合快速原型text-embedding-3-small15368191OpenAI多语言但中文稍弱建议对于中文客服场景优先选择智谱embedding-2或 BGE-large-zh。如果预算有限可以使用 M3E-base 本地部署。步骤 2环境准备确保已安装所需库。我们继续使用智谱 Embedding 和 Chroma。如果尚未安装pipinstalllangchain langchain-openai langchain-community chromadb新建embedding_advanced.py导入模块并初始化importosfromdotenvimportload_dotenvfromlangchain_openaiimportOpenAIEmbeddingsfromlangchain_community.vectorstoresimportChromafromlangchain_core.documentsimportDocument load_dotenv()embeddingsOpenAIEmbeddings(modelembedding-2,api_keyos.getenv(ZHIPU_API_KEY),base_urlhttps://open.bigmodel.cn/api/paas/v4)步骤 3构建带元数据的向量存储在长期记忆中每条记忆都应该携带元数据例如user_id所属用户memory_type记忆类型偏好、事实、事件timestamp创建时间importance重要性评分1-5我们创建一些模拟的长期记忆文档documents[Document(page_content用户喜欢科幻小说最喜欢的作家是刘慈欣。,metadata{user_id:user_001,memory_type:preference,timestamp:2025-03-01,importance:5}),Document(page_content用户上次投诉订单 12345 的物流太慢要求补偿。,metadata{user_id:user_001,memory_type:event,timestamp:2025-03-10,importance:4}),Document(page_content用户偏好使用优惠券对价格敏感。,metadata{user_id:user_001,memory_type:preference,timestamp:2025-02-15,importance:3}),Document(page_content用户询问过如何修改收货地址。,metadata{user_id:user_001,memory_type:event,timestamp:2025-03-05,importance:2}),Document(page_content用户是 VIP 会员享受优先客服。,metadata{user_id:user_001,memory_type:fact,timestamp:2025-01-01,importance:5}),Document(page_content用户喜欢在晚上 8 点后咨询问题。,metadata{user_id:user_001,memory_type:preference,timestamp:2025-03-12,importance:2}),]# 创建向量存储vectorstoreChroma.from_documents(documentsdocuments,embeddingembeddings,collection_nameuser_memories,persist_directory./memory_db)print(f已存储{len(documents)}条记忆)步骤 4元数据过滤检索当用户提问时我们通常只想检索该用户的记忆而不是所有人的。Chroma 支持filter参数进行元数据过滤。defsearch_with_filter(query:str,user_id:str,k:int3):只在指定用户的记忆中检索resultsvectorstore.similarity_search(query,kk,filter{user_id:user_id}# 元数据过滤)returnresults# 测试query用户喜欢什么类型的书resultssearch_with_filter(query,user_001,k2)print(元数据过滤检索结果)fordocinresults:print(f -{doc.page_content}(类型:{doc.metadata[memory_type]}, 重要性:{doc.metadata[importance]}))你还可以组合多个过滤条件不同向量库语法略有差异# Chroma 支持 $and, $or 等操作filter_complex{$and:[{user_id:user_001},{memory_type:preference}]}resultsvectorstore.similarity_search(query,k3,filterfilter_complex)步骤 5相似度阈值过滤有时候检索到的内容可能与查询无关。我们可以设置相似度阈值只保留相似度高于某个值的记忆。Chroma 的similarity_search_with_score返回距离分数越小越相似我们可以据此过滤。defsearch_with_threshold(query:str,user_id:str,k:int5,max_distance:float1.0):带相似度阈值的检索距离越小越相似resultsvectorstore.similarity_search_with_score(query,kk,filter{user_id:user_id})# 过滤掉距离大于阈值的filtered[(doc,score)fordoc,scoreinresultsifscoremax_distance]returnfiltered# 测试query用户对价格怎么看resultssearch_with_threshold(query,user_001,k5,max_distance0.8)print(\n相似度阈值检索结果)fordoc,scoreinresults:print(f -{doc.page_content}(距离:{score:.4f}))注意不同向量库的距离度量不同余弦距离、欧氏距离等阈值需要根据实际情况调整。建议先用一批测试查询观察距离分布再确定合适的阈值。步骤 6MMR 多样性检索如果用户的问题涉及多个方面普通相似度检索可能返回多条高度相似的记忆导致信息冗余。MMRMax Marginal Relevance可以在“相关性”和“多样性”之间取得平衡。defsearch_with_mmr(query:str,user_id:str,k:int3,fetch_k:int10,lambda_mult:float0.5): MMR 检索 - fetch_k: 先检索出 fetch_k 个候选 - lambda_mult: 0 表示最大多样性1 表示最大相关性 resultsvectorstore.max_marginal_relevance_search(query,kk,fetch_kfetch_k,lambda_multlambda_mult,filter{user_id:user_id})returnresults# 测试query用户有什么偏好和重要事件resultssearch_with_mmr(query,user_001,k3,fetch_k6,lambda_mult0.6)print(\nMMR 检索结果)fordocinresults:print(f -{doc.page_content}(类型:{doc.metadata[memory_type]}))你会看到 MMR 返回的记忆更加多样化覆盖了偏好、事件、事实等不同类型。步骤 7多级检索策略推荐在实际的客服 Agent 中我们可以组合多种检索方式形成多级检索策略第一级精确匹配——如果用户提到了订单号、工单号等结构化信息直接从 SQL 数据库查询。第二级元数据过滤 语义检索——在用户自己的记忆中用 Embedding 检索相关片段。第三级MMR 多样性——确保检索结果覆盖不同类型的信息偏好、事件、事实。第四级重排序Rerank——用更精确的模型对候选结果重新打分可选后续学习。我们实现一个综合检索函数defcomprehensive_retrieval(query:str,user_id:str,k:int5):综合检索元数据过滤 相似度阈值 MMR# 先用 MMR 获取多样化候选candidatesvectorstore.max_marginal_relevance_search(query,kk*2,fetch_kk*4,lambda_mult0.6,filter{user_id:user_id})# 再用相似度分数过滤可选# 这里简化处理直接返回 MMR 结果的前 k 个returncandidates[:k]# 测试query用户的历史投诉和偏好resultscomprehensive_retrieval(query,user_001,k4)print(\n综合检索结果)fordocinresults:print(f -{doc.page_content})print(f 元数据:{doc.metadata})步骤 8对比不同 Embedding 模型可选如果你有多个 Embedding 模型的 API如智谱和 OpenAI可以对比它们在相同查询下的检索效果。这里仅提供思路# 使用智谱 Embeddingzhipu_embeddingsOpenAIEmbeddings(modelembedding-2,api_keyos.getenv(ZHIPU_API_KEY),base_urlhttps://open.bigmodel.cn/api/paas/v4)# 使用 OpenAI Embedding如果有 Key# openai_embeddings OpenAIEmbeddings(modeltext-embedding-3-small)# 分别构建向量存储用相同查询检索对比结果步骤 9将检索集成到记忆管理器将上述检索策略封装到MemoryManager中classMemoryManager:def__init__(self,user_id,vectorstore,embeddings):self.user_iduser_id self.vectorstorevectorstoredefretrieve_relevant_memories(self,query:str,k:int5):检索与当前问题相关的长期记忆# MMR 检索 元数据过滤resultsself.vectorstore.max_marginal_relevance_search(query,kk,fetch_kk*3,lambda_mult0.6,filter{user_id:self.user_id})# 按重要性排序results.sort(keylambdadoc:doc.metadata.get(importance,0),reverseTrue)returnresultsdefformat_memories_for_prompt(self,memories:list)-str:将记忆格式化为提示词可用的文本ifnotmemories:return暂无相关记忆。lines[]fordocinmemories:mem_typedoc.metadata.get(memory_type,unknown)lines.append(f[{mem_type}]{doc.page_content})return\n.join(lines)# 使用managerMemoryManager(user_001,vectorstore,embeddings)memoriesmanager.retrieve_relevant_memories(用户喜欢什么)formattedmanager.format_memories_for_prompt(memories)print(\n格式化后的记忆)print(formatted)三、常见问题与调试Q1元数据过滤时Chroma 报错说不支持复杂的过滤条件。→ Chroma 支持$and、$or、$eq、$ne、$gt、$lt等操作符。但不同版本语法可能略有差异。建议查阅 Chroma 官方文档确认当前版本的过滤语法。Q2相似度阈值设多少合适→ 取决于 Embedding 模型和距离度量。对于余弦距离通常 0.5-1.0 之间。建议先用一批查询打印所有结果的距离分数观察分布后再设定阈值。也可以不设阈值直接取 Top-K。Q3MMR 的lambda_mult怎么调→lambda_mult1等价于普通相似度检索最大相关性lambda_mult0等价于最大多样性可能返回不太相关的结果。通常 0.5-0.7 之间比较平衡。建议根据业务需求实验确定。Q4检索到的记忆太多Token 消耗大怎么办→ 限制k值如最多 5 条或者在格式化时截断每条记忆的长度如每条最多 100 字。也可以只保留重要性评分高于阈值的记忆。Q5如何评估检索质量→ 构建测试集给定查询和期望检索到的记忆 ID计算召回率RecallK和精确率PrecisionK。也可以用 LLM 评估检索结果与查询的相关性。Q6长期记忆的向量库越来越大检索变慢怎么办→ 定期清理低价值记忆重要性低、时间久远使用分层存储热记忆在内存冷记忆在磁盘使用更高效的向量索引如 HNSW或者按用户分片存储。四、今日总结与作业今天你完成了✅ 理解了 Embedding 模型的选择标准并了解了常见中文模型的对比。✅ 掌握了向量数据库的进阶检索功能元数据过滤、相似度阈值、MMR。✅ 设计了多级检索策略并实现了综合检索函数。✅ 将检索策略集成到MemoryManager中为客服 Agent 的长期记忆做好了准备。今日作业必做为你的长期记忆库添加更多模拟数据至少 20 条覆盖不同用户、不同类型偏好、事件、事实、不同重要性。测试元数据过滤和 MMR 检索的效果。实现一个函数evaluate_retrieval(query, expected_ids, k)计算检索结果的召回率检索到的期望记忆数 / 期望记忆总数。对比similarity_search、similarity_search_with_score带阈值、max_marginal_relevance_search三种方法在同一个查询上的结果差异记录你的观察。思考题在客服场景中如果用户问“我的订单什么时候到”而长期记忆中有多条关于该用户订单的记录你如何设计检索策略来确保找到最相关的那条请描述你的方案。明日预告我们将学习如何从对话中自动抽取记忆——让 Agent 在与用户聊天时自动识别并存储重要信息如用户偏好、订单号、投诉记录而无需人工干预。这是长期记忆系统自动化的关键一步。有任何问题欢迎随时提问