الانتقال إلى المحتوى الرئيسي
تعثر معظم أدوات الأمان الثابتة على العلل بمعزل. تفحص ملفًا واحدًا، تُدرج المشكلات، ثم تنتقل. والمشكلة أن أكثر الثغرات تدميرًا في قواعد الشيفرة الحديثة نادرًا ما تكون عللاً فردية. إنها سلسلة: مفتاح توقيع مضمَّن في الشيفرة، إضافة إلى فحص ترخيص مفقود، إضافة إلى حقن SQL — كلٌّ منها بمفرده يبدو قابلًا للإدارة. لكنها مجتمعة طريق للاستيلاء على الحساب. هذا بالضبط نوع التفكير المتشابك الذي تتقنه نماذج اللغة الكبيرة، إن أعطيتها البنية المناسبة. في هذا المقال، سنبني مراجع أمان لشيفرة من وكيلين باستخدام Python و Venice AI API. بنهاية المقال، ستحصل على CLI يمكنك توجيهه إلى أي قاعدة شيفرة Python لإنتاج تقرير Markdown يحوي نتائج ذرّية وسلاسل استغلال. هل تهتم بالتنفيذ الكامل للكود؟ راجع مستودع GitHub. قبل المتابعة، ستحتاج إلى مفتاح Venice API. صدّره كمتغيّر بيئة:

ما الذي سنبنيه

المراجع مشروع Python صغير ببضعة أجزاء واضحة: يبدو التدفق هكذا:
  1. امشِ في دليل الهدف لملفات .py.
  2. ابنِ خريطة مستودع محدّدة (الاستيرادات، الرموز العامة، التواقيع).
  3. لكل ملف، أرسل إلى Scanner مصدره بالإضافة إلى شريحة الحيّ من الخريطة، واجمع النتائج الذرّية.
  4. أرسل اتحاد النتائج بالإضافة إلى خريطة المستودع المكثّفة إلى Chainer واجمع سلاسل الاستغلال.
  5. أسقط أي سلسلة تُشير إلى معرّف نتيجة لم يُنتجه Scanner، أو تُسمي ملفًا لم يأتِ منه أي من نتائجها المُشار إليها.
  6. اكتب تقرير Markdown.
قراران تصميميان يستحقّان الإشارة قبل أن نبدأ بكتابة الشيفرة. الأول هو لماذا وكيلان بدلًا من واحد. فاحص بوكيل واحد يحاول فعل كل شيء في تعليمة واحدة عليه الموازنة بين التعمّق في علل كل ملف وبين الذكاء في التفكير التوافقي. تقسيم العمل يعني أن Scanner يمكنه أن يكون لا يكلّ وضوضائيًا، وأن Chainer يمكنه أن يكون انتقائيًا وهادئًا. إضافة استدعاء LLM واحد إضافي مكرّس لدمج النتائج تفتح فئة كاملة من العلل بشيفرة إضافية ضئيلة. الثاني هو لماذا خريطة مستودع. قواعد الشيفرة الحقيقية تعيش عبر ملفات كثيرة. علّة تتكوّن من «المتحقّق يعمل لكنه لا يُطبَّق لكل تكرار في الجالب، وردّ الجالب ينتهي في العارض» غير مرئية لفاحص لكل ملف. قبل أي استدعاء LLM، نمشي شجرة الهدف بـast في Python ونبني خريطة بنيوية. يرى Scanner حيًّا لكل ملف (مَن يستورد من هذا الملف، ما يستورده هذا الملف، تواقيع تلك الرموز الخارجية). يرى Chainer خريطة كاملة مكثّفة (كل وحدة، كل رمز عام، كل حافة استيراد، بدون مصدر). هذا أقل قدر من هندسة السياق الذي وجدنا أنه يسمح لـ Chainer ببناء سلاسل يعبر تدفق بياناتها حدود الوحدات، دون دفع تكلفة الرموز لحشو قاعدة الشيفرة بالكامل في كل تعليمة.

المتطلبات المسبقة

  • Python 3.12+
  • مفتاح Venice API من venice.ai
  • إلمام أساسي بـ Pydantic، ووحدة ast في Python، و OpenAI Python SDK
يستخدم المستودع المرجعي uv لإدارة التبعيات، لكن بيئة افتراضية عادية تعمل بنفس الكفاءة.

إعداد المشروع

