Skip to Content

AI Function Calling

AI Function Calling

@autobe fundamentally prefers AI function calling to generate AST (Abstract Syntax Tree) data over having AI write raw programming code as text. The system validates the AST data generated through AI function calling, provides feedback to the AI for correction when errors are detected, and finally converts the validated AST data into actual programming code.

Therefore, the success of @autobe depends on three critical factors. First, how precisely and efficiently we can create AI function calling schemas. Second, how detailed and accurate validation feedback we can provide to the AI when it generates incorrect AST data. Finally, how clearly we can communicate the coding rules that @autobe must follow while constructing code (composing AST data) to the AI.

To address these challenges, @autobe adopts typia to generate AI function calling schemas at the compiler level. The compiler integrated with typia not only creates AI function calling schemas but also generates validation functions for each type. Moreover, the coding rules that @autobe must follow are embedded as comments in each AST type. These comments are recorded as type descriptions when typia converts TypeScript types into AI function calling schemas.

This approach creates a comprehensive development story that ensures both type safety and rule compliance through compiler-driven automation.

Schema Made by Compiler

import { AutoBeOpenApi, AutoBePrisma } from "@autobe/prisma"; import { ILlmApplication } from "@samchon/openapi"; import typia from "typia"; const app: ILlmApplication<"chatgpt"> = typia.llm.application< ICodeGenerator, "chatgpt", { reference: true } >(); console.log(app); interface ICodeGenerator { /** * Generate Prisma AST application for database schema design. */ generatePrismaSchema(app: AutoBePrisma.IApplication): void; /** * Generate OpenAPI document for RESTful API design. */ generateOpenApiDocument(app: AutoBeOpenApi.IDocument): void; generateTestFunction(func: AutoBeTest.IFunction): void; }

πŸ’» Typia Playground LinkΒ 

AST (Abstract Syntax Tree) structures are inherently recursive with infinite depth and countless union types. Therefore, creating AI function calling schemas for AST should never be done manually. It must be automatically generated by a compiler to ensure both stability and productivity.

The typia.llm.application<App, Model, Options>() function serves as the cornerstone of this approach. This powerful utility automatically generates comprehensive AI function calling schemas from TypeScript type definitions. By leveraging compile-time type analysis, it creates schemas that are not only type-safe but also include rich metadata and validation rules embedded directly in the type system.

The function supports multiple AI models through its generic parameters, allowing for model-specific optimizations and feature support. The options parameter enables fine-tuning of schema generation, including reference handling, description enrichment, and validation strictness. This compiler-driven approach eliminates the manual effort and potential errors associated with hand-crafted schemas while providing superior type safety and maintainability.

Comments over Prompts

