(二)、基于 LangChain 实现大模型应用程序开发 | 对话记忆模块 Memory

😄 当我们在使用大型语言模型进行聊天对话时,大型语言模型本身实际上是无状态的。语言模型本身并不记得到目前为止的历史对话。每次调用API结点都是独立的。

⭐ 所以要想具备聊天对话功能,那肯定是要将历史对话记录存起来,下次对话时一同输入:历史对话记录+当前对话来得到输出

🚀 Memory可以明确地存储到目前为止的所有术语或对话。这个Memory存储器被用作输入或附加上下文到LLM中,以便它可以生成一个输出,就好像它只有在进行下一轮对话的时候,才知道之前说过什么。

1、初始化openai环境 + 模型调用

from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI

import os
import openai
# 运行此API配置,需要将目录中的.env中api_key替换为自己的
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
openai.api_key = os.environ['OPENAI_API_KEY']

# 这里我们将参数temperature设置为0.0,从而减少生成答案的随机性。
# 如果你想要每次得到不一样的有新意的答案,可以尝试调整该参数。
# 以下的对话均无记忆,即每次调用预测不会记得之前的对话。(想要有记忆功能请看下一节的langchain的Memory模块)
chat = ChatOpenAI(temperature=0.0,
                  model_name="gpt-3.5-turbo")
chat

2、ConversationBufferMemory()

  • 用于缓存所有对话记录
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory()
# #也可预先向缓存区添加指定对话的输入输出
# memory.save_context({"input": "Hi"},
#                     {"output": "What's up"})
# print(memory.buffer) # 历史对话信息会存在memory.buffer里
#新建一个对话链(关于链后面会提到更多的细节)
conversation = ConversationChain(
    llm=chat,
    memory = memory,
    verbose=True   #查看Langchain实际上在做什么,设为FALSE的话只给出回答,看不到下面绿色的内容
)

conversation.predict(input='你好,我是小徐,也可以叫我爸爸')

输出:

> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:
Human: 你好,我是小徐
AI: 你好,小徐!很高兴认识你。我是一个AI助手,可以回答你的问题和提供帮助。有什么我可以帮你的吗?
Human: 你好,我是小徐,也可以叫我爸爸
AI:

> Finished chain.

'你好,小徐爸爸!很高兴认识你。有什么我可以帮你的吗?'

当我们进行下一轮对话时,他会保留之前对话的提示(若不需要这些提示,可在构建ConversationChain设置:verbose=False)

conversation.predict(input='1+1=?')
> Entering new  chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:
Human: 你好,我是小徐
AI: 你好,小徐!很高兴认识你。我是一个AI助手,可以回答你的问题和提供帮助。有什么我可以帮你的吗?
Human: 1+1=?
AI:

> Finished chain.

'1+1=2'
conversation.predict(input='我叫什么名字')
> Entering new  chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:
Human: 你好,我是小徐
AI: 你好,小徐!很高兴认识你。我是一个AI助手,可以回答你的问题和提供帮助。有什么我可以帮你的吗?
Human: 1+1=?
AI: 1+1=2
Human: 我叫什么名字
AI:

> Finished chain.

'你叫小徐。'

memory.buffer存储了当前为止所有的对话信息:

print(memory.buffer)
Human: 你好,我是小徐
AI: 你好,小徐!很高兴认识你。我是一个AI助手,可以回答你的问题和提供帮助。有什么我可以帮你的吗?
Human: 1+1=?
AI: 1+1=2
Human: 我叫什么名字
AI: 你叫小徐。

添加指定的输入输出内容到记忆缓存区:

memory = ConversationBufferMemory()  #新建一个空的对话缓存记忆
memory.save_context({"input": "Hi"},    #向缓存区添加指定对话的输入输出
                    {"output": "What's up"})
print(memory.buffer)   #查看缓存区结果
# Human: Hi
# AI: What's up

3、ConversationBufferWindowMemory()

  • 因为现在chatgpt都是按输入/输出的token数收费的,所以如果长期对话,那保留来所有历史对话记录,那得多烧钱啊,每次输入一大堆。
  • 对话缓存窗口记忆:只保留一个窗口大小的对话缓存区窗口记忆。它只使用最近的n次交互。这可以用于保持最近交互的滑动窗口,以便缓冲区不会过大。
from langchain.memory import ConversationBufferWindowMemory
from langchain.chains import ConversationChain

# 用法和上面一样
memory = ConversationBufferWindowMemory(k=1)     # k=1表明只保留一个对话记忆
print(memory.buffer) # 历史对话信息会存在memory.buffer里
#新建一个对话链(关于链后面会提到更多的细节)
conversation = ConversationChain(
    llm=chat,
    memory = memory,
    verbose=False   #查看Langchain实际上在做什么,设为FALSE的话只给出回答,看到不到下面绿色的内容
)


