جستجوی متنی سنتی یا استفاده از شباهت کسینوسی ساده روی قطعههای متنی کد، در پروژههای بزرگ نرمافزاری کارایی ندارد. وقتی کدهای تکراری، کدهای تولیدشده با هوش مصنوعی و معماریهای چندریپازیتوری در میان باشند، حتی بزرگترین پنجرههای بافتار مدلهای زبانی هم نمیتوانند بدون یک سیستم بازیابی دقیق و رتبهبندیشده، پاسخهای مستند و قابل اتکا ارائه دهند.
در این پروژه نهایی، یک سامانهی کامل RAG روی کدبیس پیاده میکنید که کد را با ابزار Tree-sitter در مرز توابع و کلاسها قطعهبندی میکند، با جستجوی ترکیبی متراکم و پراکنده (BM25) دادهها را واکشی مینماید و با گراف نمادها و بازرتبهبندی کراسانکودر، پاسخی مستند به شماره خطوط تحویل میدهد. همچنین این سیستم با هر تغییر در Git، فرایند ایندکس مجدد را بهشکل افزایشی و سریع مدیریت میکند.
برای اجرای بخشهای مختلف این پروژه، به ابزارهایی مانند Qdrant و مدلهای زبانی خارجی یا محلی نیاز است. توجه داشته باشید که دسترسی به سرویسهای ارائهدهندهی API خارجی (مانند OpenAI یا ارائهدهندگان ابری) و پرداخت مستقیم ارزی برای آنها از داخل ایران با چالشهایی همراه است؛ با این حال، میتوانید در بخشهای مختلف از مدلهای متنباز خودمیزبان مانند nomic-embed-code روی زیرساخت محلی یا گیتویهای ارائهدهندهی API سازگار استفاده کنید.
در سال 2026، هر سازمان مهندسی جدی یک سیستم جستجوی کد داخلی اجرا میکند که معنا را میفهمد، نه صرفاً رشتههای متنی را. سیستم Amp در Sourcegraph، پاسخهای کدبیس در Cursor، گراف سازمانی Augment، ابزار repomap در Aider و MCP داخلی Pinterest همگی ساختار یکسانی دارند: ریپازیتوریهای متعددی را میخوانند، با tree-sitter آنها را پارس میکنند، قطعههای متنی را در سطح تابع و کلاس امبد میکنند، جستجوی ترکیبی (hybrid search) انجام میدهند، بازرتبهبندی میکنند و در نهایت با ارجاع دقیق به کد پاسخ میدهند. در این پروژه نهایی باید سیستمی بسازید که از پسِ 2 میلیون خط کد در 10 ریپازیتوری بربیاید و با هر بار git push، فرایند نمایهسازی مجدد افزایشی (incremental re-indexing) را بدون مشکل تاب بیاورد.
فازهای تمرینشده: P5 · P7 · P11 · P13 · P17
زمان: 30 ساعت
مسئله
تا سال 2026، هر ایجنت (Agent) برنامهنویسی پیشرو همراه با یک لایهی بازیابی از کدبیس عرضه میشود؛ چرا که پنجرهی بافتار (Context Window) بهتنهایی مسائل بین چند ریپازیتوری را حل نمیکند. پنجرهی بافتار 1 میلیون توکنی Claude کمککننده است، اما نیاز به بازیابی رتبهبندیشده را از بین نمیبرد. جستجوی سادهی کسینوسی روی قطعههای خام متنی، نتایج را در مواجهه با کدهای تولیدشده توسط مدل، کدهای تکراری در مونوریپوها و کدهای کماستفاده در دنبالهی طولانی نمادها خراب میکند. راهکار محیط عملیاتی (پروداکشن)، جستجوی ترکیبی (امبدینگ متراکم + BM25) روی قطعههای متنی آگاه به AST بههمراه یک بازرتبهبند (re-ranker) است که گرافی از ارجاعات نمادها پشتیبان آن باشد.
شما این فرایند را با ایندکس کردن یک ناوگان واقعی از کدها — نه یک ریپازیتوری آموزشی و تستی — و سنجش معیارهای MRR@10، وفاداری (Faithfulness) به ارجاعات و تازگی افزایشی یاد میگیرید. حالتهای شکست (Failure modes) ماهیت زیرساختی دارند: یک مونوریپو با 100 هزار فایل، یک push که نیمی از فایلها را دستکاری میکند و پرسشی که برای رسیدن به پاسخ درست باید از دلِ چهار ریپازیتوری مختلف عبور کند.
مبانی مفهومی
یک پایپلاین (Pipeline) ورودیِ آگاه به AST هر فایل را با tree-sitter پارس میکند، گرههای تابع و کلاس را بیرون میکشد و قطعهبندی متن (Chunking) را بهجای پنجرههای توکنی ثابت، در مرز گرهها انجام میدهد. هر قطعه سه بازنمایی دریافت میکند: یک امبدینگ متراکم (Dense embedding) با Voyage-code-3 یا nomic-embed-code، اصطلاحات پراکندهی BM25 و یک خلاصهی کوتاه به زبان طبیعی. این خلاصه، مودالیتی سومی برای بازیابی اضافه میکند؛ برای نمونه، کاربر میپرسد «X چطور مجوز میگیرد؟» و خلاصه واژهی «authz» را ذکر میکند، حتی اگر داخل کد فقط check_permission آمده باشد.
بازیابی بهصورت ترکیبی است. هر پرسش همزمان جستجوی متراکم و BM25 را فعال میکند، k نتیجهی برتر را ادغام کرده و اجتماع آنها را به یک بازرتبهبند کراسانکودر (Cross-encoder مانند Cohere rerank-3 یا bge-reranker-v2-gemma-2b) میسپارد. فهرست بازرتبهبندیشده به یک مدل سنتزکنندهی با بافتار طولانی (Claude Sonnet 4.7 با کش کردن پرامپت یا نسخهی خودمیزبان Llama 3.3 70B) فرستاده میشود و سیستم به آن دستور میدهد به ازای هر ادعا، به نام فایل و بازهی خطوط ارجاع دهد. پاسخهای بدون ارجاع توسط یک پسفیلتر رد میشوند.
تازگی دادهها در سطح زیرساخت، چالش اصلی است. دستور Git push یک diff میگیرد: کدام فایلها و کدام نمادها تغییر کردهاند؟ فقط برای قطعههای متنی متأثر، دوباره امبدینگ تولید میشود. یالهای بینفایلی نمادها که دچار تغییر شدهاند (ایمپورتها، فراخوانی متدها) دوباره محاسبه میشوند. بدین ترتیب ایندکس بدون پردازش دوبارهی 2 میلیون خط کد در هر commit، پایدار و بهروز میماند.
معماری
git push --> webhook --> ingest worker (LlamaIndex Workflow)
|
v
tree-sitter parse + AST chunk
|
+--------------+----------------+
v v v
dense BM25 index summary (LLM)
(Voyage / bge) (Tantivy) (Haiku 4.5)
| | |
+------> Qdrant / pgvector <----+
|
v
symbol graph (Neo4j / kuzu)
|
query --> LangGraph agent (retrieve -> rerank -> synth)
|
v
Claude Sonnet 4.7 1M context
|
v
answer + file:line citations
استک فنی
- پارس کردن: tree-sitter با گرامر 17 زبان برنامهنویسی (Python، TS، Rust، Go، Java، C++ و غیره)
- امبدینگهای متراکم: Voyage-code-3 (سرویس ابری) یا nomic-embed-code-v1.5 (خودمیزبان)، با bge-code-v1 بهعنوان طرح پشتیبان (Fallback)
- ایندکس پراکنده: Tantivy (زبان Rust) بههمراه BM25F با وزندهی فیلدی روی نام نماد در برابر بدنهی آن
- پایگاه دادهی برداری: Qdrant 1.12 با جستجوی ترکیبی، یا ترکیب pgvector + pgvectorscale برای تیمهای با کمتر از 50 میلیون بردار
- مدل خلاصهسازی قطعهها: Claude Haiku 4.5 یا Gemini 2.5 Flash با کش کردن پرامپت
- بازرتبهبند: Cohere rerank-3 یا نسخهی خودمیزبان bge-reranker-v2-gemma-2b
- ارکستراسیون (Orchestration): جریانهای کاری LlamaIndex Workflows برای دریافت داده، LangGraph برای ایجنت پرسوجو
- سنتزکننده: Claude Sonnet 4.7 (با بافتار 1 میلیون توکن) بههمراه کش کردن پرامپت
- گراف نمادها: Neo4j (مدیریتشده) یا kuzu (درونبرنامهای) برای یالهای ایمپورت و فراخوانی
- رصدپذیری: اسپنهای (Spans) ابزار Langfuse برای هر مرحلهی بازیابی و سنتز
پیادهسازی گامبهگام
-
پیمایشگر ورودی (Ingestion walker): تاریخچهی git را در هر push hook پیمایش کنید. فایلهای تغییریافته را گردآوری کنید. برای هر فایل، آن را با tree-sitter پارس کرده و گرههای کلاس و تابع را همراه با اسپن کامل سورسکد استخراج کنید. رکوردهای قطعهها را با فرمت
{repo, path, start_line, end_line, symbol, body}بسازید. -
خلاصهساز قطعهها: قطعهها را برای فراخوانی Haiku 4.5 با قابلیت کش کردن پرامپت روی متن اولیهی سیستم (system preamble) دستهبندی کنید. پرامپت: «این تابع را در یک جمله خلاصه کنید و قرارداد عمومی (public contract) و اثرات جانبی آن را نام ببرید.» خلاصه را کنار قطعه ذخیره کنید.
-
استخر امبدینگ: دو صف موازی بسازید: متراکم (Voyage-code-3 با دستههای 128 تایی) و خلاصه (همان مدل، ولی روی رشتهی متنی خلاصه). بردارها را با دادههای پیوست
{repo, path, start_line, end_line, symbol, kind}در Qdrant بنویسید. -
ایندکس BM25: یک ایندکس Tantivy با وزندهی فیلدی راهاندازی کنید: وزن نام نماد 4، وزن بدنهی نماد 1 و وزن خلاصه 2. این کار پاسخ به پرسشهای «پیدا کردن تابع با نام X» را در کنار «پیدا کردن تابعی که کار X را انجام میدهد» ممکن میکند.
-
گراف نمادها: برای هر قطعه، یالها را ثبت کنید: ایمپورتها (این فایل از نماد Y در ریپازیتوری Z استفاده میکند)، فراخوانیها (این تابع متد M از کلاس C را صدا میزند)، وراثت. دادهها را در kuzu ذخیره کنید. از این گراف هنگام پرسوجو برای گسترش دامنهی بازیابی در سراسر ریپازیتوریها استفاده میشود.
-
ایجنت پرسوجو: یک گراف LangGraph با سه گره بسازید. گره
retrieveجستجوی متراکم و BM25 را موازی اجرا کرده و بر اساس (repo, path, symbol) موارد تکراری را حذف میکند. گرهrerankکراسانکودر را روی 50 مورد برتر اجرا کرده و 10 تای اول را نگه میدارد. گرهsynthمدل Claude Sonnet 4.7 را با قطعههای بازرتبهبندیشده در بافتار فراخوانی میکند، پرامپت سیستم را کش میکند و ارجاع با فرمت file:line را اجباری میسازد. -
اعمال سختگیرانهی ارجاعدهی: خروجی مدل را اعتبارسنجی کنید؛ هر ادعایی که فاقد نشانگر ارجاع
(repo/path:start-end)باشد برای پرسش دوباره علامتگذاری شده یا حذف میشود. فقط پاسخی را که مستند به ارجاع است به کاربر تحویل دهید. -
ایندکس مجدد افزایشی: در هر وبهوک، diff را در سطح نماد محاسبه کنید. فقط قطعههایی را دوباره امبد کنید که متن آنها تغییر کرده است. یالهای نمادها را برای قطعههایی که ایمپورتهایشان عوض شده دوباره محاسبه کنید. معیار سنجش: ایندکس مجدد یک push شامل 50 فایل در کمتر از 60 ثانیه برای کدی با مجموع 2 میلیون خط.
-
ارزیابی: 100 پرسش بینریپازیتوری را همراه با ارجاعات دقیق طلایی (file:line) برچسبگذاری کنید. معیارهای MRR@10، nDCG@10، وفاداری به ارجاعات (نسبت ادعاهای دارای ارجاع قابل بررسی) و تاخیر در چارکهای p50 و p99 را اندازه بگیرید.
استفاده از سیستم
$ code-rag ask "how is S3 multipart abort wired into our retry budget?"
[retrieve] 12 chunks dense + 7 chunks bm25, 16 unique after dedup
[rerank] top-5 kept (cohere rerank-3)
[synth] claude-sonnet-4.7, cache hit rate 68%, 2.1s
answer:
Multipart aborts are triggered by `AbortMultipartOnFail` in
services/uploader/retry.go:122-148, which decrements the per-bucket
retry budget defined in config/budgets.yaml:34-51 ...
citations: [services/uploader/retry.go:122-148, config/budgets.yaml:34-51,
libs/s3client/multipart.ts:44-61]
خروجی پروژه
مهارت قابلتحویل در قالب فایل outputs/skill-codebase-rag.md. این سیستم با دریافت مجموعهای از ریپازیتوریها، پایپلاین ورودی، ایندکس ترکیبی و ایجنت پرسوجو را برپا میکند و برای هر پرسش بینریپازیتوری، پاسخی مستند به ارجاع برمیگرداند. شیوهنامهی نمرهدهی (Rubric):
| وزن | معیار | شیوهی سنجش |
|---|---|---|
| 25 | کیفیت بازیابی | MRR@10 و nDCG@10 روی یک مجموعهی ارزیابی مستقل 100 سوالی |
| 20 | وفاداری به ارجاعات | نسبت ادعاهای داخل پاسخ که ارجاع معتبر و قابل بررسی به file:line دارند |
| 20 | تاخیر و مقیاسپذیری | تاخیر p95 پرسوجو تحت بار 10k پرسش در ثانیه (QPS) روی کل دادههای ایندکسشده |
| 20 | صحت ایندکسگذاری افزایشی | زمان سپریشده از git push تا لحظهی قابلجستجو شدن برای یک commit شامل 50 فایل |
| 15 | رابط کاربری و ساختار پاسخ | قابلیت کلیک روی ارجاعات، پیشنمایش تکهکدها، امکان پرسشهای ادامهدار |
| 100 |
تمرینها
-
مدل Voyage-code-3 را با نسخهی خودمیزبان nomic-embed-code جایگزین کنید. اختلاف MRR@10 را اندازه بگیرید. گزارش دهید که آیا فعال کردن بازرتبهبندی، این اختلاف را جبران میکند یا خیر.
-
حدود 20% کد تولیدشده توسط هوش مصنوعی (boilerplate تولیدی LLM) به مجموعهی کدها اضافه کرده و دوباره ارزیابی کنید. خراب شدن نتایج بازیابی را مشاهده کنید. یک فلگ «generated» به متادیتای قطعهها بیفزایید و وزن این نتایج را کاهش دهید.
-
کارایی جستجوی ترکیبی Qdrant را در مقایسه با pgvector + pgvectorscale روی ابعاد دیتای خود بنچمارک کنید. تاخیر p99 را در اندازهی دستهی 1 گزارش دهید.
-
یک بررسی رانش (drift) مبتنی بر نمونهگیری اضافه کنید: هر هفته ارزیابی 100 سوالی را تکرار کنید. در صورت افت MRR@10 به بیش از 5%، هشدار ارسال کنید.
-
سیستم را برای تفکیک نمادهای چندزبانه توسعه دهید: تابع پایتونی که یک سرویس Go را روی gRPC صدا میزند. از گراف نمادها برای اتصال آنها استفاده کنید.
اصطلاحات کلیدی
| اصطلاح | در گفتوگوها | معنای دقیق فنی |
|---|---|---|
| قطعهبندی متن آگاه به AST (AST-aware chunking) | «تفکیک در سطح تابع» | برش دادن کد در مرز گرههای tree-sitter بهجای پنجرههای توکنی ثابت |
| جستجوی ترکیبی (Hybrid search) | «متراکم + پراکنده» | اجرای موازی BM25 و جستجوی برداری، ادغام k نتیجهی برتر و بازرتبهبندی نهایی |
| بازرتبهبندی با کراسانکودر (Cross-encoder rerank) | «رتبهبندی مرحلهی دوم» | مدلی که هر جفت (پرسش، کاندیدا) را همزمان امتیازدهی میکند و دقیقتر از شباهت کسینوسی است |
| کش کردن پرامپت (Prompt caching) | «پرامپت سیستم کششده» | قابلیت مدلهای 2026 شرکتهای Claude و OpenAI که هزینهی توکنهای پیشوند تکراری را تا 90% کاهش میدهد |
| گراف نمادها (Symbol graph) | «گراف کد» | ثبت یالها برای روابط ایمپورت، فراخوانی و وراثت میان فایلها و ریپازیتوریهای مختلف |
| وفاداری به ارجاعات (Citation faithfulness) | «نرخ پاسخهای مستند» | نسبتی از ادعاها که کاربر میتواند با کلیک روی ارجاع و خواندن اسپنِ ارجاعشده درستی آنها را بررسی کند |
| ایندکس مجدد افزایشی (Incremental re-index) | «مدتزمان از push تا جستجو» | زمان واقعی سپریشده از لحظهی git push تا زمانی که نمادهای تغییریافته قابل جستجو شوند |
برای مطالعهی بیشتر
- Sourcegraph Amp — هوش کد چندریپازیتوری در محیط عملیاتی
- معماری Cody RAG در Sourcegraph — مرجع تحلیلی جامع برای این پروژه نهایی
- Aider repo-map — نمای رتبهبندیشدهی ریپازیتوری با tree-sitter
- گراف سازمانی Augment Code — سیستم تجاری RAG مبتنی بر گراف نمادها
- مستندات جستجوی ترکیبی Qdrant — پیادهسازی مرجع
- امبدینگهای کد در Voyage AI — جزییات مدل Voyage-code-3
- Cohere rerank-3 — مرجع کراسانکودر
- جستجوی پلتفرم داخلی Pinterest با MCP — مرجع پلتفرم داخلی سازمان
