سنبني في هذا الدرس وكيلاً مخصصاً يخدم احتياجاً واقعياً: مساعد محاسبة آلي لمكتب صغير في الدار البيضاء يعالج الفواتير الواردة، يستخرج البيانات، يصنّفها، ويُسجلها في جدول Excel ثم يُنشئ تقريراً شهرياً. الهدف: نقل العمل من 8 ساعات أسبوعياً إلى 30 دقيقة مراجعة فقط.
1. تعريف نطاق الوكيل بدقة
قبل أي كود، اكتب على ورقة: ما الذي سيفعله الوكيل؟ ما الذي لن يفعله؟ ما الأدوات التي يحتاجها؟ مثالنا:
- يفعل: قراءة PDF فاتورة، استخراج المورد والتاريخ والمبلغ والـ TVA، تصنيف وفق دليل الحسابات، تسجيل في Google Sheets.
- لا يفعل: إرسال مدفوعات، تعديل بيانات بنكية، التواصل مع الموردين.
- الأدوات: قارئ PDF، تصنيف نصي، Google Sheets API، إرسال إشعار Telegram.
2. تجهيز البيئة
npm init -y
npm install @anthropic-ai/claude-agent-sdk pdf-parse googleapis node-telegram-bot-api zod
export ANTHROPIC_API_KEY=sk-ant-...
export GSHEET_ID=...
3. تعريف الأدوات الأربع
import { tool } from '@anthropic-ai/claude-agent-sdk';
import { z } from 'zod';
import pdf from 'pdf-parse';
const readPdf = tool({
name: 'read_invoice_pdf',
description: 'قراءة محتوى نصي من ملف PDF فاتورة',
inputSchema: z.object({ path: z.string() }),
handler: async ({path}) => {
const buf = await Bun.file(path).arrayBuffer();
const data = await pdf(Buffer.from(buf));
return data.text.slice(0, 8000);
}
});
const classifyExpense = tool({
name: 'classify_expense',
description: 'تصنيف مصروف وفق دليل الحسابات SYSCOA المغربي',
inputSchema: z.object({ description: z.string(), amount: z.number() }),
handler: async ({description, amount}) => {
if (/internet|hosting|hetzner|ovh/i.test(description)) return '6175 خدمات اتصالات';
if (/loyer|location/i.test(description)) return '6132 إيجار';
if (/restaurant|repas/i.test(description)) return '6256 ضيافة';
return '6189 خدمات متنوعة';
}
});
4. كتابة System Prompt محكم
const systemPrompt = `أنت محاسب آلي يعمل لمكتب استشارات في الدار البيضاء.
- تُعالج فواتير المغرب والاتحاد الأوروبي.
- تتحدث بالعربية الفصحى عند الحوار، وتستعمل أرقاماً عربية شرقية أو غربية حسب طلب المستخدم.
- التزم بمعيار SYSCOA المغربي للحسابات.
- لا تُسجّل أبداً بيانات بنكية كاملة. أخفِ آخر 4 أرقام فقط.
- إذا كانت الفاتورة غير واضحة، اطلب توضيحاً قبل التصنيف.
- أرسل إشعاراً عبر Telegram إلى المدير المالي عند تجاوز فاتورة 5000 درهم.`;
5. الحلقة الرئيسية
const result = query({
prompt: 'عالج كل ملفات PDF في مجلد /invoices/2026-04 وأنشئ تقريراً شهرياً.',
options: {
model: 'claude-sonnet-4-6',
systemPrompt,
tools: [readPdf, classifyExpense, appendToSheet, sendTelegram],
maxTurns: 30,
permissionMode: 'auto-with-hooks'
}
});
for await (const msg of result) {
if (msg.type === 'tool_use') console.log('🔧', msg.name, msg.input);
if (msg.type === 'text') console.log(msg.content);
}
6. إضافة Hook للموافقة على المصاريف الكبيرة
const hooks = {
PreToolUse: async (tool, input) => {
if (tool === 'append_to_sheet' && input.amount > 5000) {
const ok = await askHumanViaTelegram(`فاتورة ${input.amount} د. تأكيد؟`);
if (!ok) return { block: true, message: 'رفض المستخدم' };
}
return { allow: true };
}
};
7. اختبار الوكيل
أنشئ مجلد tests/fixtures به 10 فواتير حقيقية (بأسماء موردين شائعين: Hetzner، Wave، Orange، CMI). شغّل الوكيل في وضع dry-run يُسجل دون كتابة Google Sheets. تحقق من دقة التصنيف يدوياً ثم عدّل قاعدة classifyExpense.
8. النشر على VPS بـ systemd
على Hetzner CX22، أنشئ خدمة systemd تشغّل الوكيل كل ساعة عبر OnCalendar=hourly. وجّه السجلات إلى Loki. أضف نقطة /health لمراقبتها بـ Uptime Kuma.
9. التكلفة الفعلية
| البند | التكلفة الشهرية |
|---|---|
| VPS Hetzner CX22 | 4.51 € |
| Anthropic API (1000 فاتورة) | ~12 USD |
| Telegram Bot | 0 |
| Google Sheets | 0 |
| المجموع | ~17 USD |
مقارنة بـ 8 ساعات أسبوعية لموظف بأجر 80 د/الساعة = 2560 د شهرياً (~250 USD).
10. الأخطاء الشائعة
| الخطأ | الحل |
|---|---|
| السماح للوكيل بالكتابة دون مراجعة | أضف PreToolUse + هاتف بشري |
| system prompt قصير | اشرح قواعد العمل بدقة |
| عدم تسجيل tool_use | سجّل كل استدعاء للتدقيق |
| تجاهل أخطاء PDF محمي | أضف فحص encryption قبل القراءة |
11. أسئلة متكررة
هل أستطيع استعمال Opus 4.7 بدلاً من Sonnet؟ نعم، للفواتير المعقدة أو متعددة العملات. التكلفة أعلى 5×.
كيف أحمي مفتاح API؟ Vault مثل Doppler أو متغير بيئة على الخادم، لا تضعه في الكود.
هل يعمل في وضع offline؟ Claude API يحتاج إنترنت. للعمل offline، Mistral 7B محلياً عبر Ollama، لكن جودة أقل.