Rorkで「AIチャット機能付きアプリを作りたい」というとき、最初に思い浮かぶのはOpenAIやGeminiのAPIでしょう。でも、「地下鉄の中でも使える」「センシティブなデータを送信したくない」「APIコストをゼロにしたい」という要件が加わると、話が変わります。
こういったケースで選択肢になるのが、デバイス上またはローカルサーバー上で動く「エッジAI」です。RorkアプリにOllamaベースのローカルAI機能を組み込む基本的な考え方と実装のポイントを順番にご紹介します。
エッジAIを使うべきシチュエーション
全てのAIアプリにエッジAIが適しているわけではありません。どんなケースで検討すべきかを整理します。
向いているケース:
- 日記・メモアプリなど、プライバシーを最優先するアプリ
- 登山・キャンプガイドなど、電波が届かない場所で使うアプリ
- 医療・法律など、データを外部に送信できないアプリ
- APIコストを抑えたい無料アプリ
向いていないケース:
- 最新のニュースや時事情報が必要なアプリ
- 高い創造性や汎用的な知識が必要なアプリ
- デバイスのスペックが低い環境をターゲットにするアプリ
Rorkアプリからローカルサーバーへの接続
最も現実的な構成は「デバイス内ではなく、同じLAN内のPCでOllamaを動かし、アプリからHTTPで接続する」アプローチです。デバイスのスペック制限を回避しながら、ネット環境なしで動作します。
Rorkアプリ側からは、OpenAI互換のAPIエンドポイントとして呼び出せます:
// Rorkアプリ内でのAPI呼び出し(Expo/React Native)
const callLocalAI = async (userMessage) => {
// OllamaはOpenAI互換のエンドポイントも提供
const response = await fetch('http://192.168.1.10:11434/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'gemma4:9b',
prompt: userMessage,
stream: false
})
});
const data = await response.json();
return data.response;
};192.168.1.10 はOllamaを動かしているPCのローカルIPアドレスに変更してください。同じWiFiに繋がっていれば、スマートフォンからアクセスできます。
接続できない場合のフォールバック実装
ローカルサーバーに接続できない状況(外出先など)のためのフォールバックも実装しておきましょう:
// フォールバックありのAI呼び出し
const callAI = async (userMessage) => {
// まずローカルを試みる
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000); // 3秒でタイムアウト
const response = await fetch('http://192.168.1.10:11434/api/generate', {
method: 'POST',
signal: controller.signal,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'gemma4:9b',
prompt: userMessage,
stream: false
})
});
clearTimeout(timeoutId);
const data = await response.json();
return { text: data.response, source: 'local' };
} catch (localError) {
// ローカルが使えない場合はクラウドAPIにフォールバック
console.log('ローカルAI接続失敗、クラウドにフォールバック');
return await callCloudAI(userMessage);
}
};Rorkでのシンプルなチャット実装
Rorkを使ってこの仕組みを組み込んだ基本的なチャット画面の構成:
// ChatScreen.js(Rorkで生成されるコンポーネントに組み込む)
import React, { useState } from 'react';
import { View, TextInput, FlatList, TouchableOpacity, Text } from 'react-native';
export default function ChatScreen() {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const sendMessage = async () => {
if (!input.trim() || loading) return;
const userMessage = { id: Date.now(), role: 'user', text: input };
setMessages(prev => [...prev, userMessage]);
setInput('');
setLoading(true);
try {
const response = await callAI(input);
const aiMessage = {
id: Date.now() + 1,
role: 'assistant',
text: response.text,
isLocal: response.source === 'local'
};
setMessages(prev => [...prev, aiMessage]);
} catch (error) {
console.error('AI呼び出しエラー:', error);
} finally {
setLoading(false);
}
};
return (
<View style={{ flex: 1, padding: 16 }}>
<FlatList
data={messages}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => (
<View style={{
alignSelf: item.role === 'user' ? 'flex-end' : 'flex-start',
backgroundColor: item.role === 'user' ? '#007AFF' : '#E5E5E5',
borderRadius: 12,
padding: 12,
marginBottom: 8,
maxWidth: '80%'
}}>
<Text style={{ color: item.role === 'user' ? 'white' : 'black' }}>
{item.text}
</Text>
{item.isLocal && (
<Text style={{ fontSize: 10, color: '#666', marginTop: 4 }}>
🔒 オフライン処理
</Text>
)}
</View>
)}
/>
<View style={{ flexDirection: 'row', marginTop: 8 }}>
<TextInput
value={input}
onChangeText={setInput}
placeholder="メッセージを入力..."
style={{ flex: 1, borderWidth: 1, borderRadius: 8, padding: 8 }}
/>
<TouchableOpacity
onPress={sendMessage}
disabled={loading}
style={{ marginLeft: 8, backgroundColor: '#007AFF', borderRadius: 8, padding: 8 }}
>
<Text style={{ color: 'white' }}>送信</Text>
</TouchableOpacity>
</View>
</View>
);
}まずは試してみることから
Rorkで「Ollamaに繋がるチャットアプリ」を作ることは、難しくありません。PCでOllamaを起動し、Rorkで生成したアプリのAPIエンドポイントをローカルIPに向けるだけです。
プライバシー重視のアプリや、オフライン対応が必要なアプリの開発を考えているなら、まず実際に動かしてみることをお勧めします。より高度な実装(完全オフラインのオンデバイスAI、ファインチューニングモデルの配布、バックグラウンド推論)については、プレミアム記事で詳しく解説しています。
12年の個人開発で見えてきたこと
リリース直後にチェックしているもの
- クラッシュレポートの上位エラーを24時間ごとに確認しているか
- AdMob/StoreKit の収益ダッシュボードに異常検知が出ていないか
- ユーザーレビューに技術的な指摘が含まれていないか