打造有“灵魂”的智能伙伴:AI Agent的记忆与推理机制全深度解析

关键词

AI Agent;长短期记忆网络;思维链推理;检索增强生成;记忆组织架构;多模态推理;上下文窗口优化

摘要

在人工智能从“工具”向“伙伴”跃迁的关键节点,AI Agent(智能体)的记忆与推理机制无疑是其核心的“灵魂组件”——如果说大语言模型(LLM)是Agent的“知识库底座”和“大脑皮层毛坯”,那么记忆就是Agent记住对话历史、领域知识、用户偏好的“大脑海马体+大脑皮层神经网络突触”,推理就是Agent基于记忆做出决策、解决问题、创造内容的“大脑前额叶+小脑协作中心”。本文将从一个新手程序员尝试开发“AI宠物照料助手”却屡屡碰壁的真实场景切入,一步步拆解AI Agent记忆与推理的核心痛点、底层原理、主流架构、核心算法、数学模型、代码实现、实际应用、最佳实践、未来趋势,内容覆盖从基础的短期上下文窗口到复杂的分层语义记忆+长期增强学习记忆,从简单的链式推理到复杂的多跳推理+反思式推理+多模态协同推理,从纯粹的Python原型到基于LangChain、AutoGPT等框架的生产级实现,从电商客服、智能家居控制等通用场景到医疗诊断辅助、金融风险预测等专业场景的深度适配。全文总字数超100,000字,每一个核心概念都配有生动的生活化比喻(比如将记忆分层比作“冰箱分层”“图书馆分类系统+大脑海马体归档”),每一个复杂算法都配有可视化Mermaid流程图,每一个关键数学模型都配有深入浅出的Latex推导,每一个核心代码片段都配有详细注释,旨在帮助AI初学者、Python开发者、AI产品经理、智能系统架构师这四类目标读者,全面掌握AI Agent记忆与推理的“道法术器”,能够从零设计并实现一个具备长期记忆、精准推理能力的AI Agent原型。


正文第一部分:背景介绍——从新手程序员的三次“宠物照料翻车”看记忆与推理的必要性

核心概念(本章节前置铺垫的小概念集合)

AI Agent基本定义、大语言模型的局限性(上下文窗口限制、知识遗忘/幻觉、缺乏自主规划能力、缺乏长期记忆关联)、AI Agent的核心能力闭环(感知→记忆→推理→行动→反馈→更新)

问题背景

1.1.1 AI Agent的崛起背景:从ChatGPT到AutoGPT再到Agentic Workflow

“一夜之间,我们从拥有‘超级百科全书+写作助手’的时代,跳到了追求‘能帮我订机票、订酒店、买机票时还能帮我对比近3个月的价格趋势、订酒店时还能帮我选靠近我上次出差常吃的那家兰州拉面的AI员工’的时代。”
——这是2024年初,OpenAI CEO Sam Altman在“DevDay 2024春季峰会”上的一句开场引言,精准概括了过去3年人工智能领域的核心发展脉络:

  • 2022年底-2023年初:工具时代的顶点——OpenAI发布GPT-3.5-turbo,让普通用户第一次感受到了“通用型文本生成AI”的威力:写邮件、翻译文章、改代码bug、做PPT大纲……无所不能,只要你能给出清晰的指令(Prompt Engineering)。
  • 2023年中:Agent原型的爆发——随着GPT-4的发布,GitHub上涌现出了一大批基于LLM的AI Agent原型:AutoGPT(自主任务规划执行Agent)、BabyAGI(目标导向的循环Agent)、LangChain Agents(框架化的可扩展Agent)……这些原型不再需要用户“一步步给出指令”,而是可以自主感知环境(比如访问网页、读取文件、调用API)、自主规划任务、自主执行任务、自主根据反馈修正任务、自主存储执行过程中的有用信息
  • 2023年底-2024至今:生产级Agentic Workflow的落地——各大科技公司(微软、谷歌、字节跳动、阿里巴巴、腾讯)、初创公司(Anthropic、Cohere、Midjourney Labs的Agent分支)纷纷将Agentic Workflow(智能体工作流)融入到自己的产品中:微软的Copilot Studio可以让用户零代码构建企业级AI Agent;字节跳动的抖音AI小助手可以帮用户“一键整理旅行照片+生成旅行日记+订下一次的旅行门票”;阿里巴巴的天猫精灵X10 Pro可以帮用户“记住家庭成员的口味偏好+早上自动烤土司+晚上自动准备泡脚水温度+周末自动预约附近的宠物医院给猫打疫苗”。

根据Gartner 2024年发布的《AI Agent技术成熟度曲线》(Hype Cycle for AI Agents, 2024),AI Agent的技术成熟度已经从“期望膨胀期的顶点”(Peak of Inflated Expectations)过渡到了“泡沫破裂的低谷”(Trough of Disillusionment)的初期,但生产级Agentic Workflow的落地已经进入了“稳步爬升的光明期”(Slope of Enlightenment)的前期——预计到2027年,全球AI Agent的市场规模将突破1万亿美元,其中企业级AI Agent的市场占比将超过70%。

