وقتی یک ایجنت جواب را از خود مدل بسازد، هیچ نقطه‌ای برای شک کردن باقی نمی‌ماند. در agent-me مرحله‌ای به نام Critic بین جمع‌آوری شواهد و نوشتن جواب می‌نشیند و هر وقت بازیاب هیچ شاهدی برنگرداند، جلوی ساختن پاسخ را می‌گیرد. در این نوشته مخزن را نصب می‌کنیم، هر دو حالت را صدا می‌زنیم و عددها را از خروجی واقعی سرور می‌خوانیم.

ایجنت دوم یعنی چه: معماری به جای پرامپت

بیشتر چت‌بات‌های شخصی عملاً سه چیز هستند: یک پرامپت، یک پایگاه داده‌ی برداری، و یک رابط گفت‌وگو. این سه‌تا می‌توانند درباره‌ی یک نفر واقعیت‌های زندگی‌نامه‌ای را به یاد بیاورند، اما این با «نمایش دادن قابل اتکای یک شخص» فرق دارد. خود مخزن این تمایز را صریح می‌گذارد: به یاد آوردن واقعیت‌ها درباره‌ی یک شخص آسان است، ساختن سامانه‌ای که آن شخص را قابل اتکا نمایش دهد بسیار سخت‌تر است.[1]

پاسخ مخزن این است که یک ایجنت شخصی را نه به‌عنوان یک پرامپت، بلکه به‌عنوان یک سامانه ببینید. خط لوله‌ای که خودش تعریف می‌کند از حافظه‌ی قابل بازبینی شروع می‌شود. بعد به بازیابی می‌رسد، سپس برنامه‌ریزی، شواهد، نقد، راستی‌آزمایی، و در پایان پاسخ. همان چیزی که در README به شکل یک خط عمودی نوشته شده، در کد به چهار یا پنج مرحله‌ی ترتیبی تبدیل می‌شود که هرکدام قرارداد تایپ‌شده‌ی خودش را دارد.[2]

نقش‌ها و پیاده‌سازی فعلی هر کدام در مخزن
بخشنقشپیاده‌سازی فعلی
حافظه‌ی شخصیآنچه ایجنت می‌داندمارک‌داون بازبینی‌شونده تحت کنترل نسخه
بازیابیپیدا کردن شواهد شخصی پیش از پاسخبازیاب محلی و قطعی
Plannerتعیین رویکرد به پرسشطرح تایپ‌شده
Researcherجمع‌آوری شواهد طرحبرش دقیق متن مبدأ و فراداده
Criticبه چالش کشیدن ترکیب بی‌پشتوانهدروازه‌ی کفایت شواهد
Writerتولید پاسخ مستندخروجی آگاه به ارجاع
Verifierجلوگیری از عبور خروجی نامعتبربررسی اختیاری مسیر ارجاع و فراداده

تفاوت مهم دیگر این است که این مخزن ادعای «اثبات حقیقت» ندارد. خودش در یادداشت کنار معماری می‌نویسد که Verifier مسیرهای ارجاع و ناوردایی‌های پیاده‌شده‌ی خروجی را بررسی می‌کند، اما درستی معنایی را ثابت نمی‌کند. این محدودیت را نگه داشتن، خودش یک نوع شواهد است.[3]

نصب: چهار وابستگی و بدون کلید API

مخزن به پایتون ۳٫۱۱ به بالا نیاز دارد و فهرست وابستگی‌هایش کوتاه است. یعنی برای بالا آوردن هسته‌ی API هیچ سرویس بیرونی لازم نیست. حالت پیش‌فرض روی بازیابی استخراجی محلی کار می‌کند و در نتیجه به کلید مدل نیاز ندارد؛ اگر `/ready` شما `answer_mode` را به‌صورت `extractive` گزارش کند، یعنی همه‌چیز محلی است.[2] وابستگی‌ها دقیقاً چهار تا هستند: fastapi، httpx، pydantic-settings و uvicorn.

مسیر رسمی مخزن با Docker Compose است.[10] برای اینکه بتوانیم خروجی خام را ببینیم، همان هسته‌ی API را مستقیم با uvicorn بالا می‌آوریم و مسیر `backend` را به آن می‌دهیم. نتیجه‌ی یکسانی می‌گیرید اگر اول `.env.example` را کپی کنید و بعد این را اجرا کنید: docker compose up --build

git clone https://github.com/jzjzzzzzzz/agent-me.git
cd agent-me

# چهار وابستگی هسته؛ بدون کلید API و بدون سرویس بیرونی
python3 -m venv .venv
.venv/bin/pip install "fastapi>=0.115,<1" "httpx>=0.27,<1" \
    "pydantic-settings>=2.6,<3" "uvicorn[standard]>=0.32,<1"

.venv/bin/uvicorn app.main:app --app-dir backend --port 8021

اگر به‌جای venv از `uv` استفاده می‌کنید، خود مخزن دستور `make setup` را پیشنهاد می‌کند که هم محیط را می‌سازد و هم بسته‌های فرانت‌اند را نصب می‌کند. برای کار با API تنها، همان چهار بسته کافی است.

