หากต้องการแยกวิเคราะห์การตอบกลับจาก Prompt API เป็นรูปแบบใดรูปแบบหนึ่ง เช่น JSON เพื่อประมวลผลเพิ่มเติม ให้ใช้ Structured Output API
Structured Output API ช่วยให้คุณกำหนดโครงสร้างเอาต์พุตเป้าหมายได้โดยใช้ คลาสและคำอธิบายประกอบ Kotlin จากนั้น Prompt API จะแสดงคำตอบในรูปแบบของออบเจ็กต์ Kotlin
การสร้างเอาต์พุตที่มีโครงสร้างมีประโยชน์อย่างยิ่งสำหรับงานต่างๆ เช่น งานต่อไปนี้
- การแยกเอนทิตี: การแยกฟิลด์ที่มีโครงสร้าง (เช่น ชื่อกิจกรรม วันที่ สถานที่) จากข้อความที่ไม่มีโครงสร้าง
- การจัดประเภท: จัดหมวดหมู่ข้อความอินพุตเป็นหมวดหมู่ที่กำหนดไว้ล่วงหน้า
- การซีเรียลไลซ์ข้อมูล: การแปลงอินพุตของผู้ใช้ที่ไม่มีโครงสร้างเป็นรูปแบบที่เหมาะสําหรับการจัดเก็บฐานข้อมูลหรือการเรียก API
ข้อกำหนดเบื้องต้น
หากต้องการยืนยันว่า Structured Output API พร้อมใช้งานในอุปกรณ์ ให้ใช้
isStructuredOutputFeatureAvailable() API API จะแสดง true หาก Structured Output API พร้อมใช้งานในอุปกรณ์ และแสดง false ในกรณีอื่นๆ
suspend fun isStructuredOutputFeatureAvailable(): Boolean
นอกจากนี้ Structured Output API ยังมีข้อกำหนดต่อไปนี้ด้วย
- API ระดับ 26 ขึ้นไป ของ Android (
minSdk26) - ปลั๊กอิน KSP เวอร์ชัน 2.3.6 ขึ้นไป
ข้อจำกัด
Structured Output API มีข้อจำกัดต่อไปนี้
- ใช้ได้ใน Kotlin เท่านั้น
- ProGuard อาจรบกวนการแยกวิเคราะห์คลาสที่มีคำอธิบายประกอบ เพิ่มคลาสที่มีคำอธิบายประกอบลงในกฎการเก็บรักษาเพื่อยกเว้นคลาสเหล่านั้นจาก ProGuard หากคุณได้รับข้อผิดพลาดในการแยกวิเคราะห์ เช่น
# Keep classes used by structured output for deserialization for release builds.
-keep class com.google.mlkit.genai.demo.kotlin.Plant { *; }
กำหนดค่าโปรเจ็กต์
หากต้องการเริ่มต้นใช้งาน Structured Output API ให้ทำตามขั้นตอนต่อไปนี้
เพิ่ม ML Kit Prompt API เป็นทรัพยากร Dependencyในไฟล์
build.gradle.kts(หรือbuild.gradle) ระดับแอป หากยังไม่ได้ทำเพิ่มปลั๊กอิน KSP ลงในไฟล์
build.gradle.ktsระดับโปรเจ็กต์ ใช้ปลั๊กอิน KSP เวอร์ชันที่เข้ากันได้กับ Kotlin เวอร์ชันของคุณ เราขอแนะนำให้ใช้ KSP เวอร์ชัน 2.3.6 ขึ้นไปdependencies { ... classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:2.3.6" }เพิ่มทรัพยากร Dependency ของคอมไพเลอร์ที่มีโครงสร้างลงในไฟล์
build.gradle.ktsระดับแอปdependencies { ... ksp("com.google.mlkit:genai-schema-compiler:1.0.0-alpha1") }
กำหนดโครงสร้างเอาต์พุต
กำหนดโครงสร้างของข้อมูลที่ต้องการให้โมเดลแสดงผลโดยใช้คลาสข้อมูล Kotlin คำอธิบายประกอบหลัก 2 รายการสำหรับการกำหนดโครงสร้างเอาต์พุตมีดังนี้
- ใช้คำอธิบายประกอบ
@Generableเพื่อกำหนดคลาสเป็นเป้าหมายสำหรับเอาต์พุตที่มีโครงสร้าง - ใช้คำอธิบายประกอบ
@Guideในพร็อพเพอร์ตี้ของคลาสเพื่อระบุคำอธิบายและข้อจำกัดที่แนะนำเอาต์พุตของโมเดล
ตัวอย่างต่อไปนี้จะกำหนดโครงสร้างสำหรับการแยกข้อมูลพืช
import com.google.mlkit.genai.schema.annotations.Generable
import com.google.mlkit.genai.schema.annotations.Guide
@Generable
data class PlantList(
@Guide(description = "The list of plants found", minItems = 1, maxItems = 5)
val plants: List<Plant>
)
@Generable("Information about a plant species")
data class Plant(
@Guide(description = "The common name of the plant")
val commonName: String,
@Guide(description = "The full latin scientific name of the plant")
val scientificName: String,
@Guide(
description = "The maximum height of the plant in centimeters.",
minimum = 1.0,
maximum = 10000.0
)
val maxHeightCm: Int,
@Guide(description = "Whether the plant is poisonous or not")
val isPoisonous: Boolean?,
@Guide(
description = "The primary continent where this plant is native to",
enumValues = ["Africa", "Antarctica", "Asia", "Australia", "Europe", "North America", "South America"]
)
val nativeContinent: String
)
ประเภทที่รองรับและข้อจำกัด
ระบบรองรับประเภทต่อไปนี้ภายใน@Generableคลาสที่มีคำอธิบายประกอบ
พร้อมกับ@Guideข้อจำกัดที่เกี่ยวข้อง
| ประเภท | คำอธิบาย | ข้อจำกัด@Guideที่รองรับ |
|---|---|---|
String |
สำหรับข้อความ | description, enumValues |
Double / Float |
สำหรับเลขจุดลอยตัว | description, minimum, maximum |
Int / Long |
สำหรับจำนวนเต็ม | description, minimum, maximum |
Boolean |
สำหรับค่าจริง/เท็จ | description |
List<T> |
สำหรับรายการประเภทที่รองรับหรือคลาส @Generable ที่ซ้อนกัน
|
description, minItems, maxItems |
List<String> |
สำหรับรายการค่า String |
description, enumValues, minItems,
maxItems |
@Generable ชั้นเรียน |
สำหรับออบเจ็กต์ที่มีโครงสร้างซ้อนกัน | description |
สร้างเนื้อหาที่มีโครงสร้าง
หากต้องการขอเอาต์พุตที่มีโครงสร้าง ให้ใช้ฟังก์ชันตัวช่วย generateTypedContentRequest เพื่อรวมพรอมต์มาตรฐานและระบุคลาสเอาต์พุตเป้าหมาย
// 1. Initialize your GenerativeModel as usual
val generativeModel = Generation.getClient()
// 2. Prepare the prompt text
val promptText = "List some common plants found in California."
val baseRequest = GenerateContentRequest.Builder(TextPart(promptText)).build()
// 3. Create the typed request, specifying the target class (e.g., PlantList)
val typedRequest = generateTypedContentRequest(
generateContentRequest = baseRequest,
outputClass = PlantList::class,
// Instructs ML Kit to include the generated schema structure in the prompt
// sent to AICore. This should always be set to `true` unless the model
// already knows what output format to use.
includeSchemaInPrompt = true
)
// 4. Run the inference
try {
val typedResponse = generativeModel.generateContent(typedRequest)
// 5. Access the parsed object
// The response candidates contain the parsed object of type T (PlantList in this case)
val plantList: PlantList? = typedResponse.candidates.firstOrNull()?.response
if (plantList != null) {
// Process the structured data
for (plant in plantList.plants) {
Log.d("StructuredOutput", "Found plant: ${plant.commonName} (${plant.scientificName})")
}
} else {
Log.e("StructuredOutput", "Failed to parse response into the desired structure.")
// Inspect finish reason for details
val finishReason = typedResponse.candidates.firstOrNull()?.finishReason
Log.d("StructuredOutput", "Finish reason: $finishReason")
}
} catch (e: GenAiException) {
// Handle API errors
when (e.errorCode) {
GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS -> {
Log.e("StructuredOutput", "The class structure is not supported.")
}
GenAiException.STRUCTURED_OUTPUT_INVALID_VALUE -> {
Log.e("StructuredOutput", "The model generated values that violate the schema constraints.")
}
else -> {
Log.e("StructuredOutput", "API error: ${e.message}")
}
}
}
จัดการเหตุผลและข้อผิดพลาดในการสิ้นสุด
เมื่อใช้ Structured Output API คุณควรจัดการข้อยกเว้นที่อาจเกิดขึ้นซึ่ง API ส่งคืนมา และตรวจสอบพร็อพเพอร์ตี้ finishReason ในการตอบกลับ
candidates หากการตอบกลับที่แยกวิเคราะห์แล้วเป็น Null
ค่า finishReason
พร็อพเพอร์ตี้ finishReason อาจมีค่าใดค่าหนึ่งต่อไปนี้
TypedFinishReason.STOP: โมเดลสร้างเสร็จเรียบร้อยแล้วและเอาต์พุตตรงกับสคีมาTypedFinishReason.MAX_TOKENS: โมเดลหยุดทำงานเนื่องจากถึงขีดจำกัดโทเค็น แล้ว เอาต์พุตอาจไม่สมบูรณ์TypedFinishReason.PARSE_CLASS_ERROR: โมเดลสร้างข้อความเสร็จสมบูรณ์แล้ว แต่ แยกวิเคราะห์ JSON ที่ได้เป็นคลาส Kotlin เป้าหมายไม่ได้TypedFinishReason.STRUCTURE_NOT_ANNOTATED: คลาสเป้าหมายหรือคลาสที่ซ้อนกัน ไม่มีคำอธิบายประกอบ@Generableที่จำเป็นTypedFinishReason.STRUCTURE_VALUES_INVALID: ค่าที่สร้างขึ้นละเมิดข้อจำกัดที่กำหนดไว้ในคำอธิบายประกอบ@Guide(เช่น ค่าอยู่นอกช่วง ขนาดรายการอยู่นอกขอบเขต)TypedFinishReason.OTHER: หยุดการสร้างเนื่องจากสาเหตุอื่นๆ
ข้อยกเว้น
Structured Output API อาจแสดง GenAiException โดยมีรหัสข้อผิดพลาดต่อไปนี้
GenAiException.STRUCTURED_OUTPUT_INVALID_CLASS(-104): โครงสร้างของคลาสที่มีคำอธิบายประกอบไม่ถูกต้องหรือมีประเภทที่ไม่รองรับ โดยปกติแล้วข้อผิดพลาดนี้จะเป็น ข้อผิดพลาดในการกำหนดค่าขณะพัฒนา ตรวจสอบคำจำกัดความ@Generableคลาสข้อมูล เพื่อให้แน่ใจว่าระบบรองรับประเภทพร็อพเพอร์ตี้ทั้งหมดและไม่มี การอ้างอิงแบบวงกลมGenAiException.STRUCTURED_OUTPUT_INVALID_VALUE(-105): ค่าที่โมเดลสร้างขึ้นไม่ถูกต้องหรือตรวจสอบข้อจำกัดไม่สำเร็จ นี่คือข้อผิดพลาด รันไทม์ หากพบข้อผิดพลาดนี้บ่อยครั้ง ให้ลองใช้ วิธีแก้ปัญหาต่อไปนี้- ปรับแต่งคำสั่งพรอมต์เพื่อนำโมเดลอย่างเข้มงวดมากขึ้น
- ผ่อนปรนข้อจำกัด (เช่น ขีดจำกัดขั้นต่ำ สูงสุด หรือขนาดรายการ) ในคำอธิบายประกอบ
@Guideหากข้อจำกัดดังกล่าวจำกัดความสามารถของโมเดลมากเกินไป - การใช้กลยุทธ์สำรองในแอป เช่น ลองส่งคำขออีกครั้งหรือแสดงสถานะเริ่มต้น
นับโทเค็น
หากต้องการตรวจสอบว่าพรอมต์ที่มีโครงสร้างอยู่ภายในขีดจำกัดโทเค็นอินพุตหรือไม่ ให้คำนวณ
จำนวนโทเค็นโดยใช้วิธีcountTokens()
เนื่องจากคำขอเอาต์พุตที่มีโครงสร้างต้องสั่งให้โมเดลใช้โครงสร้างสคีมา
การนับโทเค็นในข้อความพรอมต์ดิบเพียงอย่างเดียว (โดยใช้GenerateContentRequestอินสแตนซ์) จึงไม่ถูกต้อง หากต้องการรับจํานวนโทเค็นที่ถูกต้อง
คุณต้องส่งอินสแตนซ์ GenerateTypedContentRequest ที่สมบูรณ์ ซึ่งรวมถึงการกําหนดค่าคลาสและสคีมาเป้าหมาย ไปยังเมธอด countTokens()
suspend fun <T : Any> countTokens(request: GenerateTypedContentRequest<T>): CountTokensResponse