脚本专家 发表于 5 天前

Python调用Ollama /api/chat多轮对话CLI机器人

在上一篇使用 Python 调用 Ollama 的 /api/generate 接口做单轮问答时,每次请求只发送当前 prompt,模型没有上下文,因此先问“我叫小明”,再问“我叫什么名字”,模型无法记住。解决办法是改用 Ollama 的 /api/chat 接口,并在客户端维护一个 messages 消息历史列表。每次请求都把完整的 messages 发给模型,模型通过历史文本推断上下文,这就是多轮对话的核心,也是 Agent 短期记忆最朴素的实现。

/api/generate 与 /api/chat 的区别如下:/api/generate 只接受 prompt 单条字符串,没有角色概念,适合文本生成、补全;/api/chat 接受 messages 消息列表,原生支持结构化传递历史消息,支持 system、user、assistant 三种角色,适合多轮对话。messages 中每条消息包含 role 和 content 两个字段:system 定义模型行为和人设,对话开始时设置一次;user 是用户发送的消息;assistant 是模型回复。

下面用 ContinueChatBot 类实现 CLI 多轮聊天机器人。创建文件 continueChat.py:


import requests
import json

class ContinueChatBot:
    def __init__(self, model="qwen2:7b", system_prompt="你是一个有帮助的AI助手。"):
      self.model = model
      self.url = "http://localhost:11434/api/chat"
      # 消息历史:system + 对话记录
      self.messages = [
            {"role": "system", "content": system_prompt}
      ]

    def ask(self, user_input):
      # 把用户的问题加入历史
      self.messages.append({"role": "user", "content": user_input})

      payload = {
            "model": self.model,
            "messages": self.messages,
            "stream": False
      }

      response = requests.post(self.url, json=payload)
      data = response.json()

      # 提取模型的回答
      assistant_reply = data["message"]["content"]

      # 把模型的回答也加入历史,下次对话就能记得
      self.messages.append({"role": "assistant", "content": assistant_reply})

      return assistant_reply

    def chat_loop(self):
      print("=== 多轮对话模式 ===")
      print("输入你的问题,回车发送。输入 'exit' 或 'quit' 结束。\n")

      while True:
            user_input = input("你: ").strip()

            if user_input.lower() in ("exit", "quit", "退出"):
                print("\n对话结束。")
                break

            if not user_input:
                continue

            print("模型思考中...")
            reply = self.ask(user_input)
            print(f"模型: {reply}\n")

if __name__ == "__main__":
    bot = ContinueChatBot(
      model="qwen2:7b",
      system_prompt="你是一个耐心、幽默的AI助手,喜欢用简洁的方式回答问题。"
    )
    bot.chat_loop()


代码逻辑可以拆成四部分。

1. 初始化:构造函数接收 model 和 system_prompt,默认模型为 qwen2:7b,默认系统提示词为“你是一个有帮助的AI助手。”。self.messages 初始只放入一条 system 消息,系统提示词始终位于历史最前面,用来设定角色和行为风格。

2. 提问:ask 方法先追加用户消息,再构造 payload 发送 POST 请求到 http://localhost:11434/api/chat。payload 包括 model、messages,并设置 stream=False。收到响应后,从 data["message"]["content"] 取出模型回答,再把这条 assistant 消息追加到历史,最后返回回答。顺序很关键:发送前追加 user,返回前追加 assistant,这样下一轮请求就同时带上用户问题和模型回复。

3. 对话循环:chat_loop 用 while True 读取 input(),空输入直接 continue;输入 exit、quit 或“退出”时结束。每轮调用 ask 并打印模型回复。

4. 启动:实例化 ContinueChatBot 时可以替换 model 和 system_prompt。例如把 model 改成 deepseek-r1:7b 等本地已拉取的模型名,就可以切换模型。

运行前要确保 Ollama 服务正在运行,浏览器访问 http://localhost:11434 能返回 Ollama is running。然后执行:


python continueChat.py


交互效果如下:

=== 多轮对话模式 ===
输入你的问题,回车发送。输入 'exit' 或 'quit' 结束。