$ curl -s http://127.0.0.1:8021/health
{"status":"healthy"}

$ curl -s http://127.0.0.1:8021/ready
{"status":"ready","knowledge_documents":1,"answer_mode":"extractive"}

عدد `knowledge_documents` مهم است: یعنی سامانه دقیقاً یک سند دارد.[2] اگر این عدد را نمی‌بینید، بازیابی چیزی برای جست‌وجو ندارد و هر پرسشی به مسیر «شواهد ناکافی» می‌افتد. مخزن یک پیش‌پرش بی‌خطر هم دارد که فقط تعداد و مسیر نسبی سندها را گزارش می‌کند، نه محتوایشان را.

$ .venv/bin/python scripts/check_knowledge.py --knowledge-dir knowledge
Knowledge corpus is valid (1 documents).
- example-profile.md

خواندن خط لوله با دو فراخوانی واقعی

نقطه‌ی ورود، `POST /api/v1/collaborate` است که با یک فیلد `workflow` بین سیاست چهارمرحله‌ای و پنج‌مرحله‌ای انتخاب می‌کند. سیاست پایه Planner و Researcher و Critic و Writer را اجرا می‌کند، و سیاست راستی‌آزما این چهار مرحله را با یک Verifier پنجم کامل می‌کند.[3]

$ curl -s http://127.0.0.1:8021/api/v1/collaborate \
    -H 'Content-Type: application/json' \
    -d '{"question":"How does the example agent plan a project?","workflow":"verified"}'

پاسخ یک شیء JSON است.[4] مقدار `grounded` در آن `true` است، یعنی دروازه‌ی شواهد عبور کرده. نام سیاست هم در فیلد `workflow` برمی‌گردد و پنج نقش را به‌ترتیب نام می‌برد. مهم‌ترین بخش، آرایه‌ی `trace` است که نقش و نتیجه و معیارهای عددی هر مرحله را می‌دهد.

پنج مرحله‌ی اجرای واقعی، با معیارهای خوانده‌شده از خروجی
مرحلهنقشنتیجهمعیارها
۱plannercompletedtask_count: ۳ / query_term_count: ۸
۲researchercompletedevidence_count: ۱ / document_count: ۱
۳criticcompletedapproved: true / query_coverage: ۰٫۵
۴writercompletedanswer_chars: ۱۹۵ / citation_count: ۱
۵verifiercompletedcitation_paths_valid: true / expected: ۱ / reported: ۱

پاسخ نهایی دو بخش دارد: متن برش‌خورده‌ی سند، و یک سطر فهرست منابع. طول این پاسخ دقیقاً ۱۹۵ نویسه است.[4] معیار `answer_chars` همین عدد را گزارش می‌کند.

نکته‌ای که از این جدول بیرون می‌آید و در README به آن تصریح نشده: `query_coverage` معیارِ Critic است و ۰٫۵ درآمده، در حالی که پرسش بی‌نقص به نظر می‌رسد. این عدد دروازه نیست. در کد، دروازه فقط وجود دست‌کم یک شاهد است؛ پوشش پرسش صرفاً گزارش می‌شود.[7]

وقتی شواهد نباشد: آزمون منفی

یک سامانه‌ی «مبتنی بر شواهد» که فقط وقتی جواب دارد که شواهد پیدا شود، ارزش واقعی‌اش را در آزمون منفی نشان می‌دهد. پرسشی می‌پرسیم که در آن سند نمی‌تواند جوابی بدهد: اندازه‌ی توصیه‌شده‌ی استخر اتصال برای سرویس صورتحساب.

$ curl -s http://127.0.0.1:8021/api/v1/collaborate \
    -H 'Content-Type: application/json' \
    -d '{"question":"What is the recommended Postgres connection pool size for our billing service?","workflow":"verified"}'

grounded : false
sources  : 0
answer   : "I could not find a grounded answer in the configured knowledge files."

3 critic   blocked   | Blocked unsupported synthesis because no matching evidence was found.
4 writer   completed | Returned the insufficient-evidence response.

این تنها جایی است که مرز واقعی پروژه دیده می‌شود. سه مرحله‌ی اول باز هم کامل اجرا می‌شوند و ردیابی‌شان هست، اما `critic` نتیجه‌اش `blocked` می‌شود و نویسنده به‌جای پاسخ، یک جمله‌ی ثابتِ کمبود شواهد برمی‌گرداند. شمار ارجاع‌ها صفر است و Verifier انتظار صفر داشت، پس همان‌جا تأیید می‌شود.[7]

همان آزمون را می‌توان به‌صورت خودکار هم اجرا کرد.[9] ارزیاب مخزن چهار مورد را پوشش می‌دهد: دو پرسش پشتیبانی‌شده، یک دامنه‌ی پشتیبانی‌نشده، و یک مورد مرزی که کلمات مشترک دارد اما کاربردشان پشتیبانی نیست.[6]

$ .venv/bin/python scripts/evaluate_collaboration.py --workflow verified
case                            expected  actual  sources  critic    result
project-planning                True     True    1        completed  PASS
preferred-work                  True     True    1        completed  PASS
unsupported-domain              False    False   0        blocked    PASS
shared-terms-unsupported-use    False    False   0        blocked    PASS