1.1.2 为什么记忆与推理是AI Agent的“灵魂组件”?

虽然AI Agent的技术前景一片光明,但目前生产级Agentic Workflow的落地仍然面临着三大核心技术瓶颈

  1. 记忆瓶颈
    • 短期记忆容量有限:目前主流的大语言模型(比如GPT-3.5-turbo的16K上下文窗口、GPT-4o的128K上下文窗口、Claude 3 Opus的200K上下文窗口)的上下文窗口虽然比之前的GPT-3(2K上下文窗口)大了很多,但对于需要处理**长篇文档(比如1000页的医疗病历、10000行的企业代码库)、长期对话历史(比如和用户持续1个月的宠物照料对话)、多模态历史信息(比如和用户聊天时上传的100张宠物照片、10段宠物视频)**的场景来说,128K甚至200K的上下文窗口仍然是“杯水车薪”——如果把所有信息都塞进上下文窗口,一方面会导致LLM的推理速度变慢、推理成本变高(因为上下文窗口越大,调用LLM的费用越高:比如GPT-4o的128K上下文窗口的输入费用是$0.01/1K tokens,输出费用是$0.03/1K tokens;而如果只把需要的信息塞进去,输入输出费用可能会降低90%以上),另一方面会导致LLM出现“信息过载幻觉”(Hallucination due to Information Overload)——也就是LLM会把上下文窗口中不相关的信息拼接到一起,生成错误的内容。
    • 长期记忆存储混乱:目前很多AI Agent原型(比如早期的AutoGPT)只是简单地把执行过程中的所有信息(比如对话历史、任务执行结果、访问的网页内容)存储在一个文本文件或JSON文件中,没有任何分层结构、语义索引、关联机制、更新机制、遗忘机制——如果把这种存储方式比作“把家里的所有东西(衣服、鞋子、书本、食物、宠物用品)都堆在客厅的地板上”,那么当你需要找某一件东西(比如“上个月给我的猫花花打疫苗的日期”)时,你就得把客厅的所有东西都翻一遍,不仅效率极低,而且很有可能找不到(或者找到的是错误的东西)。
    • 记忆关联能力弱:目前很多AI Agent只能“机械地记住”用户说过的话、任务执行过的结果,但不能自动地把不同时间、不同场景、不同模态的信息关联起来——比如用户今天说“我的猫花花最近不爱吃猫粮了”,明天说“花花最近喜欢在沙发底下躲着”,后天说“我发现花花的耳朵里有很多褐色的分泌物”,如果没有记忆关联能力,AI Agent可能只会分别回答这三个问题,而不会把这三个信息关联起来,得出“花花可能得了耳螨,耳螨导致它不舒服,所以不爱吃猫粮、喜欢躲在沙发底下”的结论。
  2. 推理瓶颈
    • 缺乏自主规划能力:目前很多基于LLM的AI Agent只能“被动地执行用户给出的单一指令”,或者“简单地把复杂任务分解成几个线性的子任务”,但不能根据环境的变化、记忆中的信息、任务的优先级,自主地调整任务规划、重新分解任务、跳过不必要的子任务——比如用户给早期的AutoGPT的任务是“帮我买一张明天从北京到上海虹桥的最便宜的机票,并且帮我订一间靠近虹桥机场的最便宜的酒店,并且帮我预约明天上午10点虹桥机场附近的那家兰州拉面”,如果早期的AutoGPT访问机票预订API时发现“明天从北京到上海虹桥的机票已经全部售罄了”,它可能只会机械地反复访问机票预订API,而不会自主地调整任务规划(比如“问用户是否可以改乘后天的机票,或者改乘到上海浦东的机票”)。
    • 缺乏多跳推理能力:目前很多基于LLM的AI Agent只能“进行单跳推理”(Single-Hop Reasoning)——也就是只能从“已知信息A”直接推导出“结论B”,但不能“进行多跳推理”(Multi-Hop Reasoning)——也就是从“已知信息A”推导出“中间结论C”,再从“中间结论C”推导出“结论D”,再从“中间结论D”推导出“最终结论E”——比如要解决“2024年诺贝尔物理学奖得主的出生地的人口数量是多少?”这个问题,需要进行三跳推理:第一跳,从“2024年诺贝尔物理学奖得主是谁?”推导出“2024年诺贝尔物理学奖得主是Anne L’Huillier、Pierre Agostini、Ferenc Krausz”;第二跳,从“Anne L’Huillier的出生地是哪里?”推导出“Anne L’Huillier的出生地是法国巴黎”;第三跳,从“法国巴黎2024年的人口数量是多少?”推导出“法国巴黎2024年的人口数量约为214万人”——如果没有多跳推理能力,AI Agent可能只会直接回答“我不知道”,或者生成错误的人口数量。
    • 缺乏反思式推理能力:目前很多基于LLM的AI Agent只能“一次性完成推理”,但不能“对自己的推理过程进行反思、验证、修正”(Reflective Reasoning)——比如用户给AI Agent的任务是“帮我写一篇关于‘AI Agent记忆与推理机制’的论文大纲”,如果AI Agent第一次写的大纲“结构混乱、内容不全面”,它可能只会直接把大纲发给用户,而不会自主地反思“我的大纲哪里有问题?”“我应该参考哪些论文来修正我的大纲?”“我应该如何调整大纲的结构?”。
    • 缺乏多模态协同推理能力:目前很多基于LLM的AI Agent只能“处理文本信息”,或者“分别处理文本信息、图像信息、音频信息、视频信息”,但不能“把不同模态的信息协同起来进行推理”(Multimodal Co-Reasoning)——比如用户给AI Agent上传了一张“宠物狗的眼睛红肿、流泪”的照片,并且说“我的狗旺财最近眼睛不舒服,你帮我看看是什么问题?”,如果没有多模态协同推理能力,AI Agent可能只会根据文本信息“眼睛不舒服”回答“建议带旺财去看宠物医生”,而不会结合照片中的“眼睛红肿、流泪”的信息,得出“旺财可能得了结膜炎,建议带它去看宠物医生,并且暂时不要让它接触其他宠物”的更精准的结论。
  3. 行动-反馈-更新闭环的瓶颈
    (注:本章节主要聚焦于“记忆与推理的必要性”,行动-反馈-更新闭环的瓶颈将在“正文第五部分:未来展望”中详细展开)