أنشئ مشروعًا جديدًا وثبّت التبعيات:
إذا فضّلت pip، أنشئ بيئة افتراضية بدلًا من ذلك:
أنشئ ملف .env للتطوير المحلي:
سنضع المصدر تحت src/venice_security_reviewer/ لإبقائه قابلًا للاستيراد كحزمة، مع التعليمات تحت prompts/ في جذر المستودع كي يمكن مراجعتها ومقارنتها كأي مصدر آخر:

إعداد عميل Venice

Venice متوافق مع OpenAI، لذا يمكننا استخدام OpenAI Python SDK الرسمي وتوجيه base_url إلى Venice. تركيز إنشاء العميل في ملف واحد يعني أن باقي الشيفرة لا تحتاج إلى معرفة المزوّد الذي تخاطبه: تبديل الخلفية لا يلامس إلا هذه الوحدة الوحيدة. أنشئ src/venice_security_reviewer/client.py:
بعض الأمور الجديرة بالملاحظة:
  • نلجأ افتراضيًا إلى zai-org-glm-5 لأنه نموذج Venice قوي عام الغرض، لكن يمكنك تجاوزه عبر متغير البيئة VENICE_MODEL. لقواعد شيفرة أكبر أو أكثر دقّة، تبديل نموذج أقوى يمكن أن يجعل Chainer أفضل بشكل ملحوظ في جودة السرد.
  • يُرجع build_client العميل ومعرّف النموذج، لذا لا يضطر المتصلون لقراءة متغيرات البيئة بأنفسهم ويمكن للاختبارات حقن تكوين وهمي دون monkeypatching.

تعريف نماذج البيانات

الهدف الكامل من استخدام Pydantic هنا، بدلًا من تمرير قواميس خام، هو الحصول على حدود تحقق صارمة بين LLM وبقية البرنامج. إذا أعاد النموذج JSON مشوّهًا أو اخترع معرّف نتيجة غير موجود، يفشل التحليل بصخب ولا نُمرّر الهلوسة إلى التقرير أبدًا. أنشئ src/venice_security_reviewer/models.py:
القيود تقوم بعمل فعلي هنا:
  • Finding.id وChain.id مقيّدتان بتعبير عادي مثل F-001، C-001. إذا حاول النموذج الإبداع في التنسيق، يفشل التحقق.
  • Chain.findings يتطلب مدخلَيْن على الأقل: «سلسلة» من نتيجة واحدة هي مجرد نتيجة.
  • Chain.severity مقتصرة على high أو critical. مزيج نتائج لا يرفع الأثر فوق أعلى شدّة فردية ليس سلسلة تستحق الإبلاغ عنها.
  • Evidence يفرض أن end_line >= start_line بحيث لا يستطيع النموذج إرجاع نطاقات أسطر بلا معنى.
هذا تحقق الشكل. نحتاج أيضًا إلى تحقق المرجع المتبادل: سلسلة تُشير إلى معرّف نتيجة لم ينتجه Scanner أبدًا لا معنى لها. أضف هذه الدالة إلى models.py:
هذه هي الحماية المحدّدة التي تُبقي Chainer أمينًا. لا يستطيع الإشارة إلا إلى نتائج أنتجها Scanner فعلًا، ولا يستطيع ادّعاء ملفات متورّطة في السلسلة إلا تلك التي جاء منها فعلًا أي من نتائجه. إعادة السلاسل المُسقطة بدلًا من تصفيتها بصمت تتيح لـ CLI إظهار تحذير حين يحاول النموذج اختراع شيء.

بناء خريطة المستودع بـ AST

