۱. مقدمه

شما به دره ماموران رسیدهاید. یک منطقه باز است: بیشه احضار. در پایان این آزمایشگاه، موجودی به طراحی خودتان در آنجا زندگی میکند و دقیقاً خواهید دانست که کدام قسمت دستگاه آن را ساخته است.

این موچی است. چهار کلمه آن را ساخته است - "چیزی دنج که باران را دوست دارد".
یک عامل از چند قطعه کوچک تشکیل شده است، به علاوه سیمکشی بین آنها. هر فصل در اینجا یک قطعه اضافه میکند و سپس سیمکشی را به شما نشان میدهد.
فصل | قطعهای که اضافه میکنید | سیم |
۱ | یک مدل با دستورالعمل | هنوز هیچ کدام — فقط میتواند صحبت کند |
۲ | یک ابزار | مدل → ابزار |
۴ | یک ابزار دوم | ابزار → عامل · یک فرهنگ لغت مشترک |
۵ | یک تماس برگشتی | شما → سیم · دستتان را داخل ببرید و آن را عوض کنید |
بخش سخت هر چارچوب عاملی این نیست که «عامل چیست». بخش سخت این است که دادهها کجا نگهداری میشوند و چگونه به مورد بعدی میرسند. این آزمایشگاه سه بار این را میپرسد و سه بار به آن پاسخ میدهد.
فصل ۳ عمداً در آن جدول نیست. به محض اینکه اولین ابزار شما کار کرد، کد را زمین میگذارید و به مدت پنج دقیقه در دره تمام شده بازی میکنید. با دو سوال برمیگردید و فصلهای ۴ و ۵ پاسخها هستند.
شما دو ویرایش انجام خواهید داد. هر دو یک خط هستند. این تمام تایپ در این آزمایشگاه است - هر چیز دیگری که میخوانید، اجرا میکنید و تماشا میکنید.
اینجا همه چیز ADK 2 است.
آنچه نیاز دارید: یک حساب گوگل با قابلیت پرداخت و یک مرورگر. شما به یک پروژه گوگل کلود از قبل نیاز ندارید - Setup یک پروژه ایجاد میکند. همه چیز در Cloud Shell اجرا میشود - پایتون، uv و gcloud از قبل در آنجا نصب شدهاند و Gemini از طریق Vertex AI با اعتبارنامههای شما قابل دسترسی است. هیچ کلید API در هیچ کجای این آزمایشگاه وجود ندارد.
۲. راهاندازی
همه چیز در این آزمایشگاه در Cloud Shell اجرا میشود - پایتون، uv و gcloud از قبل در آنجا نصب شدهاند و Gemini از طریق Vertex AI با استفاده از اعتبارنامههای شخصی شما قابل دسترسی است. هیچ کلید API در هیچ کجای این آزمایشگاه وجود ندارد و هیچ چیزی برای نصب روی لپتاپ شما وجود ندارد.
یک چیز هست که این آزمایشگاه نمیتواند به شما بدهد: یک پروژه گوگل کلود به همراه صورتحساب. مرحله ۱ حسابی برای شما ایجاد میکند که میتوانید هزینه آن را پرداخت کنید؛ مرحله ۴ آن حساب را به یک پروژه تبدیل میکند. آنها را به ترتیب انجام دهید - هر مرحله بعد از مرحله ۴، پروژهای را که مرحله ۴ ایجاد میکند، میخواند.
۱ · یک حساب کاربری با قابلیت پرداخت دریافت کنید (تقریباً ۱ دقیقه)
🌐 قبل از هر کاری این کار را انجام دهید. با یک حساب گوگل که قابلیت پرداخت صورتحساب در آن فعال است، وارد شوید. هر حسابی از این نوع کار میکند. اگر حساب شما فعال نیست، یک دوره آزمایشی رایگان را شروع کنید؛ این کار به شما یک حساب پرداخت صورتحساب میدهد که تمام چیزی است که در مرحله ۴ به آن نیاز دارید.
۲ · باز کردن پوسته ابری (تقریباً ۱ دقیقه)
🌐 روی گزینهی «فعال کردن پوستهی ابری» در بالای کنسول گوگل کلود کلیک کنید - این آیکون به شکل ترمینال در سربرگ قرار دارد.

🌐 روی «باز کردن ویرایشگر» (آیکون باز کردن پوشه با مداد) کلیک کنید. این کار ویرایشگر Cloud Shell را به همراه یک فایل اکسپلورر در سمت چپ باز میکند - هر زمان که یک مرحله علامتگذاری شده باشد، در آنجا کار میکنید ✏️.

🌐 اگر امروز در هر مرحلهای از شما خواسته شد که مجوز دهید، برای ادامه روی «مجوز دادن» کلیک کنید.
🌐 یک ترمینال درون ویرایشگر باز کنید - یعنی تب ۱ ، جایی که هر 💻 مرحله اجرا میشود. اگر از قبل در پایین صفحه نیست، آن را با View → Terminal باز کنید:

