Back to OSS
LLMCodable
Codableのような直感的なプロトコルでLLMベースの構造化データ変換を実現
Swift
llmcodableai
LLMCodable
Codableのような直感的なプロトコルでLLMベースの構造化データ変換を実現するSwiftパッケージ
特徴
import LLMCodable
// 曖昧なテキストから構造化データへ変換
@Generable
struct Person: LLMCodable {
@Guide(description: "The person's full name")
var name: String
@Guide(description: "Age in years", .range(0...150))
var age: Int
@Guide(description: "Occupation or job title")
var occupation: String?
}
// LLMを使ってデコード
let input: String = "谷口恭一は24歳のiOSエンジニアです"
let person = try await input.decode(as: Person.self)
// Person(name: "谷口恭一", age: 24, occupation: "iOSエンジニア")
// LLMフレンドリーな形式にエンコード
let markdown = person.llmEncoded(using: .markdown)
// Person:
// - name: 谷口恭一
// - age: 24
// - occupation: iOSエンジニア
- Codableライクなプロトコル -
LLMDecodableとLLMEncodableでSwiftらしいAPI設計 - Foundation Modelsとの統合 - Apple Intelligence(
@Generable,@Guide)をシームレスに活用 - ストリーミング対応 - プロパティ単位・配列要素単位のリアルタイムデコード
- 信頼度スコア - 抽出精度の信頼度を0.0〜1.0で取得
- 複数エンコード形式 - Markdown、JSON、自然言語、カスタム形式に対応
- 非同期処理対応 - Swift Concurrencyによるasync/await API
インストール
// Package.swift
dependencies: [
.package(url: "https://github.com/no-problem-dev/LLMCodable.git", .upToNextMajor(from: "1.0.0"))
]
または Xcode: File > Add Package Dependencies > URL入力
基本的な使い方
1. モデルの定義
import LLMCodable
@Generable
struct MeetingNotes: LLMCodable {
@Guide(description: "Main topics discussed in the meeting")
var topics: [String]
@Guide(description: "Action items with descriptions")
var actionItems: [String]
@Guide(description: "Attendee names")
var attendees: [String]
}
2. テキストからデコード
let text: String = """
Today's meeting with Alice, Bob, and Charlie covered the Q4 roadmap and budget review.
Action items: Alice will prepare the presentation, Bob will gather metrics.
"""
let notes = try await text.decode(as: MeetingNotes.self)
print(notes.topics) // ["Q4 roadmap", "budget review"]
print(notes.attendees) // ["Alice", "Bob", "Charlie"]
print(notes.actionItems) // ["Alice will prepare the presentation", "Bob will gather metrics"]
3. 構造化データをエンコード
// Markdown形式
let markdown = notes.llmEncoded(using: .markdown)
// JSON形式
let json = notes.llmEncoded(using: .json)
// 自然言語形式
let natural = notes.llmEncoded(using: .naturalLanguage)
4. ストリーミングデコード
プロパティが生成されるたびにUIを更新:
let stream = try reviewText.decodeStream(as: MovieReview.self)
for try await partial in stream {
if let title = partial.title {
self.title = title // タイトルが生成されたら即座に表示
}
if let rating = partial.rating {
self.rating = rating
}
}
5. 配列要素のストリーミング
配列の各要素が完成するたびに取得:
let stream = recipeText.decodeElements(of: Recipe.self)
for try await recipe in stream {
recipes.append(recipe) // 各レシピが完成次第追加
}
6. 信頼度スコア付きデコード
入力の曖昧さに基づく信頼度を取得:
let ambiguousInput: String = "多分30歳くらいの田中さん"
let result = try await ambiguousInput.decodeWithConfidence(as: Person.self)
print(result.value.name) // "田中"
print(result.confidence) // 0.7(曖昧な入力のため低め)
7. カスタムセッションの使用
let session = LanguageModelSession()
let options = GenerationOptions(temperature: 0.7)
let input: String = "Kyoichi is a 24-year-old developer"
let person = try await input.decode(
as: Person.self,
using: session,
options: options
)
プロトコル
LLMDecodable
曖昧なテキストから構造化データへの変換を定義するプロトコル。Generableに準拠していれば、デフォルト実装が自動的に提供されます。
| メソッド | 説明 |
|---|---|
decode(from:) |
基本的なデコード |
decodeStream(from:) |
プロパティ単位のストリーミング |
decodeElements(of:) |
配列要素単位のストリーミング(StringProtocol拡張のみ) |
decodeWithConfidence(from:) |
信頼度スコア付きデコード |
すべてのメソッドはStringProtocolの拡張として利用可能(推奨):
// Input-first API(推奨)
let person = try await text.decode(as: Person.self)
// Type-first API
let person = try await Person.decode(from: text)
LLMEncodable
構造化データをLLMフレンドリーな文字列へ変換するプロトコル。
public protocol LLMEncodable: PromptRepresentable {
func llmEncoded(using strategy: LLMEncodingStrategy) -> String
}
Encodableに準拠していれば、デフォルト実装が自動的に提供されます。
LLMCodable
LLMDecodableとLLMEncodable両方に準拠する型エイリアス。
public typealias LLMCodable = LLMDecodable & LLMEncodable
エンコード形式
| 形式 | 説明 | 用途 |
|---|---|---|
.markdown |
Markdown形式の構造化テキスト | ドキュメント、レポート |
.json |
JSON形式 | API連携、データ保存 |
.naturalLanguage |
自然言語の文章 | チャット、説明文 |
.custom(formatter:) |
カスタムフォーマッター | 任意の形式 |
使用例
情報抽出
@Generable
struct ContactInfo: LLMCodable {
@Guide(description: "Email address")
var email: String?
@Guide(description: "Phone number")
var phone: String?
@Guide(description: "Physical address")
var address: String?
}
let text: String = "連絡先: example@email.com、電話は090-1234-5678、住所は東京都渋谷区"
let contact = try await text.decode(as: ContactInfo.self)
センチメント分析
@Generable
enum Sentiment: String, Codable, CaseIterable {
case positive, neutral, negative
}
@Generable
struct SentimentAnalysis: LLMCodable {
@Guide(description: "Overall sentiment")
var sentiment: Sentiment
@Guide(description: "Key phrases that influenced the sentiment")
var keyPhrases: [String]
}
// 信頼度スコア付きで分析
let result = try await text.decodeWithConfidence(as: SentimentAnalysis.self)
print(result.value.sentiment) // .positive
print(result.confidence) // 0.95
要約生成
@Generable
struct ArticleSummary: LLMCodable {
@Guide(description: "One-line summary of the article")
var headline: String
@Guide(description: "Key points from the article")
var keyPoints: [String]
@Guide(description: "Relevant tags or categories")
var tags: [String]
}
要件
- iOS 26+ / macOS 26+
- Swift 6.2+
- Xcode 26+
ライセンス
MIT License - 詳細は LICENSE を参照
開発者向け情報
- 🚀 リリース作業: リリースプロセス - 新バージョンをリリースする手順
サポート
- 📚 APIリファレンス(DocC)
- 🐛 Issue報告
- 💬 ディスカッション
Made with ❤️ by NOPROBLEM