Skip to Content
📖 Guide DocumentsLLM Function CallingstructuredOutput() function

structuredOutput() function

undefined

typia
export namespace llm { // STRUCTURED OUTPUT export function structuredOutput< T extends Record<string, any>, Config extends Partial<ILlmSchema.IConfig & { equals: boolean }> = {}, >(): ILlmStructuredOutput<T>; // SCHEMA ONLY (use structuredOutput() for full interface) export function parameters< Parameters extends Record<string, any>, Config extends Partial<ILlmSchema.IConfig> = {}, >(): ILlmSchema.IParameters; }

All-in-one interface for LLM structured output.

typia.llm.structuredOutput<T>() is a function generating ILlmStructuredOutput<T> containing everything needed for handling LLM structured outputs: the JSON schema for prompting, and functions for parsing, coercing, and validating responses.

  • parameters: JSON schema to pass to LLM providers
  • parse: Lenient JSON parser with type coercion
  • coerce: Type coercion for pre-parsed objects
  • validate: Schema validation with error details

LLM Function Calling and Structured Output

LLM selects proper function and fill arguments.

In nowadays, most LLM (Large Language Model) like OpenAI are supporting “function calling” feature. The “LLM function calling” means that LLM automatically selects a proper function and fills parameter values from conversation with the user (may by chatting text).

Structured output is another feature of LLM. The “structured output” means that LLM automatically transforms the output conversation into a structured data format like JSON.

When to use structuredOutput() vs parameters()

  • Use structuredOutput() when you need parsing, coercion, and validation together
  • Use parameters() when you only need the schema (e.g., passing to response_format)

structuredOutput() is essentially parameters() + parse() + coerce() + validate() bundled together.

example/src/llm/structuredOutput.ts
import { LlmJson } from "@typia/utils"; import OpenAI from "openai"; import typia, { tags } from "typia"; interface IMember { email: string & tags.Format<"email">; name: string; age: number & tags.Minimum<0>; hobbies: string[]; joined_at: string & tags.Format<"date">; } const main = async (): Promise<void> => { // Generate structured output interface const output = typia.llm.structuredOutput<IMember>(); // Use schema with OpenAI const client: OpenAI = new OpenAI({ apiKey: "<YOUR_OPENAI_API_KEY>", }); const completion: OpenAI.ChatCompletion = await client.chat.completions.create({ model: "gpt-4o", messages: [ { role: "user", content: [ "I am a new member of the community.", "", "My name is John Doe, and I am 25 years old.", "I like playing basketball and reading books,", "and joined to this community at 2022-01-01.", ].join("\n"), }, ], response_format: { type: "json_schema", json_schema: { name: "member", schema: output.parameters as any, }, }, }); // Parse LLM response with type coercion const parsed = output.parse(completion.choices[0].message.content!); if (!parsed.success) { console.error("Parse failed:", parsed.errors); return; } // Validate the parsed data const validated = output.validate(parsed.data); if (!validated.success) { // Format errors for LLM feedback console.error(LlmJson.stringify(validated)); return; } console.log("Success:", validated.data); }; main().catch(console.error);

Parse & Coerce

Using parse() for raw JSON strings
const output = typia.llm.structuredOutput<IMember>(); // LLM returns raw JSON string const jsonString = '{"name": "John", "age": "25"}'; // parse() handles lenient JSON + type coercion const result = output.parse(jsonString); if (result.success) { console.log(result.data.age); // 25 (number, not string) }

Type Coercion:

LLMs frequently return wrong types. Both parse() and coerce() automatically fix these based on the schema:

  • "42"42 (when schema expects number)
  • "true"true (when schema expects boolean)
  • "null"null (when schema expects null)
  • "{...}"{...} (double-stringified objects)
  • "[...]"[...] (double-stringified arrays)

0% → 100% Success Rate on Union Types

Qwen3.5 model shows 0% success rate when handling union types with double-stringified JSON objects. With type coercion, the success rate jumps to 100%.

For Pre-parsed Objects, Use coerce()

Some LLM SDKs (Anthropic, Vercel AI, LangChain, MCP) parse JSON internally and return JavaScript objects directly. In these cases, use coerce() instead of parse() to fix types without re-parsing.

For more details, see JSON Utilities.

Validation Feedback

Validation with LLM feedback
import { LlmJson } from "@typia/utils"; const output = typia.llm.structuredOutput<IMember>(); const parsed = output.parse(llmResponse); if (parsed.success) { const validated = output.validate(parsed.data); if (!validated.success) { // Format errors for LLM to understand and self-correct const feedback = LlmJson.stringify(validated); console.log(feedback); // Send feedback back to LLM for retry } }

Formatted Error Output:

{ "name": "John", "age": -5, // ❌ [{"path":"$input.age","expected":"number & Minimum<0>"}] "email": "invalid", // ❌ [{"path":"$input.email","expected":"string & Format<\"email\">"}] }

The LLM reads this feedback and self-corrects on the next turn.

In the AutoBe  project (AI-powered backend code generator), qwen3-coder-next showed only 6.75% raw function calling success rate on compiler AST types. However, with validation feedback, it reached 100%.

Config Options

// Use validateEquals (strict mode - reject extra properties) const strictOutput = typia.llm.structuredOutput< IMember, { equals: true } >(); // Strict validation rejects objects with extra properties const result = strictOutput.validate({ name: "John", age: 25, email: "john@example.com", hobbies: ["reading"], extraField: "not allowed", // ❌ rejected });

Comparison

Featureparameters()structuredOutput()
Schema generation
parse() function
coerce() function
validate() function
Use caseSchema onlyFull workflow

For schema-only needs, use parameters(). For the complete structured output workflow, use structuredOutput().

Restrictions

typia.llm.structuredOutput<T>() follows the same restrictions as typia.llm.parameters<T>() and typia.llm.schema<T>() functions.

The type T must be a keyworded object type with static keys without any dynamic keys. Also, the object type must not be nullable or optional.

If you don’t follow the LLM’s keyworded arguments rule, typia.llm.structuredOutput<T>() will throw a compilation error.

src/examples/llm.structuredOutput.violation.ts
import typia from "typia"; typia.llm.structuredOutput<string>(); typia.llm.structuredOutput<Record<string, boolean>>(); typia.llm.structuredOutput<Array<number>>();
Last updated on