오늘도 공부
3. session_notes로 공부하는 AI 에이전트 세션 관리 본문
GitHub - MiniMax-AI/Mini-Agent: A minimal yet professional single agent demo project that showcases the core execution pipeline
A minimal yet professional single agent demo project that showcases the core execution pipeline and production-grade features of agents. - MiniMax-AI/Mini-Agent
github.com
"""Example 3: Session Note Tool Usage
This example demonstrates the Session Note Tool - one of the core features
that allows agents to maintain memory across sessions.
Based on: tests/test_note_tool.py, tests/test_integration.py
"""
import asyncio
import json
import tempfile
from pathlib import Path
from mini_agent import LLMClient
from mini_agent.agent import Agent
from mini_agent.config import Config
from mini_agent.tools import BashTool, ReadTool, WriteTool
from mini_agent.tools.note_tool import RecallNoteTool, SessionNoteTool
async def demo_direct_note_usage():
"""Demo: Direct usage of Session Note tools."""
print("\n" + "=" * 60)
print("Demo 1: Direct Session Note Tool Usage")
print("=" * 60)
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".json") as f:
note_file = f.name
try:
# Create tools
record_tool = SessionNoteTool(memory_file=note_file)
recall_tool = RecallNoteTool(memory_file=note_file)
# Record some notes
print("\n📝 Recording notes...")
result = await record_tool.execute(
content="User is a Python developer working on agent systems",
category="user_info",
)
print(f" ✓ {result.content}")
result = await record_tool.execute(
content="Project name: mini-agent, Tech: Python 3.12 + async",
category="project_info",
)
print(f" ✓ {result.content}")
result = await record_tool.execute(
content="User prefers concise, well-documented code",
category="user_preference",
)
print(f" ✓ {result.content}")
# Recall all notes
print("\n🔍 Recalling all notes...")
result = await recall_tool.execute()
print(result.content)
# Recall filtered notes
print("\n🔍 Recalling user preferences only...")
result = await recall_tool.execute(category="user_preference")
print(result.content)
# Show the memory file
print("\n📄 Memory file content:")
print("=" * 60)
notes = json.loads(Path(note_file).read_text())
print(json.dumps(notes, indent=2, ensure_ascii=False))
print("=" * 60)
finally:
Path(note_file).unlink(missing_ok=True)
async def demo_agent_with_notes():
"""Demo: Agent using Session Notes to remember context."""
print("\n" + "=" * 60)
print("Demo 2: Agent with Session Memory")
print("=" * 60)
# Load configuration
config_path = Path("mini_agent/config/config.yaml")
if not config_path.exists():
print("❌ config.yaml not found")
return
config = Config.from_yaml(config_path)
if not config.llm.api_key or config.llm.api_key.startswith("YOUR_"):
print("❌ API key not configured")
return
with tempfile.TemporaryDirectory() as workspace_dir:
print(f"📁 Workspace: {workspace_dir}\n")
# Load system prompt (Agent will auto-inject workspace info)
system_prompt_path = Path("mini_agent/config/system_prompt.md")
if system_prompt_path.exists():
system_prompt = system_prompt_path.read_text(encoding="utf-8")
else:
system_prompt = "You are a helpful AI assistant."
# Add Session Note instructions
note_instructions = """
IMPORTANT - Session Note Management:
You have access to record_note and recall_notes tools. Use them to:
- record_note: Save important facts, preferences, decisions that should persist
- recall_notes: Retrieve previously saved notes
Guidelines:
- Proactively record key information during conversations
- Recall notes at the start to restore context
- Categories: user_info, user_preference, project_info, decision, etc.
"""
system_prompt += note_instructions
# Initialize LLM
llm_client = LLMClient(
api_key=config.llm.api_key,
api_base=config.llm.api_base,
model=config.llm.model,
)
# Memory file
memory_file = Path(workspace_dir) / ".agent_memory.json"
# Tools including Session Note tools
tools = [
ReadTool(workspace_dir=workspace_dir),
WriteTool(workspace_dir=workspace_dir),
BashTool(),
SessionNoteTool(memory_file=str(memory_file)),
RecallNoteTool(memory_file=str(memory_file)),
]
# === First Session ===
print("=" * 60)
print("Session 1: Teaching the agent about user preferences")
print("=" * 60)
agent1 = Agent(
llm_client=llm_client,
system_prompt=system_prompt,
tools=tools,
max_steps=15,
workspace_dir=workspace_dir,
)
task1 = """
Hello! Let me introduce myself:
- I'm Alex, a senior Python developer
- I'm building an AI agent framework called "mini-agent"
- I use Python 3.12 with asyncio
- I prefer type hints and comprehensive docstrings
- My coding style: clean, functional, well-tested
Please remember this information for future conversations.
Also, create a simple README.md file acknowledging you understood.
"""
print(f"\n📝 User message:\n{task1}\n")
print("🤖 Agent is working...\n")
agent1.add_user_message(task1)
try:
result1 = await agent1.run()
print("\n" + "=" * 60)
print("Agent response:")
print("=" * 60)
print(result1)
print("=" * 60)
# Check memory file
if memory_file.exists():
notes = json.loads(memory_file.read_text())
print(f"\n✅ Agent recorded {len(notes)} notes in memory")
for note in notes:
print(f" - [{note['category']}] {note['content'][:50]}...")
else:
print("\n⚠️ No notes found")
except Exception as e:
print(f"❌ Error: {e}")
return
# === Second Session (New Agent Instance) ===
print("\n\n" + "=" * 60)
print("Session 2: New agent instance (simulating new conversation)")
print("=" * 60)
agent2 = Agent(
llm_client=llm_client,
system_prompt=system_prompt,
tools=tools,
max_steps=10,
workspace_dir=workspace_dir,
)
task2 = """
Hello! I'm back. Do you remember who I am and what project I'm working on?
What were my code style preferences?
"""
print(f"\n📝 User message:\n{task2}\n")
print("🤖 Agent is working (should recall previous notes)...\n")
agent2.add_user_message(task2)
try:
result2 = await agent2.run()
print("\n" + "=" * 60)
print("Agent response:")
print("=" * 60)
print(result2)
print("=" * 60)
print("\n✅ Session Note Demo completed!")
print("\nKey Points:")
print(" 1. Agent in Session 1 recorded important information")
print(" 2. Agent in Session 2 recalled previous notes")
print(" 3. Memory persists across agent instances via file")
except Exception as e:
print(f"❌ Error: {e}")
async def main():
"""Run all demos."""
print("=" * 60)
print("Session Note Tool Examples")
print("=" * 60)
print("\nSession Notes allow agents to remember context across sessions.")
print("This is a key feature for building production-ready agents.\n")
# Run demos
await demo_direct_note_usage()
print("\n" * 2)
await demo_agent_with_notes()
print("\n" + "=" * 60)
print("All demos completed! ✅")
print("=" * 60)
if __name__ == "__main__":
asyncio.run(main())
03_session_notes.py 해설: “기억”을 도구로 만들면 무엇이 달라지나
이 글은 examples/03_session_notes.py를 기반으로, Mini Agent에서 “기억(memory)”을 구현하는 가장 단순하고 실용적인 방법을 설명합니다.
핵심은 한 문장입니다.
대화 히스토리(컨텍스트)와 별개로, 중요한 정보를 파일에 저장/조회하는 도구를 제공하면 “세션을 넘어가는 기억”을 만들 수 있다.
TL;DR
- SessionNoteTool(record_note)과 RecallNoteTool(recall_notes)는 JSON 파일을 백엔드로 쓰는 지속 메모리입니다.
-
- 도구를 직접 써보는 데모, 2) Agent에게 메모리를 사용하게 하는 데모, 두 파트로 구성됩니다.
- “메모리가 있다”는 건 자동이 아니라, Agent가 recall을 호출하도록 프롬프트/정책을 설계해야 합니다.

