LiteRT-LM Swift API 实战:在 iOS 与 macOS 应用中集成端侧大模型
2026/9/17 22:05:47 网站建设 项目流程

LiteRT-LM Swift API 实战:在 iOS 与 macOS 应用中集成端侧大模型

【免费下载链接】LiteRT-LMLiteRT-LM is Google's production-ready, high-performance, open-source inference framework for deploying Large Language Models on edge devices.项目地址: https://gitcode.com/GitHub_Trending/li/LiteRT-LM

本文以仓库 samples/ios_and_mac/README.md 为骨架,讲解如何使用 LiteRT-LM 的 Swift API,通过 Swift Package Manager(SPM)把.litertlm格式的端侧大模型(如 Gemma 4 E2B)原生集成进 iOS 15+ 与 macOS 12+ 应用,覆盖依赖接入、模型打包、引擎初始化、对话创建与流式输出等完整链路;并结合仓库内 Swift 封装层与 C 底层接口的源码,说明每个 API 背后的实际调用与配置含义,读完即可在 Xcode 中跑通一个 SwiftUI 聊天 Demo。

前置条件

官方示例目录要求的最低环境如下(与仓库根目录 Package.swift 中声明的平台版本一致):

条件要求
iOS15.0 或更高
macOS12.0 或更高
Xcode15.0 或更高
模型文件一个.litertlm格式的模型文件(例如 Gemma 系列)

.litertlm是 LiteRT-LM 的端侧模型封装格式,包含模型权重、分词器与元数据。仓库中models/目录下有 gemma4、qwen3 等多个模型族的元数据与 chat template 示例,runtime/testdata/下则有大量.litertlm测试模型,可用于理解该格式的构成。

第 1 步:通过 SPM 添加 LiteRTLM 依赖

在 Xcode 中按如下步骤把 LiteRTLM 的 Swift 包加入工程:

  1. 选择File>Add Package Dependencies...
  2. 在右上角搜索栏输入 LiteRT-LM 的 GitHub 仓库地址(google-ai-edge/LiteRT-LM)并回车;
  3. 从列表中选中该包,点击Add Package
  4. 勾选要添加依赖的目标 App,点击Finish

仓库根目录的 Package.swift 就是 SPM 清单,从中可以看到包的完整结构:

  • 包名LiteRTLMswift-tools-version: 5.9,同时支持.iOS(.v15).macOS(.v12)两个平台;
  • 通过.binaryTarget分别声明了 iOS(CLiteRTLM)与 macOS(CLiteRTLM_mac)两个预编译的CLiteRTLM.xcframework二进制目标,并带有校验和(checksum)用于完整性验证;
  • LiteRTLM目标封装 Swift 层,源码位于 swift/ 目录(Engine.swiftConversation.swiftConfig.swiftMessage.swift等),按平台条件依赖对应的 C 预编译库;
  • 另有LiteRTLMFoundationModels库(适配 Apple Foundation Models,位于 swift/apple_fm/),以及分布在 swift 目录下的多个独立测试 target(EngineTestsConversationTestsMessageTests等)。

[!NOTE] 若添加包后出现no such module LiteRTLM报错,说明 App target 还没有链接该库,按以下步骤手动补上:

  1. 在项目导航器中点击你的工程;
  2. 选中你的 App target;
  3. 进入General标签页;
  4. 滚动到Frameworks, Libraries, and Embedded Content
  5. 点击+按钮;
  6. 选择LiteRTLM Package->LiteRTLM
  7. 点击Add

第 2 步:把模型文件加入 App Bundle

  1. 获取一个兼容的.litertlm模型文件(例如 Gemma 4 E2B,可在模型社区搜索litert-community/gemma-4-E2B-it-litert-lm);
  2. 把模型文件拖入 Xcode 的项目导航器,在弹出的对话框中确保勾选了你的 App target,使其被复制进 App Bundle;
  3. (备选方案)如果运行时找不到模型文件,可到工程的Build Phases>Copy Bundle Resources中手动添加该文件。

模型文件的文件名(不含扩展名)会在代码中作为Bundle.main.path(forResource:ofType:)forResource参数使用。仓库示例 ContentView.swift 中使用的资源名是gemma-4-E2B-it、类型是litertlm,实际使用时请替换为你自己模型的资源名。

第 3 步:编写 SwiftUI 聊天页面

仓库的 samples/ios_and_mac/ContentView.swift 给出了一个可直接运行的 SwiftUI 聊天 Demo,核心流程分为五步:找模型 → 构造配置 → 初始化引擎 → 创建会话 → 流式发送消息

3.1 从 App Bundle 定位模型文件

guard let modelPath = Bundle.main.path( forResource: "gemma-4-E2B-it", ofType: "litertlm") else { statusMessage = "Model file not found in app bundle!" return }

forResource/ofType对应第 2 步添加到 Bundle 的模型文件名与扩展名。找不到文件时,优先检查是否已通过Copy Bundle Resources正确打包。

3.2 构造EngineConfig并初始化Engine

