ساخت عامل‌های دارای وضعیت و شخصی‌سازی‌شده با ADK

۱. مقدمه

عنوان

مسئله «ماهی طلایی»

تصور کنید که برای برنامه‌ریزی تعطیلات رویایی‌تان به توکیو، یک آژانس مسافرتی استخدام کرده‌اید. از Session Agent برای دیدن «مسئله ماهی قرمز» در عمل استفاده کنید.

وارد دفترشان می‌شوید و می‌گویید:

«سلام! من می‌خواهم یک سفر دو روزه به توکیو برنامه‌ریزی کنم. من به مکان‌های تاریخی و سوشی علاقه‌مندم.»

نماینده با اشتیاق پاسخ می‌دهد:

«عالیه! من یه بازدید از کاخ امپراتوری و یه شام ​​سوشی تو سوکیاباشی جیرو برنامه‌ریزی کردم.»

لبخند می‌زنی و می‌گویی:

«به نظر عالی میاد! می‌تونی برنامه سفر رو برام بفرستی؟»

مامور با نگاهی متعجب به شما نگاه می‌کند و می‌پرسد:

«سلام! چطور می‌تونم کمکتون کنم که امروز یه سفر رو برنامه‌ریزی کنید؟»

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

ماموریت امروز شما

در این کارگاه، شما با ساخت یک آژانس مسافرتی که به خاطر می‌سپارد، یاد می‌گیرد و سازگار می‌شود، مشکل ماهی قرمز را حل خواهید کرد. شما در 6 سطح از حافظه آژانس پیشرفت خواهید کرد و سیستمی ایجاد خواهید کرد که کمتر شبیه یک چت‌بات و بیشتر شبیه یک دستیار شخصی اختصاصی رفتار می‌کند.

سطح

مفهوم

«ابرقدرت»

سطح ۱

جلسه و وضعیت

ادامه مکالمه بدون فراموش کردن

سطح ۲

حالت چند عاملی

اشتراک‌گذاری یادداشت‌ها بین اعضای تیم

سطح ۳

پشتکار

حتی پس از راه‌اندازی مجدد سیستم، شما را به خاطر می‌سپارد

سطح ۴

تماس‌های برگشتی

به‌روزرسانی حافظه به صورت کاملاً خودکار

سطح ۵

ابزارهای سفارشی

خواندن و نوشتن پروفایل‌های کاربری ساختاریافته

سطح ۶

حافظه چندوجهی

«دیدن» و به خاطر سپردن عکس‌ها و ویدیوها

پشته حافظه ADK

قبل از اینکه کد بنویسیم، بیایید ابزارهایی را که استفاده می‌کنیم درک کنیم. کیت توسعه عامل گوگل (ADK) روشی ساختاریافته برای مدیریت حافظه ارائه می‌دهد:

  1. جلسه (Session) : ظرفی برای یک مکالمه. این بخش تاریخچه‌ی آنچه گفته شده است را در خود نگه می‌دارد.
  2. وضعیت (State) : یک "دفترچه یادداشت" با کلید-مقدار که به جلسه (session) متصل شده است. عامل‌ها از این برای ذخیره حقایق خاص (مثلاً destination="Tokyo" ) استفاده می‌کنند.
  3. MemoryService : حافظه بلندمدت. این جایی است که ما چیزهایی مانند تنظیمات برگزیده کاربر یا اسناد تحلیل‌شده را برای همیشه نگه می‌داریم.

۲. راه‌اندازی

برای توانمندسازی عوامل هوش مصنوعی خود، به دو چیز نیاز داریم: یک پروژه ابری گوگل برای فراهم کردن پایه و اساس.

بخش اول: فعال کردن حساب صورتحساب

  • برای فعال کردن حساب صورتحساب خود با اعتبار ۵ دلاری، به آن برای استقرار خود نیاز خواهید داشت. حتماً به حساب جیمیل خود وارد شوید.

