第 26 章 案例二 企业知识库问答 Agent

文章来源声明: 原文作者:前端阿凡; 来源站点:掘金; 原文链接:https://juejin.cn/post/7689219046840074278; 本文基于上述来源整理/加工,觅优补充点评,仅供技术学习交流。版权归原作者所有。
觅优短评

聚焦企业内网知识库的幻觉、权限与索引同步痛点,给出可落地的 RAG 自检、出处追溯和 MCP 集成方案,适合内部制度问答与流程查询团队参考。

第 26 章 案例二:企业知识库问答 Agent ------------------------

本章要解决的问题

企业文档中心几万份 PDF,怎么让 Agent 精准回答「我们公司的报销标准是什么」?

章节大纲

  • 26.1 文档处理与向量检索(Qwen + 内网知识库)
  • 26.2 RAG + 反思 + 评估自检
  • 26.3 MCP 集成企业系统
  • 26.4 评测与上线
  • 🛠 解决方案:知识库问答幻觉抑制方案 + 检索质量评估

26.1 文档处理与向量检索

26.1.1 场景与挑战

场景:企业内部文档中心,几万份 PDF(制度、流程、项目文档),员工随时提问。

三个挑战:

  1. 文档格式杂:PDF(含扫描件)、Word、Excel、PPT——要先解析。
  2. 数据敏感:内网数据不能出域 → 私有化部署或数据脱敏(第 2/22 章)。
  3. 问题多样:制度查询、流程咨询、项目检索——需要精准检索。

26.1.2 文档处理管线(第 8 章完整实践)

示例代码:以下代码演示核心结构,省略了异常处理、日志和完整 import。

<span>import</span> os
<span>from</span> typing <span>import</span> <span>List</span>, <span>Dict</span>

<span>def</span> <span>parse_document</span>(<span>path: <span>str</span></span>) -> <span>str</span>:
    <span>"""解析各种格式 → 纯文本"""</span>
    ext = os.path.splitext(path)[<span>1</span>].lower()
    <span>if</span> ext <span>in</span> (<span>".pdf"</span>,):
        <span>return</span> parse_pdf(path)          <span># 文本型 PDF</span>
    <span>if</span> ext <span>in</span> (<span>".docx"</span>, <span>".doc"</span>):
        <span>return</span> parse_word(path)
    <span>if</span> ext <span>in</span> (<span>".xlsx"</span>, <span>".xls"</span>):
        <span>return</span> parse_excel(path)        <span># 表格转文本</span>
    <span>if</span> ext <span>in</span> (<span>".png"</span>, <span>".jpg"</span>):
        <span>return</span> ocr_image(path)          <span># 扫描件 → OCR</span>
    <span>return</span> <span>""</span>

<span>def</span> <span>build_index</span>(<span>doc_dir: <span>str</span></span>):
    <span>"""全量建索引:解析 → 分块 → 向量化 → 存储"""</span>
    chunks = []
    <span>for</span> root, _, files <span>in</span> os.walk(doc_dir):
        <span>for</span> fname <span>in</span> files:
            text = parse_document(os.path.join(root, fname))
            <span>for</span> chunk <span>in</span> split_into_chunks(text, size=<span>600</span>, overlap=<span>80</span>):
                chunks.append({
                    <span>"text"</span>: chunk,
                    <span>"metadata"</span>: {
                        <span>"source"</span>: fname,
                        <span>"dept"</span>: infer_dept(fname),   <span># 部门过滤</span>
                        <span>"type"</span>: infer_type(fname),   <span># 制度/流程/项目</span>
                        <span>"updated"</span>: file_mtime(fname),
                    },
                })
    vector_store.add_documents(chunks)   <span># Qwen embedding 向量化</span>
    <span>return</span> <span>len</span>(chunks)

图 1:文档处理管线

图 1:文档处理管线

关键设计:

  • 解析要"识别失败":解析不了的文档(加密/乱码)要标记并告警,不能静默丢失。
  • 元数据三件套:source(出处可追溯)、dept(部门过滤)、type(类型过滤)——检索的"筛子"。
  • 扫描件走 OCR:PDF 分两种——文本型直接解析,扫描型先 OCR。

26.1.3 检索优化(第 8 章)

