Cactus 绑定(Binding)选型完全指南:React Native / Flutter / Kotlin / Swift / Python / Rust / CLI / C++ 对比与集成实战

原创2026-10-09 14:41:111,735 阅读
文章标签:推理引擎模型推理服务算子库模型量化边缘计算

Cactus 绑定(Binding)选型完全指南:React Native / Flutter / Kotlin / Swift / Python / Rust / CLI / C++ 对比与集成实战

本指南是 Cactus 端侧 AI 推理引擎的官方绑定选型文档。Cactus 是一个面向移动端、可穿戴设备、智能家居与机器人场景的量化、内核、运行时与推理引擎,所有绑定都以 cactus_engine.h 提供的 C FFI 为统一底座。读完本文,你将能根据目标平台(iOS / Android / macOS / Arm Linux)和开发语言,快速判断该选 React Native、Flutter、Kotlin、Swift、Python、Rust、CLI 还是 C++,并掌握每种绑定的安装、集成、首次推理与流式转录的完整代码路径。

一、能力总览:八种绑定,一套能力矩阵

Cactus 的核心设计是:底层只有一份 C FFI 接口(定义在 cactus_engine.h),所有高级语言绑定都是围绕这份接口的薄封装。这意味着无论你选择哪种绑定,能调用的能力完全一致——LLM 文本生成、流式输出、视觉(VLM)、音频理解、语音转录、Function Calling、RAG / Embeddings、云端回退(Cloud Fallback)全部可用。

React Native Flutter Kotlin Swift Python Rust CLI C++
平台 iOS, Android iOS, Android, macOS Android, iOS (KMP) iOS, macOS Arm Linux, macOS Arm Linux, macOS macOS, Arm Linux Arm Linux, macOS, iOS, Android
安装 build / source build build build pip build / source brew / source header
LLM ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
流式输出 ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
视觉(Vision) ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
音频(Audio) ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
转录(Transcription) ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
Function Calling ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
RAG / Embeddings ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
云端回退(Cloud Fallback) ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅

从实现层面看,bindings/README.md 明确记录了各绑定的 FFI 机制差异:

  • python/ 使用 ctypes
  • swift/ 使用 C module map
  • kotlin/ 在 Android 上用 JNI、在 iOS 上用 Kotlin/Native cinterop(KMP)
  • flutter/ 使用 Dart FFI
  • rust/ 使用裸 extern "C" 声明
  • react-native/ 是建立在原生 Kotlin 与 Swift 绑定之上的薄桥接层

而平台原生构件(Android 的 .so、Apple 的 .a / XCFramework)统一由 android/ 与 apple/ 两个目录构建,各绑定共享同一批产物。

二、快速推荐:按场景三秒定位

正在开发移动 App?

  • React Native —— 已有 React Native 工程?直接 npm install 即可接入,桥接层最薄
  • Flutter —— 跨平台移动端 + macOS 全覆盖,提供完整原生绑定
  • Kotlin —— 原生 Android 应用或 Kotlin Multiplatform 项目
  • Swift —— 原生 iOS/macOS 应用,可直接享受 Metal 加速

服务端或脚本场景?

  • Python —— 服务端推理、批处理、快速原型验证
  • CLI —— 免写代码即可快速测试模型、进入交互式会话

嵌入原生应用?

  • C++ —— 游戏引擎、原生桌面应用或任何 C/C++ 项目,直接包含头文件
  • Rust —— 需要安全 FFI 的系统级集成

三、逐绑定详解:安装、集成与首段推理

所有绑定都要求先在本机完成 Cactus 环境搭建(source ./setup,脚本见仓库根目录 setup)。构建命令 cactus build 会生成各平台的原生产物,随后按语言接入。

3.1 React Native:已有 RN 工程的最快路径

安装与集成(见 bindings/react-native/README.md):

cactus build --apple
cactus build --android

集成共三步:把本目录的桥接文件加入 RN 工程;加入它们依赖的原生绑定——bindings/kotlin/(Android 侧)、bindings/swift/(Apple 侧);在 MainApplication.kt 注册 Android 包:

