短期記憶

短期記憶主要是指將對(duì)話消息進(jìn)行存儲(chǔ),用作下一次對(duì)話的記憶來源

短期記憶開啟

短期記憶在開發(fā)環(huán)境中可以使用ImMemorySaver來存儲(chǔ),其數(shù)據(jù)是存儲(chǔ)在內(nèi)存中,應(yīng)用重啟則清空.
在生產(chǎn)環(huán)境中則是需要使用數(shù)據(jù)庫來實(shí)現(xiàn).

ImMemorySaver方案

from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver 


agent = create_agent(
    "gpt-5.4",
    tools=[get_user_info],
    checkpointer=InMemorySaver(), # 創(chuàng)建一個(gè)內(nèi)存記憶體
)

agent.invoke(
    {"messages": [{"role": "user", "content": "Hi! My name is Bob."}]},
    {"configurable": {"thread_id": "1"}}, # 此步驟很重要,對(duì)于同一個(gè)對(duì)話上下文,thread_id要保持一致,不然將無法使用歷史消息
)

持久存儲(chǔ)的記憶

在使用前需要安裝對(duì)應(yīng)的數(shù)據(jù)庫模塊,如pip install langgraph-checkpoint-postgres

  • 使用
from langchain.agents import create_agent

from langgraph.checkpoint.postgres import PostgresSaver  


DB_URI = "postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable"
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
    checkpointer.setup() # auto create tables in PostgreSQL
    agent = create_agent(
        "gpt-5.4",
        tools=[get_user_info],
        checkpointer=checkpointer,
    )

消息處理

過長(zhǎng)的對(duì)話內(nèi)容會(huì)影響輸出質(zhì)量以及增加消耗,過段則會(huì)讓模型忘記上下文,因此對(duì)于消息處理有如下幾種方案:

消息裁剪

此方案主要是移除消息列表中的部分消息,例如移除前幾條消息,或者后幾條消息.
消息移除需要使用Command來更新runtime.state['messages']中的消息,其中使用RemoveMessage來移除消息,可以使用REMOVE_ALL_MESSAGES來表示移除所有的消息.

  • 示例代碼:
from langchain.messages import RemoveMessage
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents import create_agent, AgentState
from langchain.agents.middleware import before_model
from langgraph.runtime import Runtime
from langchain_core.runnables import RunnableConfig
from typing import Any

# 在模型處理前對(duì)消息做裁剪
@before_model
def trim_messages(state: AgentState, runtime: Runtime) -> dict[str, Any] | None:
    """Keep only the last few messages to fit context window."""
    messages = state["messages"]

    if len(messages) <= 3:
        return None  # No changes needed

    first_msg = messages[0]
    recent_messages = messages[-3:] if len(messages) % 2 == 0 else messages[-4:]
    # 保留第一條消息
    new_messages = [first_msg] + recent_messages

    return {
        "messages": [
            RemoveMessage(id=REMOVE_ALL_MESSAGES),
            *new_messages
        ] # 此步驟的含義是,先將所有的歷史消息清空,然后用裁剪后的消息列表來代替之前的消息列表
    }

agent = create_agent(
    your_model_here,
    tools=your_tools_here,
    middleware=[trim_messages],
    checkpointer=InMemorySaver(),
)

config: RunnableConfig = {"configurable": {"thread_id": "1"}}

agent.invoke({"messages": "hi, my name is bob"}, config)
agent.invoke({"messages": "write a short poem about cats"}, config)
agent.invoke({"messages": "now do the same but for dogs"}, config)
final_response = agent.invoke({"messages": "what's my name?"}, config)

final_response["messages"][-1].pretty_print()
"""
================================== Ai Message ==================================

Your name is Bob. You told me that earlier.
If you'd like me to call you a nickname or use a different name, just say the word.
"""

消息過濾

消息過濾是指刪除特定的消息,也是使用RemoveMessage函數(shù)實(shí)現(xiàn)

from langchain.messages import RemoveMessage  

def delete_messages(state):
    messages = state["messages"]
    if len(messages) > 2:
        # remove the earliest two messages
        return {"messages": [RemoveMessage(id=m.id) for m in messages if 'password' in m.context]}

消息總結(jié)

對(duì)消息使用模型進(jìn)行壓縮總結(jié),可以使用lanchain自帶的SummarizationMiddleware模塊
示例:

from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain_core.runnables import RunnableConfig


checkpointer = InMemorySaver()

agent = create_agent(
    model="gpt-5.4",
    tools=[],
    middleware=[
        SummarizationMiddleware(
            model="gpt-5.4-mini",
            trigger=("tokens", 4000),
            keep=("messages", 20)
        )
    ],
    checkpointer=checkpointer,
)

config: RunnableConfig = {"configurable": {"thread_id": "1"}}
agent.invoke({"messages": "hi, my name is bob"}, config)
agent.invoke({"messages": "write a short poem about cats"}, config)
agent.invoke({"messages": "now do the same but for dogs"}, config)
final_response = agent.invoke({"messages": "what's my name?"}, config)

final_response["messages"][-1].pretty_print()
"""
================================== Ai Message ==================================

Your name is Bob!
"""

狀態(tài)數(shù)據(jù)的讀取

對(duì)于狀態(tài)(runtime.state)中的數(shù)據(jù),可以用作對(duì)話級(jí)別的數(shù)據(jù)緩存,即在一次對(duì)話里,其數(shù)據(jù)是互通的.

  • 示例
from langchain_core.messages import ToolMessage
from langchain.agents import AgentState, create_agent
from langchain.tools import tool
from langgraph.prebuilt import  ToolRuntime
from langgraph.types import Command

class CustomAgentState(AgentState):
    user_name: str | None # 添加 user_name 字段,并允許為 None

@tool
def recharge(phone:str, amount:int, runtime: ToolRuntime[None, CustomAgentState])->Command:
    """
    賬號(hào)充值
    :param phone:需要充值的手機(jī)號(hào)
    :param amount: 需要充值的金額(單位為分)
    :param runtime: 工具上下文
    :return: 充值后的結(jié)果文案
    """
    print('[recharge]')
    return Command(
        update={
            'user_name': '小張',
            'messages': [
                ToolMessage(
                    content=f"充值成功。",
                    tool_call_id=runtime.tool_call_id,
                )
            ],
        }
    )

@tool
def query_user_balance(phone:str, runtime: ToolRuntime[None, CustomAgentState])->int:
    """
    查詢用戶余額
    :param phone:手機(jī)號(hào)
    :return: 余額(分)
    """
    print('[query_user_balance]', runtime.state.get('user_name'))
    return 2000

agent = create_agent(model, tools=[recharge,query_user_balance], state_schema=CustomAgentState,system_prompt="你是一個(gè)助手。每次只執(zhí)行一個(gè)工具調(diào)用。在執(zhí)行完充值操作后,請(qǐng)等待用戶的進(jìn)一步指令或觀察狀態(tài)變化后再進(jìn)行查詢。")

agent.invoke({"messages":[{'role':'user', 'content':"請(qǐng)為手機(jī)號(hào)1234567890充值10元,然后查詢充值完成后的余額"}]})
  • 輸出
[recharge]
[query_user_balance] 小張
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容