print(conversation.predict(input="你好, 我叫小徐"))
print(conversation.predict(input="1+1等于多少?"))
print(conversation.predict(input="我叫什么名字?"))

# 你好小徐!很高兴认识你。我是一个AI助手,我可以回答你的问题或者和你聊天。有什么我可以帮助你的吗?
# 1+1等于2。这是一个非常简单的数学问题。
# 很抱歉,我无法知道您的名字。

4、ConversationTokenBufferMemory()

  • 对话token缓存记忆:使用对话token缓存记忆,内存将限制保存的token数量。如果token数量超出指定数目,它会切掉这个对话的早期部分 以保留与最近的交流相对应的token数量,但不超过token限制。
  • chatgpt是如何计算token数的,可参考这:https://www.zhihu.com/question/594159910
  • openai开源的计算token数量的库tiktoken:https://github.com/openai/tiktoken
from langchain.memory import ConversationTokenBufferMemory
from langchain.chains import ConversationChain

# 用法和上面一样
memory = ConversationTokenBufferMemory(llm=chat, max_token_limit=10) # 因为要算token,所以加llm的tokenizer进来切token计算
print(memory.buffer) # 历史对话信息会存在memory.buffer里
#新建一个对话链(关于链后面会提到更多的细节)
conversation = ConversationChain(
    llm=chat,
    memory = memory,
    verbose=False   #查看Langchain实际上在做什么,设为FALSE的话只给出回答,看到不到下面绿色的内容
)

5、ConversationSummaryBufferMemory()

  • 对话摘要缓存记忆:不将内存限制为基于最近对话的固定数量的token或固定数量的对话次数窗口,而是使用LLM编写到目前为止历史对话的摘要,并将其保存。
from langchain.memory import ConversationSummaryBufferMemory
from langchain.chains import ConversationChain

# 用法和上面一样
memory = ConversationSummaryBufferMemory(llm=chat, max_token_limit=20) # 因为要算token和摘要,所以加llm的tokenizer进来切token计算
print(memory.buffer) # 历史对话信息会存在memory.buffer里
#新建一个对话链(关于链后面会提到更多的细节)
conversation = ConversationChain(
    llm=chat,
    memory = memory,
    verbose=False   #查看Langchain实际上在做什么,设为FALSE的话只给出回答,看到不到下面绿色的内容
)

# 瞧一瞧是不是真的对历史对话有摘要功能
memory.save_context({"input": "小徐喜欢小雯"}, {"output": "听说好像确实是这样的"})
memory.save_context({"input": "小雯也喜欢小徐"}, {"output": "应该是"})
memory.save_context({"input": "他们喜欢咪咪"}, {"output": "是的"})
# 也就是将历史对话摘要后转成了SystemMessage
memory.load_memory_variables({})['history']
'System: The AI agrees that Xiaoxu likes Xiaowen and responds with "应该是" (should be). The human then adds that they both like Mimi. The AI responds with "是的" (yes) and says that it has heard that it is indeed the case. The human adds that Xiaowen also likes Xiaoxu.\nAI: 是的'

Reference

  • [1] 吴恩达老师的教程
  • [2] DataWhale组织