COLLABORATION_EVAL 4/4 passed

عدد ۰٫۷۵ از کجا می‌آید

مهم‌ترین عدد این مخزن در یک ثابت خوانده می‌شود: کف پوشش پرسش برابر ۰٫۷۵ است. اگر نسبت هم‌پوشانی یک بند با پرسش کمتر از این عدد باشد، آن بند اصلاً به‌عنوان شاهد وارد نمی‌شود.[8]

بازیاب کلمه‌های ایست را فقط از پرسش حذف می‌کند، نه از متن بند. پرسش نمونه‌ی ما هشت نویسه‌ی نرمال‌شده دارد که چهارتایش ایست‌اند، پس چهار توکن باقی می‌ماند: agent، example، plan و project. از این چهار توکن، سه توکن در بند سند هست و یکی نیست. یعنی ۳ تقسیم بر ۴، که می‌شود ۰٫۷۵، و چون کف هم ۰٫۷۵ است، این بند نگه داشته می‌شود.[8]

# همان حساب، مستقیم از تابع خود مخزن
from app.knowledge import _query_tokens, _MIN_QUERY_COVERAGE
from app.text import normalized_tokens

paragraph = ("For project planning, the example agent starts with user goals, writes "
             "acceptance criteria, builds the smallest complete path, and verifies "
             "it with automated tests.")

q  = _query_tokens("How does the example agent plan a project?")
ov = q & normalized_tokens(paragraph)

print(sorted(q))        # ['agent', 'example', 'plan', 'project']
print(len(ov) / len(q))  # 0.75
print(_MIN_QUERY_COVERAGE)  # 0.75  -> بند نگه داشته می‌شود

همان فرمول روی پرسش دوم چه می‌شود؟ پرسش صورتحساب پس از حذف ایست‌ها هشت توکن باقی‌شده دارد و هیچ‌کدام در بند سند نیستند. نتیجه صفر است، یعنی بند کاملاً حذف می‌شود، `sources` خالی می‌ماند و همان `blocked` که در بخش قبل دیدیم رخ می‌دهد.

حساب پوشش برای هر دو پرسش، در کنار عدد گزارش‌شده
پرسشتوکن پرسشهم‌پوشانیامتیازنتیجه
برنامه‌ریزی پروژه۴۳۰٫۷۵نگه داشته شد
استخر اتصال صورتحساب۸۰۰٫۰۰حذف شد

این دقیقاً همان عددی است که سرور در آرایه‌ی `sources` گزارش کرد. پس آن ۰٫۷۵ یک ادعا نیست؛ از کد و از خروجی در دو جا می‌آید.

قبل از اینکه روی پروژه‌ی خودتان بگذارید

مخزن صریح می‌گوید که محتوای نمونه‌ی عمومی خیالی است و هر مالک باید دانش واقعی خودش را در فضای کاری خصوصی جدا نگه دارد. یعنی سندی که در بالا دیدیم، الگوست نه داده‌ی شما.[2]

سه محدودیت را جدی بگیرید. نخست، بازیاب این مخزن برداری نیست؛ هم‌پوشانی واژگانی حساب می‌کند، پس هر پرسشی که واژه‌ی مشترک نداشته باشد از دست می‌رود. دوم، Verifier درستی معنایی را ثابت نمی‌کند و خود مخزن این را می‌گوید.[5] سوم، مسیر دوم می‌تواند پرسش و تاریخچه‌ی گفت‌وگو و زمینه‌ی بازیابی‌شده را به یک نقطه‌ی سازگار با OpenAI بفرستد. پیش از افزودن دانش خصوصی، سند اعتماد را بخوانید.[5]

پس روش استفاده روشن است: ساختار پنج‌مرحله‌ای و آزمون منفیِ آن ارزش اصلی این مخزن است. برای کاری که در بودجه‌ی کانتکست: سه جایی که پول ایجنت خرج می‌شود گفتیم، همین دروازه‌ی شواهد یکی از سه سرفصل است، و اینجا به‌جای توضیح نظری، در کد پیاده شده و قابل اندازه‌گیری است. اگر هم پیش از این پیاده‌سازی لایه‌ی مجوز را جدا نگه داشته‌اید، آن بحث در لایه‌ی مجوز ایجنت به همان شکل جدا می‌ماند.

منابع

  1. مخزن jzjzzzzzzz/agent-me روی گیت‌هاب
  2. فایل README مخزن، معماری و مسیرهای نصب
  3. سند معماری و قراردادهای مرحله‌ای
  4. مرجع API و طرح‌واره‌ی نقاط پایانی
  5. سند اعتماد، جریان داده و مرزهای استقرار
  6. موردهای ارزیابی همکاری، شامل مورد مرزی
  7. کد نقش‌ها: Planner، Researcher، Critic، Writer و Verifier
  8. کد بازیاب و ثابت کف پوشش ۰٫۷۵
  9. اسکریپت ارزیاب همکاری
  10. فایل Makefile مخزن و دستورهای راه‌اندازی