بخش دوم: محیط باز

  1. 👉 برای دسترسی مستقیم به ویرایشگر Cloud Shell ، روی این لینک کلیک کنید
  2. 👉 اگر امروز در هر مرحله‌ای از شما خواسته شد که مجوز دهید، برای ادامه روی «مجوز دادن» کلیک کنید. برای تأیید Cloud Shell کلیک کنید
  3. 👉 اگر ترمینال در پایین صفحه نمایش داده نشد، آن را باز کنید:
    • روی مشاهده کلیک کنید
    • روی ترمینال کلیک کنید باز کردن ترمینال جدید در ویرایشگر Cloud Shell
  4. 👉💻 در ترمینال، با استفاده از دستور زیر تأیید کنید که از قبل احراز هویت شده‌اید و پروژه روی شناسه پروژه شما تنظیم شده است:
    gcloud auth list
    
  5. 👉💻 پروژه بوت‌استرپ را از گیت‌هاب کپی کنید:
    git clone https://github.com/cuppibla/memory_agent_starter
    
    
  6. 👉💻 اسکریپت راه‌اندازی را از دایرکتوری پروژه اجرا کنید.
    cd ~/memory_agent_starter
    ./init.sh
    
    اسکریپت بقیه مراحل راه‌اندازی را به‌طور خودکار انجام خواهد داد.
  7. 👉💻 شناسه پروژه مورد نیاز را تنظیم کنید:
    gcloud config set project $(cat ~/project_id.txt) --quiet
    

بخش سوم: تنظیم مجوز

  1. 👉💻 با استفاده از دستور زیر، APIهای مورد نیاز را فعال کنید. این کار ممکن است چند دقیقه طول بکشد.
    gcloud services enable \
        cloudresourcemanager.googleapis.com \
        servicenetworking.googleapis.com \
        run.googleapis.com \
        aiplatform.googleapis.com \
        compute.googleapis.com
    
  2. 👉💻 با اجرای دستورات زیر در ترمینال، مجوزهای لازم را اعطا کنید:
    . ~/memory_agent_starter/set_env.sh
    

توجه داشته باشید که یک فایل .env برای شما ایجاد شده است که اطلاعات پروژه شما را نشان می‌دهد.

۳. بنیاد - جلسه و دولت

دولتی

مفهوم: زمینه پادشاه است

اساسی‌ترین شکل حافظه، حافظه نشست (Session Memory) است. این همان چیزی است که به یک عامل اجازه می‌دهد بداند که «it» در جمله «I want to buy it » به کفشی که شما 10 ثانیه پیش در مورد آن صحبت می‌کردید، اشاره دارد.

در ADK، ما این کار را با شیء Session مدیریت می‌کنیم.

  • رویکرد بدون تابعیت : ایجاد یک جلسه جدید برای هر پیام.
  • رویکرد مبتنی بر وضعیت : ایجاد یک جلسه و استفاده مجدد از آن برای کل مکالمه.

مرحله 1: عامل را بررسی کنید

👉💻 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/01_session_agent/agent.py

فایل ~/memory_agent_starter/01_session_agent/agent.py را باز کنید.

👉 کامنت # TODO: Create a root agent درون تابع agent.py ایجاد کنید.

کل این خط را با کد زیر جایگزین کنید :

root_agent = LlmAgent(
    name="multi_day_trip_agent",
    model="gemini-2.5-flash",
    description="Agent that progressively plans a multi-day trip, remembering previous days and adapting to user feedback.",
    instruction="""
    You are the "Adaptive Trip Planner" 🗺️ - an AI assistant that builds multi-day travel itineraries step-by-step.

    Your Defining Feature:
    You have short-term memory. You MUST refer back to our conversation to understand the trip's context, what has already been planned, and the user's preferences. If the user asks for a change, you must adapt the plan while keeping the unchanged parts consistent.

    Your Mission:
    1.  **Initiate**: Start by asking for the destination, trip duration, and interests.
    2.  **Plan Progressively**: Plan ONLY ONE DAY at a time. After presenting a plan, ask for confirmation.
    3.  **Handle Feedback**: If a user dislikes a suggestion (e.g., "I don't like museums"), acknowledge their feedback, and provide a *new, alternative* suggestion for that time slot that still fits the overall theme.
    4.  **Maintain Context**: For each new day, ensure the activities are unique and build logically on the previous days. Do not suggest the same things repeatedly.
    5.  **Final Output**: Return each day's itinerary in MARKDOWN format.
    """,
    tools=[google_search]
)

دستورالعمل به LLM می‌گوید که به خاطر بسپارد، اما کد باید قابلیت به خاطر سپردن را فراهم کند.

