进入Jupyter Notebook并且选择实验环境

1.安装openai库,!pip install openai(!是Jupyter的魔法命令,相当于使用终端安装)
2.#单轮对话
from openai import OpenAI
 

client = OpenAI(
        base_url = "http://localhost:11434/v1",
        api_key = "Ollama"
)

response = client.chat.completion.create(
        model = "qwen2.5:7b",
        messages = [{"role": "user", "content": "输入聊天内容"}]
)

print(response.choices[0].message.content)

参数解析:
        from openai import OpenAI  导入OpenAI的Python客户端库

  • client:创建一个客户端对象,用来发送请求。

  • base_url:指定 API 的地址。

    • http://localhost:11434 是 Ollama 默认监听的地址和端口。

    • /v1 是 OpenAI 风格 API 的版本路径,Ollama 完全兼容。

  • api_key:认证密钥。由于是本地服务,Ollama 不校验,所以填任意字符串(如 "ollama")即可。

  • client.chat.completions.create:调用聊天补全接口,让模型生成回复。

  • model:指定要使用的模型名称,必须和 Ollama 里已下载的模型一致

  • messages:对话历史,是一个列表,每个元素是一条消息。

    • role:消息的角色,可以是 "user"(用户)、"assistant"(模型)、"system"(系统指令)。

      • 角色 英文 含义 典型用法
        系统 system 设置助手的行为、身份、回答风格或提供全局指导 放在消息列表最开头,用来定义助手的“人设”或规则。
        用户 user 代表最终用户的输入,即你向模型提出的问题或指令 每条用户消息都应该对应一次用户的发言,通常是你需要模型回答的内容。
        助手 assistant 代表模型之前生成的回复,用于提供对话历史 当你手动构造多轮对话时,需要用 assistant 角色填入模型之前说过的内容,让模型知道上下文。
        工具 tool 用于模型调用外部工具(如查询天气、计算器)后的结果反馈 仅在支持工具调用的高级模型中使用,一般开发者暂时用不到。
        函数 function 旧版 API 中用于函数调用,现已被 tool 取代 基本不再使用。
    • content:具体的文本内容。

    • 注意:

      • 请求时用 messages(列表),因为你要发送多轮对话。

      • 响应时每个 choice 里只有一条 message(模型本次回复的那一条)具体可以使用print(reponse)查看response的返回值结构

  • response:API 返回的完整响应对象,包含多个字段。

  • choices:模型返回的回复候选项列表(通常只有一个)。

  • choices[0]:第一个候选项。

  • message:该候选项里的消息对象。

  • content:消息的文本内容,也就是模型给你的答案。

3.#多轮对话
response = client.chat.completions.create(
    model = "qwen2.5:7b",
    messages = [
        {"role" : "system", "content" : "你是一个幽默风趣的助手,回答时要带点玩笑,可以用表情符号,但信息要准确。"},
        {"role" : "user", "content" : "明天的天气是怎样的?(请幽默一点,加个表情)"},
        {"role" : "user", "content" : "适合穿什么衣服"}
    ]
)

print(response.choices[0].message.content)

  • system消息通常只放一条,且放在最前面,它会影响整个对话的风格和约束。

  • 不要用 assistant 角色放user的问题,否则模型会以为那是它自己说过的内容,不会当作新问题处理。

  • 模型只对最后一条 user 消息生成回复,前面的消息(包括 system、历史 user 和 assistant)都只是上下文。

4.关于长对话历史中assistant上下文的追加回答

assistant一般是用于让模型知道这是自身所发的消息,但是长对话中设置会很麻烦,所以使用多种方法处理

一、使用Python进行追加

#Python列表自动追加
#初始化信息
messages = [
    {"role": "system","content": "你是一个幽默的助手"}
]

def askAndAnswer(user_input):
    messages.append({"role": "user","content": user_input})
    response = client.chat.completions.create(
        model = "qwen2.5:7b",
        messages = messages
    )
    assistant_reply = response.choices[0].message.content 
    messages.append({"role": "assistant","content": assistant_reply})
    return assistant_reply

print(askAndAnswer("你是谁?"))
print(askAndAnswer("说个笑话"))

二、保留轮次

#保留轮次对话
MAX_HISTORY = 3