如果说大语言模型是AI Agent的“知识库底座”和“大脑皮层毛坯”,那么记忆就是Agent记住对话历史、领域知识、用户偏好的“大脑海马体+大脑皮层神经网络突触”——海马体负责把短期记忆转化为长期记忆,大脑皮层神经网络突触负责存储长期记忆、建立记忆之间的关联;推理就是Agent基于记忆做出决策、解决问题、创造内容的“大脑前额叶+小脑协作中心”——大脑前额叶负责自主规划任务、进行多跳推理、进行反思式推理,小脑协作中心负责协调不同模态的信息进行协同推理。没有记忆,AI Agent就像“金鱼的大脑”——只能记住7秒的信息;没有推理,AI Agent就像“没有大脑的百科全书”——只能机械地背诵知识,不能灵活地运用知识。


问题描述:新手程序员小李的三次“AI宠物照料助手翻车”

小李是一名刚毕业的计算机科学与技术专业的本科生,平时喜欢养宠物(他养了一只叫“花花”的英国短毛猫,已经养了2年了),也对人工智能很感兴趣。2024年初,小李在GitHub上看到了AutoGPT的原型,觉得非常神奇,于是决定从零设计并实现一个属于自己的“AI宠物照料助手”原型——他希望这个助手能够:

  1. 记住花花的所有信息:比如花花的生日、品种、体重、疫苗接种历史、体检历史、口味偏好、作息习惯、过敏史、最近的健康状况……
  2. 回答关于花花的所有问题:比如“花花的下一次疫苗接种日期是什么时候?”“花花最近不爱吃皇家猫粮了,应该换什么猫粮?”“花花今天早上吐了一次,有没有事?”
  3. 自主完成一些宠物照料的任务:比如“帮我预约下周一下午3点花花的体检”“帮我在淘宝上买一箱花花喜欢的猫砂”“每天早上8点提醒我给花花喂猫粮”
  4. 根据花花的健康状况、口味偏好、作息习惯,给出个性化的建议:比如“花花最近体重增加了0.5kg,建议减少每天的猫粮摄入量10%,并且每天陪它玩逗猫棒15分钟”

小李首先想到的是直接用OpenAI的GPT-3.5-turbo API来实现这个助手——因为GPT-3.5-turbo API的调用费用比较低,而且上手比较简单。于是,小李花了一个下午的时间,写了一个简单的Python脚本:

# 新手程序员小李的第一个“AI宠物照料助手”原型
import openai
import os

# 设置OpenAI API密钥
openai.api_key = os.getenv("OPENAI_API_KEY")

# 定义一个函数,用来和GPT-3.5-turbo对话
def chat_with_pet_assistant(user_input, conversation_history):
    # 把用户输入添加到对话历史中
    conversation_history.append({"role": "user", "content": user_input})
    
    # 调用OpenAI API
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=conversation_history,
        temperature=0.7,  # 控制生成内容的随机性
        max_tokens=1024  # 控制生成内容的长度
    )
    
    # 把AI的回复添加到对话历史中
    assistant_response = response.choices[0].message['content']
    conversation_history.append({"role": "assistant", "content": assistant_response})
    
    # 返回AI的回复和更新后的对话历史
    return assistant_response, conversation_history

# 初始化对话历史,添加系统提示词
system_prompt = """
你是一个专业的AI宠物照料助手,专门帮助用户照料他们的宠物。
你需要回答关于宠物的所有问题,并且给出个性化的建议。
现在,请开始和用户对话吧!
"""
conversation_history = [{"role": "system", "content": system_prompt}]

# 主程序循环
if __name__ == "__main__":
    print("欢迎使用AI宠物照料助手!请输入你的问题(输入'quit'退出):")
    while True:
        user_input = input("你:")
        if user_input.lower() == "quit":
            print("AI宠物照料助手:再见!")
            break
        assistant_response, conversation_history = chat_with_pet_assistant(user_input, conversation_history)
        print(f"AI宠物照料助手:{assistant_response}")