💻 بررسی کنید که Cloud Shell با کدام حساب کاربری وارد سیستم شده است:
gcloud auth list
👀 حساب کاربری خودتان را که با * مشخص شده است، در نظر بگیرید و این حساب باید همان حسابی باشد که در مرحله ۱ با آن وارد سیستم شدهاید .
۳ · آزمایشگاه را آماده کنید (تقریباً ۱ دقیقه)
💻 مخزن را کلون کنید:
cd ~
git clone https://github.com/cuppibla/agent-valley-lab.git
cd ~/agent-valley-lab
۴ · پروژه خود را ایجاد کنید (حدود ۲ دقیقه)
💻 یک اسکریپت حساب صورتحساب شما را پیدا میکند، یک پروژه روی آن ایجاد میکند و Cloud Shell را به آن پروژه ارجاع میدهد:
cd ~/agent-valley-lab
./setup_project.sh
👀 انتظار یک ✓ برای حساب پرداختی که انتخاب کرده، یک ✓ برای پروژهای که ایجاد کرده، و یک پایان مانند این را داشته باشید:
Project ready: agent-valley-4271 Next: ./setup_codelab.sh
agent-valley-4271 شناسه پروژه شماست - شماره شما ارقام متفاوتی خواهد داشت. چهار اتفاق در آنجا رخ میدهد:
صورتحساب | جدیدترین | |
پروژه | | |
انتخاب میکند | شناسه را در | |
منتظر می ماند | نظرسنجیها تا زمانی که پروژه جدید واقعاً اجازه اجرا پیدا کند، تا دو دقیقه | |
🌐 همان پروژه اکنون در کنسول است - شناسه آن در کارت اطلاعات پروژه در داشبورد قرار دارد:

۵ · نصب و نشانهگیری به سمت Vertex AI (حدود ۳ دقیقه)
💻 uv را نصب کنید، سه متغیری که ADK را به Vertex AI ارسال میکنند را اکسپورت کنید و تنظیمات را اجرا کنید:
cd ~/agent-valley-lab
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.local/bin/env
export GOOGLE_GENAI_USE_VERTEXAI=True
export GOOGLE_CLOUD_PROJECT=$(gcloud config get project)
export GOOGLE_CLOUD_LOCATION=global
./setup_codelab.sh
$(gcloud config get project) چیزی برای برگرداندن دارد زیرا مرحله ۴ آن را تنظیم کرده است. به همین دلیل است که مرحله ۴ اول میآید.
setup_codelab.sh فایل خود-توان (idempotent) است - اجرای مجدد آن به هر تعداد بار که بخواهید، بیخطر است. این فایل به ترتیب چهار کار انجام میدهد:
API | مرحله ۴ پروژه انتخاب شده را میخواند و API هوش مصنوعی Vertex را روی آن فعال میکند. | |
محیط UV | | |
.env | سه متغیری که آزمایشگاه میخواند را مینویسد - هیچ کلید API در هیچ کجا وجود ندارد | |
بررسی مدل | یک تماس واقعی با Gemini برقرار میکند، بنابراین یک پروژه بد همینجا در زمان راهاندازی شکست میخورد، نه بعداً در یک فصل | |
۶ · ثابت کنید سبز است (~۱ دقیقه)
💻 پیشپرواز را اجرا کنید - هر تیک یک کاوش واقعی است، نه یک حدس:
cd ~/agent-valley-lab
uv run python scripts/preflight.py
👀 انتظار میرود که هر خط - از جمله Vertex AI · project تیک بخورد. Vertex AI · project — به PREFLIGHT GREEN ختم میشود. یک خط میگوید grove · 0 tools ← no edits yet ؛ درست است. آن ابزار گمشده، کل نکتهی فصل ۲ است.
ادامه مطلب (اختیاری)
۳. ۱ · اولین نماینده شما
قطعه: یک مدل با دستورالعمل. سیم: هنوز هیچ کدام - و نکته دقیقاً همین است.
- چی ؟ با کوچکترین نمایندهی موجود آشنا شو و تمامش رو بخون.
- چرا - همه چیز بعداً در این آزمایشگاه این فایل به علاوه یک چیز دیگر است.
- چگونه - یک دستور، یک فایل، دو جمله تایپ شد.
👉💻 در تب ۱ ، رابط کاربری توسعهدهندگان ADK را اجرا کنید:
cd ~/agent-valley-lab
uv run adk web . --allow_origins="*"
👉🔬 رابط کاربری توسعهدهندگان را از طریق پیشنمایش وب → تغییر پورت → ۸۰۰۰ باز کنید. روی انتخاب یک برنامه کلیک کنید. دو برنامه نمایش داده میشوند: grove و grove_locked . grove را انتخاب کنید. برنامهای که قفل شده، عامل نهایی است - شما همان درخواستی را که در فصل ۵ به آن اشاره کردیم، روی آن اجرا میکنید.
کل نماینده را بخوانید
👉📖 grove/agent.py را باز کنید. کامنتها را نادیده بگیرید - چهار خط مهم هستند :
cloudshell edit ~/agent-valley-lab/grove/agent.py
root_agent = LlmAgent(
name="grove",
model="gemini-3-flash-preview",
instruction=INSTRUCTION,
)
این یه ماموره. همهش.
-
name— چیزی که رابط کاربری توسعهدهنده آن را به عنوان آن فهرست میکند. -
model— کدام مغز. اینجا، فلش جمینی ۳. -
instruction— خلاصه وضعیت فعلی. 👉📖 به بالا بروید وINSTRUCTIONبخوانید: هفت جمله ساده که به آن میگوید یک آهنگری دارد، هر چیزی که یک مسافر توصیف میکند همیشه به شکل یک حیوان بامزه از آب در میآید، و احضار تنها کاری است که آهنگری میتواند انجام دهد.
👀 بدون ابزار. بدون حافظه. فقط یک مدل و شرح کار.
باهاش حرف بزن
👉🔬 این را تایپ کنید:
Summon a fox familiar for me.
شما باید چیزی دوستداشتنی ببینید . در اینجا یک پاسخ واقعی از همین نماینده آمده است:
کوره آهنگری با آبی ملایم و مهآلود میدرخشد، در حالی که یک قورباغهی چاق و خزهزده با ژاکتی کوچک و بافتهشده از کابل بیرون میآید و یک کلاه چایِ بخارآلود از جنس بلوط را در آغوش گرفته است.

