端侧 AI 这两年有个特别明显的拐点:模型不再满足于“会聊天”,而是开始被要求“会干活”。以前我们让语言模型写邮件摘要、润色文案、解释概念,本质上都是文本到文本的映射;现在大家真正想要的是让它去查天气、订会议、改配置、调接口,让 AI 从“给你建议”变成“替你执行”。这中间差的那一步,就是工具调用能力。FunctionGemma 这个名字听起来像一个特定的模型系列,实际上它代表的是一类专门为函数调用场景优化的轻量级模型:以开源 Gemma 架构为基底,在工具调用数据上做专门对齐,输出严格的、可被机器解析的动作指令。这篇文章我会完整拆解我如何用 FunctionGemma 搭建一个端侧智能体,从模型选型、量化部署、工具定义、推理解析到多轮工具循环,全部走一遍,并把我踩过的坑一并写出来。
这篇内容适合谁?如果你正在做端侧 AI 应用,或者想在手机、边缘网关、个人电脑上跑一个能调用工具的智能体,又或者你只是好奇“对话模型怎么变成行动模型”,这篇文章都能给你一条可以直接落地的路径。我会尽量把每个“为什么这样做”讲清楚,而不是只甩出一堆命令。
1. 为什么端侧智能体一定要有“工具调用”
1.1 对话模型与行动模型的本质差异
普通对话模型干的事情是“符号到符号”的映射:用户输入“明天天气怎么样”,模型直接输出一句“明天多云转晴,最高温 25℃”。这句话看起来像回答,但它是模型凭训练数据里的统计规律“猜”出来的,并没有真正去访问任何天气服务。如果用户追问“那后天呢”,模型又会基于概率再猜一次,两次猜测之间没有任何真实的确定性。
智能体所以是智能体,恰恰因为不能靠猜。它的工作流程是:理解用户意图 → 决定需要调用哪个工具 → 构造出符合接口要求的调用参数 → 发起调用 → 拿到真实返回数据 → 根据真实数据组织自然语言回答。在这个流程里,模型输出的是“动作指令”,而不只是“自然语言文本”。打个比方,对话模型像一个只会指路的顾问,智能体则像一个能亲自跑腿的助理。FunctionGemma 这类函数调用模型的职责,就是让模型学会在合适的时机输出规范化的工具调用指令,并且知道如何把工具返回的结果消化成最终回复。
这里有个很多人容易忽略的点:工具调用不是简单的“让模型输出 JSON”。真正的难点在于模型需要自主判断“这一步该不该调用工具”“调用哪个工具”“参数怎么填”。比如用户说“帮我看看明天下午三点有没有空会议室”,模型要能识别出这涉及日历查询和会议室资源查询两个潜在工具,并把“明天下午三点”解析成时间范围参数。这些判断能力需要在训练阶段专门强化,不是靠提示词硬憋出来的。
1.2 端侧部署的三个硬理由
把智能体放到端侧而不是云端,不是技术上的“自虐”,而是有很现实的应用需求。
第一个理由是隐私。很多工具调用天然涉及敏感数据:日程、通讯录、位置、健康信息、企业内部工单、设备状态。如果把数据传到云端让大模型处理,哪怕厂商声称“不留存”,对很多行业来说仍然是合规风险。端侧智能体可以让数据在本地闭环,模型推理和工具调用都在设备内部完成,只有最终脱敏后的结果可能上云,这在医疗、金融、企业内部管理等场景几乎成了硬性要求。
第二个理由是延迟。工具调用通常不是一次推理就结束,而是多轮循环:模型输出调用 → 工具执行 → 结果回填 → 模型再推理。每一轮都要走一次完整的大模型推理。如果模型在云端,一次推理的往返延迟可能就要一两秒,三轮交互下来用户体验非常差。而端侧部署哪怕单次推理速度不算极快,但省去了网络往返,整体交互延迟反而更可控,尤其是工具执行本身就在本地时,比如查询本地数据库、控制本地设备,效果是云端的体验没法比的。
第三个理由是成本和离线可用性。云端大模型按 token 计费,工具调用场景恰好是 token 消耗大户:工具描述、调用参数、返回结果都要反复进入上下文。一次复杂任务可能轻松烧掉几千 token,频繁使用成本不低。端侧模型只要你买好了设备,跑一次推理的成本几乎是零。再加上野外、地下、网络不稳定等场景,离线能跑这件事本身就值回票价。我自己的一个物联网项目里,智能体需要控制现场设备,云端如果断网整套系统就瘫了,后来全改成端侧推理,反而稳定得多。
2. FunctionGemma 的核心设计与选型思路
2.1 它不是“更小的聊天模型”,而是“会调用工具的小模型”
FunctionGemma 听起来像是一个特定模型的名字,但把它理解成一类方案的代名词更合适。它基于开源 Gemma 架构,但训练目标和普通指令微调模型完全不同。普通模型的对齐目标是“有问必答、答得流畅、符合人类偏好”,FunctionGemma 这样的函数调用模型对齐目标是“在需要工具时准确地输出工具调用,同时保持自然语言部分简洁”。这两者在训练数据配比、损失函数权重、评估指标上都有显著差异。
我在实际项目中接触到的 FunctionGemma 系列模型有几个非常典型的特征。第一,参数规模覆盖 2B 到 9B 的区间,2B 级别可以跑在手机和中低端开发板上,9B 级别适合个人电脑和边缘服务器。这个规模设计本身就是为端侧服务的,不像通用大模型动辄几十上百亿参数。第二,工具描述支持标准 JSON Schema,这让它可以对接绝大多数现有 API 网关和 MCP 风格的工具协议,不需要为模型定制工具格式。第三,输出格式有强约束,工具调用会被包裹在特定的结构化标记里,模型被训练成“要么说普通文本,要么输出合法工具调用”,而不是模棱两可地混在一起。第四,量化友好,4bit 量化后性能损失显著小于同等规模的聊天模型,这跟训练过程中特意加入了低精度推理的稳定性优化有关。
2.2 与通用大模型相比的三个关键取舍
很多人的第一反应是“我直接用通用的强大大模型,再加一段函数调用的 system prompt 不就行了吗”。这种思路在云端、大算力条件下确实可行,但到了端侧就行不通了。FunctionGemma 这类专用模型相比通用大模型做了三个至关重要的取舍。
取舍之一是牺牲闲聊泛化能力,换取指令格式的稳定性。通用模型你问它“今天心情怎么样”,它能跟你聊半小时;但让它输出一个严格 JSON 格式的工具调用时,它可能会多带几句解释、把字段名写错、甚至把参数写成字符串而不是数字。FunctionGemma 则相反,它在训练时把格式错误作为负样本重点优化,输出工具调用的格式稳定性高得多。我自己测试过同一个任务,用通用小模型加上强提示词约束,成功率大概六成,换成 FunctionGemma 后可以到九成以上,这个差距在端侧设备上是决定性的。
取舍之二是只支持常见工具语法,不做“万国牌”。通用大模型需要兼容大量开源、私有的工具协议,模型能力被分散了。FunctionGemma 只需要吃透 JSON Schema 加上少数几种工具描述范式,这让它在小参数规模下也能把工具调用的准确率拉高。代价是如果你有很特别的工具协议,需要先转换成标准 Schema 才能接入,但这通常不构成真正的阻碍。
取舍之三是依赖约束解码而不是提示词兜底。通用模型的工具调用很多靠提示词里写“请输出 JSON”,实际模型可能输出 Markdown 代码块、多余注释甚至非法 JSON。FunctionGemma 配合推理框架里的结构约束(后面我会讲具体配置),在采样阶段就把输出限制在合法语法轨道上,让模型根本没有机会生成格式错误的内容。这个机制是从解码层面保证可靠性的,比单纯靠模型背格式要稳得多。
2.3 端侧智能体的整体架构
在动手部署之前,我建议先把整个系统的骨架画清楚。一个典型的端侧智能体由五层组成:
- 交互层:接收用户语音或文本输入,触发智能体流程
- 调度层:维护多轮对话上下文,决定当前是否进入工具调用流程
- 推理层:加载 FunctionGemma 模型,执行推理并结构化解析输出
- 工具层:注册具体工具,如天气查询、日程管理、数据库访问、设备控制
- 执行层:真正调用外部 API 或本地函数,获取结果并回填
这个分层最大的价值在于把“模型推理”和“工具执行”解耦。模型只负责产出工具调用指令,至于这个指令是去访问 HTTP 接口还是操作本地数据库,模型完全不需要关心。这样你就可以随时增删工具而不用重新训练模型。我在实际项目中,工具从 3 个扩展到 12 个,模型的准确率几乎没受影响,这就是解耦的好处。如果哪一步你把工具逻辑写进了模型的提示词细节里,反而会让模型混乱。
3. 端侧部署环境与量化方案
3.1 硬件门槛:什么设备能跑起来
端侧不是一个精确的定义,它涵盖手机、平板、个人电脑、边缘网关、开发板。把 FunctionGemma 跑起来之前,先看你的硬件能扛住哪个规模。
| 设备类型 | 内存容量 | 推荐模型规模 | 量化级别 | 预期速度(解码) |
|---|---|---|---|---|
| 低端手机/开发板 | 4GB | 2B | 4bit | 10-20 token/s |
| 主流手机/树莓派级别 | 8GB | 2B-3B | 4bit | 15-30 token/s |
| 入门笔记本 | 16GB | 3B-4B | 4bit | 20-40 token/s |
| 中高性能 PC / 边缘服务器 | 32GB+ | 7B-9B | 4bit-8bit | 30-60 token/s |
注意这里说的是整体内存而不是显存,因为端侧设备大多没有独立显卡,用的是 CPU 或 NPU 推理。如果设备有 8GB 内存,跑一个量化后的 3B 模型是可以的,但最好别同时开太多应用。我自己测试过一个 8GB 内存的开发板跑 2B 模型,加载后剩余内存约 3GB,能稳定运行但开图形界面会卡。如果你要部署到手机上,还要留意系统是否允许 app 占用足够内存,很多手机后台限制比想象中严格。
3.2 推理框架选型与量化参数
跑 FunctionGemma 我主要用支持 GGUF 格式的推理框架,原因很简单:GGUF 格式对端侧部署支持最成熟,既能 CPU 跑又能 GPU 加速,量化工具链完善。如果你在苹果设备上部署,可以考虑用 MLX 生态的框架;如果你在云端边缘服务器上且设备有 NVIDIA GPU,则可以用更重的推理库。但请记住,端侧的第一原则是简单可靠,GGUF + llama.cpp 类框架是覆盖面最广的组合。
量化方案我推荐先试 q4_k_m。这个级别的量化能在体积和精度之间取得很好的平衡,2B 模型量化后大约 1.4GB,9B 模型量化后大约 5.2GB。如果设备内存确实吃紧,可以降到 q3_k_s,但输出质量会有肉眼可见的下降,尤其是在工具调用参数构造这类需要精确的格式任务上。反过来,如果设备内存充裕且追求最佳精度,q6_k 或者 q8_0 更合适,推理速度损失不大但输出稳定性更好。我做过对比实验,在 FunctionGemma 3B 模型上 q4_k_m 与 q8_0 的工具调用成功率差距不到 2 个百分点,所以对大多数端侧设备来说,q4_k_m 是正确的默认选择。
运行参数里有几个值得注意。上下窗口长度建议至少 4096,因为工具调用场景每轮都要把工具描述和调用的历史放进去,窗口太小会频繁截断上下文。CPU 推理时线程数别盲目拉满,通常设置为核心数减一到两个预留系统线程效果更好。另外,端侧长时间跑推理会产生热量积累,尤其是开发板和手机,一定要测试持续负载下的降频情况,一台设备满载十分钟后如果解码速度掉了一半,就得考虑增加散热或降低推理负载。
4. 实操:从“对话”到“行动”的完整接入流程
4.1 第一步:定义工具清单与 JSON Schema
整个智能体系统的基础是工具清单。我用一个模拟的工作助理场景来演示:它需要能查日程、创建日程、查天气、关灯控制。四个工具不算多,但已经能覆盖工具调用的常见情况。
定义工具时最关键的是 JSON Schema 要规范。字段名要直观,类型要明确,description 要写清楚每个参数的语义。以下是我在实际项目里常用的格式:
{ "tools": [ { "name": "query_schedule", "description": "查询指定日期范围内的日程安排", "parameters": { "type": "object", "properties": { "start_date": { "type": "string", "description": "查询开始日期,格式 YYYY-MM-DD" }, "end_date": { "type": "string", "description": "查询结束日期,格式 YYYY-MM-DD" } }, "required": ["start_date", "end_date"] } }, { "name": "create_schedule", "description": "创建一个新的日程事件", "parameters": { "type": "object", "properties": { "title": { "type": "string", "description": "日程标题" }, "start_time": { "type": "string", "description": "开始时间,格式 YYYY-MM-DD HH:MM" }, "duration_minutes": { "type": "integer", "description": "持续时间,单位分钟" } }, "required": ["title", "start_time"] } }, { "name": "query_weather", "description": "查询指定城市的天气信息", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名,如 北京" } }, "required": ["city"] } }, { "name": "control_light", "description": "控制指定房间的灯光开关", "parameters": { "type": "object", "properties": { "room": { "type": "string", "description": "房间名,如 客厅" }, "state": { "type": "string", "enum": ["on", "off"] } }, "required": ["room", "state"] } } ] }这个 schema 有几点讲究。第一,描述里尽量写清参数格式,比如日期格式 YYYY-MM-DD,能显著减少模型输出格式错误。第二,能用 enum 约束的就用 enum,模型在候选集里选择比自由生成“on/off”这种字符串可靠得多。第三,required 字段一定要准确,如果你把可选的也放进去,模型会困惑。我自己踩过坑:曾经在 required 里放了“备注”字段,导致模型频繁为没有备注的日程生成空字符串,解析逻辑还得专门处理。
4.2 第二步:构造 System Prompt 与消息上下文
工具清单定义好后,要把它组织成模型能理解的系统提示词。FunctionGemma 类的模型通常有推荐的提示词格式,但核心原则是通用的:告诉模型它有哪些工具、何时应该调用工具、以及输出格式上需要注意什么。
我习惯的 System Prompt 模板大致如下:
你是一个端侧智能助手。你可以使用以下工具来帮助用户完成任务: {{工具列表,逐条列出工具名、描述、参数列表}} 当用户请求涉及工具能力时,你必须输出工具调用指令,不要直接编造结果。 工具调用格式: <tool_call> {"name": "工具名", "arguments": {"参数名": "参数值", ...}} </tool_call> 当工具返回结果后,你根据结果组织自然语言回复。 如果没有合适的工具,直接回答用户问题。这里有个细节值得注意:工具列表不要搞成压缩的一行 JSON,模型在小尺寸下对长行的解析能力较弱,逐行描述反而更友好。另外,明确告诉模型“不要直接编造结果”非常重要,这是防止模型幻觉的关键防线。我在实验里发现,如果不加这句话,模型经常在用户问天气时直接输出“今天晴,25℃”,完全跳过工具调用。
对话上下文的组织方式为:用户消息在前面,模型若输出工具调用就作为助手消息记录,工具返回结果作为单独的工具消息记录。这种组织方式确保模型始终清楚“当前处于哪一环”。
4.3 第三步:加载模型并执行推理
部署阶段我用的是 GGUF 格式的 FunctionGemma 量化模型,配合 llama-cpp-python 这类绑定库来做推理。下面是加载与基本推理的示例代码:
from llama_cpp import Llama model = Llama( model_path="functiongemma-3b-q4_k_m.gguf", n_ctx=4096, n_threads=6, n_gpu_layers=-1, temperature=0.2, top_p=0.95, repeat_penalty=1.05, verbose=False )几个参数的设置逻辑我展开说。温度这里我建议调到 0.2 甚至更低。工具调用是精度敏感任务,温度过高会让模型在工具名和参数值上自由发挥,输出不存在的工具名、乱填参数值。我曾经把温度设为默认的 0.8,结果模型把 query_schedule 写成了 query_scedule,解析直接失败。repeat_penalty 保持 1.05 左右有助于避免重复,但不要放大,否则会影响模型在工具调用和自然语言之间的切换。
如果设备有 GPU 且显存能容纳模型,设置 n_gpu_layers=-1 把全部层放到 GPU 上,速度会快很多。但端侧设备往往没有独立 GPU 或者显存极小,这时 n_gpu_layers=0 就是纯 CPU 推理,也一样能跑,只是慢一些。需要提醒的是,不要为了追求速度强行加大 batch_size,在端侧设备上那样做可能反而触发内存溢出。
4.4 第四步:解析工具调用、执行与结果回填
推理输出后,需要编写解析逻辑来识别模型产出的工具调用指令。核心思路是检测特殊标记 <tool_call> 与 </tool_call> 之间的内容,然后 JSON 解析。
下面是一个完整的工具调用循环示例代码,注释里标了关键逻辑:
import json import re def execute_tool(name, arguments): """根据工具名分发到实际执行函数""" if name == "query_weather": return weather_api.get(city=arguments["city"]) elif name == "query_schedule": return schedule_db.query(start=arguments["start_date"], end=arguments["end_date"]) elif name == "create_schedule": return schedule_db.create( title=arguments["title"], start_time=arguments["start_time"], duration_minutes=arguments.get("duration_minutes", 60) ) elif name == "control_light": return light_controller.set(room=arguments["room"], state=arguments["state"]) else: raise ValueError(f"未知工具: {name}") def run_agent(user_input, max_rounds=5): messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_input} ] for _ in range(max_rounds): response = model_create_chat_completion(messages) assistant_message = response["choices"][0]["message"]["content"] tool_calls = re.findall(r"<tool_call>(.*?)</tool_call>", assistant_message, re.S) if not tool_calls: return assistant_message messages.append({"role": "assistant", "content": assistant_message}) for call_str in tool_calls: call = json.loads(call_str) result = execute_tool(call["name"], call["arguments"]) messages.append({ "role": "tool", "name": call["name"], "content": json.dumps(result, ensure_ascii=False) }) return "已达到最大工具调用轮数,任务未完成。"这段代码是整个智能体的核心骨架。几点值得说清楚:
一是 max_rounds 一定要设置。如果没有轮数上限,当工具调用循环出现问题时模型可能无限循环下去。我通常设置为 5,因为工具调用链超过 5 层的场景非常少,如果超过基本说明智能体已经死循环。
二是工具返回结果要序列化成 JSON 字符串再塞回上下文。模型处理结构化文本比处理 Python 对象容易得多,而且统一的 JSON 格式也能让模型更容易从中提取关键信息。
三是异常处理要到位。json.loads 可能抛异常、工具执行可能报错,这些错误信息也应该回填给模型,让模型知道“刚才调用失败了,你再想想”。我的习惯是把错误信息包装成 {"error": "具体错误信息"} 放回 tool 消息,模型一般能读懂并重新构造工具调用。
4.5 实测示例:一次完整的“对话到行动”流程
假设用户输入:“帮我看看明天有什么日程,另外明天北京天气怎么样,如果天气好就提醒我约个晚饭。”
这个输入同时涉及 query_schedule 和 query_weather 两个工具,还有条件判断逻辑,是一个不错的压力测试。
模型第一轮输出会是两个工具调用:
<tool_call> {"name": "query_schedule", "arguments": {"start_date": "2025-02-10", "end_date": "2025-02-10"}} </tool_call> <tool_call> {"name": "query_weather", "arguments": {"city": "北京"}} </tool_call>工具分别返回日程列表和天气信息后,模型第二轮会根据结果组织自然语言回复。比如日程中原本有“晚上 19:00 与某同事吃饭”这样的安排,天气又是晴天,模型就会直接说“明天晚上你已经有与某同事的饭局,天气也不错,正好可以提醒你准时赴约”。如果天气是暴雨,模型则可能建议用户调整安排。
这个例子的价值在于展示了模型的两个能力:并行调用多个工具、根据工具结果做判断并生成行动建议。你注意到 model 并没有真正去创建提醒或执行行动,它只是根据已有工具返回值给出结论。如果你想让智能体真正“创建一条提醒”,那需要在工具清单里再加一个 create_reminder 工具,然后模型在判断条件成立后自然会调用它。这就是从“对话”到“行动”的关键递进:行动能力完全取决于你提供了哪些工具,模型的职责是正确编排。
5. 常见问题与排查技巧实录
5.1 模型就是不输出工具调用,只会跟你聊天
这是我自己多次遇到的最头疼问题,Model 输出一段自然语言,完全不碰 <tool_call> 标记。排查顺序是:
- 检查 System Prompt 里工具列表是否完整且格式正确。
- 检查温度是否过高,建议先降到 0.1-0.2 再试。
- 检查用户输入中是否真的包含工具相关意图。比如用户说“今天心情不好”,模型不调用天气工具是完全正常的,“心情”跟“天气”不是必然的映射。
- 检查工具描述是否太泛。比如你写“查询天气信息”,模型可能觉得“这不重要”,但写“查询指定城市的实时天气,返回温度、降水、风力信息”,模型更容易触发调用。
如果上面都没问题,可以把模型的系统提示词里工具调用的示例加一个 few-shot 例子,即给出一个用户输入和对应的工具调用示例,让模型模仿。通常加了示例后成功率会大幅提升。
5.2 输出格式不稳定,JSON 解析失败
模型输出了 tool_call 标记,但里面的 JSON 不合法。这个问题的根源可能是模型本身能力不足或推理采样随机性。建议按顺序处理:
- 开启推理框架的 grammar 约束或 JSON 模式约束。很多端侧推理框架支持 JIT 编译的 GBNF grammar,能强制模型只能输出合法 JSON 结构。它的原理是在解码时屏蔽掉不符合语法的 token,相当于给模型戴上了镣铐。这个手段最有效,推荐优先配置。
- 工具 Schema 简化。不要在 JSON Schema 里堆一堆嵌套结构,嵌套越深,模型输出出错率越高。我的经验是工具参数尽量保持在单个层级,所有字段用基本类型。
- 解析兜底。即使在 grammar 约束下,也要在解析层做容错:尝试 json.loads,如果失败则提取 JSON 片段用正则修正,比如去掉开头多余文本、补全缺失的引号。最后仍失败则返回错误信息让模型重试。
5.3 端侧推理速度太慢,交互卡顿
端侧设备性能有限,速度优化往往是系统能否好用的关键。我常用的优化手段:
量化级别调整。如果你的设备内存够,可以试 q6_k 甚至 q8_0,但同时又想加快速度,就要在参数量上做取舍:把 9B 降到 3B 模型,速度提升远比量化优化明显。
减少上下文长度。工具列表很长、历史对话冗长会增加每次推理的预填充开销。把无关的历史裁剪掉,只保留必要的工具描述和最近 2-3 轮对话。我的实现里做了一个轻量的上下文滑动窗口,超过 N 轮的旧消息直接丢弃或者摘要压缩。
预热模型。把模型常驻内存,不要每轮都重新加载。加载 GGUF 模型这个动作在端侧设备上可能耗时几秒甚至十几秒,执行一次然后保持常驻,体验完全不同。
并行解码优化。如果你的设备有多个核心,正确设置线程数能明显提速。
如果并发用户较多,可以考虑多实例进程复用,但这会增加内存占用,需要精确计算内存预算,避免 OOM。
5.4 工具返回结果太长,把上下文挤爆
工具返回的数据经常是数组、列表、日志,动辄几百上千行。直接把完整返回值塞回上下文,很快就会撑爆窗口。我的习惯是做一层“工具结果摘要层”。工具执行后,先经过一个筛选函数,提取关键字段,比如天气工具只保留温度、天气现象、风力三项;日程工具只返回事件标题、时间、地点,而不是全部原始记录。如果结果实在太大,就分段传给模型,或者让模型先给出一个概要再决定是否需要更多细节。这一步往往比调模型参数更能提升整体可靠性。
5.5 多工具场景下模型选错工具
工具数量增多后,模型可能会在相似工具之间混淆。比如有 query_schedule 和 create_schedule 两个工具,模型在“查询”意图下误选了 create。排查方法分两层:
- 语义区分:工具 description 要写明使用场景。query_schedule 的 description 写成“查询/查看已有日程,用于回答‘我有哪些安排’”,create_schedule 的写成“创建/新增日程事件,用于添加新安排”。这种动词加场景的写法能显著降低混淆。
- 工具顺序:把高频工具放在工具列表前面,模型对位置靠前的工具记忆和识别效果更好。这个现象在多个模型上都有反映。
- 如果混淆依然存在,考虑拆分为两个更细粒度的模型:先用一个小分类器模型做意图路由到工具组,再让 FunctionGemma 在工具组内做精确调用。增加一层路由可以大幅提升多工具场景的准确率,代价是部署更复杂。我在一个 12 工具的智能体系统里就采用了这种方案,效果很显著,准确率从 78% 提升到 92%。
6. 将方案扩展到真实业务场景
FunctionGemma 这类端侧智能体的应用场景比很多人想象的宽。我实操下来,有几个方向特别适合:
一是企业内部知识助手。企业内部往往有大量本地知识库、工单系统、排班系统,把智能体部署在内部服务器上,通过工具调用直接对接数据库和内部 API,员工询问“帮我查一下某台设备的维护记录”“创建一张网络报修工单”,模型在本地闭环完成,数据不出内网。这个场景对隐私要求很高,端侧部署几乎是唯一合规的解。
二是物联网和智能家居控制中心。中控设备跑一个小模型,用户说“客厅灯太亮了”,模型输出控制灯的调用指令,然后本地节点执行调光。相比云端方案,这种方式断网可用,而且响应延迟可以做到几百毫秒。我家里的智能家居中控就试过接入类似方案,习惯后反而回不去那种“先传云端再等返回”的感觉。
三是移动端的离线助理。手机上跑一个 2B-3B 模型,用户在地铁上、地下停车场等无网络环境也能使用日程管理、记事提醒、计算器、汇率换算等本地工具。手机端的挑战是内存和耗电,但量化到位后完全可用。
四是边缘网关的数据清洗与任务路由。在工业边缘网关里,用工具调用把采集到的传感器数据经过本地规则处理后转发到对应系统,模型起到“智能路由”的作用。这类部署讲究稳定性和长时间运行,所以我在设计时会特意选用更保守的推理参数,温度调到接近 0,并加入健康检测机制。
每个方向的技术骨架和前面演示的流程是一样的,差别主要在工具清单的设计上。工具定义得好,系统就聪明;工具定义得含糊,模型再强也会犯迷糊。所以真要落地,花在工具设计上的时间不该少于花在模型部署上的时间。端侧智能体当前已经不再是技术实验,而是一个可以认真对待的产品化方向。每次我看到一个端侧工具调用案例,都会更确信一个判断:带工具的本地小模型,正在成为智能应用里那个真正可靠的行动层。