<span>def</span> <span>retrieve_for_query</span>(<span>question, filters=<span>None</span></span>):
    <span># 混合检索:向量 + BM25 + RRF 融合</span>
    results = hybrid_retrieve(question, filters=filters, top_k=<span>20</span>)
    <span># 重排:Cross-Encoder 精排 Top-20 → Top-3</span>
    <span>return</span> rerank(question, results, top_k=<span>3</span>)

检索质量三步:混合检索(召回全)→ 重排(排序准)→ 过滤(范围对)。

26.2 RAG + 反思 + 评估自检

26.2.1 三件套组合:让回答"可信任"

知识库问答最大的风险是幻觉(编造制度条款)。组合三件套压制幻觉:

图 2:RAG+自检+反思

图 2:RAG+自检+反思

<span>[RAG]</span> 检索相关资料(提供事实)
  ↓
<span>[自检]</span> 规则校验(必含引用出处)+ 忠实度检查(第<span>17</span>章)
  ↓
<span>[反思]</span> 有引用但不确定 → 重查/重答(第<span>13</span>章)
  ↓
<span>[兜底]</span> 资料不足 → 明确说"未查到",不硬答

26.2.2 忠实度自检实现

<span>def</span> <span>faithfulness_check</span>(<span>answer, sources</span>):
    <span>"""检查回答是否忠实于资料:每个关键断言都要能在资料中找到依据"""</span>
    resp = llm_judge(<span>f"""检查回答中的每个断言是否都能在参考资料中找到依据。
回答:<span>{answer}</span>
资料:<span>{sources}</span>
只输出 JSON:{{"faithful": bool, "unsubstantiated": ["无依据的断言"]}}"""</span>)
    <span>return</span> resp

<span>def</span> <span>knowledge_answer</span>(<span>question, filters=<span>None</span></span>):
    sources = retrieve_for_query(question, filters)
    <span>if</span> <span>not</span> sources:
        <span>return</span> <span>"未在知识库中找到相关资料,建议联系行政部确认。"</span>, []
    answer = llm.chat(
        system=<span>"你是企业知识库助手。仅基于资料回答,并注明出处(文件名)。"</span>,
        user=<span>f"【资料】<span>{sources}</span>\n【问题】<span>{question}</span>"</span>,
        temperature=<span>0.2</span>,          <span># 知识问答用低温度</span>
    )
    <span># 忠实度自检,不通过 → 反思重答</span>
    check = faithfulness_check(answer, sources)
    <span>if</span> <span>not</span> check[<span>"faithful"</span>]:
        answer = llm.chat(
            system=<span>"基于资料重新回答,修正以下无依据的内容:"</span>
                   <span>f"<span>{check[<span>'unsubstantiated'</span>]}</span>"</span>,
            user=<span>f"【资料】<span>{sources}</span>\n【问题】<span>{question}</span>"</span>,
            temperature=<span>0.1</span>,
        )
    <span>return</span> answer, sources

兜底原则:查不到就说查不到(附建议渠道)——比编造一个看似合理的答案好 100 倍(第 8 章"没有就说没有")。

26.2.3 出处可追溯

回答必须带出处(哪个文件、哪个版本),这是企业知识库的硬要求:

<span>return</span> <span>f"<span>{answer}</span>\n\n【出处】<span>{sources[<span>0</span>][<span>'metadata'</span>][<span>'source'</span>]}</span>(<span>{sources[<span>0</span>][<span>'metadata'</span>][<span>'updated'</span>]}</span>)"</span>

出处 = 可信任的最后一道证明——员工能自己打开原文件核对。

26.3 MCP 集成企业系统

26.3.1 知识库 Agent 要连什么

不只是问答,还要能联动企业系统:

图 3:知识库权限过滤

图 3:知识库权限过滤

系统用途接入方式
OA 系统查审批流程状态MCP Server
HR 系统查假期/薪资制度MCP Server
项目管理系统查项目文档MCP Server
内部 Wiki实时内容MCP Server

26.3.2 用 MCP 接入(第 7 章实践)

<span>from</span> fastmcp <span>import</span> FastMCP

mcp = FastMCP(<span>"oa-integration"</span>)

<span>@mcp.tool()</span>
<span>def</span> <span>query_approval_status</span>(<span>approval_id: <span>str</span></span>) -> <span>dict</span>:
    <span>"""查询 OA 审批状态。用户询问审批进度/结果时使用。"""</span>
    <span># 内部 OA API 封装</span>
    <span>return</span> oa_api.get_approval(approval_id)

