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

۱. مقدمه

عنوان

مشکل «ماهی قرمز»

تصور کنید که یک کارگزار مسافرتی را برای برنامه‌ریزی تعطیلات رؤیایی‌تان به توکیو استخدام می‌کنید. از نماینده جلسه برای دیدن «مشکل ماهی قرمز» در عمل استفاده کنید.

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

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

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

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

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

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

نماینده با نگاهی خالی به شما نگاه می‌کند و می‌پرسد:

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

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

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

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

سطح

مفهوم

«Superpower»

سطح ۱

جلسه و وضعیت

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

سطح ۲

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

هم‌رسانی یادداشت‌ها بین اعضای تیم

سطح ۳

پایداری

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

سطح ۴

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

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

سطح ۵

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

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

سطح ۶

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

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

پشته حافظه ADK

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

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

۲. تنظیم کردن

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

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

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

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

  1. 👉 برای رفتن مستقیم به ویرایشگر Cloud Shell، روی این پیوند کلیک کنید
  2. 👉 اگر امروز در هر مرحله‌ای از شما خواسته شد که مجوز بدهید، برای ادامه دادن روی مجاز کردن کلیک کنید. برای صدور مجوز Cloud Shell کلیک کنید
  3. 👉 اگر پایانه در پایین صفحه نشان داده نمی‌شود، آن را باز کنید:
    • روی مشاهده کلیک کنید
    • روی پایانه کلیک کنیدباز کردن پایانه جدید در «ویرایشگر Cloud Shell»
  4. 👉💻 در پایانه، بااستفاده از فرمان زیر، تأیید کنید که قبلاً اصالت‌سنجی شده‌اید و پروژه روی شناسه پروژه شما تنظیم شده است:
    gcloud auth list
    
  5. 👉💻 پروژه راه‌اندازی را از GitHub همانندسازی کنید:
    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. 👉💻 میاناهای برنامه‌سازی کاربردی لازم را بااستفاده از فرمان زیر فعال کنید. این کار ممکن است چند دقیقه طول بکشد.
    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 برای شما ایجاد شده است. که اطلاعات پروژه شما را نشان می‌دهد.

۳. The Foundation - Session & State

stateful

مفهوم: بافت پادشاه است

ابتدایی‌ترین شکل حافظه حافظه جلسه است. این همان چیزی است که به نماینده اجازه می‌دهد بداند «آن» در جمله «می‌خواهم آن را بخرم» به کفشی اشاره دارد که ۱۰ ثانیه پیش درباره آن صحبت می‌کردید.

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

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

مرحله ۱: بررسی «نماینده»

👉💻 در پایانه 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]
)

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

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

باز کردن ~/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 را در تابع main.py پیدا کنید.

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

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

امتحان کنید

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

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

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, ...)

مرحله ۳: اجرا کردن عامل

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

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

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

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

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

نکته کلیدی

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

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

غذا

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

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

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

  • 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. نماینده حمل‌ونقل: مسیرهای رسیدن به آن رستوران را ارائه می‌دهد.

The Magic Hand-off: Notice how foodie_agent passes the baton to 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}: «نماینده حمل‌ونقل» آن پاسخ را به‌طور خودکار می‌خواند.

(No Action Needed) Step 2: The Orchestrator

باز کردن 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 Terminal، گردش کار چندعاملی را اجرا کنید:

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

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

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

نکته کلیدی

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

۵. The Reboot - Persistence

stateful

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

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

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

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

👉💻 در پایانه 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، به مورد آزمایشی ۳: بازیابی بین‌جلسه‌ای نگاه کنید.

👉 نظر # 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 را در تابع main.py پیدا کنید.

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

                    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 برای تولید استفاده کنید. این کار تضمین می‌کند که مکالمه‌های کاربر پس‌از بازراه‌اندازی سرور حفظ شود و امکان تجزیه‌وتحلیل سابقه بلندمدت را فراهم می‌کند.

‫۶. جاسوس - پاسخ تماس

stateful

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

در 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.
    """

مرحله ۳: آزمایش کردن Spy

👉💻 در پایانه، با کپی و جای‌گذاری کردن فرمان زیر، اسکریپت را اجرا کنید:

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

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

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

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

نکته کلیدی

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

‫۷. The File Cabinet - Custom Tools

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

stateful

تاکنون، «حافظه» یک گزارش گپ یا یک جفت کلید-مقدار ساده بوده است. اما اگر لازم باشد نمایه کاربر پیچیده‌ای را به‌خاطر بسپارید چه؟ برای مثال، 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 وضعیت را به‌طور خودکار مدیریت می‌کرد، در اینجا نماینده کنترل را در دست دارد.

  • در ابتدا انتخاب می‌کند که با recall_user_preferences تماس بگیرد.
  • وقتی می‌گویید «من پاک‌گیاه‌خوار هستم»، انتخاب می‌کند که با save_user_preferences تماس بگیرد.

مرحله ۳: ساختن نمایه

👉💻 اجرای متن:

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

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

  1. «سلام، برای شام برنامه‌ریزی کن.» -> عامل پایگاه داده را بررسی می‌کند، چیزی پیدا نمی‌کند. اولویت‌ها را می‌پرسد.
  2. «من پاک‌گیاه‌خوار هستم.» -> Agent saves "vegan" to DB.
  3. دستورگان را بازراه‌اندازی کنید.
  4. «سلام، برای شام برنامه‌ریزی کن.» -> نماینده پایگاه داده را بررسی می‌کند، «پاک‌گیاه‌خوار» را می‌بیند، و بلافاصله رستوران پاک‌گیاه‌خواران را پیشنهاد می‌دهد.

نکته کلیدی

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

‫۸. The Brain - Multimodal Memory

stateful

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

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

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

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

👉💻 در پایانه 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]

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

مرحله ۴: اجرا کردن Brain

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

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

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

«براساس تصویر، ویدیو، و صدایی که قبلاً با شما هم‌رسانی کردم…»

عامل پاسخ خواهد داد:

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

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

نکته کلیدی

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

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

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

شما ساختید

قابلیت

عامل جلسه

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

چندعاملی

خاطره تیمی مشترک

عامل پایدار

سابقه بلندمدت

عامل باحالت

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

نماینده نمایه

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

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

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

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

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