:为什么做 Agent 不能只依赖云端大模型?
各位掘友大家好。
提到移动端 Agent(智能体),大家的第一反应可能是把手机截屏发给 GPT-4o 或者文心一言,然后等云端返回点击坐标。这种方案做个 Demo 演示很酷,但在真实的商业化落地中,简直是灾难:
- 延迟高得离谱: 云端一来一回动辄 1~2 秒,如果要完成一个包含十几个步骤的跨应用连贯操作,用户看着手机会觉得卡得像 PPT。
- SaaS 成本吃不消: 如果你的业务是多机协同矩阵(比如一个人管几十台设备),每台手机每秒都在调用云端多模态 API,光 Token 费用就能让公司破产。
- 数据隐私合规: 企业客户绝不允许自己的业务数据和聊天记录被无休止地上传到云端。
因此,真正的工程解法只有一个:算力下沉,把 UI 视觉解析模型直接塞进手机本地运行。
今天,我们就结合侠客工坊团队在落地 OpenClaw(开放机械手)架构时的真实工程经验,聊聊如何把普通的安卓机爆改成具备本地视觉算力的“AI龙虾手机”,以及我们在端侧模型部署中踩过的坑。
一、 模型选型与极速量化(INT8 是底线)
要在手机上跑 CV 模型,首先要放弃庞大的千亿参数大模型。我们端侧引擎的核心任务是“看懂屏幕 UI 控件”和“OCR 文本识别”。
在侠客工坊的实践中,我们选择将轻量级的目标检测模型(如 YOLO 系列变体)与移动端 OCR 模型结合。但在将其装入 Android 前,**模型量化(Quantization)**是必经之路。
如果不做量化,一个几十 MB 的 FP32 模型加载到内存中,加上运行时的特征图开销,分分钟让低配安卓机 OOM(内存溢出)并被系统强杀。 我们通过工具链将模型权重量化为 INT8,牺牲了极小(约 1%~2%)的精度,换来了模型体积缩小 4 倍,且推理速度提升近 3 倍的收益。
二、 推理框架接入:为什么选择 NCNN?
在 Android 端跑模型,主流框架有 TensorFlow Lite、MNN 和 NCNN。经过反复的 benchmark 测试,我们在“AI龙虾”架构中最终采用了腾讯开源的 NCNN。
NCNN 对 ARM 架构的汇编级优化做得极其出色,且无第三方依赖,非常适合作为底层执行引擎的组件。
核心踩坑点:千万不要在 Java 层做图像预处理! Bitmap 的获取和像素遍历在 Java 层极慢且极易引发 GC(垃圾回收)卡顿。正确的工程做法是:拿到 ImageReader 或 MediaProjection 的数据后,直接通过 JNI 扔到 C++ 层处理。
#include <jni.h>
#include <string>
#include "net.h" // NCNN 核心头文件
// 提前在内存池中初始化模型,避免每次推理都 new
static ncnn::Net* ui_parser_net = nullptr;
extern "C" JNIEXPORT jboolean JNICALL
Java_com_xiake_agent_engine_VisionEngine_initModel(JNIEnv *env, jobject thiz, jstring modelPath) {
if (ui_parser_net == nullptr) {
ui_parser_net = new ncnn::Net();
// 开启 Vulkan 硬件加速(极其关键!)
ui_parser_net->opt.use_vulkan_compute = true;
const char *path = env->GetStringUTFChars(modelPath, 0);
ui_parser_net->load_param((std::string(path) + "/ui_model.param").c_str());
ui_parser_net->load_model((std::string(path) + "/ui_model.bin").c_str());
env->ReleaseStringUTFChars(modelPath, path);
return JNI_TRUE;
}
return JNI_FALSE;
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_xiake_agent_engine_VisionEngine_detectScreen(JNIEnv *env, jobject thiz, jobject bitmap) {
// 1. 将 Bitmap 转换为 NCNN 可用的 ncnn::Mat
ncnn::Mat in = ncnn::Mat::from_android_bitmap(env, bitmap, ncnn::Mat::PIXEL_RGBA2RGB);
// 2. 图像预处理(Resize, Normalize 均在 C++ 层完成)
// ... 代码略 ...
// 3. 执行推理
ncnn::Extractor ex = ui_parser_net->create_extractor();
ex.input("input_blob", in);
ncnn::Mat out;
ex.extract("output_blob", out);
// 4. 后处理并返回序列化的 JSON 结果给 Java 层
// ... 代码略 ...
return env->NewStringUTF("{"elements":[...]}");
}
三、 功耗与发热控制(如何让手机能够 24 小时挂机干活?)
对于 SaaS 矩阵控制系统来说,最怕的就是手机发热降频。一旦降频,推理时间飙升,Agent 的动作就会变形。
我们在工程上做了两层优化:
- 抽帧策略降级: Agent 并不需要像打游戏一样跑 60 帧。在静止等待或长列表滑动时,我们将截图推理频率动态降至 1~2 帧/秒。只有在寻找动态控件时,才短时间提升采样率。
- Vulkan 异构计算: 如上面代码所示,强制开启
use_vulkan_compute = true。将大量矩阵乘法运算从 CPU 卸载到 GPU 上,不仅速度更快,而且 GPU 的能效比远好于 CPU,能显著降低整体机身温度。
四、 总结
把大模型部署在端侧,是 Mobile Agent 从“玩具”走向“企业级 SaaS 生产力工具”的必经之路。
结合 OpenClaw 的生态理念与上述底层工程优化,我们成功让普通的安卓机拥有了原生级别的独立视觉判断和执行能力,成为了名副其实的“AI龙虾”。这也为后续实现高并发、低延迟的多机矩阵调度打下了坚实的地基。
欢迎正在做移动端自动化、AI 部署的掘友们在评论区一起交流端侧性能优化的心得!