let fileManager = FileManager.default guard let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first else { fatalError("Could not find caches directory") } let config = try EngineConfig( modelPath: modelPath, backend: .gpu, cacheDir: cacheDirectory.path) // let config = try EngineConfig( // modelPath: modelPath, backend: .cpu(), cacheDir: cacheDirectory.path) let newEngine = Engine(engineConfig: config) try await newEngine.initialize()

这里有两个值得注意的实践点:

  • backend.gpu走 Metal 加速(iOS/macOS 上的 GPU 后端);.cpu()为 CPU 后端,可通过Backend.cpu(threadCount:)指定线程数。两种后端的定义见 swift/Config.swift。
  • cacheDir:必须指向应用可写的目录(如 Caches),用于放置模型加载产生的缓存文件。若不传,默认使用模型文件所在目录。

Engine是一个actor(见 swift/Engine.swift),initialize()内部最终调用 C 层litert_lm_engine_settings_create(...)创建设置、litert_lm_engine_create(settings)创建原生引擎句柄。源码注释特别提醒:初始化可能耗时较长(视模型大小和硬件可达秒级),不要在主线线程执行,SwiftUI 的.task {}修饰符天然在后台执行,正适合此场景。

3.3 创建Conversation会话

self.engine = newEngine self.conversation = try await newEngine.createConversation()

createConversation()(swift/Engine.swift)内部做了这些事:

  • 校验引擎已初始化(否则抛LiteRTLMError.engine(.notInitialized));
  • 校验系统消息数量:ConversationConfigsystemMessageinitialMessages里的 system 角色消息不能同时存在、且 system 消息不能多于一条,否则抛LiteRTLMError.config(.multipleSystemMessages)
  • 把 sampler 参数(topK/topP/temperature/seed)、LoRA 路径、thinking 配置、工具描述等序列化后通过 C 接口写入会话配置,最终调用litert_lm_conversation_create(engineHandle, cConversationConfig)创建原生会话。

3.4 流式发送消息并实时渲染