👉🔬 از دیگران بپرسید که چه پاسخ واضحی میدهند:
Show me it.
شما باید کلمات زیباتری ببینید - و این تمام چیزی است که وجود دارد. نه تصویری. نه فایلی. نه قورباغهای.
👉🔬 روی برگه ایالت کلیک کنید. خالی است.
👀 این نه یک باگ است و نه یک مدل بد. تنها کانال خروجی یک مدل، متن است. بنابراین ادعایی در مورد بازیگری و یک عمل واقعی، از آن یکسان به نظر میرسند.
یک مامور بدون ابزار، مکالمهای بسیار مختصر و مفید است.
ادامه مطلب (اختیاری)
۴. ۲ · اولین ابزار شما
قطعه: یک تابع. سیم: مدل → ابزار.
- چه چیزی - به عامل یک عملکرد بدهید، سپس ببینید وقتی از آن استفاده میکند چه اتفاقی میافتد.
- چرا - این تفاوت بین توصیف یک قورباغه و ساختن آن است.
- چگونه — دو کاراکتر را حذف کنید، بازی را مجدداً اجرا کنید و ردپا را بخوانید.
یکی را ویرایش کنید
👉📖 دوباره grove/agent.py را باز کنید. ابزارها از قبل در بالا وارد شدهاند - آنها تمام مدت آنجا بودهاند. فقط عامل یکی از آنها را در دست نداشته است.
cloudshell edit ~/agent-valley-lab/grove/agent.py
👉✏️ ویرایش اول — علامت # را از ابتدای خط tools= حذف کنید، سپس ذخیره کنید:
root_agent = LlmAgent(
name="grove",
model="gemini-3-flash-preview",
instruction=INSTRUCTION,
# 👉 EDIT ONE — delete the "# " at the start of the next line, then save.
tools=[cast_candidates],
)
یک ابزار. یک نام، یک کاری که این عامل اکنون میتواند انجام دهد. فصل ۴ مورد دوم را اضافه میکند و آن کل آزمایشگاه است.
👉💻 رابط کاربری توسعهدهنده هنگام شروع، عامل را بارگذاری کرد، بنابراین عامل جدید را به آن بدهید. در تب ۱ ، Ctrl+C را فشار دهید و سپس دوباره آن را اجرا کنید:
cd ~/agent-valley-lab
uv run adk web . --allow_origins="*"
👉🔬 جلسه جدید به grove . همان چیزی را که قبلاً پرسیدید، درخواست کنید:
something cozy that likes rain and drinks tea
باید ببینید که دیگر حرف نمیزند و شروع به کار میکند: یک چیپ cast_candidates ، مکثی حدود دوازده ثانیه، سپس یک تصویر واقعی از موجودی که وقتی Enter را فشار دادید وجود نداشت.

فراخوان ابزار چیست؟
👉🔬 برای باز کردن چیپ cast_candidates روی آن کلیک کنید.

👀 چهار پیام. به مرحله دوم توجه کنید: خروجی مدل هنوز فقط یک پیام است. مدل تابع شما را نامگذاری کرده و آرگومان را نوشته است - شما گفتهاید "cozy, rain, tea" و مدل یک توصیف بصری کامل از طرف شما ایجاد کرده است - اما چیزی اجرا نکرده است. در زمان اجرا اجرا شده است.
قرارداد
👉📖 forge/agent/tools.py باز کنید و cast_candidates پیدا کنید:
cloudshell edit ~/agent-valley-lab/forge/agent/tools.py
async def cast_candidates(description: str, tool_context: ToolContext) -> dict:
"""Draw the familiar a traveler described.
Args:
description: What the creature looks like — species, colours, mood, era.
"""
👀 نام، امضا و آن رشتهی راهنما، کل توضیحات این تابع هستند که مدل همیشه خواهد دید. به همین دلیل است که به زبان انگلیسی ساده نوشته شده است. آن را برای خواننده بنویسید، نه برای کامپایلر.
تصویر واقعاً از کجا آمده است
حالا کل زنجیره را دنبال کنید. این بخشی است که اکثر آموزشها از آن صرف نظر میکنند.

