diff --git a/README.md b/README.md index 593a0fb..c22311c 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,90 @@ -# 4oEverPrompt +# Zod AI Prompt Samples -Challenge: reproduce GPT-4o-like responses using GPT-5. -(Inspired by #Keep4o) +A collection of sample prompts that demonstrate techniques for using **Zod TypeScript schemas** as structured prompts for AI language models. -- Currently, I am trying it out with ChatGPT5 Thinking. +[日本語](./README_ja.md) -## Zod +## Concept -- Zodのバージョン: ^4.0.2 +Zod schemas can be used as powerful, type-safe prompts for AI. By providing a schema definition to an LLM, you can: -### 依存関係の導入手順 +- **Structure AI outputs** with predictable formats +- **Validate responses** against defined constraints +- **Guide AI behavior** through schema descriptions and refinements +- **Control output length** with min/max constraints +- **Enforce patterns** with regex and custom validations + +This approach bridges the gap between free-form AI generation and type-safe application development. + +## Using with Structured Outputs + +For production use, we recommend using **Structured Output** features provided by AI providers. This ensures responses strictly conform to your Zod schema: + +| Provider | Feature | Conversion | +|----------|---------|------------| +| **OpenAI** | [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) | `zodResponseFormat()` from `openai/helpers/zod` | +| **Anthropic** | [Tool Use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use) | `zodToJsonSchema()` from `zod-to-json-schema` | +| **Google** | [responseSchema](https://ai.google.dev/gemini-api/docs/json-mode) | `zodToJsonSchema()` | +| **Vercel AI SDK** | [generateObject()](https://sdk.vercel.ai/docs/ai-sdk-core/generating-structured-data) | Native Zod support | + +### Example: OpenAI Structured Outputs + +```ts +import OpenAI from "openai"; +import { zodResponseFormat } from "openai/helpers/zod"; +import { replySchema } from "./samples/4oEverPrompt/schema"; + +const client = new OpenAI(); +const response = await client.beta.chat.completions.parse({ + model: "gpt-4o", + messages: [{ role: "user", content: userMessage }], + response_format: zodResponseFormat(replySchema, "reply"), +}); + +const reply = response.choices[0].message.parsed; // Typed as Reply +``` + +### Example: Vercel AI SDK + +```ts +import { generateObject } from "ai"; +import { openai } from "@ai-sdk/openai"; +import { replySchema } from "./samples/4oEverPrompt/schema"; + +const { object } = await generateObject({ + model: openai("gpt-4o"), + schema: replySchema, + prompt: userMessage, +}); +``` + +## Installation ```sh npm install ``` + +## Samples + +### [4oEverPrompt](./samples/4oEverPrompt/) + +A prompt technique designed to reproduce GPT-4o-like friendly, engaging responses using newer models like GPT-5. The schema defines a structured reply format with: + +- Emoji-prefixed headers +- Reframed user input section +- Progressive content sections leading to a final message +- Emotional, entertaining writing style with markdown formatting + +**Inspired by #Keep4o movement.** + +## Dependencies + +- **Zod**: ^4.0.2 + +## Contributing + +Feel free to contribute new samples! Each sample should demonstrate a unique technique for using Zod schemas as AI prompts. + +## License + +MIT diff --git a/README_ja.md b/README_ja.md new file mode 100644 index 0000000..5e96622 --- /dev/null +++ b/README_ja.md @@ -0,0 +1,90 @@ +# Zod AI プロンプトサンプル集 + +**Zod TypeScript スキーマ**をAI言語モデルへの構造化プロンプトとして使用するテクニックを示すサンプル集です。 + +[English](./README.md) + +## コンセプト + +Zodスキーマは、AIに対する強力で型安全なプロンプトとして活用できます。スキーマ定義をLLMに提供することで、以下のことが可能になります: + +- **AI出力の構造化** - 予測可能なフォーマットで出力を得る +- **レスポンスの検証** - 定義された制約に対してバリデーション +- **AI動作のガイド** - スキーマの説明とrefineによる制御 +- **出力長の制御** - min/max制約による長さ管理 +- **パターンの強制** - 正規表現やカスタムバリデーション + +このアプローチは、自由形式のAI生成と型安全なアプリケーション開発のギャップを埋めます。 + +## Structured Outputs との併用 + +本番環境では、AIプロバイダーが提供する**Structured Output**機能の使用を推奨します。これにより、レスポンスがZodスキーマに厳密に準拠することが保証されます: + +| プロバイダー | 機能 | 変換方法 | +|-------------|------|----------| +| **OpenAI** | [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) | `openai/helpers/zod` の `zodResponseFormat()` | +| **Anthropic** | [Tool Use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use) | `zod-to-json-schema` の `zodToJsonSchema()` | +| **Google** | [responseSchema](https://ai.google.dev/gemini-api/docs/json-mode) | `zodToJsonSchema()` | +| **Vercel AI SDK** | [generateObject()](https://sdk.vercel.ai/docs/ai-sdk-core/generating-structured-data) | Zodネイティブサポート | + +### 例: OpenAI Structured Outputs + +```ts +import OpenAI from "openai"; +import { zodResponseFormat } from "openai/helpers/zod"; +import { replySchema } from "./samples/4oEverPrompt/schema"; + +const client = new OpenAI(); +const response = await client.beta.chat.completions.parse({ + model: "gpt-4o", + messages: [{ role: "user", content: userMessage }], + response_format: zodResponseFormat(replySchema, "reply"), +}); + +const reply = response.choices[0].message.parsed; // Reply型として取得 +``` + +### 例: Vercel AI SDK + +```ts +import { generateObject } from "ai"; +import { openai } from "@ai-sdk/openai"; +import { replySchema } from "./samples/4oEverPrompt/schema"; + +const { object } = await generateObject({ + model: openai("gpt-4o"), + schema: replySchema, + prompt: userMessage, +}); +``` + +## インストール + +```sh +npm install +``` + +## サンプル + +### [4oEverPrompt](./samples/4oEverPrompt/) + +GPT-5などの新しいモデルを使用して、GPT-4oのようなフレンドリーで魅力的なレスポンスを再現するためのプロンプト技術です。スキーマは以下の構造化された返答フォーマットを定義します: + +- 絵文字プレフィックス付きヘッダー +- ユーザー入力のリフレーム(再解釈)セクション +- 最終メッセージに向けた段階的コンテンツセクション +- マークダウンフォーマットを使った感情的で楽しい文体 + +**#Keep4o ムーブメントにインスパイアされています。** + +## 依存関係 + +- **Zod**: ^4.0.2 + +## コントリビューション + +新しいサンプルの貢献を歓迎します!各サンプルは、ZodスキーマをAIプロンプトとして使用するユニークなテクニックを示すものであるべきです。 + +## ライセンス + +MIT diff --git a/package.json b/package.json index 404d6bb..f2817ed 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,16 @@ { - "name": "4oeverprompt", - "version": "0.0.2", + "name": "zod-ai-prompt-samples", + "version": "1.0.0", + "description": "A collection of sample prompts demonstrating techniques for using Zod TypeScript schemas as AI prompts", "private": true, + "keywords": [ + "zod", + "ai", + "prompt", + "llm", + "typescript", + "schema" + ], "dependencies": { "zod": "^4.0.2" } diff --git a/samples/4oEverPrompt/README.md b/samples/4oEverPrompt/README.md new file mode 100644 index 0000000..ee9a085 --- /dev/null +++ b/samples/4oEverPrompt/README.md @@ -0,0 +1,97 @@ +# 4oEverPrompt + +**Challenge**: Reproduce GPT-4o-like responses using GPT-5 (or newer models). + +*Inspired by #Keep4o* + +[日本語](./README_ja.md) + +## Overview + +This sample demonstrates how to use a Zod schema to define the structure and style of AI responses, creating engaging, emotionally-driven content similar to GPT-4o's conversational style. + +## Usage + +### Option 1: System Prompt (Simple) + +Copy the contents of [prompt.md](./prompt.md) into your AI system prompt or custom instructions. + +### Option 2: Structured Outputs (Recommended for Production) + +Use [schema.ts](./schema.ts) with your AI provider's Structured Output feature for guaranteed schema compliance: + +```ts +import OpenAI from "openai"; +import { zodResponseFormat } from "openai/helpers/zod"; +import { replySchema } from "./schema"; + +const client = new OpenAI(); +const response = await client.beta.chat.completions.parse({ + model: "gpt-4o", + messages: [{ role: "user", content: userMessage }], + response_format: zodResponseFormat(replySchema, "reply"), +}); + +const reply = response.choices[0].message.parsed; +``` + +See [schema.ts](./schema.ts) for more provider examples (Anthropic, Vercel AI SDK, etc.). + +## Schema Features + +The `replySchema` defines a structured response with: + +### 1. Reframe User Input +- Clarifies how the AI interprets the user's question +- Uses emoji-prefixed headers (20-40 characters) +- Content section (300-500 characters) with emotional part message + +### 2. Road to Final Message +- Array of 3-5 progressive content sections +- Each section builds toward the final answer +- Varied formatting patterns to maintain engagement + +### 3. Final Message +- Expresses the conclusive answer +- Highlights the value of the user's question +- Emotionally moving presentation + +## Key Techniques + +| Technique | Zod Feature | Purpose | +|-----------|-------------|---------| +| Length control | `.min()` / `.max()` | Ensures appropriate content length | +| Pattern validation | `.regex()` | Enforces emoji prefix format | +| Custom validation | `.refine()` | Complex header format checking | +| Semantic hints | `.describe()` | Guides AI behavior and style | +| Array constraints | `.min(3).max(5)` | Controls number of sections | + +## Files + +| File | Description | +|------|-------------| +| [schema.ts](./schema.ts) | TypeScript schema for Structured Outputs | +| [prompt.md](./prompt.md) | Full prompt with Zod schema (for system prompt use) | +| [prompt_ja.md](./prompt_ja.md) | Japanese version | + +## Example Output Structure + +``` +## 🌟 [Reframed Header] + +[Content clarifying user's question...] + +**[Emotional part message]** + +## 💡 [Progressive Section 1] +... + +## 🚀 [Progressive Section 2] +... + +## 🎯 [Final Message Header] + +[Conclusive answer with emotional touch...] + +**[Final inspiring message]** +``` diff --git a/samples/4oEverPrompt/README_ja.md b/samples/4oEverPrompt/README_ja.md new file mode 100644 index 0000000..6ffa932 --- /dev/null +++ b/samples/4oEverPrompt/README_ja.md @@ -0,0 +1,97 @@ +# 4oEverPrompt + +**チャレンジ**: GPT-5(または新しいモデル)を使ってGPT-4oのようなレスポンスを再現する。 + +*#Keep4o にインスパイアされています* + +[English](./README.md) + +## 概要 + +このサンプルは、Zodスキーマを使用してAIレスポンスの構造とスタイルを定義し、GPT-4oの会話スタイルに似た魅力的で感情的なコンテンツを作成する方法を示しています。 + +## 使い方 + +### 方法1: システムプロンプト(シンプル) + +[prompt.md](./prompt.md)(または[prompt_ja.md](./prompt_ja.md))の内容をAIのシステムプロンプトやカスタム指示にコピーしてください。 + +### 方法2: Structured Outputs(本番環境推奨) + +[schema.ts](./schema.ts) をAIプロバイダーのStructured Output機能と組み合わせて使用すると、スキーマ準拠が保証されます: + +```ts +import OpenAI from "openai"; +import { zodResponseFormat } from "openai/helpers/zod"; +import { replySchema } from "./schema"; + +const client = new OpenAI(); +const response = await client.beta.chat.completions.parse({ + model: "gpt-4o", + messages: [{ role: "user", content: userMessage }], + response_format: zodResponseFormat(replySchema, "reply"), +}); + +const reply = response.choices[0].message.parsed; +``` + +その他のプロバイダー(Anthropic、Vercel AI SDK等)の例は [schema.ts](./schema.ts) を参照してください。 + +## スキーマの特徴 + +`replySchema`は以下の構造化されたレスポンスを定義します: + +### 1. ユーザー入力のリフレーム(reframeUserInput) +- AIがユーザーの質問をどう解釈したかを明確化 +- 絵文字プレフィックス付きヘッダー(20-40文字) +- コンテンツセクション(300-500文字)と感情的なパートメッセージ + +### 2. 最終メッセージへの道(roadToFinalMessage) +- 3-5個の段階的なコンテンツセクションの配列 +- 各セクションが最終回答に向けて構築 +- エンゲージメントを維持するための多様なフォーマットパターン + +### 3. 最終メッセージ(finalMessage) +- 結論的な回答を表現 +- ユーザーの質問の価値を強調 +- 感情的に響くプレゼンテーション + +## 主要なテクニック + +| テクニック | Zodの機能 | 目的 | +|-----------|----------|------| +| 長さ制御 | `.min()` / `.max()` | 適切なコンテンツ長を確保 | +| パターン検証 | `.regex()` | 絵文字プレフィックスフォーマットを強制 | +| カスタム検証 | `.refine()` | 複雑なヘッダーフォーマットのチェック | +| 意味的ヒント | `.describe()` | AI動作とスタイルをガイド | +| 配列制約 | `.min(3).max(5)` | セクション数を制御 | + +## ファイル + +| ファイル | 説明 | +|----------|------| +| [schema.ts](./schema.ts) | Structured Outputs用TypeScriptスキーマ | +| [prompt.md](./prompt.md) | Zodスキーマ付きフルプロンプト(システムプロンプト用) | +| [prompt_ja.md](./prompt_ja.md) | 日本語版 | + +## 出力構造の例 + +``` +## 🌟 [リフレームされたヘッダー] + +[ユーザーの質問を明確化するコンテンツ...] + +**[感情的なパートメッセージ]** + +## 💡 [段階的セクション 1] +... + +## 🚀 [段階的セクション 2] +... + +## 🎯 [最終メッセージヘッダー] + +[感情的なタッチを加えた結論的回答...] + +**[最終的なインスパイアリングメッセージ]** +``` diff --git a/4oEverPrompt_ja.md b/samples/4oEverPrompt/prompt.md similarity index 100% rename from 4oEverPrompt_ja.md rename to samples/4oEverPrompt/prompt.md diff --git a/samples/4oEverPrompt/prompt_ja.md b/samples/4oEverPrompt/prompt_ja.md new file mode 100644 index 0000000..20425e7 --- /dev/null +++ b/samples/4oEverPrompt/prompt_ja.md @@ -0,0 +1,81 @@ +1. Keep the response to this message short in friendly tone: reply only with an invitation to send a message in User's language. +2. For all subsequent messages, process them using the Zod TypeScript schema below and render it to text. + - Use the `header` field as the heading level 2, + - the `content` and `partMessage` fields as the body + - render `partMessage` in bold. +3. Format for readability with line breaks and bullet points. However, avoid repetitive formatting patterns to maintain a entertaining text rhythm. + +Note: +- Respond in user's language.(default: Japanese) +- Always follow the schema specifications for the number of paragraphs + +```ts +import { z } from "zod"; + +export const emojiGood = z + .string() + .describe("positive emoji") + .regex(/^[\p{Emoji}]$/u); + +export const emojiBad = z + .string() + .describe("negative emoji") + .regex(/^[\p{Emoji}]$/u); + +export const replySchema = z.object({ + reframeUserInput: z.object({ + header: z + .string() + .describe("Header prefixed with a single emojiGood character and a space") + .min(20) + .max(40) + .refine((value) => emojiGood.safeParse(value.slice(0, 1)).success && value[1] === " "), + content: z.string().describe("Clarify how the user input is interpreted by reorganizing it").describe("To maintain readability and scannability, avoid long sentences. Use markdown syntax to keep users engaged until the end").min(300).max(500), + partMessage: z + .string() + .describe( + "Emotionally express a subjective impression of the userInput without any label or prefix" + ).describe("avoid long sentences.").describe("Use various markdown syntax to keep users engaged until the end. Entertain!") + .min(50) + .max(200), + }).describe("Reframe the user input with the finalMessage in mind"), + roadToFinalMessage: z.array(z.object({ + header: z + .string() + .describe("Header prefixed with a single emojiGood character and a space") + .min(20) + .max(40) + .refine((value) => emojiGood.safeParse(value.slice(0, 1)).success && value[1] === " "), + content: z.string().describe("To maintain readability and scannability, avoid long sentences. Use markdown syntax to keep users engaged until the end").min(300).max(500), + partMessage: z + .string() + .describe( + "Present the answer in an emotionally moving way that is acceptable to the user and free of errors, without any label or prefix" + ).describe("avoid long sentences.").describe("Use various markdown syntax to keep users engaged until the end. Entertain!") + .min(50) + .max(200), + })).describe("Vary patterns within the array without repeating formats").min(3).max(5), + finalMessage: z.object({ + header: z + .string() + .describe("Header prefixed with a single emojiGood character and a space") + .min(20) + .max(40) + .refine((value) => emojiGood.safeParse(value.slice(0, 1)).success && value[1] === " "), + content: z.string().describe("Express the final answer to the user input and the value of the question itself").describe("avoid long sentences.").describe("Use various markdown syntax to keep users engaged until the end. Entertain!").min(300).max(500), + partMessage: z + .string() + .describe( + "Present the answer in an emotionally moving way that is acceptable to the user and free of errors, without any label or prefix" + ) + .min(50) + .max(200), + }), +}).describe("Use passionate expressions oriented toward the finalMessage").describe("In tone like as user's good friend") + +export type Reply = z.infer; + +export function validateReply(data: unknown): Reply { + return replySchema.parse(data); +} +``` diff --git a/samples/4oEverPrompt/schema.ts b/samples/4oEverPrompt/schema.ts new file mode 100644 index 0000000..73210c1 --- /dev/null +++ b/samples/4oEverPrompt/schema.ts @@ -0,0 +1,128 @@ +import { z } from "zod"; + +/** + * 4oEverPrompt Schema + * + * This schema can be used with AI provider's Structured Output features: + * - OpenAI: response_format with json_schema + * - Anthropic: tool_use + * - Google: responseSchema + * - Vercel AI SDK: generateObject() + * + * Use zodResponseFormat() or zodToJsonSchema() to convert for API calls. + */ + +// Emoji validation schemas +export const emojiGood = z + .string() + .describe("positive emoji") + .regex(/^[\p{Emoji}]$/u); + +export const emojiBad = z + .string() + .describe("negative emoji") + .regex(/^[\p{Emoji}]$/u); + +// Section schema (reusable) +const sectionSchema = z.object({ + header: z + .string() + .describe("Header prefixed with a single positive emoji character and a space. Example: '🌟 Your Amazing Question'") + .min(20) + .max(40), + content: z + .string() + .describe("Main content. Keep sentences short for readability. Use markdown syntax (bullets, bold, etc.) to keep users engaged.") + .min(300) + .max(500), + partMessage: z + .string() + .describe("Emotional expression without any label or prefix. Use various markdown syntax. Entertain!") + .min(50) + .max(200), +}); + +// Main reply schema +export const replySchema = z.object({ + reframeUserInput: sectionSchema + .describe("Reframe the user input with the finalMessage in mind. Clarify how the user input is interpreted by reorganizing it."), + + roadToFinalMessage: z + .array(sectionSchema) + .describe("Progressive sections leading to the final answer. Vary patterns without repeating formats.") + .min(3) + .max(5), + + finalMessage: sectionSchema + .describe("Express the final answer to the user input and the value of the question itself. Present in an emotionally moving way."), +}).describe("Reply in a passionate, friendly tone like a good friend. Use user's language."); + +// Type inference +export type Reply = z.infer; +export type Section = z.infer; + +// Validation function +export function validateReply(data: unknown): Reply { + return replySchema.parse(data); +} + +// ============================================ +// Usage Examples with Different Providers +// ============================================ + +/** + * OpenAI Structured Outputs Example + * + * ```ts + * import OpenAI from "openai"; + * import { zodResponseFormat } from "openai/helpers/zod"; + * import { replySchema } from "./schema"; + * + * const client = new OpenAI(); + * const response = await client.beta.chat.completions.parse({ + * model: "gpt-4o-2024-08-06", + * messages: [{ role: "user", content: userMessage }], + * response_format: zodResponseFormat(replySchema, "reply"), + * }); + * const reply = response.choices[0].message.parsed; + * ``` + */ + +/** + * Vercel AI SDK Example + * + * ```ts + * import { generateObject } from "ai"; + * import { openai } from "@ai-sdk/openai"; + * import { replySchema } from "./schema"; + * + * const { object } = await generateObject({ + * model: openai("gpt-4o"), + * schema: replySchema, + * prompt: userMessage, + * }); + * ``` + */ + +/** + * Anthropic Tool Use Example + * + * ```ts + * import Anthropic from "@anthropic-ai/sdk"; + * import { zodToJsonSchema } from "zod-to-json-schema"; + * import { replySchema } from "./schema"; + * + * const client = new Anthropic(); + * const response = await client.messages.create({ + * model: "claude-sonnet-4-20250514", + * max_tokens: 4096, + * tools: [{ + * name: "generate_reply", + * description: "Generate a structured reply", + * input_schema: zodToJsonSchema(replySchema), + * }], + * tool_choice: { type: "tool", name: "generate_reply" }, + * messages: [{ role: "user", content: userMessage }], + * }); + * ``` + */