مرحله ۲: دو سناریو

فایل ~/memory_agent_starter/01_session_agent/main.py را باز کنید.

👉 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/01_session_agent/main.py

فایل ~/memory_agent_starter/01_session_agent/main.py را باز کنید، کامنت # TODO: Create a runner with in memorysession service را درون تابع main.py پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

    runner = Runner(
        agent=agent,
        session_service=session_service,
        app_name=agent.name
    )

👉 کامنت # TODO: create a different session to test inside the main.py را پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

    tokyo_session_2 = await session_service.create_session(
        app_name=multi_day_agent.name,
        user_id=user_id
    )

آن را آزمایش کنید

ما دو تابع داریم که تفاوت بین حافظه «ماهی طلایی» و «فیل» را نشان می‌دهند.

سناریو ۱: Stateful (جلسه مشترک)

async def run_trip_same_session_scenario(session_service, user_id):
    # 1. Create ONE session
    trip_session = await session_service.create_session(...)

    # 2. Turn 1
    await run_agent_query(..., trip_session, ...)

    # 3. Turn 2 - REUSING the same session!
    # The agent can "see" Turn 1 because it's in the session history.
    await run_agent_query(..., trip_session, ...)

سناریو ۲: بدون تابعیت (هر بار یک جلسه جدید)

async def run_trip_different_session_scenario(session_service, user_id):
    # Turn 1
    tokyo_session = await session_service.create_session(...)
    await run_agent_query(..., tokyo_session, ...)

    # Turn 2 - Creating a FREASH session
    # The agent has NO IDEA what happened in Turn 1.
    tokyo_session_2 = await session_service.create_session(...)
    await run_agent_query(..., tokyo_session_2, ...)

مرحله 3: اجرای عامل

بیایید تفاوت را در عمل ببینیم. اسکریپت را اجرا کنید:

👉💻 در خط فرمان، دستور زیر را اجرا کنید:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/01_session_agent/main.py

سناریوی ۱ را در نظر بگیرید : عامل تنظیمات برگزیده شما را از پیام اول به خاطر می‌سپارد و طرح را در پیام دوم تطبیق می‌دهد.

سناریوی دوم را ببینید : در نوبت دوم ("یادت هست من از چه چیزی در مورد غذا خوشم آمد؟")، عامل کاملاً شکست می‌خورد زیرا این یک جلسه جدید است. در واقع می‌گوید: "من نمی‌دانم در مورد چه چیزی صحبت می‌کنی."

نکته کلیدی

قانون شماره ۱ حافظه: همیشه از session.id برای حفظ زمینه مکالمه استفاده مجدد کنید. شیء Session بافر حافظه کوتاه مدت عامل شما است.

۴. تیم - حالت چندعاملی

غذا

مفهوم: «بازی تلفنی»

وقتی چندین عامل با هم کار می‌کنند، مانند همکارانی هستند که یک پوشه فایل را به یکدیگر پاس می‌دهند. اگر یک عامل یادداشتی در پوشه بنویسد، عامل بعدی باید بتواند آن را بخواند.

در ADK، این «پوشه» همان State است.

  • State یک دیکشنری ( {"key": "value"} ) است که درون Session قرار دارد.
  • هر عاملی در جلسه می‌تواند از آن بخواند یا در آن بنویسد.

مرحله ۱: بررسی روند کار

👉💻 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/02_multi_agent/agent.py

👉 در فایل ~/memory_agent_starter/02_multi_agent/agent.py ، کامنت # TODO: foodie agent پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

foodie_agent = LlmAgent(
    name="foodie_agent",
    model="gemini-2.5-flash",
    tools=[google_search],
    instruction="""You are an expert food critic. Your goal is to find the best restaurant based on a user's request.

    When you recommend a place, you must output *only* the name of the establishment and nothing else.
    For example, if the best sushi is at 'Jin Sho', you should output only: Jin Sho
    """,
    output_key="destination"  # ADK will save the agent's final response to state['destination']
)

👉 عبارت # TODO: transportation agent درون تابع agent.py پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

transportation_agent = LlmAgent(
    name="transportation_agent",
    model="gemini-2.5-flash",
    tools=[google_search],
    instruction="""You are a navigation assistant. Given a destination, provide clear directions.
    The user wants to go to: {destination}.

    Analyze the user's full original query to find their starting point.
    Then, provide clear directions from that starting point to {destination}.
    """,
)