👀 سه چیز که ارزش توقف کردن را دارند:
- عامل شما هرگز چیزی رسم نکرده است.
groveیک مدل متنی است - متن ورودی، متن خروجی. تصویر از یک مدل دوم ،gemini-2.5-flash-image، که از داخل تابع شما فراخوانی میشود، آمده است. - سبک هنری به صورت تصاویر وارد میشود. 👉📖
forge/agent/backends.pyرا باز کنید و_style_refs()را پیدا کنید. چهار تصویر نمونه با هر درخواست وارد میشوند. این همان جهت هنری است که نمیتوانستید به عنوان یک اعلان بنویسید.cloudshell edit ~/agent-valley-lab/forge/agent/backends.py - مدل هرگز تصویر را نمیبیند. پیکسلها با
save_artifact()ذخیره میشوند. چیزی که به مدل برمیگردد رشته"candidate_0.png"است - به اندازه کافی کوچک که در یک اعلان جا شود.
نماینده شما چندوجهی نشد. شما به آن دری به چیزی دادید که از قبل وجود داشت.
تو یک دست به آن دادهای. قبل از دست دوم، برو و ببین کار تمامشده چه حسی دارد.
ادامه مطلب (اختیاری)
۵. ۳ · دره
هیچ ویرایشی در این فصل وجود ندارد. هیچ ایده جدیدی وجود ندارد. شما یک تصویر را در ابزار توسعهدهنده ساختهاید - حالا بروید و از چیز تمامشده به مدت پنج دقیقه استفاده کنید.
👉💻 بگذارید adk web در حال اجرا باشد. یک تب ترمینال دوم (تب ۲) را با علامت + در نوار ابزار پنل ترمینال باز کنید:
cd ~/agent-valley-lab
bash valley.sh
👉🔬 دره را از طریق پیشنمایش وب → تغییر پورت → ۳۲۰۰ باز کنید، ▶ شروع و سپس بیشه احضار را فشار دهید.

👉🔬 یک نوع انتخاب کنید، یک تغییر تایپ کنید و احضار کنید. برایش اسم بگذارید. آن را مطالبه کنید.
👉🔬 سپس آن را بپوشانید: روی یک پیشنهاد مانند یک تاج طلایی ضربه بزنید و تماشا کنید که به عنوان یک جمله در کادر درخواست قرار میگیرد. اگر دوست دارید کلمات را تغییر دهید. ✦ ارسال را فشار دهید. این کار را سه یا چهار بار انجام دهید. عجله نکنید؛ این بخش از آزمایشگاه فقط سرگرم کننده است.

سه چیز هنگام بازی
- شما قبلاً کد پشت این را خواندهاید. جمله شما به یک عامل میرود، عامل
cast_candidatesیاgenerate_lookفراخوانی میکند - همان توابعی که پنج دقیقه پیش docstring های آنها را خواندید. - یک پیشنهاد، کلمات را مینویسد، دکمهای را فشار نمیدهد. این عمدی است. یک دکمه هیچ قصدی را حمل نمیکند، بنابراین چیزی برای خواندن توسط مدل وجود ندارد. یک جمله، قصدی را حمل میکند - که تنها دلیلی است که یک عامل میتواند اصلاً در این حلقه باشد.
- اینجا هیچ چیز به ویرایش شما نیاز نداشت. دره، عاملهای خودش را اجرا میکند (
forge/agent/lanes.py). قبل از اینکه شما به چیزی دست بزنید، کار میکرد.
دو چیز که هنوز نمیتوانید توضیح دهید
هر دو واقعی هستند. هر دو پاسخ دارند. هیچ کدام از پاسخها در این فصل نیست.
👉🔬 هنگام ارسال درخواست، به پنل سمت راست نگاه کنید.

before_model inject character_sheet after_model guard: pass before_tool identity lock → candidate_0.png after_tool + a golden crown · outfit: a golden crown
👀 شش خط برای یک جمله. چیزی جایی نوشته میشود، و چیزی از طرف شما تصویری را انتخاب میکند. این تصویر چیست و کجا میرود؟
👉🔬 حالا به نوار زیر «از روی این تصویر کار کنید» نگاه کنید و یک چیز پنجم و یک ششم اضافه کنید.

