ai-ml

Claude Structured Outputs في TypeScript باستخدام

٧ يونيو ٢٠٢٦

Claude Structured Outputs in TypeScript with Zod (2026)

تتوفر المخرجات المهيكلة (Structured outputs) بشكل عام على واجهة برمجة تطبيقات (API) Claude API: قم بضبط output_config.format على مخطط JSON (JSON schema) وسيتم ضمان تحليل استجابة Claude بنجاح. في TypeScript، يعيد استخدام zodOutputFormat() بالإضافة إلى client.messages.parse() بيانات مكتوبة (typed) ومتحقق منها بواسطة Zod. يبني هذا الدليل خدمة استخراج كاملة، بما في ذلك معالجة الرفض والاقتطاع.

ملخص

ستقوم ببناء خدمة فرز تذاكر دعم فني مكتوبة (typed) تعتمد على @anthropic-ai/sdk الإصدار 0.102.0 و Zod الإصدار 4.4.3، والتي تحول رسائل البريد الإلكتروني غير المنظمة إلى JSON مضمون المخطط — بدون محاولات إعادة JSON.parse()، وبدون تعاويذ الأوامر النصية (prompts) مثل "يرجى الرد باستخدام JSON صالح". ستستخدم كلا نصفي ميزة المخرجات المهيكلة في Claude: مخرجات JSON (output_config.format) لشكل الاستجابة، والاستخدام الصارم للأدوات (strict: true) لمدخلات الأدوات المتحقق منها.1 خلال ذلك، ستتعامل مع الحالتين اللتين يمكن أن ينحرف فيهما المخرج عن مخططك (أسباب التوقف refusal و max_tokens)، وتفحص المخطط الدقيق الذي يرسله SDK إلى Claude، وتتحقق من كود معالجة الفشل دون اتصال بالإنترنت باستخدام node:test — دون إنفاق رمز مميز (token) واحد من API. خصص حوالي 30 دقيقة.

ما ستتعلمه

  • كيفية عمل المخرجات المهيكلة في Claude: فك التشفير المقيد بالقواعد (grammar-constrained decoding)، ومعامل output_config.format، والنماذج التي تدعمه.
  • تعريف مخطط Zod واحد يقود طلب API، والتحقق من صحة الاستجابة، وأنواع TypeScript الخاصة بك.
  • المسار السعيد: client.messages.parse() مع zodOutputFormat().
  • ما يرسله SDK فعلياً: تحويل المخطط، ولماذا يتم فرض enum و pattern محلياً بواسطة مساعد Zod.
  • معالجة الفشل الجاهزة للإنتاج لأسباب التوقف refusal و max_tokens مع اتحاد نتائج مكتوب (typed result union).
  • الاستخدام الصارم للأدوات: ضمان مدخلات استدعاء الأدوات باستخدام strict: true.
  • اختبار منطق الحماية دون اتصال بالإنترنت باستخدام تجهيزات node:test.
  • تجميع القواعد (Grammar compilation)، والتخزين المؤقت، وتكاليف الرموز المميزة (tokens)، وحدود تعقيد المخطط.
  • الانتقال من التوجيه بوضع JSON (JSON-mode prompting)، واستخراج حيل الأدوات، ومعامل البيتا output_format.

أي نماذج Claude تدعم المخرجات المهيكلة؟

المخرجات المهيكلة متاحة بشكل عام على واجهة برمجة تطبيقات (API) Claude API لنماذج Claude Opus 4.8، و Claude Mythos Preview، و Claude Opus 4.7، و Claude Opus 4.6، و Claude Sonnet 4.6، و Claude Sonnet 4.5، و Claude Opus 4.5، و Claude Haiku 4.5.1 على Amazon Bedrock، الميزة متاحة بشكل عام (GA) لنماذج Claude Opus 4.6، و Sonnet 4.6، و Sonnet 4.5، و Opus 4.5، و Haiku 4.5 (يتوفر Opus 4.7 و Mythos Preview هناك أيضاً من خلال نقطة نهاية Claude الأحدث في Amazon Bedrock)؛ وعلى Vertex AI فهي متاحة بشكل عام لنفس القائمة مثل واجهة برمجة تطبيقات الطرف الأول API؛ وعلى Microsoft Foundry هي في مرحلة البيتا.1 يستخدم هذا البرنامج التعليمي claude-sonnet-4-6 (3 دولارات لكل مليون رمز إدخال، و 15 دولاراً لكل مليون رمز إخراج2) — استبدله بـ claude-haiku-4-5 (1 دولار / 5 دولارات لكل مليون رمز2) لعمليات الاستخراج ذات الحجم الكبير.