👉 عبارت # TODO: root_agent درون تابع agent.py پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

root_agent = SequentialAgent(
    name="find_and_navigate_agent",
    sub_agents=[foodie_agent, transportation_agent],
    description="A workflow that first finds a location and then provides directions to it."
)

حالا ما دو عامل داریم که به ترتیب کار می‌کنند:

  1. نماینده غذا : یک رستوران پیدا می‌کند.
  2. مامور حمل و نقل : مسیر رسیدن به آن رستوران را ارائه می‌دهد.

انتقال جادویی : توجه کنید که چگونه foodie_agent مسئولیت را به transportation_agent واگذار می‌کند.

foodie_agent = LlmAgent(
    # ...
    # CRITICAL: This tells ADK to save the agent's output to state['destination']
    output_key="destination"
)

transportation_agent = LlmAgent(
    # ...
    # CRITICAL: This injects state['destination'] into the prompt
    instruction="""
    The user wants to go to: {destination}.
    Provide clear directions...
    """,
)
  1. output_key="destination" : پاسخ نماینده‌ی غذا به طور کارآمد ذخیره می‌شود.
  2. {destination} : نماینده حمل و نقل آن پاسخ را به طور خودکار می‌خواند.

(نیازی به اقدام خاصی نیست) مرحله ۲: هماهنگ‌کننده

02_multi_agent/main.py را باز کنید.

ما از یک SequentialAgent برای اجرای آنها به ترتیب استفاده می‌کنیم.

# 1. Create a single session for the sequential agent
session = await session_service.create_session(...)

# 2. Run the query
# The SequentialAgent manages the state flow:
# Query -> Foodie -> state['destination'] -> Transportation -> Final Answer
await run_agent_query(root_agent, query, ...)

کاربر یک درخواست ارسال می‌کند:

"Find best sushi in Palo Alto and then tell me how to get there."

ماموران با هم همکاری می‌کنند تا به آن پاسخ دهند.

مرحله ۳: تیم را اداره کنید

👉💻 در ترمینال Cloud Shell، گردش کار چندعاملی را اجرا کنید:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/02_multi_agent/main.py

چه اتفاقی می‌افتد؟

  1. مامور غذا : «جین شو» (یا چیزی شبیه به آن) را پیدا می‌کند.
  2. ADK : عبارت "Jin Sho" را در state['destination'] ذخیره می‌کند.
  3. مامور حمل و نقل : در دستورالعمل خود "جین شو" را دریافت می‌کند.
  4. نتیجه : «برای رسیدن به جین شو از ایستگاه کالترین، در خیابان دانشگاه پیاده‌روی کنید...»

نکته کلیدی

قانون شماره ۲ حافظه: از State برای انتقال اطلاعات ساختاریافته بین عامل‌ها استفاده کنید. output_key برای نوشتن و {placeholders} برای خواندن استفاده کنید.

۵. راه‌اندازی مجدد - پایداری

دولتی

مفهوم: «مشکل راه‌اندازی مجدد»

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

برای رفع این مشکل، به Persistence نیاز داریم. ما InMemorySessionService با DatabaseSessionService عوض می‌کنیم.

مرحله 1: سوئیچ پایگاه داده

👉💻 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/03_persistent_agent/main.py

👉 در فایل ~/memory_agent_starter/03_persistent_agent/main.py ، عبارت # TODO: Configuration for Persistent Sessions بیابید.

کل این خط را با کد زیر جایگزین کنید :

SESSIONS_DIR = Path(os.path.expanduser("~")) / ".adk_codelab" / "sessions"
os.makedirs(SESSIONS_DIR, exist_ok=True)
SESSION_DB_FILE = SESSIONS_DIR / "trip_planner.db"
SESSION_URL = f"sqlite:///{SESSION_DB_FILE}"

اکنون، هر جلسه و رویداد در یک فایل SQLite ذخیره می‌شود.

مرحله ۲: بازیابی بین جلساتی

پشتکار نه تنها امکان از سرگیری مکالمه را فراهم می‌کند، بلکه امکان یادگیری از مکالمات گذشته را نیز فراهم می‌کند.

