Разработка AI-ассистента в мобильном приложении на базе Claude (Anthropic)
Claude — модели от Anthropic с одним из наибольших контекстных окон среди коммерчески доступных LLM. Claude 3.5 Sonnet поддерживает 200K токенов контекста, что для мобильного ассистента означает возможность загрузить в один запрос всю переписку за несколько недель или большой документ без трансклинации. Это меняет подходы к управлению историей диалога.
Anthropic Messages API: структура и особенности
Anthropic API по структуре похоже на OpenAI, но с важными отличиями. Система промптов в Claude — отдельный параметр system, а не сообщение с ролью system в массиве messages. Это критически важно: попытка передать системный промпт внутри messages ухудшает качество следования инструкциям.
struct AnthropicRequest: Encodable {
let model: String // "claude-3-5-sonnet-20241022"
let maxTokens: Int // обязательный параметр, нет дефолта
let system: String // системный промпт — отдельно
let messages: [Message]
let stream: Bool
enum CodingKeys: String, CodingKey {
case model, system, messages, stream
case maxTokens = "max_tokens"
}
}
max_tokens в Anthropic API — обязательный параметр без дефолта. Если забыть его передать, API вернёт ошибку 400. Это отличие от OpenAI, где max_tokens опционален.
Аутентификация: заголовок x-api-key (не Authorization: Bearer). Версионирование API через anthropic-version: 2023-06-01. Без этого заголовка — 400 Bad Request.
Стриминг через SSE
Claude поддерживает стриминг через Server-Sent Events. Структура потока отличается от OpenAI: события content_block_start, content_block_delta, content_block_stop, message_delta — каждое содержит свои поля.
На iOS обработка SSE через URLSession + AsyncBytes:
for try await line in response.bytes.lines {
guard line.hasPrefix("data: ") else { continue }
let jsonString = String(line.dropFirst(6))
guard jsonString != "[DONE]" else { break }
if let data = jsonString.data(using: .utf8),
let event = try? JSONDecoder().decode(StreamEvent.self, from: data),
event.type == "content_block_delta" {
let delta = event.delta?.text ?? ""
await MainActor.run { self.appendText(delta) }
}
}
Важно обрабатывать все типы событий, а не только content_block_delta — message_delta содержит информацию о stop_reason (например, max_tokens), которую нужно показывать пользователю.
Большой контекст: преимущества и ограничения на мобиле
200K токенов — примерно 150 000 слов или ~500 страниц текста. Для мобильного ассистента это возможность работать с полным документом без RAG-пайплайна. Пользователь прикрепил PDF договора — его можно целиком передать в контекст и задавать вопросы.
Оборотная сторона: большой контекст = долгий time-to-first-token. При 50K токенов в запросе первый токен ответа может прийти через 3–5 секунд даже на хорошем соединении. На мобиле нужен индикатор прогресса, который появляется сразу, до первого токена, иначе пользователь думает, что приложение зависло.
Стоимость также растёт линейно с контекстом — для приложений с пользовательской оплатой это важно учитывать при проектировании UI счётчика токенов.
Vision: передача изображений
Claude 3.5 Sonnet поддерживает изображения через base64 в content block:
let imageContent = ContentBlock(
type: "image",
source: ImageSource(
type: "base64",
mediaType: "image/jpeg",
data: imageBase64
)
)
Ограничение: максимум 20 изображений в одном запросе, каждое до 5 МБ. На мобиле перед отправкой изображение нужно сжать до разумного размера — UIGraphicsImageRenderer или BitmapFactory.Options с inSampleSize.
Процесс работы
Ключевые вопросы до начала разработки: нужна ли работа с документами (PDF, изображения), каков ожидаемый объём диалога, нужен ли серверный прокси (да — обязательно, API-ключ не хранится в приложении).
Реализация: Anthropic API клиент → стриминговый UI → управление историей с учётом 200K лимита → опциональная работа с файлами.
Ориентиры по срокам
Базовый текстовый ассистент — 1–2 недели. С поддержкой документов, изображений, серверным прокси — 3–4 недели.