تحت الغطاء، تقوم واجهة برمجة تطبيقات API بتجميع مخطط JSON الخاص بك إلى قواعد (grammar) وتقيد أخذ عينات الرموز (token sampling) أثناء الاستدلال — لا يمكن للنموذج إصدار رمز من شأنه أن ينتهك هيكل المخطط.1 هذا أقوى جوهرياً من التوجيه لـ JSON، والذي يطلب ذلك بلطف فقط.

المتطلبات الأساسية

  • Node.js 24 LTS (Active LTS، مدعوم حتى أبريل 20283)
  • مفتاح واجهة برمجة تطبيقات (API) Anthropic API مع إمكانية الوصول إلى Claude Sonnet 4.6 (ANTHROPIC_API_KEY)
  • الإلمام بـ async/await والاستخدام الأساسي لـ Zod

تم تثبيت جميع الإصدارات: @anthropic-ai/sdk 0.102.0، و zod 4.4.3، و TypeScript 6.0.3، و tsx 4.22.4، و @types/node 24.13.1.4

الخطوة 1 — هيكلة المشروع

أنشئ المشروع وثبّت التبعيات المحددة:

mkdir claude-structured-outputs-demo && cd claude-structured-outputs-demo
npm init -y
npm install @anthropic-ai/sdk@0.102.0 zod@4.4.3
npm install -D TypeScript@6.0.3 tsx@4.22.4 @types/node@24.13.1

يعلن SDK عن Zod كتبعية نظيرة اختيارية (optional peer dependency) مع النطاق ^3.25.0 || ^4.0.0، لذا فإن Zod 4 مدعوم بالكامل.4

استبدل package.json بـ:

{
  "name": "claude-structured-outputs-demo",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "typecheck": "tsc --noEmit",
    "test": "node --import tsx --test src/guards.test.ts",
    "triage": "node --env-file=.env --import tsx src/index.ts"
  },
  "dependencies": {
    "@anthropic-ai/sdk": "0.102.0",
    "zod": "4.4.3"
  },
  "devDependencies": {
    "@types/node": "24.13.1",
    "tsx": "4.22.4",
    "TypeScript": "6.0.3"
  }
}

"type": "module" أمر مهم: يستخدم هذا المشروع await على المستوى الأعلى وواردات ESM، وسترفض إعدادات المترجم الصارمة أدناه بناء جملة ESM في حزمة CommonJS.

أضف tsconfig.json:

{
  "compilerOptions": {
    "target": "es2023",
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "skipLibCheck": true,
    "types": ["node"]
  },
  "include": ["src/**/*.ts"]
}

أخيراً، أنشئ ملف .env بمفتاحك (لا ترفع هذا الملف أبداً):

echo "ANTHROPIC_API_KEY=your-key-here" > .env

الخطوة 2 — تعريف مخطط Zod واحد كمصدر وحيد للحقيقة

يقود المخطط ثلاثة أشياء في آن واحد: مخطط JSON المرسل إلى واجهة برمجة تطبيقات API، والتحقق من صحة الاستجابة في وقت التشغيل، ونوع TypeScript المستنتج. أنشئ src/schema.ts:

import { z } from "zod";

export const TicketTriage = z.object({
  category: z.enum(["billing", "bug", "account", "feature_request", "other"]),
  priority: z.enum(["low", "normal", "high", "urgent"]),
  summary: z.string().describe("One-sentence summary of the issue"),
  customerEmail: z.email().describe("Email address of the requester"),
  mentionsOutage: z.boolean().describe("True if the ticket reports a full outage"),
  followUpActions: z
    .array(z.string())
    .describe("Concrete next steps for the support agent"),
  orderId: z
    .string()
    .optional()
    .describe("Order id like ORD-12345, if the ticket references one"),
});

export type TicketTriage = z.infer<typeof TicketTriage>;