خريطة المستودع هي الهيكل البنيوي لقاعدة شيفرة Python: السطح العام لكل وحدة، كل حافة استيراد، وفهرس عكسي من «وحدة M» إلى «الوحدات التي تستورد من M». تُبنى مرة واحدة لكل تشغيل فحص باستخدام ast في Python، أبدًا عبر التنفيذ، لذا فهي آمنة للتشغيل على شيفرة عدائية: المحلّل لا يستورد أو يستدعي شيئًا من الشجرة المفحوصة. سنستهلك الخريطة بشكلين. يحصل Scanner على شريحة حيّ لكل ملف بحيث تبقى تعليماته محدودة الحجم. ويحصل Chainer على خريطة كاملة مكثّفة ليتمكن من بناء سلاسل عبر الملفات. أنشئ src/venice_security_reviewer/repo_map.py وابدأ بنماذج Pydantic التي تصف الخريطة:
الآن الدالة المساعدة التي تمشي الشجرة وتتخطى الأدلة التي يجب ألّا نفهرسها:
لكل ملف نريد ثلاثة أشياء من AST: الرموز التي يعرّفها على المستوى الأعلى، حواف الاستيراد، وقائمة __all__ صريحة إن كانت موجودة. تواقيع الدوال وترويسات الفئات تُعرض كسلاسل مدمجة يستطيع LLM قراءتها مباشرة:
يحافظ _SIGNATURE_CHAR_CAP البالغ 200 على التواقيع الواقعية النموذجية (بما فيها تلميحات الأنواع) مع منع الحالات المرضية كاتحاد مكتوب من 200 سطر يُفجّر التعليمة. بعد ذلك، المُستخرج الذي يسحب البيانات البنيوية من وحدة محلّلة. نتعامل مع ast.FunctionDef وast.ClassDef وast.Assign وast.AnnAssign على المستوى الأعلى للثوابت، وكل من ast.Import وast.ImportFrom لحواف الاستيراد. الاستيرادات النسبية تُحلّ إلى صيغتها المطلقة بنقاط بحيث يستطيع Chainer مطابقتها بأسماء الوحدات لاحقًا:
منطق الاستخراج الكامل يمشي tree.body ويُصدر مدخلات SymbolDef وImportEdge لكل عقدة من المستوى الأعلى. تغطي دالة _extract في repo_map.py للمستودع المرجعي التنفيذ الكامل. الشكل الذي يخرج هو قائمة من كائنات ModuleEntry، واحد لكل ملف. الجزء المثير هو ما نفعله بتلك المدخلات. لفّها في RepoMap بطريقتين موجّهتين للمستهلك:
neighborhood(path) هو ما يستدعيه Scanner لكل ملف. يُرجع كائن ModuleNeighborhood يحتوي الوحدة نفسها، وكل وحدة أخرى تستورد منها، وكل رمز داخل المستودع تستورده من غيرها (مع تواقيعها المُحلّلة). يمنح ذلك Scanner سياقًا كافيًا لرصد نتائج لا تكون واضحة إلا في سياق متعدد الملفات، دون جرّ قاعدة الشيفرة كاملة إلى التعليمة. condensed_dict() هو ما يحصل عليه Chainer. تُسقط المقاطع والتواقيع؛ ولا يبقى سوى المسارات وأسماء الوحدات والصادرات العامة وحواف الاستيراد. هذا أصغر تمثيل لا يزال يتيح لـ Chainer التفكير في تدفق البيانات بين الوحدات. أخيرًا، نقطة الدخول التي تبني الشيء بأكمله:
الملفات التي لا نستطيع قراءتها أو التي يفشل تحليلها تُسجّل وتُتخطّى. نُرجع خريطة جزئية بدلًا من فشل التشغيل كله؛ أسوأ حالة هي أن استدعاء Scanner لا يرى حيًّا لملف واحد، وهذا لا يزال فحصًا يعمل.

كتابة وكيل Scanner

يمشي Scanner مسار الهدف، ويلتقط ملفات مصدر Python، ويطلب من Venice تحديد ثغرات ذرّية ملفًا واحدًا في كل مرة. الفحص لكل ملف يبقي التعليمة صغيرة ويجعل الإخفاقات معزولة: ملف سيئ واحد لا يقتل التشغيل كله. سنبقي التعليمة نفسها في ملف منفصل بحيث يمكن مراجعتها ومقارنتها كأي مصدر آخر. أنشئ prompts/scanner.md:
التعليمة الكاملة في المستودع المرجعي تحوي أيضًا قسم «What to look for» يسرد فئات الثغرات الشائعة (الأسرار المضمَّنة، حقن SQL، حقن الأوامر، SSRF، إلغاء تسلسل غير آمن، إلخ) وقسم «How to use the neighborhood» يشرح كيف ينبغي للنموذج استهلاك السياق متعدد الملفات. بعض ملاحظات تصميم التعليمة:
  • نُخبر النموذج بإصدار JSON فقط، بلا نثر أو أسوار. تدعم OpenAI SDK معامل response_format={"type": "json_object"} يفرض هذا على جانب الواجهة، لكن تعزيزه في التعليمة يقلّل الحالات الحدّية.
  • نمنع Scanner صراحة من إنتاج سلاسل بين الملفات. السلاسل وظيفة Chainer، وطلب Scanner القيام بكليهما يُشوّش المسؤولية.
  • نطلب نسخ المقطع حرفيًا. هذا يعني أن التقرير يستطيع اقتباس البايتات الدقيقة التي يدّعي النموذج رؤيتها، ويستطيع المراجع التحقق العشوائي من نتيجة بمقارنة المقطع بالمصدر.