override fun getPackages() = PackageList(this).packages.apply {
    add(com.cactus.reactnative.CactusPackage())
}

首次推理:TypeScript 侧的接口定义见 bindings/react-native/index.ts,init / complete / destroy 均为 Promise 化调用,handle 为字符串形式的句柄:

import Cactus from './index';

const handle = await Cactus.init('/path/to/model', null, false);
const result = await Cactus.complete(handle, messagesJson, null, null, null, false);
await Cactus.destroy(handle);

从 index.ts 的 CactusNativeModule 接口可以看出,React Native 绑定完整暴露了引擎能力:prefill、tokenize、scoreWindow、transcribe、streamTranscribe*、embed / imageEmbed / audioEmbed、ragQuery、index* 向量索引系列、日志与遥测。还提供了 CactusEvents(NativeEventEmitter)用于接收 {token, tokenId} 类型的流式 token 事件。

流式转录:按 16 kHz 单声道 PCM16(base64 编码)持续推送音频块,每次调用返回 {"success":true,"confirmed":...,"pending":...}(confirmed 为最终结果,pending 为易变尾部,仅用于实时预览):

const stream = await Cactus.streamTranscribeStart(handle, '{"language":"en"}');
for (const chunkBase64 of pcmChunks) {
  const json = await Cactus.streamTranscribeProcess(stream, chunkBase64);
  // 解析 json -> 追加 "confirmed",将 "pending" 作为实时预览展示
}
const tail = await Cactus.streamTranscribeStop(stream);

3.2 Flutter:Dart FFI 直连 C 接口

安装与集成(见 bindings/flutter/README.md):

cactus build --apple
cactus build --android

集成四步走:

  1. 将 android/libcactus_engine.so 复制到应用的 jniLibs/arm64-v8a/
  2. iOS 工程中加入 apple/cactus-ios.xcframework
  3. macOS 工程中加入 apple/cactus-macos.xcframework
  4. 将 cactus.dart 复制进 Dart 源码树,并在 pubspec.yaml 添加 ffi 依赖

绑定实现位于 bindings/flutter/cactus.dart:Android / Linux 平台通过 DynamicLibrary.open('libcactus_engine.so') 加载动态库,Apple 平台则使用 DynamicLibrary.process() 链接静态产物,随后以 lookupFunction 逐一绑定 cactus_init、cactus_complete、cactus_destroy 等符号。

首次推理:注意 Dart FFI 的内存管理——toNativeUtf8() 分配的原生内存必须用 calloc.free 释放:

import 'dart:ffi';
import 'cactus.dart';
import 'package:ffi/ffi.dart';

final modelPath = '/path/to/model'.toNativeUtf8();
final model = cactusInit(modelPath, nullptr, false);
calloc.free(modelPath);

const messagesJson = '[{"role":"user","content":"Hello"}]';
final msgs = messagesJson.toNativeUtf8();
final buf = calloc<Int8>(65536);
cactusComplete(model, msgs, buf.cast(), 65536, nullptr, nullptr, nullptr, nullptr, nullptr, 0);
final response = buf.cast<Utf8>().toDartString();
calloc.free(msgs);
calloc.free(buf);
cactusDestroy(model);

流式转录:与 C API 的 cactus_stream_transcribe_* 三函数一一对应:

final opts = '{"language":"en"}'.toNativeUtf8();
final stream = cactusStreamTranscribeStart(model, opts);
final out = calloc<Int8>(65536);
for (final chunk in pcmChunks) { // 每块:16 kHz 单声道 PCM16 字节
  final p = calloc<Uint8>(chunk.length)..asTypedList(chunk.length).setAll(0, chunk);
  cactusStreamTranscribeProcess(stream, p, chunk.length, out.cast(), 65536);
  calloc.free(p);
  // 从 out.cast<Utf8>().toDartString() 解析 {"confirmed":...,"pending":...}
}
cactusStreamTranscribeStop(stream, out.cast(), 65536);
calloc.free(opts);
calloc.free(out);

