网站首页 > 技术文章 正文
我们将优化之前的 Flask 聊天机器人,添加记忆功能,并总结 30 天学习成果,最后提出下一步建议。
优化聊天机器人 - 添加记忆功能
为了让聊天机器人更智能,我们将改进上下文管理,添加长期记忆功能,使其能够记住用户之前的对话内容,并基于完整的对话历史生成更连贯的回答。
优化后的代码 (app.py):
python
from flask import Flask, render_template, request, jsonify
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
app = Flask(__name__)
# 全局变量存储模型和对话历史
tokenizer = None
model = None
device = None
chat_history = [] # 存储完整的对话历史
def load_qwen_model():
global tokenizer, model, device
try:
model_name = "Qwen/Qwen-1.8B-Chat"
print(f"正在加载模型 {model_name}...")
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
print("模型加载成功!")
return True
except Exception as e:
print(f"加载模型时出错: {str(e)}")
return False
def generate_response(user_input, max_length=100):
try:
# 构建完整的对话历史作为上下文
history_text = "".join([f"用户: {entry['user']}\n机器人: {entry['bot']}\n"
for entry in chat_history]) # 使用全部历史
full_input = history_text + f"用户: {user_input}\n机器人: "
# 编码输入
inputs = tokenizer(full_input, return_tensors="pt").to(device)
# 检查输入长度,避免超过模型限制
if len(inputs["input_ids"][0]) > 1024: # 假设模型最大上下文为1024 tokens
# 截取最近的部分
truncated_history = "".join([f"用户: {entry['user']}\n机器人: {entry['bot']}\n"
for entry in chat_history[-5:]]) # 保留最后5轮
full_input = truncated_history + f"用户: {user_input}\n机器人: "
inputs = tokenizer(full_input, return_tensors="pt").to(device)
# 生成回答
outputs = model.generate(
inputs["input_ids"],
max_length=max_length + len(inputs["input_ids"][0]),
num_return_sequences=1,
temperature=0.7,
top_p=0.9,
do_sample=True
)
# 解码并提取回答部分
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
bot_response = response[len(full_input):].strip()
return bot_response
except Exception as e:
return f"生成回答时出错: {str(e)}"
@app.route('/')
def index():
return render_template('index.html', chat_history=chat_history)
@app.route('/chat', methods=['POST'])
def chat():
user_input = request.form.get('user_input', '').strip()
if not user_input:
return jsonify({'error': '请输入内容!'})
# 生成回答
bot_response = generate_response(user_input)
# 更新对话历史
chat_history.append({'user': user_input, 'bot': bot_response})
return jsonify({'bot_response': bot_response, 'chat_history': chat_history})
# 添加清理历史的功能
@app.route('/clear', methods=['POST'])
def clear_history():
global chat_history
chat_history = []
return jsonify({'message': '对话历史已清除', 'chat_history': chat_history})
if __name__ == "__main__":
if load_qwen_model():
app.run(debug=True, host='0.0.0.0', port=5000)
else:
print("模型加载失败,无法启动服务")
更新后的 HTML 模板 (templates/index.html):
在之前的 HTML 基础上,添加清理历史按钮:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>千问聊天机器人</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.chat-container { max-width: 800px; margin: auto; }
.chat-history { border: 1px solid #ccc; padding: 10px; height: 400px; overflow-y: auto; }
.message { margin: 5px 0; }
.user { color: blue; }
.bot { color: green; }
.input-area { margin-top: 10px; }
.button-area { margin-top: 10px; }
</style>
</head>
<body>
<div class="chat-container">
<h2>千问聊天机器人</h2>
<div class="chat-history" id="chatHistory">
{% for entry in chat_history %}
<div class="message user">你: {{ entry.user }}</div>
<div class="message bot">机器人: {{ entry.bot }}</div>
{% endfor %}
</div>
<div class="input-area">
<textarea id="userInput" rows="3" cols="50" placeholder="输入你的问题..."></textarea><br>
<button onclick="sendMessage()">发送</button>
</div>
<div class="button-area">
<button onclick="clearHistory()">清除历史</button>
</div>
</div>
<script>
function sendMessage() {
const userInput = document.getElementById('userInput').value;
if (!userInput.trim()) {
alert('请输入内容!');
return;
}
fetch('/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'user_input=' + encodeURIComponent(userInput)
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error);
return;
}
updateChatHistory(data.chat_history);
document.getElementById('userInput').value = '';
})
.catch(error => console.error('Error:', error));
}
function clearHistory() {
fetch('/clear', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
.then(response => response.json())
.then(data => updateChatHistory(data.chat_history))
.catch(error => console.error('Error:', error));
}
function updateChatHistory(history) {
const chatHistory = document.getElementById('chatHistory');
chatHistory.innerHTML = '';
history.forEach(entry => {
chatHistory.innerHTML += `<div class="message user">你: ${entry.user}</div>`;
chatHistory.innerHTML += `<div class="message bot">机器人: ${entry.bot}</div>`;
});
chatHistory.scrollTop = chatHistory.scrollHeight;
}
document.getElementById('userInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
</script>
</body>
</html>
优化亮点:
- 记忆功能:
- 默认使用完整的对话历史作为上下文。
- 当输入超过模型最大上下文长度(假设1024 tokens)时,自动截取最近5轮对话。
- 历史清理:
- 新增 /clear 路由和“清除历史”按钮,允许用户重置对话。
- 用户体验:
- 保留了之前的实时更新和自动滚动功能。
总结 30 天学习成果
经过 30 天的学习,你从零开始逐步掌握了基于大模型的聊天机器人开发,以下是主要成果:
- 基础知识:
- 熟悉了 Python 编程基础和 transformers 库的使用。
- 理解了大模型(如千问)的加载、分词和生成逻辑。
- 项目开发:
- Day 28-29: 完成了命令行版聊天机器人,支持基本的输入输出和错误处理。
- Day 29: 升级为 Flask Web 应用,实现了网页访问和连续问答显示。
- Day 30: 添加了记忆功能和历史清理功能,提升了机器人实用性。
- 技能提升:
- 掌握了前后端交互(Flask + HTML/JavaScript)。
- 学会了处理大模型的上下文管理和优化。
下一步建议
你的学习旅程告一段落,但这只是起点!以下是下一步建议:
- 深入学习 Transformers:
- 研究注意力机制(Attention)和模型微调(Fine-tuning),尝试在特定领域(如客服、知识问答)优化千问模型。
- 阅读 Hugging Face 的官方文档或《Transformers: State-of-the-Art Natural Language Processing》一书。
- 模型部署:
- 使用 Docker 将聊天机器人打包,部署到云服务器(如 AWS、阿里云),实现公网访问。
- 探索模型量化(如使用 ONNX 或 TensorRT)以提升推理速度。
- 扩展功能:
- 添加多模态支持(如图片输入)。
- 实现用户身份管理,支持多用户独立对话历史。
运行与测试
- 确保依赖已安装:
bash
pip install flask transformers torch
- 运行 app.py,访问 http://localhost:5000。
- 测试记忆功能,例如:
- 输入:“我叫小明。”
- 再输入:“我叫什么名字?”(机器人应记住“小明”)
至此,第 30 天的学习任务完成,你的聊天机器人已具备基本智能和 Web 交互能力,30 天学习圆满收官!下一步,勇敢迈向更深入的 NLP 领域吧!
看看问答效果吧,简单模型就只能当玩具了!
猜你喜欢
- 2025-04-26 Python机器学习库Sklearn系列教程(21)-参数优化
- 2025-04-26 DeepSeek高赞回答:35岁被优化搞python,月入过万,看完后绝了
- 2025-04-26 Python 列表:从入门到高阶,避坑 + 性能优化全攻略
- 2025-04-26 Python跨平台GUI开发终极指南:3大框架×5项优化×教育行业实战案例
- 2025-04-26 通过优化代码来提高 Python 程序执行速度
- 2025-04-26 超参数黑盒(Black-box)优化的Python代码示例
- 2025-04-26 Python人工智能tensorflow优化器Optimizer算法汇总
- 2025-04-26 Python贝叶斯优化器Bayes_opt优化深度森林Deep Forest分类模型
- 2025-04-26 300分钟Python入门第26天 - 小明的天气预测优化
- 2025-04-26 Deepseek还真不错帮着优化了Python代码
- 263℃Python短文,Python中的嵌套条件语句(六)
- 263℃python笔记:for循环嵌套。end=""的作用,图形打印
- 261℃PythonNet:实现Python与.Net代码相互调用!
- 256℃Python实现字符串小写转大写并写入文件
- 255℃Python操作Sqlserver数据库(多库同时异步执行:增删改查)
- 116℃原来2025是完美的平方年,一起探索六种平方的算吧
- 96℃Python 和 JavaScript 终于联姻了!PythonMonkey 要火?
- 89℃Ollama v0.4.5-v0.4.7 更新集合:Ollama Python 库改进、新模型支持
- 最近发表
- 标签列表
-
- python中类 (31)
- python 迭代 (34)
- python 小写 (35)
- python怎么输出 (33)
- python 日志 (35)
- python语音 (31)
- python 工程师 (34)
- python3 安装 (31)
- python音乐 (31)
- 安卓 python (32)
- python 小游戏 (32)
- python 安卓 (31)
- python聚类 (34)
- python向量 (31)
- python大全 (31)
- python次方 (33)
- python桌面 (32)
- python总结 (34)
- python浏览器 (32)
- python 请求 (32)
- python 前端 (32)
- python验证码 (33)
- python 题目 (32)
- python 文件写 (33)
- python中的用法 (32)