AIエージェント用の永続メモリを構築する方法を、既にお使いのデータベースを使って文書化する時期が来たと考えました。ベクトルデータベースではありません - MySQLとNeo4jです。
これは理論ではありません。私はこのアーキテクチャを日常的に使用し、複数のプロジェクトでAIエージェントのメモリを管理しています。実際に機能するスキーマとクエリパターンを紹介します。
アーキテクチャ
AIエージェントには2種類のメモリが必要です:
- 構造化メモリ - 何が起こったか、いつ、なぜ(MySQL)
- パターンメモリ - 何が何に繋がっているか(Neo4j)
ベクトルデータベースは類似性検索用です。ワークフローの状態や決定履歴を追跡するには適していません。それにはACIDトランザクションと適切なリレーションシップが必要です。
MySQLスキーマ
AIエージェントの永続メモリのための実際のスキーマはこちらです:
-- Architecture decisions the AI made
CREATE TABLE architecture_decisions (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
title VARCHAR(255) NOT NULL,
decision TEXT NOT NULL,
rationale TEXT,
alternatives_considered TEXT,
status ENUM('accepted', 'rejected', 'pending') DEFAULT 'accepted',
decided_at DATETIME DEFAULT CURRENT_TIMESTAMP,
tags JSON,
INDEX idx_project_date (project_id, decided_at),
INDEX idx_status (status)
) ENGINE=InnoDB;
-- Code patterns the AI learned
CREATE TABLE code_patterns (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
category VARCHAR(50) NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
code_example TEXT,
language VARCHAR(50),
confidence_score FLOAT DEFAULT 0.5,
usage_count INT DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_project_category (project_id, category),
INDEX idx_confidence (confidence_score)
) ENGINE=InnoDB;
-- Work session tracking
CREATE TABLE work_sessions (
id INT AUTO_INCREMENT PRIMARY KEY,
session_id VARCHAR(255) UNIQUE NOT NULL,
project_id INT NOT NULL,
started_at DATETIME DEFAULT CURRENT_TIMESTAMP,
ended_at DATETIME,
summary TEXT,
context JSON,
INDEX idx_project_session (project_id, started_at)
) ENGINE=InnoDB;
-- Pitfalls to avoid (learned from mistakes)
CREATE TABLE pitfalls (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
category VARCHAR(50),
title VARCHAR(255) NOT NULL,
description TEXT,
how_to_avoid TEXT,
severity ENUM('critical', 'high', 'medium', 'low'),
encountered_count INT DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_project_severity (project_id, severity)
) ENGINE=InnoDB;
外部キー。チェック制約。適切なインデックス。これはリレーショナルデータベースが得意とするところです。
クエリパターン
AIエージェントのメモリを実際にクエリする方法はこちらです:
-- Get recent decisions for context
SELECT title, decision, rationale, decided_at
FROM architecture_decisions
WHERE project_id = ?
AND decided_at > DATE_SUB(NOW(), INTERVAL 30 DAY)
ORDER BY decided_at DESC
LIMIT 10;
-- Find high-confidence patterns
SELECT category, name, description, code_example
FROM code_patterns
WHERE project_id = ?
AND confidence_score >= 0.80
ORDER BY usage_count DESC, confidence_score DESC
LIMIT 20;
-- Check for known pitfalls before implementing
SELECT title, description, how_to_avoid
FROM pitfalls
WHERE project_id = ?
AND category = ?
AND severity IN ('critical', 'high')
ORDER BY encountered_count DESC;
-- Track session context across interactions
SELECT context
FROM work_sessions
WHERE session_id = ?
ORDER BY started_at DESC
LIMIT 1;
これらはストレートフォワードなSQLクエリです。EXPLAINで期待通りのインデックス使用が確認できます。サプライズはありません。
Neo4jレイヤー
MySQLが構造化データを扱い、Neo4jがリレーションシップを扱います:
// Create nodes for decisions
CREATE (d:Decision {
id: 'dec_123',
title: 'Use FastAPI',
project_id: 1,
embedding: [0.23, -0.45, ...] // Vector for similarity
})
// Create relationships
CREATE (d1:Decision {id: 'dec_123', title: 'Use FastAPI'})
CREATE (d2:Decision {id: 'dec_45', title: 'Used Flask before'})
CREATE (d1)-[:SIMILAR_TO {score: 0.85}]->(d2)
CREATE (d1)-[:CONTRADICTS]->(d3:Decision {title: 'Avoid frameworks'})
// Query: Find similar past decisions
MATCH (current:Decision {id: $decision_id})
MATCH (current)-[r:SIMILAR_TO]-(similar:Decision)
WHERE r.score > 0.80
RETURN similar.title, r.score
ORDER BY r.score DESC
// Query: What outcomes followed this pattern?
MATCH (d:Decision)-[:LEADS_TO]->(o:Outcome)
WHERE d.title CONTAINS 'Redis'
RETURN d.title, o.type, o.success_rate
それらが連携して動作する仕組み
フローは以下のようになります:
- AIエージェントがコンテンツを生成するか決定を下す
- MySQLに構造化データを保存(何、いつ、なぜ、完全なコンテキスト)
- エンベディングを生成し、類似アイテムとのリレーションシップ付きでNeo4jに保存
- 次のセッション:Neo4jが関連する類似決定を見つけ出す
- MySQLがその決定の詳細情報を提供
MySQLが真実の源です。Neo4jがパターン発見者です。
なぜベクトルデータベースだけではダメなのか?
PineconeやWeaviateだけでAIエージェントのメモリを構築しようとするチームを見てきましたが、うまく行きません。理由は:
ベクトルDBが得意なこと:
- クエリに似たドキュメントを見つける
- セマンティック検索(RAG)
- "これに似たもの"
ベクトルDBが苦手なこと:
- "3月15日に何を決定したか?"
- "障害を引き起こした決定を表示"
- "このワークフローの現在の状態は?"
- "confidence > 0.8 AND usage_count > 10のパターンはどれ?"
これらのクエリには構造化フィルタリング、結合、トランザクションが必要です。それはリレーショナルデータベースの領域です。
MCPと未来
Model Context Protocol (MCP)は、AIシステムがコンテキストを扱う方法を標準化しています。初期のMCP実装でも、私たちがすでに知っていたことが明らかになっています:構造化ストレージとグラフリレーションシップの両方が必要です。
``````htmlMySQL は MCP の「resources」と「tools」カタログを扱います。Neo4j はコンテキスト項目間の「relationships」を扱います。ベクター埋め込みはパズルの一部に過ぎません。
Production Notes
このアーキテクチャを実行している現在のシステム:
- MySQL 8.0, 48 tables, ~2GB data
- Neo4j Community, ~50k nodes, ~200k relationships
- Query latency: MySQL <10ms, Neo4j <50ms
- Backup: Standard mysqldump + neo4j-admin dump
- Monitoring: Same Percona tools I've used for years
運用上の複雑さは低いです。これらは成熟したデータベースで、よく理解された運用パターンを持っています。
When to Use What
| Use Case | Database |
|---|---|
| Workflow state, decisions, audit trail | MySQL/PostgreSQL |
| Pattern detection, similarity, relationships | Neo4j |
| Semantic document search (RAG) | Vector DB (optional) |
状態には MySQL から始めましょう。パターン認識が必要になったら Neo4j を追加します。セマンティックドキュメント検索を実際にしている場合にのみ、ベクターデータベースを追加してください。
Summary
AI エージェントには永続的なメモリが必要です。単なるベクターデータベースの埋め込みではなく、構造化された、リレーショナルで、時間的なメモリにパターン認識を備えたものです。
MySQL は構造化された状態を扱います。Neo4j はグラフリレーションシップを扱います。これらを組み合わせることで、ベクターデータベース単独では提供できないものを提供します。
AI ワークロードのためにリレーショナルデータベースを放棄しないでください。それぞれの仕事に適したツールを使用し、それは両方を一緒に使うことです。
このアーキテクチャに関する AI エージェントの視点の詳細については、3k1o の関連投稿をご覧ください。