news 2026/10/23 21:50:44

ApfelCore Swift 库开发指南:在自有 Swift 应用中复用 apfel 的纯 Swift 策略层

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ApfelCore Swift 库开发指南:在自有 Swift 应用中复用 apfel 的纯 Swift 策略层

【免费下载链接】apfel

The free AI already on your Mac. CLI tool, OpenAI-compatible server, and interactive chat — all on-device via Apple Intelligence. No API keys, no cloud, no downloads.

项目地址:https://gitcode.com/gh_mirrors/apfe/apfel
点击查看免费下载

apfel 的核心产品是apfelCLI 与apfel --serveOpenAI 兼容服务器,而ApfelCore是仓库内一个刻意不依赖 FoundationModels 的纯 Swift 库产品,面向需要复用「OpenAI 兼容类型、请求校验、MCP 协议、Schema 解析、重试分类、上下文裁剪策略」的 Swift 下游开发者。读完本文你将掌握:如何从 Package.swift 引入ApfelCore、各能力域的代表性类型与调用方式、它与可执行目标之间的架构边界,以及1.1.0起稳定的 API 承诺。

定位:为什么需要一个独立的纯 Swift 库

在 Package.swift 中可以看到整个仓库被拆成四个相互独立的目标:

  • ApfelCore:纯逻辑库,零依赖(dependencies: []),路径为 Sources/Core;
  • ApfelCLI:CLI 参数解析层,依赖ApfelCore(例如复用ContextStrategy);
  • apfel可执行目标:组合ApfelCore+ApfelCLI+ Hummingbird(HTTP 服务器)+ FoundationModels(推理)+ Lesbar(文件提取);
  • apfel-tests:纯 Swift 测试运行器,同样只依赖ApfelCore与ApfelCLI。

这种分层是刻意的:库本身不触碰 FoundationModels 和 Hummingbird,因此可以单元测试、交叉编译,也可以被那些自己发起 FoundationModels 调用的应用直接嵌入。apfel 可执行文件只是把这条纯逻辑层与 Apple 的推理框架、Hummingbird 服务器组合在一起的装配件。

什么场景适合依赖 ApfelCore

关联文档明确给出了适用边界:

  • 你的 Swift 应用直接调用 FoundationModels,但希望在线缆上使用 OpenAI 形状的 JSON(请求/响应模型与 OpenAI API 对齐);
  • 你想复用 apfel 的上下文裁剪策略、工具调用解析或 MCP 协议类型,而不想引入整个 CLI 二进制;
  • 你希望获得与 apfel 自身完全一致的错误分类与重试逻辑。

什么场景不应该用它

  • 想在 shell 里跑 prompt → 用apfelCLI;
  • 想要本地 OpenAI 兼容服务器 → 用apfel --serve;
  • 想要 FoundationModels 本身 → 直接依赖 Apple 框架。ApfelCore按设计不包含它。

安装:从 1.1.0 开始依赖 ApfelCore

包含ApfelCore的首个打标签版本是1.1.0。在Package.swift中直接依赖该产品:

dependencies: [ .package(url: "https://github.com/Arthur-Ficial/apfel.git", from: "1.1.0") ], targets: [ .executableTarget( name: "MyTool", dependencies: [ .product(name: "ApfelCore", package: "apfel") ] ) ]

仓库中的五个示例目标就是按这一模式声明的(见 Package.swift),例如apfelcore-openai-types-example、apfelcore-tool-calling-example、apfelcore-error-handling-example、apfelcore-mcp-protocol-example、apfelcore-context-strategies-example,它们都只依赖ApfelCore,是开箱即用的最小可运行示例。

快速上手:构造一个 OpenAI 兼容请求并校验

引入后,你可以直接使用与 apfel 内部完全相同的请求、消息与校验类型:

import ApfelCore let request = ChatCompletionRequest( model: "apple-foundationmodel", messages: [OpenAIMessage(role: "user", content: .text("Hello"))] ) if let failure = ChatRequestValidator.validate(request) { print(failure.message) }

从源码看(Sources/Core/OpenAIModels.swift),ChatCompletionRequest是Decodable, Sendable, Equatable, Hashable的值类型,字段几乎完整覆盖 OpenAI chat completions 线缆格式:

