# Live structured-output test against Z.AI (Anthropic format) with glm-4.5-air.
#
# set -a && . ./.env && set +a && mix run examples/structured_output.exs
#
# The model is forced to call the `final_result` output tool whose args match a
# JSON Schema derived from an Ecto schema; we validate them with a changeset.
key = System.get_env("ZAI_API_KEY") || System.get_env("ANTHROPIC_AUTH_TOKEN")
unless key do
IO.puts("ZAI_API_KEY not set — skipping.")
System.halt(0)
end
defmodule Extract do
use Ecto.Schema
@primary_key false
embedded_schema do
field(:name, :string)
field(:age, :integer)
field(:mood, Ecto.Enum, values: [:happy, :sad, :neutral])
end
def changeset(s, a) do
s
|> Ecto.Changeset.cast(a, [:name, :age, :mood])
|> Ecto.Changeset.validate_required([:name, :age])
|> Ecto.Changeset.validate_number(:age, greater_than: 0, less_than: 150)
end
end
alias ExAgent
model =
ExAgent.Models.Anthropic.new(
model: System.get_env("ZAI_MODEL", "glm-4.5-air"),
auth_token: key,
base_url: "https://api.z.ai/api/anthropic"
)
agent =
ExAgent.new(
model: model,
output: Extract,
instructions: "Extract structured data from the user's message.",
model_settings: [max_tokens: 512, temperature: 0]
)
{:ok, result} =
ExAgent.run(agent, "Hi! I'm Mara, I'm 30 years old, and I'm feeling pretty happy today.")
IO.puts("=== STRUCTURED OUTPUT ===")
IO.inspect(result.output, label: "output")
IO.puts("\nname: #{result.output.name}, age: #{result.output.age}, mood: #{result.output.mood}")
IO.puts("\n=== USAGE ===")
IO.inspect(result.usage, label: "usage")