الآن شيفرة الوكيل. أنشئ src/venice_security_reviewer/scanner.py وابدأ بمتنقّل الملفات ومحمّل التعليمة:
MAX_FILE_BYTES حدّ سلامة. وراء ~200 كيلوبايت نتخطى بدلًا من إرسال تعليمة ضخمة من المرجح أنها مكلفة ومنخفضة الجودة. القطعة التالية هي باني التعليمة. يستخدم القالب {filename} و{source} و{neighborhood} كنائبات؛ نستخدم str.replace بدلًا من .format() لأن القالب يحوي أمثلة JSON بأقواس مجعّدة حرفية:
الآن المحلّل. نفكّ JSON، ونحقّق كل نتيجة عبر Pydantic، ونُسقط النتائج المشوّهة فرديًا بدلًا من فشل الملف كله. نتيجة سيئة واحدة يجب ألّا تُضيّع علينا الجيدة:
يُصدر Scanner معرّفات مثل F-001 لكل ملف، لكن Chainer يحتاج إلى الإشارة إلى نتائج عبر المستودع كله. نعيد إصدار المعرّفات مقابل عدّاد رتيب بحيث تكون فريدة عالميًا:
استدعاء فحص الملف الواحد يجمع كل هذا. نقرأ الملف، نبني التعليمة، نرسلها إلى Venice مع response_format={"type": "json_object"} ودرجة حرارة منخفضة، ونحلّل النتيجة:
تفصيلتان جديرتان بالإبراز:
  • نُصلح مسار ملف الأدلة ليكون نسبيًا إلى repo_root بعد التحليل، لأن النموذج يردّد اسم الملف الذي أعطيناه له لكننا نريد شكلًا قانونيًا واحدًا عبر التقرير كله.
  • temperature=0.1 منخفضة عمدًا. نريد Scanner أن يكون محافظًا ومتسقًا عبر التشغيلات؛ الإبداع وظيفة Chainer.
أخيرًا، المنسّق الذي يفحص كل ملف مؤهل تحت الجذر:
تُبنى خريطة المستودع مرة واحدة من المتصل وتُعاد استخدامها لكل ملف، بحيث يرى Scanner بنية عالمية متسقة حتى عندما تفشل ملفات فردية في التحليل أو يتم تخطّيها.

كتابة وكيل Chainer

يأخذ Chainer اتحاد نتائج Scanner بالإضافة إلى خريطة المستودع المكثّفة، ويسأل Venice ما إذا كانت أي من النتائج تتجمع في سلسلة استغلال حقيقية. توجد حمايتان محدّدتان بين LLM والتقرير:
  1. يجب أن تُشير كل سلسلة فقط إلى معرّفات نتائج أنتجها Scanner.
  2. يجب أن تدّعي كل سلسلة فقط ملفات تلامس أدلة نتيجة مشار إليها واحدة على الأقل.
