手撸一个 deepseek 聊天历史对话、多轮对话(ollama + deepseek + langchain + flask)

前言

为了让聊天更加智能化,体验更好,打算搞个聊天历史对话,让 deepseek 可以结合上下文回答。

一、准备环境

  1. ollama,用于在本地运行、部署和管理大型语言模型(LLMs)。
  2. deepseek 模型,本文用的 deepseek-r1:14b。
  3. langchain,大语言模型应用程序的开发框架,主要 python 实现。

二、开发思路

  1. 使用 langchain 的 SQLChatMessageHistory 模块管理聊天历史记录,每段对话一个 session_id。
  2. 将聊天历史记录存储在 sqlite 数据库。
  3. 设置聊天上下文最大次数,即多轮对话次数,达到之后清空聊天记录。

三、代码解读

  1. 初始化 llm
python 复制代码
# 设置Ollama的主机和端口
os.environ["OLLAMA_HOST"] = "127.0.0.1"
os.environ["OLLAMA_PORT"] = "11434"


def get_llm():
    # 定义提示模板
    template = """
    你是一个专业的助手,请根据用户的问题,生成详细且专业的回答。
    用户的问题:{input}
    """

    prompt = ChatPromptTemplate.from_template(template)

    # 初始化Ollama模型
    model = OllamaLLM(model="deepseek-r1:14b")

    # 创建链
    llm = prompt | model

    return llm
  1. 初始化聊天历史
python 复制代码
# 初始化聊天历史
def get_session_history(session_id):
    return SQLChatMessageHistory(session_id, "sqlite:///chat_history.db")
  1. 基于聊天历史对话
python 复制代码
def start_chat_history(input, session_id):
    # 判断是否新起对话
    delete_chat_history(session_id)

    # 初始化llm
    llm = get_llm()

    # 创建带历史记录的链
    runnable_with_history = RunnableWithMessageHistory(
        llm,
        get_session_history,
        input_messages_key="input"  # 明确指定输入键
    )

    # 提问参数
    translation_params = {
        "input": input
    }

    # 执行调用
    return runnable_with_history.stream(
        translation_params,
        config={"configurable": {"session_id": session_id}}
    )
  1. 达到最大对话记录清空历史

先看下 chat_history.db 的表结构

session_id 是个字符串类型,别的系统调用时可以把用户的 user_id 之类的作为对话标识,代码如下:

python 复制代码
# 查询对话历史
def query_by_session_id(session_id):
    conn = sqlite3.connect('chat_history.db')
    curs = conn.cursor()
    sql = 'SELECT count(1) FROM message_store WHERE session_id = '+ session_id
    curs.execute(sql)
    results = curs.fetchall()
    curs.close()
    conn.close()
    return results


# 删除对话历史
def delete_by_session_id(session_id):
    conn = sqlite3.connect('chat_history.db')
    curs = conn.cursor()
    sql = 'DELETE FROM message_store WHERE session_id = '+ session_id
    curs.execute(sql)
    conn.commit()
    curs.close()
    conn.close()


# 达到最大对话记录清空历史
def delete_chat_history(session_id):
    history_count = query_by_session_id(session_id)
    count = history_count[0][0]
    # 一个对话两条记录,一个用户,一个AI
    if count >= MAX_CHAT * 2:
        delete_by_session_id(session_id)

五、完整代码

python 复制代码
import os

import sqlite3
from langchain_ollama.llms import OllamaLLM
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import SQLChatMessageHistory

# 多轮对话次数
MAX_CHAT = 3

# 设置Ollama的主机和端口
os.environ["OLLAMA_HOST"] = "127.0.0.1"
os.environ["OLLAMA_PORT"] = "11434"


def get_llm():
    # 定义提示模板
    template = """
    你是一个专业的助手,请根据用户的问题,生成详细且专业的回答。
    用户的问题:{input}
    """

    prompt = ChatPromptTemplate.from_template(template)

    # 初始化Ollama模型
    model = OllamaLLM(model="deepseek-r1:14b")

    # 创建链
    llm = prompt | model

    return llm


