本文译自「On-Device Function Calling with FunctionGemma」,原文链接medium.com/google-deve…,由Sasha Denisov发布于2025年12月29日。
我为什么相信离线代理
我是 flutter_gemma 的创建者和维护者——这是一个用于在移动设备上本地运行 LLM 的 Flutter 插件。我越是使用设备端 AI,就越发确信:未来属于本地代理,或者至少是混合代理。
为什么?
想象一下,你是一位想要构建带有 AI 代理的移动或 Web 应用的开发者。当智能体部署在云端时,你会面临一系列问题:
-
延迟 — 用户需要等待响应,速度取决于网络连接质量
-
Token成本 — 你需要权衡用户定价和利润率
-
隐私 — GDPR 和其他法规要求谨慎处理数据
-
网络依赖 — 没有网络就无法提供服务
所有这些问题都可以通过将 AI 迁移到设备端来解决。
我在《把离线AI智能体装进口袋里》(The Dawn of Offline AI Agents in Your Pocket)一文中对此进行了详细阐述。但文章中的示例更像是Demo,而非生产解决方案。像 Gemma 3n 这样的模型虽然能够很好地处理函数调用,但它们体积过大:无法集成到应用程序包中,需要单独下载,即使在旗舰机型上推理速度也很慢。在低端设备上,它们根本无法运行。而较小的型号则经常出现故障,难以记住工具。
对于生产环境,你需要一个专门的型号:
-
体积小 — 可放入手机内存
-
速度快 — 解码速度 >100 tok/s
-
专为函数调用而生 — 并非通用聊天工具
而这样的型号现在已经存在——FunctionGemma。
什么是 FunctionGemma?
FunctionGemma 是 Gemma 3 270M 的一个特殊版本,专为函数调用而设计。
Google 于 2025 年 12 月(几天前)发布了它。它回应了开发者在 Gemma 3 270M 发布后提出的主要需求——为设备端代理提供原生函数调用支持。
主要规格:
实际应用效果:
-
288 MB — 可直接嵌入应用包,无需单独下载
-
551 MB RAM — 即使在配备 4 GB 内存的入门级设备上也能流畅运行
-
2.7 亿个参数 — 比 Gemma 3n E2B 小 10 倍,但足以满足函数调用需求
-
25.6 万词汇表 — 庞大的词汇表能够很好地处理结构化数据和 JSON
-
0.3 秒 TTFT — 模型几乎瞬间响应
在 flutter_gemma 插件的示例应用中查看其速度:
有一点很重要。该模型的初始准确率只有 58%。听起来不太像能直接用于生产环境,对吧?
但关键在于:FunctionGemma 可以轻松地针对你的特定函数进行微调。微调后,准确率跃升至 85%。+27%——这就是“有时有效”和“可用于生产环境”之间的区别。
与竞品对比
为了更直观地比较,我们不妨将 FunctionGemma 与几个最接近的替代方案进行比较:Gemma 3n 和 Gemma 3 1B 作为间接竞争对手(支持函数调用的通用模型),Llama 作为流行的开源选项,以及 Hammer——MadeAgents 出品的直接竞争对手,专为函数调用而设计。
FunctionGemma 仅提供 int8 版本(288 MB)——由于模型本身已经很小,这已经足够了。Gemma 3n E2B 则相反——仅提供 int4 版本,因为 int8 版本将占用约 6 GB 的空间。
int8 与 int4 — 有什么区别? 量化将模型权重从 32/16 位数字压缩为 8 位 (int8) 或 4 位 (int4)。位数越少,文件越小,推理速度越快,但质量可能越低。
int8 — 质量和大小之间的平衡。质量损失极小(约 1~3%),文件大小比 FP16 减少约 2 倍。
int4 — 最大程度的压缩,文件大小减少约 4 倍。质量损失更明显(约 2~10%,具体取决于模型),但通常可以接受,尤其对于函数调用而言。
还有一个重要的指标——准确率。伯克利函数调用排行榜 (BFCL) 是评估函数调用能力的标准基准。 Gemma 3 1B 的得分约为 31%,Llama 3.2 1B 约为 26%,两者未经微调的性能都很弱。由于 Gemma 3n 是通用型程序,因此未对其进行测试。Hammer 2.1 0.5B 没有公开数据,但其 1.5B 版本开箱即用的得分约为 73%——尽管它在 int8 内存中占用约 1.5GB 的空间,是 FunctionGemma(288MB)的 5 倍。
何时选择哪种模型
-
快速原型,无需微调 → Hammer 或 FunctionGemma 基础模型。
-
速度最快 + 体积最小 + 准确率最高 → FunctionGemma(2.7 亿字节,约 126 tok/秒,微调后准确率达 85%)
-
多模态智能体(文本 + 图像) → Gemma 3n
FunctionGemma 的独特格式
与大多数使用 JSON 的模型不同,FunctionGemma 拥有自己的格式和特殊标记。
函数调用格式
<start_function_call>call:change_background_color
{color:<escape>red<escape>}<end_function_call>
让我们来分解一下:<start_function_call> — 函数调用开始,call: — 前缀,change_background_color — 函数名,{color:<escape>red<escape>} — 带转义标记的参数,<end_function_call> — 函数调用结束。
开发者角色
FunctionGemma 经过优化,以 developer 作为指令角色。使用 system(例如在 Hammer 或标准 Gemma 中)不会激活函数调用模式——模型将完全忽略你的工具定义。
messages = [
{"role": "developer", "content": "You are a model that can do function calling..."},
{"role": "user", "content": "make it red"}
]
使用 system 不会激活函数调用模式。
枚举支持
一个 2.7 亿的模型可能会产生虚假的参数值。如果没有约束,请求“把它变成红色”可能会生成 {“color”: “crimson”} 或 {“color”: “rouge”}。枚举类型强制模型仅从有效值中选择,从而确保函数调用的可靠性。
格式:
enum:[<escape>red<escape>,<escape>blue<escape>,<escape>green<escape>]
声明函数时,枚举类型位于 description 和 type 之间:
color:{description:<escape>The color name<escape>,enum:[<escape>red<escape>,...],type:<escape>STRING<escape>}
停止标记
什么是停止标记? 停止标记是告知模型何时停止生成数据的特殊标记。对于 FunctionGemma,需要两个停止标记:<end_of_turn> — 消息结束,<start_function_response> — 模型停止并等待函数结果。
为什么它们很重要: 如果没有 <start_function_response>,模型在函数调用后不会暂停,而是会错误地获取响应。这两个标记都必须在模型转换为 .task 格式时设置。
stop_tokens=[
"<end_of_turn>",
"<start_function_response>", # Model stops, waits for result
]
模型准备流程
让我们详细了解一下模型准备流程——从微调到最终生成可在设备端运行的格式。理解这一点至关重要,因为 Google 最初只发布了 PyTorch 格式的 FunctionGemma 模型,而移动端部署需要进行格式转换。
该流程首先使用 TRL/SFTTrainer 对 JSONL 格式的训练数据上的 google/functiongemma-270m-it 基础模型进行微调。训练完成后,使用 ai-edge-torch 和 dynamic_int8 量化算法将模型转换为 TFLite 格式。最后一步取决于目标运行时环境:对于 MediaPipe,将 TFLite 模型与分词器和停止标记合并到一个 .task 包中,该包可在 iOS、Android 和 Web 上运行。或者,你可以将其打包为 .litertlm 格式,用于 LiteRT-LM 运行时,该运行时提供 NPU 加速和更广泛的平台支持,包括桌面平台。
转换为 TFLite 后,你可以选择将模型打包为两种可在设备端运行的格式之一:.task(用于 MediaPipe)或 .litertlm(用于 LiteRT-LM)。
task — 这是 MediaPipe 格式,经过长时间的实战检验。MediaPipe LLM 推理 API 已存在多年,可在 iOS、Android 和 Web 上可靠运行。模型与分词器和元数据一起打包在一个文件中。支持 GPU 加速。这就是 flutter_gemma 目前使用的格式。
litertlm — 这是 Google 推出的一种新格式,是 .task 的升级版,具有更好的压缩效果和额外的元数据。MediaPipe 也可以在 iOS、Android 和 Web 上运行 .litertlm,但不具备 NPU 等额外功能。 .litertlm 的主要优势在于其独立的运行时 LiteRT-LM:它支持 NPU(神经处理单元),可实现更强大的加速,并支持桌面平台——Linux、macOS、Windows,甚至 Raspberry Pi。但 LiteRT-LM 运行时目前仍处于早期预览阶段:iOS 和 Web 平台暂不支持(即将推出)。
如何选择?
移动应用(iOS + Android)或 Web 应用——请选择 .task。原生支持 MediaPipe LLM 推理 API:Android 和 iOS 都有现成的示例。在 Flutter 上,flutter_gemma 也开箱即用地支持它。
仅限 Android + 最大程度利用硬件 — 使用 LiteRT-LM 运行时的 .litertlm 文件可实现 NPU 加速。请在 Google Play(适用于 Android)和 TestFlight(适用于 iOS)上查看 AI Edge Gallery——这是 Google 的演示应用,包含 FunctionGemma、语音命令和小游戏。源代码位于 GitHub。目前仅支持 Android。
桌面端(Linux、macOS、Windows)——仅支持通过 LiteRT-LM 集成的 .litertlm 文件。有多种集成选项:
-
CLI 工具
lit——从 HuggingFace 拉取模型,并只需一条命令即可运行推理。适用于 macOS、Linux 和 Windows 的二进制文件 -
Kotlin API — 适用于 Android 和 JVM(Linux、macOS、Windows)的完整 SDK
-
C++ API — 用于原生集成并支持流式传输的引擎、会话和对话类
flutter_gemma 支持
flutter_gemma 通过 MediaPipe LLM 推理 API,支持 iOS、Android 和 Web 上的 .task 和 .litertlm 格式。
至于基于 NPU 和桌面平台的 LiteRT-LM 运行时,相关工作已经在进行中。一旦 Google 开放 iOS 的公共 API(预计在 2026 年初),我们将添加全面支持。桌面平台也在我们的计划之中——敬请期待,即将推出。
即用型 Colab Notebook
我已经为整个流程准备好了 Notebook:
-
微调 — 加载基础模型,准备 JSONL 数据集,使用 TRL/SFTTrainer 进行训练,保存到云端硬盘
-
TFLite 转换 — 使用 ai-edge-torch 将 PyTorch 模型转换为 TFLite 模型,应用 int8 量化
-
任务包 — 将 TFLite、分词器和停止标记合并为 .task 文件,用于 MediaPipe
-
LiteRT-LM 包 — 使用 ai-edge-torch-nightly 转换为 .litertlm 文件,并添加元数据和停止标记,用于 LiteRT-LM 运行时
训练数据格式
为了优化 FunctionGemma 在你的函数上的性能,你需要训练数据——用户请求示例及其对应的函数调用。数据格式为简单的 JSONL,其中每一行将用户短语映射到一个函数名及其参数。
{"user_content": "make it red", "tool_name": "change_background_color", "tool_arguments": "{\"color\": \"red\"}"}
{"user_content": "rename app to Hello", "tool_name": "change_app_title", "tool_arguments": "{\"title\": \"Hello\"}"}
{"user_content": "show alert saying hi", "tool_name": "show_alert", "tool_arguments": "{\"title\": \"Alert\", \"message\": \"hi\"}"}
你需要多少个示例?
在我的演示应用中,我使用了 284 个示例,每个功能大约 90-100 个。多样性很重要:不仅仅是重复 94 次“把它变成红色”,而是不同的表达方式,例如“改成红色”、“设置背景为红色”、“我想要一个红色背景”、“请把背景变成红色”等等。模型需要了解真实用户是如何表达请求的。
与 flutter_gemma 集成
https://github.com/DenisovAV/flutter_gemma — 我的 Flutter 插件,用于在本地运行 Gemma 模型(以防你忘记了):)
模型设置
选择模型类型 — 这将激活特殊的 FunctionGemma 解析器。
// ModelType.functionGemma activates the special parser
final model = Model.functionGemma_270M;
// or your fine-tuned version
final model = Model.functionGemma_demo;
定义函数
使用 JSON Schema 格式描述你的函数 — 与 OpenAI 函数调用相同。
final tools = [
Tool(
name: 'change_background_color',
description: 'Changes the app background color',
parameters: {
'type': 'object',
'properties': {
'color': {
'type': 'string',
'enum': ['red', 'blue', 'green', 'yellow', 'purple', 'orange'],
'description': 'The color name',
},
},
'required': ['color'],
},
),
];
创建带有工具的聊天
创建聊天时传递你的工具 — 插件将自动生成系统提示。
final chat = await model.createChat(tools: tools);
处理响应
处理数据流 — 你将获得文本标记或函数调用。
await chat.addQuery(Message.text(text: userInput, isUser: true));
await for (final response in chat.generateChatResponseAsync()) {
if (response is TextResponse) {
// Regular text
appendToUI(response.token);
} else if (response is FunctionCallResponse) {
// Function call!
final result = await executeFunction(
response.name, // "change_background_color"
response.args, // {"color": "red"}
);
// Send result back to the model
await chat.addQuery(Message.toolResponse(
toolName: response.name,
response: result,
));
}
}
底层工作原理
插件自动生成包含函数声明的提示符
FunctionCallParser解析特殊的 FunctionGemma 格式流式安全函数调用检测
跨平台:iOS、Android、Web
实际示例
演示应用 — 你已在上方看到过它的截图。我创建了一个包含三个函数的演示:change_background_color(更改背景颜色)、change_app_title(更改标题)和show_alert(显示警告对话框)。
示例对话框
用户: “将背景设为红色”
模型:“<start_function_call>call:change_background_color{color:red}<end_function_call>”
插件: 解析函数调用,调用 changeBackgroundColor(“red”),将结果发送给模型,模型生成响应:“完成!背景现在是红色了。”
即用型模型 — 无需转换
要试用 FunctionGemma,你无需完成整个流程或进行微调。我已经准备好了即用型模型:
1.基础模型(已转换为 .task 文件):
Google 仅以 PyTorch 格式发布了 FunctionGemma。我完成了整个转换流程,并上传了最终的 .task 文件:sasha-denisov/function-gemma-270M-it。这是 Google 的原始模型,未经微调。准确率约为 58%——虽然不算完美,但足以用于实验和原型开发。只想尝试在设备上调用函数?那就下载这个模型吧。
2.针对演示应用进行了微调:
如果你想查看微调后的效果,这里有一个基于 flutter_gemma 示例中的函数训练的模型:sasha-denisov/functiongemma-flutter-gemma-demo。该模型使用 284 个示例训练了 3 个函数(change_background_color、change_app_title 和 show_alert)。准确率显著高于基准模型。
结论
FunctionGemma 是 Google 最小的函数调用专用模型——2.7 亿个参数,288 MB,解码速度约为 126 tok/s。没错,它需要微调(准确率从 58% 提升到 85%),没错,它使用了一种奇怪的自定义格式,而不是 JSON。但它适用于任何手机,响应速度极快,而且确实有效。现在就可以构建带有离线 AI 代理的应用——体积小、速度快、可靠性高,足以满足生产环境的需求。无需等待模型体积更小、设备速度更快的“神奇未来”,未来已来!
Flutter 让这一切变得格外轻松——一套代码库,覆盖所有平台:iOS、Android、Web 和桌面。如果你想更进一步,flutter_gemma 是开源的,我们始终欢迎贡献者。
_本文是我关于移动应用中 AI 实际应用系列文章的一部分。接下来将会是:“完全设备端 RAG — 完整指南” — 订阅即可获取更新。
联系作者: GitHub, LinkedIn, Medium, X
相关链接
- FunctionGemma 模型卡, Google 博客 — FunctionGemma, HuggingFace 上的 FunctionGemma, flutter_gemma, Hammer 2.1, Gemma 3n, LiteRT-LM
欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!
保护原创,请勿转载!