على مدى عامين، كان بناء وكيل برمجي يعني كتابة الحلقة بنفسك: استدعِ النموذج، حلّل استدعاءات الأدوات، نفّذها، أعد النتائج، وكرّر حتى الانتهاء. الجميع أعاد بناء الآلية نفسها، والجميع أخطأ في الأجزاء الصعبة بطرق دقيقة — ضغط السياق، والتعافي من أخطاء الأدوات، وحدود الصلاحيات، والاستئناف بعد الانهيار.
يتبنّى AI SDK 7 موقفاً مختلفاً. فبدلاً من منحك أدوات أفضل لبناء حلقة، يمنحك الحلقات التي تعمل فعلاً. يغلّف HarnessAgent أطر الوكلاء الراسخة — Claude Code وCodex وPi — خلف واجهة TypeScript واحدة، ثم يتيح لك ضبط ما يمكنها الوصول إليه: أي بيئة معزولة تعمل داخلها، وأي مهارات تُحمّل، وأي أدوات تتطلب موافقة بشرية.
يبني هذا الدرس وكيل مراجعة طلبات السحب (Pull Requests) على GitHub باستخدام هذه المنظومة. في النهاية سيكون لديك وكيل يستنسخ مستودعاً داخل بيئة معزولة، ويراجع طلب السحب بمهارة كتبتها أنت، ويطلب الإذن قبل نشر أي شيء علني، وينجو من إعادة تشغيل الخادم في منتصف العمل.
لماذا الأطر الجاهزة بدلاً من حلقتك الخاصة؟ الإطار (harness) هو حصيلة الضبط المتراكم لوكيل برمجي إنتاجي — بنية التوجيهات، وإدارة السياق، ومخططات الأدوات، وسلوك إعادة المحاولة. يتيح لك HarnessAgent أن ترث هذا العمل وتصرف جهدك على ما يخصّك فعلاً: منطق المجال، وحواجز الأمان، وسطح التكامل.
المتطلبات المسبقة
قبل البدء، تأكد من توفر:
- Node.js 20 أو أحدث (يُفضّل Node 24 — بيئة التنفيذ المعزولة تستهدفه)
- TypeScript 5.5+ وإلمام بالتكرار غير المتزامن
- حساب Vercel إن أردت استخدام البيئات المعزولة المستضافة (البيئات المحلية تعمل بدونه)
- مفتاح API لمزود واحد على الأقل — Anthropic لـ Claude Code، أو OpenAI لـ Codex
- رمز وصول شخصي من GitHub بصلاحية
repoلمثال المراجعة - معرفة عملية بمساعد
tool()في AI SDK — إن كنت جديداً عليه، ابدأ من درس وكلاء البث في AI SDK 5
ما الذي ستبنيه
وكيل مراجعة يعمل من سطر الأوامر:
- يستقبل اسم مستودع GitHub ورقم طلب السحب
- يشغّل بيئة معزولة مع المستودع مُستنسخاً داخلها
- يشغّل Claude Code داخل تلك البيئة مع مهارة مراجعة مخصصة
- يقرأ فروقات الشيفرة والمشكلات المرتبطة عبر أدوات ذات أنواع محددة
- يشترط موافقة صريحة قبل نشر تعليق مراجعة
- يحفظ حالته بحيث تُستأنف الجلسة المقطوعة بدل أن تبدأ من الصفر
سنبنيه طبقة تلو الأخرى، ونشغّله عند كل خطوة.
الخطوة 1: إعداد المشروع
أنشئ المشروع وثبّت حزم AI SDK 7:
mkdir pr-review-agent && cd pr-review-agent
pnpm init
pnpm add ai@latest zod
pnpm add @ai-sdk/anthropic @ai-sdk/openai
pnpm add @ai-sdk/sandbox @ai-sdk/workflow @ai-sdk/tui
pnpm add -D typescript tsx @types/nodeملف tsconfig.json بالحد الأدنى:
{
"compilerOptions": {
"target": "ES2023",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "dist"
},
"include": ["src"]
}اضبط "type": "module" في package.json، ثم أنشئ ملف البيئة:
# .env
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
GITHUB_TOKEN=ghp_...
VERCEL_OIDC_TOKEN=... # مطلوب فقط للبيئات المستضافةلا ترفع هذا الملف إلى المستودع أبداً. أضف .env إلى .gitignore قبل أول commit. الوكلاء الذين ينفذون أوامر Shell يجعلون تسريب بيانات الاعتماد أخطر بكثير من المعتاد — فبيئة معزولة تحمل رمز الإنتاج ليست معزولة إلا بالاسم.
الخطوة 2: أول HarnessAgent
ابدأ بأصغر شيء قابل للتشغيل. أنشئ src/hello-agent.ts:
import 'dotenv/config';
import { HarnessAgent } from 'ai';
import { claudeCode } from 'ai/harnesses';
const agent = new HarnessAgent({
harness: claudeCode,
instructions:
'You are a careful code reviewer. Be concise and specific. ' +
'Prefer concrete line references over general advice.',
});
const result = await agent.generate({
prompt: 'Explain what a race condition is in a Node.js HTTP handler, in three sentences.',
});
console.log(result.text);شغّله:
pnpm tsx src/hello-agent.tsثلاثة أمور تستحق الانتباه. لم تكتب أي حلقة — HarnessAgent يملكها. ولم تصف صيغة استدعاء الأدوات للنموذج — الإطار يأتي بصيغته الخاصة. وinstructions تُضاف فوق توجيهات النظام الخاصة بالإطار بدل أن تستبدلها، فتوجّه السلوك دون التخلي عن الضبط الذي جئت من أجله.
تبديل الإطار تغيير من سطر واحد:
import { codex } from 'ai/harnesses';
const agent = new HarnessAgent({
harness: codex, // [!code highlight]
instructions: 'You are a careful code reviewer...',
});الخطوة 3: أضف بيئة معزولة
حتى الآن لا يملك الوكيل بيئة تنفيذ. امنحه واحدة. البيئة المعزولة (sandbox) هي نظام ملفات ومساحة عمليات منفصلة يمكن للوكيل تشغيل أوامر Shell داخلها دون المساس بجهازك.
أنشئ src/sandboxed-agent.ts:
import 'dotenv/config';
import { HarnessAgent } from 'ai';
import { claudeCode } from 'ai/harnesses';
import { createVercelSandbox } from '@ai-sdk/sandbox';
const agent = new HarnessAgent({
harness: claudeCode,
sandbox: createVercelSandbox({
runtime: 'node24',
ports: [4000],
timeoutMs: 10 * 60 * 1000,
}),
instructions:
'You have a sandbox with Node 24. Use shell commands to inspect and test code. ' +
'Always run the test suite before concluding that a change is safe.',
});
const result = await agent.generate({
prompt:
'Create a small Node script that computes the 40th Fibonacci number ' +
'both recursively and iteratively, then benchmark both and report the difference.',
});
console.log(result.text);صار الوكيل الآن يكتب الملفات، ويشغّل node، ويقرأ المخرجات، ويستنتج منها — كل ذلك داخل حاوية تختفي عند انتهاء التشغيل.
للتطوير المحلي يمكنك تجنّب الرحلة إلى الخادم المستضاف:
import { createLocalSandbox } from '@ai-sdk/sandbox';
const sandbox = createLocalSandbox({
cwd: './workspace',
allowedCommands: ['node', 'npm', 'pnpm', 'git', 'ls', 'cat', 'grep'],
});allowedCommands حدّ حقيقي وليس اقتراحاً. البيئة المحلية تشارك نظام ملفاتك. بدون قائمة سماح، فإن "شغّل الاختبارات" و"احذف المستودع" فعلان من الفئة نفسها بالنسبة للوكيل. في الإنتاج، فضّل البيئة المستضافة — فالعزل تفرضه الحاوية لا مقارنة نصية.
الخطوة 4: غلّف معرفة المجال كمهارة
التوجيهات تصبح ثقيلة بسرعة. حين يبدأ نصّك يحتوي على قوائم تحقق وأعراف الفريق، انقله إلى مهارة (skill) — كتلة توجيهات مسمّاة وموصوفة وقابلة لإعادة الاستخدام يحمّلها الإطار عند الحاجة.
أنشئ src/skills/review-pr.ts:
export const reviewPullRequestSkill = {
name: 'review-github-pr',
description:
'Reviews a GitHub pull request against the team engineering standards. ' +
'Use whenever the user asks for a PR review, code review, or diff assessment.',
content: `
# Pull Request Review
## Procedure
1. Read the PR title, body, and linked issues to establish intent.
2. Read the full diff before commenting on any single file.
3. Check the diff against the review checklist below.
4. Verify claims by running code in the sandbox — never assert that a test
passes without running it.
5. Produce the output in the required format.
## Review checklist
- **Correctness:** off-by-one errors, unhandled null and undefined,
incorrect async ordering, missing await.
- **Error handling:** every catch block either handles or rethrows.
Empty catch blocks are always a finding.
- **Security:** unvalidated input reaching a query, a shell command,
or a filesystem path. Secrets in source.
- **Tests:** does each behavioural change have a corresponding test?
- **Scope:** does the diff do anything the PR description does not mention?
## Output format
For each finding emit exactly:
**[severity] file:line** — one-sentence description of the defect.
Then a concrete failure scenario: specific inputs leading to specific wrong output.
Severity is one of: blocker, major, minor, nit.
If you find nothing, say so plainly. Do not invent findings to appear thorough.
`,
};اربطها بالوكيل:
const agent = new HarnessAgent({
harness: claudeCode,
sandbox: createVercelSandbox({ runtime: 'node24' }),
skills: [reviewPullRequestSkill], // [!code highlight]
instructions: 'You are a senior engineer reviewing code for a TypeScript team.',
});حقل description هو الجزء الحامل للثقل. يقرأ الإطار الأوصاف ليقرر متى تكون المهارة ذات صلة، لذا اكتبها كشرط تفعيل ("استخدمها كلما طلب المستخدم...") لا كملخّص.
أما الأطر التي تعمل داخل حاويات يديرها المزود، فارفع المهارة مرة واحدة وأشر إليها بمُعرّف بدل إعادة إرسال محتواها في كل استدعاء:
import { uploadSkill } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { readFileSync } from 'node:fs';
const { providerReference } = await uploadSkill({
api: anthropic.skills(),
files: [
{ path: 'review-pr/SKILL.md', content: readFileSync('./skills/review-pr/SKILL.md') },
],
displayTitle: 'PR Review Standards',
});الخطوة 5: امنح الوكيل أدوات ذات أنواع محددة
المهارات تخبر الوكيل كيف يفكر. الأدوات تمنحه الوصول. وكيلنا يحتاج إلى GitHub، فلنعرّف أدوات بمخططات Zod.
أنشئ src/tools/github.ts:
import { tool } from 'ai';
import { z } from 'zod';
const GITHUB_API = 'https://api.github.com';
async function gh(path: string, token: string, init?: RequestInit) {
const response = await fetch(`${GITHUB_API}${path}`, {
...init,
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
...init?.headers,
},
});
if (!response.ok) {
throw new Error(`GitHub ${response.status}: ${await response.text()}`);
}
return response;
}
export const readPullRequest = tool({
description: 'Fetch a pull request title, body, author, and unified diff.',
inputSchema: z.object({
owner: z.string().describe('Repository owner, e.g. "vercel"'),
repo: z.string().describe('Repository name, e.g. "ai"'),
number: z.number().int().positive().describe('Pull request number'),
}),
contextSchema: z.object({ token: z.string() }),
execute: async ({ owner, repo, number }, { context: { token } }) => {
const meta = await gh(`/repos/${owner}/${repo}/pulls/${number}`, token).then((r) => r.json());
const diff = await gh(`/repos/${owner}/${repo}/pulls/${number}`, token, {
headers: { Accept: 'application/vnd.github.v3.diff' },
}).then((r) => r.text());
return {
title: meta.title,
body: meta.body ?? '',
author: meta.user?.login,
changedFiles: meta.changed_files,
additions: meta.additions,
deletions: meta.deletions,
diff: diff.slice(0, 120_000),
};
},
});
export const postReviewComment = tool({
description:
'Post a review comment on a pull request. This is publicly visible and cannot be undone.',
inputSchema: z.object({
owner: z.string(),
repo: z.string(),
number: z.number().int().positive(),
body: z.string().min(1).describe('Markdown body of the review comment'),
}),
contextSchema: z.object({ token: z.string() }),
execute: async ({ owner, repo, number, body }, { context: { token } }) => {
const result = await gh(`/repos/${owner}/${repo}/issues/${number}/comments`, token, {
method: 'POST',
body: JSON.stringify({ body }),
}).then((r) => r.json());
return { url: result.html_url, id: result.id };
},
});تفصيلان مهمان هنا.
يُبقي contextSchema رمز GitHub خارج مدخلات النموذج تماماً. الوكيل يختار أي طلب سحب يقرأ؛ وبيئة التشغيل هي من تزوّد بيانات الاعتماد. النموذج لا يرى الرمز أصلاً، ومن ثمّ لا يستطيع تسريبه في رد أو سطر سجل أو ملف يكتبه داخل البيئة المعزولة.
أما حد diff.slice(0, 120_000) فمقصود. طلب سحب ضخم قد ينتج فروقات تستهلك نافذة السياق بالكامل ولا تترك مجالاً للاستدلال. الاقتطاع عند حد معروف يفشل بشكل متوقّع بدل أن يفشل بشكل غامض.
الخطوة 6: احمِ الأدوات الخطرة بالموافقة
readPullRequest غير مؤذية. أما postReviewComment فتنشر شيئاً علنياً باسمك. يتيح لك AI SDK 7 التعبير عن هذا الفرق بشكل تصريحي:
import { HarnessAgent } from 'ai';
import { claudeCode } from 'ai/harnesses';
import { createVercelSandbox } from '@ai-sdk/sandbox';
import { readPullRequest, postReviewComment } from './tools/github.js';
import { reviewPullRequestSkill } from './skills/review-pr.js';
export const reviewAgent = new HarnessAgent({
harness: claudeCode,
sandbox: createVercelSandbox({ runtime: 'node24', timeoutMs: 15 * 60 * 1000 }),
skills: [reviewPullRequestSkill],
tools: { readPullRequest, postReviewComment },
toolApproval: {
postReviewComment: 'user-approval', // [!code highlight]
},
toolContext: { token: process.env.GITHUB_TOKEN! },
instructions:
'You are a senior engineer reviewing code for a TypeScript team. ' +
'Review thoroughly before posting anything. Post at most one comment per run.',
});حين يستدعي الوكيل postReviewComment، يتوقف التشغيل ويُظهر طلب موافقة بدل التنفيذ. تعامل معه عبر التكرار على البث:
const stream = await reviewAgent.stream({
prompt: 'Review pull request 412 in vercel/ai and post your findings.',
});
for await (const part of stream.fullStream) {
if (part.type === 'tool-approval-request') {
console.log(`\nAgent wants to call: ${part.toolName}`);
console.log(JSON.stringify(part.input, null, 2));
const approved = await askUser('Approve? (y/n) ');
await stream.respondToApproval({ id: part.id, approved });
}
if (part.type === 'text-delta') process.stdout.write(part.text);
}ويمكنك أيضاً التعبير عن السياسة كدالة حين يعتمد القرار على الوسائط لا على هوية الأداة:
toolApproval: {
postReviewComment: async ({ input }) =>
input.body.length > 2000 ? 'user-approval' : 'auto-approve',
}الموافقة حدّ أمني لا لمسة تجربة استخدام. القاعدة التي تصمد في الإنتاج: أي أداة يظهر أثرها خارج عمليتك — نشر، إرسال بريد، نشر إصدار، دفع، حذف — تكون محميّة بالموافقة افتراضياً. أما أدوات القراءة فقط فتعمل بحرية. هذا التصنيف الواحد يمنع معظم أنماط الفشل التي تجعل الفرق تفقد الثقة بالوكلاء.
الخطوة 7: أضف المهل الزمنية والمراقبة
الوكيل المتوقف عن الاستجابة أسوأ من الوكيل الفاشل. يوفّر AI SDK 7 مهلاً زمنية متعددة الطبقات:
const result = await reviewAgent.generate({
prompt: 'Review pull request 412 in vercel/ai.',
timeout: {
totalMs: 15 * 60 * 1000, // التشغيل بالكامل
stepMs: 90_000, // أي خطوة مفردة
chunkMs: 20_000, // الفجوة بين أجزاء البث
toolMs: 30_000, // الافتراضي لكل استدعاء أداة
tools: {
readPullRequestMs: 45_000, // الفروقات الكبيرة تحتاج وقتاً أطول
},
},
});chunkMs هو المعامل الذي يتخطاه الناس ثم يندمون على تخطّيه — فهو يلتقط اتصال مزوّد متوقفاً كان سيبقى مفتوحاً حتى انتهاء totalMs.
للتتبّع، سجّل القياسات مرة واحدة عند الإقلاع:
import { registerTelemetry } from 'ai';
import { OpenTelemetry } from '@ai-sdk/opentelemetry';
registerTelemetry(new OpenTelemetry());ثم اقرأ مقاييس كل تشغيل من الخطوة الأخيرة:
const { performance } = await result.finalStep;
console.log({
responseTimeMs: performance.responseTimeMs,
outputTokensPerSecond: performance.outputTokensPerSecond,
timeToFirstOutputMs: performance.timeToFirstOutputMs,
totalTokens: result.usage.totalTokens,
});إن كانت لديك منظومة مراقبة قائمة، فإن درس Langfuse لمراقبة نماذج اللغة يوضح كيفية توجيه هذه الآثار إلى لوحة تحكم مع إسناد التكلفة على مستوى التوجيه.
الخطوة 8: اجعل التشغيل قابلاً للاستئناف
مراجعة طلب سحب قد تستغرق عشر دقائق. عمليات النشر وإعادة التشغيل والتصغير إلى الصفر كلها تحدث داخل هذه النافذة. يحفظ WorkflowAgent حالة الوكيل بين الخطوات فتُستأنف الجلسة المقطوعة من آخر نقطة تفتيش.
import { WorkflowAgent } from '@ai-sdk/workflow';
import { claudeCode } from 'ai/harnesses';
import { createVercelSandbox } from '@ai-sdk/sandbox';
import { readPullRequest, postReviewComment } from './tools/github.js';
import { reviewPullRequestSkill } from './skills/review-pr.js';
export const durableReviewAgent = new WorkflowAgent({
harness: claudeCode,
sandbox: createVercelSandbox({ runtime: 'node24' }),
skills: [reviewPullRequestSkill],
tools: { readPullRequest, postReviewComment },
toolApproval: { postReviewComment: 'user-approval' },
toolContext: { token: process.env.GITHUB_TOKEN! },
workflowId: (input) => `pr-review-${input.owner}-${input.repo}-${input.number}`,
});المعرّف workflowId الحتمي يمنحك خاصية عدم التكرار مجاناً: إعادة تشغيل طلب السحب نفسه تستأنف الجلسة القائمة بدل أن تبدأ مراجعة مكررة.
اربطه بـ webhook لتبدأ المراجعات عند أحداث طلبات السحب:
// app/api/github-webhook/route.ts
import { durableReviewAgent } from '@/lib/review-agent';
export async function POST(req: Request) {
const event = await req.json();
if (event.action !== 'opened' && event.action !== 'synchronize') {
return new Response('ignored', { status: 200 });
}
await durableReviewAgent.trigger({
owner: event.repository.owner.login,
repo: event.repository.name,
number: event.pull_request.number,
prompt: `Review pull request ${event.pull_request.number}.`,
});
return new Response('queued', { status: 202 });
}ولأن trigger تعود فور إدراج المهمة بشكل دائم في الطابور، يستجيب الـ webhook ضمن مهلة GitHub بأريحية بينما يواصل الوكيل عمله.
الخطوة 9: شغّله من واجهة طرفية
للتجريب المحلي، تمنحك @ai-sdk/tui جلسة تفاعلية بأسطر قليلة:
// src/cli.ts
import 'dotenv/config';
import { runAgentTUI } from '@ai-sdk/tui';
import { reviewAgent } from './review-agent.js';
await runAgentTUI({
agent: reviewAgent,
title: 'PR Review Agent',
onApprovalRequest: async ({ toolName, input }) => ({
approved: await confirmInTerminal(`Call ${toolName}?`, input),
}),
});pnpm tsx src/cli.tsتعرض الواجهة الطرفية الاستدلال واستدعاءات الأدوات وMarkdown كنص منسّق، وتتعامل مع طلبات الموافقة داخلها. وهي أسرع طريقة لمراقبة ما يفعله وكيلك فعلاً قبل وضعه خلف webhook.
اختبار التنفيذ
تحقق من كل طبقة على حدة:
الإطار يستجيب. شغّل src/hello-agent.ts. يجب أن تحصل على ثلاث جمل دون أي استدعاء أدوات.
البيئة المعزولة تنفّذ. شغّل src/sandboxed-agent.ts وتأكد أن المخرجات تحتوي أرقام قياس حقيقية. إن أورد الوكيل توقيتات دون أن يشغّل شيئاً، فالبيئة غير مربوطة — تحقق من تمرير createVercelSandbox ومن صلاحية رمزك.
المهارة تُحمَّل. اطلب مراجعة طلب سحب وتأكد أن المخرجات تتبع صيغة **[severity] file:line**. إن لم تفعل، فوصف المهارة لا يُطابق — اجعله شرط تفعيل أوضح.
الموافقة تحجب. اطلب من الوكيل نشر تعليق وأجب بـ n. تحقق عبر واجهة GitHub أنه لا يوجد تعليق:
curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/repos/OWNER/REPO/issues/412/comments" | jq 'length'الاستئناف يعمل. أطلق تشغيلاً دائماً، وأنهِ العملية بعد أول استدعاء أداة، ثم أعد التشغيل بالمعرّف workflowId نفسه. يجب أن تُستأنف الجلسة بدل إعادة قراءة الفروقات من الصفر.
استكشاف الأخطاء
Sandbox timed out في المستودعات الكبيرة. الميزانية الافتراضية غالباً أصغر من أن تكفي تثبيتاً كاملاً. ارفع timeoutMs للبيئة وامنح readPullRequest قيمة toolMs أطول خاصة بها. وإن كان التثبيت هو المهيمن، جهّز صورة البيئة مسبقاً بالاعتماديات مدمجة.
الوكيل يتجاهل المهارة. المشكلة في الوصف دائماً تقريباً. "يراجع طلبات السحب" ملخّص؛ أما "استخدمها كلما طلب المستخدم مراجعة طلب سحب أو مراجعة شيفرة أو تقييم فروقات" فهو شرط تفعيل. اكتب شروط تفعيل.
طلبات الموافقة لا تصل أبداً. لا تستطيع generate() إظهارها — فهي لا تُحلّ إلا عند انتهاء التشغيل. تتطلب الموافقات استخدام stream() والتكرار على fullStream، أو دالة onApprovalRequest في الواجهة الطرفية.
نفاد نافذة السياق مع الفروقات الكبيرة. خفّض حدّ diff.slice وأضف أداة تجلب رقعة ملف واحد عند الطلب. ترك الوكيل يسحب الملفات انتقائياً أفضل من دفع الفروقات كاملة عبر النافذة.
أخطاء الترحيل من AI SDK 6. شغّل أداة التحويل بدل التعديل اليدوي:
npx @ai-sdk/codemod v7التغيير اليدوي الرئيسي هو تحوّل Agent إلى ToolLoopAgent. وإن كان وكيلك يستخدم حلقة مكتوبة يدوياً حول generateText، فلن تمسّها أداة التحويل — ذلك ترحيل يعود إليك أن تقوم به بوعي.
الخطوات التالية
- وسّع مجموعة الأدوات. أضف أدوات لحالة التكامل المستمر والمشكلات المرتبطة وخيوط المراجعات السابقة ليستدل الوكيل على التاريخ لا على الفروقات الحالية فقط.
- ادمج الأطر. شغّل Claude Code وCodex على طلب السحب نفسه ووازن بين نتائجهما — الاختلاف بين إطارين مؤشر قوي على غموض حقيقي في الشيفرة.
- أضف التقييمات. ابنِ مجموعة اختبارات من طلبات سحب بعيوب معروفة وقِس معدل الاكتشاف كلما ضبطت المهارات. يغطي درس Promptfoo للتقييمات الأدوات اللازمة لذلك.
- احفظ النتائج. اكتب المراجعات إلى قاعدة بيانات لتتبّع فئات العيوب الأكثر تكراراً في فريقك.
- وسّع إلى MCP. اعرض أدواتك عبر بروتوكول سياق النموذج لتعمل القدرات نفسها في Cursor وClaude Desktop — راجع درس بناء خادم MCP.
الخلاصة
التحوّل في AI SDK 7 هو تحوّل في مستوى التجريد. لم تعد تجمّع وكيلاً من مكوّنات أولية؛ بل تهيّئ بيئة لوكيل يعمل أصلاً. والأجزاء التي تقدّمها أنت هي وحدها التي لا يستطيع غيرك تقديمها: حدّ البيئة المعزولة، ومعرفة المجال المُغلّفة كمهارة، والأدوات ذات الأنواع المحددة التي تصل إلى أنظمتك، وسياسة الموافقة التي تقرر أي الأفعال يجوز لآلة أن تنفذها دون إشراف.
الجزء الأخير هو الأجدر بالتأمل. وكيل برمجي يملك عزلاً في بيئة معزولة، وتحديد نطاق لبيانات الاعتماد عبر contextSchema، وبوابات موافقة على كل فعل ظاهر للخارج — ليس عرضاً توضيحياً، بل نظاماً يمكنك توجيهه إلى مستودع حقيقي. والطبقات التي بنيتها هنا، بهذا الترتيب، هي بالضبط ما يجعل ذلك صحيحاً.
ابدأ بمسار القراءة فقط. اضبط جودة المراجعة حتى ترضيك. وعندها فقط، سلّم الوكيل رمزاً يستطيع الكتابة به.