AIエージェント活用実践編状態管理とメモリ設計

会話履歴の保存と再開 — 実装編

無料公開レッスン / 読了目安 7


学習のねらい

設計編で整理した永続化の方針(JSON または SQLite)を、実際にコードに落とし込みます。 JSON ファイル / SQLite データベース / セッション再開 / ユーザーIDとの紐付け の4ステップを最小コードで体験します。

JSON 形式での保存

最もシンプルな方法です。json.dump() でリストを保存し、json.load() で読み込むだけです。

import json

conversation_history = [
    {"role": "user", "content": "こんにちは"},
    {"role": "assistant", "content": "ごきげんよう"}
]

# 保存
with open("conversation_123.json", "w", encoding="utf-8") as f:
    json.dump(conversation_history, f, ensure_ascii=False, indent=2)

# 読み込み
with open("conversation_123.json", "r", encoding="utf-8") as f:
    loaded_history = json.load(f)

print(loaded_history)

ensure_ascii=False を入れると日本語がそのまま読める形で保存されます。

SQLite データベースへの保存

各会話ターンを1レコードとして保存し、session_id で束ねる方式です。 SQLite はファイルベースなので、別途サーバを立てる必要がありません。

import sqlite3
import json  # contentはJSON文字列として保存

def save_message(session_id, role, content):
    conn = sqlite3.connect('conversations.db')
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS messages (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            session_id TEXT NOT NULL,
            role TEXT NOT NULL,
            content TEXT NOT NULL,
            timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
        )
    ''')
    cursor.execute(
        "INSERT INTO messages (session_id, role, content) VALUES (?, ?, ?)",
        (session_id, role, json.dumps(content)),
    )
    conn.commit()
    conn.close()

def load_messages(session_id):
    conn = sqlite3.connect('conversations.db')
    cursor = conn.cursor()
    cursor.execute(
        "SELECT role, content FROM messages WHERE session_id = ? ORDER BY timestamp",
        (session_id,),
    )
    messages = [{"role": row[0], "content": json.loads(row[1])} for row in cursor.fetchall()]
    conn.close()
    return messages

content に辞書などが入る可能性があるので、json.dumps() で文字列化して保存します。

セッション再開時の復元

会話を再開するときは、保存しておいた履歴を読み込んで LLM の messages の冒頭に含めるだけです。

from anthropic import Anthropic

client = Anthropic()

# loaded_history に JSON か SQLite から読み込んだ履歴が入っているとする
loaded_history.append({"role": "user", "content": "昨日の続きですが、あの件はどうなりましたか?"})

response = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=loaded_history,  # 過去の履歴を含めて送信
)
print(response.content[0].text)

ユーザーIDとの紐付け

複数のユーザーが使う場合、誰の会話かを識別するために ユーザーID と会話セッションを紐付けます。

  • ファイル名にユーザーIDを含める(例: conversation_user123.json)
  • データベースのテーブルに user_id カラムを追加し、インデックスを張る

これにより、ユーザーごとに独立した履歴を管理し、パーソナライズされた応答が返せます。

まとめ

会話履歴の永続化は、JSON ファイル → SQLite と段階的に発展させるのが現実的です。 セッション再開時には保存された履歴を messages 冒頭に含めて送り、ユーザーIDとセッションを必ず紐付けましょう。 次のレッスンでは、LLM の知識を補完する「知識ベース(KB)統合」について学びます。

参考リンク


会話履歴の保存と再開 — 実装編 | AIエージェント活用実践編 第1章 - AI研修