Cactus 绑定(Binding)选型完全指南:React Native / Flutter / Kotlin / Swift / Python / Rust / CLI / C++ 对比与集成实战
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/使用ctypesswift/使用 C module mapkotlin/在 Android 上用 JNI、在 iOS 上用 Kotlin/Native cinterop(KMP)flutter/使用 Dart FFIrust/使用裸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
集成四步走:
- 将
android/libcactus_engine.so复制到应用的jniLibs/arm64-v8a/ - iOS 工程中加入
apple/cactus-ios.xcframework - macOS 工程中加入
apple/cactus-macos.xcframework - 将
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
- 将
android/libcactus_engine.so复制到app/src/main/jniLibs/arm64-v8a/ - 将
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 架构,从源码结构看可以明确梳理出四层:
-
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_*)以及日志与遥测。 -
平台原生构件层:
android/产出libcactus_engine.so,apple/产出静态库(libcactus_engine-device.a/libcactus_engine-simulator.a)与 XCFramework。这一层对上层语言完全透明——你只需要把对应文件放进工程。 -
语言 FFI 层:各绑定按语言惯例选择机制——Python 用
ctypes、Dart 用lookupFunction、Kotlin 用 JNIexternal声明、Swift 用 C module map、Rust 用extern "C"、React Native 用NativeModules桥接。 -
调用方应用层:所有绑定最终都围绕同一套"句柄 + 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。