👀 هیچ چیز جای هیچ چیز دیگری را نگرفت. OUTFIT · 4 ، و مسیر سمت راست نشان میدهد که لیست به صورت یک آیتم در حال افزایش است - a golden crown → a golden crown, a starry cape → و همینطور ادامه. هر رندر از کل لیست ساخته میشود، به همین دلیل است که تاج چهار نوبت پس از درخواست شما هنوز آنجاست.
👀 دو نکته در آن عکس وجود دارد. پیشنهادی که از قبل پوشیدهاید، علامت ( ✓ ) دارد - چیپها فقط نمایی از همان لیست هستند. و هر مورد یک ✕ دارد: برداشتن چیزی یک دکمه است، نه یک جمله. چیزی برای تفسیر وجود ندارد، بنابراین کاری برای مدل وجود ندارد - دقیقاً آینهی «یک پیشنهاد کلمات را مینویسد، دکمهای را فشار نمیدهد» در بالا.
👀 این هنوز موجود شماست. شما هرگز آن را دوباره توصیف نکردید - چهار کلمه در مورد یک کلاه تایپ کردید. چیزی تصویر اصلی را برای شما نگه داشته است. چه چیزی این کار را انجام میدهد و آیا میتوانید آن را خاموش کنید؟
هر دو سوال را نگه دارید. سوال اول فصل بعدی است. سوال دوم فصل آخر است.
👀 دره را رها کنید - فصل ۵ به آن برمیگردد.
ادامه مطلب (اختیاری)
۶. ۴ · ابزار دوم — و نحوهی تعامل این دو
اون خط توی پنل سمت راست دره رو یادتونه — after_tool · + Crown · outfit: Crown ? از اینجا اومده.
قطعه: یک عملکرد دیگر. سیم: ابزار → عامل. این فصلی است که هفتهها در وقت مردم صرفهجویی میکند.
- چه چیزی - یک ابزار دوم اضافه کنید و ببینید که چگونه میداند ابزار اول چه کاری انجام داده است.
- چرا - این دو تابع هرگز یکدیگر را فراخوانی نمیکنند. چیز دیگری دادهها را حمل میکند.
- چگونه — یک نام دیگر، یک جمله دیگر، و تب ایالت.
ویرایش دو
cloudshell edit ~/agent-valley-lab/grove/agent.py
👉✏️ ویرایش دوم — به grove/agent.py برگردید، یک نام دیگر داخل براکتها اضافه کنید، سپس ذخیره کنید:
tools=[cast_candidates, lock_candidate],
این آخرین ویرایش در این آزمایشگاه است. اضافه کردن یک ابزار در واقع فقط اضافه کردن یک نام به یک لیست است.
👉📖 آنچه را که تحویل دادید بخوانید - lock_candidate در forge/agent/tools.py :
async def lock_candidate(index: int, name: str, tool_context: ToolContext) -> dict:
"""Lock one candidate as the canonical character. Spends no model — a pure state write."""
candidates = tool_context.state.get("temp:candidates", [])
ref = candidates[index]
tool_context.state["character_ref"] = ref
👀 به چیزی که در امضای آن وجود ندارد توجه کنید: نه نام فایلی، نه تصویری، نه فهرستی. تنها چیزی که مدل میتواند به آن بدهد یک شماره و یک نام است.
👉💻 به تب ۱ برگردید، رابط کاربری dev را مجدداً راهاندازی کنید تا عامل جدید را دریافت کند — Ctrl+C ، سپس دوباره آن را اجرا کنید:
cd ~/agent-valley-lab
uv run adk web . --allow_origins="*"
یک جمله، دو ابزار
👉🔬 جلسه جدید در grove . هر دو چیز را همزمان بخواهید:
summon something cozy that likes rain, and call it Mochi
این بار باید دو تراشه به ترتیب ببینید - cast_candidates ، سپس lock_candidate - و سپس نام آشنای شما.

سوال
👉🔬 تراشه lock_candidate را باز کنید. مدل دقیقاً آن را با این فراخوانی کرد:
lock_candidate(index=0, name="Mochi")
👀 خب — فایلی که قفل کرده را از کجا آورده؟
نه از مدل. مدل یک عدد را ارسال کرده است. نام فایل از temp:candidates آمده است، که cast_candidates چند ثانیه قبل نوشته بود.
این مدل دادهها را از یک ابزار به ابزار دیگر منتقل نمیکرد، بلکه یک فرهنگ لغت این کار را انجام میداد.
فرهنگ لغت
👉📖 به آخرین خطوط cast_candidates در همان فایل نگاه کنید:
tool_context.state["temp:candidates"] = filenames
tool_context.state["character_sheet"] = {"name": "", "description": description}
tool_context.state["provisional_ref"] = filenames[0]
tool_context.state["temp:provisional_ref_png"] = pngs[0][0]
👀 tool_context.state یک دیکشنری است که توسط همه چیز در جلسه به اشتراک گذاشته شده است. یک ابزار در آن مینویسد، ابزار بعدی از آن میخواند. هیچ پیامی رد و بدل نمیشود، هیچ کانال بازگشتی بین آنها وجود ندارد. یک اتاق مشترک.
👀 اولین مورد از آن چهار مورد نوشتن، همان handoff است که همین الان تماشا کردید - lock_candidate temp:candidates میخواند و اندیس ۰ را از آن بیرون میکشد. دو مورد آخر یک پین موقت هستند: یک پرتره اکنون وجود دارد، بنابراین چیزی وجود دارد که نقاشی بعدی میتواند به آن متصل شود، حتی اگر کسی آن را ادعا نکرده باشد و هنوز نامی ندارد. هیچ چیز تا زمانی که ابزار بعدی آن را اعلام نکند، معتبر نیست.
و نماینده هم آن را میخواند
👉📖 حالا نوبت شخص ثالث است. forge/agent/character_forge.py را باز کنید و به دستورالعملهای آن نگاه کنید:
cloudshell edit ~/agent-valley-lab/forge/agent/character_forge.py
Character card: {character_sheet?}
👀 آن آکولادها تزئینی نیستند. ADK قبل از هر فراخوانی مدل، آنها را در from state پر میکند. ابزار character_sheet را نوشت؛ اعلان آن را دوباره میخواند. رفت و برگشت کامل شد و هیچ یک از این سه فایل، فایل دیگری را وارد نمیکند.

