知识库 Agent
🎯 学习目标
- 搭建文档上传 → 索引 → 对话检索全链路
- 回答展示引用来源与「无法回答转人工」
- 文档更新触发增量 re-index
引言
智能客服 = RAG + 会话管理 + 业务规则。本课按周交付:先 MVP 检索问答,再补缓存与增量索引。
章节正文
第 1 步:第 1 步:架构
上传 API → Loader/Splitter → Embedding → Qdrant/Chroma
用户问 → Query Embed → Top-K → Prompt + LLM → 回答 + citations
会话 → Redis/Postgres多租户:collection 按 tenant_id 隔离。
第 2 步:第 2 步:索引管道
python
from langchain_openai import OpenAIEmbeddings
from langchain_qdrant import QdrantVectorStore
from qdrant_client import QdrantClient
emb = OpenAIEmbeddings(model="text-embedding-3-small")
client = QdrantClient(":memory:") # 生产换持久化
vectorstore = QdrantVectorStore(client=client, collection_name="kb", embedding=emb)
def index_files(files):
for f in files:
docs = load_and_split(f)
vectorstore.add_documents(docs)第 3 步:第 3 步:带引用的 RAG 链
python
from langchain_core.runnables import RunnablePassthrough
def format_docs(docs):
return "\n\n".join(
f"[{i+1}] {d.page_content}\n来源: {d.metadata.get('source')}"
for i, d in enumerate(docs)
)
rag = (
RunnablePassthrough.assign(docs=lambda x: vectorstore.similarity_search(x["question"], k=4))
| RunnablePassthrough.assign(
answer=lambda x: (prompt | llm | StrOutputParser()).invoke({
"context": format_docs(x["docs"]),
"question": x["question"],
})
)
)Prompt 要求:「仅依据 context;无依据则说不知道」。
第 4 步:第 4 步:客服策略
- 相似度低于阈值 →
handoff_human: true - 相同 FAQ query 缓存 10min(Redis)
- 文档
updated_at变化 → 删旧 chunk id 再 embed - 会话结束生成摘要给人工坐席
动手练习
- 上传 3 份 Markdown FAQ,问 5 个问题并展示引用
- 实现低分拒答转人工按钮
- 更新一份文档后验证答案变化
本节小结
客服 RAG = 多租户索引 + 引用 + 拒答/转人工 + 缓存 + 增量索引。