3.3 Kotlin:原生 Android + Kotlin Multiplatform

安装与集成(见 bindings/kotlin/README.md):

cactus build --android
  1. 将 android/libcactus_engine.so 复制到 app/src/main/jniLibs/arm64-v8a/
  2. 将 Cactus.kt 和 CactusCallbacks.kt 复制进 Kotlin 源码树

JNI 声明位于 bindings/kotlin/Cactus.kt:CactusJNI 对象在 init {} 块中执行 System.loadLibrary("cactus_engine"),随后以 @JvmStatic external 声明全套 native 方法。该 JNI 桥本身(android/cactus_jni.cpp,编译进 libcactus_engine.so)与 JVM 语言无关——Java 消费方完全可以自己写一份与 Cactus.kt 签名等价的 CactusJNI.java(native 声明匹配 Java_com_cactus_CactusJNI_* 符号),同一份库、同一组符号。

首次推理(Android):

val handle = CactusJNI.nativeInit("/path/to/model", null, false)
val buf = ByteArray(65536)
CactusJNI.nativeComplete(handle, messagesJson, buf, null, null, null, null)
val response = String(buf, 0, buf.indexOf(0))
CactusJNI.nativeDestroy(handle)

流式转录(Android)——推入 16 kHz 单声道 PCM16,每次调用读回 {"success":true,"confirmed":...,"pending":...}:

val stream = CactusJNI.nativeStreamTranscribeStart(handle, "{\"language\":\"en\"}")
val out = ByteArray(65536)
for (chunk in pcmChunks) { // 每块:16 kHz 单声道 PCM16 字节
    CactusJNI.nativeStreamTranscribeProcess(stream, chunk, out)
    // 从 String(out, 0, out.indexOf(0)) 解析 confirmed / pending
}
CactusJNI.nativeStreamTranscribeStop(stream, out)

Kotlin Multiplatform(KMP):源码按 expect/actual 结构组织——

commonMain/  Cactus.common.kt     expect 声明
commonMain/  CactusCallbacks.kt   共享回调接口
androidMain/ Cactus.android.kt    actual:JNI 实现
iosMain/     Cactus.ios.kt        actual:cinterop 实现

build.gradle.kts 配置:Android target 之外,为 iosArm64() 与 iosSimulatorArm64() 分别配置 cinterop(def 文件指向 cactus.def,includeDirs 指向 cactus-engine 目录)与框架链接(-L/path/to/cactus/apple 下分别链接 libcactus_engine-device / libcactus_engine-simulator):

kotlin {
    androidTarget()

    listOf(iosArm64(), iosSimulatorArm64()).forEach { target ->
        target.compilations.getByName("main") {
            cinterops {
                val cactus by creating {
                    defFile("src/nativeInterop/cinterop/cactus.def")
                    includeDirs("/path/to/cactus/cactus-engine")
                }
            }
        }
        val libSuffix = if (target.name == "iosSimulatorArm64") "simulator" else "device"
        target.binaries.framework {
            linkerOpts("-L/path/to/cactus/apple", "-lcactus_engine-$libSuffix")
        }
    }
}

共享代码中的用法:KMP 模式下暴露的是与 C API 同名的函数风格 API:

val model = cactusInit("/path/to/model", null, false)
val result = cactusComplete(model, messagesJson, null, null, null, null)

// 流式转录:启动、喂入 PCM16 块、停止
val stream = cactusStreamTranscribeStart(model, "{\"language\":\"en\"}")
val out = cactusStreamTranscribeProcess(stream, pcmChunk)   // {"success":true,"confirmed":...,"pending":...}
val tail = cactusStreamTranscribeStop(stream)

cactusDestroy(model)

3.4 Swift:原生 Apple 平台 + Metal 加速

安装与集成(见 bindings/swift/README.md):

cactus build --apple

