尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

iOS集成Grok AI实战:从API调用到Projects项目管理开发指南

iOS集成Grok AI实战:从API调用到Projects项目管理开发指南 最近在尝试将 Grok 集成到 iOS 项目中进行 AI 功能开发时发现其官方文档和社区资料相对零散尤其是在 Xcode 项目管理、依赖集成和真机调试等环节新手容易踩坑。本文旨在提供一个从零开始的完整实战指南详细拆解如何在 iOS 项目中集成 Grok并利用其新增的“Projects”功能来构建一个结构化的 AI 应用。无论你是想为现有 App 添加智能对话还是想从零开发一个 AI 驱动的独立应用这篇教程都能提供清晰的路径和可复现的代码。1. 背景与核心概念什么是 Grok 及其 Projects 功能在深入代码之前我们有必要先厘清几个核心概念这能帮助你更好地理解后续的集成工作。Grok 是什么简单来说Grok 是一个由 xAI 公司开发的大型语言模型LLM类似于 ChatGPT 或 Claude。它能够理解并生成人类语言完成对话、代码编写、内容创作等多种任务。对于开发者而言Grok 提供了 API 接口允许我们将这种强大的 AI 能力嵌入到自己的应用程序中从而为用户提供智能交互体验。Grok 的 Projects 功能意味着什么根据官方信息和社区讨论Grok 的 “Projects” 功能并非指 iOS 开发中的 Xcode 项目文件.xcodeproj而是 Grok 平台或 API 层面的一种工作区或上下文管理机制。你可以将其理解为对话/任务隔离每个“Project”可以专注于一个特定的主题或任务例如“旅行规划助手”、“代码审查工具”保持对话历史和上下文的独立性。资源与配置管理可能关联特定的知识库、系统提示词System Prompt或文件上传使得 AI 的行为在该项目内保持一致性。团队协作单元在企业或团队场景下不同的项目可能对应不同的团队、不同的权限和不同的数据范围。对于 iOS 开发者我们的核心任务就是通过 Grok API在我们的 App 中创建、切换和管理这些“Projects”从而为用户提供更有组织、更专业的 AI 服务。为什么 iOS 开发者需要关注移动端是用户接触 AI 最直接的入口之一。通过集成 Grok你可以增强 App 功能为笔记、社交、教育类 App 添加智能问答和内容生成。创建专属 AI 助手构建一个具有特定领域知识如法律、医疗、编程的个性化助手 App。探索新的交互模式结合 iOS 的原生能力如语音、ARKit、快捷指令创造全新的 AI 交互体验。2. 环境准备与版本说明开始编码前请确保你的开发环境已就绪。以下版本是撰写本文时的主流选择请根据实际情况调整。操作系统macOS Ventura (13.0) 或更高版本。这是运行 Xcode 和 iOS 模拟器的硬性要求。集成开发环境 (IDE)Xcode 15.0 或更高版本。建议从 Mac App Store 下载最新稳定版。编程语言Swift 5.9 或更高版本。Xcode 15 默认支持 Swift 5.9它提供了更强大的并发特性和宏支持。依赖管理Swift Package Manager (SPM)。这是苹果首选的依赖管理工具集成在 Xcode 中无需额外安装。测试设备iOS 17.0 或更高版本的模拟器或真机。Grok API 调用需要网络请确保模拟器或真机可以访问互联网。Grok API 访问你需要一个有效的 xAI API 密钥。目前可能需要加入等待列表或通过特定渠道获取。本文假设你已拥有一个可用的 API Key。网络调试工具可选但推荐Charles Proxy或Proxyman。用于抓包分析 API 请求和响应在调试时非常有用。项目结构预览我们将创建一个名为GrokIOSDemo的单视图应用。最终的项目结构大致如下GrokIOSDemo/ ├── GrokIOSDemo.xcodeproj ├── GrokIOSDemo/ │ ├── App/ │ │ ├── GrokIOSDemoApp.swift // App 入口 │ │ └── ProjectManager.swift // Projects 功能核心管理类 │ ├── Models/ │ │ ├── GrokProject.swift // Project 数据模型 │ │ └── ChatMessage.swift // 消息数据模型 │ ├── Services/ │ │ └── GrokAPIService.swift // 网络请求层封装 API 调用 │ ├── Views/ │ │ ├── ContentView.swift // 主界面 │ │ ├── ProjectListView.swift // 项目列表视图 │ │ └── ChatView.swift // 聊天对话视图 │ └── Resources/ │ ├── Assets.xcassets │ └── Info.plist └── README.md3. 核心原理与 API 拆解在动手写代码前理解 Grok API 如何工作以及“Projects”功能在 API 层面的体现至关重要。Grok API 基础Grok 提供了基于 HTTP 的 RESTful API其对话核心端点通常是/v1/chat/completions这与 OpenAI API 格式相似。一个最基本的请求需要包含API Key在 HTTP Header 的Authorization字段中携带格式为Bearer YOUR_API_KEY。模型标识指定使用哪个 Grok 模型例如grok-beta。消息数组包含对话历史的messages数组每个消息有role(如user,assistant,system) 和content。“Projects”功能在 API 中的体现目前Grok API 可能通过以下一种或多种方式实现“Projects”概念project_id参数在请求体或 Header 中传入一个project_id服务器端据此隔离上下文和计费。system角色消息每个“Project”可以关联一个特定的system消息用来定义 AI 在该项目中的角色、行为和知识边界。通过切换不同的system提示词来模拟切换项目。独立的会话/线程类似 ChatGPT 的 Threads每个 Project 对应一个独立的会话 ID (thread_id)拥有独立的对话历史。对于我们的 iOS 客户端核心任务就是管理多个project_id或system提示词。在发送聊天请求时将当前活动的项目标识传递给 API。在本地持久化存储不同项目的对话历史。安全与最佳实践提醒API Key 是最高机密绝对不要将其硬编码在客户端代码中尤其是提交到 Git 仓库。对于生产环境应该通过你自己的后端服务器转发请求由服务器持有 API Key。本文为演示方便将在客户端直接调用 API。请务必使用如Xcode Configuration Files (.xcconfig)或环境变量来管理敏感信息并在.gitignore中排除它们。4. 完整实战构建一个 Grok Projects 管理应用接下来我们将一步步构建这个应用。请打开 Xcode选择 “Create New Project…”模板选择 “iOS” - “App”命名为GrokIOSDemo界面选择 “SwiftUI”生命周期选择 “SwiftUI App”。4.1 创建数据模型 (Models)首先定义我们的核心数据结构。1. GrokProject.swift这个模型代表一个 Grok 项目。// 文件路径GrokIOSDemo/Models/GrokProject.swift import Foundation struct GrokProject: Identifiable, Codable { let id: UUID var name: String var description: String var systemPrompt: String // 该项目对应的系统提示词 var createdAt: Date var isActive: Bool // 标记当前活动项目 init(id: UUID UUID(), name: String, description: String, systemPrompt: String, createdAt: Date Date(), isActive: Bool false) { self.id id self.name name self.description description self.systemPrompt systemPrompt self.createdAt createdAt self.isActive isActive } }2. ChatMessage.swift这个模型代表聊天中的一条消息。// 文件路径GrokIOSDemo/Models/ChatMessage.swift import Foundation struct ChatMessage: Identifiable, Codable { let id: UUID let projectId: UUID // 关联到所属的项目 let role: String // user, assistant, system let content: String let timestamp: Date init(id: UUID UUID(), projectId: UUID, role: String, content: String, timestamp: Date Date()) { self.id id self.projectId projectId self.role role self.content content self.timestamp timestamp } }4.2 实现网络服务层 (Services)这是与 Grok API 通信的核心。我们需要处理请求的构建、发送和响应解析。GrokAPIService.swift// 文件路径GrokIOSDemo/Services/GrokAPIService.swift import Foundation enum APIError: Error { case invalidURL case noData case decodingError case serverError(String) } class GrokAPIService { // 警告此处仅为演示。真实项目中应从安全的位置获取如 Keychain 或后端。 private let apiKey YOUR_GROK_API_KEY_HERE private let baseURL https://api.x.ai/v1 // 请替换为实际的 Grok API 地址 static let shared GrokAPIService() private init() {} /// 发送聊天消息到 Grok API /// - Parameters: /// - messages: 消息数组 /// - projectSystemPrompt: 当前项目的系统提示词 /// - completion: 异步回调返回助手回复或错误 func sendChatMessage(messages: [ChatMessage], projectSystemPrompt: String?, completion: escaping (ResultString, APIError) - Void) { // 1. 构建最终的 messages 数组 var finalMessages: [[String: String]] [] // 如果有项目特定的系统提示词则插入为第一条 system 消息 if let systemPrompt projectSystemPrompt, !systemPrompt.isEmpty { finalMessages.append([role: system, content: systemPrompt]) } // 添加历史消息转换角色和内容 for msg in messages { finalMessages.append([role: msg.role, content: msg.content]) } // 2. 构建请求体 let requestBody: [String: Any] [ model: grok-beta, // 使用合适的模型名 messages: finalMessages, temperature: 0.7, max_tokens: 1000 ] guard let url URL(string: \(baseURL)/chat/completions) else { completion(.failure(.invalidURL)) return } var request URLRequest(url: url) request.httpMethod POST request.setValue(application/json, forHTTPHeaderField: Content-Type) request.setValue(Bearer \(apiKey), forHTTPHeaderField: Authorization) do { request.httpBody try JSONSerialization.data(withJSONObject: requestBody, options: []) } catch { completion(.failure(.decodingError)) return } // 3. 发起网络请求 let task URLSession.shared.dataTask(with: request) { data, response, error in // 处理网络错误 if let error error { completion(.failure(.serverError(error.localizedDescription))) return } guard let data data else { completion(.failure(.noData)) return } // 4. 解析响应 do { if let json try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let choices json[choices] as? [[String: Any]], let firstChoice choices.first, let message firstChoice[message] as? [String: Any], let content message[content] as? String { completion(.success(content)) } else { // 尝试解析错误信息 if let errorJson try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let errorMsg errorJson[error] as? String { completion(.failure(.serverError(errorMsg))) } else { completion(.failure(.decodingError)) } } } catch { completion(.failure(.decodingError)) } } task.resume() } }关键点解释projectSystemPrompt参数我们将项目的系统提示词作为可选参数传入。如果存在则将其作为role: system的消息插入到请求数组的头部。这是实现“Projects”上下文隔离的核心。错误处理我们定义了一个简单的APIError枚举来分类处理可能出现的错误。安全警告再次强调apiKey直接写在代码中是极不安全的。下一步我们会改进。4.3 实现项目管理器 (App/ProjectManager.swift)这是一个使用ObservableObject的类用于管理应用状态包括项目列表、当前活动项目和聊天历史。我们将使用AppStorage进行简单的持久化。// 文件路径GrokIOSDemo/App/ProjectManager.swift import Foundation import SwiftUI class ProjectManager: ObservableObject { Published var projects: [GrokProject] [] Published var activeProject: GrokProject? Published var messages: [ChatMessage] [] // 使用 UserDefaults 持久化存储项目列表 AppStorage(savedProjects) private var savedProjectsData: Data Data() init() { loadProjects() // 如果没有项目创建一个默认的 if projects.isEmpty { let defaultProject GrokProject( name: 通用助手, description: 一个全能的 AI 助手, systemPrompt: 你是一个乐于助人的 AI 助手。请用清晰、友好的中文回答用户的问题。 ) addProject(defaultProject) switchToProject(defaultProject) } } // 加载项目 private func loadProjects() { guard let decoded try? JSONDecoder().decode([GrokProject].self, from: savedProjectsData) else { projects [] return } projects decoded // 尝试恢复上次的活动项目 if let active projects.first(where: { $0.isActive }) { activeProject active loadMessages(for: active.id) } } // 保存项目 private func saveProjects() { guard let encoded try? JSONEncoder().encode(projects) else { return } savedProjectsData encoded } // 添加新项目 func addProject(_ project: GrokProject) { var newProject project // 确保新项目不是活动状态除非是第一个 newProject.isActive projects.isEmpty projects.append(newProject) saveProjects() if newProject.isActive { activeProject newProject messages.removeAll() // 切换到新项目清空当前消息或加载其历史 } } // 切换到指定项目 func switchToProject(_ project: GrokProject) { // 更新所有项目的活动状态 for i in 0..projects.count { projects[i].isActive (projects[i].id project.id) } activeProject project saveProjects() // 加载该项目的聊天历史这里简化处理实际应从本地数据库加载对应 projectId 的消息 loadMessages(for: project.id) } // 删除项目 func deleteProject(at offsets: IndexSet) { let idsToDelete offsets.map { projects[$0].id } // 如果删除的是活动项目需要激活另一个 if let activeId activeProject?.id, idsToDelete.contains(activeId) { activeProject nil } projects.remove(atOffsets: offsets) saveProjects() // 如果活动项目被清空选择第一个项目如果有 if activeProject nil, let firstProject projects.first { switchToProject(firstProject) } } // 发送消息 func sendMessage(_ content: String) { guard let activeProject activeProject else { return } // 1. 创建用户消息并添加到本地列表 let userMessage ChatMessage(projectId: activeProject.id, role: user, content: content) messages.append(userMessage) // 2. 调用 API GrokAPIService.shared.sendChatMessage(messages: messages, projectSystemPrompt: activeProject.systemPrompt) { [weak self] result in DispatchQueue.main.async { switch result { case .success(let assistantReply): // 3. 收到回复创建助手消息 let assistantMessage ChatMessage(projectId: activeProject.id, role: assistant, content: assistantReply) self?.messages.append(assistantMessage) case .failure(let error): // 4. 处理错误可以显示一个错误消息 let errorMessage ChatMessage(projectId: activeProject.id, role: assistant, content: 抱歉请求出错: \(error.localizedDescription)) self?.messages.append(errorMessage) } } } } // 加载指定项目的消息历史简化版实际应使用 CoreData 或 SQLite private func loadMessages(for projectId: UUID) { // 此处为演示每次切换项目清空消息。真实应用应从数据库加载对应 projectId 的历史消息。 messages.removeAll() // 模拟加载一些初始消息可选 // messages loadFromDatabase(projectId: projectId) } }4.4 构建用户界面 (Views)我们将创建三个主要的 SwiftUI 视图。1. ProjectListView.swift// 文件路径GrokIOSDemo/Views/ProjectListView.swift import SwiftUI struct ProjectListView: View { EnvironmentObject var projectManager: ProjectManager State private var showingAddProject false var body: some View { NavigationView { List { ForEach(projectManager.projects) { project in HStack { VStack(alignment: .leading) { Text(project.name) .font(.headline) Text(project.description) .font(.caption) .foregroundColor(.secondary) .lineLimit(2) } Spacer() if project.isActive { Image(systemName: checkmark.circle.fill) .foregroundColor(.blue) } } .contentShape(Rectangle()) .onTapGesture { projectManager.switchToProject(project) } } .onDelete(perform: projectManager.deleteProject) } .navigationTitle(Grok Projects) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button(action: { showingAddProject true }) { Image(systemName: plus) } } } .sheet(isPresented: $showingAddProject) { AddProjectView() .environmentObject(projectManager) } } } } // 添加项目的表单视图 struct AddProjectView: View { EnvironmentObject var projectManager: ProjectManager Environment(\.dismiss) var dismiss State private var name State private var description State private var systemPrompt 你是一个专业的助手。请根据项目主题提供帮助。 var body: some View { NavigationView { Form { Section(header: Text(项目信息)) { TextField(项目名称, text: $name) TextField(项目描述, text: $description) } Section(header: Text(AI 角色设定 (System Prompt))) { TextEditor(text: $systemPrompt) .frame(height: 150) } } .navigationTitle(新建项目) .toolbar { ToolbarItem(placement: .cancellationAction) { Button(取消) { dismiss() } } ToolbarItem(placement: .confirmationAction) { Button(创建) { let newProject GrokProject( name: name.isEmpty ? 未命名项目 : name, description: description, systemPrompt: systemPrompt ) projectManager.addProject(newProject) dismiss() } .disabled(name.isEmpty) } } } } }2. ChatView.swift// 文件路径GrokIOSDemo/Views/ChatView.swift import SwiftUI struct ChatView: View { EnvironmentObject var projectManager: ProjectManager State private var newMessageText var body: some View { VStack { // 聊天消息列表 ScrollViewReader { proxy in ScrollView { LazyVStack(spacing: 12) { ForEach(projectManager.messages) { message in MessageBubble(message: message) .id(message.id) } } .padding() } .onChange(of: projectManager.messages.count) { _ in // 滚动到底部 if let lastMessage projectManager.messages.last { withAnimation { proxy.scrollTo(lastMessage.id, anchor: .bottom) } } } } // 输入区域 HStack { TextField(输入消息..., text: $newMessageText, axis: .vertical) .textFieldStyle(RoundedBorderTextFieldStyle()) .lineLimit(1...5) Button(action: sendMessage) { Image(systemName: paperplane.fill) .padding(8) .background(newMessageText.isEmpty ? Color.gray : Color.blue) .foregroundColor(.white) .clipShape(Circle()) } .disabled(newMessageText.isEmpty) } .padding() } .navigationTitle(projectManager.activeProject?.name ?? 聊天) .navigationBarTitleDisplayMode(.inline) } private func sendMessage() { let text newMessageText.trimmingCharacters(in: .whitespacesAndNewlines) guard !text.isEmpty else { return } projectManager.sendMessage(text) newMessageText } } struct MessageBubble: View { let message: ChatMessage var body: some View { HStack { if message.role user { Spacer() } VStack(alignment: message.role user ? .trailing : .leading, spacing: 4) { Text(message.content) .padding(.horizontal, 12) .padding(.vertical, 8) .background(message.role user ? Color.blue : Color.gray.opacity(0.2)) .foregroundColor(message.role user ? .white : .primary) .clipShape(RoundedRectangle(cornerRadius: 16)) Text(message.timestamp, style: .time) .font(.caption2) .foregroundColor(.secondary) } if message.role assistant { Spacer() } } } }3. ContentView.swift// 文件路径GrokIOSDemo/Views/ContentView.swift import SwiftUI struct ContentView: View { StateObject private var projectManager ProjectManager() var body: some View { TabView { ProjectListView() .tabItem { Label(项目, systemImage: folder) } if let _ projectManager.activeProject { ChatView() .tabItem { Label(聊天, systemImage: message) } } } .environmentObject(projectManager) } }4.5 应用入口与安全配置1. 应用入口 (GrokIOSDemoApp.swift)// 文件路径GrokIOSDemo/App/GrokIOSDemoApp.swift import SwiftUI main struct GrokIOSDemoApp: App { var body: some Scene { WindowGroup { ContentView() } } }2. 安全存储 API Key (重要)绝对不要将 API Key 硬编码在GrokAPIService中。正确做法是使用 Xcode 的配置文件和环境变量。步骤 1创建配置文件在项目导航器中右键点击项目名 -New File...- 选择Settings Bundle命名为Settings。或者直接在项目根目录创建一个Config.xcconfig文件。步骤 2添加配置项在Config.xcconfig文件中添加GROK_API_KEY YOUR_ACTUAL_API_KEY_HERE步骤 3在项目中引用在 Xcode 项目设置中找到PROJECT - Info - Configurations。为Debug和Release配置都设置Config.xcconfig文件。在Build Settings中确保GROK_API_KEY被正确导入通常会自动生成GROK_API_KEY构建变量。步骤 4在代码中读取修改GrokAPIService.swift中的apiKey获取方式private var apiKey: String { // 从 Info.plist 或环境变量读取 guard let key Bundle.main.object(forInfoDictionaryKey: GROK_API_KEY) as? String else { fatalError(GROK_API_KEY not found in Info.plist. Please configure it in your .xcconfig file.) } return key }确保Info.plist中有一个键GROK_API_KEY其值设置为$(GROK_API_KEY)这样 Xcode 会在构建时从.xcconfig文件注入值。步骤 5添加到 .gitignore将Config.xcconfig添加到你的.gitignore文件中防止密钥泄露。4.6 运行与验证配置 API Key按照上述安全步骤将你的 Grok API Key 配置到项目中。选择模拟器在 Xcode 顶部选择一款 iOS 17 的模拟器如 iPhone 15 Pro。构建并运行点击Cmd R。操作流程App 启动后你会看到一个“通用助手”项目。点击“项目”标签页可以创建新项目例如“代码评审专家”系统提示词设为“你是一个经验丰富的软件工程师请严格评审用户提供的代码片段指出潜在 bug、性能问题和代码风格问题。”。切换到新创建的项目然后进入“聊天”标签页。输入问题例如“帮我看看这段 Swift 代码有什么问题”观察回复。你会发现在不同项目下AI 的角色和回答风格会根据你设定的systemPrompt而改变这就是“Projects”功能的核心体现。5. 常见问题与排查思路在集成和开发过程中你可能会遇到以下问题问题现象可能原因排查思路与解决方案编译错误Cannot find type ‘UUID’ in scope未导入Foundation框架。确保在使用了UUID,Date,Codable等类型的 Swift 文件顶部有import Foundation。网络请求失败错误码 401API Key 无效、过期或未正确设置。1. 检查GrokAPIService中的apiKey是否正确。2. 确认 API Key 是否有调用权限。3. 使用网络调试工具如 Charles查看请求头中的Authorization字段是否正确携带了Bearer前缀。网络请求失败错误码 404API 端点 URL 错误。1. 确认baseURL和端点路径 (/v1/chat/completions) 是否正确。请查阅最新的 Grok API 官方文档。2. 检查网络连接确保模拟器/真机可以访问外网。收到回复但内容为空或格式错误API 响应解析失败。1. 使用print或断点打印出原始的data字符串查看 API 返回的实际 JSON 结构。2. 检查JSONSerialization解析路径是否正确特别是choices[0].message.content这个路径。3. Grok API 的响应格式可能微调需要适配。切换项目后聊天历史没有隔离消息存储未与projectId关联。本文示例为了简化将消息存储在内存数组messages中切换项目时清空。真实项目应使用CoreData或SQLite.swift等数据库每条消息都关联projectId并在loadMessages(for:)方法中查询对应项目的历史。真机上无法发出网络请求iOS 应用网络权限问题。1. 在Info.plist中添加App Transport Security Settings字典并在其下添加Allow Arbitrary Loads类型为Boolean值设为YES仅限开发测试生产环境应配置精确域名。2. 对于 iOS 14如果使用localhost调试后端还需添加NSAllowsLocalNetworking键。输入框无法换行SwiftUITextField默认单行。如示例所示使用TextField(..., axis: .vertical)并设置lineLimit范围如1...5来支持多行输入。项目列表数据没有保存AppStorage编码/解码失败。确保GrokProject模型的所有属性都遵循Codable协议。UUID和Date类型本身是Codable的。检查saveProjects()和loadProjects()方法中的JSONEncoder/JSONDecoder调用是否被正确执行。6. 最佳实践与工程建议将 AI 功能集成到生产级 iOS 应用时需要考虑更多工程化问题。架构优化引入 Repository 模式问题ProjectManager目前承担了太多职责状态管理、业务逻辑、数据持久化。建议将数据持久化如对GrokProject和ChatMessage的 CRUD 操作抽象到独立的Repository或DataStore协议中。这样便于后续替换存储方案如从 UserDefaults 迁移到 CoreData也使得ProjectManager更专注于业务逻辑协调。网络层增强异步处理使用 Swift 的async/await重构GrokAPIService使代码更简洁。重试与超时为网络请求添加重试逻辑和合理的超时时间。请求队列对于聊天应用可以考虑实现一个简单的请求队列防止用户快速发送多条消息时产生混乱。使用专用网络库对于复杂的 API 交互可以考虑引入Alamofire或使用URLSession的扩展来简化请求构建和响应处理。数据持久化升级使用 CoreData 或 SwiftData对于聊天记录这种结构化且可能大量增长的数据UserDefaults和AppStorage不是最佳选择。迁移到CoreData或 iOS 17 的SwiftData可以更好地管理关系、实现分页加载和高效查询。用户体验优化流式响应Grok API 可能支持流式响应Streaming。实现类似 ChatGPT 的打字机效果可以极大提升用户体验。这需要处理URLSession的dataTask或URLSessionWebSocketTask来接收分块数据。离线支持缓存之前的对话记录即使无网络也能查看历史。上下文长度管理AI 模型有上下文窗口限制。需要实现一个逻辑在消息历史过长时智能地截断或总结早期对话以保留最重要的上下文。安全与隐私后端代理如前所述生产环境必须通过你自己的后端服务器转发 API 请求。这可以隐藏 API Key、进行用户认证、实施速率限制、记录审计日志并能在服务器端处理敏感数据。本地数据加密如果聊天内容敏感应考虑对本地存储的聊天记录进行加密。用户同意明确告知用户对话数据可能会用于改进服务根据 Grok 的服务条款并提供数据管理选项。测试单元测试为GrokAPIService(模拟网络)、ProjectManager的业务逻辑编写单元测试。UI 测试为关键的用户流程如创建项目、发送消息编写 UI 测试。快照测试使用Point-Free的swift-snapshot-testing等库对 SwiftUI 视图进行快照测试防止意外更改。通过本教程你不仅成功将一个强大的 AI 模型集成到了 iOS 应用中还实现了一个核心的“Projects”管理功能使你的应用能够提供多个有特定上下文和角色的 AI 对话体验。从数据模型设计、网络层封装、状态管理到 UI 构建我们覆盖了一个功能完整的 AI 应用所需的主要环节。
返回列表