ببینش.
👉🔬 روی تب State کلیک کنید. هر دو ابزار اجرا شدهاند، بنابراین کل رکورد به این صورت است:
__session_metadata__ {...}
character_sheet {"name": "Mochi", "description": "A cozy red panda...", "style_notes": ""}
provisional_ref ""
character_ref "candidate_0.png"
look_history []
👀 __session_metadata__ دفترداری خود رابط کاربری توسعهدهنده است. چهار تای دیگر مال شماست. cast_candidates character_sheet را با نامی که هنوز خالی است نوشت و تصویر آن را به عنوان provisional_ref پین کرد؛ lock_candidate نام را پر کرد، character_ref نوشت و پین موقت را به "" برگرداند. آن خط خالی فصل مینیاتوری است: بعد از cast_candidates یک ارجاع وجود دارد، تصویری که چیزی میتواند به آن متصل شود. فقط بعد از lock_candidate یک کاراکتر وجود دارد - named، canonical، character_ref . هر دو بار تصویر یکسانی دارند؛ lock_candidate مرحلهای است که بین این دو قرار میگیرد و رشته خالی رسید آن است. یک لنگر در رکورد، نه دو لنگر.
👀 هر دو ابزار همچنین bytes را نوشتند و هیچکدام از این مجموعهها در این لیست نیستند: temp:provisional_ref_png و temp:character_ref_png . فصل ۵ درباره دلیل وجود این کلیدها است و قانون بعدی این است که چرا نمیتوانید آنها را ببینید.
👀 دو قانون که ارزش به خاطر سپردن دارند:
- چیزهای بزرگ وارد حالت نمیشوند. تصویر ۱.۳ مگابایتی به مصنوعات رفت؛ رشته کوتاهی که آن را نامگذاری میکند به حالت رفت. هر اعلان متن است، بنابراین هر چیزی که مدل باید ببیند باید در داخل آن جای گیرد.
- پیشوند مادام العمر است.
temp:یک نوبت طول میکشد. هیچ پیشوندی مکالمه را ادامه نمیدهد.user:برای همیشه طول میکشد - یعنی هفته ۴.
خروجی واقعی یک ابزار، جملهای نیست که بعد از آن میگوید، بلکه چیزی است که از خود به جا میگذارد.
ادامه مطلب (اختیاری)
۷. ۵ · پاسخ به تماس — دست بردن در سیم
در ابتدا، شما چهار بار لباس آشنای خود را پوشیدید و چهرهاش هرگز تغییر نکرد - حتی اگر حتی یک بار هم آن را دوباره توصیف نکردید. این فصلی است که این موضوع دیگر یک راز نیست.
قطعه: کد شما، در یک لحظه مشخص. سیم: شما → سیم.
- چه چیزی - کد خودتان را بین مدل درخواستی و ابزار در حال اجرا قرار دهید.
- چرا - یک دستورالعمل یک درخواست است. اینگونه است که شما یک قانون وضع میکنید.
- چگونه - یک فایل برای خواندن، یک جمله ارسال شده به دو مامور، و یک کلید در دره.
پنج لحظه
👉📖 forge/agent/callbacks.py را باز کنید. پنج تابع، پنج لحظه نامگذاری شده:
cloudshell edit ~/agent-valley-lab/forge/agent/callbacks.py

