[langgraph] 메모리
원문 출처: https://langchain-ai.github.io/langgraph/agents/memory/
LangGraph는 대화형 에이전트 구축에 필수적인 두 가지 메모리 유형을 지원합니다:
- 단기 메모리(Short-term memory): 세션 내에서 메시지 히스토리를 유지하며, 진행 중인 대화를 추적합니다.
- 장기 메모리(Long-term memory): 여러 세션에 걸쳐 사용자별 또는 애플리케이션 레벨의 데이터를 저장합니다.
이 가이드에서는 LangGraph에서 두 가지 메모리 유형을 사용하는 방법을 설명합니다. 메모리 개념에 대한 더 깊은 이해는 LangGraph 메모리 문서를 참고하세요.

단기 메모리와 장기 메모리 모두 LLM 상호작용 간 연속성을 유지하려면 영속적 저장소가 필요합니다. 실제 서비스 환경에서는 데이터베이스에 저장하는 것이 일반적입니다.
용어 정리
- 단기 메모리 = 스레드 레벨 메모리(thread-level memory)
- 장기 메모리 = 크로스 스레드 메모리(cross-thread memory)
- 스레드(thread)는 동일한
thread_id
로 그룹화된 일련의 관련 실행(run)입니다.
단기 메모리(Short-term memory)
단기 메모리를 사용하면 에이전트가 다중 턴 대화를 추적할 수 있습니다. 사용 방법:
- 에이전트 생성 시
checkpointer
를 제공합니다. checkpointer는 에이전트 상태의 영속화를 담당합니다. - 에이전트 실행 시 config에 고유한
thread_id
를 전달합니다. 이 값은 대화 세션을 식별하는 고유 문자열입니다.
API Reference: create_react_agent | InMemorySaver
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver() # (1)!
def get_weather(city: str) -> str:
"""주어진 도시의 날씨를 조회합니다."""
return f"{city}의 날씨는 항상 맑음!"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_weather],
checkpointer=checkpointer # (2)!
)
# 에이전트 실행
config = {
"configurable": {
"thread_id": "1" # (3)!
}
}
sf_response = agent.invoke(
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
config
)
# 같은 thread_id로 대화 이어가기
ny_response = agent.invoke(
{"messages": [{"role": "user", "content": "what about new york?"}]},
config # (4)!
)
InMemorySaver
는 메모리에 상태를 저장하는 checkpointer입니다. 실제 서비스에서는 데이터베이스 등 영속 저장소를 사용하세요. LangGraph Platform을 사용하면 프로덕션용 checkpointer가 자동 제공됩니다.- 에이전트에 checkpointer를 전달합니다. 이를 통해 여러 호출 간 상태가 유지됩니다.
- config에 고유한
thread_id
를 전달합니다. 이 값은 대화 세션을 식별합니다. - 같은
thread_id
로 호출하면 이전 메시지 히스토리가 자동으로 포함되어, 예를 들어 뉴욕 날씨를 물을 때도 대화 맥락이 유지됩니다.
메시지 히스토리 관리(Manage message history)
긴 대화는 LLM의 컨텍스트 윈도우를 초과할 수 있습니다. 대표적인 해결책은:
- 요약(summarization): 대화 내용을 요약해 유지
- 트리밍(trimming): 히스토리에서 앞/뒤 N개 메시지 삭제
이렇게 하면 LLM의 컨텍스트 한계를 넘지 않으면서 대화 맥락을 유지할 수 있습니다.
메시지 히스토리 관리를 위해 pre_model_hook
(모델 호출 전 항상 실행되는 함수/노드)을 지정할 수 있습니다.
메시지 히스토리 요약(Summarize message history)
긴 대화는 LLM의 컨텍스트 윈도우를 초과할 수 있습니다. 대표적 해결책은 대화 내용을 요약해 유지하는 것입니다.
pre_model_hook
에 SummarizationNode를 사용하면 됩니다.
API Reference: ChatAnthropic | count_tokens_approximately | create_react_agent | AgentState | InMemorySaver
from langchain_anthropic import ChatAnthropic
from langmem.short_term import SummarizationNode
from langchain_core.messages.utils import count_tokens_approximately
from langgraph.prebuilt import create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.checkpoint.memory import InMemorySaver
from typing import Any
model = ChatAnthropic(model="claude-3-7-sonnet-latest")
summarization_node = SummarizationNode(
token_counter=count_tokens_approximately,
model=model,
max_tokens=384,
max_summary_tokens=128,
output_messages_key="llm_input_messages",
)
class State(AgentState):
context: dict[str, Any] # 요약 정보 관리용
checkpointer = InMemorySaver()
agent = create_react_agent(
model=model,
tools=tools,
pre_model_hook=summarization_node,
state_schema=State,
checkpointer=checkpointer,
)
context
키는 이전 요약 정보를 관리합니다. 매번 LLM 호출마다 요약하지 않도록 효율적으로 관리합니다.
메시지 히스토리 트리밍(Trim message history)
트리밍은 히스토리에서 앞/뒤 N개 메시지를 삭제하는 방식입니다. 자세한 구현은 별도 가이드를 참고하세요.
도구에서 단기 메모리 읽기(Read in tools)
에이전트는 도구 내부에서 단기 메모리(state)에 접근할 수 있습니다.
API Reference: InjectedState | create_react_agent
from typing import Annotated
from langgraph.prebuilt import InjectedState, create_react_agent
class CustomState(AgentState):
user_id: str
def get_user_info(
state: Annotated[CustomState, InjectedState]
) -> str:
"""사용자 정보 조회"""
user_id = state["user_id"]
return "User is John Smith" if user_id == "user_123" else "Unknown user"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_info],
state_schema=CustomState,
)
agent.invoke({
"messages": "look up user information",
"user_id": "user_123"
})
자세한 내용은 컨텍스트 가이드를 참고하세요.
도구에서 단기 메모리 쓰기(Write from tools)
도구 실행 중 단기 메모리(state)를 업데이트하려면, 도구에서 state 업데이트를 반환하면 됩니다. 이는 중간 결과를 저장하거나 이후 도구/프롬프트에서 활용할 정보를 남길 때 유용합니다.
API Reference: InjectedToolCallId | RunnableConfig | ToolMessage | InjectedState | create_react_agent | AgentState | Command
from typing import Annotated
from langchain_core.tools import InjectedToolCallId
from langchain_core.runnables import RunnableConfig
from langchain_core.messages import ToolMessage
from langgraph.prebuilt import InjectedState, create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.types import Command
class CustomState(AgentState):
user_name: str
def update_user_info(
tool_call_id: Annotated[str, InjectedToolCallId],
config: RunnableConfig
) -> Command:
"""사용자 정보 조회 및 업데이트"""
user_id = config["configurable"].get("user_id")
name = "John Smith" if user_id == "user_123" else "Unknown user"
return Command(update={
"user_name": name,
"messages": [
ToolMessage(
"Successfully looked up user information",
tool_call_id=tool_call_id
)
]
})
def greet(
state: Annotated[CustomState, InjectedState]
) -> str:
"""사용자 정보 조회 후 인사"""
user_name = state["user_name"]
return f"Hello {user_name}!"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[update_user_info, greet],
state_schema=CustomState
)
agent.invoke(
{"messages": [{"role": "user", "content": "greet the user"}]},
config={"configurable": {"user_id": "user_123"}}
)
자세한 내용은 도구에서 state 업데이트 가이드를 참고하세요.
장기 메모리(Long-term memory)
장기 메모리는 여러 대화에 걸쳐 사용자별/애플리케이션별 데이터를 저장하는 데 사용합니다. 예를 들어 챗봇에서 사용자 선호도나 정보를 기억할 수 있습니다.
장기 메모리 사용 방법:
- store를 설정해 데이터 영속화
- 도구/프롬프트 내부에서 get_store 함수로 store에 접근
읽기(Read)
사용자 정보를 조회하는 도구 예시
from langchain_core.runnables import RunnableConfig
from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
store.put(
("users",),
"user_123",
{
"name": "John Smith",
"language": "English",
}
)
def get_user_info(config: RunnableConfig) -> str:
"""사용자 정보 조회"""
store = get_store()
user_id = config["configurable"].get("user_id")
user_info = store.get(("users",), user_id)
return str(user_info.value) if user_info else "Unknown user"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_info],
store=store
)
agent.invoke(
{"messages": [{"role": "user", "content": "look up user information"}]},
config={"configurable": {"user_id": "user_123"}}
)
쓰기(Write)
사용자 정보를 업데이트하는 도구 예시
from typing_extensions import TypedDict
from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
class UserInfo(TypedDict):
name: str
def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str:
"""사용자 정보 저장"""
store = get_store()
user_id = config["configurable"].get("user_id")
store.put(("users",), user_id, user_info)
return "Successfully saved user info."
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[save_user_info],
store=store
)
agent.invoke(
{"messages": [{"role": "user", "content": "My name is John Smith"}]},
config={"configurable": {"user_id": "user_123"}}
)
# store에서 직접 값 확인
store.get(("users",), "user_123").value
시맨틱 검색(Semantic search)
LangGraph는 장기 메모리 내 항목을 시맨틱 유사도로 검색할 수도 있습니다.
사전 구축 메모리 도구(Prebuilt memory tools)
LangMem은 장기 메모리 관리를 위한 LangChain 공식 라이브러리입니다. 자세한 사용법은 LangMem 문서를 참고하세요.