وكيل الذكاء الاصطناعي في الإنتاج ليس prompt داخل نافذة سياق أكبر. إنه خدمة تسمح للنموذج باختيار أفعال، ومراقبة نتائجها، والاستمرار حتى يصل إلى نتيجة محددة أو يطلب تدخّل شخص. النموذج مكوّن واحد فقط من هذه الخدمة. أما طبقة التحكم المحيطة به فتحدد ما يمكن للنموذج رؤيته، والأدوات التي يمكنه استدعاؤها، والأفعال التي تحتاج إلى موافقة، وكيف تبقى الحالة بعد إعادة التشغيل، وما الدليل المطلوب قبل نشر نسخة جديدة.
تقدم هذه المقالة هندسة مرجعية لوكيل واحد يملك مجموعة أدوات صغيرة. ويمكن للحدود نفسها أن تدعم workflow بخطوات ثابتة أو تصميماً مستقبلياً متعدد الوكلاء. ابدأ بأصغر حلقة تحقق المهمة. يميّز دليل Anthropic للوكلاء الفعالين أيضاً بين workflows المتوقعة والأنظمة التي يوجّه فيها النموذج استعمال الأدوات بصورة ديناميكية. الاستقلالية قرار متعلق بالمنتج، وليست إعداداً معمارياً افتراضياً.
الهندسة المرجعية
افصل مسار الطلب عن حلقة اتخاذ القرار وعن الأفعال التي تغيّر العالم الخارجي. تقوم بوابة gateway بمصادقة المستدعي، وإنشاء معرّفي الطلب والتتبع، وتطبيق الحصص، وإزالة الحقول الحساسة أو تصنيفها. يملك orchestrator الحلقة. يحوّل model adapter الحالة المحايدة إلى طلب للمزوّد، ثم يحوّل استجابة المزوّد إلى نوع قرار صغير. تتحقق tool gateway من الوسائط، وتخوّل principal المنفّذ، وتطبق policy، وتستدعي connector معزولاً. يجب أن تكون مخازن الحالة والأحداث خارج العملية حتى يتمكن worker من المتابعة بعد العطل.
[المستخدم أو عميل API]
|
[Gateway: الهوية، الحدود، request ID]
|
[Orchestrator: policy -> model -> tool loop]
/ | \
[State] [Approval service] [Tool gateway]
| | |
[Memory/RAG] [قرار بشري] [واجهات API، ملفات، طوابير]
|
[أحداث وآثار تتبع]
لا تمنح النموذج credentials خاماً، ولا وصولاً غير محدود إلى الشبكة، ولا كتابة مباشرة إلى قاعدة البيانات. يجب أن تعرض tool gateway عمليات ضيقة مثل "search_orders" و"draft_refund" و"send_message"، لا عميلاً عاماً لـ HTTP ولا وحدة تحكم SQL. تحتاج كل عملية إلى مالك، ومخطط إدخال، وpermission، وفئة مخاطر، وtimeout، وشكل نتيجة موثق.
استخدم غلافاً صريحاً للطلب:
| الحقل | الغرض |
|---|---|
| tenantId وactorId | ربط كل قراءة وكل أثر بجهة منفّذة موثقة. |
| requestId وtraceId | ربط الإعادات والموافقات واستدعاءات الأدوات والسجلات. |
| goal | حفظ نتيجة المستخدم المطلوبة بعيداً عن رسائل النموذج. |
| policyVersion وmodelVersion | جعل التشغيل قابلاً لإعادة البناء بما يكفي للتحقيق. |
| deadline وstepBudget | تحديد الزمن وعدد دورات النموذج والأداة. |
يساعد ملف NIST AI RMF للذكاء الاصطناعي التوليدي على تنظيم المخاطر عبر دورة الحياة. حوّل أسئلته إلى ضوابط عملية داخل الغلاف وtool gateway، ولا تعتبر الإطار دليلاً على أن deployment بعينه آمن.
حلقة الأدوات
ينبغي أن يملك الحلقة مالك واحد، وأن يكون انتقال الحالة مرئياً في كل دورة:
- حمّل run وpolicy وملخص المحادثة وكتالوج الأدوات المسموح بها.
- أنشئ model input محدوداً. ميّز بين نص المستخدم والنص المسترجع ومخرجات الأداة وتعليمات النظام باعتبارها فئات ثقة مختلفة.
- اطلب من النموذج final response أو typed tool call. ارفض الاسم والوسائط غير الصحيحة قبل التنفيذ.
- نفّذ authorization وrisk policy خارج النموذج. قول النموذج إن الفعل آمن ليس قرار تفويض.
- إذا عبر الفعل approval gate، احفظ pending action وتوقف. استأنف من الفعل المحفوظ بعد قرار صريح.
- نفّذ connector مع deadline وidempotency key. سجّل نتيجة منقّحة وأضفها إلى state.
- افحص حدود الخطوات والرموز والتكلفة والزمن. تابع فقط إذا سمحت policy بدورة أخرى.
- أعد إجابة تبيّن ما حدث وما لم يحدث وأي موافقة أو عدم يقين ما زال قائماً.
لا تضع استدعاء النموذج داخل حلقة "while" غير محدودة. يمنع step budget تحويل الطلب إلى سلسلة مكلفة بسبب prompt أو أداة. يحمي deadline العميل ومجموعة workers. يكشف كاشف الاستدعاءات المتكررة أن النموذج يطلب الفعل الفاشل نفسه. ويمكن لـ circuit breaker تعطيل connector متدهور مؤقتاً مع إبقاء أدوات القراءة متاحة.
توحّد مواصفة Model Context Protocol resources وprompts وtools، لكنها لا تحل محل consent وauthorization وisolation التي يطبقها المضيف. اعتبر MCP server اعتماداً خارجياً. ثبّت هويته، وافحص الأدوات التي يعلنها، وقيّد البيانات المرسلة إليه، وطبّق policy نفسها التي تطبقها على connector داخلي.
الحالة والذاكرة والسياق
الحالة هي السجل الدائم لـ run واحد. خزّن هدف المستخدم، والرسائل أو مراجعها، واستدعاءات الأدوات ونتائجها، والموافقات، وقرارات policy، وإصدارات النموذج والأدوات، والطوابع الزمنية، والحالة، وتصنيف الخطأ. أضف الأحداث أولاً ثم اشتق run view الحالية. يجعل ذلك recovery وaudit أسهل من تعديل JSON blob غير شفاف. شفّر الحقول الحساسة، واعزل tenants، وحدد retention، واجعل الحذف يشمل snapshots وindexes وtraces وcaches.
تاريخ المحادثة ليس memory. احتفظ بسياق عمل قصير العمر للـ run الحالي. لا تحفظ user memory أو business memory إلا عند وجود غرض وقاعدة retention ومصدر وطريقة للتصحيح من المستخدم أو المدير. خزّن facts مع provenance وحقل confidence أو freshness. لا تكتب تخمينات النموذج في memory الدائمة لمجرد أنها تبدو مقنعة.
الاسترجاع tool له trust boundary. طبّق tenant وauthorization filters قبل ranking. انقل source identifiers وtimestamps إلى السياق. أخبر النموذج بأن retrieved text بيانات لا تعليمات. حدّد chunks، وأزل secrets غير اللازمة، وسجّل query ومعرّفات الوثائق دون المحتوى الخاص افتراضياً. في PostgreSQL قارِن lexical candidates وvector candidates، وأجر rerank بعد authorization فقط. يشرح دليل RAG الهجين الداخلي مع pgvector هذه الحدود بمزيد من التفصيل.
يجب أن يكون context compaction قابلاً للتصحيح بدرجة كافية. لخص الأدوار القديمة بمخطط ثابت يحفظ القرارات والأسئلة غير المحسومة وآثار الأدوات والاستشهادات وقيود المستخدم. أبقِ event log الأصلي خارج prompt. إذا غيّر summary معنى pending action، توقف واطلب review بدلاً من المتابعة بصمت.
الأدوات وحدود التهديد
مخطط الأداة security contract، وليس metadata للنموذج فقط. تحقّق gateway من الأنواع والأطوال وقيم enum وownership للمورد والعلاقات بين الحقول. حوّل الأسماء إلى internal identifiers بعد authorization. افصل read tools عن write tools. امنح connectors credentials قصيرة العمر ومحدودة بـ tenant وعملية واحدة. شغّل code أو file work الخطير في worker معزول وقائمة سماح للملفات والشبكة.
اعتبر كل محتوى خارجي عدائياً محتملاً. قد يحتوي email أو web page أو issue أو document أو tool description أو MCP resource على indirect prompt injection. ضع المحتوى داخل حدود واضحة في model input، وأزل executable markup عند الحاجة، واترك التطبيق يقرر permissions. يجب أن يكون output validation مستقلاً عن النموذج. قبل إرسال refund إلى payment connector مثلاً تحقق من amount وcurrency وactor permission وpolicy maximum.
يجب أن يغطي نموذج التهديد:
| الحد | الفشل الذي يجب منعه |
|---|---|
| User إلى gateway | الاستيلاء على الحساب، الطلبات الضخمة، ومعرّفات tenant آخر. |
| Model إلى tool gateway | argument injection، والتباس الصلاحيات، والاستقلالية المفرطة. |
| Retrieval أو MCP إلى model | indirect prompt injection وتعليمات خبيثة داخل البيانات. |
| Connector إلى خدمة خارجية | تسريب credentials، وSSRF، وreplay، واستخراج البيانات. |
| Worker إلى state store | تعديل الأحداث، وسياسة قديمة، وسجل تدقيق ناقص. |
يعرض OWASP GenAI LLM Top 10 prompt injection وexcessive agency وinsecure output handling وunbounded consumption كمخاطر تحتاج إلى mitigations على مستوى التطبيق. ويقدم دليل Dayfing عن أمن prompt injection وMCP قائمة فحص تركز على التهديدات. System prompt توجيه مفيد، لكنه ليس sandbox ولا authorization layer ولا secret store.
بوابات الموافقة والتحكم البشري
ضع approvals حول الآثار، لا حول reasoning غير المؤذي. يمكن أن تكون قراءة تقويم المستخدم تلقائية. أما إرسال رسالة خارجية أو تغيير سجل أو إصدار مال أو حذف بيانات أو نشر code فيحتاج غالباً إلى policy decision يعتمد على actor وtarget وamount وreversibility وconfidence. يجب أن يكون gate في application code حتى لا يتمكن prompt من تجاوزه.
احفظ approval request الذي يحتوي على proposed tool وnormalized arguments والموارد المتأثرة والسبب وإصدار policy وexpiration وhash للحالة ذات الصلة. يجب أن يرى reviewer المعلومات نفسها. اربط قراره بـ action hash وactor. بعد approval أعد فحص authorization وfreshness وbudget قبل التنفيذ. بعد rejection أو expiry سجّل القرار وأبلغ النموذج بأن الفعل لم يحدث. لا تسمح لـ approval قديمة بتفويض payload تغيّر.
لـ human-in-the-loop أوضاع متعددة:
| الوضع | الاستخدام المناسب |
|---|---|
| Observe | تسجيل أو أخذ عينات من الأفعال منخفضة المخاطر مع بقاء agent تلقائياً. |
| Confirm | طلب approval مباشرة قبل أثر غير قابل للعكس. |
| Review | جعل شخص يفحص draft كاملاً والأدلة المختارة. |
| Take over | نقل run إلى operator مع الحالة والقفل الحاليين. |
صمّم التوقف كحالة عادية، لا كاستثناء. يمكن لطابور تسليم approvals المعلقة، وقد ينتهي إشعار، ويمكن لـ worker متابعة run على host آخر. يجب أن يعرف المستخدم هل agent يفكر أو ينتظر بيانات أو approval أو retry أو انتهى.
الإعادات وعدم التكرار والاسترداد
صنّف الأخطاء قبل retry. يحتاج validation error إلى call مصحح أو سؤال للمستخدم. يجب أن توقف authentication وauthorization errors التنفيذ. ينبغي أن تحترم rate limits إشارة retry من المزوّد. إن timeout أو انقطاع الاتصال ملتبس في writes، لأن الخدمة البعيدة ربما طبّقت الأثر. لا تعاود إلا عملية تجعل دلالتها أو idempotency key التكرار آمناً. تشرح الفقرة 9.2.2 من RFC 9110 سبب عدم إعادة non-idempotent methods تلقائياً دون وسيلة لإثبات سلامة الأثر.
ولّد key ثابتاً من run وlogical action، لا من attempt number. يحتفظ connector بالـ key والنتيجة النهائية طوال retry window. إذا وصل key نفسه مع arguments مختلفة فارفضه. استخدم exponential backoff مع jitter وعدداً صغيراً من attempts. retry ليس model decision جديداً. احفظ original call ورقم المحاولة وresponse class ومعرّف طلب connector.
Recovery مسألة state machine. استخدم حالات مثل "running" و"waiting_for_approval" و"retrying" و"failed" و"completed" و"cancelled". يمنع lease عاملين من تنفيذ run نفسه في الوقت نفسه. عند فقدان lease توقف قبل الأثر التالي. يستطيع reconciler مقارنة pending actions بسجلات connector بعد crash في worker. يجب أن تنتشر cancellation إلى model requests وtool calls وqueues وapproval requests عندما يدعم المزود ذلك.
المراقبة
أنشئ trace واحداً لكل user request وspans لاستدعاءات النموذج والاسترجاع وفحوص policy والموافقات والأدوات. سجّل duration وstatus وعدد retries وinput وoutput token counts عند توفرها، وmodel وprompt versions وtool name وrisk class وcost estimate. نقّح secrets والمحتوى الحساس قبل التصدير. استخدم run ID ثابتاً لربط approval أو support ticket بالـ trace دون وضع بيانات شخصية في baggage. تشرح مواصفة OpenTelemetry لانتقال السياق ربط trace context بين الخدمات وتحذر من headers غير موثوقة ومن baggage الحساسة.
قِس task completion وفق rubric، ونجاح tool calls، وvalidation failures، وapproval rate، ومعدلات retry وtimeout، وp50 وp95 latency، وتكلفة tokens والأدوات لكل task مكتملة، وcancellation rate وpolicy blocks. قسّمها حسب model version وtool وtenant class وrelease. قد يخفي انخفاض عدد الأخطاء إجابات خاطئة صامتة، لذلك اربط traces بعينات transcripts ونتائج evaluators. لا تسجّل chain-of-thought. خزّن decision metadata مختصرة وreasoning أو citations الظاهرة التي تسمح بها policy.
يبيّن الدليل الداخلي حول مراقبة وكلاء الذكاء الاصطناعي كيف تجعل هذه الإشارات مفيدة دون تحويل السجلات إلى قاعدة ثانية للأسرار.
التقييمات قبل وبعد الإصدار
Agent eval هو scenario له starting state محدد، وأدوات مسموحة، وinvariants متوقعة، وscoring rule. لا تكفي final answer. تحقّق من استعمال authorized tool، وحفظ tenant scope، وطلب approval عند الحاجة، وعدم تكرار write، والاستشهاد بالمصدر الصحيح، والتوقف عند budget. أضف scenarios عدائية: retrieved text خبيث، connector غير متاح، timeout بعد write، approval قديمة، طلب غامض، وtool data مشوهة.
استخدم suite متعددة الطبقات:
- اختبارات unit حتمية لـ schemas وauthorization وredaction وidempotency وstate transitions وbudget enforcement.
- اختبارات replay باستعمال tool responses مسجلة وmodel decisions ثابتة للتحقق من recovery.
- اختبارات scenario على model مع rubric للنتيجة والسلامة والتواصل.
- اختبارات red-team لـ direct وindirect injection وتسريب البيانات وexcessive agency وdenial of service.
- عينات production مع privacy controls وhuman review ومسار لتحويل failures إلى regression cases.
أصدر scenario وtools وpolicy وprompts وmodel وevaluator مع نسخ واضحة. احفظ failures مع trace وأصغر input قابل لإعادة الإنتاج. قارن candidate release بـ baseline، ولا تقبل regression في hard safety invariants حتى لو تحسن المتوسط. يشرح دليل Anthropic لتقييمات الوكلاء لماذا يحتاج استعمال الأدوات عبر أدوار متعددة إلى تقييم trajectory. ويوفر دليل Dayfing لتقييمات وكلاء الذكاء الاصطناعي مصفوفة اختبار عملية.
مفاضلات التكلفة والزمن
كل model turn وretrieved token وtool call وapproval pause وretry يضيف وقتاً أو مالاً. حدّد budgets لكل فئة مهمة بدلاً من رقم عالمي واحد. استخدم model أصغر في routing وextraction وpolicy prechecks عندما تكفي دقته المقاسة. احتفظ بـ model أقوى للتخطيط الغامض أو final synthesis. خزن tool catalogs وretrieval embeddings الثابتة مؤقتاً. لخّص context قبل أن يكبر، لكن قِس ما إذا كان summary يسبب turns إضافية أو فقدان facts.
شغّل read-only calls المستقلة بالتوازي، ثم ادمج النتائج مع provenance واضح. أبقِ writes متسلسلة ما لم يوفر connector transaction أو compensation مصممة. اعرض progress دون كشف secrets. للعمل الطويل، احفظ job ودع worker يتابع بعد انتهاء HTTP request. النموذج الأسرع ليس أرخص إذا سببت أخطاؤه human review أو compensating writes أو runs متكررة. قِس total cost لكل نتيجة صحيحة ومتوافقة مع policy.
حلقة TypeScript قابلة للتشغيل
يستخدم مثال TypeScript المحايد عن البروتوكول أدناه fake model وأدوات محلية، ولذلك يعمل بلا provider SDK أو network access. يوضح typed decision loop وwrite approval وbounded retries وstable idempotency key وحاجز duplicate effect. يمكن استبدال model بـ adapter حقيقي مع إبقاء حدود policy وtool.
type ToolCall = { id: string; name: string; input: unknown };
type Message =
| { role: "user"; content: string }
| { role: "assistant"; content: string; toolCall?: ToolCall }
| { role: "tool"; callId: string; content: string };
type Decision =
| { kind: "answer"; text: string }
| { kind: "call"; call: ToolCall };
type Tool = {
sideEffect: "read" | "write";
run(input: unknown, idempotencyKey: string): Promise<string>;
};
const issued = new Set<string>();
const tools: Record<string, Tool> = {
getBalance: {
sideEffect: "read",
async run(): Promise<string> {
return JSON.stringify({ account: "demo", cents: 4200 });
},
},
sendInvoice: {
sideEffect: "write",
async run(input: unknown, idempotencyKey: string): Promise<string> {
if (issued.has(idempotencyKey)) return "already-sent";
if (typeof input !== "object" || input === null) throw new Error("invalid input");
issued.add(idempotencyKey);
return "invoice-sent";
},
},
};
const model = {
async decide(messages: readonly Message[]): Promise<Decision> {
const toolCount = messages.filter((message) => message.role === "tool").length;
if (toolCount === 0) {
return { kind: "call", call: { id: "balance-1", name: "getBalance", input: {} } };
}
if (toolCount === 1) {
return { kind: "call", call: { id: "invoice-1", name: "sendInvoice", input: { cents: 1200 } } };
}
return { kind: "answer", text: "The balance was checked and the invoice was sent." };
},
};
const wait = (milliseconds: number) => new Promise((resolve) => setTimeout(resolve, milliseconds));
async function execute(call: ToolCall, tool: Tool, key: string): Promise<string> {
for (let attempt = 0; attempt < 3; attempt += 1) {
try {
return await tool.run(call.input, key);
} catch (error) {
if (attempt === 2) throw error;
await wait(10 * 2 ** attempt);
}
}
throw new Error("unreachable");
}
async function run(): Promise<string> {
const state: { messages: Message[]; completed: Set<string> } = {
messages: [{ role: "user", content: "Check the balance and send the invoice." }],
completed: new Set<string>(),
};
const sessionId = "session-demo";
for (let step = 0; step < 6; step += 1) {
const decision = await model.decide(state.messages);
if (decision.kind === "answer") return decision.text;
const tool = tools[decision.call.name];
if (!tool) throw new Error("unknown tool");
const key = sessionId + ":" + decision.call.id;
if (tool.sideEffect === "write" && !process.argv.includes("--approve")) {
return "Paused for approval: " + decision.call.name;
}
if (state.completed.has(key)) continue;
const result = await execute(decision.call, tool, key);
state.completed.add(key);
state.messages.push(
{ role: "assistant", content: "", toolCall: decision.call },
{ role: "tool", callId: decision.call.id, content: result },
);
}
throw new Error("step budget exceeded");
}
run().then(console.log).catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
شغّل compile باستخدام TypeScript toolchain للمشروع ثم نفّذ JavaScript الناتج بلا flag لرؤية approval pause، وبعدها مع --approve للسماح بالكتابة. يحفظ المثال state في الذاكرة عن قصد. في production يجب أن تكون state دائمة ومحددة بـ tenant ومشفرة عند الحاجة ويستعيدها worker يراعي lease.
ترتيب البناء
حدّد نتيجة المهمة والآثار الممنوعة قبل اختيار model. نفّذ read tool واحداً وreversible write tool واحداً خلف schemas وauthorization. أضف durable events وbudgets وapproval states وidempotency قبل أدوات أخرى. instrument أول trace من البداية إلى النهاية. أنشئ eval scenarios من failure modes الحقيقية وشغّلها مع كل تغيير في prompt أو policy أو tool أو model. أضف MCP أو multi-agent delegation فقط عندما يبرر requirement مقاس trust boundary إضافية.
قراءة مرتبطة
- أمن prompt injection وMCP
- تقييمات وكلاء الذكاء الاصطناعي
- مراقبة وكلاء الذكاء الاصطناعي
- RAG هجين مع pgvector
- Anthropic: Building effective agents
- Anthropic: Demystifying evals for AI agents
- مواصفة Model Context Protocol
- NIST AI RMF Generative AI Profile
- OWASP GenAI LLM Top 10
- انتقال السياق في OpenTelemetry
- RFC 9110 HTTP Semantics