AI Structured Output
Use LlmGenerateObjectTool from @loopstack/llm-provider-module to generate structured data conforming to a JSON Schema. Provider-agnostic — works with Claude, OpenAI, and other providers.
Define a Document
import { z } from 'zod';
import { Document } from '@loopstack/common';
export const FileDocumentSchema = z
.object({
filename: z.string(),
description: z.string(),
code: z.string(),
})
.strict();
export type FileDocumentType = z.infer<typeof FileDocumentSchema>;
@Document({
schema: FileDocumentSchema,
uiConfig: __dirname + '/file-document.yaml',
})
export class FileDocument {
filename: string;
description: string;
code: string;
}Workflow Example
import { z, toJSONSchema } from 'zod';
import { BaseWorkflow, DocumentEntity, Final, Initial, InjectTool, Transition, Workflow } from '@loopstack/common';
import type { LlmGenerateObjectResult } from '@loopstack/llm-provider-module';
import { LlmGenerateObjectTool, LlmMessageDocument } from '@loopstack/llm-provider-module';
import { FileDocument, FileDocumentSchema, FileDocumentType } from './documents/file-document';
@Workflow({
uiConfig: __dirname + '/prompt-structured-output.ui.yaml',
schema: z.object({
language: z.enum(['python', 'javascript', 'java', 'cpp', 'ruby', 'go', 'php']).default('python'),
}),
})
export class PromptStructuredOutputWorkflow extends BaseWorkflow {
@InjectTool({ provider: 'claude', model: 'claude-sonnet-4-6' })
llmGenerateObject: LlmGenerateObjectTool;
llmResult?: DocumentEntity<FileDocumentType>;
@Transition({ from: 'ready', to: 'prompt_executed' })
async prompt() {
const args = this.ctx.run.args as { language: string };
const result = await this.llmGenerateObject.call({
outputSchema: toJSONSchema(FileDocumentSchema) as Record<string, unknown>,
prompt: this.render(__dirname + '/templates/prompt.md', { language: args.language }),
});
const objectResult = result.data as LlmGenerateObjectResult;
this.llmResult = await this.repository.save(
FileDocument,
objectResult.data as FileDocumentType,
{ validate: 'skip' },
);
}
@Final({ from: 'prompt_executed' })
async respond() {
await this.repository.save(
LlmMessageDocument,
{
role: 'assistant',
content: [{ type: 'text', text: `Generated: ${this.llmResult?.content?.description ?? ''}` }],
},
{ id: 'status' },
);
}
}How It Works
- Convert your Zod schema to JSON Schema using
toJSONSchema() - Pass the JSON Schema as
outputSchematollmGenerateObject.call() - The provider forces the LLM to return data matching the schema
- Save the result as a typed document using
this.repository.save()
Key Parameters
await this.llmGenerateObject.call({
outputSchema: toJSONSchema(MyDocumentSchema) as Record<string, unknown>,
prompt: 'Generate structured data.',
// provider and model come from @InjectTool defaults
});Registry References
- prompt-structured-output-example-workflow — Generates structured code files using the LLM provider
Last updated on