Image: AI generated
المشكلة
وكلاء الكود الذكي (مثل Claude Code) يتنقلون في قواعد الكود باستخدام grep للعثور على الملفات و read لفتحها. وحدة read هي الملف.
ماذا يحدث عندما يحتوي ملف واحد على 20 دالة؟
تحتاج نوع CrossError واحد → read
→ 19 دالة غير ضرورية تأتي معه
→ تلوث السياق
أفاد بحث “Lost in the Middle” (Stanford, 2024) أن أداء LLM ينخفض بأكثر من 30% عندما تُدفن المعلومات ذات الصلة في منتصف السياق. وكشف “Context Length Alone Hurts LLM Performance” (Amazon, 2025) أن حتى الرموز غير الضرورية الفارغة تسبب تدهوراً بنسبة 13.9-85%.
دراسة GSM-DC (Yang et al., EMNLP 2025) تذهب أبعد. من خلال تجارب مضبوطة، أثبتت أن السياق غير ذي الصلة لا “يدفن” المعلومات المفيدة فحسب، بل يُضعف بشكل كبير اختيار مسار الاستدلال والدقة الحسابية لـ LLM. الـ 19 دالة غير الضرورية التي تأتي معه ليست “هدراً” — إنها “تداخل”.
أثبت البحث أن “السياق الأقصر أفضل”. لكن لم تكن هناك أداة لتقسيم الكود هيكلياً بحيث يُحمّل فقط ما هو ضروري.
filefunc يسد هذه الفجوة. هو اتفاقية هيكلة كود وأداة CLI لتطوير تطبيقات Go — خدمات الواجهة الخلفية، أدوات CLI، مولدات الكود، ومدققات SSOT.
المبدأ الأساسي
ملف واحد، مفهوم واحد. اسم الملف = اسم المفهوم.
سواء كان func أو type أو interface أو مجموعة const — القاعدة واحدة. كل القواعد الأخرى تُشتق من هذا المبدأ الواحد.
# بدون filefunc
read utils.go → 20 func، 19 غير ضرورية. السياق ملوث.
# مع filefunc
read check_one_file_one_func.go → func واحدة. بالضبط ما هو مطلوب.
عدم فتح 290 ملفاً غير ضروري أهم من اختيار الـ 5-10 الصحيحة. دراسة إكمال الكود في ASE 2025 (Yusuf et al.) أفادت أن الاسترجاع على مستوى الأجزاء يحسن جودة إكمال الكود بنسبة 6% مقارنة بالاسترجاع على مستوى الملف، و16% مقارنة بعدم وجود سياق. ليست كمية السياق هي التي تحدد الجودة — إنها الدقة.
المواطن الأول هو وكيل الذكاء الاصطناعي
هيكل كود filefunc مصمم لوكلاء الذكاء الاصطناعي، لا للبشر.
وكلاء الذكاء الاصطناعي يتنقلون بـ grep، لا بـ ls. سواء كان هناك 500 أو 1000 ملف، rg '//ff:func feature=validate' واحد يكفي. المزيد من الملفات يعني أن كل ملف أصغر — ضوضاء أقل لكل read. المزيد من الملفات أفضل فعلياً. أفاد Cao et al. (2026) بنتائج تجريبية تُظهر أن وكلاء البرمجة يعالجون مجموعات بيانات تصل إلى 3 تريليون رمز عبر تنقل نظام الملفات (ls، grep، read)، متفوقين على نماذج السياق الطويل الحالية بنسبة 17.3%. وحدة تنقل وكيل الذكاء الاصطناعي هي الملف.
“ألن يكون هناك عدد كبير جداً من الملفات؟” — للبشر، نعم. لكن إزعاج البشر هو مشكلة طبقة العرض (تُحل بإضافات IDE مثل VSCode). هيكل filefunc لا يتنازل ليناسب عادات التصفح البشرية.
يتغير مسار التنقل
التقليدي
طلب المستخدم
→ لا نعرف ماذا يوجد، ls، find
→ فتح ملفات لفهم الهيكل
→ grep مرة أخرى للعثور على ملفات ذات صلة
→ فتح ملف، 20 func، معظمها غير ذات صلة
→ تكلفة التنقل > وقت العمل الفعلي
مع filefunc
طلب المستخدم + توفير codebook
→ بناء استعلام grep فوراً من codebook
→ read 20-30 ملفاً (كل واحد مفهوم واحد، كلها سياق صالح)
→ العمل
قراءة 30 ملفاً ليست مشكلة إذا كانت جميعها سياقاً صالحاً. المشكلة هي قراءة ملف واحد والحصول على ضوضاء بحجم 30 ملفاً.
الـ Codebook
يحتل codebook المكانة الأهم في تصميم filefunc. يأتي قبل قواعد التعليقات التوضيحية. codebook مصمم جيداً يجعل استعلامات grep دقيقة؛ grep دقيق يجعل قائمة read نظيفة.
# codebook.yaml
required:
feature: [validate, annotate, chain, parse, codebook, report, cli]
type: [command, rule, parser, walker, model, formatter, loader, util]
optional:
pattern: [error-collection, file-visitor, rule-registry]
level: [error, warning, info]
مفاتيح required يجب أن تكون موجودة في كل تعليق //ff:func و //ff:type — لا فجوات مسموحة، لضمان موثوقية grep. مفاتيح optional تُستخدم فقط عند الحاجة.
codebook هو خريطة المشروع لوكلاء الذكاء الاصطناعي. بدونه، يبدأ الوكيل التنقل دون معرفة المفردات. معه، يمكن للوكيل إصدار استعلامات دقيقة فوراً مثل feature=validate أو type=rule دون استكشاف مسبق.
استخدام قيمة في تعليق غير موجودة في codebook هو ERROR. تطبيع المفردات عبر codebook يكشف features مفقودة، types مكررة، وتصنيفات غامضة. الثغرات يجب أن تكون مرئية لإدارتها. codebook نفسه يخضع للتحقق أيضاً — مفتاح واحد على الأقل في required، لا قيم مكررة، أحرف صغيرة وشرطات فقط.
تعليقات البيانات الوصفية
كل ملف يبدأ بتعليقات في الأعلى، بحيث يمكن تحليل البيانات الوصفية من الأسطر الأولى دون قراءة الجسم بالكامل.
//ff:func feature=validate type=rule control=sequence
//ff:what F1: validates one func per file
//ff:why Primary citizen is AI agent. 1 file 1 concept prevents context pollution.
//ff:checked llm=gpt-oss:20b hash=a3f8c1d2
func CheckOneFileOneFunc(gf *model.GoFile) []model.Violation {
| التعليق | المحتوى | مطلوب |
|---|---|---|
//ff:func | بيانات feature، type، control لملفات func | مطلوب لملفات func |
//ff:type | بيانات feature، type لملفات type | مطلوب لملفات type |
//ff:what | وصف سطر واحد — ماذا تفعل هذه الدالة/النوع | مطلوب |
//ff:why | لماذا بُنيت بهذه الطريقة — المنطق وراء القرار | اختياري |
//ff:checked | توقيع التحقق LLM (يُولَّد تلقائياً بواسطة llmc) | تلقائي |
الصيغة هي //ff:key key1=value1 key2=value2. قابل للبحث فوراً بـ grep/ripgrep، وقابل للتحليل بواسطة الأدوات كأزواج مفتاح-قيمة مهيكلة. يتبع نفس نمط توجيهات Go //go:generate و //go:embed.
control — 1 func 1 control
control= مطلوب لكل ملف func. القيمة واحدة من ثلاث:
| control | المعنى | حد العمق |
|---|---|---|
sequence | تنفيذ تسلسلي | 2 |
selection | تفرع (switch) | 2 |
iteration | حلقة | dimension + 1 |
مبني على نظرية Bohm-Jacopini (1966): كل برنامج هو مزيج من sequence، selection، وiteration. filefunc يفرض هذا على مستوى الدالة — دالة واحدة، تدفق تحكم واحد.
الدوال مع control=iteration تتطلب أيضاً dimension=. يحدد بُعد البيانات المُتكررة. dimension=1 يعني قائمة مسطحة (depth ≤ 2)؛ dimension ≥ 2 يتطلب تعشيش نوع مسمى (struct/interface).
filefunc يتحقق أيضاً من تطابق تعليق control مع الكود الفعلي. إذا كان control=selection بدون switch، أو control=sequence يحتوي switch أو loop، فهو ERROR.
خط أنابيب تنقل LLM
التعليقات تعمل كفهرس بحث — لا حاجة لبنية تحتية ثقيلة مثل تضمينات المتجهات.
1. تقليص هيكلي (لا حاجة لـ LLM، فقط grep)
بناء استعلام grep بناءً على codebook
→ استخراج 20-30 ملفاً مرشحاً
2. تصفية بالبيانات الوصفية (بدون LLM، أو نموذج صغير جداً)
قراءة تعليق الأعلى فقط لكل ملف
→ تضييق إلى 5-10 عبر name/input/output/what
3. عمل دقيق (LLM كبير، سياق أدنى)
قراءة كاملة لـ 5-10 ملفات فقط
→ تعديل أو توليد كود
السياق يتقلص في كل مرحلة. عندما يُشرك LLM الكبير، لا يتبقى سوى الملفات الضرورية حقاً.
CLI
validate — التحقق من قواعد هيكل الكود
filefunc validate # الدليل الحالي
filefunc validate /path/to/project # جذر المشروع صراحة
filefunc validate --format json
يتطلب go.mod و codebook.yaml في جذر المشروع. للقراءة فقط. يخرج بكود 1 عند المخالفة.
chain — تتبع علاقات الاستدعاء
filefunc chain func RunAll # الدرجة الأولى (افتراضي)
filefunc chain func RunAll --chon 2 # الدرجة الثانية (يشمل الدوال المستدعاة معاً)
filefunc chain func RunAll --chon 3 # الدرجة الثالثة (الحد الأقصى)
filefunc chain func RunAll --child-depth 3 # الاستدعاءات الفرعية فقط
filefunc chain func RunAll --parent-depth 3 # المستدعون الأصليون فقط
filefunc chain feature validate # كامل الـ feature
تحليل AST في الوقت الفعلي. --chon هي مسافة العلاقة. الدرجة الأولى هي المستدعي/المستدعى المباشر؛ الدرجة الثانية تشمل الدوال المستدعاة معاً.
go callgraph الحالي يجري تحليلاً ثابتاً كاملاً وينتج آلاف العقد. chain يتتبع فقط ضمن نفس الـ feature. feature الـ codebook هو مستوى التكبير.
llmc — التحقق بـ LLM
filefunc llmc # الدليل الحالي
filefunc llmc --model qwen3:8b
filefunc llmc --threshold 0.9
يتحقق من تطابق //ff:what مع جسم الدالة باستخدام LLM محلي (ollama). درجات من 0.0 إلى 1.0، العتبة الافتراضية 0.8. عند النجاح، يُكتب //ff:checked llm=<النموذج> hash=<الهاش> تلقائياً. إذا تغير الجسم، يتغير الهاش — يُطلب إعادة التحقق.
يعالج مشكلة انجراف التعليقات الأساسية — //ff:what لغة طبيعية ولا يمكن التحقق منها آلياً — باستخدام LLM صغير. قيد 1 file 1 func يضمن مطابقة 1:1 على مستوى الملف، مما يجعل هذا النهج ممكناً.
القواعد
قواعد هيكل الملفات
| القاعدة | عند المخالفة |
|---|---|
| func واحدة لكل ملف (اسم الملف = اسم الدالة) | ERROR |
| type واحد لكل ملف (اسم الملف = اسم النوع) | ERROR |
| الطرق: ملف واحد طريقة واحدة | ERROR |
init() لا يمكن أن تكون وحدها (يجب أن تكون مع var أو func) | ERROR |
ملفات _test.go يمكن أن تحتوي على عدة funcs | استثناء |
| مجموعات const المتماسكة دلالياً يمكن أن تتشارك ملفاً | استثناء |
قواعد جودة الكود
| القاعدة | عند المخالفة |
|---|---|
| عمق التعشيش: sequence=2، selection=2، iteration=dimension+1 | ERROR |
| حد أقصى 1000 سطر لكل func | ERROR |
| موصى به: sequence/iteration 100 سطر، selection 300 سطر | WARNING |
حدود عمق التعشيش تختلف حسب نوع control. sequence وselection: عمق 2. iteration: dimension + 1 — dimension=1 (قائمة مسطحة) يعني عمق 2، dimension=2 (هيكل متعشش) يعني عمق 3. بالاقتران مع نمط early return في Go، معظم الكود يتسع بشكل مريح ضمن هذه الحدود.
selection (switch) يميل إلى cases أطول، لذا عدد الأسطر الموصى به هو 300.
.ffignore
ضع ملف .ffignore في جذر المشروع لاستبعاد المسارات من جميع أوامر filefunc. يستخدم نفس بناء جملة .gitignore.
vendor/
*.pb.go
*_gen.go
internal/legacy/
لاستبعاد الكود المولَّد (protobuf، مخرجات codegen) أو كود vendor الخارجي حيث لا يمكن فرض قواعد filefunc بشكل معقول.
التكامل مع whyso
لأن func = file، سجل تغييرات الدالة يُطابق بدقة سجل تغييرات ملفها.
whyso history check_ssac_openapi.go # سجل تغييرات دالة CheckSSaCOpenAPI
عندما يحتوي ملف على عدة دوال، يجب البحث في diffs لمعرفة أي دالة تغيرت. مع filefunc، تغيير الملف = تغيير الدالة. تكلفة تتبع صفرية.
كشف الاقتران الضمني
whyso coupling check_ssac_openapi.go
دوال عُدلت معاً في نفس الطلب:
check_response_fields.go 8 مرات
check_err_status.go 5 مرات
types.go 4 مرات
إذا استمرت دالتان في الظهور معاً في إحصائيات الاقتران رغم عدم وجود علاقة صريحة، فهذه إشارة تبعية مخفية. قد تكونان تنفذان نفس قاعدة العمل من زوايا مختلفة، أو تتطابقان ضمنياً في الصيغ بدون interface، أو تتعطلان دائماً معاً.
لماذا Go فقط
هيكل filefunc لا يُترجم بسهولة إلى لغات أخرى. gofmt يفرض تنسيق الكود، early return هو النمط المتعارف عليه، لا توجد استثناءات، والحزمة = الدليل. التوسع إلى لغات أخرى يتطلب استراتيجية فرض هيكلية بمستوى gofmt. هذا خارج نطاق filefunc.
حالات الاستخدام المستهدفة محددة أيضاً: خدمات الواجهة الخلفية، أدوات CLI، مولدات الكود، مدققات SSOT. مكتبات الخوارزميات، برمجة الأنظمة المنخفضة المستوى، والمسارات الحرجة للأداء ليست مستهدفة.
ملخص
في عصر LLM، يجب تحسين هيكل الكود لكفاءة تنقل الذكاء الاصطناعي، لا لراحة التصفح البشري. filefunc هو الخطوة الأولى في هذا التحول.
ملف واحد، مفهوم واحد. تطبيع المفردات بالـ codebook، إرفاق البيانات الوصفية بالتعليقات، العثور على الملف الدقيق بـ grep واحد. لا يأتي كود غير ضروري عند قراءة ملف. تلوث السياق يُحظر على المستوى الهيكلي.
الكود: github.com/park-jun-woo/filefunc
المراجع
- Nelson F. Liu, Kevin Lin, John Hewitt, Ashwin Paranjape, Michele Bevilacqua, Fabio Petroni, Percy Liang (2024). “Lost in the Middle: How Language Models Use Long Contexts.” Transactions of the Association for Computational Linguistics, vol. 12. Link
- Yufeng Du, Minyang Tian et al. (2025). “Context Length Alone Hurts LLM Performance Despite Perfect Retrieval.” Findings of EMNLP 2025. Link
- Minglai Yang, Ethan Huang, Liang Zhang, Mihai Surdeanu, William Yang Wang, Liangming Pan (2025). “How Is LLM Reasoning Distracted by Irrelevant Context?” EMNLP 2025 Main Conference. Link
- Uswat Yusuf, Genevieve Caumartin, Diego Elias Costa (2025). “Beyond More Context: How Granularity and Order Drive Code Completion Quality.” ASE 2025. Link
- Weili Cao, Xunjian Yin, Bhuwan Dhingra, Shuyan Zhou (2026). “Coding Agents are Effective Long-Context Processors.” arXiv preprint. Link
- Han Li, Letian Zhu, Bohan Zhang et al. (2026). “ContextBench: A Benchmark for Context Retrieval in Coding Agents.” arXiv preprint. Link
- Kishan Maharaj et al. (2026). “Robustness and Reasoning Fidelity of Large Language Models in Long-Context Code Question Answering.” arXiv preprint. Link
- Carlos E. Jimenez, John Yang, Alexander Wettig, Shunyu Yao, Kexin Pei, Ofir Press, Karthik R. Narasimhan (2024). “SWE-bench: Can Language Models Resolve Real-World GitHub Issues?” ICLR 2024 (Oral). Link
- Corrado Bohm, Giuseppe Jacopini (1966). “Flow Diagrams, Turing Machines, and Languages with Only Two Formation Rules.” Communications of the ACM, vol. 9, no. 5. Link
- David L. Parnas (1972). “On the Criteria to Be Used in Decomposing Systems into Modules.” Communications of the ACM, vol. 15, no. 12. Link
مقال ذو صلة: Ratchet Pattern — كيف تجعل الوكيل ينهي المهمة — النمط وراء filefunc. تنفيذ أحادي الاتجاه قائم على Verifier.
مقال ذو صلة: ذكاء النموذج أقل أهمية من طوبولوجيا التغذية الراجعة — لماذا هيكل التغذية الراجعة يحدد النتائج أكثر من أداء النموذج.
سجل التغييرات
- 2026-03-16: الإصدار الأول