文章目录
-
- [📄 文件信息](#📄 文件信息)
- [🎯 功能概述](#🎯 功能概述)
- [📦 前置条件](#📦 前置条件)
- [💡 核心概念](#💡 核心概念)
- [📦 依赖模块](#📦 依赖模块)
- [💻 完整代码](#💻 完整代码)
- [📊 运行效果](#📊 运行效果)
- [🔍 核心实现](#🔍 核心实现)
-
- [1. 角色Prompt设计](#1. 角色Prompt设计)
- [2. 聊天历史管理](#2. 聊天历史管理)
- [3. 带记忆功能的Chain](#3. 带记忆功能的Chain)
- [4. 命令行交互](#4. 命令行交互)
- [💡 扩展建议](#💡 扩展建议)
- [📚 参考资料](#📚 参考资料)
📄 文件信息
- 创建时间:2026-01-08
- 作者:zuozewei
- 功能:基于LangChain的角色扮演聊天机器人实现
- 技术栈:Python、LangChain、DeepSeek API
- 源代码:https://github.com/zuozewei/blog-example/tree/master/AI-LLM/LangChain
🎯 功能概述
实现角色扮演聊天机器人(孔子),支持聊天历史、上下文控制、流式响应。
📦 前置条件
环境要求
- 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等
- 用户体验:增强交互效果