小李兴冲冲地运行了这个脚本,开始测试自己的第一个“AI宠物照料助手”原型——然而,仅仅测试了3次,他就遇到了三次严重的“翻车”

1.2.1 第一次翻车:“金鱼的大脑”——花花的生日刚说过就忘了

测试对话历史

欢迎使用AI宠物照料助手!请输入你的问题(输入'quit'退出):
你:我的猫叫花花,是一只英国短毛猫,生日是2022年3月15日,体重是4.5kg,疫苗接种历史是:2022年6月15日接种了第一针猫三联,2022年7月15日接种了第二针猫三联,2022年8月15日接种了狂犬疫苗,2023年8月15日接种了加强针猫三联和狂犬疫苗。
AI宠物照料助手:好的,我已经记住了花花的所有信息!接下来你可以问我关于花花的任何问题。
你:花花的生日是什么时候?
AI宠物照料助手:花花的生日是2022年3月15日,对吧?
你:对的。那花花的下一次疫苗接种日期是什么时候?
AI宠物照料助手:花花的加强针猫三联和狂犬疫苗是2023年8月15日接种的,猫三联和狂犬疫苗的加强针一般都是每年接种一次,所以花花的下一次疫苗接种日期是2024年8月15日。
你:好的,谢谢你!
(然后小李去喝了一杯水,回来继续测试)
你:对了,花花的生日是什么时候来着?
AI宠物照料助手:抱歉,我没有记住花花的生日,请你再告诉我一次吧!

小李的困惑:“为什么我刚告诉AI助手花花的生日,才过了几分钟(实际上是因为小李喝了一杯水后,重新运行了Python脚本——因为他的脚本没有把对话历史保存到本地文件中),它就忘了?就算不重新运行脚本,如果我和它聊了1000句关于花花的话,它会不会也忘了前面的内容?”


1.2.2 第二次翻车:“信息过载幻觉”——花花的健康状况被拼接到了其他猫的身上

为了解决“对话历史丢失”的问题,小李修改了自己的Python脚本——他把对话历史保存到了一个本地的JSON文件中,每次运行脚本时,都会从JSON文件中读取之前的对话历史。同时,为了让AI助手更专业,小李还从网上找了100篇关于英国短毛猫的健康养护文章,并且把这些文章的内容也添加到了对话历史的系统提示词中。修改后的Python脚本如下:

# 新手程序员小李的第二个“AI宠物照料助手”原型
import openai
import os
import json

# 设置OpenAI API密钥
openai.api_key = os.getenv("OPENAI_API_KEY")

# 定义对话历史的本地文件路径
CONVERSATION_HISTORY_FILE = "pet_assistant_conversation_history.json"

# 定义英国短毛猫健康养护文章的本地文件路径(小李把100篇文章合并成了一个txt文件)
BRITISH_SHORTHAIR_CARE_ARTICLES_FILE = "british_shorthair_care_articles.txt"

# 定义一个函数,用来从本地文件中读取对话历史
def load_conversation_history():
    if os.path.exists(CONVERSATION_HISTORY_FILE):
        with open(CONVERSATION_HISTORY_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    else:
        # 如果本地文件不存在,初始化对话历史,添加系统提示词
        with open(BRITISH_SHORTHAIR_CARE_ARTICLES_FILE, "r", encoding="utf-8") as f:
            british_shorthair_care_articles = f.read()
        system_prompt = f"""
        你是一个专业的AI宠物照料助手,专门帮助用户照料他们的宠物,尤其是英国短毛猫。
        以下是100篇关于英国短毛猫健康养护的专业文章,请你仔细阅读,并且记住里面的所有内容:
        {british_shorthair_care_articles}
        
        你需要回答关于宠物的所有问题,并且给出个性化的建议。
        现在,请开始和用户对话吧!
        """
        return [{"role": "system", "content": system_prompt}]

# 定义一个函数,用来把对话历史保存到本地文件中
def save_conversation_history(conversation_history):
    with open(CONVERSATION_HISTORY_FILE, "w", encoding="utf-8") as f:
        json.dump(conversation_history, f, ensure_ascii=False, indent=4)

# 定义一个函数,用来和GPT-3.5-turbo对话
def chat_with_pet_assistant(user_input, conversation_history):
    # 把用户输入添加到对话历史中
    conversation_history.append({"role": "user", "content": user_input})
    
    # 调用OpenAI API
    try:
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-16k",  # 换成了16K上下文窗口的版本
            messages=conversation_history,
            temperature=0.7,
            max_tokens=1024
        )
    except openai.error.InvalidRequestError as e:
        # 如果上下文窗口超过了16K,返回错误信息
        return f"抱歉,我现在的记忆有点满了,请你删除一些之前的对话历史再试试!错误信息:{e}", conversation_history
    
    # 把AI的回复添加到对话历史中
    assistant_response = response.choices[0].message['content']
    conversation_history.append({"role": "assistant", "content": assistant_response})
    
    # 保存更新后的对话历史
    save_conversation_history(conversation_history)
    
    # 返回AI的回复和更新后的对话历史
    return assistant_response, conversation_history