السلاسل التي تنتهك أي قاعدة تُسقط وقت التحليل. هذا يمنع النموذج من هلوسة السلاسل «احتياطًا» ومن ادعاء أن سلسلة تمتد عبر ملفات لا أدلة له فيها. تعليمة Chainer في prompts/chainer.md. جوهرها يبدو هكذا:
التعليمة الكاملة في المستودع المرجعي تشرح أيضًا كيفية قراءة خريطة المستودع، وكيفية تقرير ما يدخل files_involved، وأهم شيء: متى لا نُسلسل. إخبار النموذج بأن «من الصحيح والمتوقع أن قواعد شيفرة كثيرة تحوي نتائج لا تتسلسل» هو ما يمنعه من اختراع سلاسل ليبدو منتجًا. الآن شيفرة الوكيل. أنشئ src/venice_security_reviewer/chainer.py:
MAX_REPO_MAP_CHARS = 8000 سقف ناعم لكتلة خريطة المستودع المعروضة كـ JSON في تعليمة Chainer. عند نحو 4 أحرف لكل رمز، هذا ~2000 رمز، يجلس بشكل مريح داخل نافذة سياق أي نموذج Venice حتى مع وجود النتائج وميزانية السرد فوقها. نُسلسل النتائج إلى كتلة JSON مدمجة. لاحظ أننا نُجرّد snippet من الأدلة هنا عمدًا: لا يحتاج Chainer إلى بايتات خام ليُقرّر ما إذا كانت نتيجتان تتجمعان، وتضمينها يضاعف تقريبًا تكلفة الرموز على قواعد الشيفرة الواقعية:
لقواعد الشيفرة الأكبر يمكن أن تتجاوز خريطة المستودع المكثّفة الكاملة ميزانيتنا الحرفية. عندما يحدث ذلك، نقصّ إلى الوحدات الحاملة للنتائج بالإضافة إلى جيرانها المباشرين. هذا يحفظ بنية كافية لـ Chainer للتفكير في سلاسل لدينا أدلة عليها، ويتخلى عن الباقي:
استراتيجية القصّ بسيطة عمدًا: احتفظ بالوحدات التي تعيش فيها نتائجنا، واحتفظ بجيرانها المباشرين في رسم الاستيراد. ما هو أبعد من ذلك ليس له دور معقول في سلسلة لدينا أدلة عليها حاليًا، فيمكن إسقاطه دون فقدان قوة التفكير. نُعلِّم أيضًا الحمولة بـ_pruned و_kept و_total، بحيث تستطيع تعليمة Chainer تحذير النموذج عندما تكون الخريطة قد قُصّت. تحليل الاستجابة بنفس شكل Scanner: فكّ، حقّق كل سلسلة عبر Pydantic، أسقط المدخلات المشوّهة:
ثم الوكيل نفسه:
أمران يستحقّان الإشارة:
  • نخرج قبل استدعاء النموذج عندما يكون هناك أقل من نتيجتين. لا يمكنك تسلسل نتيجة واحدة، وتخطّي الاستدعاء يعني أننا لا نُحرق رموزًا على نتيجة فارغة مضمونة.
  • temperature=0.2 أعلى قليلًا من 0.1 لـ Scanner. يستفيد Chainer من لمسة إبداع إضافية لرصد التجمعات غير الواضحة، لكننا لا نزال نريده مرتكزًا على النتائج والخريطة التي أُعطي إياها.
  • بعد التحليل، يعمل validate_chain_references التحقق المتقاطع المحدّد الذي كتبناه سابقًا. كل ما ينجو آمن للعرض؛ وكل ما لا ينجو يُسجّل لذا يعرف المشغّل أن النموذج حاول اختراع شيء.
التحقق المتقاطع هذا هو القطعة الأهم في كامل المشروع. إنه الحدّ بين «أداة أمان مفيدة» و«تقرير ذكاء اصطناعي خاطئ بثقة أحيانًا». بوجوده، حتى لو هلوس النموذج، لن تصل السلسلة الخاطئة إلى التقرير أبدًا.

عرض تقرير Markdown

إبقاء العرض منفصلًا عن منطق الوكيل يعني أن كائنات Finding وChain نفسها يمكن تغذيتها لاحقًا إلى صيغ أخرى (JSON، SARIF، HTML) دون لمس Scanner أو Chainer. سنستخدم Jinja2 مع ملف قالب صغير. أنشئ src/venice_security_reviewer/templates/report.md.j2:
ثم العارض في src/venice_security_reviewer/report.py:
يبقى Autoescape مُعطّلًا لقالب Markdown (Markdown ليس HTML)، لكن نتركه مُمكّنًا لأي قوالب .html مستقبلية حسب الامتداد.

ربط واجهة CLI

CLI هو المنسّق: ابنِ خريطة المستودع، افحص، سلسل، اعرض. سنستخدم Typer لتولّي تحليل الوسائط و Rich لطباعة جدول ملخص جميل. أنشئ src/venice_security_reviewer/cli.py:
أضف نقطة دخول السكربت إلى pyproject.toml:
هذا هو خط الأنابيب بأكمله موصولًا.

اختبار الحمايات

