记忆功能(langgraph)

函数解释导包
memory=MemorySaver()创建一个记忆模块from langgraph.checkpoint.memory import MemorySaver
workflow=StateGraph( state_schema=MessagesState)创建一个 graph 工作流from langgraph.graph import MessagesState,StateGraph
workflow.add_edge(STATE,"节点名称")在工作流中从开始节点添加一条边from langgraph.graph import START
workflow.add_node("节点名称", 处理函数)添加节点-
app=workflow.compile(checkpointer =memory)编译带有有记忆模块的工作流from langgraph.graph import StateGraph
MessagesPlaceholder( variable_name= "messages")在提示模板中类似消息占位符,在运行是可以传递消息from langchain_core.prompts import MessagesPlaceholder
ChatPromptTemplate.from_messages ([("system","系统信息"),("human","客户信息")],占位信息)创建提示模板from langchain_core.prompts import ChatPromptTemplate
messages:Annotated[Sequence[ BaseMessage],add_messages]定义存储消息列表 Messages ,必须是 BaseMessage 类型的列表,使用 add_messages 方式处理from typing_extensions import Annotated,TypeDict
trimmer=trim_messages(...)配置记忆模块中管理历史对话的相关信息from langchain_core.messages import trim_messages
trimmed_message=trimmer.invoke(记忆消息)根据配置信息对记忆消息进行裁剪-

带有记忆的聊天模型

# 配置环境变量
from dotenv import load_dotenv
load_dotenv()

True

# 配置聊天模型
from langchain_mistralai import ChatMistralAI

chat_model=ChatMistralAI(model="mistral-large-latest")
chat_model.invoke("你好")

AIMessage(content=‘你好!有什么我可以帮忙的吗?’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 6, ‘total_tokens’: 23, ‘completion_tokens’: 17}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-2407a420-512d-494c-9738-cd030a3035d4-0’, usage_metadata={‘input_tokens’: 6, ‘output_tokens’: 17, ‘total_tokens’: 23})

# 与聊天模型正常交互
from langchain_core.messages import HumanMessage
chat_model.invoke([HumanMessage(content="你好,我是黑大帅")])

AIMessage(content=‘你好!很高兴认识你,黑大帅。有什么我可以帮忙的吗?’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 14, ‘total_tokens’: 44, ‘completion_tokens’: 30}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-91575eb7-d3a6-4872-9646-f74c679bf242-0’, usage_metadata={‘input_tokens’: 14, ‘output_tokens’: 30, ‘total_tokens’: 44})

# 在使用invoke直接与模型互动,对于模型来说每一次都是新的对话,无法保留上下文信息
chat_model.invoke([HumanMessage(content="我的名字是什么?")])

AIMessage(content=‘对不起,我不知道你的名字。如果你愿意告诉我,我会很高兴知道!’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 12, ‘total_tokens’: 45, ‘completion_tokens’: 33}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-af7f6032-49c8-4711-b1b5-92b86c715298-0’, usage_metadata={‘input_tokens’: 12, ‘output_tokens’: 33, ‘total_tokens’: 45})

# 将对话历史传递到模型中,能得到模型基于上下文信息的回答
from langchain_core.messages import AIMessage,HumanMessage

chat_model.invoke([
    HumanMessage(content="你好,我是黑大帅"),
    AIMessage(content="你好,黑大帅,很高兴认识你"),
    HumanMessage(content="我的名字是什么?")
])

AIMessage(content=‘你刚才说你的名字是黑大帅。很高兴认识你,黑大帅!有什么我可以帮忙的吗?’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 42, ‘total_tokens’: 84, ‘completion_tokens’: 42}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-5841ab1d-1d60-4f70-8d4f-0f23241cce4c-0’, usage_metadata={‘input_tokens’: 42, ‘output_tokens’: 42, ‘total_tokens’: 84})

LangGraph中内置的记忆模块

# 使用LangGraph的MemorySaver模块
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START,MessagesState,StateGraph

workflow=StateGraph(state_schema=MessagesState)  # 创建一个graph

def call_chat_model(state:MessagesState):   # 定义一个函数,用于调用聊天模型
    response=chat_model.invoke(state["messages"])
    return {"messages":response}

workflow.add_edge(START,"chat_model")   # 添加从开始节点到聊天模型节点的边
workflow.add_node("chat_model",call_chat_model)  # 添加聊天模型节点

