15天学会AI应用开发(三)把历史对话作为提示词会怎样

AI大模型服务的用户很多,它对每个用户的印象仅存在于当前会话中,一旦用户离开当前会话重新开启新的会话,AI会把该用户当作是新用户,而非之前已经对话过的某个用户。

也就是说,AI没有持久记忆的功能,它记不住你上次问了什么,也记不住它上次回答了什么。这意味着AI没法从过往的对话中吸取经验,原本纠正了的错误还会继续犯错,原本积累了的知识重开转头就忘。

一、历史对话能作为提示词吗?

大模型的用户那么多,推理过程已经消耗许多算力了,不可能再给每个用户分配单独的存储空间以实现记忆功能。既然大模型放弃了记忆功能,开发者就得在AI应用这边增加对话记忆,以弥补大模型缺失的记忆。

具体而言,在用户每次退出会话之时,AI应用就要保存本次会话的各轮问答内容。然后下次开启新会话时,AI应用先把上次的多轮问答合并后作为初始提示词发给大模型,再接收处理用户的新问题。好让大模型知晓用户之前已经问过了哪些问题,并且上次的大模型都做了哪些回答,于是心中有数、方能投用户之所好。

二、提示词形式的历史对话例子

包含上回多轮问答内容的初始提示词举例如下:

“用户之前已经问过你多个问题了,后续推理请参考之前的问答内容。

上次用户的问题和AI的回答按照时间升序排列如下:

【用户】推荐一本关于历史的书,要内容详细、适合入门

【AI】推荐《明朝那些事儿》,通俗好读

【用户】有没有国外历史的?比如欧洲史

【AI】推荐《欧洲通史上下两千年》

【用户】太长了有没有更短的?我只想快速了解核心脉络

【AI】那看《极简欧洲史》精简版,100页搞定”

上面的初始提示词首先说明这不是普通的问题,而是上次用户与AI的问答交互内容;接着把用户与AI的对话内容一一罗列,其中用户的提问以【用户】开头,AI的回答以【AI】开头。这样大模型一开始就了解用户比较关注入门的历史读物,尤其是欧洲的历史梗概。

三、根据消息数量精简上下文

当然,历史会话中的问答内容可能很多,把所有历史对话统统发给下次的大模型,既不经济也不可取。只能摘取历史对话的局部内容,提炼之后形成下次会话的初始提示词,才是可行的做法。

历史对话的提炼方式有很多,最简单的就是拾取最新最近最靠后的几条问答内容。因为较老较远较靠前的问答过去比较久了,很可能用户已经不再关注。按照思维惯性,用户大概率更关注上次最后的几次问达,那么提取最新的会话问答就足够了。

接下来将以Python代码演示如何按照消息数量来截断早期的上下文(即问答内容)。在运行Python代码之前,请确保电脑已经按照本教程的第一篇文章安装了 Python 3.10.11 和 PyCharm 2022.2 。

下面是只保留两轮对话内容的Python代码例子:

# 上下文仓库:存放所有历史对话

context_history = []

# 限制最多保留 2 轮对话,超出自动截断

MAX_CONTEXT_ROUND = 2

# 模拟角色标记

ROLE_USER = "用户"

ROLE_AI = "AI"

# 模拟一轮对话 & 上下文管理

def chat(user_input: str) -> tuple[str, str]:

    # ① 先把当前用户问题加入上下文

    context_history.append({

        "role": ROLE_USER,

        "content": user_input

    })

    # 关键:上下文截断,超出限制就删掉最旧的

    while len(context_history) > MAX_CONTEXT_ROUND * 2:

        context_history.pop(0)  # 删除列表第一个(最早的记录)

    # ② 拼接完整上下文的提示词(发给大模型的最终内容)

    full_prompt = ""

    for msg in context_history:

        full_prompt += f"{msg['role']}:{msg['content']}\n"

    # ③ 模拟AI回答(实际项目要调用大模型接口)

    ai_reply = f"我结合上下文回答:收到你的问题【{user_input}】"

    # ④ AI回答也存入上下文,供下一轮使用

    context_history.append({

        "role": ROLE_AI,

        "content": ai_reply

    })

    return ai_reply, full_prompt

# 测试运行

if __name__ == "__main__":

    # 连续多轮提问,观察截断效果

    questions = [

        "请推荐一本小说",

        "再来一本科幻的",

        "不要太长的",

        "有没有悬疑类?"

    ]

    for idx, q in enumerate(questions, 1):

        print(f"\n===== 第{idx}轮对话 =====")

        reply, prompt = chat(q)

        print("当前拼接的完整上下文:")

        print(prompt)

        print("AI回复:", reply)

四、历史对话上下文的精简结果

运行上面的Python代码,观察到下面的输出日志:

===== 第1轮对话 =====

当前拼接的完整上下文:

用户:请推荐一本小说

AI回复: 我结合上下文回答:收到你的问题【请推荐一本小说】

===== 第2轮对话 =====

当前拼接的完整上下文:

用户:请推荐一本小说

AI:我结合上下文回答:收到你的问题【请推荐一本小说】

用户:再来一本科幻的

AI回复: 我结合上下文回答:收到你的问题【再来一本科幻的】

===== 第3轮对话 =====

当前拼接的完整上下文:

AI:我结合上下文回答:收到你的问题【请推荐一本小说】

用户:再来一本科幻的

AI:我结合上下文回答:收到你的问题【再来一本科幻的】

用户:不要太长的

AI回复: 我结合上下文回答:收到你的问题【不要太长的】

===== 第4轮对话 =====

当前拼接的完整上下文:

AI:我结合上下文回答:收到你的问题【再来一本科幻的】

用户:不要太长的

AI:我结合上下文回答:收到你的问题【不要太长的】

用户:有没有悬疑类?

AI回复: 我结合上下文回答:收到你的问题【有没有悬疑类?】

可见,在第3轮对话时,AI应用还保存着前两轮(第1轮和第2轮)的对话记录;但到了第4轮对话,AI应用只保存最近两轮(第2轮和第3轮)的对话记录,更早的第1轮对话被删掉了。

以上的Python代码纯粹演示用,不涉及任何AI库。从下一篇文章开始,本教程将逐步引入AI库以深入介绍AI应用开发。

本系列的AI应用开发文章目录为《15天学会AI应用开发全目录(零基础小白,零Token消耗)》。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容