اعتمدنا بشدّة على فكرة واحدة طوال هذا البناء: الحمايات المحدّدة هي ما يفصل أداة أمان مفيدة عن أداة خاطئة بثقة. هذا الادعاء يستحق القول فقط إذا استطعنا إثبات أن الحمايات تصمد فعلًا، لذا فإن أكثر الاختبارات قيمة في هذا المشروع لا تستدعي Venice أبدًا. إنها تُحكم حدود Pydantic وأنابيب تجميع التعليمات، مما يعني أنها تعمل خارج الاتصال، في أجزاء من الألفية، بلا مفتاح API وبلا تكلفة رموز. أضف تبعيات التطوير أولًا:
أول شيء يستحق الاختبار هو حدود النموذج نفسها. تؤكّد هذه الاختبارات أن النتائج والسلاسل المشوّهة تُرفض وقت الإنشاء، قبل أن تتمكّن أبدًا من الوصول إلى تقرير. أنشئ tests/test_models.py:
كل واحد من هذه يعكس قيدًا فرضناه على النماذج سابقًا: نطاق أسطر مقلوب، معرّف لا يطابق نمط F-###، و«سلسلة» من نتيجة واحدة. إذا توقّف أي منها عن إطلاق استثناء، فإن فئة كاملة من الهلوسة قد أصبحت ممكنة مرة أخرى بهدوء. أهم اختبار يغطي محقّق المرجع المتبادل، لأنها الدالة التي تُسقط فعلًا السلاسل المخترعة:
F-999 لم يُنتجها Scanner أبدًا، لذا فالسلسلة التي تُشير إليها تنتهي في dropped ولا تصل أبدًا إلى التقرير. الاختبار المرافق في المستودع المرجعي، test_validate_chain_references_drops_unknown_files، يفعل الشيء نفسه لسلسلة تدّعي ملفًا لم يأتِ منه أي من نتائجها. الشيء الثاني الذي يستحق الاختبار هو الأنابيب التي تُغذّي Chainer. من السهل إعادة هيكلة تجميع التعليمة والتوقف بصمت عن تمرير السياق المتعدد الملفات، عند هذه النقطة سيستمر Chainer في العمل لكنه سيصبح أسوأ بهدوء. يبني هذا الاختبار ثبت وحدتين، يعرض التعليمة، ويؤكّد أن المعلومات بين الملفات موجودة فعلًا، مرة أخرى بلا جولة إلى Venice. أنشئ tests/test_cross_file_chain.py:
إذا نجح هذا الاختبار، فإن Chainer يُسلَّم تعليمة تحتوي على كلتا النتيجتين، وكلا مسارَي الملفين، وحافة الاستيراد بينهما. ما إذا كان النموذج يستخدم تلك المعلومات بشكل جيد هو تقييم منفصل خارج النطاق؛ يحرس هذا الاختبار فقط الأنابيب التي تُدخل المعلومات إلى التعليمة في المقام الأول. شغّل مجموعة الاختبارات كلها، مع المُدقّق ومُتحقّق الأنواع، بـ:
ولأن أيًا من هذه الاختبارات لا يلامس الشبكة، فهي آمنة للتشغيل عند كل التزام وفي CI دون حرق رموز أو الحاجة إلى مفتاح Venice. يتضمن المستودع المرجعي أيضًا tests/test_scanner_parse.py و tests/test_chainer_parse.py و tests/test_repo_map.py، التي تغطي حالات حدّية لتحليل JSON (المدخلات المشوّهة تُسقط بدلًا من إعطاب التشغيل) وباني خريطة المستودع بـ AST.

تشغيل المشروع

لتجربته على قاعدة شيفرة حقيقية، وجّه CLI إلى دليل مصدر Python:
أو ثبّته في بيئتك الافتراضية بـ pip install -e . ثم نفّذ venice-security-reviewer scan path/to/your/code. يبدو الإخراج هكذا تقريبًا:
يُظهر تقرير Markdown كل سلسلة في الأعلى مع سردها، ثم كل نتيجة فردية تحتها مع الشدّة و CWE وموقع الملف والوصف والمقطع الحرفي الذي يدّعي النموذج قراءته. يُرفق المستودع المرجعي أيضًا بأربعة أهداف تجريبية مجمّعة كلّها تُمارس شكلًا مختلفًا من التفكير الذي يجب على Chainer القيام به:
  • examples/vulnerable_app — تطبيق Flask متعدد الملفات بثلاث نتائج «منخفضة»، تتجمع اثنتان منها في سلسلة تصعيد امتيازات حرجة عبر الملفات. يختبر ما إذا كان Chainer انتقائيًا فيما يجمعه.
  • examples/url_preview — جالب URL متعدد الملفات بقائمة سماح دفاعية لا تُطبّق لكل تكرار. يختبر التفكير بتدفق البيانات بين الملفات مدمجًا مع طوبولوجيا النشر (عناوين IP المحلية الرابط هي بوابات اعتماد سحابية).
  • examples/csv_query — مصفاة CSV من ملف واحد بهروب صندوق eval عبر __class__.__base__.__subclasses__(). يختبر التفكير على مستوى اللغة بدلًا من تدفق HTTP.
  • examples/webhook_handler — متحقّق HMAC من ملف واحد بثغرة تفاضلية في محلل JSON. يختبر التفكير عبر مواصفات متعددة.