集成有两条路线:

  • XCFramework(推荐):将 apple/cactus-ios.xcframework(或 apple/cactus-macos.xcframework)拖入 Xcode 并 Embed & Sign。框架内已捆绑 cactus_engine.h,因此 import cactus 可直接使用。
  • 静态库:链接 apple/libcactus_engine-device.a(或 apple/libcactus_engine-simulator.a),把 bindings/swift/module.modulemap 复制进工程,并在 Header Search Paths 中加入 cactus-engine/,使 module map 能找到 cactus_engine.h。

首次推理:Swift 侧通过 C module map 导入,函数名采用下划线式 C 命名:

import cactus

let model = cactus_init("/path/to/model", nil, false)
var buf = CChar
cactus_complete(model, messagesJson, &buf, buf.count, nil, nil, nil, nil, nil, 0)
let response = String(cString: buf)
cactus_destroy(model)

流式转录:流式函数以同样的方式暴露,推入 16 kHz 单声道 PCM16 并读回 {"success":true,"confirmed":...,"pending":...}:

let stream = cactus_stream_transcribe_start(model, "{\"language\":\"en\"}")
var buf = CChar
for chunk in pcmChunks {            // 每块:16 kHz 单声道 16-bit PCM
    chunk.withUnsafeBytes { raw in
        _ = cactus_stream_transcribe_process(stream, raw.bindMemory(to: UInt8.self).baseAddress, raw.count, &buf, buf.count)
    }
    // 解析 String(cString: buf) -> 追加 "confirmed",实时展示 "pending"
}
cactus_stream_transcribe_stop(stream, &buf, buf.count)

3.5 Python:ctypes 绑定,服务端与原型验证首选

安装(见 bindings/python/README.md):绑定模块位于 python/cactus/bindings/cactus.py,通过 ctypes 加载 libcactus_engine.{so,dylib}——优先从 /python/cactus/bindings/lib/(随包分发)加载,开发构建则从 cactus-engine/build/ 加载,产物由 cactus build --python 生成。

git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup
cactus build --python

配套命令(详见 python/README.md):

# 下载预构建模型 bundle
cactus download LiquidAI/LFM2-VL-450M
cactus download openai/whisper-small

# 可选:配置 Cactus Cloud API Key 以启用自动云端回退
cactus auth

首次推理:Python 绑定采用模块级函数并直接镜像 C FFI,模型句柄是普通的 int(即 C 指针值):

from cactus import ensure_model, cactus_init, cactus_complete, cactus_destroy
import json

# 若本地没有预构建 bundle,则自动从 HuggingFace 下载
bundle = ensure_model("LiquidAI/LFM2-VL-450M")

model = cactus_init(str(bundle), None, False)
messages = json.dumps([{"role": "user", "content": "What is 2+2?"}])
result = cactus_complete(model, messages, None, None, None)
print(result["response"])
cactus_destroy(model)

Python 绑定是能力最全的封装之一:cactus_complete 返回的 dict 包含 success、error、cloud_handoff、response、可选 thinking(模型输出思维链内容时出现,位于 function_calls 之前)、function_calls、segments、confidence、计时统计(time_to_first_token_ms、total_time_ms、prefill_tps、decode_tps、ram_usage_mb)与 token 计数(prefill_tokens、decode_tokens、total_tokens)。此外还覆盖 prefill(预填充 KV cache 以降低后续首 token 延迟)、transcribe、流式转录、文本/图像/音频 Embedding、tokenize、rag_query、向量索引 index_* 全系列,以及日志与遥测接口。

流式转录:confirmed 词为最终结果(追加进转录文本),pending 为易变尾部(每次调用替换,仅用于实时展示):

stream = cactus_stream_transcribe_start(model, {"language": "en"})
transcript = ""
for chunk in pcm_chunks:                       # 每块:16 kHz 单声道 16-bit PCM 字节
    out = cactus_stream_transcribe_process(stream, chunk)
    transcript += out["confirmed"]             # 将 out["pending"] 单独作为实时预览展示
