Section 4/141 menit

4. Desain Schema @Generable yang Optimal

4. Desain Schema @Generable yang Optimal

Prinsip Desain Schema

1. Flat lebih baik dari Nested yang Dalam

swift
// ❌ Terlalu dalam: model lebih sulit mengisi semua nested fields dengan akurat
@Generable
struct Report {
    var metadata: Metadata
    var content: Content
    var analysis: Analysis
}
// di mana masing-masing punya 3-4 field nested lagi

// ✓ Flat atau maksimal 2 level: lebih akurat dan prediktabel
@Generable
struct Report {
    @Guide(description: "Judul laporan")
    var title: String

    @Guide(description: "Nama penulis")
    var authorName: String

    @Guide(description: "Tanggal dalam format YYYY-MM-DD")
    var date: String

    @Guide(description: "Poin-poin utama laporan, maksimal 5")
    var keyPoints: [String]

    @Guide(description: "Kesimpulan satu paragraf")
    var conclusion: String
}

2. Array dengan Batas Eksplisit

swift
// ❌ Tanpa batas: model mungkin menghasilkan terlalu banyak atau terlalu sedikit
@Generable
struct TaggedContent {
    var tags: [String]
}

// ✓ Batas eksplisit di @Guide
@Generable
struct TaggedContent {
    @Guide(description: "Antara 3 sampai 7 tag relevan, lowercase, dipisah tanpa duplikasi")
    var tags: [String]
}

3. Optional yang Bermakna

swift
// ❌ Semua optional: model tidak tahu field mana yang penting
@Generable
struct ProductExtract {
    var name: String?
    var price: Double?
    var brand: String?
    var description: String?
}

// ✓ Required hanya yang selalu ada, optional untuk yang memang tidak pasti
@Generable
struct ProductExtract {
    @Guide(description: "Nama produk — selalu ada dalam listing")
    var name: String  // Required — selalu ada

    @Guide(description: "Harga dalam angka, nil jika tidak disebutkan eksplisit")
    var price: Double?  // Optional — mungkin tidak ada

    @Guide(description: "Merek atau brand, nil jika produk generik")
    var brand: String?  // Optional — tidak selalu ada

    @Guide(description: "Deskripsi singkat 1-2 kalimat")
    var summary: String  // Required — selalu bisa dibuat dari konteks
}

Komposisi Schema untuk Domain Kompleks

swift
// Domain model yang dipecah jadi schema yang lebih kecil dan dapat dikomposisi
@Generable
enum Priority: String {
    case critical, high, medium, low
}

@Generable
enum IssueType: String {
    case bug, feature, improvement, documentation, question
}

@Generable
struct IssueLabel {
    @Guide(description: "Nama label, lowercase dengan dash, contoh: ui-bug, performance")
    var name: String

    @Guide(description: "Kategori label: technical, product, atau process")
    var category: String
}

@Generable
struct ParsedIssue {
    @Guide(description: "Judul issue yang singkat dan deskriptif")
    var title: String

    @Guide(description: "Jenis issue berdasarkan konten")
    var type: IssueType

    @Guide(description: "Prioritas berdasarkan dampak dan urgensi yang disebutkan")
    var priority: Priority

    @Guide(description: "Dua hingga empat label yang relevan")
    var labels: [IssueLabel]

    @Guide(description: "Langkah reproduksi jika ini bug, nil untuk non-bug")
    var reproductionSteps: [String]?

    @Guide(description: "Estimasi kompleksitas: simple, moderate, atau complex")
    var complexity: String
}

Validasi Post-Generation

@Generable menjamin tipe data, tapi tidak menjamin nilai yang valid secara semantik. Selalu validasi setelah generate:

swift
struct IssueParser {
    private let session = LanguageModelSession()

    func parse(issueText: String) async throws -> ParsedIssue {
        let raw = try await session.respond(
            to: "Parse issue GitHub berikut:\n\n\(issueText)",
            generating: ParsedIssue.self
        ).content

        return try validate(raw)
    }

    private func validate(_ issue: ParsedIssue) throws -> ParsedIssue {
        guard !issue.title.trimmingCharacters(in: .whitespaces).isEmpty else {
            throw IssueParseError.emptyTitle
        }
        guard issue.labels.count >= 2 else {
            throw IssueParseError.insufficientLabels
        }
        // Validasi semantik lainnya
        return issue
    }
}