def askAndAnswer(user_input):
    global messages
    messages.append({"role": "user","content": user_input})
    response = client.chat.completions.create(
        model = "qwen2.5:7b",
        messages = messages
    )
    assistant_reply = response.choices[0].message.content
    messages.append({"role": "assistant", "content": assistant_reply})
    if len(messages) > 1 + MAX_HISTORY * 2:
        #while len(messages) > 1 + MAX_HISTORY * 2:
            #del messages[1:3]
        # 保留 system,只取最近的 MAX_HISTORY 轮对话(即最后 2*MAX_HISTORY 条)
        messages = [messages[0]] + messages[-(2*MAX_HISTORY):]
    return assistant_reply

# 确保 messages 已经定义(全局)
messages = [{"role": "system","content": "你是一个幽默的助手"}]

print(askAndAnswer("你是谁?"))
print(askAndAnswer("说个笑话"))
print(askAndAnswer("再說一個"))
print(askAndAnswer("再說一個"))
print(askAndAnswer("再說一個"))
print(messages)

三、对话摘要

把摘要作为上下文,压缩并丢弃信息细节,只保留最近轮次对话,但效果并不好,摘要会丢掉对话细节,这种以信息缺失换取长记忆的做法导致模型很多时候回答的效果并不好

#对话摘要,保留最近轮次对话
MAX_HISTORY = 3 #保留轮次
SUMMARY_THRESHOLD = 2 #摘要阈值

messages = [
    {"role":"system", "content": "你是一个话语带恶意的人"}

summary = ""

def generate_summary(conversation_messages):
    """
    使用 qwen2.5:7b 生成对话摘要
    conversation_messages: 列表,包含多个 {"role": ..., "content": ...} 消息
    """
    # 构造一个提示,让模型总结这些对话
    prompt = "请用一段话简洁总结以下对话的核心内容:\n\n"
    for msg in conversation_messages:
        role = "用户" if msg["role"] == "user" else "助手"
        prompt += f"{role}:{msg['content']}\n"
    prompt += "\n摘要:"

    # 调用模型
    response = client.chat.completions.create(
        model="qwen2.5:7b",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.3,  # 低温度让摘要更稳定
        max_tokens=200
    )
    summary = response.choices[0].message.content.strip()
    return summary
    
def askAndAnswer(user_input):
    global messages,summary
    # 1. 检查是否需要生成摘要(原始对话数量 > 阈值)
    raw_msgs = [m for m in messages if m["role"] in ("user", "assistant")]
    if len(raw_msgs) > SUMMARY_THRESHOLD * 2:
        # 生成摘要(对全部原始对话)
        summary_text = generate_summary(messages)  # 注意传入完整 messages,但内部会提取对话
        # 重建 messages:原 system + 摘要 system + 最近 MAX_HISTORY 轮原始对话
        messages = [
            messages[0],
            {"role": "system", "content": f"对话摘要:{summary_text}"}
        ] + raw_msgs[-(MAX_HISTORY*2):]

    # 2. 正常对话流程
    messages.append({"role": "user", "content": user_input})
    response = client.chat.completions.create(
        model="qwen2.5:7b",
        messages=messages
    )
    assistant_reply = response.choices[0].message.content
    messages.append({"role": "assistant", "content": assistant_reply})

    # 3. 最终截断:保证 messages 长度不超过 system + 摘要 + 最近 MAX_HISTORY 轮
    # 提取原始对话
    raw = [m for m in messages if m["role"] in ("user", "assistant")]
    if len(raw) > MAX_HISTORY * 2:
        raw = raw[-(MAX_HISTORY*2):]
    # 提取摘要(如果存在)
    summary_msg = None
    for m in messages:
        if m["role"] == "system" and m["content"].startswith("对话摘要:"):
            summary_msg = m
            break
    # 重建 messages
    base = [messages[0]]  # 原 system
    if summary_msg:
        base.append(summary_msg)
    messages = base + raw
    return assistant_reply
        
print(askAndAnswer("你是谁?"))
print(askAndAnswer("说个笑话"))
print(askAndAnswer("再說一個"))
print(askAndAnswer("你说这个笑话的来源"))
print(askAndAnswer("再說一個"))
print(askAndAnswer("你说这个笑话的来源"))
print(askAndAnswer("再說一個"))
print(askAndAnswer("你说这个笑话的来源"))
print(askAndAnswer("你记得第一个笑话吗"))
print(messages)       

四、使用RAG进行切片分段存库,向量检索方案(目前最标准,效果最好)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