「このAI、毎回一からです」と感じさせるアプリは、使い捨てにされます。
ChatGPTが多くのユーザーに愛される理由のひとつは、会話の流れを覚えていることです。でも、Rorkで作るアプリのAI機能の多くは、セッションをまたぐと記憶がリセットされます。起動するたびに「こんにちは、はじめまして」から始まるAIを、ユーザーはどう感じるでしょうか。
ユーザーの文脈をアプリ内に保持し、LLMへ渡すことで「自分のことを知っているAI」を実現する設計パターンを順を追って整理していきます。
なぜ文脈のないAIは失敗するのか
AIチャット機能を持つアプリを考えてみます。ユーザーが「旅行の計画を立てたい」と話しかけたとき、初回は「どこに行きたいですか?」と返せます。
しかし2日後に同じユーザーが「追加で調べてほしいことがある」と話しかけたとき、文脈を持たないAIは「何について調べますか?」と聞き返します。前の会話を覚えていないからです。
これを繰り返すたびに、ユーザーは「説明し直す手間」を強いられます。その手間の蓄積が離脱につながります。
設計の全体像
必要なコンポーネントは3つです。
- ユーザーコンテキストストレージ — 過去の会話・好み・行動を端末内に保存する
- コンテキストビルダー — 保存データをLLMが理解できる文章に変換する
- LLM呼び出し — コンテキストをシステムプロンプトに注入してAPI呼び出しをする
実装1: ユーザーコンテキストをMMKVで保存する
AsyncStorageより高速なMMKVを使います。RorkアプリでMMKVを使う場合、Rork MaxのExpo設定で事前にネイティブモジュールを有効化しておく必要があります。
import { MMKV } from 'react-native-mmkv';
const storage = new MMKV({ id: 'user-context' });
// ユーザーコンテキストの型定義
interface UserContext {
preferences: {
language: string;
topics: string[];
tone: 'casual' | 'formal';
};
recentConversations: Array<{
summary: string;
timestamp: number;
}>;
profileFacts: string[]; // 「東京在住」「30代」等、会話から抽出した事実
}
// 保存
function saveUserContext(ctx: UserContext) {
storage.set('user_context', JSON.stringify(ctx));
}
// 取得
function getUserContext(): UserContext | null {
const raw = storage.getString('user_context');
return raw ? JSON.parse(raw) : null;
}実装2: 会話からプロファイル情報を自動抽出する
会話の中からユーザーについての事実を自動的に抽出して保存します。これにより、ユーザーが「自己紹介」を省略できるようになります。
async function extractAndSaveUserFacts(
userMessage: string,
existingFacts: string[]
): Promise<string[]> {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'x-api-key': process.env.EXPO_PUBLIC_ANTHROPIC_KEY!,
'anthropic-version': '2023-06-01',
'content-type': 'application/json',
},
body: JSON.stringify({
model: 'claude-haiku-4-5-20251001',
max_tokens: 256,
system: `ユーザーのメッセージから、将来の会話で役立つ個人情報を抽出してください。
既知の情報: ${existingFacts.join('、')}
新しい事実のみをJSON配列で返してください。新しい情報がなければ空配列を返してください。
例: ["東京在住", "旅行が趣味", "3歳の子供がいる"]`,
messages: [{ role: 'user', content: userMessage }],
}),
});
const data = await response.json();
try {
const newFacts = JSON.parse(data.content[0].text);
return [...new Set([...existingFacts, ...newFacts])];
} catch {
return existingFacts;
}
}Haiku(最小・最速・最安のモデル)を使うのがポイントです。事実抽出のような軽タスクにOpusやSonnetを使う必要はありません。コスト削減に直結します。
実装3: コンテキストをシステムプロンプトに注入する
保存したコンテキストを使って、「このユーザーのことを知っているAI」を演出します。
function buildSystemPrompt(ctx: UserContext | null): string {
if (!ctx) {
return 'あなたは親切なアシスタントです。';
}
const parts = ['あなたは親切なアシスタントです。'];
if (ctx.profileFacts.length > 0) {
parts.push(`\n【ユーザーについて知っていること】\n${ctx.profileFacts.join('\n')}`);
}
if (ctx.recentConversations.length > 0) {
const recent = ctx.recentConversations
.slice(-3) // 直近3件のみ
.map(c => `- ${c.summary}`)
.join('\n');
parts.push(`\n【最近の会話の概要】\n${recent}`);
}
if (ctx.preferences.tone === 'casual') {
parts.push('\nフレンドリーで砕けた口調で話してください。');
}
return parts.join('');
}
// 実際のAPI呼び出し
async function chat(userMessage: string): Promise<string> {
const ctx = getUserContext();
const systemPrompt = buildSystemPrompt(ctx);
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: { /* ... */ },
body: JSON.stringify({
model: 'claude-haiku-4-5-20251001',
max_tokens: 1024,
system: systemPrompt,
messages: [{ role: 'user', content: userMessage }],
}),
});
// レスポンス後にコンテキストを更新
if (ctx) {
const newFacts = await extractAndSaveUserFacts(userMessage, ctx.profileFacts);
saveUserContext({ ...ctx, profileFacts: newFacts });
}
const data = await response.json();
return data.content[0].text;
}プライバシーへの配慮
ユーザーの個人情報を端末内に保存するため、プライバシーポリシーへの明記と、データ削除機能の提供が必要です。
// ユーザーが「リセット」した場合
function clearUserContext() {
storage.delete('user_context');
}設定画面に「AIの記憶をリセット」ボタンを設置するだけで、ユーザーの安心感が大きく変わります。わたし自身のアプリでこの機能を追加したところ、レビューで「プライバシーに配慮されている」というコメントをもらいました。
実装のコストと効果
この実装で追加されるAPI費用は、会話1回につき事実抽出でHaiku呼び出し1回分(約0.01円〜0.1円)だけです。
効果として得られるのは「このアプリ、自分のことを覚えてくれている」というユーザー体験です。その体験の差が、継続率に現れます。
技術的な複雑さを最小限に、ユーザー体験の向上を最大化できるこのパターンは、個人開発者がAI機能を差別化する上で最もコスパが高い投資のひとつだと思っています。
12年の個人開発で見えてきたこと
リリース直後にチェックしているもの
- クラッシュレポートの上位エラーを24時間ごとに確認しているか
- AdMob/StoreKit の収益ダッシュボードに異常検知が出ていないか
- ユーザーレビューに技術的な指摘が含まれていないか