@autobe/interface
export namespace AutoBePrisma { /** * Interface representing a single Prisma schema file within the application. * * Each file focuses on a specific business domain and contains related * models. File organization follows domain-driven design principles as seen * in the uploaded schemas. */ export interface IFile { /** * Name of the schema file to be generated. * * Should follow the naming convention: "schema-{number}-{domain}.prisma" * Examples: "schema-02-systematic.prisma", "schema-03-actors.prisma" The * number indicates the dependency order for schema generation. */ filename: string & tags.Pattern<"^[a-zA-Z0-9._-]+\\.prisma$">; /** * Business domain namespace that groups related models. * * Used in Prisma documentation comments as "@\namespace directive". * Examples from uploaded schemas: "Systematic", "Actors", "Sales", "Carts", * "Orders", "Coupons", "Coins", "Inquiries", "Favorites", "Articles" */ namespace: string; /** * Array of Prisma models (database tables) within this domain. * * Each model represents a business entity or concept within the namespace. * Models can reference each other through foreign key relationships. */ models: IModel[]; } /** * Interface representing a single Prisma model (database table). * * Based on the uploaded schemas, models follow specific patterns: * * - Main business entities (e.g., shopping_sales, shopping_customers) * - Snapshot/versioning entities for audit trails (e.g., * shopping_sale_snapshots) * - Junction tables for M:N relationships (e.g., * shopping_cart_commodity_stocks) * - Materialized views for performance (prefixed with mv_) */ export interface IModel { /** * Name of the Prisma model (database table name). * * Should follow snake_case convention with domain prefix. Examples: * "shopping_customers", "shopping_sale_snapshots", "bbs_articles" * Materialized views use "mv_" prefix: "mv_shopping_sale_last_snapshots" */ name: string & tags.Pattern<"^[a-z][a-z0-9_]*$">; /** * Detailed description explaining the business purpose and usage of the * model. * * Should include: * * - Business context and purpose * - Key relationships with other models * - Important behavioral notes or constraints * - References to related entities using "{@\link ModelName}" syntax Example: * "Customer information, but not a person but a **connection** basis..." */ description: string; /** * Indicates whether this model represents a materialized view for * performance optimization. * * Materialized views are read-only computed tables that cache complex query * results. They're marked as "@\hidden" in documentation and prefixed with * "mv_" in naming. Examples: mv_shopping_sale_last_snapshots, * mv_shopping_cart_commodity_prices */ material: boolean; //---- // FIELDS //---- /** * The primary key field of the model. * * In all uploaded schemas, primary keys are always UUID type with "@\id" * directive. Usually named "id" and marked with "@\db.Uuid" for PostgreSQL * mapping. */ primaryField: IPrimaryField; /** * Array of foreign key fields that reference other models. * * These establish relationships between models and include Prisma relation * directives. Can be nullable (optional relationships) or required * (mandatory relationships). May have unique constraints for 1:1 * relationships. */ foreignFields: IForeignField[]; /** * Array of regular data fields that don't reference other models. * * Include business data like names, descriptions, timestamps, flags, * amounts, etc. Common patterns: created_at, updated_at, deleted_at for * soft deletion and auditing. */ plainFields: IPlainField[]; //---- // INDEXES //---- /** * Array of unique indexes for enforcing data integrity constraints. * * Ensure uniqueness across single or multiple columns. Examples: unique * email addresses, unique codes within a channel, unique combinations like * (channel_id, nickname). */ uniqueIndexes: IUniqueIndex[]; /** * Array of regular indexes for query performance optimization. * * Speed up common query patterns like filtering by foreign keys, date * ranges, or frequently searched fields. Examples: indexes on created_at, * foreign key fields, search fields. */ plainIndexes: IPlainIndex[]; /** * Array of GIN (Generalized Inverted Index) indexes for full-text search. * * Used specifically for PostgreSQL text search capabilities using trigram * operations. Applied to text fields that need fuzzy matching or partial * text search. Examples: searching names, nicknames, titles, content * bodies. */ ginIndexes: IGinIndex[]; } }

@autobe invests significantly more effort in embedding coding rules as comments within the types used for AI function calling rather than relying on system prompts to enforce these rules.

This approach stems from a critical observation: AI models often fail to consistently follow system prompt rules, and these rules are frequently ignored entirely when context grows large. In contrast, description information written in function calling schemas is reliably followed by AI models. When AI generates information for a type specified through function calling, it references the type’s description information again, making type-level comments far more effective than system prompts in coding agents.

The AutoBePrisma.IFile and AutoBePrisma.IModel types exemplify this approach by meticulously documenting the rules that must be followed for each interface and property type. For example, the filename property must follow the schema-{number}-{domain}.prisma format, and when defining database models, the name property must use snake_case convention with domain prefixes like shopping_customers or bbs_articles. Each comment provides concrete examples and specific constraints that guide the AI toward generating compliant code structures.

This comment-driven approach ensures that coding rules are embedded directly where the AI encounters them during code generation, creating a more reliable and maintainable system than traditional prompt-based instruction methods.

Validation Feedback

@samchon/openapi
import { ILlmSchema } from "./ILlmSchema"; import { IValidation } from "./IValidation"; /** * LLM function metadata. * * `ILlmFunction` is an interface representing a function metadata, which has * been used for the LLM (Language Large Model) function calling. Also, it's a * function structure containing the function {@link name}, {@link parameters} and * {@link output return type}. * * If you provide this `ILlmFunction` data to the LLM provider like "OpenAI", * the "OpenAI" will compose a function arguments by analyzing conversations * with the user. With the LLM composed arguments, you can execute the function * and get the result. * * By the way, do not ensure that LLM will always provide the correct arguments. * The LLM of present age is not perfect, so that you would better to validate * the arguments before executing the function. I recommend you to validate the * arguments before execution by using * [`typia`](https://github.com/samchon/typia) library. * * @author Jeongho Nam - https://github.com/samchon * @template Model Type of the LLM model * @reference https://platform.openai.com/docs/guides/function-calling */ export interface ILlmFunction<Model extends ILlmSchema.Model> { /** * Representative name of the function. * * @maxLength 64 */ name: string; /** List of parameter types. */ parameters: ILlmSchema.ModelParameters[Model]; /** * Collection of separated parameters. * * Filled only when {@link ILlmApplication.IOptions.separate} is configured. */ separated?: ILlmFunction.ISeparated<Model>; /** * Expected return type. * * If the function returns nothing (`void`), the `output` value would be * `undefined`. */ output?: ILlmSchema.ModelSchema[Model]; /** * Description of the function. * * For reference, the `description` is a critical property for teaching the * purpose of the function to LLMs (Large Language Models). LLMs use this * description to determine which function to call. * * Also, when the LLM converses with the user, the `description` explains * the function to the user. Therefore, the `description` property has the * highest priority and should be carefully considered. */ description?: string | undefined; /** * Whether the function is deprecated or not. * * If the `deprecated` is `true`, the function is not recommended to use. * * LLM (Large Language Model) may not use the deprecated function. */ deprecated?: boolean | undefined; /** * Category tags for the function. * * You can fill this property by the `@tag ${name}` comment tag. */ tags?: string[] | undefined; /** * Validate function of the arguments. * * You know what? LLM (Large Language Model) like OpenAI takes a lot of * mistakes when composing arguments in function calling. Even though `number` * like simple type is defined in the {@link parameters} schema, LLM often * fills it just by a `string` typed value. * * In that case, you have to give a validation feedback to the LLM by using * this `validate` function. The `validate` function will return detailed * information about every type errors about the arguments. * * And in my experience, OpenAI's `gpt-4o-mini` model tends to construct an * invalid function calling arguments at the first trial about 50% of the * time. However, if correct it through this `validate` function, the success * rate soars to 99% at the second trial, and I've never failed at the third * trial. * * > If you've {@link separated} parameters, use the * > {@link ILlmFunction.ISeparated.validate} function instead when validating * > the LLM composed arguments. * * > In that case, This `validate` function would be meaningful only when you've * > merged the LLM and human composed arguments by * > {@link HttpLlm.mergeParameters} function. * * @param args Arguments to validate * @returns Validation result */ validate: (args: unknown) => IValidation<unknown>; } export namespace ILlmFunction { /** Collection of separated parameters. */ export interface ISeparated<Model extends ILlmSchema.Model> { /** * Parameters that would be composed by the LLM. * * Even though no property exists in the LLM side, the `llm` property would * have at least empty object type. */ llm: ILlmSchema.ModelParameters[Model]; /** Parameters that would be composed by the human. */ human: ILlmSchema.ModelParameters[Model] | null; /** * Validate function of the separated arguments. * * If LLM part of separated parameters has some properties, this `validate` * function will be filled for the {@link llm} type validation. * * > You know what? LLM (Large Language Model) like OpenAI takes a lot of * > mistakes when composing arguments in function calling. Even though * > `number` like simple type is defined in the {@link parameters} schema, LLM * > often fills it just by a `string` typed value. * * > In that case, you have to give a validation feedback to the LLM by using * > this `validate` function. The `validate` function will return detailed * > information about every type errors about the arguments. * * > And in my experience, OpenAI's `gpt-4o-mini` model tends to construct an * > invalid function calling arguments at the first trial about 50% of the * > time. However, if correct it through this `validate` function, the * > success rate soars to 99% at the second trial, and I've never failed at * > the third trial. * * @param args Arguments to validate * @returns Validate result */ validate?: ((args: unknown) => IValidation<unknown>) | undefined; } }

Does AI function calling always produce type-valid AST data? The answer is no. AI frequently experiences hallucinations even during function calling, generating AST data that is not type-valid. To correct these AI errors, validation feedback must be provided back to the AI.

The typia.llm.application<App, Model, Options>() function used by @autobe to create AI function calling schemas for AST data includes a built-in runtime type checker specialized for AI validation feedback. This validator doesn’t just identify type violations; it generates detailed, AI-friendly error messages that help the model understand exactly what went wrong and how to fix it.

Even when AI function calling produces AST data that is type-correct, there are cases where the data fails to follow @autobe’s coding rules or contains contradictions that make conversion to programming code impossible. In these scenarios, @autobe’s custom-developed compiler’s built-in compilation feedback feature activates to assist in AI correction.

This dual-layer validation system ensures that both type safety and business rule compliance are maintained throughout the code generation process. The compiler-level feedback provides semantic validation beyond simple type checking, catching logical inconsistencies and rule violations that could lead to non-functional generated code.

By combining runtime type validation with semantic rule validation, @autobe creates a robust feedback loop that continuously improves AI output quality while maintaining the integrity of the generated codebase. This approach transforms potential AI hallucinations from fatal errors into learning opportunities, allowing the system to iteratively refine its output until it meets all requirements.

Last updated on