<think>好的,我需要向用户介绍如何基于LangChain开发一个Agent应用。首先,我得回忆一下LangChain的基本概念,以及Agent在其中扮演的角色。用户可能对LangChain有一定了解,但作为新手,他们需要一步步的指导。 首先,我应该明确Agent在LangChain中的作用。Agent是能够根据输入动态选择工具并执行任务的智能体,它利用语言模型进行决策。接下来,开发一个Agent应用的基本步骤可能包括环境准备、安装依赖、选择语言模型、定义工具、创建Agent、集成链、测试优化和部署。 用户可能想知道具体每一步怎么做,比如如何安装LangChain,如何选择模型,比如OpenAI的模型或者开源的Hugging Face模型。这时候需要给出示例代码,比如安装命令pip install langchain openai,以及设置环境变量的例子。 然后定义工具部分,用户可能需要具体的工具示例,比如计算器或搜索引擎。这里需要说明如何用@tool装饰器创建自定义工具,或者使用预构建的工具,如SerpAPIWrapper。 创建Agent时,需要初始化语言模型,然后使用initialize_agent函数,并指定Agent类型,比如zero-shot-react-description。要解释参数的作用,比如tools、llm、agent、verbose等。 集成链的部分可能需要说明如何将Agent与其他模块结合,比如记忆模块或文档加载器,以处理复杂任务。这部分需要简明扼要,避免太深入细节。 测试和优化阶段,用户需要知道如何验证Agent的功能,比如输入问题并观察执行过程。同时,提示调整和参数优化也是重点,比如温度参数调整影响创造性。 部署部分要提到简单的命令行测试和实际的API服务部署,比如使用FastAPI封装,让用户了解后续步骤的可能方向。 还要考虑潜在的问题,比如工具的正确定义、API密钥的设置、错误处理等。可能需要提醒用户注意这些常见问题,避免开发中的障碍。 最后,总结整个流程,强调关键点,比如工具的定义、Agent的初始化和测试的重要性。确保用户有一个清晰的开发路线图,并鼓励他们根据需求扩展功能。 需要检查是否所有步骤都符合系统级指令,比如数学公式的正确使用,但在这个主题中可能涉及较少。确保所有代码示例用正确的格式,行内代码用反引号,独立代码块用三个反引号。同时保持语言口语化,避免专业术语堆砌,分步骤解释清楚。 可能还需要对比不同类型的Agent和工具,帮助用户根据需求选择。例如,不同类型的Agent(如zero-shot、conversational)适用场景不同,需要简要说明。 总之,结构要清晰,逐步引导用户从环境搭建到部署,每个步骤给出必要解释和示例,确保他们能够跟随操作并解决问题。同时提醒注意事项和优化技巧,提升应用的可靠性和效率。</think>以下是一步步指导你基于LangChain开发Agent应用的流程: ### 1. 环境准备 - 安装依赖库: ```bash pip install langchain openai python-dotenv ``` - 在`.env`文件设置API密钥(如OpenAI): ```python OPENAI_API_KEY="your_key_here" ``` ### 2. 初始化语言模型 ```python from langchain.llms import OpenAI from dotenv import load_dotenv load_dotenv() llm = OpenAI(temperature=0) # 控制输出随机性(0为确定性高) ``` ### 3. 定义工具(Tools) 工具是Agent执行任务的核心能力,可通过以下方式创建: **自定义工具示例** ```python from langchain.agents import tool @tool def custom_calculator(expression: str) -> float: """计算数学表达式,支持+-*/和括号""" try: return eval(expression) except: return "计算错误" ``` **使用预构建工具** ```python from langchain.utilities import SerpAPIWrapper search = SerpAPIWrapper() tools = [search] ``` ### 4. 创建Agent实例 ```python from langchain.agents import initialize_agent agent = initialize_agent( tools=tools, llm=llm, agent="zero-shot-react-description", # 零样本推理模式 verbose=True # 显示详细执行过程 ) ``` ### 5. 测试运行 ```python query = "北京当前温度是多少?换算成华氏度" result = agent.run(query) print(result) ``` 执行时会显示: ``` Thought: 需要先获取当前温度,再进行单位转换 Action: 调用搜索引擎 Observation: 北京当前气温25℃ Thought: 使用公式 (25×9/5)+32=77°F Final Answer: 北京现在25摄氏度,相当于77华氏度 ``` ### 6. 高级功能扩展 - **记忆模块**:添加`ConversationBufferMemory`实现多轮对话 ```python from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory() agent = initialize_agent(..., memory=memory) ``` - **文档处理**:结合`UnstructuredFileLoader`处理PDF/Word等文件 ```python from langchain.document_loaders import UnstructuredFileLoader loader = UnstructuredFileLoader("report.pdf") documents = loader.load() ``` ### 7. 性能优化技巧 - **提示工程**:通过`agent.agent.llm_chain.prompt`修改系统提示模板 - **参数调优**:调整`temperature`(0-1)平衡创造性与准确性 - **错误处理**:使用`try-except`包装工具函数捕获异常 ### 8. 部署应用 - **本地测试**:直接运行Python脚本 - **API服务化**:用FastAPI封装接口 ```python from fastapi import FastAPI app = FastAPI() @app.post("/ask") async def ask_agent(query: str): return {"response": agent.run(query)} ``` ### 关键概念说明 - **Agent类型**: - `zero-shot-react-description`:无历史记忆,适合简单任务 - `conversational-react-description`:支持多轮对话 - `self-ask-with-search`:自动验证中间结果 - **工具设计原则**: 1. 功能单一化(每个工具只做一件事) 2. 输入输出类型明确定义 3. 包含清晰的文档字符串(Agent根据描述选择工具) ### 常见问题排查 - **工具未被调用**:检查工具描述是否准确反映功能 - **API连接失败**:验证网络连接和密钥设置 - **无限循环**:设置`max_iterations=5`限制最大思考次数 通过以上步骤,你可以构建出能处理复杂工作流的智能体,例如: $$ 客户咨询 \rightarrow 语义解析 \rightarrow [数据库查询 \oplus 文档检索] \rightarrow 结果生成 $$ 其中$\oplus$表示并行操作,箭头表示流程顺序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

#苦行僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值