From a9c5a40394364989d6510e558ddcfb33ce34fd53 Mon Sep 17 00:00:00 2001 From: Jeongho Nam Date: Mon, 23 Dec 2024 04:03:51 +0900 Subject: [PATCH] Detailed documentation about `typia.llm.application()` function --- website/pages/docs/llm/_meta.js | 3 +- website/pages/docs/llm/application.mdx | 1284 +++++++++--------------- website/pages/docs/llm/strategy.mdx | 1221 ++++++++++++++++++++++ 3 files changed, 1686 insertions(+), 822 deletions(-) create mode 100644 website/pages/docs/llm/strategy.mdx diff --git a/website/pages/docs/llm/_meta.js b/website/pages/docs/llm/_meta.js index fa132a7e29..289f188dfc 100644 --- a/website/pages/docs/llm/_meta.js +++ b/website/pages/docs/llm/_meta.js @@ -1,5 +1,6 @@ export default { - application: "application() function", + application: "application() functions", parameters: "parameters() function", schema: "schema() function", + strategy: "Documentation Strategy", }; diff --git a/website/pages/docs/llm/application.mdx b/website/pages/docs/llm/application.mdx index 5964edd2b1..da2cb4be71 100644 --- a/website/pages/docs/llm/application.mdx +++ b/website/pages/docs/llm/application.mdx @@ -1,6 +1,358 @@ import { Callout, Tabs } from 'nextra/components' ## `application()` function +typia, + ILlmApplication, + ILlmFunction, + ILlmSchema, + ]}> + +```typescript filename="typia" showLineNumbers {2-9} +export namespace llm { + // LLM FUNCTION CALLING APPLICATION SCHEMA + export function application< + App extends Record, + Model extends ILlmSchema.Model, + Config extends Partial = {}, + >( + options?: Partial, "separate">>, + ): ILlmApplication; + + // +VALIDATE FUNCTION EMBEDDED + export function applicationOfValidate< + App extends Record, + Model extends ILlmSchema.Model, + Config extends Partial = {}, + >( + options?: Partial, "separate">>, + ): ILlmApplicationOfValidate; + + // STRUCTURED OUTPUT + export function parameters< + Parameters extends Record, + Model extends ILlmSchema.Model, + Config extends Partial = {}, + >(): ILlmSchema.ModelParameters[Model]; + + // TYPE SCHEMA + export function schema< + T, + Model extends ILlmSchema.Model, + Config extends Partial = {}, + >( + ...$defs: Extract< + ILlmSchema.ModelSchema[Model], + { $ref: string } + > extends never + ? [] + : [Record] + ): ILlmSchema.ModelSchema[Model]; +} +``` + + +```typescript filename="@samchon/openapi" showLineNumbers +import { IGeminiSchema } from "./IGeminiSchema"; +import { ILlmFunction } from "./ILlmFunction"; +import { ILlmSchema } from "./ILlmSchema"; + +/** + * Application of LLM function calling. + * + * `ILlmApplication` is a data structure representing a collection of + * {@link ILlmFunction LLM function calling schemas}, composed from a native + * TypeScript class (or interface) type by the `typia.llm.application()` + * function. + * + * Also, there can be some parameters (or their nested properties) which must be + * composed by Human, not by LLM. File uploading feature or some sensitive information + * like secrety key (password) are the examples. In that case, you can separate the + * function parameters to both LLM and human sides by configuring the + * {@link ILlmApplication.IOptions.separate} property. The separated parameters are + * assigned to the {@link ILlmFunction.separated} property. + * + * For reference, when both LLM and Human filled parameter values to call, you can + * merge them by calling the {@link HttpLlm.mergeParameters} function. In other words, + * if you've configured the {@link ILlmApplication.IOptions.separate} property, you + * have to merge the separated parameters before the funtion call execution. + * + * @reference https://platform.openai.com/docs/guides/function-calling + * @author Jeongho Nam - https://github.com/samchon + */ +export interface ILlmApplication { + /** + * Model of the LLM. + */ + model: Model; + + /** + * List of function metadata. + * + * List of function metadata that can be used for the LLM function call. + */ + functions: ILlmFunction[]; + + /** + * Configuration for the application. + */ + options: ILlmApplication.IOptions; +} +export namespace ILlmApplication { + /** + * Options for application composition. + */ + export type IOptions = { + /** + * Separator function for the parameters. + * + * When composing parameter arguments through LLM function call, + * there can be a case that some parameters must be composed by human, + * or LLM cannot understand the parameter. + * + * For example, if the parameter type has configured + * {@link IGeminiSchema.IString.contentMediaType} which indicates file + * uploading, it must be composed by human, not by LLM + * (Large Language Model). + * + * In that case, if you configure this property with a function that + * predicating whether the schema value must be composed by human or + * not, the parameters would be separated into two parts. + * + * - {@link ILlmFunction.separated.llm} + * - {@link ILlmFunction.separated.human} + * + * When writing the function, note that returning value `true` means + * to be a human composing the value, and `false` means to LLM + * composing the value. Also, when predicating the schema, it would + * better to utilize the {@link GeminiTypeChecker} like features. + * + * @param schema Schema to be separated. + * @returns Whether the schema value must be composed by human or not. + * @default null + */ + separate: null | ((schema: ILlmSchema.ModelSchema[Model]) => boolean); + } & ILlmSchema.ModelConfig[Model]; +} +``` + + +```typescript filename="@samchon/openapi" showLineNumbers +import { ILlmSchema } from "./ILlmSchema"; + +/** + * 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. + * + * @reference https://platform.openai.com/docs/guides/function-calling + * @author Jeongho Nam - https://github.com/samchon + */ +export interface ILlmFunction { + /** + * Representative name of the function. + */ + name: string; + + /** + * List of parameter types. + */ + parameters: ILlmSchema.ModelParameters[Model]; + + /** + * Collection of separated parameters. + */ + separated?: ILlmFunction.ISeparated; + + /** + * Expected return type. + * + * If the function returns nothing (`void`), the `output` value would + * be `undefined`. + */ + output?: ILlmSchema.ModelSchema[Model]; + + /** + * Whether the function schema types are strict or not. + * + * Newly added specification to "OpenAI" at 2024-08-07. + * + * @reference https://openai.com/index/introducing-structured-outputs-in-the-api/ + */ + strict: true; + + /** + * Description of the function. + * + * For reference, the `description` is very important property to teach + * the purpose of the function to the LLM (Language Large Model), and + * LLM actually determines which function to call by the description. + * + * Also, when the LLM conversates with the user, the `description` is + * used to explain the function to the user. Therefore, the `description` + * property has the highest priroity, and you have to consider it. + */ + 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[]; +} +export namespace ILlmFunction { + /** + * Collection of separated parameters. + */ + export interface ISeparated { + /** + * Parameters that would be composed by the LLM. + */ + llm: ILlmSchema.ModelParameters[Model] | null; + + /** + * Parameters that would be composed by the human. + */ + human: ILlmSchema.ModelParameters[Model] | null; + } +} +``` + + +```typescript filename="@samchon/openapi" showLineNumbers +import { IChatGptSchema } from "./IChatGptSchema"; +import { IClaudeSchema } from "./IClaudeSchema"; +import { IGeminiSchema } from "./IGeminiSchema"; +import { ILlamaSchema } from "./ILlamaSchema"; +import { ILlmSchemaV3 } from "./ILlmSchemaV3"; +import { ILlmSchemaV3_1 } from "./ILlmSchemaV3_1"; + +/** + * The schemas for the LLM function calling. + * + * `ILlmSchema` is an union type collecting every the schemas for the + * LLM function calling. + * + * Select a proper schema type according to the LLM provider you're using. + * + * @template Model Name of the target LLM model + * @reference https://platform.openai.com/docs/guides/function-calling + * @reference https://platform.openai.com/docs/guides/structured-outputs + * @author Jeongho Nam - https://github.com/samchon + */ +export type ILlmSchema = + ILlmSchema.ModelSchema[Model]; + +export namespace ILlmSchema { + export type Model = "chatgpt" | "claude" | "gemini" | "llama" | "3.0" | "3.1"; + export interface ModelConfig { + chatgpt: IChatGptSchema.IConfig; + claude: IClaudeSchema.IConfig; + gemini: IGeminiSchema.IConfig; + llama: ILlamaSchema.IConfig; + "3.0": ILlmSchemaV3.IConfig; + "3.1": ILlmSchemaV3_1.IConfig; + } + export interface ModelParameters { + chatgpt: IChatGptSchema.IParameters; + claude: IClaudeSchema.IParameters; + gemini: IGeminiSchema.IParameters; + llama: ILlamaSchema.IParameters; + "3.0": ILlmSchemaV3.IParameters; + "3.1": ILlmSchemaV3_1.IParameters; + } + export interface ModelSchema { + chatgpt: IChatGptSchema; + claude: IClaudeSchema; + gemini: IGeminiSchema; + llama: ILlamaSchema; + "3.0": ILlmSchemaV3; + "3.1": ILlmSchemaV3_1; + } + + /** + * Type of function parameters. + * + * `ILlmSchema.IParameters` is a type defining a function's pamameters + * as a keyworded object type. + * + * It also can be utilized for the structured output metadata. + * + * @reference https://platform.openai.com/docs/guides/structured-outputs + */ + export type IParameters = + ILlmSchema.ModelParameters[Model]; + + /** + * Configuration for the LLM schema composition. + */ + export type IConfig = + ILlmSchema.ModelConfig[Model]; +} +``` + + + +LLM function calling application schema from a native TypeScript class or interface type. + +`typia.llm.application()` is a function composing LLM (Large Language Model) calling application schema from a native TypeScript class or interface type. The function returns an `ILlmApplication` instance, which is a data structure representing a collection of LLM function calling schemas. + +If you put LLM function schema instances registered in the `ILlmApplication.functions` to the LLM provider like `OpenAI ChatGPT`, the LLM will select a proper function to call with parameter values of the target function in the conversations with the user. This is the "LLM Function Calling". + +You can specify the LLM provide model by the second `Model` template argument. It's because detailed specification of the function schema is different by the LLM provider model. Here is the list of LLM schema definitions of each model. Determine one of them carefully reading the LLM schema definitions. + +If you've determined, let's make A.I. Chatbot super-easily with `typia.llm.application()` function. + + - Supported schemas + - [`IChatGptSchema`](https://github.com/samchon/openapi/blob/master/src/structures/IChatGptSchema.ts): OpenAI ChatGPT + - [`IClaudeSchema`](https://github.com/samchon/openapi/blob/master/src/structures/IClaudeSchema.ts): Anthropic Claude + - [`IGeminiSchema`](https://github.com/samchon/openapi/blob/master/src/structures/IGeminiSchema.ts): Google Gemini + - [`ILlamaSchema`](https://github.com/samchon/openapi/blob/master/src/structures/ILlamaSchema.ts): Meta Llama + - Midldle layer schemas + - [`ILlmSchemaV3`](https://github.com/samchon/openapi/blob/master/src/structures/ILlmSchemaV3.ts): middle layer based on OpenAPI v3.0 specification + - [`ILlmSchemaV3_1`](https://github.com/samchon/openapi/blob/master/src/structures/ILlmSchemaV3_1.ts): middle layer based on OpenAPI v3.1 specification + + +**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. + +- https://platform.openai.com/docs/guides/function-calling +- https://platform.openai.com/docs/guides/structured-outputs + + + + + +## `applicationOfValidate()` typia, ILlmApplication, @@ -9,7 +361,7 @@ import { Callout, Tabs } from 'nextra/components' ILlmApplicationOfValidate, ]}> -```typescript filename="typia" showLineNumbers {2-18} +```typescript filename="typia" showLineNumbers {11-18} export namespace llm { // LLM FUNCTION CALLING APPLICATION SCHEMA export function application< @@ -382,333 +734,123 @@ export namespace ILlmApplicationOfValidate { * calling. Also, it's a function structure containing the function * {@link name}, {@link parameters} and {@link output return type}. * - * If you provide this `ILlmFunctionOfValidate` 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. - * - * If the LLM function calling take s a mistake that composing wrong typed - * {@link parameters}, you can correct the parameters by delivering the return - * value of the {@link validate} function. The {@link validate} function is a - * validator function reporting the detailed information about the wrong typed - * {@link parameters}. - * - * By the way, do not ensure that LLM will always provide the correct arguments. - * The LLM of present age is not perfect, and sometimes takes a mistake that composing - * wrong typed {@link parameters}. In that case, you can correc the parameters by - * delivering the return value of the {@link validate} function. The {@link validate} - * function reports the detailed information about the wrong typed {@link parameters}, - * - * @reference https://platform.openai.com/docs/guides/function-calling - * @author Jeongho Nam - https://github.com/samchon - */ -export interface ILlmFunctionOfValidate - extends ILlmFunction { - validate(props: object): IValidation; -} -export namespace ILlmFunctionOfValidate { - export import ISeparated = ILlmFunction.ISeparated; -} -``` - - - -LLM function calling application schema from a native TypeScript class or interface type. - -`typia.llm.application()` is a function composing LLM (Large Language Model) calling application schema from a native TypeScript class or interface type. The function returns an `ILlmApplication` instance, which is a data structure representing a collection of LLM function calling schemas. - -If you put LLM function schema instances registered in the `ILlmApplication.functions` to the LLM provider like `OpenAI ChatGPT`, the LLM will select a proper function to call with parameter values of the target function in the conversations with the user. This is the "LLM Function Calling". - -You can specify the LLM provide model by the second `Model` template argument. It's because detailed specification of the function schema is different by the LLM provider model. Here is the list of LLM schema definitions of each model. Determine one of them carefully reading the LLM schema definitions. - -If you've determined, let's make A.I. Chatbot super-easily with `typia.llm.application()` function. - - - Supported schemas - - [`IChatGptSchema`](https://github.com/samchon/openapi/blob/master/src/structures/IChatGptSchema.ts): OpenAI ChatGPT - - [`IClaudeSchema`](https://github.com/samchon/openapi/blob/master/src/structures/IClaudeSchema.ts): Anthropic Claude - - [`IGeminiSchema`](https://github.com/samchon/openapi/blob/master/src/structures/IGeminiSchema.ts): Google Gemini - - [`ILlamaSchema`](https://github.com/samchon/openapi/blob/master/src/structures/ILlamaSchema.ts): Meta Llama - - Midldle layer schemas - - [`ILlmSchemaV3`](https://github.com/samchon/openapi/blob/master/src/structures/ILlmSchemaV3.ts): middle layer based on OpenAPI v3.0 specification - - [`ILlmSchemaV3_1`](https://github.com/samchon/openapi/blob/master/src/structures/ILlmSchemaV3_1.ts): middle layer based on OpenAPI v3.1 specification - - -**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. - -- https://platform.openai.com/docs/guides/function-calling -- https://platform.openai.com/docs/guides/structured-outputs - - - - - -## Description Comment - - -```typescript filename="example/src/llm.application.simple.ts" showLineNumbers {4} -import { ILlmApplication } from "@samchon/openapi"; -import typia, { tags } from "typia"; - -const app: ILlmApplication<"chatgpt"> = typia.llm.application< - BbsArticleController, - "chatgpt" ->(); - -console.log(app); - -interface BbsArticleController { - /** - * Create a new article. - * - * Writes a new article and archives it into the DB. - * - * @param props Properties of create function - * @returns Newly created article - */ - create(props: { - /** - * Information of the article to create - */ - input: IBbsArticle.ICreate; - }): Promise; - - /** - * Update an article. - * - * Updates an article with new content. - * - * @param props Properties of update function - * @param input New content to update - */ - update(props: { - /** - * Target article's {@link IBbsArticle.id}. - */ - id: string & tags.Format<"uuid">; - - /** - * New content to update. - */ - input: IBbsArticle.IUpdate; - }): Promise; - - /** - * Erase an article. - * - * Erases an article from the DB. - * - * @param props Properties of erase function - */ - erase(props: { - /** - * Target article's {@link IBbsArticle.id}. - */ - id: string & tags.Format<"uuid">; - }): Promise; -} - -/** - * Article entity. - * - * `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System). - */ -interface IBbsArticle extends IBbsArticle.ICreate { - /** - * Primary Key. - */ - id: string & tags.Format<"uuid">; - - /** - * Creation time of the article. - */ - created_at: string & tags.Format<"date-time">; - - /** - * Last updated time of the article. - */ - updated_at: string & tags.Format<"date-time">; -} -namespace IBbsArticle { - /** - * Information of the article to create. - */ - export interface ICreate { - /** - * Title of the article. - * - * Representative title of the article. - */ - title: string; - - /** - * Content body. - * - * Content body of the article writtn in the markdown format. - */ - body: string; - - /** - * Thumbnail image URI. - * - * Thumbnail image URI which can represent the article. - * - * If configured as `null`, it means that no thumbnail image in the article. - */ - thumbnail: - | null - | (string & tags.Format<"uri"> & tags.ContentMediaType<"image/*">); - } - - /** - * Information of the article to update. - * - * Only the filled properties will be updated. - */ - export type IUpdate = Partial; -} -``` - - -```javascript filename="example/bin/llm.application.simple.js" showLineNumbers -import typia from "typia"; - -const app = { - model: "chatgpt", - options: { - reference: false, - separate: null, - }, - functions: [ - { - name: "create", - parameters: { - type: "object", - properties: { - input: { - description: - "Information of the article to create.\n\n------------------------------\n\nDescription of the current {@link IBbsArticle.ICreate} type:\n\n> Information of the article to create.\n\n------------------------------\n\nDescription of the parent {@link IBbsArticle} type:\n\n> Article entity.\n> \n> `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", - type: "object", - properties: { - title: { - title: "Title of the article", - description: - "Title of the article.\n\nRepresentative title of the article.", - type: "string", - }, - body: { - title: "Content body", - description: - "Content body.\n\nContent body of the article writtn in the markdown format.", - type: "string", - }, - thumbnail: { - title: "Thumbnail image URI", - description: - "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", - anyOf: [ - { - type: "null", - }, - { - type: "string", - description: "@format uri\n@contentMediaType image/*", - }, - ], - }, - }, - required: ["title", "body", "thumbnail"], - additionalProperties: false, - }, - }, - required: ["input"], - additionalProperties: false, - $defs: {}, - }, - output: { - description: - "Article entity.\n\n`IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", - type: "object", - properties: { - id: { - title: "Primary Key", - description: "Primary Key.\n\n\n@format uuid", - type: "string", - }, - created_at: { - title: "Creation time of the article", - description: "Creation time of the article.\n\n\n@format date-time", - type: "string", - }, - updated_at: { - title: "Last updated time of the article", - description: - "Last updated time of the article.\n\n\n@format date-time", - type: "string", - }, - title: { - title: "Title of the article", - description: - "Title of the article.\n\nRepresentative title of the article.", - type: "string", - }, - body: { - title: "Content body", - description: - "Content body.\n\nContent body of the article writtn in the markdown format.", - type: "string", - }, - thumbnail: { - title: "Thumbnail image URI", - description: - "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", - anyOf: [ - { - type: "null", - }, - { - type: "string", - description: "@format uri\n@contentMediaType image/*", - }, - ], - }, - }, - required: [ - "id", - "created_at", - "updated_at", - "title", - "body", - "thumbnail", - ], - additionalProperties: false, - }, - description: - "Create a new article.\n\nWrites a new article and archives it into the DB.", - strict: true, - }, - ], -}; -console.log(app); + * If you provide this `ILlmFunctionOfValidate` 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. + * + * If the LLM function calling take s a mistake that composing wrong typed + * {@link parameters}, you can correct the parameters by delivering the return + * value of the {@link validate} function. The {@link validate} function is a + * validator function reporting the detailed information about the wrong typed + * {@link parameters}. + * + * By the way, do not ensure that LLM will always provide the correct arguments. + * The LLM of present age is not perfect, and sometimes takes a mistake that composing + * wrong typed {@link parameters}. In that case, you can correc the parameters by + * delivering the return value of the {@link validate} function. The {@link validate} + * function reports the detailed information about the wrong typed {@link parameters}, + * + * @reference https://platform.openai.com/docs/guides/function-calling + * @author Jeongho Nam - https://github.com/samchon + */ +export interface ILlmFunctionOfValidate + extends ILlmFunction { + validate(props: object): IValidation; +} +export namespace ILlmFunctionOfValidate { + export import ISeparated = ILlmFunction.ISeparated; +} ``` -Here is the example code utilizing the `typia.llm.application()` function. +LLM function calling application schema with validators. + +`typia.llm.applicationOfValidate()` is a function combined `typia.llm.application()` and [`typia.validate()`](../validators/validate) functions. Every function schema instances registered in the `ILlmApplicationOfValidate.functions` have their own parameters validator `ILlmFunctionOfValidate.validate()`, and they will report the detailed information about the wrong typed parameters. + +This validator function is useful when implementing the actual LLM function calling feature. It's because LLM function calling sometimes takes a mistake that composing wrong typed arguments. In that case, you can correct the arguments by delivering the return value of the `ILlmFunctionOfValidate.validate()` function to the LLM provider. Then, the LLM provider will correct the arguments at the next function calling. + +Here is an actual program code correcting the OpenAI (ChatGPT) function calling. + +```typescript filename="ChatGptFunctionCaller.ts" showLineNumbers {22, 33-43, 72} copy +import OpenAI from "openai"; +import typia, { ILlmFunctionOfValidate, IValidation } from "typia"; + +import { ILlmMessage } from "../structures/ILlmMessage"; -As you can see, above example code is writing detailed descriptions for every functions and their parameter/return types. Such detailed descriptions are very important to teach the purpose of the function to the LLM (Language Large Model), and LLM actually determines which function to call by the description. +export namespace ChatGptFunctionCaller { + export interface IProps { + function: ILlmFunctionOfValidate<"chatgpt">; + messages: ILlmMessage[]; + } -Therefore, don't forget to writing detailed descriptions. It's very import feature for the LLM function calling. + export const test = async (props: IProps): Promise => { + let result: IValidation | undefined = undefined; + for (let i: number = 0; i < 3; ++i) { + if (result && result.success === true) break; + result = await step(props, result); + } + }; -Also, the reason every functions defined in the `BbsArticleController` type have only one object typed parameter is, it is the rule of LLM function calling. Such only one object parameter defining with static key-value pairs is called the keyword arguments. If you violate the LLM function calling's keyworded arguments rule, `typia.llm.application` will throw a compilation error. + const step = async ( + props: IProps, + previous?: IValidation.IFailure, + ): Promise> => { + const client: OpenAI = new OpenAI({ + apiKey: "YOUR-SECRET-KEY", + }); + const completion: OpenAI.ChatCompletion = + await client.chat.completions.create({ + model: "gpt-4o", + messages: previous + ? [ + ...props.messages.slice(0, -1), + { + role: "assistant", + content: [ + "You A.I. assistant has composed wrong typed arguments.", + "", + "Here is the detailed list of type errors. Review and correct them at the next function calling.", + "", + "```json", + JSON.stringify(previous.errors, null, 2), + "```", + ].join("\n"), + } satisfies OpenAI.ChatCompletionMessageParam, + ...props.messages.slice(-1), + ] + : props.messages, + tools: [ + { + type: "function", + function: { + name: props.function.name, + description: props.function.description, + parameters: props.function.parameters as Record, + }, + }, + ], + tool_choice: "required", + parallel_tool_calls: false, + }); + + const toolCalls: OpenAI.ChatCompletionMessageToolCall[] = completion.choices + .map((c) => c.message.tool_calls ?? []) + .flat(); + if (toolCalls.length === 0) + throw new Error("ChatGPT has not called any function."); + + const results: IValidation[] = toolCalls.map((call) => { + const { input } = typia.assert<{ input: any }>( + JSON.parse(call.function.arguments), + ); + return props.function.validate(input); + }); + return results.find((r) => r.success === true) ?? results[0]; + }; +} +``` @@ -1113,506 +1255,6 @@ interface BbsArticleController { -## Function Hiding -Hiding some functions by comment tag. - -If you write `@hidden`, `@human` or `@internal` tag onto a function description comment, the function would not participate in the LLM (Large Language Model) function calling application composition. `ILlmFunction` schema does not be genrated in the `ILlmApplication.functions` collection. - -It's a good feature to hide some internal functions, so that avoiding the LLM function calling. - - - -```typescript filename="example/src/llm.application.hideden.ts" showLineNumbers {38, 54, 74} -import { - ClaudeTypeChecker, - ILlmApplication, - ILlmSchema, -} from "@samchon/openapi"; -import typia, { tags } from "typia"; - -const app: ILlmApplication<"chatgpt"> = typia.llm.application< - BbsArticleController, - "chatgpt" ->(); - -console.log(app); - -interface BbsArticleController { - /** - * Create a new article. - * - * Writes a new article and archives it into the DB. - * - * @param props Properties of create function - * @returns Newly created article - */ - create(props: { - /** - * Information of the article to create - */ - input: IBbsArticle.ICreate; - }): Promise; - - /** - * Read an article. - * - * Reads an article from the DB. - * - * @param props Properties of read function - * @returns The article - * @hidden - */ - at(props: { - /** - * Target article's {@link IBbsArticle.id}. - */ - id: string & tags.Format<"uuid">; - }): Promise; - - /** - * Update an article. - * - * Updates an article with new content. - * - * @param props Properties of update function - * @param input New content to update - * @internal - */ - update(props: { - /** - * Target article's {@link IBbsArticle.id}. - */ - id: string & tags.Format<"uuid">; - - /** - * New content to update. - */ - input: IBbsArticle.IUpdate; - }): Promise; - - /** - * Erase an article. - * - * Erases an article from the DB. - * - * @param props Properties of erase function - * @human - */ - erase(props: { - /** - * Target article's {@link IBbsArticle.id}. - */ - id: string & tags.Format<"uuid">; - }): Promise; -} -``` - - -```javascript filename="example/bin/llm.application.hideden.js" showLineNumbers -import typia from "typia"; -const app = { - model: "chatgpt", - options: { - reference: false, - separate: null, - }, - functions: [ - { - name: "create", - parameters: { - type: "object", - properties: { - input: { - description: - "Information of the article to create.\n\n------------------------------\n\nDescription of the current {@link IBbsArticle.ICreate} type:\n\n> Information of the article to create.\n\n------------------------------\n\nDescription of the parent {@link IBbsArticle} type:\n\n> Article entity.\n> \n> `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", - type: "object", - properties: { - title: { - title: "Title of the article", - description: - "Title of the article.\n\nRepresentative title of the article.", - type: "string", - }, - body: { - title: "Content body", - description: - "Content body.\n\nContent body of the article writtn in the markdown format.", - type: "string", - }, - thumbnail: { - title: "Thumbnail image URI", - description: - "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", - anyOf: [ - { - type: "null", - }, - { - type: "string", - description: "@format uri\n@contentMediaType image/*", - }, - ], - }, - }, - required: ["title", "body", "thumbnail"], - additionalProperties: false, - }, - }, - required: ["input"], - additionalProperties: false, - $defs: {}, - }, - output: { - description: - "Article entity.\n\n`IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", - type: "object", - properties: { - id: { - title: "Primary Key", - description: "Primary Key.\n\n\n@format uuid", - type: "string", - }, - created_at: { - title: "Creation time of the article", - description: "Creation time of the article.\n\n\n@format date-time", - type: "string", - }, - updated_at: { - title: "Last updated time of the article", - description: - "Last updated time of the article.\n\n\n@format date-time", - type: "string", - }, - title: { - title: "Title of the article", - description: - "Title of the article.\n\nRepresentative title of the article.", - type: "string", - }, - body: { - title: "Content body", - description: - "Content body.\n\nContent body of the article writtn in the markdown format.", - type: "string", - }, - thumbnail: { - title: "Thumbnail image URI", - description: - "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", - anyOf: [ - { - type: "null", - }, - { - type: "string", - description: "@format uri\n@contentMediaType image/*", - }, - ], - }, - }, - required: [ - "id", - "created_at", - "updated_at", - "title", - "body", - "thumbnail", - ], - additionalProperties: false, - }, - description: - "Create a new article.\n\nWrites a new article and archives it into the DB.", - strict: true, - }, - { - name: "update", - parameters: { - type: "object", - properties: { - id: { - title: "Target article's {@link IBbsArticle.id}", - description: - "Target article's {@link IBbsArticle.id}.\n\n\n@format uuid", - type: "string", - }, - input: { - description: - "Make all properties in T optional\n\n------------------------------\n\nDescription of the current {@link PartialIBbsArticle.ICreate} type:\n\n> Make all properties in T optional", - type: "object", - properties: { - title: { - title: "Title of the article", - description: - "Title of the article.\n\nRepresentative title of the article.", - type: "string", - }, - body: { - title: "Content body", - description: - "Content body.\n\nContent body of the article writtn in the markdown format.", - type: "string", - }, - thumbnail: { - title: "Thumbnail image URI", - description: - "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", - anyOf: [ - { - type: "null", - }, - { - type: "string", - description: "@format uri\n@contentMediaType image/*", - }, - ], - }, - }, - required: ["title", "body", "thumbnail"], - additionalProperties: false, - }, - }, - required: ["id", "input"], - additionalProperties: false, - $defs: {}, - }, - description: "Update an article.\n\nUpdates an article with new content.", - strict: true, - }, - ], -}; -console.log(app); -``` - - - - - - -## Specialization -You can utilize [type tags](../validators/tags/#type-tags) (or [validator's comment tags](../validators/tags/#comment-tags)) to constructing special fields of JSON schema. - -If you write any comment on a property, it would fill the `IJsonSchema.description` value. Also, there're special comment tags only for JSON schema definition that are different with [validator's comment tags](../validators/tags/#comment-tags) like below. - - - `@deprecated` - - `@hidden` - - `@internal` - - `@title {string}` - - `@default {value}` - -Let's see how those [type tags](../validators/tags/#type-tags), comment tags and description comments are working with example code. - - - -```typescript copy filename="examples/src/llm-schema.ts" showLineNumbers -import { IChatGptSchema } from "@samchon/openapi"; -import typia, { tags } from "typia"; - -export const schema: IChatGptSchema = typia.llm.schema(); - -interface Special { - /** - * Deprecated tags are just used for marking. - * - * @title Unsigned integer - * @deprecated - */ - type: number & tags.Type<"int32">; - - /** - * Internal tagged property never be shown in JSON schema. - * - * It even doesn't be shown in other `typia` functions like `assert()`. - * - * @internal - */ - internal: number[]; - - /** - * Hidden tagged property never be shown in JSON schema. - * - * However, it would be shown in other `typia` functions like `stringify()`. - * - * @hidden - */ - hidden: boolean; - - /** - * You can limit the range of number. - * - * @exclusiveMinimum 19 - * @maximum 100 - * @default 30 - */ - number?: number; - - /** - * You can limit the length of string. - * - * Also, multiple range conditions are also possible. - */ - string: string & - ( - | (tags.MinLength<3> & tags.MaxLength<24>) - | (tags.MinLength<40> & tags.MaxLength<100>) - ); - - /** - * You can limit the pattern of string. - * - * @pattern ^[a-z]+$ - */ - pattern: string; - - /** - * You can limit the format of string. - * - * @format date-time - */ - format: string | null; - - /** - * In the Array case, possible to restrict its elements. - */ - array: Array> & tags.MinItems<3>; -} -``` - - -```javascript filename="examples/bin/llm-schema.js" showLineNumbers -import typia from "typia"; -export const schema = { - type: "object", - properties: { - type: { - type: "integer", - deprecated: true, - title: "Unsigned integer", - description: "Deprecated tags are just used for marking.", - }, - number: { - type: "number", - exclusiveMinimum: true, - minimum: 19, - maximum: 100, - title: "You can limit the range of number", - description: "You can limit the range of number.", - }, - string: { - oneOf: [ - { - type: "string", - minLength: 3, - maxLength: 24, - }, - { - type: "string", - minLength: 40, - maxLength: 100, - }, - ], - title: "You can limit the length of string", - description: - "You can limit the length of string.\n\nAlso, multiple range conditions are also possible.", - }, - pattern: { - type: "string", - pattern: "^[a-z]+$", - title: "You can limit the pattern of string", - description: "You can limit the pattern of string.", - }, - format: { - oneOf: [ - { - type: "string", - format: "date-time", - }, - { - type: "null", - }, - ], - title: "You can limit the format of string", - description: "You can limit the format of string.", - }, - array: { - type: "array", - items: { - type: "string", - format: "uuid", - }, - minItems: 3, - title: "In the Array case, possible to restrict its elements", - description: "In the Array case, possible to restrict its elements.", - }, - }, - required: ["type", "string", "pattern", "format", "array"], - additionalProperties: false, -}; -``` - - - - - - -## Customziation -If what you want is not just filling regular properties of LLM schema specification, but to adding custom properties into the JSON schema definition, you can do it through the `tags.TagBase.schema` property type or `tags.JsonSchemaPlugin` type. - -For reference, the custom property must be started with `x-` prefix. It's a rule of LLM schema. - - - -```typescript copy filename="examples/src/llm-schema-custom.ts" copy showLineNumbers {7-9, 13, 17-18} -import typia, { tags } from "typia"; - -type Monetary = tags.TagBase<{ - target: "number"; - kind: "monetary"; - value: Value; - schema: { - "x-monetary": Value; - }; -}>; - -type Placeholder = tags.JsonSchemaPlugin<{ - "x-placeholder": Value; -}>; - -interface IAccount { - code: string & Placeholder<"Write you account code please">; - balance: number & Monetary<"dollar">; -}; - -typia.llm.schema(); -``` - - -```javascript copy filename="examples/bin/llm-schema-custom.js" showLineNumbers {7, 11} -import typia from "typia"; -({ - type: "object", - properties: { - code: { - type: "string", - "x-placeholder": "Write you account code please", - }, - balance: { - type: "number", - "x-monetary": "dollar", - }, - }, - required: ["code", "balance"], - additionalProperties: false, -}); -``` - - - - - - ## Restrictions `typia.llm.application()` follows the same restrictions of below. diff --git a/website/pages/docs/llm/strategy.mdx b/website/pages/docs/llm/strategy.mdx new file mode 100644 index 0000000000..8bf75e9b44 --- /dev/null +++ b/website/pages/docs/llm/strategy.mdx @@ -0,0 +1,1221 @@ +import { Callout, Tabs } from 'nextra/components' + +## Description Comment + + +```typescript filename="example/src/llm.application.bbs.ts" showLineNumbers copy +import { ILlmApplication, ILlmFunction } from "@samchon/openapi"; +import typia, { tags } from "typia"; + +const app: ILlmApplication<"chatgpt"> = typia.llm.application< + BbsArticleController, + "chatgpt" +>(); +const func: ILlmFunction<"chatgpt"> | undefined = app.functions.find( + func => func.name === "create" +); +console.log(func?.description); + +interface BbsArticleController { + /** + * Create a new article. + * + * Writes a new article and archives it into the DB. + * + * @param props Properties of create function + * @returns Newly created article + */ + create(props: { + /** + * Information of the article to create + */ + input: IBbsArticle.ICreate; + }): Promise; + + /** + * Update an article. + * + * Updates an article with new content. + * + * @param props Properties of update function + * @param input New content to update + */ + update(props: { + /** + * Target article's {@link IBbsArticle.id}. + */ + id: string & tags.Format<"uuid">; + + /** + * New content to update. + */ + input: IBbsArticle.IUpdate; + }): Promise; + + /** + * Erase an article. + * + * Erases an article from the DB. + * + * @param props Properties of erase function + */ + erase(props: { + /** + * Target article's {@link IBbsArticle.id}. + */ + id: string & tags.Format<"uuid">; + }): Promise; +} + +/** + * Article entity. + * + * `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System). + */ +interface IBbsArticle extends IBbsArticle.ICreate { + /** + * Primary Key. + */ + id: string & tags.Format<"uuid">; + + /** + * Creation time of the article. + */ + created_at: string & tags.Format<"date-time">; + + /** + * Last updated time of the article. + */ + updated_at: string & tags.Format<"date-time">; +} +namespace IBbsArticle { + /** + * Information of the article to create. + */ + export interface ICreate { + /** + * Title of the article. + * + * Representative title of the article. + */ + title: string; + + /** + * Content body. + * + * Content body of the article writtn in the markdown format. + */ + body: string; + + /** + * Thumbnail image URI. + * + * Thumbnail image URI which can represent the article. + * + * If configured as `null`, it means that no thumbnail image in the article. + */ + thumbnail: + | null + | (string & tags.Format<"uri"> & tags.ContentMediaType<"image/*">); + } + + /** + * Information of the article to update. + * + * Only the filled properties will be updated. + */ + export type IUpdate = Partial; +} +``` + + +```javascript filename="example/src/llm.application.bbs.js" showLineNumbers +import typia from "typia"; +const app = { + model: "chatgpt", + options: { + reference: false, + strict: false, + separate: null, + }, + functions: [ + { + name: "create", + parameters: { + description: " Properties of create function", + type: "object", + properties: { + input: { + description: + "Information of the article to create.\n\n------------------------------\n\nDescription of the current {@link IBbsArticle.ICreate} type:\n\n> Information of the article to create.\n\n------------------------------\n\nDescription of the parent {@link IBbsArticle} type:\n\n> Article entity.\n> \n> `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", + type: "object", + properties: { + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: ["title", "body", "thumbnail"], + }, + }, + required: ["input"], + additionalProperties: false, + $defs: {}, + }, + output: { + description: + "Article entity.\n\n`IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", + type: "object", + properties: { + id: { + title: "Primary Key", + description: "Primary Key.\n\n\n@format uuid", + type: "string", + }, + created_at: { + title: "Creation time of the article", + description: "Creation time of the article.\n\n\n@format date-time", + type: "string", + }, + updated_at: { + title: "Last updated time of the article", + description: + "Last updated time of the article.\n\n\n@format date-time", + type: "string", + }, + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: [ + "id", + "created_at", + "updated_at", + "title", + "body", + "thumbnail", + ], + }, + description: + "Create a new article.\n\nWrites a new article and archives it into the DB.", + }, + { + name: "update", + parameters: { + description: " Properties of update function", + type: "object", + properties: { + id: { + title: "Target article's {@link IBbsArticle.id}", + description: + "Target article's {@link IBbsArticle.id}.\n\n\n@format uuid", + type: "string", + }, + input: { + description: + "Make all properties in T optional\n\n------------------------------\n\nDescription of the current {@link PartialIBbsArticle.ICreate} type:\n\n> Make all properties in T optional", + type: "object", + properties: { + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: [], + }, + }, + required: ["id", "input"], + additionalProperties: false, + $defs: {}, + }, + description: "Update an article.\n\nUpdates an article with new content.", + }, + { + name: "erase", + parameters: { + description: " Properties of erase function", + type: "object", + properties: { + id: { + title: "Target article's {@link IBbsArticle.id}", + description: + "Target article's {@link IBbsArticle.id}.\n\n\n@format uuid", + type: "string", + }, + }, + required: ["id"], + additionalProperties: false, + $defs: {}, + }, + description: "Erase an article.\n\nErases an article from the DB.", + }, + ], +}; +const func = app.functions.find((func) => func.name === "create"); +console.log(func?.description); +console.log(func?.parameters.description); +console.log(func?.output?.description); +``` + + +```bash filename="Terminal" +Create a new article. + +Writes a new article and archives it into the DB. +``` + + + +Here is the example code utilizing the `typia.llm.application()` function. + +As you can see, above example code is writing detailed descriptions for every functions and their parameter/return types. Such detailed descriptions are very important to teach the purpose of the function to the LLM (Language Large Model), and LLM actually determines which function to call by the description. Therefore, don’t forget to writing detailed descriptions. It’s very import feature for the LLM function calling. + +Also, `ILlmFunction` type which has only `description` property about the comment, but `ILlmSchema` has two descriptive properties; `description` and `title`. The `title` property of the `ILlmSchema` can be filled by two ways. The first way is closing the first line of the description comment with a period (`.`). By the way, this way's `description` property would be the entire description comment even including the first line. + +If you don't want that, you can adapt the second way that writing `@title {string}` comment tag. In that case, the `title` value would not be contained in the `description` value. For reference, it is possible to fill the `description` property of the `ILlmSchema` by the comment tag `@description`, but you have to take care of the indentation like below. + +```typescript filename="src/structures/IMember.ts" showLineNumbers +interface IMember { + /** + * Primary Key. + * + * Above "Primary Key" would be the title of LLM schema. + */ + id: string; + + /** + * Below "Age of the member" would be the title of LLM schema. + * + * @title Age of the member + */ + age: number; + + /** + * @title Email address of the member + * @description The description property also can be filled by + * the comment tag `@description`. Instead, be + * careful about the indentation. + */ + email: string; +} +``` + + + + +## Namespace Strategy + + +```typescript filename="example/src/llm.application.bbs.ts" showLineNumbers {13-18, 35-38, 65-70} copy +import { ILlmApplication, ILlmFunction } from "@samchon/openapi"; +import typia, { tags } from "typia"; + +const app: ILlmApplication<"chatgpt"> = typia.llm.application< + BbsArticleController, + "chatgpt", +>(); +const func: ILlmFunction<"chatgpt"> | undefined = app.functions.find( + func => func.name === "create" +); +console.log(func?.parameters.properties.input?.description); + +/** + * Article entity. + * + * `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System). + */ +interface IBbsArticle extends IBbsArticle.ICreate { + /** + * Primary Key. + */ + id: string & tags.Format<"uuid">; + + /** + * Creation time of the article. + */ + created_at: string & tags.Format<"date-time">; + + /** + * Last updated time of the article. + */ + updated_at: string & tags.Format<"date-time">; +} +namespace IBbsArticle { + /** + * Information of the article to create. + */ + export interface ICreate { + /** + * Title of the article. + * + * Representative title of the article. + */ + title: string; + + /** + * Content body. + * + * Content body of the article writtn in the markdown format. + */ + body: string; + + /** + * Thumbnail image URI. + * + * Thumbnail image URI which can represent the article. + * + * If configured as `null`, it means that no thumbnail image in the article. + */ + thumbnail: + | null + | (string & tags.Format<"uri"> & tags.ContentMediaType<"image/*">); + } + + /** + * Information of the article to update. + * + * Only the filled properties will be updated. + */ + export type IUpdate = Partial; +} + +interface BbsArticleController { + /** + * Create a new article. + * + * Writes a new article and archives it into the DB. + * + * @param props Properties of create function + * @returns Newly created article + */ + create(props: { + /** + * Information of the article to create + */ + input: IBbsArticle.ICreate; + }): Promise; + + /** + * Update an article. + * + * Updates an article with new content. + * + * @param props Properties of update function + * @param input New content to update + */ + update(props: { + /** + * Target article's {@link IBbsArticle.id}. + */ + id: string & tags.Format<"uuid">; + + /** + * New content to update. + */ + input: IBbsArticle.IUpdate; + }): Promise; + + /** + * Erase an article. + * + * Erases an article from the DB. + * + * @param props Properties of erase function + */ + erase(props: { + /** + * Target article's {@link IBbsArticle.id}. + */ + id: string & tags.Format<"uuid">; + }): Promise; +} +``` + + +```javascript filename="example/src/llm.application.bbs.js" showLineNumbers +import typia from "typia"; +const app = { + model: "chatgpt", + options: { + reference: false, + strict: false, + separate: null, + }, + functions: [ + { + name: "create", + parameters: { + description: " Properties of create function", + type: "object", + properties: { + input: { + description: + "Information of the article to create.\n\n------------------------------\n\nDescription of the current {@link IBbsArticle.ICreate} type:\n\n> Information of the article to create.\n\n------------------------------\n\nDescription of the parent {@link IBbsArticle} type:\n\n> Article entity.\n> \n> `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", + type: "object", + properties: { + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: ["title", "body", "thumbnail"], + }, + }, + required: ["input"], + additionalProperties: false, + $defs: {}, + }, + output: { + description: + "Article entity.\n\n`IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", + type: "object", + properties: { + id: { + title: "Primary Key", + description: "Primary Key.\n\n\n@format uuid", + type: "string", + }, + created_at: { + title: "Creation time of the article", + description: "Creation time of the article.\n\n\n@format date-time", + type: "string", + }, + updated_at: { + title: "Last updated time of the article", + description: + "Last updated time of the article.\n\n\n@format date-time", + type: "string", + }, + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: [ + "id", + "created_at", + "updated_at", + "title", + "body", + "thumbnail", + ], + }, + description: + "Create a new article.\n\nWrites a new article and archives it into the DB.", + }, + { + name: "update", + parameters: { + description: " Properties of update function", + type: "object", + properties: { + id: { + title: "Target article's {@link IBbsArticle.id}", + description: + "Target article's {@link IBbsArticle.id}.\n\n\n@format uuid", + type: "string", + }, + input: { + description: + "Make all properties in T optional\n\n------------------------------\n\nDescription of the current {@link PartialIBbsArticle.ICreate} type:\n\n> Make all properties in T optional", + type: "object", + properties: { + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: [], + }, + }, + required: ["id", "input"], + additionalProperties: false, + $defs: {}, + }, + description: "Update an article.\n\nUpdates an article with new content.", + }, + { + name: "erase", + parameters: { + description: " Properties of erase function", + type: "object", + properties: { + id: { + title: "Target article's {@link IBbsArticle.id}", + description: + "Target article's {@link IBbsArticle.id}.\n\n\n@format uuid", + type: "string", + }, + }, + required: ["id"], + additionalProperties: false, + $defs: {}, + }, + description: "Erase an article.\n\nErases an article from the DB.", + }, + ], +}; +const func = app.functions.find((func) => func.name === "create"); +console.log(func?.parameters.properties.input?.description); +``` + + +```bash filename="Terminal" +Information of the article to create. + +------------------------------ + +Description of the current {@link IBbsArticle.ICreate} type: + +Information of the article to create. + +> Description of the parent {@link IBbsArticle} type: Article entity. +> +> `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System). +``` + + + +`typia.llm.application()` copies the parent namespaced type description comment to the children types. `typia` calls this comment writing strategy as namespace documentation, and it is recommended for the efficient documentation. + +As you can see from the above example, `BbsArticleController` has many CRUD functions about the `IBbsArticle` namespaced type. By the way, the above `IBbsArticle.ICreate` and `IBbsArticle.IUpdate` types are not repeating same description comments about the `IBbsArticle` type. Instead, just writing the short description comment about them, and just compose the LLM function calling application schema. + +In that case, the `IBbsArticle` type's description comment would be copied to the `IBbsArticle.ICreate` and `IBbsArticle.IUpdate` types like above "Console Output" case. It's a good strategy to avoid repeating same description comments, and also to deliver enough information to the LLM function calling. + + + +## Function Hiding + + +```typescript filename="example/src/llm.application.hideden.ts" showLineNumbers {38, 54, 74} +import { + ClaudeTypeChecker, + ILlmApplication, + ILlmSchema, +} from "@samchon/openapi"; +import typia, { tags } from "typia"; + +const app: ILlmApplication<"chatgpt"> = typia.llm.application< + BbsArticleController, + "chatgpt" +>(); + +console.log(app); + +interface BbsArticleController { + /** + * Create a new article. + * + * Writes a new article and archives it into the DB. + * + * @param props Properties of create function + * @returns Newly created article + */ + create(props: { + /** + * Information of the article to create + */ + input: IBbsArticle.ICreate; + }): Promise; + + /** + * Read an article. + * + * Reads an article from the DB. + * + * @param props Properties of read function + * @returns The article + * @hidden + */ + at(props: { + /** + * Target article's {@link IBbsArticle.id}. + */ + id: string & tags.Format<"uuid">; + }): Promise; + + /** + * Update an article. + * + * Updates an article with new content. + * + * @param props Properties of update function + * @param input New content to update + * @internal + */ + update(props: { + /** + * Target article's {@link IBbsArticle.id}. + */ + id: string & tags.Format<"uuid">; + + /** + * New content to update. + */ + input: IBbsArticle.IUpdate; + }): Promise; + + /** + * Erase an article. + * + * Erases an article from the DB. + * + * @param props Properties of erase function + * @human + */ + erase(props: { + /** + * Target article's {@link IBbsArticle.id}. + */ + id: string & tags.Format<"uuid">; + }): Promise; +} +``` + + +```javascript filename="example/bin/llm.application.hideden.js" showLineNumbers +import typia from "typia"; +const app = { + model: "chatgpt", + options: { + reference: false, + separate: null, + }, + functions: [ + { + name: "create", + parameters: { + type: "object", + properties: { + input: { + description: + "Information of the article to create.\n\n------------------------------\n\nDescription of the current {@link IBbsArticle.ICreate} type:\n\n> Information of the article to create.\n\n------------------------------\n\nDescription of the parent {@link IBbsArticle} type:\n\n> Article entity.\n> \n> `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", + type: "object", + properties: { + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: ["title", "body", "thumbnail"], + additionalProperties: false, + }, + }, + required: ["input"], + additionalProperties: false, + $defs: {}, + }, + output: { + description: + "Article entity.\n\n`IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).", + type: "object", + properties: { + id: { + title: "Primary Key", + description: "Primary Key.\n\n\n@format uuid", + type: "string", + }, + created_at: { + title: "Creation time of the article", + description: "Creation time of the article.\n\n\n@format date-time", + type: "string", + }, + updated_at: { + title: "Last updated time of the article", + description: + "Last updated time of the article.\n\n\n@format date-time", + type: "string", + }, + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: [ + "id", + "created_at", + "updated_at", + "title", + "body", + "thumbnail", + ], + additionalProperties: false, + }, + description: + "Create a new article.\n\nWrites a new article and archives it into the DB.", + strict: true, + }, + { + name: "update", + parameters: { + type: "object", + properties: { + id: { + title: "Target article's {@link IBbsArticle.id}", + description: + "Target article's {@link IBbsArticle.id}.\n\n\n@format uuid", + type: "string", + }, + input: { + description: + "Make all properties in T optional\n\n------------------------------\n\nDescription of the current {@link PartialIBbsArticle.ICreate} type:\n\n> Make all properties in T optional", + type: "object", + properties: { + title: { + title: "Title of the article", + description: + "Title of the article.\n\nRepresentative title of the article.", + type: "string", + }, + body: { + title: "Content body", + description: + "Content body.\n\nContent body of the article writtn in the markdown format.", + type: "string", + }, + thumbnail: { + title: "Thumbnail image URI", + description: + "Thumbnail image URI.\n\nThumbnail image URI which can represent the article.\n\nIf configured as `null`, it means that no thumbnail image in the article.", + anyOf: [ + { + type: "null", + }, + { + type: "string", + description: "@format uri\n@contentMediaType image/*", + }, + ], + }, + }, + required: ["title", "body", "thumbnail"], + additionalProperties: false, + }, + }, + required: ["id", "input"], + additionalProperties: false, + $defs: {}, + }, + description: "Update an article.\n\nUpdates an article with new content.", + strict: true, + }, + ], +}; +console.log(app); +``` + + + +Hiding some functions by comment tag. + +If you write `@hidden`, `@human` or `@internal` tag onto a function description comment, the function would not participate in the LLM (Large Language Model) function calling application composition. `ILlmFunction` schema does not be genrated in the `ILlmApplication.functions` collection. + +It's a good feature to hide some internal functions, so that avoiding the LLM function calling. + + + + +## Specialization + + +```typescript copy filename="examples/src/llm-schema.ts" showLineNumbers +import { IChatGptSchema } from "@samchon/openapi"; +import typia, { tags } from "typia"; + +export const schema: IChatGptSchema = typia.llm.schema(); + +interface Special { + /** + * Deprecated tags are just used for marking. + * + * @title Unsigned integer + * @deprecated + */ + type: number & tags.Type<"int32">; + + /** + * Internal tagged property never be shown in JSON schema. + * + * It even doesn't be shown in other `typia` functions like `assert()`. + * + * @internal + */ + internal: number[]; + + /** + * Hidden tagged property never be shown in JSON schema. + * + * However, it would be shown in other `typia` functions like `stringify()`. + * + * @hidden + */ + hidden: boolean; + + /** + * You can limit the range of number. + * + * @exclusiveMinimum 19 + * @maximum 100 + * @default 30 + */ + number?: number; + + /** + * You can limit the length of string. + * + * Also, multiple range conditions are also possible. + */ + string: string & + ( + | (tags.MinLength<3> & tags.MaxLength<24>) + | (tags.MinLength<40> & tags.MaxLength<100>) + ); + + /** + * You can limit the pattern of string. + * + * @pattern ^[a-z]+$ + */ + pattern: string; + + /** + * You can limit the format of string. + * + * @format date-time + */ + format: string | null; + + /** + * In the Array case, possible to restrict its elements. + */ + array: Array> & tags.MinItems<3>; +} +``` + + +```javascript filename="examples/bin/llm-schema.js" showLineNumbers +import typia from "typia"; +export const schema = { + type: "object", + properties: { + type: { + type: "integer", + deprecated: true, + title: "Unsigned integer", + description: "Deprecated tags are just used for marking.", + }, + number: { + type: "number", + exclusiveMinimum: true, + minimum: 19, + maximum: 100, + title: "You can limit the range of number", + description: "You can limit the range of number.", + }, + string: { + oneOf: [ + { + type: "string", + minLength: 3, + maxLength: 24, + }, + { + type: "string", + minLength: 40, + maxLength: 100, + }, + ], + title: "You can limit the length of string", + description: + "You can limit the length of string.\n\nAlso, multiple range conditions are also possible.", + }, + pattern: { + type: "string", + pattern: "^[a-z]+$", + title: "You can limit the pattern of string", + description: "You can limit the pattern of string.", + }, + format: { + oneOf: [ + { + type: "string", + format: "date-time", + }, + { + type: "null", + }, + ], + title: "You can limit the format of string", + description: "You can limit the format of string.", + }, + array: { + type: "array", + items: { + type: "string", + format: "uuid", + }, + minItems: 3, + title: "In the Array case, possible to restrict its elements", + description: "In the Array case, possible to restrict its elements.", + }, + }, + required: ["type", "string", "pattern", "format", "array"], + additionalProperties: false, +}; +``` + + + +You can utilize [type tags](../validators/tags/#type-tags) (or [validator's comment tags](../validators/tags/#comment-tags)) to constructing special fields of JSON schema. + +If you write any comment on a property, it would fill the `IJsonSchema.description` value. Also, there're special comment tags only for JSON schema definition that are different with [validator's comment tags](../validators/tags/#comment-tags) like below. + + - `@deprecated` + - `@hidden` + - `@internal` + - `@title {string}` + - `@default {value}` + +Let's see how those [type tags](../validators/tags/#type-tags), comment tags and description comments are working with example code. + + + + +## Customization +If what you want is not just filling regular properties of LLM schema specification, but to adding custom properties into the JSON schema definition, you can do it through the `tags.TagBase.schema` property type or `tags.JsonSchemaPlugin` type. + +For reference, the custom property must be started with `x-` prefix. It's a rule of LLM schema. + + + +```typescript copy filename="examples/src/llm-schema-custom.ts" copy showLineNumbers {7-9, 13, 17-18} +import typia, { tags } from "typia"; + +type Monetary = tags.TagBase<{ + target: "number"; + kind: "monetary"; + value: Value; + schema: { + "x-monetary": Value; + }; +}>; + +type Placeholder = tags.JsonSchemaPlugin<{ + "x-placeholder": Value; +}>; + +interface IAccount { + code: string & Placeholder<"Write you account code please">; + balance: number & Monetary<"dollar">; +}; + +typia.llm.schema(); +``` + + +```javascript copy filename="examples/bin/llm-schema-custom.js" showLineNumbers {7, 11} +import typia from "typia"; +({ + type: "object", + properties: { + code: { + type: "string", + "x-placeholder": "Write you account code please", + }, + balance: { + type: "number", + "x-monetary": "dollar", + }, + }, + required: ["code", "balance"], + additionalProperties: false, +}); +``` + + \ No newline at end of file