👀 یک callback فقط کد خودتان است که در هر لحظه ADK names را برای شما اجرا میکند. چه مدل بخواهد چه نخواهد، اجرا میشود.
👉📖 before_tool بخوانید. این تابع پس از درخواست مدل و قبل از اجرای تابع شما اجرا میشود - آخرین لحظهای که میتوانید آنچه ابزار قرار است دریافت کند را تغییر دهید. در اینجا تصمیم میگیرد که ترسیم بعدی به کدام تصویر متصل شود:
png = (state.get("temp:_last_output_png") if mode == "latest"
else state.get("temp:character_ref_png")
or state.get("temp:provisional_ref_png"))
if png is None: # a later turn: the temp tier is gone
png = await artifact_png(tool_context, seed)
state["temp:active_reference_png"] = png
👀 به چیزی که لمس میکند نگاه کنید: state . دیکشنری از فصل ۴. یک callback جایی است که شما به آن سیم دست میزنید. این or ترتیبی است که دو پین به آن متصل میشوند - مرجع قفل شده ابتدا، مرجع موقت از cast_candidates پشت آن - بنابراین همیشه یک چهره برای ارسال وجود دارد.
👉📖 تابع بالای آن، _apply_identity_lock ، را بخوانید. این همان تابعی است که Valley از آن استفاده میکند:
picked = state.get("requested_reference") or canon
if state.get("identity_lock", True):
return canon, canon_png, f"identity lock → overruled {picked}, anchored to {canon}"
return picked, picked_png, f"lock off → honoured {picked}"
👀 دوباره آن خط اول را بخوانید. تصویری که در دره کلیک کردید picked است. و خط بعدی میتواند آن را دور بیندازد.
آنچه که آن یک خط واقعاً تعیین میکند
هر نقاشی بعد از نقاشی اول، دقیقاً شامل دو چیز است: یک تصویر و یک جمله. آن خط بالا تصویر را انتخاب میکند.
👀 فقط دو راه برای پر کردن آن پاکت وجود دارد. همان مدل، همان الگوی سوال، هر کدام سه نوبت:
- ⚓ پین شده در هر نوبت
P0، همان پرترهای که ادعا کردید، را ارسال میکند. جمله تا اینجا کل لباس را در بر میگیرد - «حالا تاج، شال، فانوس» . چیزی جز کلمات جمع نمیشود. - ◈ تابع unpinned خروجی آخرین نوبت را ارسال میکند -
P0، سپسP1، سپسP2- و جمله فقط جدیدترین آیتم را حمل میکند. یک کپی از یک کپی.
👀 به همین دلیل است که این تغییر تدریجی است و نه آشکار. در نوبت دوم، مدل به موجود شما نگاه نمیکند؛ بلکه به بهترین حدس خودش از موجود شما نگاه میکند. هر نکتهی کوچکی که اشتباه تشخیص داده باشد، اکنون به عنوان حقیقت پایه برای نوبت سوم در نظر گرفته میشود.
تماشا کنید که چطور نگه داشته میشود
grove یک مدل و دو ابزار است. grove_locked آن به علاوهی ابزار سوم و پنج تابع فراخوانی است که خواندید - همان فایل، متصل. برای هر دو، یک جملهی یکسان ارسال کنید.
👉💻 این بخش به رابط کاربری توسعهدهندگان برگشته است، نه به دره. اگر تب ۱ هنوز آن را ارائه میدهد، بگذارید در حال اجرا باشد؛ اگر آن را متوقف کردهاید، دوباره آن را شروع کنید:
cd ~/agent-valley-lab
uv run adk web . --allow_origins="*"
👉🔬 در grove ، درخواست تغییر لباس کنید. اگر موچی از قبل در این جلسه درخواست شده است، فوراً آن را ارسال کنید؛ اگر جلسه تازه یا خالی است، ابتدا یک مورد آشنا را درخواست کنید: summon something cozy that likes rain, and call it Mochi . سپس ارسال کنید:
give it a golden crown
باید یک موجود متفاوت با تاج ببینید. grove generate_look ندارد. تنها ابزاری که دارد که ترسیم میکند cast_candidates است و هر بار که اجرا میشود، یک موجود آشنای جدید را شروع میکند - بنابراین یک موجود تازه احضار میشود. تاج را میگیرید و موچی را از دست میدهید. اینجا هرگز از هیچ چیز خواسته نشده که آن چهره را نگه دارد.
👉🔬 حالا یک برنامه انتخاب کنید →
grove_locked . این یک برنامه جدید است، بنابراین یک جلسه جدید دریافت میکند - در اینجا نیز یک مورد آشنا را ادعا کنید: summon something cozy that likes rain, and call it Mochi . سپس همان جمله را ارسال کنید:
give it a golden crown
👀 همان چهره، لباس جدید. تراشه را باز کنید: ابزاری که اجرا شد generate_look بود.
این یک نمونهی واقعی از همین جفت است، با یک نمونهی آشنای متفاوت: یک فک با بارانی زرد، سپس یک شال قرمز . همان فک با همان شال برگشت - همان پوزه، همان چشمها، همان کلاه.
👉🔬 برگه ایالت را باز کنید:
current_look {"form": "a golden crown", "artifact": "look_0.png", "anchored_to": "canon", "identity_hue": null}
👀 anchored_to: "canon" در حال حاضر before_tool یک رسید از خود به جا میگذارد. بین درخواست مدل و اجرای تابع شما، تابع پرترهای که شما درخواست کردهاید را دریافت کرده و بایتهای آن تصویر - حدود یک مگابایت PNG، نه نام فایل - را قبل از مدل تصویر قرار داده است. به همین دلیل است که چهره باقی مانده است. شما آن را در اعلان ننوشتهاید و مدل هرگز حق اظهار نظر نداشته است.
حالا خاموشش کن
👉🔬 به دره برگردید، قفل را فشار دهید تا عبارت 🔓 قفل هویت · خاموش را نشان دهد. سه یا چهار درخواست دیگر ارسال کنید و اجازه دهید نوار هر بار شما را به جلو دنبال کند.

