Skip to main content
zai.extract() takes unstructured text and a schema, and returns typed structured data. The LLM reads the text and fills in the schema fields.

Basic usage

import { adk, z } from "@botpress/runtime"

const product = await adk.zai.extract(
  "Blueberries are $3.99 and are in stock.",
  z.object({
    name: z.string(),
    price: z.number(),
    inStock: z.boolean(),
  })
)
// { name: "blueberries", price: 3.99, inStock: true }

Complex schemas

Extract nested objects and arrays:
const order = await adk.zai.extract(
  `Order #1234 from John Smith (john@example.com):
   - 2x Widget ($10 each)
   - 1x Gadget ($25)
   Shipping to 123 Main St, Springfield, IL 62701`,
  z.object({
    orderId: z.string(),
    customer: z.object({
      name: z.string(),
      email: z.string(),
    }),
    items: z.array(z.object({
      name: z.string(),
      quantity: z.number(),
      unitPrice: z.number(),
    })),
    shippingAddress: z.object({
      street: z.string(),
      city: z.string(),
      state: z.string(),
      zip: z.string(),
    }),
  })
)

Example: classifying emails

extract() works anywhere in your agent. Here it’s used inside a workflow step to parse and classify incoming emails:
import { Workflow, adk, z } from "@botpress/runtime"

export default new Workflow({
  name: "processEmails",
  handler: async ({ step }) => {
    const emails = await step("fetch-emails", async () => {
      return await fetchUnreadEmails()
    })

    const parsed = await step("parse-emails", async () => {
      return Promise.all(emails.map(email =>
        adk.zai.extract(email.body, z.object({
          intent: z.enum(["support", "sales", "billing", "other"]),
          urgency: z.enum(["low", "medium", "high"]),
          summary: z.string(),
        }))
      ))
    })
  },
})
Last modified on April 24, 2026