4.2 整线贯通:知识库问答系统实战


4.2 整线贯通:知识库问答系统实战

本节摘要:把前三章零件总装成一条真实可用的知识库问答产线。案例背景是某袜子品牌的内部帮助台,完整走一遍背景分析、五步装配、质检调优、上线解读与变式扩展,是全教程的合成大练兵。

案例:品牌帮助台的诞生

背景。一家百人规模的袜子品牌,客服三人组每天重复回答退换货、洗护、物流三类问题,答复口径经常不一致;产品手册躺在共享盘里没人翻。目标:一条"文档进、答案出"的产线,答案必须忠于手册、说不知道就不知道、多轮追问不断档。口径约束:预算有限,优先零基础设施方案;答案错比不答严重,宁可保守。

五步总装台

五步总装台

操作:五步装配实录

第一步备料。手册三十页加 FAQ 四十题,统一转成 UTF-8 文本文件,按主题拆成五个文件(退换、洗护、物流、尺码、会员)。这一步没有代码,却是质量地基——垃圾进垃圾出在任何后续步骤都无法挽回。

第二步建库,供料线三连(2.6 到 2.8 节零件):

from langchain_community.document_loaders import DirectoryLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma # 加载:目录整批进料 每文件一主题 docs = DirectoryLoader("./kb", glob="**/*.txt").load() # 切分:中文手册经验值 块300重叠40 chunks = RecursiveCharacterTextSplitter( chunk_size=300, chunk_overlap=40).split_documents(docs) # 入库:持久化到本地目录 只建一次 vs = Chroma.from_documents( chunks, OpenAIEmbeddings(), persist_directory="kb_store") print("入库块数:", len(chunks)) # 输出示例:入库块数:127

第三步装链,主带与供线对接(2.8 节图纸):

from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough from langchain_openai import ChatOpenAI retriever = vs.as_retriever(search_kwargs={"k": 3}) def fmt(docs): return "\n".join(d.page_content for d in docs) prompt = ChatPromptTemplate.from_messages([ ("system", "你是品牌帮助台客服。只依据资料回答," "资料里没有就回答:手册里没有相关内容," "请联系人工客服。"), ("human", "资料:\n{ctx}\n\n问题:{q}"), ]) qa_chain = ({"ctx": retriever | fmt, "q": RunnablePassthrough()} | prompt | ChatOpenAI(temperature=0) | StrOutputParser()) print(qa_chain.invoke("定制款能退吗")) # 输出:定制款不支持退换。

第四步加记忆,让"那洗的时候呢"这种追问成立。追问的难点在指代——"那"指的是上一轮的定制款,直接拿去检索会落空,所以要先用模型把追问改写成完整问题再检索:

from langchain_core.runnables import RunnableWithMessageHistory from langchain_core.chat_history import InMemoryChatMessageHistory store = {} def get_history(sid): return store.setdefault(sid, InMemoryChatMessageHistory()) multi_turn = RunnableWithMessageHistory( qa_chain, get_history, input_messages_key="q", history_messages_key="chat_history") cfg = {"configurable": {"session_id": "u-88"}} print(multi_turn.invoke({"q": "定制款能退吗"}, config=cfg).content) print(multi_turn.invoke({"q": "那洗的时候要注意什么"}, config=cfg).content) # 输出示例:定制款因图案特殊 建议单独冷水手洗 避免串色

第五步质检,建二十题考卷(3.3 节标尺):

exam = [("定制款能退吗", "定制款不支持退换"), ("第一次洗注意什么", "冷水手洗浮色正常"), ("发货多久到", "江浙沪次日 其余三日内"), ("尺码偏大吗", "正常偏码 按平时码选")] def check(chain) -> float: hit = 0 for q, ref in exam: ans = chain.invoke(q if isinstance(chain, object) else q) if any(k in ans for k in ref.split(",")): hit += 1 return hit / len(exam) print("考卷得分:", check(qa_chain)) # 输出示例:考卷得分: 0.75(有一题检索没命中 回炉把k调到3重跑)

结果与解读

上线两周的实测数据:三类高频问题的自动应答覆盖约七成,人工工单降四成;延迟中位数 1.9 秒;每日成本不到一杯咖啡钱。解读三条:一,收益大头来自备料与切分这两个"非代码环节"——产线再好,喂料决定上限;二,"说不知道"护栏拦下的约一成提问,全部转人工,口径零事故,验证了保守策略的正确;三,追问改写是体验分水岭,没上它之前用户第二轮满意度明显下滑。

变式扩展:同一套底盘能长出多种形态。加 3.2 节的搜索工具变"手册加全网"混合问答;换托管向量库支撑多实例部署;前面挂 4.1 节的分类小链,把售后与闲聊分流到不同产线;给客服侧加 3.3 节的裁判评估做每日自动巡检。底盘不动,上层任改——这就是装配线视角最直接的回报。

⚠️ 这条产线最隐蔽的故障源是索引过期:手册改了、共享盘的文件换了版本,仓库里还是旧口径。上线时就要定好"文档变更触发重建"的流程纪律,别等客诉发现答的是上季度的政策。

💡 复盘本案例的零件账单:九个工位用上七个,四类改装用上三类——你在此看到的不是新知识,而是编排能力。装配线学到最后,拼的是对零件边界的熟悉度。

产线装好了还躺在你的进程里。下一节解决最后一公里:把它包装成服务、配好密钥与依赖、发布出去让人调用。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U