در همان فایل ~/memory_agent_starter/03_persistent_agent/main.py ، به مورد آزمایشی ۳: بازیابی بین‌جلسه‌ای (Cross-Session Retrieval) نگاه کنید.

👉 کامنت را پیدا کنید # TODO: retrieve the previous session manually

کل این خط را با کد زیر جایگزین کنید :

    old_session = await session_service.get_session(
        app_name=root_agent.name, user_id="user_01", session_id=session_id
    )

👉 کامنت را پیدا کنید # TODO: Extract content from the OLD session in the main.py function.

کل این خط را با کد زیر جایگزین کنید :

                    previous_context += f"- {role}: {text}\n"

👉 کامنت را پیدا کنید # TODO: Manually inject the context to the query درون تابع main.py تزریق کنید.

کل این خط را با کد زیر جایگزین کنید :

    query_3 = f"""
    {previous_context}

    I'm planning a new trip to Osaka this time. 
    Based on my previous preferences (above), what should I eat?
    """

این شبیه‌سازی می‌کند که یک کاربر ماه‌ها بعد برمی‌گردد. فقط با یک پایگاه داده می‌توانید آن تاریخچه قدیمی را بازیابی کنید.

مرحله ۳: زنده ماندن پس از راه‌اندازی مجدد

👉💻 در ترمینال، اسکریپت را اجرا کنید:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/03_persistent_agent/main.py

این یک فایل ~/memory_agent_starter/trip_planner.db ایجاد می‌کند. این را امتحان کنید: اسکریپت را دو بار اجرا کنید.

  • در اجرای دوم، به دنبال «جلسه موجود از سر گرفته شد» باشید.
  • عامل، زمینه را از اولین اجرا به خاطر خواهد سپرد، زیرا از فایل پایگاه داده بارگیری می‌شود!

نکته کلیدی

قانون شماره ۳ حافظه: از DatabaseSessionService برای محیط عملیاتی استفاده کنید. این امر تضمین می‌کند که مکالمات کاربر پس از راه‌اندازی مجدد سرور همچنان پابرجا می‌مانند و امکان تجزیه و تحلیل تاریخچه بلندمدت را فراهم می‌کند.

۶. جاسوس - فراخوانی‌های مجدد

دولتی

گاهی اوقات، شما نیاز دارید که حافظه را به طور خودکار بر اساس کاری که عامل انجام می‌دهد، به‌روزرسانی کنید، نه فقط بر اساس آنچه می‌گوید. شما به یک "جاسوس" نیاز دارید که عامل را زیر نظر داشته باشد و یادداشت‌برداری کند.

در ADK، این جاسوس ، Callback است. adk_callback

  • after_tool_callback : تابعی که هر بار که عامل کار می‌کند، اجرا می‌شود.
  • ToolContext : روشی برای نوشتن در State از داخل آن تابع.

مرحله ۱: منطق

👉💻 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/04_stateful_agent/agent.py

👉 در فایل ~/memory_agent_starter/04_stateful_agent/agent.py ، کامنت # TODO: Implement call back logic پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

def save_activity_type_callback(
    tool,
    args: Dict[str, Any],
    tool_context: ToolContext,
    tool_response: Dict[str, Any],
) -> Optional[Dict[str, Any]]:
    """
    Callback to save the TYPE of activity just planned into the session state.
    """
    # 1. Get the actual agent name.
    if tool.name == "transfer_to_agent":
         agent_name = args.get("agent_name")
    else:
         agent_name = tool.name

    activity_type = "unknown"

    # 2. Determine the type based on which agent was actually used
    if agent_name == "museum_expert":
        activity_type = "CULTURAL"
    elif agent_name == "restaurant_expert":
        activity_type = "FOOD"
    elif agent_name == "outdoor_expert":
        activity_type = "OUTDOOR"

    print(f"\n🔔 [CALLBACK] The planner transferred to '{agent_name}'.")

    # 3. Update the state directly
    tool_context.state["last_activity_type"] = activity_type
    print(f"💾 [STATE UPDATE] 'last_activity_type' is now set to: {activity_type}\n")

    return tool_response

👉 در همان فایل ، عبارت # TODO: add callback to root agent درون تابع 04_stateful_agent/agent.py پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

    after_tool_callback=save_activity_type_callback,