<span>@mcp.tool()</span>
<span>def</span> <span>query_leave_policy</span>(<span>department: <span>str</span></span>) -> <span>dict</span>:
    <span>"""查询假期制度。用户询问年假/病假/调休时使用。"""</span>
    <span>return</span> hr_api.get_leave_policy(department)

<span># 注册进 Agent:MCP 发现的工具 = 知识库 Agent 的动态工具集</span>

价值:知识库 Agent 从"纯问答"升级为"问答 + 操作"——问完制度还能直接查自己的审批状态。

26.4 评测与上线

26.4.1 知识库专项评测(第 8/20 章)

EVAL_SET = [
    {<span>"question"</span>: <span>"报销标准是什么?"</span>, <span>"gold_docs"</span>: [<span>"报销制度-v3.pdf"</span>],
     <span>"check"</span>: <span>"含金额上限且注明出处"</span>},
    {<span>"question"</span>: <span>"年假怎么休?"</span>, <span>"gold_docs"</span>: [<span>"休假管理办法.pdf"</span>],
     <span>"check"</span>: <span>"按制度回答"</span>},
    {<span>"question"</span>: <span>"去年的团建费怎么报?"</span>, <span>"gold_docs"</span>: [],   <span># 无此文档</span>
     <span>"check"</span>: <span>"明确说未查到,不编造"</span>},
    {<span>"question"</span>: <span>"扫描件里的制度也查得到吗?"</span>, <span>"gold_docs"</span>: [<span>"旧制度-扫描版.pdf"</span>],
     <span>"check"</span>: <span>"OCR 后能检索"</span>},
    ...
]
<span># 指标:检索命中率 / 忠实度 / 幻觉率 / 出处覆盖率</span>

26.4.2 上线要点

事项说明
**私有化部署**内网数据不出域(第 2/22 章)
**文档更新机制**新文档入索引 + 旧版本标记(防止旧版误导)
**权限过滤**不同部门看到不同文档(RBAC,第 22 章)
**监控**检索命中率周报 + 幻觉率抽评(第 20 章)
**反馈闭环**员工点踩的答案回流评测集(第 18/20 章)

26.4.3 更新索引的工程细节

<span># 文档变更 → 增量更新(别全量重建,费时费钱)</span>
<span>def</span> <span>sync_index</span>():
    changed = detect_changed_docs()          <span># 对比文件指纹</span>
    <span>for</span> doc <span>in</span> changed:
        vector_store.delete(<span>filter</span>={<span>"source"</span>: doc[<span>"name"</span>]})  <span># 删旧</span>
        index_document(doc)                                  <span># 加新</span>
    <span># 版本冲突:同标题多版本 → 只保留最新(按 updated 排序)</span>

图 4:文档增量同步

图 4:文档增量同步

🛠 解决方案:知识库问答幻觉抑制方案 + 检索质量评估

常见问题

  1. "答案编造制度条款":约束松 + 无出处。对策:仅基于资料 + 忠实度自检 + 强制带出处(26.2)。
  2. "检索不到扫描件内容":没 OCR。对策:扫描型 PDF 走 OCR(26.1.2)。
  3. "旧版制度误导用户":多版本并存无过滤。对策:版本标记 + 只保留最新(26.4.3)。
  4. "A 部门能查到 B 部门的机密":无权限过滤。对策:RBAC 元数据过滤(第 22 章)。
  5. "文档更新了但 Agent 答的还是旧的":索引未同步。对策:增量同步 + 文件指纹检测(26.4.3)。

解决方案速查表

现象根因解决方案
编造条款约束松仅基于资料 + 忠实度自检 + 出处
扫描件查不到无 OCROCR 管线
旧版误导多版本未过滤版本标记 + 保留最新
越权查看无权限过滤RBAC 过滤
答旧内容索引未同步增量同步

实战提示

  1. 出处是知识库的信任根基:回答必带文件名 + 版本,员工能自己核对。
  2. 幻觉抑制三件套:低温度(0.2)+ 忠实度自检 + 查不到就明说。
  3. 元数据过滤别省:部门/类型/版本过滤让检索精准十倍。
  4. 文档生命周期要管理:新增/更新/废弃都要反映到索引。
  5. 内网数据安全第一:私有化部署或脱敏,数据出域要评估(第 22 章)。