
為你的行動應用打造裝置端 AI 助手
建構完全在使用者裝置上運行的對話式 AI 助手的架構模式。模型選擇、對話管理、UI 模式和生產環境考量。
裝置端 AI 助手是由在使用者手機上本地運行的語言模型驅動的對話介面。無雲端 API、無網路依賴、即時回應、完全隱私。
本指南涵蓋從模型選擇到生產部署的架構。
架構概覽
裝置端助手有四個層次:
- 模型層: llama.cpp 載入並運行 GGUF 模型
- 對話層: 管理聊天歷史、系統提示詞和上下文視窗
- 介面層: 具有串流 token 顯示的聊天 UI
- 狀態層: 持久化對話、管理模型生命週期
聊天的模型選擇
對話式 AI 受益於較大的模型。微調 3B 模型是建議的起點:
| 模型大小 | 聊天品質 | 多輪連貫性 | 建議用途 |
|---|---|---|---|
| 1B | 尚可 | 2-3 輪 | 簡單問答、常見問題機器人 |
| 3B | 良好 | 5-8 輪 | 完整聊天助手 |
微調對聊天至關重要。基礎 3B 模型會產生通用回應。微調 3B 模型用你的品牌語調說話、了解你的產品,並處理你的特定使用場景。
對話管理
提示詞範本
每個模型系列都有特定的聊天範本。Llama 3.2 的範本:
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
You are the RecipeHelper assistant. Help users find and modify recipes. Always include prep and cook times.<|eot_id|><|start_header_id|>user<|end_header_id|>
Quick dinner for two?<|eot_id|><|start_header_id|>assistant<|end_header_id|>
微調時,訓練框架會自動處理範本格式化。在推論時,你的應用程式必須在發送給 llama.cpp 之前將對話格式化為此範本。
上下文視窗管理
行動模型通常使用 2048-4096 token 的上下文視窗(可設定,但較大的視窗使用更多記憶體並減慢推論速度)。對話可能很快超過此限制。
滑動視窗方法: 保留系統提示詞和最近的 N 輪對話。當視窗填滿時丟棄最舊的輪次:
func buildPrompt(systemPrompt: String, turns: [Turn], maxTokens: Int) -> String {
var prompt = formatSystem(systemPrompt)
var tokenCount = countTokens(prompt)
// 從最新到最舊加入輪次,視窗滿時停止
var includedTurns: [Turn] = []
for turn in turns.reversed() {
let turnTokens = countTokens(formatTurn(turn))
if tokenCount + turnTokens > maxTokens - 512 { break } // 為回應保留 512
includedTurns.insert(turn, at: 0)
tokenCount += turnTokens
}
for turn in includedTurns {
prompt += formatTurn(turn)
}
return prompt
}
摘要方法: 當對話超出視窗時,將較舊的輪次摘要為緊湊的上下文並前置到系統提示詞中。這在保持 token 預算內的同時保留了關鍵資訊。但這需要一次額外的推論呼叫。
對話持久化
將對話儲存在本地儲存中(iOS 的 Core Data、Android 的 Room),以便使用者可以從上次中斷的地方繼續:
- 儲存每則訊息(角色、內容、時間戳記)
- 儲存對話元資料(標題、建立日期、最後活躍時間)
- 限制儲存的對話數量以防止無限制的儲存增長
- 允許使用者刪除對話
串流 UI
聊天介面應在 token 生成時即時顯示。這創造了快速、回應即時的助手感覺。
iOS(SwiftUI)
struct ChatView: View {
@StateObject var viewModel = ChatViewModel()
var body: some View {
ScrollView {
ForEach(viewModel.messages) { message in
MessageBubble(message: message)
}
}
.onChange(of: viewModel.streamingText) { _ in
// 自動捲動到底部
}
HStack {
TextField("Message", text: $viewModel.input)
Button("Send") { viewModel.send() }
}
}
}
Android(Compose)
@Composable
fun ChatScreen(viewModel: ChatViewModel) {
val messages by viewModel.messages.collectAsState()
val streaming by viewModel.streamingText.collectAsState()
LazyColumn {
items(messages) { message ->
MessageBubble(message)
}
if (streaming.isNotEmpty()) {
item { StreamingBubble(streaming) }
}
}
Row {
TextField(value = input, onValueChange = { input = it })
Button(onClick = { viewModel.send(input) }) { Text("Send") }
}
}
Token 顯示節奏
llama.cpp 一次生成一個 token。逐一顯示每個 token 可能導致視覺抖動。在更新 UI 之前緩衝 2-3 個 tokens,以獲得更流暢的文字顯示效果:
private var tokenBuffer = StringBuilder()
private var bufferCount = 0
fun onToken(token: String) {
tokenBuffer.append(token)
bufferCount++
if (bufferCount >= 3 || token.contains("\n")) {
updateUI(tokenBuffer.toString())
tokenBuffer.clear()
bufferCount = 0
}
}
模型生命週期管理
載入與卸載
模型載入需要 1-3 秒,取決於模型大小和裝置。卸載是即時的。管理生命週期以平衡回應性與記憶體:
- 在首次 AI 互動時載入: 不要在應用啟動時載入。在使用者開啟聊天功能時載入。
- 在活躍會話期間保持載入: 使用者在聊天中時,保持模型在記憶體中。
- 離開時卸載: 使用者離開聊天畫面時,卸載模型以釋放 RAM。
- 處理記憶體警告: 註冊系統記憶體警告,觸發時卸載模型。
載入指示器
模型首次載入時顯示短暫的載入狀態(1-3 秒)。之後,回應會立即開始生成。使用者已習慣新功能的短暫載入狀態。
為你的助手微調
基礎模型和微調模型在聊天方面的品質差距是巨大的:
| 指標 | 基礎 3B | 微調 3B |
|---|---|---|
| 切題回應 | 60-70% | 92-96% |
| 格式遵循 | 55-65% | 94-98% |
| 領域準確度 | 50-60% | 88-94% |
| 語調一致性 | 40-50% | 90-95% |
聊天的訓練資料
建立涵蓋以下內容的訓練範例:
- 常見問題: 使用者最常問的 50-100 個問題
- 邊界情況: 超出範圍的問題,搭配優雅的重新導向回應
- 多輪模式: 跨越 3-5 輪的對話,展示自然的後續追問
- 風格範例: 使用你品牌語調和偏好格式的回應
500-2,000 個訓練對話可產出高品質的聊天助手。像 Ertas 這樣的平台處理訓練流程:上傳對話範例、使用 LoRA 微調、匯出 GGUF。
生產環境考量
回應品質防護欄
裝置端模型可能生成偏離主題或不正確的回應。實施輕量級防護欄:
- 輸入驗證: 檢查超長輸入或明顯的非文字內容
- 輸出監控: 在本地記錄回應主題以識別品質問題
- 回饋機制: 讓使用者標記不良回應。利用此回饋改善訓練資料
效能監控
追蹤裝置端指標:
- 首個 token 時間(應低於 300ms)
- 每秒 tokens 數(應保持在 10 以上)
- 模型載入時間
- 推論時的記憶體使用量
- AI 互動期間的當機率
模型更新
透過你正常的模型傳遞流程推送模型改進:
- 在應用啟動時檢查更新(有連線時)
- 在背景下載
- 在下一次聊天會話開始時替換模型檔案
- 保留舊模型作為後備,直到新模型驗證通過
最終結果是一個無處不在、即時回應、每次對話零成本、並完全保護使用者資料隱私的聊天助手。
Ship AI that runs on your users' devices.
Free plan with 30 credits/mo, no card required. Paid plans from $25/mo USD.
Ship AI that runs on your users' devices.
Free plan with 30 credits/mo, no card required. Paid plans from $25/mo USD.