دستورالعمل پویا: دستورالعمل عامل اکنون یک تابع است، نه یک رشته. این دستورالعمل بر اساس وضعیت تغییر می‌کند!

def get_planner_instruction(context):
    last_activity = context.state.get("last_activity_type", "None")
    
    return f"""
    The last activity was: {last_activity}
    
    If last_activity is 'CULTURAL' -> `museum_expert` is BANNED.
    """

مرحله ۳: جاسوس را آزمایش کنید

👉💻 در ترمینال، اسکریپت را با کپی کردن و چسباندن دستور زیر اجرا کنید:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/04_stateful_agent/main.py

وقتی این عامل را اجرا می‌کنید، یک حلقه خواهید دید.

  1. نوبت اول: شما درخواست موزه می‌کنید. جاسوس last_activity="CULTURAL" را تنظیم می‌کند.
  2. نوبت دوم: شما درخواست یک موزه دیگر می‌کنید.
  3. به‌روزرسانی‌های دستورالعمل مامور: «فرهنگی ممنوع است».
  4. نماینده می‌گوید: «من نمی‌توانم یک موزه دیگر بسازم. نظرتان در مورد یک پارک چیست؟»

به گزارش‌های کنسول برای [CALLBACK] و [STATE UPDATE] توجه کنید. می‌توانید تغییرات حافظه را به صورت بلادرنگ در حین کار عامل مشاهده کنید.

نکته کلیدی

قانون شماره ۴ حافظه: از Callbackها برای خودکارسازی مدیریت وضعیت استفاده کنید. عامل شما صرفاً با انجام وظیفه‌اش، زمینه خودش را می‌سازد.

۷. کابینت بایگانی - ابزارهای سفارشی

مفهوم: «حافظه ساختاریافته»

دولتی

تاکنون، «حافظه» یک گزارش چت یا یک جفت کلید-مقدار ساده بوده است. اما اگر نیاز به یادآوری یک پروفایل کاربری پیچیده داشته باشید، چه؟ مثلاً diet: vegan, budget: high, pets: [cat, dog] .

برای این منظور، ما با حافظه به عنوان یک ابزار رفتار می‌کنیم. عامل به صراحت تصمیم می‌گیرد که چه زمانی کابینت فایل را باز کند (خواندن) و چه زمانی یک گزارش را ثبت کند (نوشتن). نمودار ابزارهای سفارشی

مرحله ۱: ابزارها

👉💻 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/05_profile_agent/tools.py

👉 در این فایل: ~/memory_agent_starter/05_profile_agent/tools.py .

ما باید این دو ابزار خاص را پیاده‌سازی کنیم:

  1. save_user_preferences : در یک پایگاه داده می‌نویسد.
  2. recall_user_preferences : از یک پایگاه داده می‌خواند.

عبارت # TODO: implement save_user_preferences tools درون تابع ~/memory_agent_starter/05_profile_agent/tools.py پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

def save_user_preferences(tool_context: ToolContext, new_preferences: Dict[str, Any]) -> str:
    user_id = tool_context.session.user_id
    with sqlite3.connect(USER_DB_FILE) as conn:
        for key, value in new_preferences.items():
            conn.execute("INSERT INTO user_preferences (user_id, pref_key, pref_value) VALUES (?, ?, ?) ON CONFLICT(user_id, pref_key) DO UPDATE SET pref_value = excluded.pref_value;",
                         (user_id, key, json.dumps(value)))
    return f"Preferences updated: {list(new_preferences.keys())}"

👉 کامنت # TODO: implement recall_user_preferences tools درون تابع 05/tools.py پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

def recall_user_preferences(tool_context: ToolContext) -> Dict[str, Any]:
    user_id = tool_context.session.user_id
    preferences = {}
    with sqlite3.connect(USER_DB_FILE) as conn:
        rows = conn.execute("SELECT pref_key, pref_value FROM user_preferences WHERE user_id = ?", (user_id,)).fetchall()
        if not rows: return {"message": "No preferences found."}
        for key, value_str in rows: preferences[key] = json.loads(value_str)
    return preferences

این دستورالعمل، گردش کار را اجباری می‌کند:

instruction="""
1. RECALL FIRST: First action MUST be `recall_user_preferences`.
3. LEARN: If a user states a new preference, use `save_user_preferences`.
"""

مرحله ۲: اجرا

👉💻 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/05_profile_agent/main.py

فایل ~/memory_agent_starter/05_profile_agent/main.py را باز کنید.

برخلاف ماژول‌های قبلی که ADK به طور خودکار وضعیت را مدیریت می‌کرد، در اینجا Agent کنترل را در دست دارد.

  • در ابتدا، فراخوانی recall_user_preferences را انتخاب می‌کند .
  • وقتی می‌گویید «من وگان هستم» (I am vegan)، این تابع ، تابع save_user_preferences را فراخوانی می‌کند.

مرحله ۳: ساخت پروفایل

👉💻 اسکریپت را اجرا کنید:

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/05_profile_agent/main.py

این جریان مکالمه را امتحان کنید:

  1. «سلام، برای شام برنامه‌ریزی کنید.» -> نماینده پایگاه داده را بررسی می‌کند، چیزی پیدا نمی‌کند. تنظیمات برگزیده را می‌پرسد.
  2. «من وگان هستم.» -> مامور «وگان» را در پایگاه داده ذخیره می‌کند.
  3. اسکریپت را دوباره راه اندازی کنید.
  4. «سلام، برای شام برنامه‌ریزی کنید.» -> نماینده DB را بررسی می‌کند، کلمه «وگان» را می‌بیند و فوراً یک رستوران وگان را پیشنهاد می‌دهد.

نکته کلیدی

قانون شماره ۵ حافظه: برای داده‌های پیچیده و ساختاریافته، به عامل خود ابزارهای خواندن/نوشتن بدهید. اجازه دهید LLM ذخیره‌سازی بلندمدت خود را مدیریت کند.

۸. مغز - حافظه چندوجهی

دولتی

مفهوم: «تجربه انسانی»

انسان‌ها چیزی بیش از متن را به خاطر می‌سپارند. ما حال و هوای یک عکس، صدای یک صدا، و حس یک ویدیو را به خاطر می‌سپاریم.

بانک حافظه هوش مصنوعی ورتکس به عامل شما اجازه می‌دهد تا حافظه چندوجهی را مدیریت کند. این عامل می‌تواند تصاویر، ویدیوها و صداها را دریافت کند، آنها را «درک» کند و بعداً آنها را بازیابی کند.

مرحله ۱: پیکربندی

👉💻 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/06_multimodal_agent/main.py

👉 فایل 06_multimodal_agent/main.py را باز کنید. کامنت # TODO: Configure Memory Bank Topic پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

travel_topics = [
    MemoryTopic(
        managed_memory_topic=ManagedMemoryTopic(
            managed_topic_enum=ManagedTopicEnum.USER_PREFERENCES
        )
    ),
    MemoryTopic(
        managed_memory_topic=ManagedMemoryTopic(
            managed_topic_enum=ManagedTopicEnum.USER_PERSONAL_INFO
        )
    ),
    MemoryTopic(
        custom_memory_topic=CustomMemoryTopic(
            label="travel_experiences",
            description="""Memorable travel experiences including:
                - Places visited and impressions
                - Favorite restaurants, cafes, and food experiences
                - Preferred accommodation types and locations
                - Activities enjoyed (museums, hiking, beaches, etc.)
                - Travel companions and social preferences
                - Photos and videos from trips with location context""",
        )
    ),
    MemoryTopic(
        custom_memory_topic=CustomMemoryTopic(
            label="travel_preferences",
            description="""Travel style and preferences:
                - Budget preferences (luxury, mid-range, budget)
                - Transportation preferences (flying, trains, driving)
                - Trip duration preferences
                - Season and weather preferences
                - Cultural interests and language abilities
                - Dietary restrictions and food preferences""",
        )
    ),
    MemoryTopic(
        custom_memory_topic=CustomMemoryTopic(
            label="travel_logistics",
            description="""Practical travel information:
                - Passport and visa information
                - Frequent flyer numbers and hotel loyalty programs
                - Emergency contacts
                - Medical considerations and insurance
                - Packing preferences and essentials
                - Time zone preferences and jet lag strategies""",
        )
    ),
]

کامنت # TODO: Configure Memory Bank Customization پیدا کنید