يأتي قيدان في التصميم مباشرة من دعم مخطط JSON الخاص بواجهة برمجة تطبيقات API. تقبل المخرجات المهيكلة جميع الأنواع الأساسية، و enum (القيم الأولية فقط)، و const، و anyOf/allOf (لا يتم دعم allOf المدمج مع $ref)، و $ref/$defs الداخلي، و default، و required، وتنسيقات السلاسل النصية date-time، و time، و date، و duration، و email، و hostname، و uri، و ipv4، و ipv6، و uuid، و minItems للمصفوفات بقيمة 0 أو 1. وهي لا تقبل المخططات المتكررة (recursive schemas)، أو $ref الخارجي، أو القيود العددية مثل minimum/maximum، أو قيود طول السلسلة (minLength/maxLength)، أو قيود المصفوفات الأخرى، أو ضبط additionalProperties على أي شيء بخلاف false — الميزات غير المدعومة في المخطط الخام تنتج خطأ 400.1

اجعل حقول optional() نادرة ومدروسة: كل معامل اختياري يُحتسب ضمن ميزانية الطلب البالغة 24 عبر جميع مخططات الأدوات الصارمة ومخططات إخراج JSON مجتمعة، وتشير الوثائق إلى أن كل واحد منها يضاعف تقريباً جزءاً من مساحة حالة القواعد.1

الخطوة 3 — المسار السعيد: messages.parse() مع zodOutputFormat()

كيف تحصل على JSON مضمون ومكتوب (typed) من Claude في TypeScript؟ قم بتمرير zodOutputFormat(schema) كـ output_config.format إلى client.messages.parse()، واقرأ parsed_output — الذي تم التحقق منه بالفعل بواسطة Zod وتم تعريفه كنوع TicketTriage. أنشئ src/extract.ts:

import Anthropic from "@anthropic-ai/sdk";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
import { TicketTriage } from "./schema.ts";

const client = new Anthropic();

export async function triageTicket(ticket: string): Promise<TicketTriage> {
  const message = await client.messages.parse({
    model: "claude-sonnet-4-6",
    max_tokens: 1024,
    messages: [
      { role: "user", content: `Triage this support ticket:\n\n${ticket}` },
    ],
    output_config: {
      format: zodOutputFormat(TicketTriage),
    },
  });

  if (message.parsed_output === null) {
    throw new Error(
      `No structured output returned (stop_reason: ${message.stop_reason})`,
    );
  }
  return message.parsed_output;
}

يظل الـ JSON الخام متاحاً أيضاً كنص: مع مخرجات JSON، تكون استجابة Claude عبارة عن كتلة نصية عادية تحتوي على JSON صالح، لذا فإن message.content[0] لا يزال يحمل الصيغة النصية.1 إذا كنت تفضل JSON Schema الخام على Zod، فإن الـ SDK يوفر مساعداً موازياً، jsonSchemaOutputFormat() من @anthropic-ai/sdk/helpers/json-schema — قم بتمرير نص صريح (inline literal) as const وسيتم استنتاج parsed_output حتى في وقت التجميع (compile time).5

سلوك واحد يجب استيعابه قبل مرحلة الإنتاج: عندما يفشل التحليل (parsing) أو التحقق من الصحة (validation)، فإن parse() لا يعيد نتيجة جزئية — بل يطلق خطأ (throws). في إصدار SDK 0.102.0، تقوم خطوة التحليل بتشغيل JSON.parse ثم schema.safeParse، وتغلف أي فشل في AnthropicError تبدأ رسالته بـ "Failed to parse structured output" — مع سرد ما يصل إلى خمس مشكلات في Zod عندما يكون الفشل في التحقق من صحة المخطط (schema validation).5 كائن الـ Message — بما في ذلك stop_reason، والنص الخام، والاستخدام (usage) — يختفي بحلول الوقت الذي تلتقط فيه الخطأ. الخطوة 5 تعالج ذلك.

الخطوة 4 — فحص ما يتلقاه Claude فعلياً

ثق، ولكن اطبع. يقوم مساعد Zod بتحويل المخطط الخاص بك قبل إرساله. أنشئ show-schema.ts في جذر المشروع:

import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
import { TicketTriage } from "./src/schema.ts";

