
为你的移动应用构建端侧AI助手
构建完全在用户设备上运行的对话式AI助手的架构模式。模型选择、对话管理、UI模式和生产考虑事项。
端侧AI助手是由在用户手机上本地运行的语言模型驱动的对话界面。无云API。无网络依赖。即时响应。完全隐私。
本指南涵盖从模型选择到生产部署的完整架构。
架构概览
端侧助手有四个层次:
- 模型层: llama.cpp加载并运行GGUF模型
- 对话层: 管理聊天历史、系统提示词和上下文窗口
- 界面层: 带流式token显示的聊天UI
- 状态层: 持久化对话,管理模型生命周期
聊天的模型选择
对话式AI受益于更大的模型。微调后的3B模型是推荐的起点:
| 模型大小 | 对话质量 | 多轮连贯性 | 推荐用于 |
|---|---|---|---|
| 1B | 够用 | 2-3轮 | 简单问答、FAQ机器人 |
| 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个token,以实现更平滑的文本呈现:
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交互时加载: 不要在应用启动时加载。在用户打开聊天功能时加载。
- 活跃会话期间保持加载: 当用户在聊天中时,保持模型在内存中。
- 离开时卸载: 当用户离开聊天界 面时,卸载模型以释放内存。
- 处理内存警告: 注册系统内存警告,触发时卸载模型。
加载指示器
模型首次加载时显示简短的加载状态(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.
Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.
Ship AI that runs on your users' devices.
Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.
Keep reading

On-Device Semantic Search: AI-Powered Search Without a Server
How to build semantic search that runs entirely on the user's phone. Local embeddings, vector similarity, and natural language queries across user content without a server or API.

On-Device Text Classification for Mobile Apps
How to build fast, accurate text classification that runs on the user's phone. Sentiment analysis, content categorization, intent detection, and spam filtering without an API call.

On-Device Content Generation: AI Drafts That Work Offline
How to build AI-powered drafting features that work without internet. Email replies, message suggestions, note expansion, and content templates generated entirely on the user's device.