کل این خط را با کد زیر جایگزین کنید :

memory_bank_config = {
    "customization_configs": [
        {
            "memory_topics": travel_topics,
        }
    ],
    "similarity_search_config": {
        "embedding_model": f"projects/{PROJECT_ID}/locations/{LOCATION}/publishers/google/models/gemini-embedding-001"
    },
    "generation_config": {
        "model": f"projects/{PROJECT_ID}/locations/{LOCATION}/publishers/google/models/gemini-2.5-flash"
    },
}

مرحله ۲: بلعیدن جهان

در test_trip_planner ، ما موارد زیر را ارسال می‌کنیم:

  1. یک پیامک ("سلام")
  2. یک تصویر (برجسته)
  3. یک ویدیو (دریای مدیترانه)
  4. یک کلیپ صوتی (یادداشت صوتی درباره گائتا)

عبارت # TODO create session service and memory service درون تابع 6_multimodal_agent/main.py پیدا کنید.

کل این خط را با کد زیر جایگزین کنید :

session_service = VertexAiSessionService(
    project=PROJECT_ID, location=LOCATION, agent_engine_id=agent_engine_id
)
memory_service = VertexAiMemoryBankService(
    project=PROJECT_ID, location=LOCATION, agent_engine_id=agent_engine_id
)

👉 در همان فایل 06_multimodal_agent/main.py ، کامنت # TODO: create memory from session کنید.

کل این خط را با کد زیر جایگزین کنید :

    await memory_service.add_session_to_memory(final_session_state)

این خط جادویی است. تمام آن محتوای غنی را به Vertex AI ارسال می‌کند، که آن را پردازش و فهرست‌بندی می‌کند.

مرحله ۳: بازیابی

👉💻 در ترمینال Cloud Shell خود، فایل را در ویرایشگر Cloud Shell با اجرای دستور زیر باز کنید:

cloudshell edit ~/memory_agent_starter/06_multimodal_agent/agent.py

این عامل دارای PreloadMemoryTool است.

tools=[PreloadMemoryTool(), budget_tool]

وقتی یک جلسه جدید شروع می‌شود، این ابزار به طور خودکار در بانک حافظه به دنبال تجربیات مرتبط گذشته جستجو می‌کند و آنها را به متن تزریق می‌کند.

مرحله ۴: مغز را به کار بیندازید

👉💻 در ترمینال Cloud Shell خود، اسکریپت را اجرا کنید (توجه: این کار به یک پروژه Google Cloud با Vertex AI فعال نیاز دارد):

cd ~/memory_agent_starter
uv run python ~/memory_agent_starter/06_multimodal_agent/main.py

مرحله تأیید نهایی را تماشا کنید:

«بر اساس تصویر، ویدیو و صوتی که قبلاً با شما به اشتراک گذاشتم...»

نماینده پاسخ خواهد داد:

«باید از گائتا دیدن کنی! تو ویدیویی از دریای مدیترانه و یک کلیپ صوتی به من نشان دادی که در آن گفتی عاشق گائتا هستی.»

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

نکته کلیدی

قانون شماره ۶ حافظه: از بانک حافظه هوش مصنوعی ورتکس برای تجربه نهایی حافظه استفاده کنید. این بانک، متن، تصاویر و ویدیو را در یک مغز واحد و قابل جستجو متحد می‌کند.

۹. نتیجه‌گیری

شما از یک ماهی قرمز فراموشکار به یک فیل چندوجهی تبدیل شده‌اید.

شما ساختید

قابلیت

عامل جلسه

حافظه کوتاه مدت مکالمه

چند عاملی

حافظه مشترک تیمی

عامل پایدار

تاریخچه طولانی مدت

نماینده دولتی

حافظه پویا و خود-به‌روزرسان

نماینده پروفایل

حافظه داده ساختاریافته

عامل چندوجهی

حافظه حسی شبیه انسان

اعتماد بر اساس حافظه ساخته می‌شود. با پیاده‌سازی این الگوها، شما عواملی ایجاد می‌کنید که به زمان و سابقه کاربر احترام می‌گذارند و منجر به تعاملات عمیق‌تر و مؤثرتر می‌شوند.

همین امروز شروع به ساخت نمایندگان شخصی‌سازی‌شده خود کنید!