返回首页

Python Ollama LLM 聊天中的消息历史

本文描述了在 Python 中使用 Ollama 和 LiteLLM 在控制台 LLM 聊天中实现消息历史的过程。添加了带有修剪的 conversation_history,完整的消息结构。提供了带有上下文的代码和对话示例。

本地 LLM 聊天中的上下文:代码和示例
Advertisement 728x90

在本地LLM聊天中实现消息历史与上下文:Python实战指南

上一部分基于LiteLLM和Ollama的控制台聊天独立处理每个请求。模型无法查看之前的消息,这会导致对话中断:对过往回复的引用会被忽略。解决方案是在Python列表中存储消息历史,并在每次新请求时传递。

这将一系列调用转变为连贯的对话。模型接收到完整上下文:系统指令、过往的用户/助手对话对,以及当前输入。

上下文的消息结构

消息格式遵循OpenAI兼容API的标准:

Google AdInline article slot
  • system:持久性指令,单独添加
  • user:用户的查询
  • assistant:模型的回复

历史仅包含用户/助手对话对。发送时结构如下:

[
    {"role": "system", "content": SYSTEM_PROMPT},
    *conversation_history,
    {"role": "user", "content": user_message}
]

顺序至关重要:系统指令设定行为,历史提供上下文,新用户消息是当前查询。

更新后的main.py代码

包含历史记录和上下文修剪的完整脚本:

Google AdInline article slot
# -*- coding: utf-8 -*-
import time
from typing import Optional
from litellm import completion

MODEL = "ollama_chat/qwen2.5:3b"
API_BASE = "http://localhost:11434"
SYSTEM_PROMPT = "你是一个乐于助人的助手。请简洁明了地回答问题。"

MAX_HISTORY_MESSAGES = 6


def trim_history(history: list, limit: int) -> list:
    if len(history) <= limit:
        return history
    return history[-limit:]


def send_request_to_llm(user_message: str, history: list) -> Optional[str]:
    messages = [
        {"role": "system", "content": SYSTEM_PROMPT},
        *history,
        {"role": "user", "content": user_message},
    ]
    try:
        start_time = time.time()
        response = completion(
            model=MODEL,
            messages=messages,
            api_base=API_BASE,
            request_timeout=120,
        )
        duration = time.time() - start_time
        print(f"\n生成时间: {duration:.2f} 秒")
        return response.choices[0].message.content
    except Exception as e:
        print(f"\n请求错误: {e}")
        return None


def main() -> None:
    print("带记忆功能的本地AI助手已启动。")
    print("输入问题或'exit'退出。\n")

    conversation_history = []

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

        if user_input.lower() in ("exit", "quit"):
            print("再见!")
            break

        if not user_input:
            print("请输入问题。")
            continue

        print("\n模型思考中...")
        answer = send_request_to_llm(user_input, conversation_history)

        if answer is not None:
            print(f"\nAI: {answer}\n")
            conversation_history.append({"role": "user",      "content": user_input})
            conversation_history.append({"role": "assistant", "content": answer})
            conversation_history = trim_history(conversation_history, MAX_HISTORY_MESSAGES)
        else:
            print("\n获取回复失败。请检查Ollama是否正在运行。\n")


if __name__ == "__main__":
    main()

关键逻辑变更

  • conversation_history:main()中的列表存储消息对
  • send_request_to_llm:接收历史记录,通过*展开
  • 保存对话对:回复后,添加用户和助手消息
  • trim_history:修剪至MAX_HISTORY_MESSAGES(6条消息——3轮对话)

| 组件 | 更新前 | 更新后 |

|-----------|---------------|--------------|

| 消息 | 系统 + 用户 | 系统 + 历史 + 用户 |

Google AdInline article slot

| 记忆 | 无 | RAM中的列表 |

| 大小 | 无限制 | 最多6条消息 |

修剪防止上下文溢出:旧消息会增加令牌数并拖慢推理速度。

测试上下文

依赖查询的对话示例:

  • 你:列举三个Python Web开发框架
  • AI:Django、Flask、FastAPI
  • 你:详细介绍一下第二个
  • AI:Flask是一个轻量级微框架...

模型通过查看之前的回复,正确引用了“第二个”。

当前实现的局限性

  • 历史记录在RAM中:重启后丢失
  • 固定限制:6条消息(可配置)
  • 无持久化:生产环境需Redis/数据库

对于Telegram机器人或Web应用,逻辑保持不变:历史记录存储在用户会话中。

重点注意事项

  • 消息格式:系统指令单独处理,历史仅含用户/助手对话对
  • 历史修剪:[-limit:]保留最近的对话对
  • 职责分离:LLM请求在send_request_to_llm中处理,状态在main()中管理
  • 超时设置:request_timeout=120适应长上下文
  • 日志记录:生成时间用于性能调试

— Editorial Team

Advertisement 728x90

继续阅读