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 关键词命中 向量召回、重排、过滤
简单拼接上下文 引用来源、权限过滤、上下文压缩
手动维护文件 增量索引、更新与删除机制

安全提醒:
检索到的文档内容应被视为数据,而不是高优先级指令。防止知识库提示注入、越权检索和敏感信息泄漏。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