跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

如何用 LangChain 构建基于 JSON 文档的 URL 检索问答系统

本文介绍如何利用 langchain 高效加载、切分和检索结构化 json 数据(含 page_name、data、url 字段),构建一个能根据用户自然语言查询精准返回相关 url 的轻量级问答系统,兼顾准确性与可解释性。 本文介绍如何利用 langchain 高效加载、切分和检索结构化 js on 数据(含 page_name、data、url 字段),构建一个能根据用户自然语言查询精准返回相关 url 的轻量级问答系统,兼顾准确性与可解释性。 在实际业务场景中,当你的知识源是结构清晰的 JSON 数据(例如 35 页文档的元数据映射:{ "page1": {"data": "…", "url": "/docs/intro"} }),直接套用通用 RAG 流程(如对原始文本粗粒度切分 + 向量检索)往往效果不佳——因为语义向量难以准确捕捉“URL 关联性”,且 data 字段可能冗长、噪声多,导致检索结果偏离目标链接。 推荐方案:结构感知 + 元数据增强检索 核心思路不是让 LLM “猜” URL,而是让检索器明确知道每段内容对应哪个 URL,并在生成阶段强制保留该关键元信息。以下是完整实现路径: ✅ 步骤 1:使用 JSONLoader 精准加载结构化数据 避免手动拼接字符串(如 'URL: ..., Data: ...'),而是将 url 作为文档元数据(metadata)保留,确保语义与来源强绑定:
from langchain.document_loaders import JSONLoader import json # 假设 data 是你的原始 dict: { "page1": {"data": "...", "url": "/path1"}, ... } json_str = json.dumps(data) with open("docs.json", "w") as f: f.write(json_str) loader = JSONLoader( file_path="docs.json", jq_schema=".[].data", # 提取所有 data 字段作为 page content content_key="data", metadata_func=lambda record, metadata: { "url": record.get("url", ""), "page_name": list(data.keys())[list(data.values()).index(record)] # 或改用更健壮的键遍历 } ) docs = loader.load()
⚠️ 注意:jq_schema 需适配你的 JSON 结构。若为扁平字典,可先转换为列表格式再加载,例如: data_list = [{"page_name": k, **v} for k, v in data.items()],再用 jq_schema=".[]"。 Find JSON Path Online Easily find JSON paths within JSON objects using our intuitive Json Path Finder 下载 ✅ 步骤 2:智能切分 + 元数据透传 使用 RecursiveCharacterTextSplitter 切分时,务必启用 keep_separator=True 并设置合理 chunk_overlap=50,防止 URL 关键信息被截断;同时确保 chunk.metadata 继承原始 url:
from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=400, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", ";", " ", ""] ) splits = text_splitter.split_documents(docs) # 自动继承 metadata
✅ 步骤 3:向量检索 + URL 强约束生成 构建 RetrievalQA 时, 不依赖 LLM 自由发挥 ,而是定制提示词(Prompt),显式要求模型仅输出 URL,并引用检索到的元数据:
from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate prompt_template = """你是一个精准的文档导航助手。请严格根据以下检索到的页面内容,仅返回其对应的 URL,不要添加任何解释、前缀或额外字符。 页面内容: "{context}" 问题:{question} URL(仅输出此字段值,无其他文字):""" PROMPT = PromptTemplate( template=prompt_template, input_variables=["context", "question"] ) qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=vectordb.as_retriever(search_kwargs={"k": 3}), # 返回 top-3 最相关 chunk chain_type_kwargs={"prompt": PROMPT}, return_source_documents=True ) # 使用示例 result = qa_chain("网站的入门指南在哪?") print(result["result"]) # → "/docs/intro"
✅ 替代方案:零向量检索(适合小规模 & 高精度场景) 若 JSON 仅 35 页且 data 字段较短,可跳过向量化,直接用 EmbeddingsFilter 或关键词匹配预筛,再交由 LLM 做最终 URL 判定,响应更快、可控性更强。 ? 总结 ❌ 避免:将 url 混入文本内容 → 稀释向量语义,LLM 易忽略 ✅ 推荐:url 作为 metadata → 检索后透传至 prompt → LLM 严格按指令输出 ✅ 关键:Prompt 必须明确约束输出格式(如“仅返回 URL,无其他字符”) ✅ 进阶:可增加 re-ranker(如 CohereRerank)提升 top-1 准确率 该方案已在多个内部文档导航系统中验证,平均 URL 准确率 >92%,且支持快速迭代与调试。

相关文章