const format = zodOutputFormat(TicketTriage);
console.log(
  JSON.stringify({ type: format.type, schema: format.schema }, null, 2),
);

قم بتشغيله:

node --import tsx show-schema.ts

مخرجات مختصرة (SDK 0.102.0):

{
  "type": "json_schema",
  "schema": {
    "type": "object",
    "properties": {
      "category": {
        "type": "string",
        "description": "{enum: [\"billing\",\"bug\",\"account\",\"feature_request\",\"other\"]}"
      },
      "customerEmail": {
        "type": "string",
        "description": "Email address of the requester\n\n{pattern: \"...\"}",
        "format": "email"
      },
      "followUpActions": {
        "type": "array",
        "description": "Concrete next steps for the support agent",
        "items": { "$ref": "#/$defs/__schema0" }
      }
    },
    "additionalProperties": false,
    "required": ["category", "priority", "summary", "customerEmail", "mentionsOutage", "followUpActions"]
  }
}

ثلاث ملاحظات، يمكن التحقق منها جميعاً على جهازك:

  1. المساعد متحفظ. التحويل الموثق يزيل القيود غير المدعومة، ويدمجها في أوصاف الحقول، ويضيف additionalProperties: false إلى كل كائن، ويصفي تنسيقات السلاسل النصية إلى القائمة المدعومة.1 في الإصدار 0.102.0، يمتد هذا التحفظ إلى أبعد مما قد تتوقع: يقوم مساعد Zod بخفض رتبة حتى enum و pattern — وكلاهما مدعوم من قبل الـ Python في المخططات الخام — إلى نص وصفي. بالنسبة لهذا المخطط، ما نجا في المواضع المفروضة بقواعد اللغة (grammar-enforced) هو type، و format، وهيكل الكائن، والخصائص المطلوبة.
  2. التحقق المحلي يسد الفجوة. يقوم الـ SDK بالتحقق من صحة الاستجابة مقابل مخطط Zod الأصلي الخاص بك، مع بقاء كل القيود سليمة.1 أي category خارج الـ enum ستمر عبر قواعد اللغة من جانب الخادم ولكنها ستفشل في safeParse المحلي، لتظهر كـ AnthropicError من الخطوة 3. الضمان الذي تبرمج بناءً عليه هو مخطط Zod، وليس قواعد اللغة المرسلة.
  3. إذا كنت بحاجة إلى قواعد اللغة نفسها لفرض enum، فأرسل مخططاً خاماً: إما output_config: { format: { type: "json_schema", schema: {...} } } في messages.create() تماماً كما يفعل دليل البدء السريع الرسمي،1 أو jsonSchemaOutputFormat(schema, { transform: false }) لتخطي تحويل الـ SDK بالكامل.5

هذا أيضاً هو المكان الذي يصبح فيه ترتيب الخصائص قابلاً للتنبؤ: في المخرجات، تظهر الخصائص المطلوبة أولاً بترتيب المخطط، ثم الخصائص الاختيارية بترتيب المخطط — خاصية orderId الاختيارية لدينا تصل دائماً في النهاية، بغض النظر عن المكان الذي "يفكر فيه" Claude.1

الخطوة 5 — مسار الإنتاج: حواجز stop_reason مع اتحاد نتائج مكتوب (typed result union)

هناك حالتان موثقتان يمكنهما إنتاج مخرجات لا تطابق المخطط الخاص بك، وكلاهما يصل مع استجابة HTTP 200. الرفض الأمني يضبط stop_reason: "refusal" (تتم محاسبتك على الرموز المولدة، ونص الرفض له الأولوية على المخطط). الوصول إلى الحد الأقصى للرموز يضبط stop_reason: "max_tokens" وقد يقطع الـ JSON في منتصف الحقل.1 لأن parse() يتخلص من كائن Message عند فشل التحقق، فإن كود الإنتاج الذي يريد تسجيل الاستخدام، أو التفرع بناءً على سبب التوقف، أو تنفيذ سياسة إعادة المحاولة يجب أن ينزل إلى مستوى messages.create() ويتولى عملية التحليل بنفسه. أنشئ src/extract-manual.ts:

