Claude Opus 5.5 tool_choice 400: اختبار 3 SDKs (2026)
٢٥ سبتمبر ٢٠٢٦

يرفض Claude Opus 5.5 الاستخدام القسري للأدوات: عندما يتم ضبط tool_choice على {"type": "any"} أو {"type": "tool"}، فإنه يعيد خطأ 400. وما إذا كان العميل (agent) الخاص بك سيتوقف عن العمل يعتمد على الـ SDK الموجود بينك وبين API. لقد قمت بالتقاط جسم الطلب الصادر من ثلاثة منهم لمعرفة أيهم يتسبب في ذلك.
ملخص: رفض claude opus 5.5 tool_choice هو واحد من أربعة تغييرات جذرية تؤثر على الكود الذي يعمل بالفعل على Claude Opus 5.1 التوجيه الرسمي هو استبدال الاختيار القسري بـ auto بالإضافة إلى استخدام صارم للأدوات.2 ولكن معظم أكواد العملاء لا تكتب tool_choice يدويًا — بل يقوم إطار عمل (framework) بكتابتها. لذا قمت بتوجيه ثلاثة SDKs إلى مسجل محلي وقرأت البيانات.
النتيجة: يقوم @ai-sdk/anthropic 4.0.63 بهدوء بإعادة كتابة الاختيار القسري إلى {"type":"auto"} ويقوم بتحذيرك. أما @langchain/anthropic 1.5.11 فلا يفعل ذلك — حيث ترسل دالة withStructuredOutput() الخاصة به {"type":"tool","name":"..."}، وهو ما يرفضه API، على الرغم من أنك لم تكتب tool_choice أبدًا. كما أن حماية AI SDK تعتمد على مطابقة سلسلة نصية فرعية (substring match) لمعرف النموذج، لذا فإن claude-opus-5.5 الذي يحتوي على نقطة يفقد هذه الحماية بصمت.
ما ستتعلمه
- إعدادات الطلب التي يرفضها Claude Opus 5.5، مع نص الخطأ الموثق
- لماذا يقرر إطار العمل الخاص بك، وليس الكود الخاص بك، ما إذا كنت ستحصل على خطأ 400
- كيفية التقاط جسم الطلب الحقيقي من أي SDK بدون مفتاح API
- ما الذي يرسله كل واحد من الـ SDKs الثلاثة فعليًا عند "فرض استدعاء أداة"
- كيف تعمل بوابة النماذج في AI SDK، وطرق كتابة معرف النموذج (model-ID) التي تتجاوزها
- الإصلاح المكون من وسيط واحد (one-argument fix) للمخرجات المهيكلة في LangChain على Opus 5.5
- فحص مسبق مستقل عن إطار العمل، وخطآن واجهتهما أثناء بنائه
ما الذي يرفضه Claude Opus 5.5
Claude Opus 5.5 هو نموذج Anthropic المصمم لعمليات البرمجة والعمل المعرفي الطويلة للعملاء، بسعر 4 دولارات لكل مليون توكن مدخل و20 دولارًا لكل مليون توكن مخرج، مقابل 5 دولارات و25 دولارًا لـ Claude Opus 5.1 إنه أرخص، ولكنه أيضًا أكثر صرامة.
هناك أربعة تغييرات جذرية تؤثر على الكود الذي يعمل بالفعل على Claude Opus 5، وأول ثلاثة منها تنطبق أيضًا على Claude Fable 5.1.1 الاستخدام القسري للأدوات هو التغيير الذي يصل إلى أكبر قدر من الأكواد، لأن أطر العمل تضبطه نيابة عنك.
إليك إعدادات شكل الطلب التي تعيد خطأ 400، مجمعة من الصفحات الرسمية:12
| الإعداد | القيمة المرفوضة | البديل |
|---|---|---|
tool_choice | {"type":"any"}, {"type":"tool","name":...} | {"type":"auto"} + strict: true |
thinking | {"type":"disabled"}, {"type":"enabled","budget_tokens":N} | تجاهله؛ قم بتعيين output_config.effort |
temperature | أي قيمة غير افتراضية | تعليمات الـ prompt |
top_p / top_k | أي قيمة غير افتراضية | تعليمات الـ prompt |
| assistant prefill | رسالة assistant في النهاية | structured outputs |
computer_20251124 | إدخال الأداة نفسها | computer_toolset_20260801 |
يغطي هذا الجدول حالات رفض شكل الطلب، وهو ما يمكن أن يكتشفه فحص ما قبل الإرسال (preflight check). هذه ليست المجموعة الكاملة من أخطاء 400 في هذا النموذج — فإعادة تشغيل كتلة التفكير (thinking block) بعد تعديل دور سابق هي حالة منفصلة، وتعتمد على تاريخ إنشاء حسابك.1
هناك تفصيلان في الجدول من السهل إغفالهما. رفض computer_20251124 ينطبق على Claude API و Google Cloud ولكن ليس على Amazon Bedrock، حيث تستمر الأداة القديمة في العمل.1
كما أن التحقق من tool_choice يعمل أيضاً على نقطة نهاية حساب التوكنات (token counting endpoint)، لذا فإن استدعاء تقدير التكلفة مع اختيار إجباري سيفشل أيضاً.1 نص الخطأ دقيق للغاية:
tool_choice: type "tool" and "any" are not supported for this model.
لماذا يحدد الإطار البرمجي (framework) ما إذا كنت ستواجه خطأ 400
اقرأ دليل الانتقال وسيبدو الإصلاح وكأنه عملية "بحث واستبدال" في الكود المصدري الخاص بك.2 بالنسبة لكود Messages API الخام، الأمر كذلك. أما بالنسبة لكود الوكيل (agent)، فعادةً لا يكون كذلك، لأن عبارة "فرض استدعاء أداة" نادراً ما تظهر كـ tool_choice في التطبيق.
بل تظهر كـ toolChoice: 'required'. أو تظهر كـ withStructuredOutput(schema). أو لا تظهر على الإطلاق — إطار برمجي يربط أداة بشكل schema ويفرضها بحيث لا يمكن للنموذج الرد بنص نثري. لن تجد في الـ diff الخاص بك أي tool_choice لتغييره.
هذا يجعل سؤال "هل تسبب Opus 5.5 في تعطل الوكيل الخاص بي؟" سؤالاً عن إصدارات التبعيات (dependencies) لديك، وليس عن الكود الخاص بك. الطريقة الأكثر مباشرة للإجابة على ذلك هي النظر إلى البيانات (bytes) التي تخرج من عمليتك.
التقاط جسم الطلب بدون مفتاح API
لا تحتاج إلى مفتاح، أو حتى توكن واحد مدفوع، لترى ما يرسله الـ SDK. كل واحد من هذه العملاء يتيح لك تجاوز رابط الـ URL الأساسي، لذا فإن خادم HTTP من اثني عشر سطراً يكفي ليحل محل API.
// recorder.mjs — a local stand-in for the Claude API.
import http from 'node:http';
export const captured = [];
const REPLY = {
id: 'msg_local', type: 'message', role: 'assistant', model: 'claude-opus-5-5',
content: [{ type: 'tool_use', id: 'toolu_1', name: 'get_weather', input: { city: 'Paris' } }],
stop_reason: 'tool_use', stop_sequence: null,
usage: { input_tokens: 1, output_tokens: 1 },
};
export function startRecorder() {
return new Promise((resolve) => {
const server = http.createServer((req, res) => {
let raw = '';
req.on('data', (c) => (raw += c));
req.on('end', () => {
captured.push({ path: req.url, body: JSON.parse(raw) });
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify(REPLY));
});
});
server.listen(0, '127.0.0.1', () =>
resolve({ server, url: `http://127.0.0.1:${server.address().port}` }));
});
}
إرجاع كتلة tool_use بدلاً من النص يهم أكثر مما يبدو. الـ SDK الذي يفرض اختياراً إجبارياً من جهة العميل سيتوقف عن العمل (throw) إذا كان الرد لا يحتوي على استدعاء أداة، ومن السهل الخلط بين هذا الخطأ وبين رفض حقيقي. لقد واجهت ذلك بالضبط واضطررت إلى إعادة تشغيل المصفوفة بالكامل.
قم بتوجيه كل عميل إلى url باستخدام مفتاح مؤقت:
const raw = new Anthropic({ apiKey: 'k', baseURL: url, maxRetries: 0 });
const anthropic = createAnthropic({ apiKey: 'k', baseURL: url });
const lc = new ChatAnthropic({ apiKey: 'k', model: 'claude-opus-5-5',
anthropicApiUrl: url, maxRetries: 0 });
قم بتعيين maxRetries: 0. إذا تُرِكت على القيمة الافتراضية، سيقوم كلا العميلين بإعادة المحاولة مع تراجع أسي (backoff) عند حدوث الأخطاء التي يسببها هذا الاختبار، وتستغرق العملية دقائق بدلاً من ثوانٍ.
ما الذي ترسله ثلاثة SDKs فعلياً
الإصدارات المثبتة من سجل npm في 2026-09-25: @anthropic-ai/sdk 0.128.0، و @ai-sdk/anthropic 4.0.63 مع ai 7.0.114، و @langchain/anthropic 1.5.11 مع @langchain/core 1.2.12، على Node v22.23.2.
كل صف أدناه هو حقل tool_choice الذي تمت قراءته من الجسم الملتقط، مع model: 'claude-opus-5-5':
| النداء | tool_choice عبر الشبكة | الحكم |
|---|---|---|
@anthropic-ai/sdk, مكتوب يدويًا {type:'any'} | {"type":"any"} | 400 |
@ai-sdk/anthropic toolChoice:'required' | {"type":"auto"} | downgraded |
@ai-sdk/anthropic toolChoice:{type:'tool'} | {"type":"auto"} | downgraded |
@ai-sdk/anthropic generateObject(schema) | absent | safe |
@langchain/anthropic bindTools(t,{tool_choice:'any'}) | {"type":"any"} | 400 |
@langchain/anthropic withStructuredOutput(schema) | {"type":"tool","name":"get_weather"} | 400 |
@langchain/anthropic withStructuredOutput(…,{method:'jsonSchema'}) | absent | safe |
تصرف الـ SDK الخام كناقل بيانات بحت هو أمر صحيح — فهو مجرد ناقل، وقد أرسل ما كتبته. الصفوف المثيرة للاهتمام هي التي يختلف فيها إطارا العمل حول نفس الطلب.
AI SDK يقوم بخفض المستوى، ويخبرك بذلك
يتعرف @ai-sdk/anthropic 4.0.63 على Claude Opus 5.5 ويعيد كتابة الاختيار القسري قبل مغادرة الطلب. وهو لا يفعل ذلك بصمت. مصفوفة warnings في النتيجة تحمل هذا، حرفيًا من تجربتي:
{
"type": "unsupported",
"feature": "toolChoice",
"details": "toolChoice 'required' is not supported by this model because it rejects forced tool use. Using 'auto' instead. Instruct the model to use a tool in the prompt and verify that a tool call was made."
}
يتم تسجيل نفس النص في وحدة التحكم (console) ما لم تقم بتعيين AI_SDK_LOG_WARNINGS إلى false. لذا فإن وضع الفشل هذا يكون مرئيًا في طرفية التطوير عند التشغيل الأول بعد تغيير معرف النموذج.
خفض المستوى ليس هو الآلية الكاملة أيضًا. إذا عادت الاستجابة بدون استدعاء لأي أداة، يقوم الـ SDK برمي ToolChoiceViolationError — فهو يخفف القيد عبر الشبكة، ثم يتحقق من جانب العميل ما إذا كان النموذج قد التزم بذلك على أي حال. هذه مقايضة معقولة: يتحول خطأ 400 صارم إلى تحذير بالإضافة إلى تأكيد لاحق.
ومع ذلك، فإن هذا يغير الدلالات البرمجية لديك. يتوقف toolChoice: 'required' عن كون ضمان تفرضه الـ API ويصبح مجرد أمل، يتم التحقق منه بعد الواقعة. منطق إعادة المحاولة المكتوب على افتراض أن تخطي استدعاء الأداة أمر مستحيل يحتاج إلى مراجعة ثانية. تظهر نفس الفجوة "هل القيد الذي طلبته لا يزال هو القيد الموجود عبر الشبكة؟" في كشف انحراف أدوات AI SDK، لأسباب مختلفة.
البوابة هي مطابقة لسلسلة فرعية
بالقراءة في dist/index.js، تأتي الحماية من دالة getModelCapabilities(modelId) التي تكون فروعها عبارة عن اختبارات بسيطة للسلاسل الفرعية، يتم فحصها بالترتيب. تم حذف أجسام الفروع هنا؛ الشروط فقط هي المهمة:
function getModelCapabilities(modelId) {
if (modelId.includes("claude-opus-5-5")) {
} else if (modelId.includes("claude-opus-5")) {
} else if (modelId.includes("claude-fable-5-1")) {
// … 10 more branches, then a final else
فرعان فقط من أصل أربعة عشر يضبطان rejectsForcedToolUse: true: وهما claude-opus-5-5 و claude-fable-5-1، وهما النموذجان اللذان تدرجهما Anthropic على أنهما يتشاركان في هذا القيد.1 كل فرع آخر يضبطها على false، بما في ذلك خيار التراجع النهائي للنموذج غير المعروف. لذا فإن الحماية تعمل فقط للمعرفات التي تحتوي حرفيًا على واحدة من هاتين السلسلتين الفرعيتين.
لقد قمت بقياس ست طرق كتابة لنفس النموذج، وقرأت كلًا من tool_choice المرسل و max_tokens الافتراضي — والذي يختلف حسب الفرع وبالتالي يكشف أي فرع تم اتخاذه:
| معرف النموذج المرسل | max_tokens | tool_choice لـ 'required' | الفرع |
|---|---|---|---|
claude-opus-5-5 | 128000 | {"type":"auto"} | Opus 5.5 |
anthropic.claude-opus-5-5 | 128000 | {"type":"auto"} | Opus 5.5 |
claude-opus-5-5-v1:0 | 128000 | {"type":"auto"} | Opus 5.5 |
claude-opus-5.5 | 128000 | {"type":"any"} | Opus 5 |
opus-5-5 | 4096 | {"type":"any"} | unknown |
opus-5.5 | 4096 | {"type":"any"} | unknown |
النماذج التي تبدأ بـ Bedrock أو تنتهي برقم الإصدار لا تزال تحتوي على السلسلة النصية الفرعية، لذا فهي تحتفظ بالحماية. جيد.
أما الثلاثة الأخيرة فلا تحتوي عليها، وتفشل بطريقتين مختلفتين. claude-opus-5.5 التي تحتوي على نقطة تقع ضمن فرع claude-opus-5 ويتم التعامل معها كأنها النموذج السابق. أما الصيغ المجردة مثل opus-5-5 فلا تطابق أي شيء وتستقر في خيار "النموذج غير المعروف" (unknown-model fallback)، والذي يمنحك أيضًا سقف مخرجات يبلغ 4096 توكن.
لا يوجد شيء غريب في هذا. فالبوابات (Gateways) والبروكسيات وملفات الإعدادات الداخلية تعيد تسمية النماذج باستمرار، وهذا المعرف يُقرأ كـ "5.5" في كل جملة تُكتب عنه بينما يكتبه API بصيغة 5-5. إذا أخطأت في ذلك، ستفقد حماية لم تكن تعلم بوجودها، بصمت — حيث لا يظهر التحذير إلا عندما يتطابق البوابة.
LangChain JS لا يمتلك أي بوابة على الإطلاق
يرسل @langchain/anthropic 1.5.11 نفس الـ tool_choice بغض النظر عن النموذج. لقد قمت بتشغيل claude-opus-5-5 و claude-opus-5 و claude-fable-5-1 عبر كلا الأسلوبين وحصلت على نتائج متطابقة في كل مرة: {"type":"any"} لـ bindTools(tools, { tool_choice: 'any' })، و {"type":"tool","name":"get_weather"} لـ withStructuredOutput(schema).
الخيار الثاني هو الفخ. withStructuredOutput() هي الطريقة المعتادة للحصول على كائن محدد النوع من النموذج في LangChain. تبدو وكأنها أداة مساعدة في التحليل (parsing helper). ولكن في الخلفية، تقوم بربط المخطط (schema) الخاص بك كأداة وتفرضه — لذا في Opus 5.5 و Fable 5.1 ينتج عن ذلك خطأ 400، من موقع استدعاء لا يذكر لا الأدوات ولا tool_choice.
هذه ليست مشكلة JavaScript فحسب. فالمشكلة رقم 40777 في LangChain، والتي فُتحت في 2026-09-23 ولا تزال مفتوحة، تبلغ عن نفس الفجوة في حزمة Python: يوجد مساعد _supports_forced_tool_choice() ويتم تطبيقه على with_structured_output()، ولكن bind_tools() ومسار الحمولة النهائي لا يستشيرانه.3 الحزم منفصلة والتغطية تختلف، لذا تحقق من الحزمة التي تستخدمها فعليًا.
إصلاح LangChain يتلخص في وسيط واحد
اطلب مخرجات مهيكلة أصلية (native structured output) بدلاً من أداة مفروضة، وسيختفي الاختيار المفروض:
// 400 on claude-opus-5-5 — binds the schema as a tool and forces it
await lc.withStructuredOutput(schema, { name: 'get_weather' }).invoke('…');
// works — sends output_config.format.json_schema, no tool_choice at all
await lc.withStructuredOutput(schema, { name: 'get_weather', method: 'jsonSchema' })
.invoke('…');
مع استخدام method: 'jsonSchema'، يحمل الجسم الملتقط output_config.format.json_schema ولا يحتوي على حقل tool_choice. وهذا يتطابق مع مسار الاستبدال الرسمي: نقل المخطط إلى المخرجات المهيكلة بدلاً من فرض أداة.2 بخصوص جانب تصميم المخطط في ذلك، راجع مخرجات Claude المهيكلة باستخدام TypeScript و Zod.
ملاحظتان حول الكتابة من واقع التجربة. الخيار يستخدم camelCase — حيث يؤدي 'json_schema' إلى حدوث TypeError. أما 'jsonMode' فيطبع "jsonMode" is not supported for Anthropic models. Falling back to "jsonSchema"، لذا فهو يعمل، ولكن يفضل استخدام المصطلح الصحيح.
لا يحتاج AI SDK إلى تغيير مماثل: generateObject() على claude-opus-5-5 يرسل بالفعل output_config.format.json_schema بدون أدوات وبدون tool_choice.
فحص مسبق لأي إطار عمل
الإصلاحات الخاصة بكل إطار عمل تتقادم بسرعة. ما أردته فعلياً هو تأكيد واحد يعمل على الجسم النهائي (final body)، بغض النظر عما أنتجه — لأن الجسم هو الشيء الوحيد الذي يحكم عليه الـ API.
كل عميل هنا يقبل fetch مخصص، لذا فإن غلافاً واحداً يغطيها جميعاً:
// preflight.mjs
const REJECTS_FORCED_TOOL_USE = [/opus-5-5/, /fable-5-1/];
// Gateways and hand-written config spell the same model several ways, so
// compare on a normalised form rather than an exact string.
export function normalizeModelId(modelId) {
return String(modelId).toLowerCase().replace(/[._]/g, '-');
}
export function checkOpus55Request(modelId, body) {
const problems = [];
const id = normalizeModelId(modelId);
const forced = REJECTS_FORCED_TOOL_USE.some((re) => re.test(id));
const tc = body.tool_choice?.type;
if (forced && (tc === 'any' || tc === 'tool')) {
problems.push(`tool_choice.type "${tc}" is rejected; use "auto" with strict tool use`);
}
const th = body.thinking?.type;
if (th === 'disabled' || th === 'enabled') {
problems.push(`thinking.type "${th}" is rejected; omit thinking and set output_config.effort`);
}
for (const p of ['temperature', 'top_p', 'top_k']) {
if (body[p] !== undefined) problems.push(`${p} is rejected; steer with the prompt instead`);
}
const last = body.messages?.[body.messages.length - 1];
if (last?.role === 'assistant') {
problems.push('assistant prefill is rejected; use structured outputs instead');
}
for (const t of body.tools ?? []) {
if (t?.type === 'computer_20251124') {
problems.push('computer_20251124 is rejected on the Claude API and Google Cloud');
}
}
return problems;
}
export function preflightFetch(realFetch = globalThis.fetch) {
return async (input, init) => {
if (typeof init?.body === 'string') {
let body = null;
try { body = JSON.parse(init.body); } catch {}
if (body?.model) {
const problems = checkOpus55Request(body.model, body);
if (problems.length) {
const err = new Error(
`Opus 5.5 preflight failed for "${body.model}": ${problems.join('; ')}`);
err.name = 'Opus55PreflightError';
// Provider SDKs rewrap a thrown fetch error as a generic connection
// error, so keep the detail reachable on `.cause` too.
err.cause = { opus55Problems: problems, model: body.model };
throw err;
}
}
}
return realFetch(input, init);
};
}
قم بتثبيته حيث تقوم ببناء العميل. جميع العملاء الثلاثة في هذا المنشور يقبلون التجاوز، وقد تأكدت من أن الحارس يعمل من خلال كل منهم:
new Anthropic({ baseURL, fetch: guarded }); // @anthropic-ai/sdk
createAnthropic({ baseURL, fetch: guarded }); // @ai-sdk/anthropic
new ChatAnthropic({ clientOptions: { fetch: guarded } }); // @langchain/anthropic
ما الذي يكتشفه الفحص المسبق
ستة اختبارات، نفس الحارس، مخرجات حقيقية:
PASS ai-sdk toolChoice:'required' (claude-opus-5-5)
BLOCK ai-sdk toolChoice:'required' (claude-opus-5.5 alias)
tool_choice.type "any" is rejected; use "auto" with strict tool use
BLOCK langchain withStructuredOutput (claude-opus-5-5)
tool_choice.type "tool" is rejected; use "auto" with strict tool use
BLOCK langchain bindTools tool_choice:'any' (claude-opus-5-5)
tool_choice.type "any" is rejected; use "auto" with strict tool use
PASS langchain bindTools (no tool_choice) (claude-opus-5-5)
PASS langchain bindTools tool_choice:'any' (claude-opus-5)
الصف الأول يمر لأن AI SDK قد قام بالفعل بخفض الإصدار — لم يتبق شيء قابل للرفض لاكتشافه. الصف الأخير يمر لأن الاختيار القسري (forced choice) مقبول تماماً في Claude Opus 5. كلاهما يمثل السلوك الذي أريده: الفحص يعمل على ما قد يرفضه الـ API، وليس على شكل الكود.
خطآن واجهتهما أثناء البناء
لم يكن أي منهما في الـ SDKs. كلاهما يستحق المعرفة إذا كنت تكتب إصدارك الخاص.
المسودة الأولى سمحت بمرور الاسم المستعار المنقوط. كتبت النمط كـ /claude-opus-5-5/، مطابقاً لمعرف النموذج الذي توثقه Anthropic — وهو بالضبط الخطأ الذي تقع فيه بوابة السلسلة الفرعية الخاصة بـ AI SDK. لقد مر claude-opus-5.5 من فحصي ومن فحص الـ SDK. تم إصلاح ذلك عن طريق توحيد . و _ إلى - قبل المطابقة، وحذف البادئة claude- من النمط.
رسالة الخطأ اختفت. الحارس الذي يرمي خطأً داخل fetch لا يظهر بوضوح: يقوم الـ SDK الخاص بالمزود بالتقاطه وإعادة تغليفه، لذا أبلغ LangChain عن Connection error. مجرد مع اختفاء نصي. ربط التفاصيل بـ err.cause وتتبع سلسلة الأسباب في المعالج يستعيدها:
let c = e, detail = null;
for (let i = 0; i < 4 && c; i++) {
if (c.opus55Problems) { detail = c.opus55Problems; break; }
c = c.cause;
}
إذا كنت تقرأ فقط error.message، سيبدو الفحص المسبق على مستوى fetch وكأنه عطل في الشبكة. هذه تجربة تصحيح أخطاء أسوأ من خطأ 400 الذي يستبدله، لذا قم بتوصيل سلسلة الأسباب قبل الاعتماد عليها.
ما لا يثبته هذا
لم يتم استخدام مفتاح API في أي مكان في هذا المنشور، ولم يصل أي طلب إلى Anthropic. قواعد الرفض مقتبسة من الصفحات الرسمية، تم جلبها في 2026-09-25;12 ما قمت بقياسه هو ما يضعه كل SDK على الشبكة. لم أشاهد بنفسي خطأ 400 مباشراً من Claude Opus 5.5.
القياسات مرتبطة بالإصدارات المذكورة أعلاه. بوابة AI SDK موجودة بدءاً من 4.0.63 — لم أقم بعمل bisect لمعرفة أي إصدار قدمها — وقد تضيف حزمة JS الخاصة بـ LangChain واحدة أيضاً. أعد تشغيل المسجل مقابل ملف lockfile الخاص بك بدلاً من الثقة في هذا الجدول بعد شهر.
كل شيء هنا يخص نظام JavaScript البيئي. حزم Python هي كود منفصل بتغطية منفصلة، كما يظهر في المشكلة #40777.3 وقد اختبرت بُعداً واحداً، وهو الاختيار القسري للأداة. قواعد الرفض الخمس الأخرى موجودة في الفحص المسبق ولكنني لم أستقصِ أي أطر عمل تسبب تفعيلها.
الخلاصة
يخبرك دليل الهجرة بما يجب تغييره في الكود الخاص بك. ولكن في بنية الوكلاء (agent stack)، يكون السؤال الأكثر فائدة هو ما الذي تقوم التبعيات (dependencies) بتغييره نيابة عنك، وقد اختلفت الإجابة بشكل حاد بين اثنين من أشهر الـ SDKs لنفس الطلب.
أحدهما كان قد أطلق بالفعل خفضاً للمستوى (downgrade) مقيداً بالنموذج مع تحذير واضح. والآخر يرسل الصيغة المرفوضة من خلال أكثر استدعاءات المخرجات المهيكلة شيوعاً. لا يمكن اكتشاف أي من هاتين الحقيقتين من خلال الـ diff الخاص بك، وهذا هو السبب في أن التسجيل يستحق الاهتمام — ولماذا يجب أن يكون الفحص المسبق على الجسم (body)، حيث يقع حكم API فعلياً.
إذا كنت ستقوم بتغيير معرف النموذج هذا الأسبوع، فقم بتسجيل حركة البيانات (wire) أولاً. لمزيد من المعلومات حول ميكانيكا حلقة الوكيل (agent-loop) المتعلقة بـ tool_choice بشكل عام، راجع استخدام أدوات Claude والحلقة الوكيلية في TypeScript.
Footnotes
-
Anthropic, "What's new in Claude Opus 5.5" — breaking changes, exact error strings, pricing, and the Fable 5.1 note. https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5 (fetched 2026-09-25) ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11
-
Anthropic, "Migrating to Claude Opus 5.5" — the full list of settings every request must satisfy, and the before/after for forced tool use. https://platform.claude.com/docs/en/models/opus-5-5/migration-guide (fetched 2026-09-25) ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
langchain-ai/langchain issue #40777, "
ChatAnthropicsends unsupported tool choice and thinking configurations for Claude Opus 5.5", opened 2026-09-23, open at the time of writing. https://github.com/langchain-ai/langchain/issues/40777 (fetched 2026-09-25) ↩ ↩2
