From e7cdb454724bd66a8bca911243213e9119ffd254 Mon Sep 17 00:00:00 2001 From: link2026 Date: Mon, 25 May 2026 15:33:51 +0800 Subject: [PATCH] =?UTF-8?q?harden(ai):=20AIRuntime=20=E5=8E=BB=E6=8E=89?= =?UTF-8?q?=E5=86=97=E4=BD=99=20weak=20self,prepare=20loading=20=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按 code quality review 反馈(2×P0): - generate() 的 Task 闭包不再 [weak self];actor 单例 strong capture 没有循环引用风险,且避免 Swift 5.10+ weak-on-actor 警告 - prepare() 的 case .loading: return 加注释说明这是有意设计, 调用方需轮询或显示 loading UI(W3 引入 prepare 队列优化) Co-Authored-By: Claude Opus 4.7 (1M context) --- 体己/AI/AIRuntime.swift | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/体己/AI/AIRuntime.swift b/体己/AI/AIRuntime.swift index 4efbcee..cdc518a 100644 --- a/体己/AI/AIRuntime.swift +++ b/体己/AI/AIRuntime.swift @@ -34,9 +34,15 @@ actor AIRuntime { /// 加载模型。首次调用会真正加载,后续幂等。 func prepare() async throws { switch status { - case .ready: return - case .loading: return // 已经在加载 - case .error, .notReady: break + case .ready: + return + case .loading: + // 已有其他调用方在加载;本次 prepare 直接返回, + // 调用方需稍后 await prepare() 再判 status,或自行轮询 / 显示加载 UI。 + // W3 引入 prepare 队列时优化。 + return + case .error, .notReady: + break } guard ModelStore.shared.isReady(.llm) else { @@ -65,7 +71,7 @@ actor AIRuntime { let snapshotSession = llmSession return AsyncThrowingStream { continuation in - Task { [weak self] in + Task { guard snapshotStatus == .ready, let session = snapshotSession else { continuation.finish(throwing: AIRuntimeError.notReady) return @@ -74,7 +80,7 @@ actor AIRuntime { // session.generate 跨 actor 边界,需要 await let stream = await session.generate(prompt: prompt, maxTokens: maxTokens) for try await chunk in stream { - await self?.recordRate(chunk.decodeRate) + await self.recordRate(chunk.decodeRate) continuation.yield(chunk) } continuation.finish()