transcript += cactus_stream_transcribe_stop(stream)["confirmed"]

3.6 Rust:裸 extern "C" FFI,系统级安全集成

安装与集成(见 bindings/rust/README.md):

cactus build

将 bindings/rust/cactus.rs 复制进你的工程(它自带 #[link] 属性),并通过 build.rs 把 Cargo 指向构建目录:

// build.rs
println!("cargo:rustc-link-search=native=/path/to/cactus/cactus-engine/build");

首次推理:全部调用都在 unsafe 块内进行,内存与 C 侧保持一致:

use std::ffi::CString;
use std::os::raw::c_char;

mod cactus;

fn main() {
    unsafe {
        let path = CString::new("/path/to/model").unwrap();
        let model = cactus::cactus_init(path.as_ptr(), std::ptr::null(), false);

        let messages = CString::new(r#"[{"role":"user","content":"Hello"}]"#).unwrap();
        let mut response = vec![0u8; 65536];
        cactus::cactus_complete(
            model,
            messages.as_ptr(),
            response.as_mut_ptr() as *mut c_char,
            response.len(),
            std::ptr::null(), std::ptr::null(),
            None, std::ptr::null_mut(),
            std::ptr::null(), 0,
        );

        cactus::cactus_destroy(model);
    }
}

流式转录:同样全部 unsafe:

let opts = CString::new(r#"{"language":"en"}"#).unwrap();
let stream = cactus::cactus_stream_transcribe_start(model, opts.as_ptr());
let mut buf = vec![0u8; 65536];
for chunk in pcm_chunks { // 每块:16 kHz 单声道 i16 字节
    cactus::cactus_stream_transcribe_process(
        stream, chunk.as_ptr(), chunk.len(),
        buf.as_mut_ptr() as *mut c_char, buf.len(),
    );
    // 追加 "confirmed";将 "pending" 作为实时预览展示
}
cactus::cactus_stream_transcribe_stop(stream, buf.as_mut_ptr() as *mut c_char, buf.len());

3.7 CLI:免写代码的模型测试与交互会话

CLI 是覆盖 macOS 与 Arm Linux 的命令行入口,安装方式分 Homebrew 与源码两种(见 docs/quickstart.md):

# Homebrew(macOS)
brew install cactus-compute/cactus/cactus

# 源码安装(macOS)
brew install cmake
git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup && cactus build --python

# 源码安装(Linux)
sudo apt-get install python3.12 python3.12-venv python3-pip cmake build-essential libcurl4-openssl-dev
git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup && cactus build --python

运行一次推理只需一行命令:

cactus run <model|path>

CLI 还提供 cactus download <model> 下载预构建 bundle、cactus transcribe 做文件转录(一次性 + 流式,见 docs/cactus_engine.md),以及 cactus auth 配置云端回退密钥等子命令(源码位于 python/cactus/cli/)。

3.8 C++:直接 C FFI,最大控制力

C++ 绑定不经过任何中间层,直接包含头文件即可:

#include <cactus_engine.h>

在 cactus-engine/ 下按 CMake 构建说明编译。支持平台最广:Arm Linux、macOS、iOS、Android 全平台。

首次推理:使用 cactus_init 传入模型路径(可同时传入 RAG 语料目录),再用 cactus_complete 完成推理,响应写入用户提供的缓冲区:

#include <cactus_engine.h>

cactus_model_t model = cactus_init(
    "path/to/weight/folder",
    "path/to/rag/documents",   // RAG 语料目录,可为 NULL
    false                      // false = 总是重建索引,true = 有缓存则加载
);

const char* messages = R"([
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "What is the capital of France?"}
])";

char response[4096];
int result = cactus_complete(
    model, messages, response, sizeof(response),
    nullptr, nullptr, nullptr, nullptr,   // options / tools / callback / user_data 均可为 NULL
    nullptr, 0                            // PCM 音频缓冲,未使用则 NULL / 0
);