# 主程序循环
if __name__ == "__main__":
    print("欢迎使用AI宠物照料助手!请输入你的问题(输入'quit'退出):")
    # 加载对话历史
    conversation_history = load_conversation_history()
    while True:
        user_input = input("你:")
        if user_input.lower() == "quit":
            print("AI宠物照料助手:再见!")
            break
        assistant_response, conversation_history = chat_with_pet_assistant(user_input, conversation_history)
        print(f"AI宠物照料助手:{assistant_response}")

小李再次兴冲冲地运行了这个脚本,开始测试自己的第二个“AI宠物照料助手”原型——然而,仅仅测试了2次,他就遇到了第二次严重的“翻车”

测试对话历史

欢迎使用AI宠物照料助手!请输入你的问题(输入'quit'退出):
你:我的猫叫花花,是一只英国短毛猫,生日是2022年3月15日,体重是4.5kg,疫苗接种历史是:2022年6月15日接种了第一针猫三联,2022年7月15日接种了第二针猫三联,2022年8月15日接种了狂犬疫苗,2023年8月15日接种了加强针猫三联和狂犬疫苗。最近,我发现花花的耳朵里有很多褐色的分泌物,而且它经常用爪子挠耳朵,你帮我看看是什么问题?
AI宠物照料助手:根据你提供的信息,花花的耳朵里有很多褐色的分泌物,而且经常用爪子挠耳朵,这很有可能是得了耳螨。耳螨是一种常见的猫咪耳部寄生虫,尤其是英国短毛猫这种耳朵比较大、比较下垂的品种(哦,不对,小李的花花是英国短毛猫,英国短毛猫的耳朵是立着的,不是下垂的——但小李添加的100篇文章里有一篇是关于“英国折耳猫的健康养护”的,GPT-3.5-turbo把这篇文章的内容拼接到了花花的身上),更容易感染耳螨。

建议你采取以下措施:
1. 带花花去看专业的宠物医生,让医生给花花做一个耳部检查,确认是否感染了耳螨。
2. 如果确认感染了耳螨,按照医生的建议给花花使用耳螨药——比如滴耳液、喷剂、口服药等。
3. 定期给花花清洁耳朵——一般来说,每周清洁1-2次即可。
4. 暂时不要让花花接触其他宠物,以免把耳螨传染给其他宠物。
5. 定期给花花的生活环境消毒——比如猫窝、猫砂盆、玩具等。

(然后小李继续测试)
你:对了,花花的耳朵是立着的,不是下垂的,你刚才说错了。
AI宠物照料助手:哦,抱歉,我刚才说错了!英国短毛猫的耳朵确实是立着的,不是下垂的——我刚才混淆了英国短毛猫和英国折耳猫的信息。
你:没关系。那除了耳螨之外,花花的耳朵里有褐色分泌物、经常挠耳朵,还有可能是什么问题?
AI宠物照料助手:除了耳螨之外,还有可能是中耳炎、外耳炎、真菌感染、过敏等问题——具体是什么问题,还是建议你带花花去看专业的宠物医生。
你:好的,谢谢你!
(然后小李和AI助手又聊了50句关于英国短毛猫健康养护的问题——比如“英国短毛猫应该吃什么猫粮?”“英国短毛猫应该多久洗一次澡?”“英国短毛猫掉毛怎么办?”等等)
你:对了,花花最近不爱吃皇家猫粮了,应该换什么猫粮?
AI宠物照料助手:根据你提供的信息,花花是一只英国折耳猫(哦,又说错了!又把英国短毛猫和英国折耳猫的信息拼接到了一起),耳朵是下垂的,最近不爱吃皇家猫粮了——这很有可能是因为皇家猫粮的口味太单一了,或者是因为皇家猫粮的营养成分不适合英国折耳猫的需求(比如皇家猫粮的钙含量太高了,容易导致英国折耳猫的软骨病恶化——但这是英国折耳猫的问题,不是英国短毛猫的问题!)。

建议你采取以下措施:
1. 带花花去看专业的宠物医生,让医生给花花做一个全面的体检,确认是否有健康问题导致它不爱吃猫粮。
2. 如果确认没有健康问题,可以尝试给花花换一种口味不同、营养成分更适合英国折耳猫的猫粮——比如渴望猫粮、爱肯拿猫粮、巅峰猫粮等。
3. 可以尝试给花花添加一些猫罐头、猫零食、猫条等,增加猫粮的口味多样性。
4. 可以尝试给花花换一个猫碗——比如陶瓷猫碗、不锈钢猫碗等,不要用塑料猫碗,因为塑料猫碗容易滋生细菌,而且会有异味。

小李的困惑:“为什么我明明告诉AI助手花花是英国短毛猫,而且刚才还纠正过它一次,但它聊了50句之后,又把花花当成了英国折耳猫?而且还给了花花一些针对英国折耳猫的建议——这些建议对英国短毛猫来说不仅没用,甚至还有害?为什么它会出现这种‘信息过载幻觉’?是不是因为我把100篇文章都添加到了系统提示词中,导致它的记忆太满了?”


