「チャットボットを作るとき、メッセージの履歴ってどうやって保存するの?」そう考えたとき、多くの人がまず思い浮かべるのは メッセージ専用のテーブルを用意してレコードを積み上げる、いわゆるオーソドックスな設計ですよね。
でも今回紹介するのは、そのやり方をあえて使わないアプローチです。ClaudeのAPIを使った自作チャットボット「Claudius」の開発者が公開した設計思想が、シンプルでいて非常に合理的なんです。🚀
「メッセージテーブルなし」とはどういうこと?

通常のチャットアプリを設計すると、データベースには大まかに以下のようなテーブルが並びます。
- users(ユーザー情報)
- conversations(会話セッション)
- messages(メッセージ1件ずつのレコード)
この messages テーブルにチャットのやりとりを1行ずつ保存するのが「普通」の発想です。
ところが Claudius の設計では、メッセージの配列をまるごと1つのドキュメントにまとめて保存しています。MongoDBのドキュメント指向の特性をうまく活かしたアプローチで、イメージとしては「会話履歴をひとつのJSONオブジェクトとして扱う」感じです。
具体的なデータ構造を見てみよう
実際のドキュメント構造はこんな感じになります。
{
"_id": "会話セッションのID",
"user_id": "ユーザーID",
"created_at": "2025-01-01T00:00:00Z",
"messages": [
{
"role": "user",
"content": "Claudeって何ができるの?"
},
{
"role": "assistant",
"content": "私はAnthropicが開発したAIアシスタントです!"
}
]
}
ポイントをまとめるとこんな感じです。
- ✅ messages フィールドが配列になっていて、やりとりが順番に格納される
- ✅ 1ドキュメント=1会話セッションという1対1の対応が明快
- ✅ この配列をそのまま Claude API のリクエストに渡せる形になっている
これがめちゃくちゃ便利なポイントです!Claude APIは会話履歴を配列形式で受け取るので、データベースから取り出した配列をそのままAPIに投げられるんですよね。余計な変換処理が要らないわけです。
なぜこの設計が「合理的」なのか
リレーショナルDB(MySQLなど)でメッセージテーブルを使う場合、APIに渡す前に「SELECT * FROM messages WHERE session_id = ? で取得 → 配列に整形 → APIへ投げる」という手順が必要です。
MongoDBのドキュメント設計ならこうなります。
import pymongo
client = pymongo.MongoClient("your_mongodb_uri")
db = client["claudius"]
conversations = db["conversations"]
# セッションIDで会話を取得
def get_messages(session_id):
doc = conversations.find_one({"_id": session_id})
# そのままClaude APIのmessagesパラメータに渡せる!
return doc["messages"] if doc else []
# メッセージを追加して保存
def append_message(session_id, role, content):
conversations.update_one(
{"_id": session_id},
{"$push": {"messages": {"role": role, "content": content}}},
upsert=True # なければ新規作成
)
$push で配列にメッセージを追加するだけ。シンプルですよね。
まとめ
今回は「メッセージテーブルなし」というユニークなデータ設計を持つ自作チャットボット Claudius の構造を紹介しました。
MongoDBのドキュメント指向の柔軟さと、Claude APIが期待するデータ形式がぴったりハマった、とても実用的な設計です。「むずかしそう」が「できそう」に変わる瞬間ですよね。
自分でもClaude APIを使ったチャットボットを作ってみたい方は、ぜひこの設計を参考にしてみてください!💡