before_tool lock off → honoured look_3.png
👀 حالا انتخاب شما مورد تقدیر قرار گرفته است، و هر رندر، رندر قبلی را کپی میکند. به امتداد نوار نگاه کنید - یک چشم گردتر، یک پوزه متفاوت، یک گوش که حرکت میکند. هیچ چیز باعث نمیشود بگویید "حیوان اشتباهی". این چیزی است که آن را خطرناک میکند: هر نوبت، نوبت قبلی را کپی میکند، بنابراین جابجاییهای کوچک روی هم انباشته میشوند.
👀 P0 → P1 → P2 → P3 — زنجیره فتوکپی از قبل، که روی سیستم آشنای شما اجرا میشود.
👉🔬 قفل را دوباره فشار دهید و یک بار دیگر ارسال کنید. دوباره برمیگردد - کانن هرگز گم نشده بود. در وضعیت فعلی نوشته شده بود، منتظر اینکه کسی دوباره به آن اشاره کند.
سه پله، نه دو پله
👀 شما اکنون از هر سه روش برای کنترل این چیز استفاده کردهاید، و آنها با هم برابر نیستند:
چه کسی آن را تضمین میکند؟ | |
یک دستورالعمل — «همیشه یک حیوان بامزه» | مدل، اگر اینطور به نظر برسد |
انتخاب شما — کلیک روی یک مرجع | هیچکس. این یک درخواست است و میتوان آن را رد کرد |
یک فراخوانی مجدد — قفل هویت | کد شما. هر نوبت. بدون استثنا. |
یک دستورالعمل یک درخواست است. یک فراخوانی مجدد یک قانون است.
هر چیزی که نمیتوانید از دست بدهید، جایش در یک اعلان نیست، و جایش در یک کلیک هم نیست. جایش در یک فراخوانی مجدد است.
۸. بستن
یک آزمون دیگر
👉🔬 برنامه را به صورت کامل بارگذاری مجدد کنید (Cmd/Ctrl + Shift + R).

👀 آشنای شما هنوز آنجاست، هنوز نام دارد، هنوز لباس پوشیده است - اما نوار بازرس خالی برگشت. هر دو یک ثانیه پیش "در برنامه" بودند. یکی نوشته شده بود؛ دیگری نه. دانستن اینکه کدام یک از دادههای شما مربوط به کدام است، بخش عمدهی کار است.
👉🔬 دکمه ✨ finish را فشار دهید، سپس ⤓ گذرنامه را ذخیره کنید .

آنچه واقعاً یاد گرفتید
یک عامل از قطعات تشکیل شده است، به علاوهی سیمکشی بین آنها:
قطعه | سیم |
یک مدل با دستورالعمل | فقط میتواند صحبت کند |
یک ابزار | مدل میپرسد، زمان اجرا اجرا میشود |
یک ابزار دوم | یک ابزار وضعیت را مینویسد، ابزار بعدی آن را میخواند |
یک تماس برگشتی | کد شما، که به آن سیم میرسد |
و حلقهای که آنها به آن اضافه میکنند: گوش دادن → تصمیمگیری → عمل کردن → تغییرات وضعیت. سپس دوباره گوش دهید. کلود کد فایلهای شما را با آن ویرایش میکند. دیپ ریسرچ با آن مرور میکند. جمینی سیالآی پوسته شما را با آن اجرا میکند. همان حلقه - ابزارهای مختلف پشت در.
یک مدل فقط میتواند صحبت کند. یک برنامه فقط میتواند از اسکریپت خود پیروی کند. یک عامل، پیوند است - و چیزی که این ابزار تغییر داده، وضعیت است.
کجا برویم؟
- هفته دوم، کارگاه ساخت و ساز را افتتاح میکند. امشب همه چیز به یک نماینده مربوط بود. هفته آینده مشکل این است که یک نماینده نمیتواند کل یک شغل را به عهده بگیرد - و پاسخ، تعداد بیشتر آنها است، نه پیشنهادهای بزرگتر. هر پنج هفته: goo.gle/agent101
- دو عامل را از هم جدا کنید.
forge/agent/character_forge.pyهمانgrove/agent.pyبه علاوهی یک ابزار سوم و پنج فراخوانی برگشتی است که آتش زدنشان را تماشا کردید. هر چیزی که اضافه شده کنترل است. - ابزار سوم،
generate_look(form)ابزاری است که هرگز بهgroveوصل نکردهاید - فقط ظاهر یکسانی را حفظ میکند زیرا یک callback مرجع آن را پین میکند. به همین دلیل است که در جایی که callbackها هستند، قرار میگیرد.