# 查询对话历史
def query_by_session_id(session_id):
    conn = sqlite3.connect('chat_history.db')
    curs = conn.cursor()
    sql = 'SELECT count(1) FROM message_store WHERE session_id = '+ session_id
    curs.execute(sql)
    results = curs.fetchall()
    curs.close()
    conn.close()
    return results


# 删除对话历史
def delete_by_session_id(session_id):
    conn = sqlite3.connect('chat_history.db')
    curs = conn.cursor()
    sql = 'DELETE FROM message_store WHERE session_id = '+ session_id
    curs.execute(sql)
    conn.commit()
    curs.close()
    conn.close()


# 达到最大对话记录清空历史
def delete_chat_history(session_id):
    history_count = query_by_session_id(session_id)
    count = history_count[0][0]
    # 一个对话两条记录,一个用户,一个AI
    if count >= MAX_CHAT * 2:
        delete_by_session_id(session_id)


# 初始化聊天历史
def get_session_history(session_id):
    return SQLChatMessageHistory(session_id, "sqlite:///chat_history.db")


def start_chat_history(input, session_id):
    # 判断是否新起对话
    delete_chat_history(session_id)

    # 初始化llm
    llm = get_llm()

    # 创建带历史记录的链
    runnable_with_history = RunnableWithMessageHistory(
        llm,
        get_session_history,
        input_messages_key="input"  # 明确指定输入键
    )

    # 提问参数
    translation_params = {
        "input": input
    }

    # 执行调用
    return runnable_with_history.stream(
        translation_params,
        config={"configurable": {"session_id": session_id}}
    )

stream = start_chat_history("风景", "1")
for chunk in stream:
        print(chunk, end="", flush=True)

六、测试效果

代码设置的 3 次记录,到达这个记录后清空开启新对话。

  1. 第一轮对话,输入"深圳旅游",返回内容:
  1. 第二轮对话,输入 "美食",返回内容:

这里可以看到已经关联了上次对话

  1. 第三轮对话,输入 "特产",返回内容:
  2. 最后一轮,测试是否清空之前 3 次对话记录,开启新的对话,输入内容 "自驾游",返回内容:

可以看到,已经跟之前对话没有关联。

其他优化空间:

  • 每次对话,AI 回答的生成摘要存储,而不是全部存储,节省空间。
  • 通过 flask 或其他框架提供 API,给别的系统调用。
  • 也可以让调用的系统自行保存历史记录,在对话接口传入聊天历史内容。
  • 试试 langchain 其他模块实现聊天历史对话

大家可以自行修改~

相关推荐
MaybeAI5 分钟前
Skill 与 Workflow:让自动化更“聪明”的系统架构
人工智能·ai·自动化·workflow·工作流
唯道行11 分钟前
计算机图形学·9 几何学
人工智能·线性代数·计算机视觉·矩阵·几何学·计算机图形学
Antonio91513 分钟前
【图像处理】tiff格式介绍
图像处理·人工智能
AndrewHZ16 分钟前
【图像处理基石】什么是alpha matting?
图像处理·人工智能·计算机视觉·matting·发丝分割·trimap·人像模式
慕云紫英29 分钟前
人工智能在全球多领域的应用潜力及当前技术面临的挑战
人工智能·aigc
“向阳的蛋”34 分钟前
生老病死(一)
人工智能·ai
流烟默37 分钟前
机器学习中模型的鲁棒性是什么
人工智能·机器学习·鲁棒性
0小豆041 分钟前
【系列开篇】从零构建智能字幕校准系统:一个AI+微服务的完整实战之旅
spring boot·python·nlp·微服务架构·实战项目·spacy·ai算法
Baihai_IDP1 小时前
并行智能体是否将重塑软件开发模式?
人工智能·程序员·ai编程
周杰伦_Jay1 小时前
【主流开发语言深度对比】Python/Go/Java/JS/Rust/C++评测
开发语言·python·golang