Last active
December 15, 2025 04:44
-
-
Save slashthinking/68ecf1773b579da22dd0ff749b1682fb to your computer and use it in GitHub Desktop.
ai sdk - JSONSchema7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { streamText, jsonSchema } from 'ai'; | |
| import 'dotenv/config'; | |
| const result = await streamText({ | |
| model: 'anthropic/claude-sonnet-4.5', | |
| tools: { | |
| // 创建订单工具 - 根据 orderType 有不同的必填字段 | |
| createOrder: { | |
| description: '创建一个新订单,根据订单类型需要不同的信息', | |
| inputSchema: jsonSchema<{ | |
| orderType: 'standard' | 'subscription' | 'gift'; | |
| productId: string; | |
| quantity: number; | |
| // 条件字段 | |
| shippingAddress?: { street: string; city: string; zipCode: string }; | |
| billingDetails?: { cardNumber: string; expiryDate: string }; | |
| subscriptionPeriod?: 'monthly' | 'annual'; | |
| recipientEmail?: string; | |
| giftMessage?: string; | |
| }>({ | |
| type: 'object', | |
| properties: { | |
| orderType: { | |
| type: 'string', | |
| enum: ['standard', 'subscription', 'gift'], | |
| description: '订单类型' | |
| }, | |
| productId: { type: 'string' }, | |
| quantity: { type: 'integer', minimum: 1 }, | |
| shippingAddress: { | |
| type: 'object', | |
| properties: { | |
| street: { type: 'string' }, | |
| city: { type: 'string' }, | |
| zipCode: { type: 'string', pattern: '^[0-9]{6}$' } | |
| }, | |
| required: ['street', 'city', 'zipCode'] | |
| }, | |
| billingDetails: { | |
| type: 'object', | |
| properties: { | |
| cardNumber: { type: 'string', pattern: '^[0-9]{16}$' }, | |
| expiryDate: { type: 'string', pattern: '^(0[1-9]|1[0-2])/[0-9]{2}$' } | |
| }, | |
| required: ['cardNumber', 'expiryDate'] | |
| }, | |
| subscriptionPeriod: { | |
| type: 'string', | |
| enum: ['monthly', 'annual'] | |
| }, | |
| recipientEmail: { | |
| type: 'string', | |
| format: 'email' | |
| }, | |
| giftMessage: { | |
| type: 'string', | |
| maxLength: 200 | |
| } | |
| }, | |
| required: ['orderType', 'productId', 'quantity'], | |
| // ============ 条件逻辑 ============ | |
| if: { | |
| properties: { orderType: { const: 'standard' } } | |
| }, | |
| then: { | |
| required: ['shippingAddress', 'billingDetails'] | |
| }, | |
| else: { | |
| if: { | |
| properties: { orderType: { const: 'subscription' } } | |
| }, | |
| then: { | |
| required: ['shippingAddress', 'billingDetails', 'subscriptionPeriod'] | |
| }, | |
| else: { | |
| // orderType === 'gift' | |
| required: ['recipientEmail'] | |
| } | |
| } | |
| }), | |
| execute: async (input) => { | |
| console.log('创建订单:', input); | |
| return { success: true, orderId: `ORD-${Date.now()}` }; | |
| } | |
| }, | |
| // 数据库查询工具 - 使用 if/then/else 支持多种查询类型 | |
| queryDatabase: { | |
| description: '查询数据库,支持多种查询方式', | |
| inputSchema: jsonSchema< | |
| | { queryType: 'byId'; id: string } | |
| | { queryType: 'byFilter'; filters: Record<string, string | number>; limit?: number } | |
| | { queryType: 'aggregate'; pipeline: Array<{ $match?: object; $group?: object }> } | |
| >({ | |
| type: 'object', | |
| properties: { | |
| queryType: { | |
| type: 'string', | |
| enum: ['byId', 'byFilter', 'aggregate'] | |
| }, | |
| id: { type: 'string' }, | |
| filters: { | |
| type: 'object', | |
| additionalProperties: { | |
| type: ['string', 'number'] | |
| } | |
| }, | |
| limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, | |
| pipeline: { | |
| type: 'array', | |
| items: { | |
| type: 'object', | |
| properties: { | |
| $match: { type: 'object' }, | |
| $group: { type: 'object' } | |
| } | |
| } | |
| } | |
| }, | |
| required: ['queryType'], | |
| if: { | |
| properties: { queryType: { const: 'byId' } } | |
| }, | |
| then: { | |
| required: ['queryType', 'id'] | |
| }, | |
| else: { | |
| if: { | |
| properties: { queryType: { const: 'byFilter' } } | |
| }, | |
| then: { | |
| required: ['queryType', 'filters'] | |
| }, | |
| else: { | |
| // queryType === 'aggregate' | |
| required: ['queryType', 'pipeline'] | |
| } | |
| } | |
| }), | |
| execute: async (input) => { | |
| console.log('数据库查询:', input); | |
| return { results: [], count: 0 }; | |
| } | |
| }, | |
| // 支付工具 - 使用 dependencies | |
| processPayment: { | |
| description: '处理支付', | |
| inputSchema: jsonSchema<{ | |
| amount: number; | |
| currency: string; | |
| paymentMethod: 'card' | 'bank' | 'wallet'; | |
| cardNumber?: string; | |
| cvv?: string; | |
| bankAccount?: string; | |
| walletId?: string; | |
| }>({ | |
| type: 'object', | |
| properties: { | |
| amount: { type: 'number', minimum: 0.01 }, | |
| currency: { type: 'string', enum: ['USD', 'EUR', 'CNY'] }, | |
| paymentMethod: { type: 'string', enum: ['card', 'bank', 'wallet'] }, | |
| cardNumber: { type: 'string', pattern: '^[0-9]{16}$' }, | |
| cvv: { type: 'string', pattern: '^[0-9]{3,4}$' }, | |
| bankAccount: { type: 'string' }, | |
| walletId: { type: 'string' } | |
| }, | |
| required: ['amount', 'currency', 'paymentMethod'], | |
| // 使用 if/then/else 替代 allOf | |
| if: { | |
| properties: { paymentMethod: { const: 'card' } } | |
| }, | |
| then: { | |
| required: ['amount', 'currency', 'paymentMethod', 'cardNumber', 'cvv'] | |
| }, | |
| else: { | |
| if: { | |
| properties: { paymentMethod: { const: 'bank' } } | |
| }, | |
| then: { | |
| required: ['amount', 'currency', 'paymentMethod', 'bankAccount'] | |
| }, | |
| else: { | |
| // paymentMethod === 'wallet' | |
| required: ['amount', 'currency', 'paymentMethod', 'walletId'] | |
| } | |
| } | |
| }), | |
| execute: async (input) => { | |
| console.log('处理支付:', input); | |
| return { transactionId: `TXN-${Date.now()}`, status: 'success' }; | |
| } | |
| }, | |
| // 递归结构 - 组织架构树 | |
| updateOrgTree: { | |
| description: '更新组织架构树', | |
| inputSchema: jsonSchema<{ | |
| root: { | |
| id: string; | |
| name: string; | |
| children?: Array<any>; // 递归类型 | |
| }; | |
| }>({ | |
| type: 'object', | |
| definitions: { | |
| node: { | |
| type: 'object', | |
| properties: { | |
| id: { type: 'string' }, | |
| name: { type: 'string' }, | |
| role: { type: 'string', enum: ['manager', 'employee', 'intern'] }, | |
| children: { | |
| type: 'array', | |
| items: { $ref: '#/definitions/node' } | |
| } | |
| }, | |
| required: ['id', 'name'] | |
| } | |
| }, | |
| properties: { | |
| root: { $ref: '#/definitions/node' } | |
| }, | |
| required: ['root'] | |
| }), | |
| execute: async (input) => { | |
| console.log('更新组织架构:', input); | |
| return { updated: true }; | |
| } | |
| } | |
| }, | |
| messages: [ | |
| { | |
| role: 'user', | |
| content: '帮我创建一个礼物订单,产品ID是 PROD-001,数量2个,收件人邮箱是 friend@example.com' | |
| } | |
| ] | |
| }); | |
| // 处理流式响应 | |
| for await (const part of result.fullStream) { | |
| if (part.type === 'text-delta') { | |
| process.stdout.write(part.text); | |
| } else if (part.type === 'tool-call') { | |
| console.log('\n\n工具调用:', part.toolName); | |
| console.log('参数:', JSON.stringify(part.input, null, 2)); | |
| } else if (part.type === 'tool-result') { | |
| console.log('结果:', JSON.stringify(part.output, null, 2)); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment