Agent2Agent (A2A) প্রোটোকল দিয়ে শুরু করা: ক্লাউড রান এবং এজেন্ট ইঞ্জিনে একটি ক্রয়কারী কনসিয়ার এবং রিমোট সেলার এজেন্ট ইন্টারঅ্যাকশন

১. 📖 ভূমিকা

983be32cd5f6b65d.png সম্পর্কে

Agent2Agent (A2A) প্রোটোকলটি AI এজেন্টদের মধ্যে যোগাযোগের মান নির্ধারণের জন্য ডিজাইন করা হয়েছে, বিশেষ করে যেগুলি বহিরাগত সিস্টেমে স্থাপন করা হয়। পূর্বে, মডেল কনটেক্সট প্রোটোকল (MCP) নামক টুলসের জন্য এই ধরনের প্রোটোকল প্রতিষ্ঠিত হয়েছিল যা LLM গুলিকে ডেটা এবং রিসোর্সের সাথে সংযুক্ত করার জন্য একটি উদীয়মান মান। A2A MCP-এর পরিপূরক হিসেবে কাজ করে যেখানে A2A একটি ভিন্ন সমস্যার উপর দৃষ্টি নিবদ্ধ করে, যেখানে MCP এজেন্টদের সরঞ্জাম এবং ডেটার সাথে সংযুক্ত করার জন্য জটিলতা কমানোর উপর দৃষ্টি নিবদ্ধ করে, A2A এজেন্টদের তাদের প্রাকৃতিক পদ্ধতিতে সহযোগিতা করতে সক্ষম করার উপর দৃষ্টি নিবদ্ধ করে। এটি এজেন্টদের সরঞ্জাম হিসাবে নয় বরং এজেন্ট হিসাবে (অথবা ব্যবহারকারী হিসাবে) যোগাযোগ করতে দেয়; উদাহরণস্বরূপ, যখন আপনি কিছু অর্ডার করতে চান তখন সামনে-পিছনে যোগাযোগ সক্ষম করে।

A2A কে MCP এর পরিপূরক হিসেবে স্থাপন করা হয়েছে, অফিসিয়াল ডকুমেন্টেশনে অ্যাপ্লিকেশনগুলিকে টুলের জন্য MCP এবং এজেন্টদের জন্য A2A ব্যবহার করার পরামর্শ দেওয়া হয়েছে - যা AgentCard দ্বারা প্রতিনিধিত্ব করা হয় (আমরা পরে এটি নিয়ে আলোচনা করব)। এরপর ফ্রেমওয়ার্কগুলি তাদের ব্যবহারকারী, দূরবর্তী এজেন্ট এবং অন্যান্য এজেন্টদের সাথে যোগাযোগের জন্য A2A ব্যবহার করতে পারে।

cb49a578e47636e1.png সম্পর্কে

এই ডেমোতে, আমরা পাইথন SDK ব্যবহার করে A2A বাস্তবায়ন শুরু করব। আমরা এমন একটি ব্যবহারের উদাহরণ খুঁজে বের করব যেখানে আমাদের কাছে ব্যক্তিগত ক্রয় কনসিয়ারেজ থাকবে যা আমাদের অর্ডার পরিচালনা করার জন্য বার্গার এবং পিৎজা বিক্রেতা এজেন্টদের সাথে যোগাযোগ করতে সাহায্য করতে পারে।

A2A ক্লায়েন্ট-সার্ভার নীতি ব্যবহার করে। এই টিউটোরিয়ালে আপনি যে সাধারণ A2A প্রবাহ আশা করবেন তা এখানে দেওয়া হল।

e7e3224d05b725f0.jpeg সম্পর্কে

  1. A2A ক্লায়েন্ট প্রথমে সমস্ত অ্যাক্সেসযোগ্য A2A সার্ভার এজেন্ট কার্ড আবিষ্কার করবে এবং একটি সংযোগ ক্লায়েন্ট তৈরি করতে এর তথ্য ব্যবহার করবে।
  2. যখন প্রয়োজন হবে, A2A ক্লায়েন্ট A2A সার্ভারে একটি বার্তা পাঠাবে, সার্ভার এটিকে সম্পন্ন করার জন্য একটি টাস্ক হিসেবে মূল্যায়ন করবে। যদি পুশ নোটিফিকেশন রিসিভার URL A2A ক্লায়েন্টে কনফিগার করা থাকে এবং A2A সার্ভার দ্বারা সমর্থিত হয়, তাহলে সার্ভারটি ক্লায়েন্টের রিসিভিং এন্ডপয়েন্টে টাস্ক অগ্রগতির অবস্থা প্রকাশ করতে সক্ষম হবে।
  3. কাজ শেষ হওয়ার পর, A2A সার্ভার A2A ক্লায়েন্টের কাছে প্রতিক্রিয়া আর্টিফ্যাক্ট পাঠাবে।

কোডল্যাবের মাধ্যমে, আপনি নিম্নরূপ ধাপে ধাপে পদ্ধতি ব্যবহার করবেন:

  1. গুগল ক্লাউড প্রজেক্ট প্রস্তুত করুন
  2. কোডিং পরিবেশের জন্য কাজের ডিরেক্টরি সেটআপ করুন
  3. ক্লাউড রানে বার্গার এজেন্ট মোতায়েন করুন
  4. ক্লাউড রানে পিৎজা এজেন্ট মোতায়েন করুন
  5. এজেন্ট ইঞ্জিনে ক্রয় কনসিয়ারেজ স্থাপন করুন
  6. স্থানীয় ইন্টারফেসের মাধ্যমে ক্রয়কারী কনসিয়ারজের সাথে যোগাযোগ করুন

স্থাপত্যের সংক্ষিপ্ত বিবরণ

আপনি নিম্নলিখিত পরিষেবা আর্কিটেকচার স্থাপন করবেন

a485135c8f7b97bd.jpeg সম্পর্কে

আপনি দুটি পরিষেবা স্থাপন করবেন যা A2A সার্ভার হিসেবে কাজ করবে, বার্গার এজেন্ট (CrewAI এজেন্ট ফ্রেমওয়ার্ক দ্বারা সমর্থিত) এবং পিৎজা এজেন্ট (Langgraph এজেন্ট ফ্রেমওয়ার্ক দ্বারা সমর্থিত)। ব্যবহারকারী কেবল সরাসরি পারচেজিং কনসির্জের সাথে যোগাযোগ করবেন যা এজেন্ট ডেভেলপমেন্ট কিট (ADK) ফ্রেমওয়ার্ক ব্যবহার করে পরিচালিত হবে যা A2A ক্লায়েন্ট হিসেবে কাজ করবে।

এই এজেন্টদের প্রত্যেকের নিজস্ব পরিবেশ এবং মোতায়েন থাকবে।

পূর্বশর্ত

  • পাইথনের সাথে কাজ করা আরামদায়ক
  • HTTP পরিষেবা ব্যবহার করে মৌলিক ফুল-স্ট্যাক আর্কিটেকচার সম্পর্কে ধারণা

তুমি কি শিখবে

  • A2A সার্ভারের মূল কাঠামো
  • A2A ক্লায়েন্টের মূল কাঠামো
  • ক্লাউড রানে এজেন্ট পরিষেবা স্থাপন করা হচ্ছে
  • এজেন্ট ইঞ্জিনে এজেন্ট পরিষেবা স্থাপন করা
  • A2A ক্লায়েন্ট কিভাবে A2A সার্ভারের সাথে সংযুক্ত হয়
  • নন-স্ট্রিমিং সংযোগের জন্য অনুরোধ এবং প্রতিক্রিয়া কাঠামো

তোমার যা লাগবে

  • ক্রোম ওয়েব ব্রাউজার
  • একটি জিমেইল অ্যাকাউন্ট
  • বিলিং অ্যাকাউন্ট সক্ষম থাকা একটি ক্লাউড প্রজেক্ট

সকল স্তরের ডেভেলপারদের জন্য (নতুনদের সহ) তৈরি এই কোডল্যাবটি তার নমুনা অ্যাপ্লিকেশনে পাইথন ব্যবহার করে। তবে, উপস্থাপিত ধারণাগুলি বোঝার জন্য পাইথন জ্ঞানের প্রয়োজন নেই।

২. 🚀 ওয়ার্কশপ ডেভেলপমেন্ট সেটআপ প্রস্তুত করা

ধাপ ১: ক্লাউড কনসোলে অ্যাক্টিভ প্রজেক্ট নির্বাচন করুন

গুগল ক্লাউড কনসোলে , প্রজেক্ট সিলেক্টর পৃষ্ঠায়, একটি গুগল ক্লাউড প্রোজেক্ট নির্বাচন করুন বা তৈরি করুন (আপনার কনসোলের উপরের বাম অংশটি দেখুন)

7758dd17c20c3094.png সম্পর্কে

এটিতে ক্লিক করুন, এবং আপনি আপনার সমস্ত প্রকল্পের তালিকা দেখতে পাবেন যেমন এই উদাহরণে,

8c93fa37e7a7b856.png সম্পর্কে

লাল বাক্সে যে মানটি নির্দেশিত তা হল PROJECT ID এবং এই মানটি পুরো টিউটোরিয়াল জুড়ে ব্যবহার করা হবে।

আপনার ক্লাউড প্রোজেক্টের জন্য বিলিং সক্ষম আছে কিনা তা নিশ্চিত করুন। এটি পরীক্ষা করতে, আপনার উপরের বাম বারে বার্গার আইকন ☰ এ ক্লিক করুন যা নেভিগেশন মেনু দেখায় এবং বিলিং মেনুটি খুঁজে বের করুন।

db07810b26fc61d6.png সম্পর্কে

যদি আপনি দেখেন "গুগল ক্লাউড প্ল্যাটফর্ম ট্রায়াল বিলিং অ্যাকাউন্ট" লিঙ্ক করা আছে , তাহলে আপনার প্রকল্পটি এই টিউটোরিয়ালের জন্য ব্যবহারের জন্য প্রস্তুত। যদি না দেখেন, তাহলে এই টিউটোরিয়ালের শুরুতে ফিরে যান এবং বিলিং অ্যাকাউন্টটি রিডিম করুন।

4f592f31aef0c40.png সম্পর্কে

ধাপ ২: ক্লাউড শেলের সাথে পরিচিত হোন

আপনি বেশিরভাগ টিউটোরিয়ালের জন্য ক্লাউড শেল ব্যবহার করবেন, গুগল ক্লাউড কনসোলের উপরে অ্যাক্টিভেট ক্লাউড শেল ক্লিক করুন। যদি এটি আপনাকে অনুমোদনের জন্য অনুরোধ করে, তাহলে অনুমোদনে ক্লিক করুন।

26f20e837ff06119.png সম্পর্কে

79b06cc89a99f840.png সম্পর্কে

ক্লাউড শেলের সাথে সংযুক্ত হয়ে গেলে, আমাদের পরীক্ষা করতে হবে যে শেল (অথবা টার্মিনাল) ইতিমধ্যেই আমাদের অ্যাকাউন্টের সাথে প্রমাণীকরণ করা হয়েছে কিনা।

gcloud auth list

যদি আপনি নীচের উদাহরণের মতো আপনার ব্যক্তিগত জিমেইল আউটপুট দেখতে পান, তাহলে সবকিছু ঠিক আছে।

Credentialed Accounts

ACTIVE: *
ACCOUNT: alvinprayuda@gmail.com

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

যদি না হয়, তাহলে আপনার ব্রাউজার রিফ্রেশ করার চেষ্টা করুন এবং অনুরোধ করা হলে Authorize- এ ক্লিক করুন (সংযোগ সমস্যার কারণে এটি ব্যাহত হতে পারে)

এরপর, আমাদের এটাও পরীক্ষা করতে হবে যে শেলটি ইতিমধ্যেই আপনার কাছে থাকা সঠিক PROJECT ID- তে কনফিগার করা আছে কিনা। যদি আপনি দেখেন যে টার্মিনালে $ আইকনের আগে ( ) এর ভিতরে একটি মান আছে (নীচের স্ক্রিনশটে, মানটি "a2a-agent-engine" ) তাহলে এই মানটি আপনার সক্রিয় শেল সেশনের জন্য কনফিগার করা প্রকল্পটি দেখায়।

8365518c832055f.png সম্পর্কে

যদি দেখানো মানটি ইতিমধ্যেই সঠিক থাকে, তাহলে আপনি পরবর্তী কমান্ডটি এড়িয়ে যেতে পারেন। তবে যদি এটি সঠিক না হয় বা অনুপস্থিত থাকে, তাহলে নিম্নলিখিত কমান্ডটি চালান।

gcloud config set project <YOUR_PROJECT_ID>

তারপর, Github থেকে এই কোডল্যাবের জন্য টেমপ্লেট ওয়ার্কিং ডিরেক্টরিটি ক্লোন করুন, নিম্নলিখিত কমান্ডটি চালান। এটি purchasing-concierge-a2a ডিরেক্টরিতে ওয়ার্কিং ডিরেক্টরি তৈরি করবে।

git clone https://github.com/alphinside/purchasing-concierge-intro-a2a-codelab-starter.git purchasing-concierge-a2a

ধাপ ৩: ক্লাউড শেল এডিটরের সাথে পরিচিত হোন এবং অ্যাপ্লিকেশন ওয়ার্কিং ডিরেক্টরি সেটআপ করুন

এখন, আমরা কিছু কোডিং কাজ করার জন্য আমাদের কোড এডিটর সেট আপ করতে পারি। এর জন্য আমরা ক্লাউড শেল এডিটর ব্যবহার করব।

ওপেন এডিটর বোতামে ক্লিক করুন, এটি একটি ক্লাউড শেল এডিটর খুলবে। 168eacea651b086c.png - [অনলাইন].

এরপর, ক্লাউড শেল এডিটরের উপরের অংশে যান এবং File->Open Folder এ ক্লিক করুন, আপনার ব্যবহারকারীর নাম ডিরেক্টরিটি খুঁজুন এবং purchasing-concierge-a2a ডিরেক্টরিটি খুঁজুন তারপর OK বোতামে ক্লিক করুন। এটি নির্বাচিত ডিরেক্টরিটিকে প্রধান কার্যকরী ডিরেক্টরি হিসাবে পরিণত করবে। এই উদাহরণে, ব্যবহারকারীর নাম হল alvinprayuda , তাই ডিরেক্টরি পাথটি নীচে দেখানো হয়েছে।

c87d2b76896d0c59.png সম্পর্কে

d5d829a1c43d7451.png সম্পর্কে

এখন, আপনার ক্লাউড শেল এডিটরটি দেখতে এরকম হওয়া উচিত

9b4793fa38e35af2.png সম্পর্কে

এবার এডিটরের জন্য টার্মিনাল খুলুন। মেনু বারে Terminal -> New Terminal এ ক্লিক করে অথবা Ctrl + Shift + C ব্যবহার করে এটি করতে পারেন। এটি ব্রাউজারের নীচের অংশে একটি টার্মিনাল উইন্ডো খুলবে।

8635b60ae2f45bbc.jpeg সম্পর্কে

আপনার বর্তমান সক্রিয় টার্মিনালটি purchasing-concierge-a2a ওয়ার্কিং ডিরেক্টরির ভিতরে থাকা উচিত। আমরা এই কোডল্যাবে Python 3.12 ব্যবহার করব এবং Python সংস্করণ এবং ভার্চুয়াল পরিবেশ তৈরি এবং পরিচালনা করার প্রয়োজনীয়তা সহজ করার জন্য আমরা uv python প্রজেক্ট ম্যানেজার ব্যবহার করব। এই uv প্যাকেজটি ইতিমধ্যেই ক্লাউড শেলে প্রি-ইন্সটল করা আছে।

.venv ডিরেক্টরিতে ভার্চুয়াল পরিবেশের জন্য প্রয়োজনীয় নির্ভরতা ইনস্টল করতে এই কমান্ডটি চালান।

uv sync --frozen

এই টিউটোরিয়ালের জন্য ঘোষিত নির্ভরতাগুলি দেখতে pyproject.toml দেখুন, যা হল a2a-sdk, google-adk, and gradio

এখন, আমাদের নীচে দেখানো কমান্ডের মাধ্যমে প্রয়োজনীয় API গুলি সক্রিয় করতে হবে। এতে কিছুটা সময় লাগতে পারে।

gcloud services enable aiplatform.googleapis.com \
                       run.googleapis.com \
                       cloudbuild.googleapis.com \
                       cloudresourcemanager.googleapis.com

কমান্ডটি সফলভাবে কার্যকর করার পরে, আপনি নীচের দেখানো বার্তার মতো একটি বার্তা দেখতে পাবেন:

Operation "operations/..." finished successfully.

৩. 🚀 ক্লাউড রানে A2A সার্ভার রিমোট সেলার এজেন্ট মোতায়েন করা

এই ধাপে, আমরা লাল বাক্স দ্বারা চিহ্নিত এই দুটি দূরবর্তী বিক্রেতা এজেন্ট মোতায়েন করব। বার্গার এজেন্ট CrewAI এজেন্ট ফ্রেমওয়ার্ক দ্বারা চালিত হবে এবং পিৎজা এজেন্ট Langgraph এজেন্ট দ্বারা চালিত হবে।

87dbae9eff7781f9.png সম্পর্কে

৪. 🚀 বার্গার বিক্রেতা এজেন্ট মোতায়েন করা - A2A সার্ভার

