
Agent2Agent å ¥é (12) - ADK Agent
ãAgent2Agentãã®å ¬åŒãµã³ãã«ãADK Agentãã詊ããã®ã§ãŸãšããŸããã
åå
1. ADK Agent
Google Agent Development Kit (ADK) ã䜿çšããŠãA2A ã䜿çšããŠéä¿¡ããã·ã³ãã«ãªãã¡ã¯ããžã§ãã¬ãŒã¿ãäœæããŸãã
2. ã»ããã¢ãã
ã»ããã¢ããæé ã¯ã次ã®ãšããã§ãã
(1) ãããžã§ã¯ããã©ã«ãã®äœæ
mkdir adk_facts
cd adk_facts(2) Pythonã®ä»®æ³ç°å¢ã®æºåã
Python 3.11以äžã䜿çšããŸãã
ã»Mac
python -m venv .venv
source .venv/bin/activateã»Windows
python -m venv .venv
.venv\Scripts\activate(3) ããã±ãŒãžã®ã€ã³ã¹ããŒã«ã
pip install a2a-sdk uvicorn
pip install google-adk(4) Gemini APIããŒãç°å¢å€æ°ã«èšå®ã
export GOOGLE_API_KEY=<Gemini APIããŒ>3. A2AãšãŒãžã§ã³ãã®å®è£
3-1. ã³ã¢ãšãŒãžã§ã³ãã®å®çŸ©
Googleæ€çŽ¢ããŒã«ãæã€ADKãšãŒãžã§ã³ããæºåããŸãã
ã»agent.py
from google.adk.agents import Agent
from google.adk.tools import google_search
# ã³ã¢ãšãŒãžã§ã³ãã®æºå
root_agent = Agent(
name="facts_agent",
model="gemini-2.5-flash-lite-preview-06-17",
description=("è峿·±ãäºå®ãäŒãããšãŒãžã§ã³ãã"),
instruction=("ããªãã¯è峿·±ãäºå®ãæäŸã§ãã圹ã«ç«ã€ãšãŒãžã§ã³ãã§ãã"),
tools=[google_search],
)Agentã®ãã©ã¡ãŒã¿ã¯ã次ã®ãšããã§ãã
ã»name : åå
ã»model : ã¢ãã«ID
ã»description : ãšãŒãžã§ã³ãã®ã¡ã¿ããŒã¿çãªçã説ææ
ã»instruction : LLMã®ã·ã¹ãã ã¡ã»ãŒãž
ã»tool : ããŒã«
3-2. AgentExecutor ã§ã³ã¢ãšãŒãžã§ã³ããã©ãã
ã»agent_executor.py
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.server.tasks import TaskUpdater
from a2a.types import (
Part,
TaskState,
TextPart,
)
from a2a.utils import new_agent_text_message, new_task
from google.adk.artifacts import InMemoryArtifactService
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
# AgentExecutorã®äœæ
class ADKAgentExecutor(AgentExecutor):
# åæå
def __init__(
self,
agent,
status_message="ãªã¯ãšã¹ããåŠçäžâŠ\n",
artifact_name="response",
):
self.agent = agent
self.status_message = status_message
self.artifact_name = artifact_name
self.runner = Runner(
app_name=agent.name,
agent=agent,
artifact_service=InMemoryArtifactService(),
session_service=InMemorySessionService(),
memory_service=InMemoryMemoryService(),
)
# å®è¡
async def execute(
self,
context: RequestContext,
event_queue: EventQueue,
) -> None:
# ãŠãŒã¶ãŒå
¥åãååŸ
query = context.get_user_input()
# æ¢åã¿ã¹ã¯ããªããã°æ°èŠäœæ
task = context.current_task or new_task(context.message)
await event_queue.enqueue_event(task)
# TaskUpdaterã®æºå
updater = TaskUpdater(event_queue, task.id, task.contextId)
if context.call_context:
user_id = context.call_context.user.user_name
else:
user_id = "a2a_user"
try:
# ã«ã¹ã¿ã ã¡ãã»ãŒãžã§ã¹ããŒã¿ã¹ãæŽæ°
await updater.update_status(
TaskState.working,
new_agent_text_message(self.status_message, task.contextId, task.id),
)
# ã»ãã·ã§ã³ãäœæãããŠãŒã¶ãŒããã®åãåãããContentåã«ã©ãã
session = await self.runner.session_service.create_session(
app_name=self.agent.name,
user_id=user_id,
state={},
session_id=task.contextId,
)
content = types.Content(
role="user", parts=[types.Part.from_text(text=query)]
)
# runnerãéåæã§å®è¡ããçæãããã€ãã³ãã鿬¡åŠç
response_text = ""
async for event in self.runner.run_async(
user_id=user_id, session_id=session.id, new_message=content
):
# æçµã¬ã¹ãã³ã¹ãã€ã³ã³ãã³ããããå Žå
if event.is_final_response() and event.content and event.content.parts:
for part in event.content.parts:
# text
if hasattr(part, "text") and part.text:
response_text += part.text + "\n"
# function_call
elif hasattr(part, "function_call"):
pass
# å®äºåŸãããã¹ãã¬ã¹ãã³ã¹ãã¢ãŒãã£ãã¡ã¯ããšããŠè¿œå
await updater.add_artifact(
[Part(root=TextPart(text=response_text))],
name=self.artifact_name,
)
# ã¿ã¹ã¯ãå®äºç¶æ
ã«æŽæ°
await updater.complete()
except Exception as e:
await updater.update_status(
TaskState.failed,
new_agent_text_message(f"ãšã©ãŒ: {e!s}", task.contextId, task.id),
final=True,
)
# ãã£ã³ã»ã«
async def cancel(
self,
context: RequestContext,
event_queue: EventQueue,
) -> None:
raise NotImplementedError("ãã£ã³ã»ã«ã¯å®è£
ãããŠããŸããã")
3-3. AgentSkill ãš AgentCard ã®æºå
ã»__main__.py
import uvicorn
from a2a.server.apps import A2AStarletteApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import (
AgentCapabilities,
AgentCard,
AgentSkill,
)
from agent import root_agent as facts_agent
from agent_executor import ADKAgentExecutor
# ã¡ã€ã³
def main():
# Agent Skill ã®æºå
skill = AgentSkill(
id="give_facts",
name="Provide Interesting Facts",
description="Googleã§è峿·±ãäºå®ãæ€çŽ¢",
tags=["search", "google", "facts"],
examples=[
"ãã¥ãŒãšãŒã¯åžã«ã€ããŠã®è峿·±ãäºå®ãæããŠãã ããã",
],
)
# Agent Card ã®æºå
agent_card = AgentCard(
name=facts_agent.name,
description=facts_agent.description,
url='http://localhost:10001/',
version="1.0.0",
defaultInputModes=["text", "text/plain"],
defaultOutputModes=["text", "text/plain"],
capabilities=AgentCapabilities(streaming=True),
skills=[skill],
)
# ãªã¯ãšã¹ããã³ãã©ã®æºå
request_handler = DefaultRequestHandler(
agent_executor=ADKAgentExecutor(
agent=facts_agent,
),
task_store=InMemoryTaskStore(),
)
# ãµãŒãã®æºå
server = A2AStarletteApplication(
agent_card=agent_card,
http_handler=request_handler
)
uvicorn.run(server.build(), host="localhost", port=10001)
# ã¡ã€ã³ã®å®è¡
if __name__ == "__main__":
main()
3-4. A2AãšãŒãžã§ã³ãã®å®è¡
(1) A2AãšãŒãžã§ã³ãã®å®è¡ã
A2Aãšã³ããã€ã³ããå
¬éãããŸãã
python __main__.pyINFO: Started server process [77075]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://localhost:10002 (Press CTRL+C to quit)4. A2AãšãŒãžã§ã³ãã®åŒã³åºã
(1) A2AãšãŒãžã§ã³ããåŒã³åºãã¯ã©ã€ã¢ã³ãã®äœæã
ã»loop_client.py
import asyncio
from typing import Any
from uuid import uuid4
import httpx
from a2a.client import A2AClient
from a2a.types import (
MessageSendParams,
SendStreamingMessageRequest,
)
# ãŠã§ã«ã«ã ã¡ãã»ãŒãžã®åºå
def print_welcome_message() -> None:
print('æ±çš A2A ã¯ã©ã€ã¢ã³ããžãããã!')
print("ã¯ãšãªãå
¥åããŠãã ãã (çµäºããã«ã¯ãexitããšå
¥å)")
# ãŠãŒã¶ãŒã¯ãšãªã®ååŸ
def get_user_query() -> str:
return input('\n> ')
# ãµãŒããšã®ãããšã
async def interact_with_server(client: A2AClient) -> None:
while True:
user_input = get_user_query()
if user_input.lower() == 'exit':
break
send_message_payload: dict[str, Any] = {
'message': {
'role': 'user',
'parts': [{'type': 'text', 'text': user_input}],
'messageId': uuid4().hex,
},
}
try:
streaming_request = SendStreamingMessageRequest(
id=uuid4().hex,
params=MessageSendParams(**send_message_payload)
)
stream_response = client.send_message_streaming(streaming_request)
async for chunk in stream_response:
print(get_response_text(chunk), end='', flush=True)
await asyncio.sleep(0.1)
except Exception as e:
print(f'ãšã©ãŒãçºçããŸãã: {e}')
# ã¬ã¹ãã³ã¹ããã¹ãã®ååŸ
def get_response_text(chunk):
data = chunk.model_dump(mode='json', exclude_none=True)
result = data.get('result', {})
# ã¢ãŒãã£ãã¡ã¯ãæŽæ°ã€ãã³ã
if 'artifact' in result:
parts = result['artifact']['parts']
# ã¹ããŒã¿ã¹æŽæ°ã€ãã³ã
elif 'status' in result and result['status'].get('message'):
parts = result['status']['message']['parts']
# ãã®ä»ã®ã€ãã³ã
else:
return ''
# æåã®ããŒãã®ããã¹ããè¿ã
return parts[0].get('text', '')
# ã¡ã€ã³
async def main() -> None:
print_welcome_message()
async with httpx.AsyncClient() as httpx_client:
client = await A2AClient.get_client_from_agent_card_url(
httpx_client, 'http://localhost:10001'
)
await interact_with_server(client)
# ã¡ã€ã³ã®å®è¡
if __name__ == '__main__':
asyncio.run(main())
(2) A2AãšãŒãžã§ã³ããåŒã³åºãã¯ã©ã€ã¢ã³ãã®å®è¡ã
python loop_client.py æ±çš A2A ã¯ã©ã€ã¢ã³ããžãããã!
ã¯ãšãªãå
¥åããŠãã ãã (çµäºããã«ã¯ãexitããšå
¥å)
> (3) 質åã
Googleæ€çŽ¢ã§ææ°ã®äºå®æ
å ±ãæããŠãããããšã確èªããŸãã
> 2025幎7æ6æ¥ã®æ¥æ¬ã®ãã¥ãŒã¹ã1ã€æããŠïŒãªã¯ãšã¹ããåŠçäžâŠ
2025幎7æ6æ¥ïŒæ¥ïŒã®æ¥æ¬ã®ãã¥ãŒã¹ãšããŠã¯ã以äžã®æ
å ±ããããŸãã
* **ãã¹ã±ããããŒã«ç·åæ¥æ¬ä»£è¡šããªã©ã³ãæŠã«èšã**
ãã¹ã±ããããŒã«ç·åæ¥æ¬ä»£è¡šããŒã ã¯ããã®æ¥ææã¢ãªãŒãã«ãŠãæ¥æ¬çåœã«ãã2025ïŒæ±äº¬å€§äŒïŒãã®ãªã©ã³ãæŠã«èšã¿ãŸããã詊åç»é²ã¡ã³ããŒïŒãã¹ã¿ãŒïŒãçºè¡šãããŠããŸãã
* **åè°é¢éžæãäžå
ã®éåæ°ç²åŸã¯åŸ®åŠãªæ
å¢**
ææ¥æ°èç€Ÿã®æ
å¢èª¿æ»ã«ãããšãåè°é¢éžæã«ãããŠãäžå
ã¯ç®æšãšããéåæ°ç²åŸã埮åŠãªç¶æ³ã§ããèªæ°å
ã¯æ¹éžåã®è°åžãäžåãèŠéãã§ãå
¬æå
ãç®æšè°åžã«å±ããªãæ
å¢ã§ããäžæ¹ãç«æ²æ°äž»å
ãåœæ°æ°äž»å
ã¯è°åžã䌞ã°ãããã§ãã
* **鹿å
å³¶çåå³¶æã§æå€§é床5匷ã®å°éçºç**
6æ¥ååŸ2æ1åããã鹿å
å³¶çã®åå³¶æã§æå€§é床5匷ã芳枬ãã匷ãå°éããããŸãããéæºå°ã¯ãã«ã©åå³¶è¿æµ·ã§ã接波ã®å¿é
ã¯ãããŸããã§ããã
ãã®ä»ã«ããTBS NEWS DIGã§ã¯æã®ãã¥ãŒã¹ããã€ãžã§ã¹ãã§æŸéããŠããŸãã ãŸãããŠã§ã¶ãŒãã¥ãŒã¹ã§ã¯ãã®æ¥ã®æŠã®æ
å ±ãªã©ãæäŸããŠããŸãã