IX. AI Agent에 “기억과 기록” 기능을 붙이는 단계
#-------- 1. 파일에 쓰고 읽기
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("에이전트 작동이 시작되었습니다. \n")
f.write("tool: search \n")
with open("notes.txt", "r", encoding="utf-8") as f:
contents = f.read()
print(contents)
print("characters: ", len(contents))
#-------- 2. 로그 파일에 추가하기
with open("runlog.txt", "a", encoding="utf-8") as f:
f.write("1단계 | search | ok\n")
f.write("2단계 | calculator | ok\n")
f.write("3단계 | read_file | failed\n")
failures = 0
with open("runlog.txt", "r", encoding="utf-8") as f:
for number, line in enumerate(f, start=1):
line = line.strip()
if line.endswith("failed"):
failures += 1
print(f"line {number}: {line}")
print("failed steps: ", failures)
#-------- 3. Agent History를 JSON으로 저장하기
import json
history= [
{"role":"system", "content":"당신은 재고 관리 어시스턴트입니다."},
{"role":"user", "content":"제품코드 4471은 재고가 몇 개입니까"},
{"role":"assistant", "content":"12개입니다."},
]
with open("history.json", "w", encoding="utf-8") as f:
json.dump(history, f, indent =2, ensure_ascii=False)
with open("history.json", "r", encoding="utf-8") as f:
restored = json.load(f)
print("messages restored: ", len(restored))
print("last message: ", restored[-1]["content"])
print("same data: ", restored == history)
#-------- 4. pathlib.Path
from pathlib import Path
data_dir = Path("agent_data")
history_file = data_dir/"sessions"/"history.json"
print(history_file)
print("name: ", history_file.name)
print("suffix: ", history_file.suffix)
print("parent: ", history_file.parent)
print("exists: ", history_file.exists())
#-------- 5. 폴더 만들기 + JSON 저장
from pathlib import Path
import json
data_dir = Path("agent_data")/"sessions"
data_dir.mkdir(parents=True, exist_ok=True)
target = data_dir/"latest.json"
target.write_text(json.dumps({"steps":3, "ok":True}), encoding="utf-8")
print("written to: ", target)
print("size: ", target.stat().st_size, "bytes")
print("contents: ", json.loads(target.read_text(encoding="utf-8")))
print("files here: ", [p.name for p in data_dir.iterdir()])
#-------- 6. 안전한 History 불러오기
from pathlib import Path
import json
def load_history(path):
p = Path(path)
if not p.exists():
print(f"no history at {p}, starting fresh")
return []
try:
return json.loads(p.read_text(encoding="utf-8"))
except json.JSONDecodeError:
print(f"history at {p} is corrupt, starting fresh")
return []
print(load_history("does_not_exist.json"))
Path("broken.json").write_text("{not json", encoding="utf-8")
print(load_history("broken.json"))
#-------- 7. 작은 Agent Persistence 시스템
import json
from datetime import datetime
from pathlib import Path
DATA_DIR = Path("agent_data")
HISTORY = DATA_DIR/"history.json"
LOG = DATA_DIR/"events.log"
def setup():
DATA_DIR.mkdir(parents=True, exist_ok=True)
def load():
if not HISTORY.exists():
return []
try:
return json.loads(HISTORY.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return []
def save(history):
HISTORY.write_text(
json.dumps(history, indent=2, ensure_ascii=False),encoding="utf-8"
)
def log_event(text):
stamp = datetime.now().strftime("%H:%M:%S")
with open(LOG, "a", encoding="utf-8") as f:
f.write(f"{stamp} {text} \n")
setup()
history = load()
print(f"loaded {len(history)} previous messages.")
run_number = len([m for m in history if m["role"]=="user"]) +1
history.append({"role":"user", "content":f"request number {run_number}"})
log_event(f"user turn {run_number}")
history.append({"role":"assistant", "content":"handled it"})
log_event("assistant replied")
save(history)
print(f"saved {len(history)} messages to {HISTORY}")
print("log_tail: ", LOG.read_text(encoding="utf-8").strip().splitlines()[-1])
앞에서 우리는:
사용자
↓
Agent
↓
LLM
↓
Tool
↓
결과
를 공부했습니다.
그런데 프로그램을 종료하면 문제가 생깁니다.
프로그램 종료
↓
history 사라짐
로그 사라짐
이전 작업 사라짐
그래서 이번 코드에서는 파일을 사용합니다.
AI Agent
│
├── history.json ← 대화 기억
│
├── events.log ← 작업 기록
│
└── agent_data/ ← Agent 데이터 저장 공간
하나씩 보겠습니다.
1. 파일에 쓰고 읽기
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("에이전트 작동이 시작되었습니다. \n")
f.write("tool: search \n")
open()
open("notes.txt", "w")
의 의미는:
notes.txt 파일을
쓰기 모드(w)로 열어라
입니다.
"w" = Write
"w"
는 쓰기 모드입니다.
파일이 없다면:
새 파일 생성
파일이 이미 있다면:
기존 내용 삭제
새 내용 작성
입니다.
예를 들어 기존 파일이:
안녕하세요
기존 데이터
였는데:
open("notes.txt", "w")
를 하면 기존 내용은 사라질 수 있습니다.
with
with open(...) as f:
는 아주 중요한 문법입니다.
파일을 열고:
파일 열기
↓
작업
↓
자동으로 파일 닫기
를 해줍니다.
예전 방식은:
f = open("notes.txt", "w")
f.write("hello")
f.close()
였습니다.
하지만 중간에 오류가 발생하면:
f.close()
가 실행되지 않을 수 있습니다.
그래서:
with open(...) as f:
를 사용하는 것이 좋습니다.
f.write()
f.write("에이전트 작동이 시작되었습니다. \n")
파일에 문자열을 씁니다.
\n은 줄바꿈입니다.
최종 파일:
에이전트 작동이 시작되었습니다.
tool: search
파일 읽기
with open("notes.txt", "r", encoding="utf-8") as f:
contents = f.read()
"r"은:
Read
읽기 모드
입니다.
f.read()
는 파일 전체를 읽습니다.
예:
contents
↓
에이전트 작동이 시작되었습니다.
tool: search
글자 수
print("characters: ", len(contents))
len()은 문자열의 길이를 계산합니다.
공백과 줄바꿈도 포함될 수 있습니다.
2. 로그 파일에 추가하기
with open("runlog.txt", "a", encoding="utf-8") as f:
이번에는 "a"입니다.
a = append
즉:
기존 내용을 지우지 않고 뒤에 추가
합니다.
예를 들어 기존 파일:
어제 실행
여기에:
f.write("오늘 실행\n")
하면:
어제 실행
오늘 실행
이 됩니다.
Agent에서는 아주 중요합니다
events.log
09:00 Agent 시작
09:01 search 실행
09:02 calculator 실행
09:03 완료
이런 식으로 기록합니다.
로그 파일 작성
f.write("1단계 | search | ok\n")
f.write("2단계 | calculator | ok\n")
f.write("3단계 | read_file | failed\n")
파일 내용:
1단계 | search | ok
2단계 | calculator | ok
3단계 | read_file | failed
한 줄씩 읽기
with open("runlog.txt", "r", encoding="utf-8") as f:
for number, line in enumerate(f, start=1):
파일 객체 f는 반복할 수 있습니다.
즉:
첫 번째 줄
두 번째 줄
세 번째 줄
순서대로 가져옵니다.
enumerate()
enumerate(f, start=1)
는:
1, 첫 번째 줄
2, 두 번째 줄
3, 세 번째 줄
을 만들어줍니다.
그래서:
for number, line in enumerate(f, start=1):
는 대략:
number = 1
line = "1단계 | search | ok\n"
number = 2
line = "2단계 | calculator | ok\n"
number = 3
line = "3단계 | read_file | failed\n"
입니다.
strip()
line = line.strip()
앞뒤 공백과 줄바꿈을 제거합니다.
"3단계 | read_file | failed\n"
↓
"3단계 | read_file | failed"
endswith()
if line.endswith("failed"):
문자열이:
failed
로 끝나는지 검사합니다.
예:
3단계 | read_file | failed
→ True
그러면:
failures += 1
실패 횟수를 증가시킵니다.
최종:
failed steps: 1

3. Agent History를 JSON으로 저장하기
이 부분이 매우 중요합니다.
history= [
{"role":"system", "content":"당신은 재고 관리 어시스턴트입니다."},
{"role":"user", "content":"제품코드 4471은 재고가 몇 개입니까"},
{"role":"assistant", "content":"12개입니다."},
]
이것은 우리가 계속 공부한 Agent의:
Conversation History
입니다.
메모리에 있을 때:
Python List
입니다.
그런데 프로그램을 종료하면 사라집니다.
그래서:
json.dump()
를 사용합니다.
JSON 파일 저장
with open("history.json", "w", encoding="utf-8") as f:
json.dump(history, f, indent=2, ensure_ascii=False)
의미:
Python history
↓
JSON 형식으로 변환
↓
history.json 저장
indent=2
JSON을 보기 좋게 만듭니다.
대략:
[
{
"role": "system",
"content": "당신은 재고 관리 어시스턴트입니다."
},
{
"role": "user",
"content": "제품코드 4471은 재고가 몇 개입니까"
}
]
ensure_ascii=False
이것도 중요합니다.
한국어를 그대로 저장합니다.
없으면 경우에 따라:
\uc5d0\uc774\uc804\ud2b8
같은 Unicode Escape 형태로 보일 수 있습니다.
따라서 한국어 데이터를 저장할 때:
ensure_ascii=False
를 자주 사용합니다.
JSON 복원
with open("history.json", "r", encoding="utf-8") as f:
restored = json.load(f)
이번에는:
history.json
↓
Python List
로 복원합니다.
확인
print("messages restored: ", len(restored))
3개 메시지입니다.
print("last message: ", restored[-1]["content"])
[-1]은 마지막 요소입니다.
즉:
{"role":"assistant", "content":"12개입니다."}
그리고:
12개입니다.
를 출력합니다.
원본과 같은가?
print("same data: ", restored == history)
JSON 저장 → 읽기 과정을 거쳤지만 데이터가 같으면:
True
입니다.
이것이 Agent의:
Memory Persistence
의 기초입니다.
4. pathlib.Path
이번부터 파일 경로를 더 Python답게 다룹니다.
from pathlib import Path
기존에는:
"agent_data/sessions/history.json"
처럼 문자열로 경로를 많이 사용했습니다.
Path를 사용하면:
data_dir = Path("agent_data")
이제:
agent_data
라는 경로 객체가 됩니다.
경로 연결
history_file = data_dir/"sessions"/"history.json"
이 문법이 매우 편리합니다.
agent_data
/
sessions
/
history.json
↓
agent_data/sessions/history.json
.name
history_file.name
↓
history.json
.suffix
history_file.suffix
↓
.json
.parent
history_file.parent
↓
agent_data/sessions
.exists()
history_file.exists()
파일이 존재하는지 확인합니다.
True
또는:
False
5. 폴더 만들기 + JSON 저장
data_dir = Path("agent_data")/"sessions"
결과:
agent_data/sessions
폴더 생성
data_dir.mkdir(parents=True, exist_ok=True)
매우 중요한 코드입니다.
parents=True
중간 폴더까지 자동 생성합니다.
agent_data
└── sessions
exist_ok=True
이미 폴더가 있어도 오류를 내지 않습니다.
즉:
폴더 없음 → 생성
폴더 있음 → 그냥 계속
파일 경로
target = data_dir/"latest.json"
↓
agent_data/sessions/latest.json
write_text()
target.write_text(
json.dumps({"steps":3, "ok":True}),
encoding="utf-8"
)
여기서는 open() 없이 바로 파일을 씁니다.
과정:
Python Dict
↓
json.dumps()
↓
JSON 문자열
↓
write_text()
↓
파일 저장
파일 크기
target.stat().st_size
파일 정보를 가져옵니다.
파일 정보
↓
st_size
↓
파일 크기(byte)
다시 읽기
target.read_text(encoding="utf-8")
파일 전체를 문자열로 읽습니다.
그 다음:
json.loads(...)
JSON 문자열을 Python Dictionary로 바꿉니다.
폴더 안 파일 보기
[p.name for p in data_dir.iterdir()]
iterdir():
폴더 내부 항목들을 순회
합니다.
예:
[
"history.json",
"latest.json"
]
6. 안전한 History 불러오기
이 함수는 실제 Agent에서 상당히 중요합니다.
def load_history(path):
Agent 시작 시:
history.json이 있으면
↓
불러오기
없으면
↓
새로운 History 시작
하는 구조입니다.
Path 객체로 변환
p = Path(path)
사용자가:
load_history("history.json")
을 호출하면:
문자열
↓
Path 객체
로 바꿉니다.
파일이 없는 경우
if not p.exists():
예:
load_history("does_not_exist.json")
파일 없음.
그러면:
print(f"no history at {p}, starting fresh")
return []
즉:
새로운 Agent History
를 반환합니다.
[]
JSON 파일이 깨진 경우
try:
return json.loads(
p.read_text(encoding="utf-8")
)
except json.JSONDecodeError:
예를 들어 파일이:
{not json
이면 JSON 형식이 아닙니다.
정상 JSON은:
{
"name": "Steven"
}
같아야 합니다.
그래서:
JSONDecodeError
가 발생합니다.
이 경우:
print("history is corrupt, starting fresh")
return []
를 합니다.
이것의 Agent적 의미
프로그램이:
history.json 없음
때문에 죽으면 안 됩니다.
또:
history.json 깨짐
때문에 Agent 전체가 죽어도 안 됩니다.
그래서:
없음 → 빈 History
깨짐 → 빈 History
정상 → History 복원
이라는 안전장치를 만드는 것입니다.
7. 마지막 코드
⭐ 작은 Agent Persistence 시스템
이 부분은 지금까지 배운 것이 모두 합쳐집니다.
구조:
agent_data/
│
├── history.json
│
└── events.log
DATA_DIR
DATA_DIR = Path("agent_data")
Agent 데이터 저장 폴더입니다.
HISTORY
HISTORY = DATA_DIR/"history.json"
↓
agent_data/history.json
LOG
LOG = DATA_DIR/"events.log"
↓
agent_data/events.log
setup()
def setup():
DATA_DIR.mkdir(parents=True, exist_ok=True)
Agent 실행 전에:
agent_data 폴더가 있는지 확인
없으면 생성합니다.
load()
def load():
역할:
history.json
↓
존재?
│
├── 없음 → []
│
└── 있음
↓
JSON 정상?
│
├── 정상 → History 반환
│
└── 깨짐 → []
입니다.
save(history)
def save(history):
현재 History를 파일에 저장합니다.
HISTORY.write_text(
json.dumps(
history,
indent=2,
ensure_ascii=False
),
encoding="utf-8"
)
log_event(text)
def log_event(text):
이벤트를 로그 파일에 기록합니다.
현재 시간
stamp = datetime.now().strftime("%H:%M:%S")
예:
21:35:12
로그 기록
with open(LOG, "a", encoding="utf-8") as f:
f.write(f"{stamp} {text} \n")
예:
21:35:12 user turn 1
21:35:13 assistant replied
Agent 시작
setup()
폴더 준비.
history = load()
이전 History 불러오기.
예:
이전 실행에서:
user: 안녕
assistant: 안녕하세요
가 저장되어 있다면 다시 복원합니다.
몇 번째 요청인지 계산
run_number = len(
[m for m in history if m["role"]=="user"]
) + 1
이 부분도 중요합니다.
예:
history = [
{"role":"user"},
{"role":"assistant"},
{"role":"user"},
]
사용자 메시지는:
2개
입니다.
따라서:
2 + 1
↓
3번째 요청
새로운 사용자 메시지
history.append({
"role":"user",
"content":f"request number {run_number}"
})
예:
{
"role": "user",
"content": "request number 3"
}
이벤트 기록
log_event(f"user turn {run_number}")
로그 파일:
21:40:11 user turn 3
Assistant 응답 추가
history.append({
"role":"assistant",
"content":"handled it"
})
그리고:
log_event("assistant replied")
로그:
21:40:12 assistant replied
History 저장
save(history)
현재까지의 대화를:
agent_data/history.json
에 저장합니다.
마지막 로그 확인
LOG.read_text(
encoding="utf-8"
).strip().splitlines()[-1]
이 코드를 분해하면:
① 파일 읽기
LOG.read_text()
↓
21:40:11 user turn 3
21:40:12 assistant replied
② 앞뒤 공백 제거
.strip()
③ 줄 단위로 나누기
.splitlines()
↓
[
"21:40:11 user turn 3",
"21:40:12 assistant replied"
]
④ 마지막 줄
[-1]
↓
21:40:12 assistant replied
🌟 이번 코드 전체를 한 그림으로 정리하면
Agent 실행
│
▼
setup()
│
▼
agent_data 폴더 준비
│
▼
load()
│
├── history.json 있음 → 불러오기
│
└── 없음/깨짐 → []
│
▼
사용자 요청 추가
│
▼
history.append()
│
▼
events.log 기록
│
▼
Assistant 응답
│
▼
history.append()
│
▼
events.log 기록
│
▼
save()
│
▼
history.json 저장
이번 코드에서 꼭 기억할 핵심
① 파일 모드
"r" → Read → 읽기
"w" → Write → 새로 쓰기
"a" → Append → 뒤에 추가
② with open()
with open(...) as f:
파일 작업 후 자동으로 닫아줍니다.
③ JSON 저장과 복원
json.dump()
Python 객체 → 파일
json.load()
파일 → Python 객체
문자열이라면:
json.dumps()
json.loads()
입니다.
④ Path
Path("agent_data") / "history.json"
파일 경로를 안전하고 편리하게 다룹니다.
⑤ Agent에서 가장 중요한 개념
이번 코드는 결국 이것을 만드는 것입니다.
RAM Memory
history
│
│ 프로그램 종료
▼
사라짐 ❌
Persistent Memory
history.json
│
│ 프로그램 종료
▼
파일에 남음 ⭕
│
│ 다음 실행
▼
다시 복원
즉, 이번 단계부터 여러분이 만들고 있는 Agent는 단순히 실행되고 끝나는 프로그램이 아니라,
이전 실행 기록을 저장하고, 다음 실행 때 다시 불러올 수 있는 Agent
로 발전하는 단계라고 보시면 됩니다.
그리고 지금까지 배운 내용을 연결하면 다음 순서입니다.
Python 기본 문법
↓
함수
↓
Dictionary / JSON
↓
History
↓
Tool
↓
Dispatcher
↓
Agent Loop
↓
Exception / Retry
↓
Logging
↓
파일 저장
↓
Persistent Memory