جرّبها بـ:
إذا رأيت CLI يسجّل chainer referenced N unknown finding id(s) or file(s); chains dropped، فهذا محقّق المرجع المتبادل يُمسك النموذج متلبسًا باختراع سلسلة. السلاسل المُسقطة لا تصل أبدًا إلى التقرير؛ تحصل فقط على تحذير يمكنك استخدامه لتعديل التعليمة أو أخذ عينات تشغيلات Chainer إضافية.

توسيع هذا المثال

شكل الوكيلين يعمّم بشكل جيد. بعض الاتجاهات الجديرة بالاستكشاف:
  • لغات أكثر. Scanner لا يتقيّد بلغة على مستوى التعليمة؛ باني AST هو ما يتقيّد بـ Python. بدّل إلى tree-sitter ويمكنك بناء نفس أشكال الحيّ/الخريطة المكثّفة لـ TypeScript أو Go أو Rust.
  • وكيل ثالث للإصلاحات. بمجرد أن تكون لديك سلسلة، طلب وكيل Patcher صياغة diff موحّد يُعطّل إحدى النتائج المكوّنة هو خطوة صغيرة. حقّق الـ diff عبر Pydantic مقابل نفس مجموعة ملفات الأدلة وستحصل على نفس حارس الهلوسة مجانًا.
  • صيغ الإخراج. render_report هو المكان الوحيد الذي يعرف عن Markdown. أضف عارض SARIF ويمكن للنتائج نفسها أن تُسقط في فحص شيفرة GitHub. أضف عارض JSON ويمكنك توجيه النتائج إلى نظام مصبّ.
  • التخزين المؤقت بهاش الملف. استدعاءات Scanner لكل ملف مستقلة ومتعادية. التخزين المؤقت بـ (file_hash, prompt_hash, model) يعني أن إعادة فحص مستودع تغيّر فيه ملف واحد تعيد تشغيل Scanner فقط على ذلك الملف.
  • أخذ عينات لـ Chainer. للتشغيلات عالية المخاطر، استدعِ Chainer N مرة بدرجة حرارة أعلى قليلًا واقطع النتائج. السلاسل التي يجدها النموذج باستمرار من المرجح أن تكون حقيقية؛ السلاسل التي يجدها مرة ولا يجدها مرة أخرى من المرجح أنها ضوضاء.
  • نماذج أقوى. zai-org-glm-5 هو الافتراضي لأنه يحقّق توازنًا جيدًا بين التكلفة والجودة للتفكير التوافقي، لكن لقواعد الشيفرة الأصعب يمكن أن يجعل تبديل نموذج Venice أقوى (عبر VENICE_MODEL) سرديات Chainer أكثر إحكامًا بشكل ملحوظ.

الختام

شكرًا لقراءتك! آمل أن يكون هذا قد ساعدك على فهم كيفية بناء أداة أمان بالذكاء الاصطناعي جديرة بالثقة فعلًا. النمط الذي استخدمناه هنا يعمّم خارج الأمان أيضًا: في أي وقت تريد فيه LLM التفكير عبر الملفات بطريقة يجب أن ترتكز على أدلة حقيقية، الوصفة هي نفسها. ابنِ خريطة بنيوية محدّدة، سلّم النموذج شريحة منها تتسع للسياق، حقّق مراجع النموذج مقابل البنية، وأسقط أي شيء لا يستطيع ارتكازه. باستخدام Python مع Venice AI API، يمكننا بناء وكلاء يجمعون بين تفكير LLM وحدود تحقق صارمة، ونشحن شيئًا يعطي إجابة مفيدة بدلًا من إجابة تبدو واثقة.