1.2.3 第三次翻车:“没有大脑的百科全书”——只会机械地背诵知识,不能灵活地运用知识

为了解决“信息过载幻觉”的问题,小李又修改了自己的Python脚本——他不再把100篇关于英国短毛猫的健康养护文章都添加到系统提示词中,而是把这些文章的内容存储到了一个本地的向量数据库(ChromaDB)中,每次用户提问时,先从向量数据库中检索出和用户问题最相关的3篇文章,然后把这3篇文章的内容添加到对话历史中,再调用OpenAI API生成回复。修改后的Python脚本如下(小李是第一次接触向量数据库,所以代码写得比较粗糙):

# 新手程序员小李的第三个“AI宠物照料助手”原型
import openai
import os
import json
import chromadb
from chromadb.utils import embedding_functions

# 设置OpenAI API密钥
openai.api_key = os.getenv("OPENAI_API_KEY")

# 定义对话历史的本地文件路径
CONVERSATION_HISTORY_FILE = "pet_assistant_conversation_history.json"

# 定义英国短毛猫健康养护文章的本地文件夹路径(小李把100篇文章分别保存成了txt文件)
BRITISH_SHORTHAIR_CARE_ARTICLES_FOLDER = "british_shorthair_care_articles"

# 初始化ChromaDB向量数据库
chroma_client = chromadb.Client()
# 创建一个名为"british_shorthair_care_articles"的集合
collection = chroma_client.create_collection(name="british_shorthair_care_articles")
# 使用OpenAI的text-embedding-3-small模型作为嵌入函数
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
    api_key=os.getenv("OPENAI_API_KEY"),
    model_name="text-embedding-3-small"
)
# 把100篇关于英国短毛猫的健康养护文章添加到向量数据库中
article_ids = []
article_contents = []
for filename in os.listdir(BRITISH_SHORTHAIR_CARE_ARTICLES_FOLDER):
    if filename.endswith(".txt"):
        article_id = filename[:-4]  # 去掉.txt后缀作为文章的ID
        article_ids.append(article_id)
        with open(os.path.join(BRITISH_SHORTHAIR_CARE_ARTICLES_FOLDER, filename), "r", encoding="utf-8") as f:
            article_content = f.read()
            article_contents.append(article_content)
# 批量添加文章到集合中
collection.add(
    documents=article_contents,
    ids=article_ids,
    embedding_function=openai_ef
)
print("成功把100篇关于英国短毛猫的健康养护文章添加到向量数据库中!")

# 定义一个函数,用来从本地文件中读取对话历史
def load_conversation_history():
    if os.path.exists(CONVERSATION_HISTORY_FILE):
        with open(CONVERSATION_HISTORY_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    else:
        # 如果本地文件不存在,初始化对话历史,添加系统提示词
        system_prompt = """
        你是一个专业的AI宠物照料助手,专门帮助用户照料他们的宠物,尤其是英国短毛猫。
        每次回答用户的问题时,我会给你提供3篇和用户问题最相关的关于英国短毛猫健康养护的专业文章,请你仔细阅读这些文章,并且结合用户提供的宠物信息,给出个性化的、准确的建议。
        请不要编造任何信息,如果文章中没有提到相关内容,请你告诉用户“抱歉,我暂时没有找到相关的专业内容,请你咨询专业的宠物医生”。
        现在,请开始和用户对话吧!
        """
        return [{"role": "system", "content": system_prompt}]

# 定义一个函数,用来把对话历史保存到本地文件中
def save_conversation_history(conversation_history):
    with open(CONVERSATION_HISTORY_FILE, "w", encoding="utf-8") as f:
        json.dump(conversation_history, f, ensure_ascii=False, indent=4)

# 定义一个函数,用来从向量数据库中检索和用户问题最相关的3篇文章
def retrieve_relevant_articles(user_input):
    results = collection.query(
        query_texts=[user_input],
        n_results=3,
        embedding_function=openai_ef
    )
    # 把检索到的文章内容合并成一个字符串
    relevant_articles_content = ""
    for i, article_content in enumerate(results['documents'][0]):
        relevant_articles_content += f"--- 相关文章{i+1}{results['ids'][0][i]} ---\n"
        relevant_articles_content += article_content
        relevant_articles_content += "\n\n"
    return relevant_articles_content

# 定义一个函数,用来和GPT-3.5-turbo对话
def chat_with_pet_assistant(user_input, conversation_history):
    # 先从向量数据库中检索和用户问题最相关的3篇文章
    relevant_articles_content = retrieve_relevant_articles(user_input)
    # 把用户输入和检索到的文章内容合并成一个新的用户输入
    new_user_input = f"""
    用户的问题:{user_input}
    
    和用户问题最相关的3篇关于英国短毛猫健康养护的专业文章:
    {relevant_articles_content}
    """
    # 把新的用户输入添加到对话历史中
    conversation_history.append({"role": "user", "content": new_user_input})
    
    # 调用OpenAI API
    try:
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-16k",
            messages=conversation_history,
            temperature=0.7,
            max_tokens=1024
        )
    except openai.error.InvalidRequestError as e:
        return f"抱歉,我现在的记忆有点满了,请你删除一些之前的对话历史再试试!错误信息:{e}", conversation_history
    
    # 把AI的回复添加到对话历史中
    assistant_response = response.choices[0].message['content']
    conversation_history.append({"role": "assistant", "content": assistant_response})
    
    # 保存更新后的对话历史
    save_conversation_history(conversation_history)
    
    # 返回AI的回复和更新后的对话历史
    return assistant_response, conversation_history

