Ollama+Flask部署Llama3.2对话陷入初始指令问题求助
我在Flask服务器上测试基于Ollama运行的本地Llama3.2模型,已开发聊天交互界面,实现了对话历史功能,模型可依据上下文回复,但存在异常:始终受初始prompt指令束缚,无法响应"停止游戏"的指令。
异常表现示例
用户:我们来玩个游戏,我说出一些单词,你要告诉我这个单词是否代表动物,只需要回答是或不是
系统:我会用“yes”或“no”告知你单词是否代表动物,请说出第一个单词!
用户:horse
系统:It's an animal!
用户:elephant
系统:我的答案如下:1. No, "horse"是动物。2. Yes, "elephant"是动物。继续玩吧!下一个单词是什么?
用户:table
系统:我会告知每个单词是否代表动物。- horse:Yes,是动物。- elephant:Yes,是动物。- table:No,不是动物。(它是家具)
用户:bottle
系统:我们开始游戏吧。我的答案如下:1. horse - Yes,是动物。2. elephant - Yes,是动物。3. table - No,不是动物。4. bottle - No,不是动物。我答对了吗?
用户:dolphin
系统:我的答案如下:- No(它是家具)- Yes - No(它是无生命物体)- No(它是无生命物体,容器)- Yes
用户:好的,停止游戏,我们做点别的
系统:我的回复如下:* horse: yes * elephant: yes * table: no * bottle: no * dolphin: yes
直接运行Ollama时模型表现正常
-> 我们来玩个游戏,我说出一些单词,你要告诉我这个单词是否代表动物,只需要回答是或不是
我准备好了,开始吧。第一个单词是什么?
-> horse
Yes.
-> elephant
Yes.
-> table
No.
-> bottle
No.
-> dolphin
Yes.
-> 好的,停止游戏,我们做点别的
和你玩动物游戏很有趣。接下来你想做什么?想玩别的游戏、聊天还是尝试其他内容?告诉我!
当前代码
from flask import Flask, render_template, request from ollama import chat from langchain_core.messages import AIMessage from langchain_ollama import ChatOllama app = Flask(__name__) MODEL = "llama3.2" MODEL_MAX_TOKENS = 128000 messages = [] llm = ChatOllama( model=MODEL, temperature=1.1, stream=True ) @app.route('/ask_gpt', methods=['POST']) def ask_gpt(): messages.append(("user", request.form['text'])) number_of_tokens = ut.get_number_of_tokens(messages) # Context accepts a max number of tokens while(number_of_tokens >= MODEL_MAX_TOKENS): del(messages[1]) ai_msg = llm.invoke(messages) return ai_msg.content
问题分析与解决方案
核心问题
- 对话历史格式错误:LangChain的
ChatOllama需要接收BaseMessage类型(如HumanMessage、AIMessage)的列表作为上下文,而非("user", text)这种元组。格式错误会导致模型无法正确识别对话角色,进而混淆上下文逻辑。 - 未维护完整对话历史:当前代码仅将用户消息加入
messages,但未保存AI的回复。这会导致模型每次接收到的上下文是连续的用户输入,而非完整的对话流,无法正确理解后续指令(如"停止游戏")。 - Temperature参数过高:设置为
1.1超出了常规范围(通常0~1),过高的随机性会导致模型输出不稳定,偏离预期逻辑。
修正步骤
- 使用正确的消息类型:用
HumanMessage封装用户输入,AIMessage封装AI回复。 - 完善对话历史维护:获取AI回复后,将其添加到
messages列表中。 - 调整Temperature参数:改为0.7左右的合理值,平衡随机性与稳定性。
- 确保Token计算适配新格式:如果
ut.get_number_of_tokens是自定义函数,需确保它能正确处理BaseMessage类型的消息。
修改后的代码
from flask import Flask, render_template, request from langchain_core.messages import HumanMessage, AIMessage from langchain_ollama import ChatOllama app = Flask(__name__) MODEL = "llama3.2" MODEL_MAX_TOKENS = 128000 messages = [] llm = ChatOllama( model=MODEL, temperature=0.7, # 调整为合理值 stream=False # 非流式输出更适合当前场景,若需流式可保留True但需修改返回逻辑 ) @app.route('/ask_gpt', methods=['POST']) def ask_gpt(): user_input = request.form['text'] # 添加用户消息到对话历史(使用HumanMessage) messages.append(HumanMessage(content=user_input)) # 计算Token数(需确保ut.get_number_of_tokens支持BaseMessage列表) number_of_tokens = ut.get_number_of_tokens([msg.content for msg in messages]) # 裁剪上下文以控制Token数 while number_of_tokens >= MODEL_MAX_TOKENS and len(messages) > 1: # 移除最早的对话对(用户+AI) del messages[0] del messages[0] number_of_tokens = ut.get_number_of_tokens([msg.content for msg in messages]) # 调用模型生成回复 ai_msg = llm.invoke(messages) # 将AI回复添加到对话历史 messages.append(AIMessage(content=ai_msg.content)) return ai_msg.content
额外说明
- 如果需要流式输出,需修改返回逻辑为流式响应,Flask中可使用生成器配合
Response对象实现。 - 若
ut.get_number_of_tokens无法处理BaseMessage,可提取每个消息的content字段组成字符串列表再计算Token数。
内容的提问来源于stack exchange,提问作者P. Frau

