Files
kangkang/体己/AI/LLMSession.swift
link2026 a02679a623 fix(build): 手动 patch SPM 链接 + 清孤儿文件让 Task 6 真正可编译
经过多轮 Xcode UI / SPM 解析失败,本 commit 合并以下修复:

pbxproj 手动 patch:
- 删除孤立的 mlx-swift XCRemoteSwiftPackageReference(版本 0.31.3 与
  mlx-swift-examples 2.29.1 锁定的 0.29.1..<0.30.0 冲突)
- 在 体己 target 加入 MLXLLM + MLXLMCommon 两个 product 依赖,绑定到
  mlx-swift-examples 包。补齐 PBXBuildFile + XCSwiftPackageProductDependency
  + packageProductDependencies + Frameworks build phase 4 处条目

LLMSession.swift 简化:
- 去掉 import MLX(避免需要把 mlx-swift transitive MLX/MLXFast/MLXNN 等
  5 个 product 也链上,大幅简化依赖)
- 移除 MLX.GPU.synchronize() 调用——研究笔记里建议的尾部同步对 AsyncStream
  数据正确性无影响,省一份直接 import 依赖

清理孤儿文件:
- 体己/AI/Theme.swift 和 体己/AI/TabBar.swift 是早期混乱中由出错的
  fix subagent 创建的占位 stub,跟 DesignSystem/Tokens.swift 重复声明
  enum Tj,导致 invalid redeclaration

附:Package.resolved 由 xcodebuild SPM resolve 生成,加入版本控制确保
团队成员锁定相同版本图。

** BUILD SUCCEEDED ** 验证通过(iPhone 17 Pro simulator)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 16:45:32 +08:00

81 lines
3.3 KiB
Swift

import Foundation
import MLXLLM
import MLXLMCommon
/// MLX ,actor 线访
/// mlx-swift-examples 2.29.1(commit 9bff95ca) API
actor LLMSession {
let container: ModelContainer
init(container: ModelContainer) {
self.container = container
}
/// ( config.json + weights + tokenizer)
static func load(folderURL: URL) async throws -> LLMSession {
let configuration = ModelConfiguration(directory: folderURL)
let container = try await LLMModelFactory.shared.loadContainer(
configuration: configuration
)
return LLMSession(container: container)
}
/// AsyncThrowingStream , Task
/// - Parameters:
/// - prompt: prompt ( processor LMInput)
/// - maxTokens: token , GenerateParameters
func generate(prompt: String, maxTokens: Int) -> AsyncThrowingStream<TokenChunk, Error> {
AsyncThrowingStream { continuation in
let task = Task {
do {
let parameters = GenerateParameters(
maxTokens: maxTokens,
temperature: Float(0.6),
topP: Float(0.9)
)
try await container.perform { (context: ModelContext) in
let userInput = UserInput(prompt: prompt)
let lmInput = try await context.processor.prepare(input: userInput)
let start = Date()
var produced = 0
for await event in try MLXLMCommon.generate(
input: lmInput,
parameters: parameters,
context: context
) {
if Task.isCancelled { break }
switch event {
case .chunk(let text):
produced += 1
let elapsed = Date().timeIntervalSince(start)
let rate = elapsed > 0 ? Double(produced) / elapsed : 0
continuation.yield(TokenChunk(text: text, decodeRate: rate))
case .info:
// ,
break
case .toolCall:
// ,switch
break
}
}
// : MLX.GPU.synchronize()
// GPU AsyncStream yield
// ,GPU
// transitive import MLX , SPM
}
continuation.finish()
} catch {
continuation.finish(throwing: error)
}
}
continuation.onTermination = { _ in task.cancel() }
}
}
}