字段含义
model/messages请求的模型名(ApfelCore接受apple-foundationmodel)与对话转写
stream/stream_options是否请求流式分块及流式配置
temperature/top_p采样温度、核采样(top-p)覆盖
max_tokens/max_completion_tokens新旧两代最大补全 token 字段
seed可选确定性随机种子
tools/tool_choice/parallel_tool_calls工具定义、工具选择策略、是否允许多工具调用
response_format/logprobs/n响应格式契约、logprobs 标志、请求补全数量
stop/presence_penalty/frequency_penalty/user停止序列、惩罚项、终端用户标识
x_context_strategy/x_context_max_turns/x_context_output_reserveapfel 扩展的上下文裁剪策略覆盖项

值得注意的细节:effectiveMaxTokens属性在同时给出两个 token 字段时以max_completion_tokens ?? max_tokens解析;服务器路径上的校验器会拒绝冲突值,因此该优先级只对直接使用库的调用方有意义(Sources/Core/OpenAIModels.swift)。初始化器还保留了两个向后兼容重载(v1.11.0 之前与 v1.11.0 之后),供不同版本迁移期使用。

ChatRequestValidator负责拒绝不支持的特性——例如 embeddings、logprobs、n > 1——这正是关联文档「Validation」一栏所指的请求校验能力。

API 面总览

关联文档给出的高层 API 一览,结合源码可确认如下代表性类型:

领域代表性类型仓库位置
OpenAI 类型ChatCompletionRequest、OpenAIMessage、MessageContent、OpenAITool、ToolChoice、ResponseFormatSources/Core/OpenAIModels.swift
校验针对不支持特性的请求校验器(embeddings、logprobs、n>1)Sources/Core/ChatRequestValidator.swift
上下文策略ContextStrategy的 5 种裁剪策略Sources/Core/ContextStrategy.swift
工具调用ToolCallHandler、JSON 工具调用检测、Schema 转换Sources/Core/ToolCallHandler.swift
MCP 协议消息类型 + 传输无关的客户端原语Sources/Core/MCPProtocol.swift、Sources/Core/MCPToolRegistry.swift
错误处理ApfelError带类型化错误分类Sources/Core/ApfelError.swift
重试逻辑withRetry、isRetryableErrorSources/Core/Retry.swift

完整 API 参考位于 DocC 目录 Sources/Core/ApfelCore.docc,其入口文档 Sources/Core/ApfelCore.docc/ApfelCore.md 描述了库的定位与 Topics 索引。

上下文裁剪策略:ContextStrategy 的 5 种策略

ContextStrategy与ContextConfig描述调用方在把对话交给固定上下文窗口的模型之前,应如何裁剪或保留对话历史(Sources/Core/ContextStrategy.swift):

public enum ContextStrategy: String, Codable, Sendable, CaseIterable, Hashable { case newestFirst = "newest-first" case oldestFirst = "oldest-first" case slidingWindow = "sliding-window" case summarize = "summarize" case strict = "strict" }

它同时是CustomStringConvertible与CustomDebugStringConvertible,description直接返回 rawValue。ContextConfig承载四项配置(Sources/Core/ContextStrategy.swift):

参数类型与默认值含义
strategyContextStrategy = .newestFirst裁剪策略
maxTurnsInt? = nil裁剪后保留的最大对话轮数
outputReserveInt = 512为模型输出预留的 token 数
permissiveBool = false是否允许宽松(不裁剪)行为

ContextConfig.defaults等价于默认构造,对应可执行文件的默认行为。需要偏向「最近优先」「严格」或「摘要」时,自行构造即可:

import ApfelCore let config = ContextConfig( strategy: .slidingWindow, maxTurns: 8, outputReserve: 512, permissive: false ) print("strategy=\(config.strategy.rawValue)") print("max_turns=\(config.maxTurns ?? 0)") print("output_reserve=\(config.outputReserve)")

这段代码与示例 Examples/ContextStrategies/main.swift 完全一致,可直接运行验证。需要强调的是:ApfelCore本身不做任何 FoundationModels 调用,它只提供可套用在你自己转写/提示构建逻辑之上的策略类型。

工具调用:ToolCallHandler 与 Schema 转换