বার্গার এজেন্টের সোর্স কোডটি remote_seller_agents/burger_agent ডিরেক্টরির অধীনে রয়েছে।

remote_seller_agents/burger_agent ডিরেক্টরির অধীনে থাকা সমস্ত ফাইল ইতিমধ্যেই আমাদের এজেন্টকে ক্লাউড রানে স্থাপন করার জন্য যথেষ্ট যাতে এটি একটি পরিষেবা হিসাবে অ্যাক্সেসযোগ্য হয়। এটি স্থাপন করতে নিম্নলিখিত কমান্ডটি চালান।

gcloud run deploy burger-agent \
    --source remote_seller_agents/burger_agent \
    --port=8080 \
    --allow-unauthenticated \
    --min 1 \
    --region us-central1 \
    --update-env-vars GOOGLE_CLOUD_LOCATION=us-central1 \
    --update-env-vars GOOGLE_CLOUD_PROJECT={your-project-id}

যদি আপনাকে জিজ্ঞাসা করা হয় যে উৎস থেকে স্থাপনের জন্য একটি কন্টেইনার সংগ্রহস্থল তৈরি করা হবে, তাহলে Y উত্তর দিন। সফলভাবে স্থাপনের পরে এটি এইরকম একটি লগ দেখাবে।

Service [burger-agent] revision [burger-agent-xxxxx-xxx] has been deployed and is serving 100 percent of traffic.
Service URL: https://burger-agent-xxxxxxxxx.us-central1.run.app

আমরা যখন পরিষেবাটি স্থাপন করব তখন এখানকার xxxx অংশটি একটি অনন্য শনাক্তকারী হবে।

একটি নতুন ব্রাউজার ট্যাব খুলুন এবং ব্রাউজারের মাধ্যমে সেই মোতায়েন করা বার্গার এজেন্ট পরিষেবাগুলির https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json রুটে যান। এটি মোতায়েন করা A2A সার্ভার এজেন্ট কার্ড অ্যাক্সেস করার URL।

সফলভাবে স্থাপন করা হলে, এজেন্ট কার্ড অ্যাক্সেস করার সময় আপনি আপনার ব্রাউজারে নীচের চিত্রের মতো প্রতিক্রিয়া দেখতে পাবেন।

3d353be0e82ff46c.png সম্পর্কে

এটি বার্গার এজেন্ট কার্ডের তথ্য যা আবিষ্কারের উদ্দেশ্যে অ্যাক্সেসযোগ্য হওয়া উচিত।

লক্ষ্য করুন যে url মানটি এখনও http://0.0.0.0:8080/ এ সেট করা আছে। এই url মানটি A2A ক্লায়েন্টের বাইরের বিশ্ব থেকে বার্তা পাঠানোর জন্য প্রধান তথ্য হওয়া উচিত এবং এটি সঠিকভাবে কনফিগার করা হয়নি।

আমাদের বার্গার এজেন্ট পরিষেবার URL-এ এই মানটি আপডেট করতে হবে একটি অতিরিক্ত পরিবেশ পরিবর্তনশীল HOST_OVERRIDE যোগ করে।

পরিবেশ পরিবর্তনশীলের মাধ্যমে এজেন্ট কার্ডে বার্গার এজেন্ট URL মান আপডেট করা হচ্ছে

বার্গার এজেন্ট পরিষেবাতে HOST_OVERRIDE যোগ করতে, নিম্নলিখিত পদক্ষেপগুলি অনুসরণ করুন

  1. ক্লাউড অনুসন্ধান করুন আপনার ক্লাউড কনসোলের উপরে অনুসন্ধান বারে চালান

f56ec00607eafb6f.png সম্পর্কে

  1. পূর্বে মোতায়েন করা বার্গার-এজেন্ট ক্লাউড রান পরিষেবাতে ক্লিক করুন

9bf379c89e7fe625.png সম্পর্কে

  1. বার্গার-সার্ভিস URL টি কপি করুন, তারপর Edit এ ক্লিক করুন এবং নতুন সংস্করণ স্থাপন করুন

75a4a1a3b7fa3cd6.png সম্পর্কে

  1. তারপর, Variable & Secrets বিভাগে ক্লিক করুন।