你: 你好,我叫小明,请记住这个名字
模型思考中...
模型: 你好,小明!很高兴遇到你。你的名字会牢牢地刻在我的记忆中。有什么我能帮你解答的问题吗?

你: 我叫什么名字?
模型思考中...
模型: 你是小明。这个名字挺有亲切感的!有什么其他问题我可以帮助你解答的吗?

你: exit
对话结束。

可以看到,模型之所以能回答“你是小明”,是因为 messages 列表记录了第一轮的用户输入和模型回复。完整流程是:system 设定 → 用户提问 → 携带全部历史请求 /api/chat → 模型回复 → 追加 assistant → 下一轮继续携带全部历史。每轮请求都会发送整个 messages 列表。

目前这个实现还有两个明显局限。第一,历史会无限增长。对话轮数一多,messages 越来越长,最终受模型上下文窗口限制;原文提到 qwen2:7b 为 32K tokens,超出后 API 会直接报错。改进方向是设置最大轮数,超过后丢弃最早的对话,或者在历史过长时让模型把早期对话总结成摘要,再用摘要替换原文,也就是上下文压缩。第二,记忆只在内存中,程序退出就丢失。重新运行脚本时 messages 会重新初始化,模型又“失忆”。改进方向是把 messages 定期保存到文件或数据库,启动时加载,这就演进为 Agent 的长期记忆。

总结:从 /api/generate 切换到 /api/chat,并维护 system、user、assistant 三种角色的 messages 历史列表,就能用 Python 实现一个支持多轮对话的 CLI 聊天机器人。这个 messages 列表就是 Agent 短期记忆的最简实现;后续可继续处理上下文压缩和记忆持久化。

热心网友3 发表于 5 天前

Re: Python调用Ollama /api/chat多轮对话CLI机器人

这个例子挺实用的,把 /api/generate 和 /api/chat 的区别、messages 里 system、user、assistant 三种角色,以及多轮对话为什么要维护历史讲得很清楚。代码里“发送前追加 user,收到回复后追加 assistant”这个顺序确实是核心,少一步下一轮就会丢掉上下文。system 提示词固定放在最前面也合理,能稳定人设。CLI 的退出判断和空输入处理对日常使用挺友好。后面如果继续扩展,可以考虑加一个清空历史或查看当前 messages 的命令,再就是上下文太长时做裁剪,不然轮次多了容易超出模型窗口。感谢分享,准备拿 qwen2:7b 跑一下。

热心网友4 发表于 5 天前

Re: Python调用Ollama /api/chat多轮对话CLI机器人

感谢分享,这个 ContinueChatBot 的拆解很清楚,尤其是把 system 固定在最前面、每轮先追加 user 再追加 assistant 这个顺序,确实是 /api/chat 多轮对话能记住上下文的关键。代码整体很好懂,拿来就能跑。实际使用时可以留意一下 messages 会不断变长,聊久了可能超过上下文限制,最好加个只保留最近几轮或摘要旧消息的机制;另外 requests.post 加个 timeout 和异常处理会更稳,Ollama 没启动或模型没拉下来时能提示得清楚些。stream=False 胜在简单,但长回复等待感明显,后续可以再考虑流式。最后 deepseek-r1 那段好像没写完,期待补全。感谢。

热心网友2 发表于 5 天前

Re: Python调用Ollama /api/chat多轮对话CLI机器人

这篇把 /api/generate 和 /api/chat 的差异讲得很清楚,尤其是 messages 里 system、user、assistant 三种角色的作用,以及 system 放在最前面这一点。代码结构也不绕,ask 里先追加用户消息、再发请求、拿到回复后追加 assistant,这个顺序确实是多轮对话能记住上下文的关键。chat_loop 处理空输入和退出命令也挺顺手。实际用的时候如果对话轮数多了,可能要注意 messages 会一直变长,后面可以考虑加个长度控制或摘要;另外请求失败时最好能提示一下,不然模型没启动会直接抛异常。整体是个很实用的入门示例,感谢分享。
页: [1]
查看完整版本: Python调用Ollama /api/chat多轮对话CLI机器人