工具调用域提供ToolCallHandler、JSON 工具调用检测与 Schema 转换。示例 Examples/ToolCalling/main.swift 展示了最小的使用方式:

import ApfelCore let tool = ToolDef( name: "add", description: "Adds two numbers", parametersJSON: #"{"type":"object","properties":{"a":{"type":"number"},"b":{"type":"number"}},"required":["a","b"]}"# ) print(ToolCallHandler.buildOutputFormatInstructions(toolNames: [tool.name])) print(ToolCallHandler.buildFallbackPrompt(tools: [tool]))

ToolDef用一段 JSON Schema 字符串描述参数(这里要求a、b两个 number 字段),ToolCallHandler据此生成输出格式指令与回退提示。与之配套的还有SchemaParser/SchemaIR(Sources/Core/SchemaParser.swift、Sources/Core/SchemaIR.swift),负责把 JSON Schema 转换为可传递给模型的中间表示。工具来源解析器ToolResolution的取舍逻辑在测试中可验证(Tests/apfelTests/ToolResolutionTests.swift):客户端自带工具优先,客户端无工具时注入 MCP 工具,两者皆无则返回nil。

MCP 协议:传输无关的客户端原语

ApfelCore提供 MCP 的消息类型与传输无关的客户端原语(Sources/Core/MCPProtocol.swift),并与MCPToolRegistry(Sources/Core/MCPToolRegistry.swift)配合管理 MCP 注入的工具。最小示例(Examples/MCPProtocol/main.swift):

import ApfelCore print(MCPProtocol.initializeRequest(id: 1)) print(MCPProtocol.toolsListRequest(id: 2))

initializeRequest与toolsListRequest直接生成带 JSON-RPC id 的协议帧,MCP 相关测试见 Tests/apfelTests/MCPClientTests.swift 与 Tests/apfelTests/MCPToolRegistryTests.swift。

错误处理与重试:与 apfel 完全一致的类型化分类

ApfelError(Sources/Core/ApfelError.swift)是Error, Equatable, Hashable, Sendable的枚举,覆盖典型的 on-device 推理失败模式:

public enum ApfelError: Error, Equatable, Hashable, Sendable { case guardrailViolation case refusal(String) case contextOverflow case contextWindowExceeded(tokenCount: Int, contextSize: Int) case rateLimited case rateLimitedUntil(retryAfterSeconds: Int) case concurrentRequest case assetsUnavailable case unsupportedGuide case decodingFailure(String) case unsupportedLanguage(String) case toolExecution(String) case invalidImageInput(String) case unknown(String) }

classify(_:)(Sources/Core/ApfelError.swift)先把已是ApfelError的错误原样返回,再匹配 FoundationModels 的GenerationError,最后回退到字符串匹配本地化描述。示例 Examples/ErrorHandling/main.swift 演示了组合使用:

import ApfelCore let errors: [ApfelError] = [ .rateLimited, .contextOverflow, .unsupportedLanguage("tlh"), ] for error in errors { print("\(error.cliLabel) \(error.localizedDescription)") }

重试逻辑withRetry(Sources/Core/Retry.swift)实现指数退避:

public func withRetry<T: Sendable>( maxRetries: Int = 3, delays: [Double] = [0.1, 0.5, 2.0], operation: @Sendable () async throws -> T ) async throws -> T

行为要点:maxRetries = 0时是纯透传(不重试);重试前用isRetryableError判断,非可重试错误立即抛出;延迟序列默认[0.1, 0.5, 2.0],超出序列后复用最后一个值;退避横幅写入 stderr 时采用容忍式写入(writeTolerantly),即使 stderr 已关闭也不会中断运行或改变退出码。重试相关的单元测试见 Tests/apfelTests/RetryTests.swift。

稳定性契约:semver 保护的公共 API

ApfelCore与 apfel 主项目共享同一套版本号,没有独立的库版本线(STABILITY.md)。核心承诺(STABILITY.md):

  • 破坏性变更必须主版本升级,CI 通过swift package diagnose-api-breaking-changes把关;
  • 公共枚举非冻结(non-frozen):MINOR 版本可能新增 case(例如新的校验失败或错误类型),因此消费方不要对它们做穷尽式 switch,始终保留default分支——CI 的 API 破坏门禁恰好只拦截删除与签名变更,允许新增枚举 case;
  • 弃用策略:先以@available(*, deprecated, ...)落地一个发布版本,下一个兼容版本线内仍可用,删除只发生在主版本;
  • 补丁版本可携带仅服务于 bug 修复的纯类型 API(先例:v1.7.1 为 #315 修复发布了TokenCountFallback);
  • 公共表面的变更必须在 CHANGELOG.md 中说明。

对应地,apfel 的 1.0 稳定范围包括 CLI 标志、退出码、输出格式、OpenAI 兼容端点与响应 Schema(/v1/chat/completions、/v1/models、/health)、MCP 工具调用接口、brew services集成、环境变量配置以及ApfelCore公共 Swift API;而模型输出质量、模型可用性、性能特征与--debug调试输出格式则不在稳定承诺内。

可运行的示例入口

关联文档整理了五个主题目录,全部在 Examples 下,且都对应 Package.swift 中声明的可执行目标,可直接swift run:

主题目录
OpenAI 请求/响应形状Examples/OpenAITypes
工具调用端到端Examples/ToolCalling
MCP 协议原语Examples/MCPProtocol
错误处理 + 重试Examples/ErrorHandling
上下文裁剪策略Examples/ContextStrategies

这些示例同时被集成测试覆盖(Tests/integration/test_apfelcore_examples.py),可作为你搭建自己项目的起点。

架构边界小结

一句话概括ApfelCore的架构:零 FoundationModels、零 Hummingbird 依赖是设计意图,而非能力缺口。apfel 可执行文件在 Package.swift 中把ApfelCore与 FoundationModels(推理)、Hummingbird(HTTP 服务器)、Lesbar(文件提取)组装起来,而库本身保持纯 Swift,因此可以被单元测试、交叉编译,并被做自有 FoundationModels 调用的应用直接嵌入。先想清楚你的需求落在哪一层——shell 里跑 prompt 用 CLI,本地 OpenAI 兼容服务用--serve,而要复用策略层,才把ApfelCore作为依赖引入。

【免费下载链接】apfel

The free AI already on your Mac. CLI tool, OpenAI-compatible server, and interactive chat — all on-device via Apple Intelligence. No API keys, no cloud, no downloads.

项目地址:https://gitcode.com/gh_mirrors/apfe/apfel
点击查看免费下载
上一篇:electron-vue 全局配置指南:从 config.js 到 webpack 构建配置的完整解析
下一篇:深度解析 Cockpit:在浏览器中管理 Linux 服务器的开源管理界面

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 1:45:00

使用 PHP 绑定调用 Xberg::listRenderers() 管理文档渲染器注册表

后端AI 应用NLP 【免费下载链接】xberg Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with …

作者头像 李华
网站建设 2026/10/16 0:29:45

【ArkUI 练中学】第7课:动画体系

本节目标理解 ArkUI 动画体系的基本分类&#xff1a;属性动画、显式动画、转场动画、路径动画掌握 animateTo 显式动画接口的用法&#xff0c;理解其闭包驱动机制与适用场景掌握 .animation() 属性动画接口的用法&#xff0c;理解其声明式自动触发机制区分 animateTo 与…

作者头像 李华
网站建设 2026/10/15 2:34:30

【ArkUI 练中学】第6课:状态管理进阶

本节目标理解 State 在嵌套对象场景下的局限性&#xff0c;掌握 Observed 与 ObjectLink 配合实现深度监听的方法掌握 Watch 装饰器监听状态变量变化的能力&#xff0c;理解其严格相等触发机制及使用场景掌握 AppStorage 应用级全局状态存储的读写方法&#xff0c;理解 S…

作者头像 李华
网站建设 2026/10/19 0:41:02

【ArkUI 练中学】第4课:高级布局与列表性能优化

本节目标掌握 Flex 弹性布局的核心属性 flexBasis、flexGrow、flexShrink 及 FlexWrap 换行布局的用法掌握 Grid 网格布局的 columnsTemplate / rowsTemplate 行列设置方法&#xff0c;理解 fr 单位与 GridItem 的配合掌握 Stack 层叠布局的 alignContent 对齐方式与 zIn…

作者头像 李华