4fcaa1176de7038d.png সম্পর্কে

  1. এরপর, Add ভ্যারিয়েবলে ক্লিক করুন এবং HOST_OVERRIDE মানটি সার্ভিস URL-এ সেট করুন (যেটি https://burger-agent-xxxxxxxxx.us-central1.run.app প্যাটার্ন সহ)

c160f7d90d219129.png সম্পর্কে

  1. অবশেষে, আপনার পরিষেবা পুনরায় স্থাপন করতে স্থাপন বোতামে ক্লিক করুন।

763bbc02ceac0e28.png সম্পর্কে

যখন আপনি https://burger-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json ব্রাউজারে আবার বার্গার-এজেন্ট এজেন্ট কার্ড অ্যাক্সেস করবেন, তখন url মানটি ইতিমধ্যেই সঠিকভাবে কনফিগার করা হবে।

9acf6c51329d6e91.png সম্পর্কে

৫. 🚀 পিৎজা বিক্রেতা এজেন্ট মোতায়েন - A2A সার্ভার

একইভাবে, পিৎজা এজেন্ট সোর্স কোডটি remote_seller_agents/pizza_agent ডিরেক্টরির অধীনে থাকে।

পূর্ববর্তী বার্গার-এজেন্ট স্থাপনের ধাপের মতো, remote_seller_agents/pizza_agent ডিরেক্টরির অধীনে থাকা সমস্ত ফাইল ইতিমধ্যেই আমাদের এজেন্টকে ক্লাউড রানে স্থাপন করার জন্য যথেষ্ট যাতে এটি একটি পরিষেবা হিসাবে অ্যাক্সেসযোগ্য হয়। এটি স্থাপন করতে নিম্নলিখিত কমান্ডটি চালান।

gcloud run deploy pizza-agent \
    --source remote_seller_agents/pizza_agent \
    --port=8080 \
    --allow-unauthenticated \
    --min 1 \
    --region us-central1 \
    --update-env-vars GOOGLE_CLOUD_LOCATION=us-central1 \
    --update-env-vars GOOGLE_CLOUD_PROJECT={your-project-id}

সফলভাবে স্থাপনের পর এটি এইরকম একটি লগ দেখাবে।

Service [pizza-agent] revision [pizza-agent-xxxxx-xxx] has been deployed and is serving 100 percent of traffic.
Service URL: https://pizza-agent-xxxxxxxxx.us-central1.run.app

আমরা যখন পরিষেবাটি স্থাপন করব তখন এখানকার xxxx অংশটি একটি অনন্য শনাক্তকারী হবে।

বার্গার এজেন্টের ক্ষেত্রেও একই কথা প্রযোজ্য, যখন আপনি ব্রাউজারের মাধ্যমে সেই স্থাপন করা পিৎজা এজেন্ট পরিষেবাগুলির https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json রুটে A2A সার্ভার এজেন্ট কার্ড অ্যাক্সেস করার চেষ্টা করেন, তখন এর এজেন্ট কার্ডে পিৎজা এজেন্ট url মানটি এখনও সঠিকভাবে কনফিগার করা হয়নি। আমাদের এর পরিবেশ ভেরিয়েবলে HOST_OVERRIDE যোগ করতে হবে।

পরিবেশ ভেরিয়েবলের মাধ্যমে এজেন্ট কার্ডে পিৎজা এজেন্ট URL মান আপডেট করা হচ্ছে

পিৎজা এজেন্ট পরিষেবাতে HOST_OVERRIDE যোগ করতে, নিম্নলিখিত পদক্ষেপগুলি অনুসরণ করুন

  1. ক্লাউড অনুসন্ধান করুন আপনার ক্লাউড কনসোলের উপরে অনুসন্ধান বারে চালান

f56ec00607eafb6f.png সম্পর্কে

  1. পূর্বে মোতায়েন করা পিৎজা-এজেন্ট ক্লাউড রান পরিষেবাতে ক্লিক করুন

d9840497ae8afa2c.png সম্পর্কে

  1. সম্পাদনা করুন এ ক্লিক করুন এবং নতুন সংস্করণ স্থাপন করুন

e45d52012bef34c6.png সম্পর্কে

  1. পিৎজা-সার্ভিস URL টি কপি করুন, তারপর Variable & Secrets বিভাগে ক্লিক করুন।

19265c4edc2be7ae.png সম্পর্কে

  1. এরপর, Add ভ্যারিয়েবলে ক্লিক করুন এবং HOST_OVERRIDE মানটি সার্ভিস URL-এ সেট করুন (যেটি https://pizza-agent-xxxxxxxxx.us-central1.run.app প্যাটার্ন সহ)

7a6bd93cb6f11b64.png সম্পর্কে

  1. অবশেষে, আপনার পরিষেবা পুনরায় স্থাপন করতে স্থাপন বোতামে ক্লিক করুন।

763bbc02ceac0e28.png সম্পর্কে

এখন, যখন আপনি আবার ব্রাউজারে pizza-agent এজেন্ট কার্ডটি অ্যাক্সেস করবেন https://pizza-agent-xxxxxxxxx.us-central1.run.app/.well-known/agent.json , তখন url মানটি ইতিমধ্যেই সঠিকভাবে কনফিগার করা হবে।

f682caa1d89c6b5d.png সম্পর্কে

এই মুহুর্তে, আমরা ইতিমধ্যেই ক্লাউড রানে বার্গার এবং পিৎজা উভয় পরিষেবাই সফলভাবে স্থাপন করেছি।

৬. 🚀 এজেন্ট ইঞ্জিনে ক্রয় কনসিয়ার্জ - A2A ক্লায়েন্ট স্থাপন করা

এই ধাপে, আমরা ক্রয়কারী কনসির্জ এজেন্ট মোতায়েন করব। এই এজেন্টের সাথেই আমরা যোগাযোগ করব।

d62d062dd6959e8.png সম্পর্কে

আমাদের ক্রয়কারী কনসিয়ারজ এজেন্টের সোর্স কোড purchasing_concierge ডিরেক্টরির অধীনে। এজেন্ট ইনিশিয়ালাইজেশনটি purchasing_concierge/purchasing_agent.py স্ক্রিপ্টে পরীক্ষা করা যেতে পারে।

এটি স্থাপন করতে এই পদক্ষেপগুলি অনুসরণ করুন:

  1. প্রথমে, আমাদের ক্লাউড স্টোরেজে আমাদের স্টেজিং স্টোরেজ তৈরি করতে হবে।
gcloud storage buckets create gs://purchasing-concierge-{your-project-id} --location=us-central1
  1. এখন, আমাদের প্রথমে .env ভেরিয়েবল প্রস্তুত করতে হবে, আসুন .env.example টি .env ফাইলে কপি করি।
cp .env.example .env
  1. এখন, .env ফাইলটি খুলুন এবং আপনি নিম্নলিখিত বিষয়বস্তু দেখতে পাবেন।
GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_PROJECT={your-project-id}
GOOGLE_CLOUD_LOCATION=us-central1
STAGING_BUCKET=gs://purchasing-concierge-{your-project-id}
PIZZA_SELLER_AGENT_URL={your-pizza-agent-url}
BURGER_SELLER_AGENT_URL={your-burger-agent-url}
AGENT_ENGINE_RESOURCE_NAME={your-agent-engine-resource-name}

এই এজেন্টটি বার্গার এবং পিৎজা এজেন্টের সাথে যোগাযোগ করবে, তাই আমাদের উভয়ের জন্য সঠিক শংসাপত্র সরবরাহ করতে হবে। আমাদের পূর্ববর্তী পদক্ষেপগুলি থেকে ক্লাউড রান URL সহ PIZZA_SELLER_AGENT_URL এবং BURGER_SELLER_AGENT_URL আপডেট করতে হবে।

যদি আপনি এটি ভুলে যান, তাহলে Cloud Run কনসোলে যান। আপনার কনসোলের উপরে সার্চ বারে "Cloud Run" টাইপ করুন এবং Cloud Run আইকনে ডান ক্লিক করে এটি একটি নতুন ট্যাবে খুলুন।

f56ec00607eafb6f.png সম্পর্কে

আপনি নীচের চিত্রের মতো আমাদের পূর্ববর্তী মোতায়েন করা রিমোট বিক্রেতা এজেন্ট পরিষেবাগুলি দেখতে পাবেন।

561e3d125ae54e35.png সম্পর্কে

এখন ঐ পরিষেবাগুলির পাবলিক URL দেখতে, পরিষেবাগুলির একটিতে ক্লিক করুন এবং আপনাকে পরিষেবার বিবরণ পৃষ্ঠায় পুনঃনির্দেশিত করা হবে। আপনি অঞ্চলের তথ্যের ঠিক পাশে উপরের অংশে URLটি দেখতে পাবেন।

382c2094967718ae.png সম্পর্কে

চূড়ান্ত পরিবেশ ভেরিয়েবলটি এর মতো দেখতে হবে।

GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_PROJECT={your-project-id}
GOOGLE_CLOUD_LOCATION=us-central1
STAGING_BUCKET=gs://purchasing-concierge-{your-project-id}
PIZZA_SELLER_AGENT_URL=https://pizza-agent-xxxxx.us-central1.run.app
BURGER_SELLER_AGENT_URL=https://burger-agent-xxxxx.us-central1.run.app
AGENT_ENGINE_RESOURCE_NAME={your-agent-engine-resource-name}
  1. এখন, আমরা আমাদের ক্রয়কারী কনসিয়ার এজেন্ট স্থাপন করতে প্রস্তুত। আমরা এটি এজেন্ট ইঞ্জিনে স্থাপন করব এবং স্থাপনার কোডটি deploy_to_agent_engine.py স্ক্রিপ্টের ভিতরে রয়েছে।

আমরা স্ক্রিপ্টটি চালিয়ে এটি স্থাপন করতে পারি:

uv run deploy_to_agent_engine.py

সফলভাবে স্থাপনের পর এটি এইরকম একটি লগ দেখাবে। এটি আপনাকে এজেন্ট ইঞ্জিন রিসোর্সের নাম "projects/xxxx/locations/us-central1/reasoningEngines/yyyy" দেখাবে।

AgentEngine created. Resource name: projects/xxxx/locations/us-central1/reasoningEngines/yyyy
To use this AgentEngine in another session:
agent_engine = vertexai.agent_engines.get('projects/xxxx/locations/us-central1/reasoningEngines/yyyy)
Deployed remote app resource: projects/xxxx/locations/us-central1/reasoningEngines/xxxx

এবং যখন আমরা এটি এজেন্ট ইঞ্জিন ড্যাশবোর্ডে পরিদর্শন করি, (সার্চ বারে "এজেন্ট ইঞ্জিন" অনুসন্ধান করুন) তখন এটি আমাদের পূর্ববর্তী স্থাপনাটি দেখাবে।

765cdbdbbc3a94bc.png সম্পর্কে

আপনি এজেন্ট ইঞ্জিন রিসোর্স নামটি সেখানে প্রদর্শিত হচ্ছে কিনা তাও পরীক্ষা করতে পারেন। তারপর, আমরা এটি পরীক্ষা করার জন্য এই রিসোর্স নামটি ব্যবহার করতে পারি।

এরপর, .env ফাইলে AGENT_ENGINE_RESOURCE_NAME এই মান দিয়ে আপডেট করুন । নিশ্চিত করুন যে আপনি সঠিক এজেন্ট ইঞ্জিন রিসোর্স নামটি প্রদান করেছেন। আপনার .env ফাইলটি এইরকম দেখাবে:

GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_PROJECT={your-project-id}
GOOGLE_CLOUD_LOCATION=us-central1
STAGING_BUCKET=gs://purchasing-concierge-{your-project-id}
PIZZA_SELLER_AGENT_URL=https://pizza-agent-xxxxx.us-central1.run.app
BURGER_SELLER_AGENT_URL=https://burger-agent-xxxxx.us-central1.run.app
AGENT_ENGINE_RESOURCE_NAME=projects/xxxx/locations/us-central1/reasoningEngines/yyyy

এজেন্ট ইঞ্জিনে মোতায়েন করা এজেন্ট পরীক্ষা করা হচ্ছে

এজেন্ট ইঞ্জিনের সাথে ইন্টারঅ্যাকশন curl কমান্ড এবং SDK এর মাধ্যমে করা যেতে পারে। উদাহরণস্বরূপ, ডিপ্লয় করা এজেন্টের সাথে ইন্টারঅ্যাকশন করার চেষ্টা করার জন্য নিম্নলিখিত কমান্ডটি চালান।

এজেন্টটি সফলভাবে স্থাপন করা হয়েছে কিনা তা পরীক্ষা করার জন্য আপনি এই কোয়েরিটি পাঠানোর চেষ্টা করতে পারেন। নিম্নলিখিত test_agent_engine.sh স্ক্রিপ্টটি চালান।

bash test_agent_engine.sh

আপনি স্ক্রিপ্টটি পরীক্ষা করে দেখতে পারেন যে আমরা এজেন্টকে "উপলব্ধ বার্গার মেনু তালিকাভুক্ত করুন" জিজ্ঞাসা করার চেষ্টা করছি।

যদি সফল হয় তবে এটি আপনার কনসোলে এইভাবে স্ট্রিম করা বেশ কয়েকটি প্রতিক্রিয়া ইভেন্ট দেখাবে।

{
  "content": {
    "parts": [
      {
        "text": "Here is our burger menu:\n- Classic Cheeseburger: IDR 85K\n- Double Cheeseburger: IDR 110K\n- Spicy Chicken Burger: IDR 80K\n- Spicy Cajun Burger: IDR 85K"
      }
    ],
    "role": "model"
  },
  "usage_metadata": {
    "candidates_token_count": 51,
    "candidates_tokens_details": [
      {
        "modality": "TEXT",
        "token_count": 51
      }
    ],
    "prompt_token_count": 907,
    "prompt_tokens_details": [
      {
        "modality": "TEXT",
        "token_count": 907
      }
    ],
    "total_token_count": 958,
    "traffic_type": "ON_DEMAND"
  },
  "invocation_id": "e-14679918-af68-45f1-b942-cf014368a733",
  "author": "purchasing_agent",
  "actions": {
    "state_delta": {},
    "artifact_delta": {},
    "requested_auth_configs": {}
  },
  "id": "dbe7fc43-b82a-4f3e-82aa-dd97afa8f15b",
  "timestamp": 1754287348.941454
}

আমরা পরবর্তী ধাপে UI ব্যবহার করার চেষ্টা করব, তবে প্রথমে A2A ক্লায়েন্টদের মূল উপাদান এবং সাধারণ প্রবাহ কী তা নিয়ে আলোচনা করা যাক।

৭. 🚀 ইন্টিগ্রেশন টেস্টিং এবং পেলোড পরিদর্শন

এবার আসুন ওয়েব UI ব্যবহার করে রিমোট এজেন্ট ইন্টারঅ্যাকশনের মাধ্যমে আমাদের ক্রয় কনসিয়ারজ পরীক্ষা করি। একটি Gradio অ্যাপ স্থাপন করতে নিম্নলিখিত কমান্ডটি চালান। এই অ্যাপটি চালানোর জন্য আপনাকে ইতিমধ্যেই .env ফাইলটি সঠিকভাবে পূরণ করতে হবে।

uv run purchasing_concierge_ui.py

সফল হলে এটি নিম্নলিখিত আউটপুট দেখাবে

* Running on local URL:  http://0.0.0.0:8080
* To create a public link, set `share=True` in `launch()`.

তারপর, Ctrl + টার্মিনালে http://0.0.0.0:8080 url-এ ক্লিক করুন অথবা ওয়েব UI খুলতে ওয়েব প্রিভিউ বোতামে ক্লিক করুন।

bf615f875b1d870.png সম্পর্কে

এভাবে কথোপকথন করার চেষ্টা করুন:

  • আমাকে বার্গার এবং পিৎজার মেনু দেখাও।
  • আমি ১টি বারবিকিউ চিকেন পিৎজা এবং ১টি মশলাদার কাজুন বার্গার অর্ডার করতে চাই।

এবং অর্ডার শেষ না হওয়া পর্যন্ত কথোপকথন চালিয়ে যান। ইন্টারঅ্যাকশনটি কেমন চলছে এবং টুল কল এবং রেসপন্স কী তা পরীক্ষা করুন? নিচের ছবিটি ইন্টারঅ্যাকশন ফলাফলের একটি উদাহরণ।

e3ada3143680efff.png

f661b0721ec6fbb0.png সম্পর্কে

789782458635578e.png সম্পর্কে

5d66b087aed1743e.png সম্পর্কে

আমরা দেখতে পাচ্ছি যে 2টি ভিন্ন এজেন্টের সাথে যোগাযোগ করলে 2টি ভিন্ন আচরণ পাওয়া যায় এবং A2A এটি ভালোভাবে পরিচালনা করতে পারে। পিৎজা বিক্রেতা এজেন্ট সরাসরি আমাদের ক্রয় এজেন্টের অনুরোধ গ্রহণ করে, যেখানে বার্গার এজেন্টকে আমাদের অনুরোধটি এগিয়ে নেওয়ার আগে আমাদের নিশ্চিতকরণের প্রয়োজন হয় এবং আমরা নিশ্চিত করার পরে এজেন্ট বার্গার এজেন্টের কাছে নিশ্চিতকরণের উপর নির্ভর করতে পারে।

এখন, আমরা A2A এর মৌলিক ধারণাগুলি সম্পন্ন করেছি এবং দেখি কিভাবে এটি ক্লায়েন্ট এবং সার্ভার আর্কিটেকচার হিসাবে বাস্তবায়িত হয়েছে।

৮. 💡 [কোড ব্যাখ্যা] A2A সার্ভার ধারণা এবং বাস্তবায়ন

রিমোট বিক্রেতা এজেন্ট ইনিশিয়ালাইজেশনটি remote_seller_agents/*/agent.py স্ক্রিপ্টে পরিদর্শন করা যেতে পারে। এখানে বিক্রেতা এজেন্টদের কোড স্নিপেট রয়েছে।

বার্গার এজেন্ট

from crewai import Agent, Crew, LLM, Task, Process
from crewai.tools import tool

...

       model = LLM(
            model="vertex_ai/gemini-2.5-flash-lite",  # Use base model name without provider prefix
        )
        burger_agent = Agent(
            role="Burger Seller Agent",
            goal=(
                "Help user to understand what is available on burger menu and price also handle order creation."
            ),
            backstory=("You are an expert and helpful burger seller agent."),
            verbose=False,
            allow_delegation=False,
            tools=[create_burger_order],
            llm=model,
        )

        agent_task = Task(
            description=self.TaskInstruction,
            agent=burger_agent,
            expected_output="Response to the user in friendly and helpful manner",
        )

        crew = Crew(
            tasks=[agent_task],
            agents=[burger_agent],
            verbose=False,
            process=Process.sequential,
        )

        inputs = {"user_prompt": query, "session_id": sessionId}
        response = crew.kickoff(inputs)
        return response

...

পিৎজা এজেন্ট

from langchain_google_vertexai import ChatVertexAI
from langgraph.prebuilt import create_react_agent

...

self.model = ChatVertexAI(
    model="gemini-2.5-flash-lite",
    location=os.getenv("GOOGLE_CLOUD_LOCATION"),
    project=os.getenv("GOOGLE_CLOUD_PROJECT"),
)
self.tools = [create_pizza_order]
self.graph = create_react_agent(
    self.model,
    tools=self.tools,
    checkpointer=memory,
    prompt=self.SYSTEM_INSTRUCTION,
)

...

আপনি দেখতে পাচ্ছেন, এই দুটি এজেন্ট ক্লায়েন্ট এজেন্টের (ADK) তুলনায় সম্পূর্ণ ভিন্ন ফ্রেমওয়ার্ক (CrewAI এবং Langgraph) দিয়ে তৈরি। A2A এর সাথে এটি কোনও সমস্যা নয়, একে অপরের সাথে যোগাযোগের জন্য তাদের অভ্যন্তরীণ কোড ভাগ করে নেওয়ার প্রয়োজন নেই, কোন ফ্রেমওয়ার্ক ব্যবহার করা হচ্ছে, কোন ভাষা ব্যবহার করা হচ্ছে, বা কোথায় স্থাপন করা হচ্ছে তা বিবেচ্য নয়।

A2A সার্ভারের মূল উপাদানগুলি

এবার A2A সার্ভারের মূল ধারণা এবং উপাদানগুলি নিয়ে আলোচনা করা যাক।

এজেন্ট কার্ড

প্রতিটি A2A সার্ভারের একটি এজেন্ট কার্ড থাকতে হবে যা /.well-known/agent.json রিসোর্সে অ্যাক্সেসযোগ্য। এটি A2A ক্লায়েন্টের আবিষ্কারের পর্যায়ে সহায়তা করার জন্য, যা এজেন্টকে কীভাবে অ্যাক্সেস করতে হবে এবং এর সমস্ত ক্ষমতা সম্পর্কে সম্পূর্ণ তথ্য এবং প্রসঙ্গ দেবে। এটি Swagger বা Postman ব্যবহার করে সু-নথিভুক্ত API ডকুমেন্টেশনের সাথে কিছুটা অনুরূপ।

এটি আমাদের মোতায়েন করা বার্গার এজেন্ট এজেন্ট কার্ডের বিষয়বস্তু।

{
  "capabilities": {
    "streaming": true
  },
  "defaultInputModes": [
    "text",
    "text/plain"
  ],
  "defaultOutputModes": [
    "text",
    "text/plain"
  ],
  "description": "Helps with creating burger orders",
  "name": "burger_seller_agent",
  "protocolVersion": "0.2.6",
  "skills": [
    {
      "description": "Helps with creating burger orders",
      "examples": [
        "I want to order 2 classic cheeseburgers"
      ],
      "id": "create_burger_order",
      "name": "Burger Order Creation Tool",
      "tags": [
        "burger order creation"
      ]
    }
  ],
  "url": "https://burger-agent-109790610330.us-central1.run.app",
  "version": "1.0.0"
}

এই এজেন্ট কার্ডগুলি অনেক গুরুত্বপূর্ণ উপাদান তুলে ধরে, যেমন এজেন্ট দক্ষতা, স্ট্রিমিং ক্ষমতা, সমর্থিত পদ্ধতি, প্রোটোকল সংস্করণ এবং অন্যান্য বিষয়।

এই সমস্ত তথ্য একটি সঠিক যোগাযোগ ব্যবস্থা তৈরি করতে ব্যবহার করা যেতে পারে যাতে A2A ক্লায়েন্ট সঠিকভাবে যোগাযোগ করতে পারে। সমর্থিত পদ্ধতি এবং প্রমাণীকরণ ব্যবস্থা নিশ্চিত করে যে যোগাযোগ সঠিকভাবে প্রতিষ্ঠিত হতে পারে, এবং এজেন্ট skills তথ্য A2A ক্লায়েন্ট সিস্টেম প্রম্পটে এমবেড করা যেতে পারে যাতে ক্লায়েন্টের এজেন্টকে দূরবর্তী এজেন্টের ক্ষমতা এবং ব্যবহার করা দক্ষতা সম্পর্কে প্রেক্ষাপট দেওয়া যায়। এই এজেন্ট কার্ডের জন্য আরও বিস্তারিত ক্ষেত্রগুলি এই ডকুমেন্টেশনে পাওয়া যাবে।

আমাদের কোডে, এজেন্ট কার্ডের বাস্তবায়ন A2A পাইথন sdk ব্যবহার করে প্রতিষ্ঠিত হয়, বাস্তবায়নের জন্য নীচের remote_seller_agents/burger_agent/main.py স্নিপেটটি পরীক্ষা করুন।

...

        capabilities = AgentCapabilities(streaming=True)
        skill = AgentSkill(
            id="create_burger_order",
            name="Burger Order Creation Tool",
            description="Helps with creating burger orders",
            tags=["burger order creation"],
            examples=["I want to order 2 classic cheeseburgers"],
        )
        agent_host_url = (
            os.getenv("HOST_OVERRIDE")
            if os.getenv("HOST_OVERRIDE")
            else f"http://{host}:{port}/"
        )
        agent_card = AgentCard(
            name="burger_seller_agent",
            description="Helps with creating burger orders",
            url=agent_host_url,
            version="1.0.0",
            defaultInputModes=BurgerSellerAgent.SUPPORTED_CONTENT_TYPES,
            defaultOutputModes=BurgerSellerAgent.SUPPORTED_CONTENT_TYPES,
            capabilities=capabilities,
            skills=[skill],
        )

...

আমরা সেখানে বেশ কয়েকটি ক্ষেত্র দেখতে পাচ্ছি যেমন:

  1. AgentCapabilities : এজেন্ট পরিষেবা দ্বারা সমর্থিত অতিরিক্ত ঐচ্ছিক ফাংশনের ঘোষণা, যেমন স্ট্রিমিং এবং/অথবা পুশ বিজ্ঞপ্তি সমর্থনের ক্ষমতা
  2. AgentSkill : এজেন্ট দ্বারা সমর্থিত টুল বা ফাংশন
  3. Input/OutputModes : সমর্থিত ইনপুট/আউটপুট ধরণের পদ্ধতি
  4. Url : এজেন্টের সাথে যোগাযোগের ঠিকানা

এই কনফিগারেশনে আমরা একটি ডায়নামিক এজেন্ট হোস্ট ইউআরএল তৈরি করি, যাতে স্থানীয় টেস্টিং এবং ক্লাউড স্থাপনার মধ্যে স্যুইচ করা সহজ হয়, তাই আমাদের পূর্ববর্তী ধাপে HOST_OVERRIDE ভেরিয়েবল যোগ করতে হবে।

টাস্ক সারি এবং এজেন্ট এক্সিকিউটর

A2A সার্ভার বিভিন্ন এজেন্ট বা ব্যবহারকারীদের কাছ থেকে অনুরোধগুলি পরিচালনা করতে পারে এবং প্রতিটি কাজকে নিখুঁতভাবে আলাদা করতে সক্ষম হতে পারে। এগুলির প্রেক্ষাপট আরও ভালভাবে কল্পনা করার জন্য, আপনি নীচের ছবিটি পরীক্ষা করতে পারেন।

10c75db36741da90.jpeg সম্পর্কে

সুতরাং, প্রতিটি A2A সার্ভার আগত কাজগুলি ট্র্যাক করতে এবং সে সম্পর্কে সঠিক তথ্য সংরক্ষণ করতে সক্ষম হওয়া উচিত। A2A SDK A2A সার্ভারে এই চ্যালেঞ্জ মোকাবেলা করার জন্য মডিউল সরবরাহ করে। প্রথমে, আমরা আগত অনুরোধটি কীভাবে পরিচালনা করতে চাই তার যুক্তিটি তাৎক্ষণিকভাবে নির্ধারণ করতে পারি। AgentExecutor abstract ক্লাসটি উত্তরাধিকার সূত্রে পেয়ে আমরা কীভাবে টাস্ক এক্সিকিউশন এবং বাতিলকরণ পরিচালনা করতে চাই তা নিয়ন্ত্রণ করতে পারি। এই উদাহরণ বাস্তবায়নটি remote_seller_agents/burger_agent/agent_executor.py মডিউলে পরিদর্শন করা যেতে পারে (পিৎজা বিক্রেতার ক্ষেত্রে অনুরূপ পথ)।

...

class BurgerSellerAgentExecutor(AgentExecutor):
    """Burger Seller AgentExecutor."""

    def __init__(self):
        self.agent = BurgerSellerAgent()

    async def execute(
        self,
        context: RequestContext,
        event_queue: EventQueue,
    ) -> None:
        query = context.get_user_input()
        try:
            result = self.agent.invoke(query, context.context_id)
            print(f"Final Result ===> {result}")

            parts = [Part(root=TextPart(text=str(result)))]
            await event_queue.enqueue_event(
                completed_task(
                    context.task_id,
                    context.context_id,
                    [new_artifact(parts, f"burger_{context.task_id}")],
                    [context.message],
                )
            )
        except Exception as e:
            print("Error invoking agent: %s", e)
            raise ServerError(error=ValueError(f"Error invoking agent: {e}")) from e

    async def cancel(
        self, request: RequestContext, event_queue: EventQueue
    ) -> Task | None:
        raise ServerError(error=UnsupportedOperationError())

...

উপরের কোডে, আমরা একটি মৌলিক প্রক্রিয়াকরণ স্কিম বাস্তবায়ন করি যেখানে এজেন্টকে অনুরোধ আসার সাথে সাথে সরাসরি আহ্বান করা হবে এবং আহ্বান শেষ হওয়ার পরে সম্পন্ন টাস্ক ইভেন্টগুলি প্রেরণ করা হবে। তবে আমরা এখানে বাতিলকরণ পদ্ধতিটি বাস্তবায়ন করিনি কারণ এটি একটি স্বল্পমেয়াদী অপারেশন হিসাবে বিবেচিত হয়েছিল।

এক্সিকিউটর তৈরি করার পর, আমরা HTTP সার্ভারকে স্পিন আপ করার জন্য সরাসরি বিল্ট-ইন DefaultRequestHandler, InMemoryTaskStore এবং A2AStarletteApplication ব্যবহার করতে পারি। এই বাস্তবায়নটি remote_seller_agents/burger_agent/__main__.py তে পরিদর্শন করা যেতে পারে।

...

        request_handler = DefaultRequestHandler(
            agent_executor=BurgerSellerAgentExecutor(),
            task_store=InMemoryTaskStore(),
        )
        server = A2AStarletteApplication(
            agent_card=agent_card, http_handler=request_handler
        )

        uvicorn.run(server.build(), host=host, port=port)

...

এই মডিউলটি আপনাকে এজেন্ট কার্ড অ্যাক্সেস করার জন্য /.well-known/agent.json রুট এবং A2A প্রোটোকল সমর্থন করার জন্য POST এন্ডপয়েন্ট বাস্তবায়ন প্রদান করবে।

সারাংশ

সংক্ষেপে, এখন পর্যন্ত আমাদের মোতায়েন করা A2A সার্ভার Python SDK ব্যবহার করে যা নীচের দুটি কার্যকারিতা সমর্থন করতে পারে:

  1. /.well-known/agent.json রুটে এজেন্ট কার্ড প্রকাশ করা হচ্ছে
  2. মেমরি টাস্ক কিউয়িং এর মাধ্যমে JSON-RPC অনুরোধ পরিচালনা করুন

এই কার্যকারিতাগুলি শুরু করার এন্ট্রি পয়েন্টটি __main__.py স্ক্রিপ্টে ( remote_seller_agents/burger_agent অথবা remote_seller_agents/pizza_agent ) পরিদর্শন করা যেতে পারে।

৯. 💡 [কোড ব্যাখ্যা] এজেন্ট ইঞ্জিন স্থাপন

purchasing_concierge/purchasing_agent.py ওয়েবসাইটে ক্রয়কারী কনসির্জ এজেন্টের কোড স্নিপেট এখানে দেওয়া হল:

from google.adk import Agent

...

def create_agent(self) -> Agent:
        return Agent(
            model="gemini-2.5-flash-lite",
            name="purchasing_agent",
            instruction=self.root_instruction,
            before_model_callback=self.before_model_callback,
            before_agent_callback=self.before_agent_callback,
            description=(
                "This purchasing agent orchestrates the decomposition of the user purchase request into"
                " tasks that can be performed by the seller agents."
            ),
            tools=[
                self.send_task,
            ],
        )

...

এই এজেন্টটি ADK ব্যবহার করে তৈরি করা হয়েছে এবং এজেন্ট ইঞ্জিনে স্থাপন করা হয়েছে।

Vertex AI Agent Engine হল এমন কিছু পরিষেবার সেট যা ডেভেলপারদের উৎপাদনে AI এজেন্ট স্থাপন, পরিচালনা এবং স্কেল করতে সক্ষম করে। এটি উৎপাদনে এজেন্টদের স্কেল করার জন্য অবকাঠামো পরিচালনা করে যাতে আমরা অ্যাপ্লিকেশন তৈরিতে মনোনিবেশ করতে পারি। আপনি এই নথিতে এই সম্পর্কে আরও পড়তে পারেন। যদি আগে আমাদের এজেন্ট পরিষেবা (যেমন প্রধান সার্ভার স্ক্রিপ্ট এবং ডকারফাইল) স্থাপনের জন্য প্রয়োজনীয় ফাইল প্রস্তুত করার প্রয়োজন হয়, তাহলে এই ক্ষেত্রে আমরা ADK এবং এজেন্ট ইঞ্জিনের সংমিশ্রণ ব্যবহার করে আমাদের নিজস্ব ব্যাকএন্ড পরিষেবা তৈরি করার প্রয়োজন ছাড়াই পাইথন স্ক্রিপ্ট থেকে সরাসরি আমাদের এজেন্ট স্থাপন করতে পারি।

এই টিউটোরিয়ালে আমরা deploy_to_agent_engine.py স্ক্রিপ্ট ব্যবহার করে স্থাপন করব, যার বিষয়বস্তু নীচে দেখানো হয়েছে।

import vertexai
from vertexai.preview import reasoning_engines
from vertexai import agent_engines
from dotenv import load_dotenv
import os
from purchasing_concierge.agent import root_agent

load_dotenv()

PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT")
LOCATION = os.getenv("GOOGLE_CLOUD_LOCATION")
STAGING_BUCKET = os.getenv("STAGING_BUCKET")

vertexai.init(
    project=PROJECT_ID,
    location=LOCATION,
    staging_bucket=STAGING_BUCKET,
)

adk_app = reasoning_engines.AdkApp(
    agent=root_agent,
)

remote_app = agent_engines.create(
    agent_engine=adk_app,
    display_name="purchasing-concierge",
    requirements=[
        "google-cloud-aiplatform[adk,agent_engines]",
        "a2a-sdk==0.2.16",
    ],
    extra_packages=[
        "./purchasing_concierge",
    ],
    env_vars={
        "GOOGLE_GENAI_USE_VERTEXAI": os.environ["GOOGLE_GENAI_USE_VERTEXAI"],
        "PIZZA_SELLER_AGENT_URL": os.environ["PIZZA_SELLER_AGENT_URL"],
        "BURGER_SELLER_AGENT_URL": os.environ["BURGER_SELLER_AGENT_URL"],
    },
)

print(f"Deployed remote app resource: {remote_app.resource_name}")

আমাদের ADK এজেন্টকে এজেন্ট ইঞ্জিনে স্থাপন করার জন্য এই ধাপগুলি প্রয়োজনীয়। প্রথমে, আমাদের ADK root_agent থেকে একটি AdkApp অবজেক্ট তৈরি করতে হবে। তারপর আমরা adk_app অবজেক্ট প্রদান করে, requirements ফিল্ডে প্রয়োজনীয়তা উল্লেখ করে, extra_packages এ এজেন্ট ডিরেক্টরি পাথ উল্লেখ করে (প্রয়োজনে আপনি এখানে অন্যান্য ডিরেক্টরি এবং ফাইলও প্রদান করতে পারেন) এবং প্রয়োজনীয় env ভেরিয়েবল প্রদান করে agent_engines.create পদ্ধতিটি চালাতে পারি।

১০. 💡 [কোড ব্যাখ্যা] A2A ক্লায়েন্ট ধারণা এবং বাস্তবায়ন

e7e3224d05b725f0.jpeg সম্পর্কে

উপরে দেখানো চিত্রটি A2A মিথস্ক্রিয়ার সাধারণ প্রবাহ:

  1. ক্লায়েন্ট /.well-known/agent.json রুটে প্রদত্ত রিমোট এজেন্ট URL-এ যেকোনো প্রকাশিত এজেন্ট কার্ড খুঁজে বের করার চেষ্টা করবে।
  2. তারপর, যখন প্রয়োজন হবে তখন এটি সেই এজেন্টকে একটি বার্তা পাঠাবে যার মধ্যে বার্তা এবং প্রয়োজনীয় মেটাডেটা প্যারামিটার (যেমন সেশন আইডি, ঐতিহাসিক প্রেক্ষাপট, ইত্যাদি) থাকবে। সার্ভার এই বার্তাটিকে একটি কাজ হিসেবে দেখবে যা সম্পন্ন করতে হবে।
  3. A2A সার্ভার অনুরোধটি প্রক্রিয়া করে, যদি সার্ভার পুশ বিজ্ঞপ্তি সমর্থন করে, তবে এটি টাস্ক প্রক্রিয়াকরণ জুড়ে কিছু বিজ্ঞপ্তি প্রকাশ করতে সক্ষম হবে (এই কার্যকারিতাটি এই কোডল্যাবের আওতার বাইরে)
  4. কাজ শেষ হওয়ার পর, A2A সার্ভার প্রতিক্রিয়া আর্টিফ্যাক্টটি ক্লায়েন্টের কাছে ফেরত পাঠাবে।

উপরের মিথস্ক্রিয়াগুলির মূল বিষয়গুলির মধ্যে কিছু হল এই আইটেমগুলি (আরও বিশদ এখানে পড়া যেতে পারে):

  • বার্তা: একজন ক্লায়েন্ট এবং একজন দূরবর্তী এজেন্টের মধ্যে যোগাযোগের একটি মোড়
  • কাজ : A2A দ্বারা পরিচালিত কাজের মৌলিক একক, একটি অনন্য আইডি দ্বারা চিহ্নিত
  • আর্টিফ্যাক্ট: একটি আউটপুট (যেমন, একটি ডকুমেন্ট, ছবি, স্ট্রাকচার্ড ডেটা) যা এজেন্ট দ্বারা তৈরি করা হয় একটি কাজের ফলে, যা অংশগুলি নিয়ে গঠিত।
  • অংশ: একটি বার্তা বা শিল্পকর্মের মধ্যে থাকা বিষয়বস্তুর ক্ষুদ্রতম একক। অংশটি একটি টেক্সট, ছবি, ভিডিও, ফাইল ইত্যাদি হতে পারে।

কার্ড আবিষ্কার

যখন A2A ক্লায়েন্ট পরিষেবাটি আপগ্রেড করা হয়, তখন সাধারণত এজেন্ট কার্ডের তথ্য সংগ্রহ করার চেষ্টা করা হয় এবং প্রয়োজনের সময় সহজেই অ্যাক্সেস করার জন্য এটি সংরক্ষণ করা হয়। এই কোডল্যাবে, আমরা এটি before_agent_callback এ বাস্তবায়ন করি, আপনি purchasing_concierge/purchasing_agent.py এ বাস্তবায়ন দেখতে পারেন নীচের কোড স্নিপেটটি দেখুন।

...

async def before_agent_callback(self, callback_context: CallbackContext):
        if not self.a2a_client_init_status:
            httpx_client = httpx.AsyncClient(timeout=httpx.Timeout(timeout=30))
            for address in self.remote_agent_addresses:
                card_resolver = A2ACardResolver(
                    base_url=address, httpx_client=httpx_client
                )
                try:
                    card = await card_resolver.get_agent_card()
                    remote_connection = RemoteAgentConnections(
                        agent_card=card, agent_url=card.url
                    )
                    self.remote_agent_connections[card.name] = remote_connection
                    self.cards[card.name] = card
                except httpx.ConnectError:
                    print(f"ERROR: Failed to get agent card from : {address}")
            agent_info = []
            for ra in self.list_remote_agents():
                agent_info.append(json.dumps(ra))
            self.agents = "\n".join(agent_info)

...

এখানে, আমরা বিল্ট-ইন A2A ক্লায়েন্ট A2ACardResolver মডিউল ব্যবহার করে সমস্ত উপলব্ধ এজেন্ট কার্ড অ্যাক্সেস করার চেষ্টা করি, তারপর আমরা এজেন্টকে বার্তা পাঠানোর জন্য প্রয়োজনীয় সংযোগ সংগ্রহ করি, তারপরে আমাদের সমস্ত উপলব্ধ এজেন্ট এবং এর স্পেসিফিকেশন প্রম্পটে তালিকাভুক্ত করতে হবে যাতে আমাদের এজেন্ট জানতে পারে যে এটি এই এজেন্টদের সাথে যোগাযোগ করতে পারে।

প্রম্পট এবং সেন্ড টাস্ক টুল

এটি হল আমাদের ADK এজেন্টকে প্রম্পট এবং টুল যা আমরা এখানে প্রদান করি।

...

def root_instruction(self, context: ReadonlyContext) -> str:
    current_agent = self.check_active_agent(context)
    return f"""You are an expert purchasing delegator that can delegate the user product inquiry and purchase request to the
appropriate seller remote agents.

Execution:
- For actionable tasks, you can use `send_task` to assign tasks to remote agents to perform.
- When the remote agent is repeatedly asking for user confirmation, assume that the remote agent doesn't have access to user's conversation context. 
So improve the task description to include all the necessary information related to that agent
- Never ask user permission when you want to connect with remote agents. If you need to make connection with multiple remote agents, directly
connect with them without asking user permission or asking user preference
- Always show the detailed response information from the seller agent and propagate it properly to the user. 
- If the remote seller is asking for confirmation, rely the confirmation question to the user if the user haven't do so. 
- If the user already confirmed the related order in the past conversation history, you can confirm on behalf of the user
- Do not give irrelevant context to remote seller agent. For example, ordered pizza item is not relevant for the burger seller agent
- Never ask order confirmation to the remote seller agent 

Please rely on tools to address the request, and don't make up the response. If you are not sure, please ask the user for more details.
Focus on the most recent parts of the conversation primarily.

If there is an active agent, send the request to that agent with the update task tool.

Agents:
{self.agents}

Current active seller agent: {current_agent["active_agent"]}
"""

...

async def send_task(self, agent_name: str, task: str, tool_context: ToolContext):
        """Sends a task to remote seller agent

        This will send a message to the remote agent named agent_name.

        Args:
            agent_name: The name of the agent to send the task to.
            task: The comprehensive conversation context summary
                and goal to be achieved regarding user inquiry and purchase request.
            tool_context: The tool context this method runs in.

        Yields:
            A dictionary of JSON data.
        """
        if agent_name not in self.remote_agent_connections:
            raise ValueError(f"Agent {agent_name} not found")
        state = tool_context.state
        state["active_agent"] = agent_name
        client = self.remote_agent_connections[agent_name]
        if not client:
            raise ValueError(f"Client not available for {agent_name}")
        session_id = state["session_id"]
        task: Task
        message_id = ""
        metadata = {}
        if "input_message_metadata" in state:
            metadata.update(**state["input_message_metadata"])
            if "message_id" in state["input_message_metadata"]:
                message_id = state["input_message_metadata"]["message_id"]
        if not message_id:
            message_id = str(uuid.uuid4())

        payload = {
            "message": {
                "role": "user",
                "parts": [
                    {"type": "text", "text": task}
                ],  # Use the 'task' argument here
                "messageId": message_id,
                "contextId": session_id,
            },
        }

        message_request = SendMessageRequest(
            id=message_id, params=MessageSendParams.model_validate(payload)
        )
        send_response: SendMessageResponse = await client.send_message(
            message_request=message_request
        )
        print(
            "send_response",
            send_response.model_dump_json(exclude_none=True, indent=2),
        )

        if not isinstance(send_response.root, SendMessageSuccessResponse):
            print("received non-success response. Aborting get task ")
            return None

        if not isinstance(send_response.root.result, Task):
            print("received non-task response. Aborting get task ")
            return None

        return send_response.root.result

...

প্রম্পটে, আমরা আমাদের ক্রয়কারী কনসিয়ারজ এজেন্টকে সমস্ত উপলব্ধ রিমোট এজেন্টের নাম এবং বিবরণ দিই, এবং self.send_task টুলে আমরা এজেন্টের সাথে সংযোগ স্থাপনের জন্য উপযুক্ত ক্লায়েন্ট পুনরুদ্ধার করার এবং SendMessageRequest অবজেক্ট ব্যবহার করে প্রয়োজনীয় মেটাডেটা পাঠানোর একটি প্রক্রিয়া প্রদান করি।

যোগাযোগ প্রোটোকল

টাস্ক ডেফিনিশন হলো A2A সার্ভারের মালিকানাধীন একটি ডোমেন। তবে, A2A ক্লায়েন্টের দৃষ্টিকোণ থেকে, তারা এটিকে সার্ভারে প্রেরিত একটি বার্তা হিসেবে দেখে। ক্লায়েন্ট থেকে আগত বার্তাগুলিকে কোন টাস্ক হিসেবে সংজ্ঞায়িত করা হবে এবং টাস্কটি সম্পন্ন করার জন্য ক্লায়েন্টের সাথে ইন্টারঅ্যাকশন প্রয়োজন কিনা তা সার্ভারের উপর নির্ভর করে। টাস্ক লাইফসাইকেল সম্পর্কে আরও বিস্তারিত জানতে এই ডকুমেন্টেশনটি পড়ুন। এর উচ্চ স্তরের ধারণাটি নীচে দৃশ্যমান করা যেতে পারে:

4f2a4c908e0fc75.jpeg সম্পর্কে

1810d38d264cb6a.jpeg সম্পর্কে

এই message -> এর বিনিময় কাজটি JSON-RPC স্ট্যান্ডার্ডের উপরে পেলোড ফর্ম্যাট ব্যবহার করে বাস্তবায়িত হয়, যেমনটি message/send প্রোটোকলের নীচের উদাহরণে দেখানো হয়েছে:

{
  # identifier for this request
  "id": "abc123",
  # version of JSON-RPC protocol
  "jsonrpc": "2.0",
  # method name
  "method": "message/send",
  # parameters/arguments of the method
  "params": {
    "message": "hi, what can you help me with?"
  }  
}

বিভিন্ন ধরণের যোগাযোগ সমর্থন করার জন্য (যেমন সিঙ্ক, স্ট্রিমিং, অ্যাসিঙ্ক) অথবা টাস্ক স্ট্যাটাসের জন্য বিজ্ঞপ্তি কনফিগার করার জন্য বিভিন্ন পদ্ধতি উপলব্ধ। এই টাস্ক ডেফিনিশন স্ট্যান্ডার্ডগুলি পরিচালনা করার জন্য A2A সার্ভারটি নমনীয়ভাবে কনফিগার করা যেতে পারে। এই পদ্ধতিগুলির বিশদ বিবরণ এই নথিতে পড়া যেতে পারে।

১১. 🎯 চ্যালেঞ্জ

এখন, আপনি কি প্রয়োজনীয় ফাইল প্রস্তুত করে নিজের হাতে ক্লাউডে Gradio অ্যাপটি স্থাপন করতে পারবেন? চ্যালেঞ্জ গ্রহণের সময় এসেছে!

১২. 🧹 পরিষ্কার করা

এই কোডল্যাবে ব্যবহৃত রিসোর্সের জন্য আপনার Google ক্লাউড অ্যাকাউন্টে চার্জ এড়াতে, এই পদক্ষেপগুলি অনুসরণ করুন:

  1. গুগল ক্লাউড কনসোলে, রিসোর্স পরিচালনা পৃষ্ঠায় যান।
  2. প্রকল্পের তালিকায়, আপনি যে প্রকল্পটি মুছতে চান তা নির্বাচন করুন এবং তারপরে মুছুন ক্লিক করুন।
  3. ডায়ালগে, প্রজেক্ট আইডি টাইপ করুন, এবং তারপর প্রজেক্টটি মুছে ফেলতে Shut down এ ক্লিক করুন।
  4. বিকল্পভাবে আপনি কনসোলে ক্লাউড রান এবং এজেন্ট ইঞ্জিনে যেতে পারেন, আপনার সবেমাত্র স্থাপন করা পরিষেবাটি নির্বাচন করুন এবং মুছে ফেলুন।