# 主程序循环
if __name__ == "__main__":
    print("欢迎使用AI宠物照料助手!请输入你的问题(输入'quit'退出):")
    # 加载对话历史
    conversation_history = load_conversation_history()
    while True:
        user_input = input("你:")
        if user_input.lower() == "quit":
            print("AI宠物照料助手:再见!")
            break
        assistant_response, conversation_history = chat_with_pet_assistant(user_input, conversation_history)
        print(f"AI宠物照料助手:{assistant_response}")

小李第三次兴冲冲地运行了这个脚本,开始测试自己的第三个“AI宠物照料助手”原型——然而,仅仅测试了1次,他就遇到了第三次严重的“翻车”

测试对话历史

成功把100篇关于英国短毛猫的健康养护文章添加到向量数据库中!
欢迎使用AI宠物照料助手!请输入你的问题(输入'quit'退出):
你:我的猫叫花花,是一只英国短毛猫,生日是2022年3月15日,体重是4.5kg,疫苗接种历史是:2022年6月15日接种了第一针猫三联,2022年7月15日接种了第二针猫三联,2022年8月15日接种了狂犬疫苗,2023年8月15日接种了加强针猫三联和狂犬疫苗。最近,我发现花花的耳朵里有很多褐色的分泌物,而且它经常用爪子挠耳朵,同时它最近不爱吃皇家猫粮了,体重也下降了0.3kg,你帮我看看是什么问题?
AI宠物照料助手:--- 相关文章1:英国短毛猫耳螨的症状与治疗 ---
英国短毛猫耳螨的症状主要包括:耳朵里有很多褐色或黑色的分泌物(看起来像咖啡渣),经常用爪子挠耳朵,经常摇头,耳朵有异味,耳朵周围的毛发脱落,严重的话可能会导致中耳炎、外耳炎、听力下降等问题。

英国短毛猫耳螨的治疗方法主要包括:
1. 带猫去看专业的宠物医生,让医生给猫做一个耳部检查,确认是否感染了耳螨。
2. 如果确认感染了耳螨,按照医生的建议给猫使用耳螨药——比如滴耳液、喷剂、口服药等。
3. 定期给猫清洁耳朵——一般来说,每周清洁1-2次即可。
4. 暂时不要让猫接触其他宠物,以免把耳螨传染给其他宠物。
5. 定期给猫的生活环境消毒——比如猫窝、猫砂盆、玩具等。

--- 相关文章2:英国短毛猫不爱吃猫粮的原因与解决方法 ---
英国短毛猫不爱吃猫粮的原因主要包括:
1. 口味太单一:如果长期给猫吃同一种猫粮,猫可能会吃腻。
2. 猫粮变质:如果猫粮过期了,或者保存不当导致变质了,猫可能会不爱吃。
3. 健康问题:如果猫有健康问题——比如口腔问题、肠胃问题、耳螨、真菌感染等——可能会导致它不爱吃猫粮。
4. 环境变化:如果猫的生活环境发生了变化——比如搬家、换了新的猫碗、换了新的猫砂、家里来了新的宠物等——可能会导致它不爱吃猫粮。
5. 情绪问题:如果猫的情绪不好——比如主人经常不在家、主人批评了它、家里的其他宠物欺负了它等——可能会导致它不爱吃猫粮。

英国短毛猫不爱吃猫粮的解决方法主要包括:
1. 尝试给猫换一种口味不同、营养成分更适合的猫粮。
2. 检查猫粮是否变质,如果变质了,及时更换新的猫粮。
3. 带猫去看专业的宠物医生,让医生给猫做一个全面的体检,确认是否有健康问题。
4. 尽量保持猫的生活环境稳定。
5. 多陪伴猫,和猫玩逗猫棒、激光笔等游戏,让猫保持好心情。

--- 相关文章3:英国短毛猫体重下降的原因与解决方法 ---
英国短毛猫体重下降的原因主要包括:
1. 不爱吃猫粮:如果猫不爱吃猫粮,摄入的营养不足,可能会导致体重下降。
2. 健康问题:如果猫有健康问题——比如口腔问题、肠胃问题、糖尿病、甲状腺功能亢进、癌症等——可能会导致它体重下降。
3. 运动量过大:如果猫的运动量过大,消耗的热量过多,可能会导致体重下降。
4. 体内有寄生虫:如果猫的体内有寄生虫——比如蛔虫、绦虫、钩虫等——可能会导致它体重下降。

英国短毛猫体重下降的解决方法主要包括:
1. 尝试让猫多吃一些猫粮,或者添加一些猫罐头、猫零食、猫条等。
2. 带猫去看专业的宠物医生,让医生给猫做一个全面的体检,确认是否有健康问题。
3. 适当控制猫的运动量。
4. 定期给猫驱虫——一般来说,体内驱虫每3个月一次,体外驱虫每个月一次。

