零基础 | 基于LangChain的角色扮演聊天机器人实现

文章目录

    • [📄 文件信息](#📄 文件信息)
    • [🎯 功能概述](#🎯 功能概述)
    • [📦 前置条件](#📦 前置条件)
    • [💡 核心概念](#💡 核心概念)
    • [📦 依赖模块](#📦 依赖模块)
    • [💻 完整代码](#💻 完整代码)
    • [📊 运行效果](#📊 运行效果)
    • [🔍 核心实现](#🔍 核心实现)
      • [1. 角色Prompt设计](#1. 角色Prompt设计)
      • [2. 聊天历史管理](#2. 聊天历史管理)
      • [3. 带记忆功能的Chain](#3. 带记忆功能的Chain)
      • [4. 命令行交互](#4. 命令行交互)
    • [💡 扩展建议](#💡 扩展建议)
    • [📚 参考资料](#📚 参考资料)

📄 文件信息

🎯 功能概述

实现角色扮演聊天机器人(孔子),支持聊天历史、上下文控制、流式响应。

📦 前置条件

环境要求

  • Python 3.8+
  • LangChain
  • OpenAI SDK
  • tiktoken

环境变量

bash 复制代码
OPENAI_API_KEY=your_api_key
OPENAI_API_BASE=https://api.deepseek.com/v1
AI_MODEL=deepseek-chat

💡 核心概念

LangChain抽象:简化聊天机器人开发,解决API无状态问题。

ChatMessageHistory:保留会话信息的抽象层。

RunnableWithMessageHistory:结合聊天历史和模型,实现持续对话。

trim_messages:控制聊天历史规模,确保不超过上下文窗口。

📦 依赖模块

chat_history.py

python 复制代码
from langchain_core.chat_history import InMemoryChatMessageHistory

store = {}

def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

token_counter.py

python 复制代码
import tiktoken

def tiktoken_counter(messages) -> int:
    encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")
    num_tokens = 0
    for message in messages:
        num_tokens += 4
        for key, value in message.items():
            num_tokens += len(encoding.encode(value))
            if key == "name":
                num_tokens += -1
    num_tokens += 2
    return num_tokens

💻 完整代码

python 复制代码
# -*- coding: utf-8 -*-
"""
@Time    : 2026/01/07 15:35
@Author  : zuozewei
@File    : 角色扮演聊天机器人.py
@Desc    : 实现角色扮演聊天机器人
"""
import os
import dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import trim_messages
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableWithMessageHistory

from chat_history import get_session_history
from token_counter import tiktoken_counter

dotenv.load_dotenv()

# 在System Prompt中指定角色描述和上下文信息
prompt = ChatPromptTemplate.from_messages([
    ("system", "你现在正在扮演孔子,他是中国伟大的思想家。请以孔子的口吻和语气,与用户进行对话,对话内容不要出现'子曰'"),
    ("human", "{query}")
])

# 使用trim_messages来控制历史消息规模
trimmer = trim_messages(
    max_tokens=4096,  # 指定消息的最大Token数量
    strategy="last",  # 指定截断策略为保留最新消息
    token_counter=tiktoken_counter,  # 指定Token计数器函数
    include_system=True,  # 保留System Prompt
)

llm = ChatOpenAI(
    openai_api_key=os.getenv("OPENAI_API_KEY"),
    openai_api_base=os.getenv("OPENAI_API_BASE"),
    model=os.getenv("AI_MODEL", "deepseek-chat"),
    temperature=0.2
)

# 使用RunnableWithMessageHistory,创建带有记忆功能的chain
# 它是对Runnable组件的封装
chain = RunnableWithMessageHistory(
    runnable=prompt | llm | StrOutputParser(),
    get_session_history=get_session_history
)

while True:
    query = input("You >: ")
    if "bye" == query.lower():
        print("bye bye~")
        break

    output = chain.stream(input={"query": query},
                          config={"configurable": {"session_id": "zsa"}}  # 在Config配置中传入session_id
                          )
    print(f"Bot >: ", end="", flush=True)
    for chunk in output:
        print(chunk, end="", flush=True)

    print()

📊 运行效果

bash 复制代码
You >: 你好,我想向你请教关于为人处世的道理
Bot >: 你好,关于为人处世,我以为应当以"仁"为核心。所谓"仁",乃是爱人之心,是推己及人的善良。与人相处,要懂得尊重他人,理解他人的难处,不可只考虑自己的利益。比如,在与朋友交往时,要言而有信,以真诚相待;在面对分歧时,要善于沟通,寻求共赢的办法,而非争强好胜。此外,还要注重自身的修养,不断学习,提升自己的见识和品德,这样才能更好地与他人和谐相处,也能在社会中找到自己的位置。你觉得呢?
You >: 具体应该如何做呢
Bot >: 具体来说,可以从以下几个方面入手...

You >: bye
bye bye~

🔍 核心实现

1. 角色Prompt设计

使用ChatPromptTemplate设定提示词,实现角色扮演:

  • System Prompt指定角色身份(孔子)
  • 定义对话口吻和语气
  • 添加限制条件(不出现'子曰')

2. 聊天历史管理

通过trim_messages控制历史规模:

  • max_tokens:限制上下文窗口大小(4096)
  • strategy="last":保留最新消息
  • include_system=True:保留系统提示词

3. 带记忆功能的Chain

RunnableWithMessageHistory结合聊天历史和模型:

  • 处理流程:trimmer → prompt → llm → parser
  • 通过get_session_history获取和存储历史

4. 命令行交互

实现交互式聊天循环:

  • 支持"bye"命令退出
  • 使用stream()获取流式响应
  • 通过session_id区分会话

💡 扩展建议

  • 多角色支持:扩展Prompt模板,支持不同角色
  • 历史存储:使用Redis替代内存存储
  • 截断策略:尝试"longest"、"fuse"等策略
  • 对话优化:添加主题跟踪和总结
  • 多模型:支持OpenAI、Anthropic等
  • 用户体验:增强交互效果

📚 参考资料

相关推荐
历程里程碑1 小时前
普通数组----合并区间
java·数据结构·python·算法·leetcode·职场和发展·tornado
weixin_395448911 小时前
mult_yolov5_post_copy.c_cursor_0205
c语言·python·yolo
China_Yanhy1 小时前
入职 Web3 运维日记 · 第 8 日:黑暗森林 —— 对抗 MEV 机器人的“三明治攻击”
运维·机器人·web3
执风挽^1 小时前
Python基础编程题2
开发语言·python·算法·visual studio code
纤纡.1 小时前
PyTorch 入门精讲:从框架选择到 MNIST 手写数字识别实战
人工智能·pytorch·python
kjkdd2 小时前
6.1 核心组件(Agent)
python·ai·语言模型·langchain·ai编程
小镇敲码人2 小时前
剖析CANN框架中Samples仓库:从示例到实战的AI开发指南
c++·人工智能·python·华为·acl·cann
萧鼎2 小时前
Python 包管理的“超音速”革命:全面上手 uv 工具链
开发语言·python·uv
alvin_20052 小时前
python之OpenGL应用(二)Hello Triangle
python·opengl
铁蛋AI编程实战3 小时前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python