responseText = "" for try await chunk in conversation.sendMessageStream(Message(prompt)) { if let firstContent = chunk.contents.first { switch firstContent { case .text(let text): responseText += text // Append the chunk live! default: break } } }

sendMessageStream(_:)(swift/Conversation.swift)返回AsyncThrowingStream<Message, Error>,每个 chunk 是一个Message,其contents.text类型的Content即增量文本。底层原理是:Swift 层通过 C 回调函数streamCallback(swift/Conversation.swift)接收原生流式分片,把tool_calls缓存、把包含contentchannels的 JSON 分片解析成MessageyieldAsyncThrowingStream,最终在isFinal时结束流或继续执行工具调用循环。

与之对应的还有同步接口sendMessage(_:)(swift/Conversation.swift),一次性返回完整回复;sendMessage还内置了自动工具调用(automaticToolCalling)与重复工具调用上限(recurringToolCallLimit = 25)的保护逻辑。

运行 App

在 iOS 真机上运行

  1. 用数据线把 iPhone 连接到 Mac;
  2. 在 Xcode 窗口顶部中央的运行目标菜单中选择你的 iPhone 名称;
  3. 点击Run按钮(或按Cmd + R)构建并安装到设备上运行。

在 macOS 上运行

  1. 在 Xcode 运行目标菜单中选择My Mac
  2. 点击Run按钮(或按Cmd + R)。

常见问题排查

[!IMPORTANT] 如果在 Mac 上使用本地构建的、未签名的库,macOS 可能会弹出 “Malware”(恶意软件)警告阻止加载。仅用于本地测试时,可在 Mac 终端执行以下命令解除隔离属性:

xattr -rd com.apple.quarantine path/to/CLiteRTLM.xcframework

其中path/to/CLiteRTLM.xcframework替换为实际的 xcframework 路径。

[!TIP] 如果真机的 iOS 版本低于 Xcode 中设置的部署目标(Deployment Target),可以到 target 的General标签页,在Minimum Deployments(或Deployment Info)中把最低 iOS 版本调低到与设备版本一致,即可继续运行。

深入:Swift API 与底层 C 接口的映射

LiteRT-LM Swift 层是一层薄封装,核心价值在于把 C 层的句柄式 API 转换为类型安全、并发友好的 Swift 接口。梳理 swift 目录可得如下对应关系:

Swift 层底层 C 接口说明
EngineConfiglitert_lm_engine_settings_create/..._set_max_num_tokens/..._set_cache_dir/..._set_lora_rank引擎级配置
Engine.initialize()litert_lm_engine_create(settings)创建原生引擎,持有OpaquePointer句柄
Engine.createConversation()litert_lm_conversation_create(engineHandle, config)创建会话,同时建立ToolManager与工具注册表
Conversation.sendMessagelitert_lm_conversation_send_message同步推理,返回完整 JSON 响应
Conversation.sendMessageStreamlitert_lm_conversation_send_message_stream+ C 回调流式推理,回调桥接AsyncThrowingStream
Conversation.cancel()litert_lm_conversation_cancel_process取消进行中的推理
Engine.deinitlitert_lm_engine_delete(handle)句柄释放,防内存泄漏

配置参数在底层的行为可以通过 swift/Engine.swift 中initializeInternal的实现确认:maxNumTokens会映射为litert_lm_engine_settings_set_max_num_tokens(等价于 KV Cache 的规模),loraRank同时写入 rank 与supported_lora_ranks,benchmark 与 speculative decoding(投机解码)等实验能力通过ExperimentalFlags(见 swift/ExperimentalFlags.swift)按需开启。

进阶:EngineConfig 与 ConversationConfig 参数详解

EngineConfig(swift/Config.swift)

参数默认值含义与约束
modelPath必填.litertlm模型文件路径
backend.cpu()CPU 或 GPU 后端;.cpu(threadCount:)可指定线程数
visionBackendnil视觉执行器后端;为nil时不初始化视觉能力(多模态模型需要时设置)
audioBackendnil音频执行器后端;为nil时不初始化音频能力
maxNumTokensnil输入+输出 token 总数上限,等价于 KV Cache 大小;nil时用模型/引擎默认值,且必须 > 0,否则构造抛错
cacheDirnil缓存文件目录,必须应用可写;nil时使用模型文件所在目录
loraRanknil文本 LoRA 权重 rank;0 或nil表示禁用 LoRA
audioLoraRanknil音频 LoRA 权重 rank;0 或nil表示禁用

ConversationConfig(swift/Config.swift)

  • systemMessage/initialMessages:预设系统提示与初始对话历史(system 消息只能有一条);
  • tools:注册给模型调用的工具列表,配合Tool/ToolManager(swift/Tool.swift、swift/ToolManager.swift)使用,automaticToolCalling默认为true,模型发起工具调用后 SDK 会自动执行并把结果回传给模型;
  • samplerConfig:采样参数,见SamplerConfig,包含topK(>0)、topP(∈[0,1])、temperature(≥0)与seed(默认 0),非法值会在构造时抛LiteRTLMError.config
  • loraPath/audioLoraPath:按会话加载 LoRA 权重文件;
  • thinkingConfig:思维链/推理生成开关与 token 预算(ThinkingConfigthinkingTokenBudget默认 -1 表示无限预算);
  • enableResponseFormat:是否启用约束解码(constrained decoding,配合 swift/ResponseFormat.swift 使用,底层走 llguidance 约束提供器),默认false
  • enableToolCallStreamingvisualTokenBudgetenableSpeculativeDecoding:分别控制工具调用流式化、视觉 token 预算与投机解码(nil时继承引擎设置)。

生成期可选参数

sendMessage/sendMessageStream还支持按次传入:extraContext(附加上下文)、RepetitionPenaltyConfig(重复惩罚,支持 repetition/presence/frequency penalty 与窗口大小)、NoRepeatNgramConfig(n-gram 禁止重复)、SuppressTokensConfig(按 token ID 屏蔽)、maxOutputTokens(输出上限;对 thinking 模型,思维 token 与最终回答共同计入该上限)以及ResponseFormat。这些参数在 swift/Conversation.swift 中逐一映射为 C 层litert_lm_conversation_optional_args_*系列接口。

MessageContent类型

swift/Message.swift 定义了多模态消息模型:Content支持.text.imageData.imageFile.audioData.audioFile.toolResponse六种形态;MessageContentsRandomAccessCollection,可容纳多个 Content)、role(system/user/model/tool)与可选的channelstoolCalls组成。也就是说,同一个聊天框架天然支持图文混排与音频输入,构造示例:

let textContent = Content.text("这张图片里有什么?") let imageContent = Content.imageData(imageData) let message = Message(of: textContent, imageContent)

完整可运行 Demo 一览

把上述步骤组装起来,就是一个功能完整的 SwiftUI 流式聊天页面:samples/ios_and_mac/ContentView.swift。其状态管理(@State持有engine/conversation)、按钮禁用逻辑(引擎就绪前Generate Response置灰)与错误兜底(初始化失败/推理失败均写回statusMessage)均可直接复用。想进一步验证 Swift API 行为,可参考仓库内对应的测试:EngineTests.swift、ConversationTests.swift、MessageTests.swift,它们展示了各 API 的典型调用方式与错误分支。

小结

集成路径总结为四步:SPM 加包 → Bundle 放模型 → 初始化Engine→ 创建Conversation流式对话。其中no such module LiteRTLM、macOS 隔离警告、部署目标不匹配这三个高频问题,按上文指引即可快速解决。若需要更细的配置能力(LoRA、约束解码、工具调用、多模态输入、benchmark 等),Swift 层全部以类型安全的方式暴露,且每个参数都能在仓库 swift 目录的源码注释中找到默认值与取值范围,是排查行为差异的第一手资料。

【免费下载链接】LiteRT-LMLiteRT-LM is Google's production-ready, high-performance, open-source inference framework for deploying Large Language Models on edge devices.项目地址: https://gitcode.com/GitHub_Trending/li/LiteRT-LM

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询