大数跨境

LangChain 实战第19课:别只会相似度!用 Metadata 过滤,让RAG命中率暴涨

LangChain 实战第19课:别只会相似度!用 Metadata 过滤,让RAG命中率暴涨 玩AI的方可乐
2025-10-07
2
导读:手把手教学,10 分钟见结果

 

你好,我是方可乐。
一个正在深耕AI编程的30+的AI应用开发工程师。
用AI编程开发过Web应用网站,浏览器插件,

微信小程序,AI智能体,RAG系统。

注公众号&添加微信:ThinkFun666

领取【AI编程资料包】



 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

去年6月份,我做了一个连自己都觉得疯狂的决定:裸辞,All in AI。

现在已经换赛道成功,继续在工作中探索。


 

继上一篇文章的RAG精排,基本上RAG的流程和常用方法都讲得差不多了,但RAG依旧有很多地方会遇到坑.

比如,有些细心的同学实践后会发现这个坑:

即使模型和算法再强,检索结果有时还是“不够聚焦”。

比如你问:

「公司请假制度是什么?」

它可能会检索出「年假政策」或「考勤规则」,虽然相关,但不一定是你想要的那一类信息。

这时候,我们可以考虑用 metadata(元数据)过滤,进一步收紧我们的筛选范围。


什么是 Metadata?

在 LangChain 的文档体系中,每个文档 Document 都由两部分组成:


           
           
           
           
            
           
           
           
           {
  "page_content"
: "这是文档的正文内容。",
  "metadata"
: {
    "source"
: "employee_policy.pdf",
    "page"
: 12,
    "category"
: "人事制度"
  }
}

其中:

  • • page_content 是真正被嵌入向量的文本;
  • • metadata 是描述文本属性的“标签信息”。

你可以把它理解成:

给每一段文本打上“来源”“分类”“时间”等标签。


为什么要用 Metadata?

仅靠文本相似度,模型只能判断“像不像”,

却不知道“你想在哪个范围里搜”。

举个例子:

文档内容
metadata.category
员工请假制度
人事制度
报销流程说明
财务制度
技术团队规范
技术规范

当你问「请假流程是什么」时, 如果我们加上过滤条件:category="人事制度", 就能让检索更精准,不会混入不相关的部门文档。

这就像数据库里的 WHERE 条件一样:


           
           
           
           
            
           
           
           
           SELECT * FROM documents WHERE category = '人事制度';

LangChain 的 metadata 过滤,本质上就是类似的逻辑过滤操作。


不同向量库对 Metadata 的支持

向量库
Metadata 支持情况
备注
Chroma
✅ 支持 JSON 格式,可多条件过滤
目前 Chroma 的过滤逻辑是“等值匹配”,类似 SQL 中的 WHERE category='人事制度',如果想实现范围查询(如时间区间),需要在上层自行控制逻辑。
FAISS
⚠️ 仅支持内存中过滤(Python层)
不支持复杂条件
Milvus / Weaviate / Pinecone
✅ 支持数据库级过滤
适合大规模场景

Metadata 在入库时怎么写?

在 LangChain 中,你可以在插入文本时传入 metadatas 参数:


           
           
           
           
            
           
           
           
           from langchain_community.vectorstores import Chroma
from
 langchain_huggingface import HuggingFaceEmbeddings

texts = [
    "公司人事制度规定员工需提前申请年假。"
,
    "财务制度要求报销需提供完整发票。"
,
    "技术部门采用敏捷开发流程。"
,
    "员工请假需提前 3 天申请。"
,
    "公司每年提供 10 天带薪年假。"
,
]

metadatas = [
    {"category": "人事制度", "source": "hr_policy.pdf"},
    {"category": "财务制度", "source": "finance_rule.pdf"},
    {"category": "技术规范", "source": "dev_guide.pdf"},
    {"category": "人事制度", "source": "hr_policy.pdf"},
    {"category": "人事制度", "source": "hr_policy.pdf"},
]

embedding_model = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")

vectorstore = Chroma.from_texts(
    texts=texts,
    metadatas=metadatas,           # ✅ 在这里写入 metadata
    embedding=embedding_model,
    persist_directory="./chroma_db_18"
)

检索时加上 Metadata 过滤

入库后,我们就能像数据库一样加上过滤条件:


           
           
           
           
            
           
           
           
           retriever = vectorstore.as_retriever(
    search_kwargs={
        "k"
: 3,
        "filter"
: {"category": "人事制度"}   # ✅ 指定筛选条件
    }
)

这样它就只会检索「人事制度」类别的文档。


实战代码