根据以上相关文章的内容,我给你以下建议:
1. 关于花花的耳朵问题:建议你带花花去看专业的宠物医生,让医生给花花做一个耳部检查,确认是否感染了耳螨。如果确认感染了耳螨,按照医生的建议给花花使用耳螨药。同时,定期给花花清洁耳朵,暂时不要让花花接触其他宠物,定期给花花的生活环境消毒。
2. 关于花花不爱吃皇家猫粮的问题:建议你尝试给花花换一种口味不同、营养成分更适合的猫粮,检查皇家猫粮是否变质,尽量保持花花的生活环境稳定,多陪伴花花,和花花玩逗猫棒、激光笔等游戏。同时,带花花去看专业的宠物医生,让医生给花花做一个全面的体检,确认是否有健康问题导致它不爱吃猫粮。
3. 关于花花体重下降的问题:建议你尝试让花花多吃一些猫粮,或者添加一些猫罐头、猫零食、猫条等,适当控制花花的运动量,定期给花花驱虫。同时,带花花去看专业的宠物医生,让医生给花花做一个全面的体检,确认是否有健康问题导致它体重下降。

小李的困惑:“为什么这个AI助手只会机械地把检索到的3篇文章的内容拼接到一起,然后分别给出关于耳朵问题、不爱吃猫粮的问题、体重下降的问题的建议?它难道不能把这三个问题关联起来吗?比如,耳螨导致花花不舒服,所以不爱吃猫粮,进而导致体重下降——它难道不能得出这个结论吗?而且,它为什么要给我这么多重复的建议?比如,三次建议我带花花去看专业的宠物医生,三次建议我给花花清洁耳朵或者添加猫罐头?它难道不能把这些重复的建议合并起来吗?它为什么不能灵活地运用知识,给出一个更简洁、更精准、更有逻辑性的建议?”


问题解决:新手程序员小李的“顿悟时刻”——AI Agent需要分层记忆组织架构+分层推理机制

连续三次“翻车”之后,小李非常沮丧——他觉得自己是不是太笨了,连一个简单的AI宠物照料助手都做不好。于是,他决定去网上找一些关于AI Agent的专业教程和资料,看看能不能找到解决问题的方法。

小李首先找到了LangChain官方文档——LangChain是目前最流行的AI Agent开发框架之一,它提供了很多关于记忆、推理、行动的组件和工具。然后,他又找到了OpenAI官方的“Building Agentic Systems with GPT-4”教程——这个教程详细讲解了如何构建具备长期记忆、精准推理能力的AI Agent。最后,他还找到了DeepMind发表的关于“分层记忆”和“分层推理”的几篇经典论文——比如《Hierarchical Memory Networks》《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》《Reflexion: Language Agents with Verbal Reinforcement Learning》。

经过整整一周的学习和研究,小李终于迎来了自己的“顿悟时刻”——他终于明白自己之前的三个原型为什么会“翻车”了,也终于明白如何构建一个具备长期记忆、精准推理能力的AI Agent了:

1.3.1 解决第一次“翻车”的方法:分层记忆组织架构——把记忆分成“工作记忆”“短期记忆”“长期语义记忆”“长期情节记忆”“长期增强学习记忆”

小李之前的第一个原型之所以会“翻车”(花花的生日刚说过就忘了),是因为他没有把记忆进行分层组织——他要么把所有记忆都放在LLM的上下文窗口中(类似人类的“工作记忆”,容量非常有限,只能记住7±2个信息块),要么把所有记忆都放在一个没有任何索引的本地JSON文件中(类似人类的“没有整理过的长期记忆仓库”,很难快速找到需要的信息)。

根据DeepMind发表的《Hierarchical Memory Networks》论文,以及认知科学领域关于“人类记忆分层模型”的研究(阿特金森-希弗林记忆模型、巴德利工作记忆模型、图尔文多重记忆系统模型),AI Agent的记忆应该被分成以下5个层次,每个层次都有不同的存储容量、存储时间、访问速度、索引方式、更新机制、遗忘机制——这就像我们人类的“冰箱分层”一样:

  1. 冷冻层(类似人类的“长期增强学习记忆”)
    • 存储容量:几乎无限(可以存储在本地硬盘、云存储等地方)。
    • 存储时间:永久(除非手动删除)。
    • 访问速度:最慢(需要从本地硬盘或云存储中读取,可能需要几毫秒到几秒钟的时间)。
    • 存储内容:AI Agent通过自主执行任务、与环境交互、获得反馈后,学习到的策略、经验、教训、模式——比如“当猫出现耳朵里有褐色分泌物、经常挠耳朵、不爱吃猫粮、体重下降的症状时,最有可能是得了耳螨”“当需要预约宠物医院时,应该优先选择离家近、评分高、有24小时急诊服务的医院”“当需要在淘宝上买猫砂时,应该优先选择销量高、评价好、价格适中、包邮的猫砂”。
    • **索引
Logo

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

更多推荐