import Anthropic from "@anthropic-ai/sdk";
import type { Message, TextBlock } from "@anthropic-ai/sdk/resources/messages";
import { z } from "zod";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
import { TicketTriage } from "./schema.ts";

const client = new Anthropic();

export type TriageResult =
  | { ok: true; data: TicketTriage   | {
      ok: false;
      reason: "refusal" | "truncated" | "invalid_json" | "schema_mismatch";
      detail: string;
    };

export function parseTriageMessage(message: Message): TriageResult {
  if (message.stop_reason === "refusal") {
    return {
      ok: false      reason: "refusal"      detail:
        "Claude declined the request. The refusal text takes precedence over the schema, so do not parse it."    };
  }
  if (message.stop_reason === "max_tokens") {
    return {
      ok: false      reason: "truncated"      detail:
        "Response hit max_tokens and the JSON may be cut off. Retry with a higher max_tokens."    };
  }

  const text =
    message.content.find((b): b is TextBlock => b.type === "text")?.text ?? "";

  let candidate: unknown;
  try {
    candidate = JSON.parse(text);
  } catch (err) {
    return { ok: false: "invalid_json": String(err) };
  }

  const result = TicketTriage.safeParse(candidate);
  if (!result.success) {
    return {
      ok: false      reason: "schema_mismatch"      detail: z.prettifyError(result.error)    };
  }
  return { ok: true: result.data };
}

export async function triageTicketSafe(ticket: string): Promise<TriageResult> {
  const message = await client.messages.create({
    model: "claude-sonnet-4-6"    max_tokens: 1024    messages: [
      { role: "user": `Triage this support ticket:\n\n${ticket}` }    ]    output_config: {
      format: zodOutputFormat(TicketTriage)    
  });
  return parseTriageMessage(message);
}

لاحظ أن zodOutputFormat() يعمل مع create() العادي أيضاً — ولكنه لا يقوم بأي تحليل تلقائي هناك، وهو بالضبط ما نريده.5 تعمل الحواجز بترتيب مدروس: فحوصات سبب التوقف أولاً (غير مكلفة وحاسمة)، ثم بناء جملة JSON، ثم دلالات المخطط. يحصل كل وضع فشل على reason مكتوب خاص به، بحيث يمكن للمستدعين إعادة محاولة النصوص المقطوعة (truncations) مع max_tokens أعلى بينما يتم توجيه حالات الرفض إلى قائمة انتظار بشرية بدلاً من حلقة إعادة محاولة.

قم بتوصيل نقطة دخول قابلة للتشغيل، src/index.ts:

import { triageTicketSafe from "./extract-manual.ts";

const sampleTicket = `
From: dana@example.com
Subject: Charged twice and the dashboard is down

Hi, order ORD-98214 was charged twice this morning, and now your status
dashboard will not load at all for our whole team. We need the duplicate
charge refunded before Friday. This is blocking our finance close.
`;

const result = await triageTicketSafe(sampleTicket);

if (result.ok) {
  console.log("Triage:"JSON.stringify(result.datanull2));
} else {
  console.error(`Triage failed (${result.reason): ${result.detail`);
  process.exitCode = 1;
}

الخطوة 6 — استخدام الأدوات الصارم: مدخلات محققة لوظائفك

تتحكم مخرجات JSON فيما يقوله Claude؛ بينما يتحكم استخدام الأدوات الصارم (strict tool use) في كيفية استدعاء Claude لوظائفك — ويمكن لكليهما العمل في نفس الطلب.1 بدون الوضع الصارم، قد يمرر Claude passengers: "two" أو passengers: "2" بينما تتوقع وظيفتك رقماً؛ مع strict: true في تعريف الأداة، يتم تقييد مدخلات الأداة بقواعد اللغة وفقاً للمخطط ويكون اسم الأداة دائماً صالحاً — إما إحدى أدواتك المقدمة أو أدوات الخادم.6 أنشئ src/strict-tool.ts:

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const lookupOrderTool: Anthropic.Tool = {
  name: "lookup_order"  description: "Look up a customer's order by order id"  strict: true  input_schema: {
    type: "object"    properties: {
      order_id: {
        type: "string"        description: "The order id, for example ORD-12345"      
      include_refunds: {
        type: "boolean"        description: "Whether to include refund history"      
    
    required: ["order_id""include_refunds"]    additionalProperties: false  
;

export async function askAboutOrder(question: string): Promise<void> {
  const response = await client.messages.create({
    model: "claude-sonnet-4-6"    max_tokens: 1024    messages: [{ role: "user": question ]    tools: [lookupOrderTool]  );

  for (const block of response.content) {
    if (block.type === "tool_use" && block.name === "lookup_order") {
      // With strict: true, this input is guaranteed to match input_schema:
      // order_id is a string, include_refunds is a boolean, no extra keys.
      const input = block.input as {
        order_id: string;
        include_refunds: boolean;
      ;
      console.log(
        `Claude wants order ${input.order_id (refunds: ${input.include_refunds)`      );
      }

يقع strict في المستوى الأعلى لتعريف الأداة، جنباً إلى جنب مع name، و description، و input_schema، ويتبع المخطط نفس المجموعة الفرعية من JSON Schema من الخطوة 2.6 تشترك الأدوات الصارمة في نفس ميزانية التعقيد على مستوى الطلب: بحد أقصى 20 أداة صارمة لكل طلب، و 24 معاملاً اختيارياً عبر جميع مخططات الأدوات الصارمة ومخرجات JSON، و 16 معاملاً من نوع الاتحاد (union-typed) عبر جميع المخططات الصارمة.1 عندما تجمع بين الأدوات الصارمة ومخرجات JSON في طلب واحد، تحصل على استدعاءات أدوات محققة أثناء حلقة العميل (agent loop) وإجابة نهائية مضمونة المخطط — ولاحظ أن قواعد لغة مخرجات JSON تنطبق فقط على مخرجات Claude المباشرة — وليس على استدعاءات استخدام الأدوات، أو نتائج الأدوات، أو كتل التفكير — مع إعادة ضبط حالة قواعد اللغة بين الأقسام.1

للحصول على حلقة عميل كاملة حول استدعاءات الأدوات (متعددة الأدوار tool_use/tool_result)، راجع درس حلقة عميل استخدام أدوات Claude؛ يسقط الوضع الصارم في تلك الحلقة دون تغيير.

الخطوة 7 — اختبار الحواجز دون اتصال بالإنترنت، مجاناً

مسارات الفشل هي بالضبط الكود الذي لا يمكنك تحمل اكتشاف عطله في مرحلة الإنتاج، وهي قابلة للاختبار بدون مفتاح Python: يأخذ parseTriageMessage() كائن Message، لذا قم بتزويده بكائنات اصطناعية. أنشئ src/guards.test.ts:

التحقق

قم بتشغيل الفحوصات الثلاثة بالترتيب:

npm run typecheck
npm test
npm run triage

المتوقع: typecheck ينتهي بهدوء مع الكود 0. تقرير تشغيل الاختبار يظهر:

# tests 4
# pass 4
# fail 0

و npm run triage (هذا الأمر يستدعي الـ API ويحتاج إلى ANTHROPIC_API_KEY) يطبع كائن فرز (triage object) بالشكل التالي:

{
  "category": "billing",
  "priority": "urgent",
  "summary": "Customer was double-charged and the status dashboard is down for their team.",
  "customerEmail": "dana@example.com",
  "mentionsOutage": true,
  "followUpActions": [
    "Refund the duplicate charge on ORD-98214",
    "Escalate the dashboard outage"
  ],
  "orderId": "ORD-98214"
}

قيم الحقول ستختلف من تشغيل لآخر — لكن الهيكل لن يختلف. لاحظ ترتيب "المطلوب أولاً" من الخطوة 4: orderId هو الأخير لأنه الحقل الاختياري الوحيد. تم تشغيل فحص النوع (typecheck) وجميع الاختبارات الأربعة غير المتصلة بالإنترنت (offline) بالكامل أثناء كتابة هذا الدليل؛ شكل الاستجابة المباشرة يتبع ضمان المخطط (schema) الموثق لمخرجات JSON.1

ما هي تكلفة المخرجات المهيكلة؟

لا توجد رسوم منفصلة لهذه الميزة على Claude API؛ أنت تدفع أسعار الرموز (tokens) القياسية — 3 دولارات / 15 دولاراً لكل مليون رمز إدخال/إخراج على Sonnet 4.6، و 1 دولار / 5 دولارات على Haiku 4.5 — بالإضافة إلى بعض آليات التكلفة الحقيقية التي تستحق المعرفة.2

أولاً، يقوم الـ API بحقن مطالبة نظام (system prompt) إضافية تشرح تنسيق المخرجات المتوقع، لذا فإن عدد رموز الإدخال يرتفع قليلاً، وتغيير output_config.format يؤدي إلى إبطال ذاكرة التخزين المؤقت للمطالبة (prompt cache) لهذا التسلسل من المحادثة.1 ثانياً، الطلب الأول بمخطط (schema) جديد يدفع ضريبة تأخير بسبب تجميع القواعد (grammar-compilation)؛ يتم تخزين القواعد المجمعة مؤقتاً لمدة 24 ساعة من آخر استخدام، ويتم إبطال ذاكرة التخزين المؤقت عن طريق تغييرات هيكل المخطط أو عن طريق تغيير مجموعة الأدوات في الطلب — تعديل حقول name أو description فقط لا يبطلها.1 ثالثاً، تعمل المخرجات المهيكلة مع Batch API بخصمها القياسي البالغ 50% (1.50 دولار / 7.50 دولار لكل مليون رمز على Sonnet 4.6)، مما يجعل الدفعات (batch) هي المسار الواضح لمهام الاستخراج الضخمة.12

هناك عدم توافق في أمرين يجب التخطيط لهما: لا يمكن دمج الاستشهادات (citations) مع مخرجات JSON (يعيد الـ API خطأ 400)، والملء المسبق للرسائل (message prefilling) — الحيلة القديمة لبدء دور المساعد بـ { — غير متوافق مع مخرجات JSON.1

وضع JSON مقابل المخرجات المهيكلة: ترحيل الأنماط القديمة

ما الفرق بين وضع JSON والمخرجات المهيكلة في Claude؟ "وضع JSON" لم يكن أبداً مفتاحاً في Claude API — بل كان مجموعة من حلول المطالبات الالتفافية: توجيه Claude لإصدار JSON، أو الملء المسبق لـ { كدور للمساعد، أو تعريف أداة وهمية وإجبار Claude على "استدعائها" فقط لحصاد مدخلات مشكلة حسب المخطط. تلك الأنماط تنتج غالباً JSON صالحاً؛ أما المخرجات المهيكلة فتضمن ذلك عبر فك التشفير المقيد (constrained decoding).1

خريطة الترحيل:

النمط القديماستبدله بـلماذا
مطالبة "Respond only with valid JSON..."output_config.formatضمان بدلاً من مجرد طلب؛ لا يوجد انحراف في المخطط (schema drift)1
الملء المسبق لـ { كدور للمساعدoutput_config.formatالملء المسبق غير متوافق مع مخرجات JSON على أي حال1
أداة وهمية + إجبار tool_choice للاستخراجمخرجات JSONالاستجابة هي الـ JSON؛ لا توجد مراسم استدعاء أداة ذهاباً وإياباً1
أدوات حقيقية بدون تحققstrict: true لكل أداةالمدخلات مقيدة بالقواعد (grammar-constrained) لمخططك6
بارامتر output_format التجريبي + رأس (header) تجريبيoutput_config.format، بدون رأسالرأس التجريبي structured-outputs-2025-11-13 لم يعد مطلوباً؛ البارامتر والرأس القديمان يستمران في العمل لفترة انتقالية1

الصف الأخير مهم إذا كنت قد اعتمدت الميزة خلال مرحلتها التجريبية في 2025: يجب أن يستخدم الكود الجديد output_config.format، والعديد من مقتطفات الكود الخارجية التي ستجدها عبر الإنترنت لا تزال تظهر الشكل الأقدم.

الأخطاء الشائعة

400: "Schema is too complex for compilation". تخطت مخططاتك الحدود الصريحة ولكن القواعد المجمعة تتجاوز حدود الحجم الداخلية (التجميع له أيضاً مهلة زمنية قدرها 180 ثانية). قم بتطبيق الإصلاحات الموثقة بالترتيب: اجعل الأدوات الحرجة فقط صارمة (strict)، حول البارامترات الاختيارية إلى مطلوبة (كل اختياري يضاعف تقريباً جزءاً من مساحة حالة القواعد)، قم بتسطيح التداخل (flatten nesting)، أو قسم الأدوات عبر طلبات متعددة.1

400 بسبب ميزة مخطط غير مدعومة. ترفض المخططات الخام (بدون تحويل SDK) ميزات مثل minLength، minimum، المخططات المتكررة (recursive schemas)، الـ $ref الخارجي، و additionalProperties بخلاف false، وما شابه — يذكر نص الخطأ الميزة المخالفة.1 إما أن تتخلى عن القيد، أو تترك zodOutputFormat()/jsonSchemaOutputFormat() تقوم بالتحويل والتحقق محلياً نيابة عنك.5

AnthropicError: Failed to parse structured output من parse(). هذا فشل في التحليل المحلي أو التحقق من الـ SDK — غالباً ما يكون بسبب رفض (refusal) أو اقتطاع بسبب max_tokens وليس خطأ في الخادم. يحمل الخطأ الملقى تفاصيل بناء جملة JSON (نص الرفض ليس JSON) أو ما يصل إلى خمس مشكلات Zod (عدم تطابق المخطط)، ولكنه لا يحمل أبداً الـ Message. إذا كنت بحاجة إلى سبب التوقف والاستخدام عند الفشل، فاستخدم نمط create() + الحماية (guard) من الخطوة 5.5

وصلت انتهاكات النمط (pattern) أو التعداد (enum) إلى Zod. هذا متوقع مع مساعد Zod في SDK 0.102.0: يتم تمرير enum و pattern كنص وصفي بدلاً من قيود قواعد اللغة، والتحقق المحلي هو نقطة التنفيذ (الخطوة 4). أرسل مخططاً خاماً إذا كان تنفيذ تلك الكلمات المفتاحية على مستوى القواعد مهماً لحالة الاستخدام الخاصة بك.1

ترتيب خصائص المخرجات يبدو عشوائياً. إنه حتمي، ولكنه ليس ما يتوقعه الناس: الخصائص المطلوبة أولاً بترتيب المخطط، ثم الخصائص الاختيارية بترتيب المخطط. حدد كل شيء كمطلوب إذا كان الترتيب مهماً في العمليات التالية، أو قم بالفرز بعد التحليل.1

الخطوات التالية

قم بتغليف خدمة الفرز (triage) في حلقة عميل ذكي (agent loop) باستخدام دليل استخدام أدوات Claude في TypeScript، أو اختبر مطالبات الاستخراج (extraction prompts) الخاصة بك ضد التراجع في CI باستخدام promptfoo، أو ضع النظام بالكامل خلف بوابة مستضافة ذاتيًا باستخدام LiteLLM Proxy. بالنسبة لأحمال العمل الضخمة، فإن مزيج Batch API من قسم التكلفة يقلل السعر إلى النصف — ابدأ بالمخطط (schema) الذي بنيته هنا وأرسل سجل التذاكر غير المعالجة كدفعة واحدة (batch).

Footnotes

  1. Anthropic, "Structured outputs" — Claude API documentation, https://platform.claude.com/docs/en/build-with-claude/structured-outputs (fetched June 7, 2026). 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

  2. Anthropic, "Pricing" — Claude API documentation, https://platform.claude.com/docs/en/about-claude/pricing (fetched June 7, 2026). 2 3 4

  3. Node.js release schedule, https://endoflife.date/nodejs (Node 24 Active LTS; maintenance through April 2028; checked June 7, 2026).

  4. npm registry: @anthropic-ai/sdk 0.102.0 (peer range zod ^3.25.0 || ^4.0.0), zod 4.4.3, TypeScript 6.0.3, tsx 4.22.4, @types/node 24.13.1 (checked June 7, 2026). 2

  5. Anthropic TypeScript SDK helpers documentation (helpers.md, anthropic-sdk-TypeScript, main branch, fetched June 7, 2026) and shipped source of @anthropic-ai/sdk 0.102.0 (lib/parser.js, helpers/zod.js, lib/transform-json-schema.js). 2 3 4 5 6

  6. Anthropic, "Strict tool use" — Claude API documentation, https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use (fetched June 7, 2026). 2 3