老规矩,下面我们上代码。新建文件:18_metadata.py


           
           
           
           
            
           
           
           
           import os
from
 dotenv import load_dotenv
from
 langchain_huggingface import HuggingFaceEmbeddings
from
 langchain_community.vectorstores import Chroma
from
 langchain_openai import ChatOpenAI
from
 langchain.chains import RetrievalQA

def
 _trim(text: str, max_len: int = 60) -> str:
    return
 text if len(text) < max_len else text[:max_len] + "..."

def
 main():
    load_dotenv()

    # ========== 1. 构建带 metadata 的文档 ==========

    texts = [
        "公司人事制度规定员工需提前申请年假。"
,
        "财务制度要求报销需提供完整发票。"
,
        "技术部门采用敏捷开发流程。"
,
        "员工请假需提前 3 天申请。"
,
        "公司每年提供 10 天带薪年假。"
,
    ]
    metadatas = [
        {"category": "人事制度", "source": "hr_policy.pdf"},
        {"category": "财务制度", "source": "finance_rule.pdf"},
        {"category": "技术规范", "source": "dev_guide.pdf"},
        {"category": "人事制度", "source": "hr_policy.pdf"},
        {"category": "人事制度", "source": "hr_policy.pdf"},
    ]

    embedding_model = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")

    vectorstore = Chroma.from_texts(
        texts=texts,
        metadatas=metadatas,
        embedding=embedding_model,
        persist_directory="./chroma_db_18"
    )

    # ========== 2. 初始化 LLM ==========

    llm = ChatOpenAI(
        model="deepseek-chat",
        base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com/v1"),
        api_key=os.getenv("DEEPSEEK_API_KEY"),
        temperature=0,
    )

    query = "请假和报销需要什么材料?"

    # ========== 3. 不加过滤 ==========

    retriever_all = vectorstore.as_retriever(search_kwargs={"k": 3})
    qa_all = RetrievalQA.from_chain_type(llm=llm, retriever=retriever_all)

    print
("\n=== 不加过滤(混合类别) ===")
    results_all = vectorstore.similarity_search_with_relevance_scores(query, k=3)
    for
 doc, score in results_all:
        print
(f"score={score:.4f} | {_trim(doc.page_content)} | {doc.metadata}")

    print
("→ LLM 回答:")
    print
(qa_all.invoke(query))

    # ========== 4. 加 metadata 过滤 ==========

    retriever_filtered = vectorstore.as_retriever(
        search_kwargs={"k": 3, "filter": {"category": "人事制度"}}
    )
    qa_filtered = RetrievalQA.from_chain_type(llm=llm, retriever=retriever_filtered)

    print
("\n=== 基于 metadata 的精准检索 ===")
    results_filtered = retriever_filtered.invoke(query)
    for
 doc in results_filtered:
        print
(f"{_trim(doc.page_content)} | {doc.metadata}")

    print
("→ LLM 回答:")
    print
(qa_filtered.invoke(query))

if
 __name__ == "__main__":
    main()

运行效果

可以看到,加了metadata筛选,就能够精准从知识库的指定文档中检索内容,提升检索效率。

当知识库的文档越多,metadata的检索越是有必要。

 


 



 

 


 

 

 

 

 

 

 

 

 

对AI应用开发感兴趣的同学,欢迎加微信申请入群交流学习。

想要学习AI应用开发的同学,可以参照我的代码跑起来,举一反三,一天一个脚印的进步,我相信,会足够坚实。


接下来100天,我会记录从Java程序员到AI应用开发工程师的完整转型路:每一个困惑、每一次突破、每一个真实瞬间。

当前是37/100。

如果你也想了解AI应用开发到底是什么,如果你也在考虑转型但还在犹豫,那就跟着我的记录,一起探索。


继续折腾中,有问题随时交流 🤝
微信号:ThinkFun666

我的免费AI编程交流群,欢迎加入讨论AI编程玩法(说明需求和来意,申请入群)



 

 



推荐阅读:

我就喜欢干这种傻事!为什么转型AI应用开发,我不建议你直接从看书开始学起?

猛然醒悟:原来 AI 编程这件事情,是有门槛的,90%的新手卡在这些地方

30岁转行 AI 应用开发:多久能学会?答案出乎意料

30岁,我放弃写了7年的Java,成功转型AI应用开发

30岁,转型AI应用开发,需要会什么技术?

30岁,空窗期一年,靠什么成功转型AI应用开发?

30岁,没报课,如何从0自学转型AI应用开发?

【声明】内容源于网络
0
0
玩AI的方可乐
1234
内容 502
粉丝 0
玩AI的方可乐 1234
总阅读204
粉丝0
内容502