실행 방법
이 파일은 두 개의 데모를 실행합니다.
uv run python examples/03_session_notes.py
주의:
- Demo 1(직접 도구 사용)은 API 키가 필요 없습니다.
- Demo 2(Agent 사용)은 mini_agent/config/config.yaml과 API 키가 필요합니다.
Demo 1: 도구를 직접 호출해 “기억 저장/조회 계약” 확인하기
demo_direct_note_usage()는 LLM도 Agent도 없이, 노트 도구를 직접 호출합니다.
1) 저장(record_note)
- 입력: content, category
- 출력: ToolResult(success=True/False, content/error)
여기서 중요한 건 “content는 자유 텍스트지만, category는 구조화의 시작점”이라는 점입니다.
카테고리를 설계해두면, 나중에 recall 시에 정보량을 조절하기가 쉬워집니다.
2) 조회(recall_notes)
- 입력: (선택) category
- 출력: 사람이 읽기 좋은 문자열로 포맷팅된 노트 목록
실무 관점 팁:
- 반환을 JSON으로 주는 것보다 “사람이 읽기 쉬운 텍스트”가 모델에게는 더 잘 먹히는 경우가 많습니다.
- 다만 운영 환경에서는 감사(audit)나 파이프라인 처리용으로 JSON도 함께 제공하는 설계가 자주 필요합니다.
3) 파일 백엔드(JSON)의 의미
이 예제는 임시 .json 파일을 사용합니다.
- 장점: 구현이 단순하고 디버깅이 쉽습니다(파일 열면 끝).
- 단점: 검색/중복/동시성/보안 같은 문제가 커지면 DB/벡터DB로 발전이 필요합니다.
이 프로젝트의 Production Guide에서도 “데모 레벨 구현”임을 명확히 말합니다.
Demo 2: Agent에 메모리를 붙여 “세션을 넘어 기억하기”
demo_agent_with_notes()는 두 개의 Agent 인스턴스를 만들어 “세션 1에서 기록 → 세션 2에서 회상”을 시뮬레이션합니다.
핵심 구성 요소
(1) 메모리 파일 경로를 고정한다
memory_file = Path(workspace_dir) / ".agent_memory.json"
Agent 인스턴스가 바뀌더라도 동일한 파일을 바라보면 “세션 간 기억”이 됩니다.
즉, 기억의 실체는 Agent 객체가 아니라 파일(스토리지) 입니다.
(2) tools에 record/recall을 함께 넣는다
tools = [
...,
SessionNoteTool(memory_file=str(memory_file)),
RecallNoteTool(memory_file=str(memory_file)),
]
Agent는 tools 목록에 있는 것만 호출할 수 있습니다.
따라서 “기억을 쓰게 하고 싶다”는 요구는 결국 tools에 넣는 것으로 시작합니다.
(3) 시스템 프롬프트로 “언제 기록/회상할지” 정책을 심는다
예제는 system prompt 뒤에 아래와 같은 가이드를 덧붙입니다.
- “대화 시작 시 recall을 호출해 컨텍스트 복원”
- “중요한 사실/선호/결정을 기록”
- “category 사용”
여기서 중요한 현실적인 포인트:
모델은 지시를 따르려고 하지만 100% 보장은 아닙니다.
운영 수준에서는 아래 같은 장치를 추가하는 경우가 많습니다.
- 매 턴 시작 시 “자동 recall”을 런타임에서 강제 실행(도구 호출을 모델 판단에 맡기지 않음)
- 또는 “답변하기 전에 반드시 recall하고 그 결과를 요약해라” 같은 강한 규칙을 프롬프트에 넣기
세션 1: “가르치기(teach)”
첫 번째 Agent(agent1)에게:
- 사용자 소개(이름/프로젝트/기술/선호)
- “기억해라” 요청
- README 생성 요청
을 한번에 줍니다. 좋은 실험 포인트는 “이 복합 요구에서 모델이 무엇을 ‘기억해야 할 정보’로 선택하는가”입니다.
세션 2: “회상하기(recall)”
두 번째 Agent(agent2)는 새 인스턴스입니다.
그런데 tools와 memory_file이 동일하므로, recall_notes만 호출하면 세션 1의 정보가 복원됩니다.
여기서 학습할 mental model은:
- 대화 히스토리는 Agent 객체 내부에 있고(프로세스 메모리)
- 노트는 파일에 있어(스토리지)
- 새 Agent는 대화 히스토리는 없지만, 파일을 통해 “기억”은 가져올 수 있다
“기억”과 “요약(summarization)”은 다른 문제다
Mini Agent에는 대화가 길어질 때 히스토리를 요약하는 로직도 있습니다(mini_agent/agent.py).
하지만 요약은 어디까지나 현재 대화 기록을 압축하는 것이고, Session Notes는 의도적으로 남기는 장기 기억입니다.
둘의 차이를 명확히 구분하면 설계가 쉬워집니다.
- 요약: 컨텍스트 윈도우 관리(기술적 제약 대응)
- 노트: 중요한 사실의 영속화(제품 기능)
실습 과제(공부용)
- “회상을 강제”하는 프롬프트 만들기
사용자 메시지에 “답변하기 전에 recall_notes를 반드시 호출하고, 반환을 먼저 요약해라”를 넣어보세요. - category 설계 실험
user_info, project_info, decision, todo 같은 카테고리를 정하고, recall을 category별로 분리해보세요. - 메모리 파일 위치 바꾸기
memory_file을 workspace 바깥으로 빼면(예: ~/.mini-agent/...) “진짜 세션 간 기억”의 느낌을 더 강하게 체감할 수 있습니다.
다음 글 안내
다음 문서인 examples/docs/04_full_agent.md에서는:
- 기본 도구 + 세션 노트 + MCP 도구(선택)
를 모두 묶어 “작은 데모에서 운영형 구조로” 확장하는 관점을 다룹니다.
'AI > Agent' 카테고리의 다른 글
| 6. AI Agent가 사용하는 Tool 스키마 (0) | 2026.02.23 |
|---|---|
| 5. Provider 선택자 만들기 (0) | 2026.02.23 |
| 4. Ai Agent에 세션 + MCP까지 적용 (0) | 2026.02.23 |
| 2. Simple Agent (AI 에이전트 기초) (0) | 2026.02.23 |
| 1. basic_tools (AI 에이전트 기초) (0) | 2026.02.23 |