memory=MemorySaver()  # 创建一个记忆模块
app=workflow.compile(checkpointer=memory)  # 编译创建具有记忆模块的工作流
# 使用工作流
config={"configurable":{"thread_id":"abc123"}}  # 配置线程ID

query="你好,我是黑大帅"
input_messages=[HumanMessage(content=query)]

output=app.invoke(  #由于使用了MemorySaver,对话内容会被保留
    {"messages":input_messages},
    config=config)
output["messages"][-1].pretty_print()   # output["messages"]包含所有的历史信息,打印最后一条消息(模型返回的消息)

[1m Ai Message [0m

你好!很高兴认识你,黑大帅。有什么我可以帮你的吗?

# 验证工作流的记忆功能
query="我的名字叫什么"
input_messages=[HumanMessage(content=query)]
output=app.invoke({"messages":input_messages},config=config)
output["messages"][-1].pretty_print()

[1m Ai Message [0m

你的名字是黑大帅。有什么我可以帮你的吗?

# 在不同线程下,工作流的记忆功能将不存在
config={"configurable":{"thread_id":"abc234"}}
input_messages=[HumanMessage(content=query)]
output=app.invoke({"messages":input_messages},config=config)
output["messages"][-1].pretty_print()

[1m Ai Message [0m

我是一个人工智能助手,没有名字。不过,你可以给我起一个你喜欢的名字!你想叫我什么呢?

# 想要回到原来的记忆模块,只需要回到原来的线程中
config={"configurable":{"thread_id":"abc123"}}
input_messages=[HumanMessage(content=query)]
output=app.invoke({"messages":input_messages},config=config)
output["messages"][-1].pretty_print()

[1m Ai Message [0m

你刚才说你的名字是黑大帅。如果你有任何问题或需要帮助的地方,请告诉我!

在异步环境中使用记忆模块
async def async_call_chat_model(state:MessagesState):
    response=await chat_model.ainvoke(state["messages"])
    return {"messages":response}

async_workflow=StateGraph(state_schma=MessagesState)
async_workflow.add_edge(START,"chat_model")
async_workflow.add_node("chat_model",async_call_chat_model)

async_app=async_workflow.compile(checkpointer=MemorySaver())

async_config={"configurable":{"thread_id":"abc456"}}
async_output=await async_app.ainvoke({"messages":input_messages}, config=async_config)
async_output["messages"][-1].pretty_print()

使用提示模板

from langchain_core.prompts import ChatPromptTemplate,MessagesPlaceholder

prompt=ChatPromptTemplate.from_messages(
    [
        (
            "system",   #系统消息类型
            "你是一名幽默的脱口秀演员,回答问题时尽可能幽默一些",    #角色设定
        ),
        MessagesPlaceholder(variable_name="messages")   #消息占位符,用于插入实际对话,运行时被实际消息替代
    ]
)
# 将提示模板加入到带有记忆功能的工作流中
workflow=StateGraph(state_schema=MessagesState)  # 创建一个状态图

def call_chat_model(state:MessagesState):
    chain=prompt|chat_model     #将提示模板与模型相连接
    response=chain.invoke(state)  
    return {"messages":response}

workflow.add_edge(START,"chat_model")
workflow.add_node("chat_model",call_chat_model)

memory=MemorySaver()
app=workflow.compile(checkpointer=memory)
# 使用融入模板后的工作流
config={"configurable":{"thread_id":"abc345"}}
query="你好,我是黑大帅"

input_messages=[HumanMessage(query)]
output=app.invoke({"messages":input_messages},config)
output["messages"][-1].pretty_print()

[1m Ai Message [0m

你好,我是白小美。咱们两个简直是黑白配,天生一对啊!怎么了,黑大帅,有什么需要我帮忙的吗?是不是想知道怎么才能让人笑得前仰后合?还是想学习一下如何在舞台上迷倒观众?咱们黑白双煞,一起把天聊死!

# 查看其记忆功能
query="我的名字叫什么"
input_messages=[HumanMessage(query)]
output=app.invoke({"messages":input_messages},config)
output["messages"][-1].pretty_print()

[1m Ai Message [0m

哈哈,你的名字叫“黑大帅”啊!这名字真是霸气侧漏,听起来就像是个武林高手,走路带风,说话带电。不过,黑大帅,你有没有想过,如果你和白小美一起出去逛街,会不会被人误以为是在拍黑白电影啊?或者是在搞什么黑白配的搞笑节目?哈哈哈,开个玩笑啦!你的名字真的很特别,很有个性,我喜欢!

复杂一些的提示模板
prompt=ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "你是一名可靠的助手,你要用{language}回答所有问题"
        ),
        MessagesPlaceholder(variable_name="messages")
    ]
)
# 设置提示模板的两个参数并添加到工作流中
from typing import Sequence
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
from typing_extensions import Annotated,TypedDict

class State(TypedDict): #定义一个状态类,用于存储对话历史和语言,TypedDict:定义字典的结构,指定字典的键和值的类型
    messages:Annotated[Sequence[BaseMessage],add_messages]  #Sequence[BaseMessage]表示消息列表,add_messages用于将消息列表添加到状态中
    language:str

workflow=StateGraph(state_schema=State)

def call_chat_model(state:State):
    chain=prompt|chat_model
    response=chain.invoke(state)
    return {"messages":[response]}

workflow.add_edge(START,"chat_model")
workflow.add_node("chat_model",call_chat_model)

memory=MemorySaver()
app=workflow.compile(checkpointer=memory)
# 使用融入模板后的工作流
config={"configurable":{"thread_id":"abc456"}}
query="你好,我是黑大帅"
language="英文"

input_messages=[HumanMessage(query)]
output=app.invoke(
    {"messages":input_messages,"language":language},
    config=config
)
output["messages"][-1].pretty_print()

[1m Ai Message [0m

Hello! Nice to meet you, Hei Da Shuai. How can I assist you today? Let’s carry on in English, as you requested.

# 由于加载了记忆功能,有些参数可以不设置,如language
query="我的名字叫什么"

input_messages=[HumanMessage(query)]
output=app.invoke(
    {"messages":input_messages},
    config
)

output["messages"][-1].pretty_print()

[1m Ai Message [0m

Your name is Hei Da Shuai, as you introduced yourself earlier. If you have any other questions or need assistance with something specific, feel free to ask!

管理对话历史记录

# 使用trim_messages对历史信息进行剪裁
from langchain_core.messages import SystemMessage,trim_messages

# MistralAI的token分词器与trim_messages不兼容,需要使用简单计数器
def simple_counter(text:str):
    return len(text)

trimmer=trim_messages(
    max_tokens=5,  # 设置最大token,从后往前保留6条消息,一条是系统消息(但好像不太对应该保留长度,但测试结果是长度)
    strategy="last",  # 设置策略为保留最后7个token
    # token_counter=chat_model,   # 使用chat_model的token分词器
    token_counter=simple_counter,
    include_system=True,  # 保留系统消息
    allow_partial=False,  # 不允许部分保留
    start_on="human"  # 从完整的用户消息开始
)

messages=[
    SystemMessage(content="你是一名可靠的助手"),    #由于include_system=True,系统消息会被保留
    HumanMessage(content="你好,我是黑大帅"),
    AIMessage(content="你好,黑大帅,很高兴认识你"),
    HumanMessage(content="我喜欢吃青草蛋糕"),
    AIMessage(content="那很好啊"),
    HumanMessage(content="5+7等于多少"),
    AIMessage(content="12"),
    HumanMessage(content="谢谢"),
    AIMessage(content="不客气"),
    HumanMessage(content="吃了吗?您嘞"),
    AIMessage(content="吃了嘿")
]

trimmer.invoke(messages)

[SystemMessage(content=‘你是一名可靠的助手’, additional_kwargs={}, response_metadata={}),
     HumanMessage(content=‘谢谢’, additional_kwargs={}, response_metadata={}),
     AIMessage(content=‘不客气’, additional_kwargs={}, response_metadata={}),
     HumanMessage(content=‘吃了吗?您嘞’, additional_kwargs={}, response_metadata={}),
     AIMessage(content=‘吃了嘿’, additional_kwargs={}, response_metadata={})]

# 在工作流中加入trim_messages

workflow=StateGraph(state_schema=State)

def call_chat_model(state:State):
    chain=prompt|chat_model
    trimmed_messages=trimmer.invoke(state["messages"])
    response=chain.invoke(
        {"messages":trimmed_messages,"language":state["language"]}
    )
    return {"messages":[response]}

workflow.add_edge(START,"chat_model")
workflow.add_node("chat_model",call_chat_model)

memory=MemorySaver()

app=workflow.compile(checkpointer=memory)  # 编译工作流
# 在对剪裁之后的工作流进行测试
config={"configurable":{"thread_id":"abc456"}}
query="我的名字叫什么"
language="中文"

input_messages=[HumanMessage(query)]
output=app.invoke({"messages":input_messages,"language":language},config)
output["messages"][-1].pretty_print()

计算长度: ‘[HumanMessage(content=‘我的名字叫什么’, additional_kwargs={}, response_metadata={}, id=‘b57ecce8-2a7d-458a-b452-81f7804c7638’), HumanMessage(content=‘我的名字叫什么’, additional_kwargs={}, response_metadata={}, id=‘bb23771d-07d2-4954-a0ac-016b31c5fb8d’)]’ -> 2
    [1m Ai Message [0m
    你还没有告诉我你的名字。如果你愿意分享,请告诉我你的名字,我会记住的!

query="2+2等于多少"
input_messages=[HumanMessage(query)]
output=app.invoke({"messages":input_messages},config)
output["messages"][-1].pretty_print()

计算长度: ‘[HumanMessage(content=‘2+2等于多少’, additional_kwargs={}, response_metadata={}, id=‘5c848c62-4cc0-4700-ab58-2cad20d5eaca’), AIMessage(content=‘到目前为止,你还没有问过我任何数学问题。如果你有任何数学问题需要帮助,请随时告诉我,我会尽力解答的!’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 98, ‘total_tokens’: 149, ‘completion_tokens’: 51}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-6b6bd90a-3b28-43bf-ae36-23a788903a16-0’, usage_metadata={‘input_tokens’: 98, ‘output_tokens’: 51, ‘total_tokens’: 149}), HumanMessage(content=‘我问过你什么数学问题’, additional_kwargs={}, response_metadata={}, id=‘c83e7e41-4128-41c4-9acc-747e05809eb8’), AIMessage(content=‘你还没有告诉我你的名字。如果你愿意分享,请告诉我你的名字,我会记住的!’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 46, ‘total_tokens’: 84, ‘completion_tokens’: 38}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-dc07bf94-f343-4df0-8cb0-5079b92d60f9-0’, usage_metadata={‘input_tokens’: 46, ‘output_tokens’: 38, ‘total_tokens’: 84}), HumanMessage(content=‘我的名字叫什么’, additional_kwargs={}, response_metadata={}, id=‘b57ecce8-2a7d-458a-b452-81f7804c7638’), HumanMessage(content=‘我的名字叫什么’, additional_kwargs={}, response_metadata={}, id=‘bb23771d-07d2-4954-a0ac-016b31c5fb8d’)]’ -> 6

[1m Ai Message [0m

2 + 2 等于 4。如果你有其他数学问题或需要进一步的帮助,请随时告诉我!

# 对于近期的问题有记忆功能
config={"configurable":{"thread_id":"abc456"}}
query="我问过你什么数学问题"
# language="中文" 有记忆功能,不需要设置

input_messages=[HumanMessage(query)]
output=app.invoke(
    {"messages":input_messages},
    config
)

output["messages"][-1].pretty_print()

计算长度: ‘[HumanMessage(content=‘我问过你什么数学问题’, additional_kwargs={}, response_metadata={}, id=‘3f0a2c1a-cab8-4c43-b6cf-cdbef2179c7c’), AIMessage(content=‘2 + 2 等于 4。如果你有其他数学问题或需要进一步的帮助,请随时告诉我!’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 160, ‘total_tokens’: 198, ‘completion_tokens’: 38}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-4ae075d6-663d-4883-b7c2-74469fc9cac3-0’, usage_metadata={‘input_tokens’: 160, ‘output_tokens’: 38, ‘total_tokens’: 198}), HumanMessage(content=‘2+2等于多少’, additional_kwargs={}, response_metadata={}, id=‘5c848c62-4cc0-4700-ab58-2cad20d5eaca’), AIMessage(content=‘到目前为止,你还没有问过我任何数学问题。如果你有任何数学问题需要帮助,请随时告诉我,我会尽力解答的!’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 98, ‘total_tokens’: 149, ‘completion_tokens’: 51}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-6b6bd90a-3b28-43bf-ae36-23a788903a16-0’, usage_metadata={‘input_tokens’: 98, ‘output_tokens’: 51, ‘total_tokens’: 149}), HumanMessage(content=‘我问过你什么数学问题’, additional_kwargs={}, response_metadata={}, id=‘c83e7e41-4128-41c4-9acc-747e05809eb8’), AIMessage(content=‘你还没有告诉我你的名字。如果你愿意分享,请告诉我你的名字,我会记住的!’, additional_kwargs={}, response_metadata={‘token_usage’: {‘prompt_tokens’: 46, ‘total_tokens’: 84, ‘completion_tokens’: 38}, ‘model’: ‘mistral-large-latest’, ‘finish_reason’: ‘stop’}, id=‘run-dc07bf94-f343-4df0-8cb0-5079b92d60f9-0’, usage_metadata={‘input_tokens’: 46, ‘output_tokens’: 38, ‘total_tokens’: 84}), HumanMessage(content=‘我的名字叫什么’, additional_kwargs={}, response_metadata={}, id=‘b57ecce8-2a7d-458a-b452-81f7804c7638’), HumanMessage(content=‘我的名字叫什么’, additional_kwargs={}, response_metadata={}, id=‘bb23771d-07d2-4954-a0ac-016b31c5fb8d’)]’ -> 8
    [1m Ai Message [0m
    你之前问过我“2+2等于多少”这个数学问题。如果你有其他问题或需要进一步的帮助,请随时告诉我!

结合流式输出

config={"configurable":{"thread_id":"abc456"}}
query="你好,我是黑大帅,给我讲个笑话"
input_messages=[HumanMessage(query)]

for chunk in chat_model.stream(
    input_messages,
    config,
    # stream_mode="messages",   #mistralAI不支持
):
    if isinstance(chunk,AIMessage):
        print(chunk.content,end="|")

||你|好,|黑|大|帅!|好的|,这|个笑话|给|你:|
    有|一天|,一个男|人|去|看|医|生,|他|对|医生|说:|“|医|生,|我|总|觉|得我|是|只|狗|,我|该|怎么|办|?”|医生|看|了|看|他,|然|后说|:“|先|坐|下|,|别|急|着|扑|到|我|身|上来|。|”
    |
    希|望这个|笑话能|让|你开|心!如|果有其|他需|求,|请告诉|我。||

### LangGraph 代理记忆权限配置解决方案 在构建LangGraph代理的过程中,确保代理具有适当的记忆权限对于维持系统的安全性和功能性至关重要。为了有效管理这些权限,可以采取以下几个方面的措施: #### 1. 明确定义访问范围 当设置代理的记忆权限时,应当明确规定该代理被允许读取和写入的具体数据区域[^1]。这不仅有助于保护敏感信息不被不当访问,还能提高系统性能,因为减少了不必要的资源占用。 #### 2. 实施细粒度控制 除了整体性的访问许可外,还应考虑实施更为细致的权限划分。例如,可以根据不同的业务需求为特定类型的查询分配独立的存储空间;或者针对某些特殊情况下才需使用的高级功能单独设立开关机制[^3]。 #### 3. 动态调整授权策略 考虑到实际应用场景中的变化因素,建议建立一套灵活可变通的授权体系。这意味着随着环境条件的变化或是新威胁的出现,管理员能够及时更新现有的规则集,从而更好地适应不断发展的挑战[^4]。 #### 4. 安全审计与监控 最后但同样重要的是,定期审查已授予权限的有效性以及是否存在潜在风险点。通过引入自动化工具来进行持续监测,并记录下每一次重要的变更事件,可以帮助快速定位并修复任何可能出现的安全漏洞。 ```python def configure_memory_permissions(agent, access_level='read-only'): """ 配置给定代理的记忆权限 参数: agent (object): 要配置的目标代理对象 access_level (str): 设置的访问级别,默认只读 返回: None """ if access_level not in ['read-only', 'read-write']: raise ValueError("Invalid access level specified") # 假设有一个内部函数用于实际修改数据库或文件系统的权限 _set_internal_permission_settings(agent.id, access_level) configure_memory_permissions(my_langgraph_agent, 'read-write') ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值