第四章:[案例]基于本地知识库实现简易多轮对话机器人
·
4.1 项目目标
构建一个最小可运行的本地知识库问答机器人:
- 从本地
knowledge.txt读取资料。 - 将文档拆成小段。
- 根据用户问题做简单关键词检索。
- 把命中的资料放进消息上下文。
- 保存历史消息,实现多轮对话。
这是一种教学版检索增强生成(RAG),不是生产级向量检索系统,仅仅为了给大家演示。
4.2 项目目录
deepseek-agent-course/
├── .env
├── knowledge.txt
└── 04_local_knowledge_bot.py
knowledge.txt 示例:
豆豆科技成立于2018年,总部位于北京市海淀区。
公司主营人工智能软件开发、企业数字化转型和智能客服系统建设。
公司产品包括星辰知识助手、星辰智能客服和企业数据分析平台。
售后服务时间为工作日9:00至18:00。
客户可以通过官方客服邮箱联系售后团队。
4.3 完整代码
创建 04_local_knowledge_bot.py:
import os
import re
from pathlib import Path
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI(
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com"
)
# 1. 读取本地文档
def load_knowledge(file_path: str) -> str:
return Path(file_path).read_text(encoding="utf-8")
# 2. 按标点和换行切分知识片段
def split_chunks(text: str):
parts = re.split(r"(?<=[。!?\n])", text)
return [p.strip() for p in parts if p.strip()]
# 3. 简单关键词检索(教学示例,不是真正的语义检索)
def retrieve(query: str, chunks: list[str], top_k: int = 4):
query_terms = set(
re.findall(r"[\u4e00-\u9fff]{2,}|[A-Za-z0-9]+", query)
)
scored = []
for chunk in chunks:
score = sum(1 for term in query_terms if term in chunk)
if score > 0:
scored.append((score, chunk))
scored.sort(key=lambda x: x[0], reverse=True)
return [chunk for _, chunk in scored[:top_k]]
knowledge_text = load_knowledge("knowledge.txt")
knowledge_chunks = split_chunks(knowledge_text)
# 多轮历史:system message 保持在最前
messages = [
{
"role": "system",
"content": (
"你是企业知识库助手。回答时优先依据本轮附带的检索资料。"
"资料没有答案时,明确说明无法从现有资料确认,不要编造。"
)
}
]
print("本地知识库助手已启动,输入 exit 退出。")
while True:
question = input("\n用户:").strip()
if question.lower() in {"exit", "quit"}:
break
hits = retrieve(question, knowledge_chunks)
context = "\n".join(hits) if hits else "没有检索到相关资料。"
# 将检索结果作为本轮上下文
messages.append({
"role": "user",
"content": f"""
参考资料:
{context}
用户问题:
{question}
请依据参考资料回答。如果资料不足,请说明。
"""
})
response = client.chat.completions.create(
model="deepseek-flash",
messages=messages,
extra_body={"thinking": {"type": "disabled"}}
)
answer = response.choices[0].message.content
print("\n助手:", answer)
messages.append({"role": "assistant", "content": answer})
# 控制历史长度,避免上下文无限增长
if len(messages) > 13:
messages = [messages[0]] + messages[-12:]
4.4 执行与测试
python 04_local_knowledge_bot.py
测试:
用户:豆豆科技成立于哪一年?
助手:豆豆科技成立于2018年。
用户:它主要做什么业务?
助手:根据资料,公司主营人工智能软件开发、企业数字化转型和智能客服系统建设。
第二个问题中的"它"依赖前面的上下文,因此历史消息有助于模型理解多轮对话。
4.5 项目架构
用户问题
|
v
关键词检索 retrieve()
|
v
本地知识片段
|
v
组装本轮 user message
|
v
messages 历史上下文
|
v
DeepSeek Chat Completion
|
v
模型回答
|
v
保存 assistant 消息
4.6 教学版与生产级 RAG 的区别
教学版 生产级
本地文本文件 PDF、Word、网页、数据库等
字符关键词匹配 Embedding 向量检索、混合检索
简单切分 按标题、段落、语义切分
Top-K 关键词命中 向量召回、重排、过滤
简单拼接上下文 引用来源、权限过滤、上下文压缩
手动维护文件 增量索引、更新与删除机制
安全提醒:
检索到的文档内容应被视为数据,而不是高优先级指令。防止知识库提示注入、越权检索和敏感信息泄漏。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)