完整的函数签名、类型与参数注释见 cactus-engine/cactus_engine.h 与 docs/cactus_engine.md。核心句柄类型包括 cactus_model_t(模型实例)、cactus_index_t(向量索引实例)、cactus_stream_transcribe_t(流式转录会话),以及 cactus_token_callback(流式 token 回调)与 cactus_log_callback_t(日志回调)。

四、背后的统一架构:一份 C FFI,八种语言绑定

理解 Cactus 绑定体系的关键在于它"一次定义、处处调用"的 FFI 架构,从源码结构看可以明确梳理出四层:

  1. C 引擎层:cactus_engine.h 定义全部 40+ 个导出符号(CACTUS_FFI_EXPORT),覆盖模型生命周期(cactus_init / cactus_destroy / cactus_reset / cactus_stop)、推理(cactus_complete / cactus_prefill)、分词(cactus_tokenize / cactus_score_window / cactus_render_prompt)、转录(cactus_transcribe / cactus_stream_transcribe_*)、Embedding(cactus_embed / cactus_image_embed / cactus_audio_embed)、RAG(cactus_rag_query)、向量索引(cactus_index_*)以及日志与遥测。

  2. 平台原生构件层:android/ 产出 libcactus_engine.so,apple/ 产出静态库(libcactus_engine-device.a / libcactus_engine-simulator.a)与 XCFramework。这一层对上层语言完全透明——你只需要把对应文件放进工程。

  3. 语言 FFI 层:各绑定按语言惯例选择机制——Python 用 ctypes、Dart 用 lookupFunction、Kotlin 用 JNI external 声明、Swift 用 C module map、Rust 用 extern "C"、React Native 用 NativeModules 桥接。

  4. 调用方应用层:所有绑定最终都围绕同一套"句柄 + JSON 消息"约定编程——模型句柄是不透明指针,messages / options / tools 一律是 JSON 字符串,响应写入调用方提供的缓冲区,返回字节数(负数表示错误,可用 cactus_get_last_error() 查询详情)。

以 C++ 为例,cactus_init 的第三个参数 cache_index 控制 RAG 索引策略(false 总是重建索引,true 在可用时加载缓存),该约定在所有语言绑定中保持一致;cactus_complete 的 options_json 可传 {"max_tokens":256,"temperature":0.7} 之类生成参数,tools_json 传 Function Calling 的 JSON Schema 定义,pcm_buffer 则可直接传入原始音频字节实现音频理解——这些能力与绑定语言无关。

五、选型决策:结合场景的最终建议

综合平台覆盖、安装方式与集成成本,推荐的决策路径如下:

移动端 App

  • 已有 React Native 代码库 → React Native:桥接已就绪,npm install 后直接调用
  • 需要 iOS + Android + macOS 三端一致体验 → Flutter:Dart FFI 直接映射 C API,一套 Dart 代码覆盖三平台
  • 原生 Android / KMP 项目 → Kotlin:Android 走 JNI、iOS 走 cinterop,expect/actual 共享业务代码
  • 原生 iOS / macOS 且看重 Metal 加速 → Swift:XCFramework 拖入即用,import cactus 直接可用

服务端 / 脚本

  • 推理服务、批处理、原型验证 → Python:模块级 API + dict 返回值,能力覆盖最全(含云端回退、向量索引)
  • 快速测试模型、交互会话、免写代码 → CLI:cactus run <model> 一行运行

系统级嵌入

  • 游戏引擎 / 桌面原生应用 / 任意 C/C++ 工程 → C++:仅需头文件,控制力最大
  • 重视内存安全与 FFI 稳定性的系统集成 → Rust:裸 extern "C" 声明 + #[link],通过 build.rs 接入构建目录

选好绑定后,前往 docs/quickstart.md 完成安装并运行你的第一次端侧推理;更完整的 C API 参考见 docs/cactus_engine.md(含转录、Embedding、RAG、索引与工具调用细节),需要自定义模型计算图可进一步阅读 docs/cactus_graph.md,转换与部署自定义微调模型则参考 docs/finetuning.md。

登录后查看全文
cactus