ํ๋ฌ๊ทธ์ธ¶
ADK(Agent Development Kit)์ ํ๋ฌ๊ทธ์ธ์ ์ฝ๋ฐฑ ํํฌ๋ฅผ ์ฌ์ฉํ์ฌ ์์ด์ ํธ ์ํฌํ๋ก ์๋ช ์ฃผ๊ธฐ์ ๋ค์ํ ๋จ๊ณ์์ ์คํ๋ ์ ์๋ ์ฌ์ฉ์ ์ง์ ์ฝ๋ ๋ชจ๋์ ๋๋ค. ํ๋ฌ๊ทธ์ธ์ ์์ด์ ํธ ์ํฌํ๋ก ์ ๋ฐ์ ๊ฑธ์ณ ์ ์ฉ๋๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํฉ๋๋ค. ํ๋ฌ๊ทธ์ธ์ ์ผ๋ฐ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋ก๊น ๋ฐ ์ถ์ : ๋๋ฒ๊น ๋ฐ ์ฑ๋ฅ ๋ถ์์ ์ํด ์์ด์ ํธ, ๋๊ตฌ ๋ฐ ์์ฑํ AI ๋ชจ๋ธ ํ๋์ ๋ํ ์์ธํ ๋ก๊ทธ๋ฅผ ์์ฑํฉ๋๋ค.
- ์ ์ฑ ์ ์ฉ: ํน์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ๊ถํ์ด ์๋์ง ํ์ธํ๊ณ ๊ถํ์ด ์๋ ๊ฒฝ์ฐ ์คํ์ ๋ฐฉ์งํ๋ ํจ์์ ๊ฐ์ ๋ณด์ ๋ณดํธ ์ฅ์น๋ฅผ ๊ตฌํํฉ๋๋ค.
- ๋ชจ๋ํฐ๋ง ๋ฐ ์ธก์ ํญ๋ชฉ: Prometheus ๋๋ Google Cloud Observability (์ด์ Stackdriver)์ ๊ฐ์ ๋ชจ๋ํฐ๋ง ์์คํ ์ ํ ํฐ ์ฌ์ฉ๋, ์คํ ์๊ฐ ๋ฐ ํธ์ถ ํ์์ ๋ํ ์ธก์ ํญ๋ชฉ์ ์์งํ๊ณ ๋ด๋ณด๋ ๋๋ค.
- ์๋ต ์บ์ฑ: ์์ฒญ์ด ์ด์ ์ ์ด๋ฃจ์ด์ก๋์ง ํ์ธํ์ฌ ๋น์ฉ์ด ๋ง์ด ๋ค๊ฑฐ๋ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ AI ๋ชจ๋ธ ๋๋ ๋๊ตฌ ํธ์ถ์ ๊ฑด๋๋ฐ๊ณ ์บ์๋ ์๋ต์ ๋ฐํํ ์ ์์ต๋๋ค.
- ์์ฒญ ๋๋ ์๋ต ์์ : AI ๋ชจ๋ธ ํ๋กฌํํธ์ ์ ๋ณด๋ฅผ ๋์ ์ผ๋ก ์ถ๊ฐํ๊ฑฐ๋ ๋๊ตฌ ์ถ๋ ฅ ์๋ต์ ํ์คํํฉ๋๋ค.
ํ: ์์ ๊ธฐ๋ฅ์๋ ํ๋ฌ๊ทธ์ธ ์ฌ์ฉ
๋ณด์ ๊ฐ๋๋ ์ผ๊ณผ ์ ์ฑ ์ ๊ตฌํํ ๋๋ ์ฝ๋ฐฑ๋ณด๋ค ๋ชจ๋์ฑ๊ณผ ์ ์ฐ์ฑ์ด ๋์ ADK ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์์ธํ ๋ด์ฉ์ ๋ณด์ ๊ฐ๋๋ ์ผ์ ์ํ ์ฝ๋ฐฑ ๋ฐ ํ๋ฌ๊ทธ์ธ์ ์ฐธ๊ณ ํ์ธ์.
ํ: ADK ํตํฉ
ADK์ฉ ์ฌ์ ๊ตฌ์ถ ํ๋ฌ๊ทธ์ธ ๋ฐ ๊ธฐํ ํตํฉ ๋ชฉ๋ก์ ๋๊ตฌ ๋ฐ ํตํฉ์ ์ฐธ๊ณ ํ์ธ์.
ํ๋ฌ๊ทธ์ธ์ ์ด๋ป๊ฒ ์๋ํฉ๋๊น?¶
ADK ํ๋ฌ๊ทธ์ธ์ BasePlugin ํด๋์ค๋ฅผ ํ์ฅํ๋ฉฐ ์์ด์ ํธ ์๋ช
์ฃผ๊ธฐ์์ ํ๋ฌ๊ทธ์ธ์ด ์คํ๋์ด์ผ ํ๋ ์์น๋ฅผ ๋ํ๋ด๋ ํ๋ ์ด์์ callback ๋ฉ์๋๋ฅผ ํฌํจํฉ๋๋ค. ์์ด์ ํธ์ Runner ํด๋์ค(Python์ ๊ฒฝ์ฐ App ๊ฐ์ฒด)์ ํ๋ฌ๊ทธ์ธ์ ๋ฑ๋กํ์ฌ ์์ด์ ํธ์ ํตํฉํฉ๋๋ค. ์์ด์ ํธ ์ ํ๋ฆฌ์ผ์ด์
์์ ํ๋ฌ๊ทธ์ธ์ ํธ๋ฆฌ๊ฑฐํ ์ ์๋ ๋ฐฉ๋ฒ๊ณผ ์์น์ ๋ํ ์์ธํ ๋ด์ฉ์ ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ ํํฌ๋ฅผ ์ฐธ๊ณ ํ์ธ์.
ํ๋ฌ๊ทธ์ธ ๊ธฐ๋ฅ์ ADK์ ํ์ฅ ๊ฐ๋ฅํ ์ํคํ
์ฒ์ ํต์ฌ ์ค๊ณ ์์์ธ ์ฝ๋ฐฑ์ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์์ด์ ํธ ์ฝ๋ฐฑ์ ํน์ ์์
์ ์ํด ๋จ์ผ ์์ด์ ํธ, ๋จ์ผ ๋๊ตฌ์ ๊ตฌ์ฑ๋๋ ๋ฐ๋ฉด, ํ๋ฌ๊ทธ์ธ์ Runner(Python์ ๊ฒฝ์ฐ App)์ ํ ๋ฒ ๋ฑ๋ก๋๋ฉฐ ํด๋น ์ฝ๋ฐฑ์ ํด๋น ๋ฌ๋๊ฐ ๊ด๋ฆฌํ๋ ๋ชจ๋ ์์ด์ ํธ, ๋๊ตฌ ๋ฐ LLM ํธ์ถ์ ์ ์ญ์ ์ผ๋ก ์ ์ฉ๋ฉ๋๋ค. ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๋ฉด ๊ด๋ จ ์ฝ๋ฐฑ ํจ์๋ฅผ ํจ๊ป ๋ฌถ์ด ์ํฌํ๋ก ์ ์ฒด์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ํ๋ฌ๊ทธ์ธ์ ์ ์ฒด ์์ด์ ํธ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฑธ์ณ ์๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ๋ฐ ์ด์์ ์ธ ์๋ฃจ์
์
๋๋ค.
์ฌ์ ๋น๋๋ ํ๋ฌ๊ทธ์ธ¶
ADK์๋ ์์ด์ ํธ ์ํฌํ๋ก์ ์ฆ์ ์ถ๊ฐํ ์ ์๋ ์ฌ๋ฌ ํ๋ฌ๊ทธ์ธ์ด ํฌํจ๋์ด ์์ต๋๋ค.
- ๋ฐ์ ๋ฐ ์ฌ์๋ ๋๊ตฌ: ๋๊ตฌ ์คํจ๋ฅผ ์ถ์ ํ๊ณ ๋๊ตฌ ์์ฒญ์ ์ง๋ฅ์ ์ผ๋ก ์ฌ์๋ํฉ๋๋ค.
- BigQuery ๋ถ์: BigQuery๋ฅผ ์ฌ์ฉํ์ฌ ์์ด์ ํธ ๋ก๊น ๋ฐ ๋ถ์์ ํ์ฑํํฉ๋๋ค.
- Model Armor: Google Cloud Model Armor ํ ํ๋ฆฟ์ ๊ธฐ๋ฐ์ผ๋ก ์ฌ์ฉ์ ์ ๋ ฅ ๋ฐ ๋ชจ๋ธ ์ถ๋ ฅ์ ํํฐ๋งํฉ๋๋ค.
- ์ปจํ ์คํธ ํํฐ: ์์ฑํ AI ์ปจํ ์คํธ๋ฅผ ํํฐ๋งํ์ฌ ํฌ๊ธฐ๋ฅผ ์ค์ ๋๋ค.
- ์ ์ญ ์ง์นจ: ์ฑ ์์ค์์ ์ ์ญ ์ง์นจ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ํ๋ฌ๊ทธ์ธ์ ๋๋ค.
- ์ํฐํฉํธ๋ก ํ์ผ ์ ์ฅ: ์ฌ์ฉ์ ๋ฉ์์ง์ ํฌํจ๋ ํ์ผ์ ์ํฐํฉํธ๋ก ์ ์ฅํฉ๋๋ค.
- ์๋ ํธ๋ ์ด์ฑ(Auto Tracing): ์์ด์ ํธ ์์ฒด ํจํค์ง์ ํจ์๋ฅผ OpenTelemetry ์คํฌ์ผ๋ก ๋ํํฉ๋๋ค.
- ๋ฉํฐ๋ชจ๋ฌ ๋๊ตฌ ๊ฒฐ๊ณผ(Multimodal Tool Results): ํจ์ ๋๊ตฌ๊ฐ ์ฝํ ์ธ ํํธ๋ฅผ ๋ชจ๋ธ์ ์ง์ ๋ฐํํ ์ ์๋๋ก ํฉ๋๋ค.
- ๋ก๊น : ๊ฐ ์์ด์ ํธ ์ํฌํ๋ก ์ฝ๋ฐฑ ์ง์ ์์ ์ค์ํ ์ ๋ณด๋ฅผ ๋ก๊น ํฉ๋๋ค.
- ๋๋ฒ๊ทธ ๋ก๊น (Debug Logging): ๊ฐ ํธ์ถ์ ๋ํ ์ ์ฒด ๋๋ฒ๊ทธ ์ ๋ณด๋ฅผ YAML ํ์ผ๋ก ์บก์ฒํฉ๋๋ค.
- ๋ชจ๋ธ ๋ฐ์ ๋ฐ ์ฌ์๋(Reflect and Retry Model): ์๋ชป๋ ํ์์ ํจ์ ํธ์ถ๊ณผ ๊ฐ์ด ์๋ต์ด ์ค๋ฅ๋ก ๋๋ ๋ ๋ชจ๋ธ์ ๋ค์ ์๋ํ๋๋ก ์์ฒญํฉ๋๋ค.
- ๋๊ตฌ ํธ์ถ ๋ฌด๊ฒฐ์ฑ(Tool Call Integrity): ์ธ์ ์ ์ ์ฅ๋ ๊ฐ ํจ์ ํธ์ถ์ ๋น๋ฐ ํค๋ก ์๋ช ํ๊ณ ํธ์ถ์ ์๋ช ์ด ๊ฒ์ฆ๋ ๊ฒฝ์ฐ์๋ง ๋๊ตฌ๋ฅผ ์คํํฉ๋๋ค. ์ํฌํ๋ก ๋ ธ๋๋ก ์คํ๋๋ ๋๊ตฌ๋ ํ์ธํ์ง ์์ต๋๋ค.
์์ด์ ํธ๋ฅผ ์ํ ์ถ๊ฐ ๊ธฐ๋ณธ ํ๋ฌ๊ทธ์ธ ๋ฐ ์๋ํํฐ ํ๋ฌ๊ทธ์ธ์ ADK ํตํฉ ํ์ด์ง๋ฅผ ํ์ธํ์ธ์.
ํ๋ฌ๊ทธ์ธ ์ ์ ๋ฐ ๋ฑ๋ก¶
์ด ์น์ ์์๋ ํ๋ฌ๊ทธ์ธ ํด๋์ค๋ฅผ ์ ์ํ๊ณ ์์ด์ ํธ ์ํฌํ๋ก์ ์ผ๋ถ๋ก ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค. ์์ ํ ์ฝ๋ ์์๋ ์ ์ฅ์์ ํ๋ฌ๊ทธ์ธ ๊ธฐ๋ณธ์ ์ฐธ๊ณ ํ์ธ์.
ํ๋ฌ๊ทธ์ธ ํด๋์ค ์์ฑ¶
BasePlugin ํด๋์ค๋ฅผ ํ์ฅํ๊ณ ๋ค์ ์ฝ๋ ์์์ ํ์๋ ๋๋ก ํ๋ ์ด์์ callback ๋ฉ์๋๋ฅผ ์ถ๊ฐํ์ฌ ์์ํฉ๋๋ค.
from google.adk.agents.base_agent import BaseAgent
from google.adk.agents.callback_context import CallbackContext
from google.adk.models.llm_request import LlmRequest
from google.adk.plugins.base_plugin import BasePlugin
class CountInvocationPlugin(BasePlugin):
"""์์ด์ ํธ ๋ฐ ๋๊ตฌ ํธ์ถ ํ์๋ฅผ ๊ณ์ฐํ๋ ์ฌ์ฉ์ ์ง์ ํ๋ฌ๊ทธ์ธ์
๋๋ค."""
def __init__(self) -> None:
"""์นด์ดํฐ๋ก ํ๋ฌ๊ทธ์ธ์ ์ด๊ธฐํํฉ๋๋ค."""
super().__init__(name="count_invocation")
self.agent_count: int = 0
self.tool_count: int = 0
self.llm_request_count: int = 0
async def before_agent_callback(
self, *, agent: BaseAgent, callback_context: CallbackContext
) -> None:
"""์์ด์ ํธ ์คํ ํ์๋ฅผ ๊ณ์ฐํฉ๋๋ค."""
self.agent_count += 1
print(f"[Plugin] Agent run count: {self.agent_count}")
async def before_model_callback(
self, *, callback_context: CallbackContext, llm_request: LlmRequest
) -> None:
"""LLM ์์ฒญ ํ์๋ฅผ ๊ณ์ฐํฉ๋๋ค."""
self.llm_request_count += 1
print(f"[Plugin] LLM request count: {self.llm_request_count}")
import { BaseAgent, BasePlugin, Context } from "@google/adk";
import type { LlmRequest, LlmResponse } from "@google/adk";
import type { Content } from "@google/genai";
export class CountInvocationPlugin extends BasePlugin {
public agentCount = 0;
public toolCount = 0;
public llmRequestCount = 0;
constructor() {
super("count_invocation");
}
async beforeAgentCallback(
agent: BaseAgent,
context: Context
): Promise<Content | undefined> {
this.agentCount++;
console.log(`[Plugin] Agent run count: ${this.agentCount}`);
return undefined;
}
async beforeModelCallback(
context: Context,
llmRequest: LlmRequest
): Promise<LlmResponse | undefined> {
this.llmRequestCount++;
console.log(`[Plugin] LLM request count: ${this.llmRequestCount}`);
return undefined;
}
}
import com.google.adk.agents.BaseAgent;
import com.google.adk.agents.CallbackContext;
import com.google.adk.models.LlmRequest;
import com.google.adk.models.LlmResponse;
import com.google.adk.plugins.BasePlugin;
import com.google.genai.types.Content;
import io.reactivex.rxjava3.core.Maybe;
public class CountInvocationPlugin extends BasePlugin {
public int agentCount = 0;
public int toolCount = 0;
public int llmRequestCount = 0;
public CountInvocationPlugin() {
super("count_invocation");
}
@Override
public Maybe<Content> beforeAgentCallback(BaseAgent agent, CallbackContext callbackContext) {
agentCount++;
System.out.println("[Plugin] Agent run count: " + agentCount);
return Maybe.empty();
}
@Override
public Maybe<LlmResponse> beforeModelCallback(
CallbackContext callbackContext, LlmRequest.Builder llmRequest) {
llmRequestCount++;
System.out.println("[Plugin] LLM request count: " + llmRequestCount);
return Maybe.empty();
}
}
/** A custom plugin that counts agent runs and LLM requests. */
class CountInvocationPlugin : Plugin {
override val name = "count_invocation"
var agentCount = 0
private set
var llmRequestCount = 0
private set
// Plugin declares one abstract member, `name`; every callback has a default,
// so a plugin only overrides the ones it cares about.
override suspend fun beforeAgent(
context: CallbackContext,
): CallbackChoice<EventActions, Content> {
agentCount++
println("[Plugin] Agent run count: $agentCount")
return CallbackChoice.Continue(EventActions())
}
override suspend fun beforeModel(
context: CallbackContext,
request: LlmRequest,
): CallbackChoice<LlmRequest, LlmResponse> {
llmRequestCount++
println("[Plugin] LLM request count: $llmRequestCount")
return CallbackChoice.Continue(request)
}
}
์ด ์์ ์ฝ๋๋ ์์ด์ ํธ ์๋ช
์ฃผ๊ธฐ ๋์ ์ด๋ฌํ ์์
์ ์คํ ํ์๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด before_agent_callback ๋ฐ before_model_callback์ ๋ํ ์ฝ๋ฐฑ์ ๊ตฌํํฉ๋๋ค.
ํ๋ฌ๊ทธ์ธ ํด๋์ค ๋ฑ๋ก¶
plugins ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ์์ด์ ํธ ์ด๊ธฐํ ์ Runner ํด๋์ค(Python์ ๊ฒฝ์ฐ App ๊ฐ์ฒด)์ ์ผ๋ถ๋ก ํ๋ฌ๊ทธ์ธ ํด๋์ค๋ฅผ ๋ฑ๋กํ์ฌ ํตํฉํฉ๋๋ค. ์ด ๋งค๊ฐ๋ณ์๋ก ์ฌ๋ฌ ํ๋ฌ๊ทธ์ธ์ ์ง์ ํ ์ ์์ต๋๋ค. ๋ค์ ์ฝ๋ ์์๋ ์ด์ ์น์
์์ ์ ์๋ CountInvocationPlugin ํ๋ฌ๊ทธ์ธ์ ๊ฐ๋จํ ADK ์์ด์ ํธ์ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
Python: Runner(plugins=...) ๋์ App(plugins=...) ์ฌ์ฉ
Python์์ Runner ๋ฐ InMemoryRunner์ plugins ๋งค๊ฐ๋ณ์๋ ์ง์ ์ค๋จ๋์์ผ๋ฉฐ DeprecationWarning์ ๋ฐ์์ํต๋๋ค. ๋์ App์ plugins๋ฅผ ์ค์ ํ๊ณ ํด๋น App์ InMemoryRunner(app=app)์ผ๋ก ๋ฌ๋์ ์ ๋ฌํ์ธ์. plugins์ app์ ๋ชจ๋ ์ ๋ฌํ๋ฉด ValueError๊ฐ ๋ฐ์ํฉ๋๋ค.
from google.adk.runners import InMemoryRunner
from google.adk import Agent
from google.adk.apps import App
from google.adk.tools.tool_context import ToolContext
from google.genai import types
import asyncio
# ํ๋ฌ๊ทธ์ธ ๊ฐ์ ธ์ค๊ธฐ.
from .count_plugin import CountInvocationPlugin
async def hello_world(tool_context: ToolContext, query: str):
print(f'Hello world: query is [{query}]')
root_agent = Agent(
model='gemini-flash-latest',
name='hello_world',
description='์ฌ์ฉ์ ์ฟผ๋ฆฌ๋ก ํฌ๋ก์๋๋ฅผ ์ถ๋ ฅํฉ๋๋ค.',
instruction="""ํฌ๋ก์๋ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ํฌ๋ก์๋์ ์ฌ์ฉ์ ์ฟผ๋ฆฌ๋ฅผ ์ถ๋ ฅํ์ญ์์ค.
""",
tools=[hello_world],
)
app = App(
name='test_app_with_plugin',
root_agent=root_agent,
# ์ฌ๊ธฐ์ ํ๋ฌ๊ทธ์ธ์ ์ถ๊ฐํฉ๋๋ค. ์ฌ๋ฌ ํ๋ฌ๊ทธ์ธ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
plugins=[CountInvocationPlugin()],
)
async def main():
"""์์ด์ ํธ์ ๋ฉ์ธ ์ง์
์ ์
๋๋ค."""
prompt = 'hello world'
runner = InMemoryRunner(app=app)
# ๋๋จธ์ง๋ ์ผ๋ฐ ADK ๋ฌ๋๋ฅผ ์์ํ๋ ๊ฒ๊ณผ ๋์ผํฉ๋๋ค.
session = await runner.session_service.create_session(
user_id='user',
app_name='test_app_with_plugin',
)
async for event in runner.run_async(
user_id='user',
session_id=session.id,
new_message=types.Content(
role='user', parts=[types.Part.from_text(text=prompt)]
)
):
print(f'** {event.author}๋ก๋ถํฐ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ต๋๋ค.')
if __name__ == "__main__":
asyncio.run(main())
import { InMemoryRunner, LlmAgent, FunctionTool } from "@google/adk";
import { z } from "zod";
import { CountInvocationPlugin } from "./count_plugin.ts";
const HelloWorldInput = z.object({
query: z.string().describe("The query string to print."),
});
async function helloWorld({ query }: z.infer<typeof HelloWorldInput>): Promise<{ result: string }> {
const output = `Hello world: query is [${query}]`;
console.log(output);
return { result: output };
}
const helloWorldTool = new FunctionTool({
name: "hello_world",
description: "Prints hello world with user query.",
parameters: HelloWorldInput,
execute: helloWorld,
});
const rootAgent = new LlmAgent({
model: "gemini-flash-latest",
name: "hello_world",
description: "Prints hello world with user query.",
instruction: `Use hello_world tool to print hello world and user query.`,
tools: [helloWorldTool],
});
async function main(): Promise<void> {
const prompt = "hello world";
const runner = new InMemoryRunner({
agent: rootAgent,
appName: "test_app_with_plugin",
plugins: [new CountInvocationPlugin()],
});
const session = await runner.sessionService.createSession({
appName: "test_app_with_plugin",
userId: "user",
});
for await (const event of runner.runAsync({
userId: "user",
sessionId: session.id,
newMessage: { role: "user", parts: [{ text: prompt }] },
})) {
console.log(`** Got event from ${event.author}`);
}
}
main();
import com.google.adk.agents.LlmAgent;
import com.google.adk.runner.InMemoryRunner;
import com.google.adk.sessions.Session;
import com.google.adk.tools.Annotations.Schema;
import com.google.adk.tools.FunctionTool;
import com.google.genai.types.Content;
import com.google.genai.types.Part;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class Main {
public static class HelloTool {
@Schema(name = "hello_world", description = "Prints hello world with user query.")
public static Map<String, Object> helloWorld(
@Schema(name = "query", description = "The query string to print.") String query) {
String output = "Hello world: query is [" + query + "]";
System.out.println(output);
return Map.of("result", output);
}
}
public static void main(String[] args) {
LlmAgent rootAgent = LlmAgent.builder()
.model("gemini-flash-latest")
.name("hello_world")
.description("Prints hello world with user query.")
.instruction("Use hello_world tool to print hello world and user query.")
.tools(FunctionTool.create(HelloTool.class, "helloWorld"))
.build();
InMemoryRunner runner = new InMemoryRunner(
rootAgent,
"test_app_with_plugin",
Collections.singletonList(new CountInvocationPlugin())
);
Session session = runner.sessionService().createSession(
"test_app_with_plugin",
"user"
).blockingGet();
Content newContent = Content.builder()
.role("user")
.parts(List.of(Part.builder().text("hello world").build()))
.build();
runner.runAsync("user", session.id(), newContent).blockingForEach(event -> {
if (event.author() != null) {
System.out.println("** Got event from " + event.author());
}
});
}
}
val rootAgent =
LlmAgent(
name = "hello_world",
model = Gemini(name = "gemini-flash-latest"),
instruction = Instruction("Greet the user."),
)
// Since adk-kotlin 0.7.0 the agent-based InMemoryRunner constructor accepts
// plugins directly; before that they had to be set on an App.
val runner =
InMemoryRunner(
agent = rootAgent,
appName = "test_app_with_plugin",
plugins = listOf(CountInvocationPlugin()),
)
Python์์๋ --extra_plugins ์ต์
์ ์ฌ์ฉํ์ฌ adk web ๋๋ adk api_server์ ๊ฐ์ ธ์ค๊ธฐ ๊ฒฝ๋ก(import path)๋ฅผ ์ ๋ฌํจ์ผ๋ก์จ ์์ด์ ํธ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ ํ๋ฌ๊ทธ์ธ์ ๋ก๋ํ ์ ์์ต๋๋ค. ADK๋ App์์ ๋ฑ๋กํ ํ๋ฌ๊ทธ์ธ ๋ค์ ์ด๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์์ฑ์๊ฐ name ์ธ์๋ฅผ ํ์ฉํ๋ ๊ฒฝ์ฐ์๋ง ํด๋์ค๋ฅผ ์ ๋ฌํ๊ณ , ๊ทธ๋ ์ง ์์ผ๋ฉด ๋ชจ๋ ์์ค์์ ์ ์๋ ํ๋ฌ๊ทธ์ธ ์ธ์คํด์ค๋ฅผ ์ ๋ฌํ์ธ์. ๋ ์ด์์ ํ๋ฌ๊ทธ์ธ์ ๋ก๋ํ๋ ค๋ฉด ์ต์
์ ๋ฐ๋ณตํ์ฌ ์ฌ์ฉํ์ธ์.
ํ๋ฌ๊ทธ์ธ์ผ๋ก ์์ด์ ํธ ์คํ¶
ํ์์ฒ๋ผ ํ๋ฌ๊ทธ์ธ์ ์คํํฉ๋๋ค. ๋ค์์ ๋ช ๋ น์ค์ ์คํํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
Java
ํ๋ฌ๊ทธ์ธ์ ADK ์น ์ธํฐํ์ด์ค์์ ์ง์๋์ง ์์ต๋๋ค. ADK ์ํฌํ๋ก์์ ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์น ์ธํฐํ์ด์ค ์์ด ์ํฌํ๋ก๋ฅผ ์คํํด์ผ ํฉ๋๋ค.
์ด์ ์ ์ค๋ช ํ ์์ด์ ํธ์ ์ถ๋ ฅ์ ๋ค์๊ณผ ๋น์ทํด์ผ ํฉ๋๋ค.
[Plugin] Agent run count: 1
[Plugin] LLM request count: 1
** Got event from hello_world
Hello world: query is [hello world]
** Got event from hello_world
[Plugin] LLM request count: 2
** Got event from hello_world
ADK ์์ด์ ํธ ์คํ์ ๋ํ ์์ธํ ๋ด์ฉ์ ์์ด์ ํธ ๋ฐํ์ ๊ฐ์ด๋๋ฅผ ์ฐธ๊ณ ํ์ธ์.
ํ๋ฌ๊ทธ์ธ์ผ๋ก ์ํฌํ๋ก ๋น๋¶
ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ ํํฌ๋ ์์ด์ ํธ์ ์คํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ๋ก์ฑ๊ณ , ์์ ํ๊ณ , ์ฌ์ง์ด ์ ์ดํ๋ โโ๋ ผ๋ฆฌ๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ์ ๋๋ค. ๊ฐ ํํฌ๋ ํ๋ฌ๊ทธ์ธ ํด๋์ค์์ ๊ตฌํํ ์ ์๋ ํน์ ๋ฉ์๋๋ก, ์ค์ํ ์๊ฐ์ ์ฝ๋๋ฅผ ์คํํ ์ ์์ต๋๋ค. ํํฌ์ ๋ฐํ ๊ฐ์ ๋ฐ๋ผ ๋ ๊ฐ์ง ์๋ ๋ชจ๋ ์ค์์ ์ ํํ ์ ์์ต๋๋ค.
- ๊ด์ฐฐ: ๋ฐํ ๊ฐ์ด ์๋ ํํฌ(
None)๋ฅผ ๊ตฌํํฉ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ก๊น ๋๋ ์ธก์ ํญ๋ชฉ ์์ง๊ณผ ๊ฐ์ ์์ ์ ์ฌ์ฉ๋๋ฉฐ, ์์ด์ ํธ ์ํฌํ๋ก๊ฐ ์ค๋จ ์์ด ๋ค์ ๋จ๊ณ๋ก ์งํ๋๋๋ก ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ํ๋ฌ๊ทธ์ธ์after_tool_callback์ ์ฌ์ฉํ์ฌ ๋๋ฒ๊น ์ ์ํด ๋ชจ๋ ๋๊ตฌ์ ๊ฒฐ๊ณผ๋ฅผ ๋ก๊น ํ ์ ์์ต๋๋ค. - ๊ฐ์
: ํํฌ๋ฅผ ๊ตฌํํ๊ณ ๊ฐ์ ๋ฐํํฉ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ์ํฌํ๋ก๋ฅผ ๋จ๋ฝ์ํต๋๋ค.
Runner๋ ์ฒ๋ฆฌ๋ฅผ ์ค๋จํ๊ณ , ํ์ ํ๋ฌ๊ทธ์ธ๊ณผ ๋ชจ๋ธ ํธ์ถ๊ณผ ๊ฐ์ ์๋ ์๋๋ ์์ ์ ๊ฑด๋๋ฐ๊ณ , ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ์ ๋ฐํ ๊ฐ์ ๊ฒฐ๊ณผ๋ก ์ฌ์ฉํฉ๋๋ค. ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋ ์บ์๋LlmResponse๋ฅผ ๋ฐํํ๋๋กbefore_model_callback์ ๊ตฌํํ์ฌ ์ค๋ณต๋๊ณ ๋น์ฉ์ด ๋ง์ด ๋๋ API ํธ์ถ์ ๋ฐฉ์งํ๋ ๊ฒ์ ๋๋ค. - ์์ : ํํฌ๋ฅผ ๊ตฌํํ๊ณ ์ปจํ ์คํธ ๊ฐ์ฒด๋ฅผ ์์ ํฉ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ํด๋น ๋ชจ๋์ ์คํ์ ๋ฐฉํดํ์ง ์๊ณ ์คํ๋ ๋ชจ๋์ ์ปจํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์์ ํ ์ ์๋๋ก ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ชจ๋ธ ๊ฐ์ฒด ์คํ์ ์ํ ์ถ๊ฐ ํ์คํ๋ ํ๋กฌํํธ ํ ์คํธ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค.
์ฃผ์: ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ ํจ์๋ ๊ฐ์ฒด ์์ค์์ ๊ตฌํ๋ ์ฝ๋ฐฑ๋ณด๋ค ์ฐ์ ํฉ๋๋ค. ์ด ๋์์ ํ๋ฌ๊ทธ์ธ ์์ค ์ฝ๋ฐฑ ์ฝ๋๊ฐ ์์ด์ ํธ, ๋ชจ๋ธ ๋๋ ๋๊ตฌ ๊ฐ์ฒด ์ฝ๋ฐฑ์ด ์คํ๋๊ธฐ ์ ์ ์คํ๋จ์ ์๋ฏธํฉ๋๋ค. ๋ํ ํ๋ฌ๊ทธ์ธ ์์ค ์์ด์ ํธ ์ฝ๋ฐฑ์ด ๋น์ด ์์ง ์์(None์ด ์๋) ์๋ต์ ๋ฐํํ๋ฉด ์์ด์ ํธ, ๋ชจ๋ธ ๋๋ ๋๊ตฌ ์์ค ์ฝ๋ฐฑ์ ์คํ๋์ง ์์ต๋๋ค (๊ฑด๋๋).
Python์์ ๋ ์ด์์ ํ๋ฌ๊ทธ์ธ์ ๋ฑ๋กํ ๋๋ ๋ค์ ๋์์ ์ ์ํ์ธ์.
- ์์: ADK๋
plugins๋ชฉ๋ก์ ํ๋ฌ๊ทธ์ธ์ด ๋ํ๋๋ ์์๋๋ก ๊ฐ ์ฝ๋ฐฑ์ ์คํํ๋ฉฐ,None์ด์ธ์ ๊ฐ์ ๋ฐํํ๋ ์ฒซ ๋ฒ์งธ ํ๋ฌ๊ทธ์ธ์์ ๋ฉ์ถฅ๋๋ค. - ์ด๋ฆ: ๊ฐ ํ๋ฌ๊ทธ์ธ์๋ ๊ณ ์ ํ
name์ด ํ์ํฉ๋๋ค. ์ด๋ฆ์ด ๊ฐ์ ๋ ํ๋ฌ๊ทธ์ธ์ด ์์ผ๋ฉดRunner๊ฐ ์์ฑ๋ ๋ValueError๊ฐ ๋ฐ์ํ๋ฏ๋ก, ๋์ผํ ํด๋์ค์ ๊ฐ ์ธ์คํด์ค์ ๊ณ ์ ํ ์ด๋ฆ์ ์ง์ ํ์ธ์. - ์์ธ: ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ์์ ๋ฐ์ํ ์์ธ๋ ์๋ ์์ธ๋ฅผ
__cause__๋ก ๊ฐ์ง๋RuntimeError๋ก ์ฝ๋์ ๋๋ฌํฉ๋๋ค.on_agent_error_callback๋ฐon_run_error_callbackํํฌ๋ ๋ค๋ฅด๊ฒ ์๋ํฉ๋๋ค. ADK๋ ๋ชจ๋ ํ๋ฌ๊ทธ์ธ์์ ์ด๋ฅผ ์คํํ๋ฉฐ, ๋ด๋ถ์์ ๋ฐ์ํ ์์ธ๋ ๋ค์ ๋ฐ์์ํค๋ ๋์ ๋ก๊ทธ์ ๊ธฐ๋กํฉ๋๋ค.
ํ๋ฌ๊ทธ์ธ ์ค๊ณ๋ ์ฝ๋ ์คํ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ค์ ํ๊ณ ์ ์ญ ๊ด์ฌ์ฌ๋ฅผ ๋ก์ปฌ ์์ด์ ํธ ๋
ผ๋ฆฌ์์ ๋ถ๋ฆฌํฉ๋๋ค. ํ๋ฌ๊ทธ์ธ์ PerformanceMonitoringPlugin๊ณผ ๊ฐ์ด ๋น๋ํ๋ ์ํ ์ ์ฅ ๋ชจ๋์ธ ๋ฐ๋ฉด, ์ฝ๋ฐฑ ํํฌ๋ ํด๋น ๋ชจ๋ ๋ด์์ ์คํ๋๋ ํน์ ํจ์์
๋๋ค. ์ด ์ํคํ
์ฒ๋ ๋ค์๊ณผ ๊ฐ์ ์ค์ํ ๋ฐฉ์์ผ๋ก ํ์ค ์์ด์ ํธ ์ฝ๋ฐฑ๊ณผ ๊ทผ๋ณธ์ ์ผ๋ก ๋ค๋ฆ
๋๋ค.
- ๋ฒ์: ํ๋ฌ๊ทธ์ธ ํํฌ๋ ์ ์ญ์ ์
๋๋ค.
Runner(Python์ ๊ฒฝ์ฐApp)์ ํ๋ฌ๊ทธ์ธ์ ํ ๋ฒ ๋ฑ๋กํ๋ฉด ํด๋น ํํฌ๋ ๊ด๋ฆฌํ๋ ๋ชจ๋ ์์ด์ ํธ, ๋ชจ๋ธ ๋ฐ ๋๊ตฌ์ ๋ณดํธ์ ์ผ๋ก ์ ์ฉ๋ฉ๋๋ค. ๋์กฐ์ ์ผ๋ก ์์ด์ ํธ ์ฝ๋ฐฑ์ ๋ก์ปฌ์ด๋ฉฐ ํน์ ์์ด์ ํธ ์ธ์คํด์ค์ ๊ฐ๋ณ์ ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. - ์คํ ์์: ํ๋ฌ๊ทธ์ธ์ด ์ฐ์ ํฉ๋๋ค. ์ฃผ์ด์ง ์ด๋ฒคํธ์ ๋ํด ํ๋ฌ๊ทธ์ธ ํํฌ๋ ํญ์ ํด๋น ์์ด์ ํธ ์ฝ๋ฐฑ๋ณด๋ค ๋จผ์ ์คํ๋ฉ๋๋ค. ์ด ์์คํ ๋์์ ํ๋ฌ๊ทธ์ธ์ ๋ณด์ ์ ์ฑ , ๋ฒ์ฉ ์บ์ฑ ๋ฐ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฑธ์น ์ผ๊ด๋ ๋ก๊น ๊ณผ ๊ฐ์ ๊ต์ฐจ ์ ๋จ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ธฐ ์ํ ์ฌ๋ฐ๋ฅธ ์ํคํ ์ฒ ์ ํ์ผ๋ก ๋ง๋ญ๋๋ค.
์์ด์ ํธ ์ฝ๋ฐฑ ๋ฐ ํ๋ฌ๊ทธ์ธ¶
์ด์ ์น์ ์์ ์ธ๊ธํ๋ฏ์ด ํ๋ฌ๊ทธ์ธ๊ณผ ์์ด์ ํธ ์ฝ๋ฐฑ ์ฌ์ด์๋ ๊ธฐ๋ฅ์ ์ ์ฌ์ฑ์ด ์์ต๋๋ค. ๋ค์ ํ๋ ํ๋ฌ๊ทธ์ธ๊ณผ ์์ด์ ํธ ์ฝ๋ฐฑ์ ์ฐจ์ด์ ์ ๋ ์์ธํ ๋น๊ตํฉ๋๋ค.
| ํ๋ฌ๊ทธ์ธ | ์์ด์ ํธ ์ฝ๋ฐฑ | |
|---|---|---|
| ๋ฒ์ | ์ ์ญ: Runner์ ๋ชจ๋ ์์ด์ ํธ/๋๊ตฌ/LLM์ ์ ์ฉ๋ฉ๋๋ค. |
๋ก์ปฌ: ๊ตฌ์ฑ๋ ํน์ ์์ด์ ํธ ์ธ์คํด์ค์๋ง ์ ์ฉ๋ฉ๋๋ค. |
| ์ฃผ์ ์ฌ์ฉ ์ฌ๋ก | ์ํ์ ๊ธฐ๋ฅ: ๋ก๊น , ์ ์ฑ , ๋ชจ๋ํฐ๋ง, ์ ์ญ ์บ์ฑ. | ํน์ ์์ด์ ํธ ๋ก์ง: ๋จ์ผ ์์ด์ ํธ์ ๋์ ๋๋ ์ํ ์์ . |
| ๊ตฌ์ฑ | Runner(Python์ ๊ฒฝ์ฐ App)์์ ํ ๋ฒ ๊ตฌ์ฑํฉ๋๋ค. |
๊ฐ BaseAgent ์ธ์คํด์ค์์ ๊ฐ๋ณ์ ์ผ๋ก ๊ตฌ์ฑํฉ๋๋ค. |
| ์คํ ์์ | ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ์ ์์ด์ ํธ ์ฝ๋ฐฑ ์ ์ ์คํ๋ฉ๋๋ค. | ์์ด์ ํธ ์ฝ๋ฐฑ์ ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ ํ์ ์คํ๋ฉ๋๋ค. |
ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ ํํฌ¶
ํ๋ฌ๊ทธ์ธ ํด๋์ค์์ ์ ์ํ ์ฝ๋ฐฑ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ฌ๊ทธ์ธ์ด ํธ์ถ๋๋ ์๊ธฐ๋ฅผ ์ ์ํฉ๋๋ค. ์ฝ๋ฐฑ์ ์ฌ์ฉ์ ๋ฉ์์ง๊ฐ ์์ ๋ ๋, Runner, Agent, Model ๋๋ Tool์ด ํธ์ถ๋๊ธฐ ์ ํ, Events์ ๋ํด, ๊ทธ๋ฆฌ๊ณ Model ๋๋ Tool ์ค๋ฅ๊ฐ ๋ฐ์ํ ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. Python์์๋ Agent๊ฐ ์์ธ๋ฅผ ๋ฐ์์ํฌ ๋์ ์คํ ์์ฒด๊ฐ ์คํจํ ๋์๋ ์ค๋ฅ ์ฝ๋ฐฑ์ด ์คํ๋ฉ๋๋ค. ์ด๋ฌํ ์ฝ๋ฐฑ์ ์์ด์ ํธ, ๋ชจ๋ธ ๋ฐ ๋๊ตฌ ํด๋์ค ๋ด์ ์ ์๋ ๋ชจ๋ ์ฝ๋ฐฑ์ ํฌํจํ๋ฉฐ ์ฐ์ ํฉ๋๋ค.
๋ค์ ๋ค์ด์ด๊ทธ๋จ์ ์์ด์ ํธ ์ํฌํ๋ก ์ค์ ํ๋ฌ๊ทธ์ธ ๊ธฐ๋ฅ์ ์ฐ๊ฒฐํ๊ณ ์คํํ ์ ์๋ ์ฝ๋ฐฑ ์ง์ ์ ๋ณด์ฌ์ค๋๋ค.
๊ทธ๋ฆผ 1. ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ ํํฌ ์์น๋ฅผ ํฌํจํ ADK ์์ด์ ํธ ์ํฌํ๋ก ๋ค์ด์ด๊ทธ๋จ.
๋ค์ ์น์ ์์๋ ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ ์ ์๋ ์ฝ๋ฐฑ ํํฌ์ ๋ํด ๋ ์์ธํ ์ค๋ช ํฉ๋๋ค.
- ์ฌ์ฉ์ ๋ฉ์์ง ์ฝ๋ฐฑ
- ๋ฌ๋ ์์ ์ฝ๋ฐฑ
- ์์ด์ ํธ ์คํ ์ฝ๋ฐฑ
- ๋ชจ๋ธ ์ฝ๋ฐฑ
- ๋๊ตฌ ์ฝ๋ฐฑ
- ์ด๋ฒคํธ ์ฝ๋ฐฑ
- ๋ฌ๋ ์ข ๋ฃ ์ฝ๋ฐฑ
์ฌ์ฉ์ ๋ฉ์์ง ์ฝ๋ฐฑ¶
์ฌ์ฉ์ ๋ฉ์์ง ์ฝ๋ฐฑ(on_user_message_callback)์ ์ฌ์ฉ์๊ฐ ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ๋ ๋ฐ์ํฉ๋๋ค. on_user_message_callback์ ์คํ๋๋ ์ฒซ ๋ฒ์งธ ํํฌ๋ก, ์ด๊ธฐ ์
๋ ฅ์ ๊ฒ์ฌํ๊ฑฐ๋ ์์ ํ ๊ธฐํ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์คํ ์์ :
runner.run()์งํ, ๋ค๋ฅธ ์ฒ๋ฆฌ ์ด์ ์ ๋ฐ์ํฉ๋๋ค. - ๋ชฉ์ : ์ฌ์ฉ์์ ์์ ์ ๋ ฅ์ ๊ฒ์ฌํ๊ฑฐ๋ ์์ ํ๋ ์ฒซ ๋ฒ์งธ ๊ธฐํ์ ๋๋ค.
- ํ๋ฆ ์ ์ด: ์ฌ์ฉ์ ์๋ณธ ๋ฉ์์ง๋ฅผ ๋์ฒดํ
types.Content๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
๋ค์ ์ฝ๋ ์์๋ ์ด ์ฝ๋ฐฑ์ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์ ๋ณด์ฌ์ค๋๋ค.
async def on_user_message_callback(
self,
*,
invocation_context: InvocationContext,
user_message: types.Content,
) -> Optional[types.Content]:
...
```
=== "TypeScript"
```typescript
async onUserMessageCallback(
invocationContext: InvocationContext,
user_message: Content
): Promise<Content | undefined> {
// ์ฌ๊ธฐ์ ๊ตฌํ์ ์์ฑํฉ๋๋ค
}
```
```java
@Override
public Maybe<Content> onUserMessageCallback(
InvocationContext invocationContext, Content userMessage) {
return Maybe.empty();
}
๋ฌ๋ ์์ ์ฝ๋ฐฑ¶
๋ฌ๋ ์์ ์ฝ๋ฐฑ(before_run_callback)์ Runner ๊ฐ์ฒด๊ฐ ์ ์ฌ์ ์ผ๋ก ์์ ๋ ์ฌ์ฉ์ ๋ฉ์์ง๋ฅผ ๋ฐ์ ์คํ์ ์ค๋นํ ๋ ๋ฐ์ํฉ๋๋ค. before_run_callback์ ์ฌ๊ธฐ์ ์คํ๋์ด ์์ด์ ํธ ๋ก์ง์ด ์์๋๊ธฐ ์ ์ ์ ์ญ ์ค์ ์ ํ์ฉํฉ๋๋ค.
- ์คํ ์์ : ์ฌ์ฉ์ ๋ฉ์์ง๊ฐ ์ฒ๋ฆฌ๋ ํ ์์ด์ ํธ ์คํ์ด ์์๋๊ธฐ ์ ์ ๋ฐ์ํฉ๋๋ค.
- ๋ชฉ์ : ํธ์ถ์ด ์คํ๋๊ธฐ ์ ์ ์ ์ญ ์ค์ ๋๋ ์ด๊ธฐํ์ ๋๋ค.
- ํ๋ฆ ์ ์ด:
types.Content๊ฐ์ฒด๋ฅผ ๋ฐํํ์ฌ ์คํ์ ์ค์งํฉ๋๋ค.Runner๊ฐ ์กฐ๊ธฐ์ ์ข ๋ฃ๋๊ณ ํด๋น ์ฝํ ์ธ ๋ฅผ ๊ฒฐ๊ณผ๋ก ํ์ฌ ์คํ์ ๋ง์นฉ๋๋ค. Python์์๋ ์ด ์กฐ๊ธฐ ์ข ๋ฃ๊ฐLlmAgent๋๋Workflow๋ฅผ ํฌํจํ ๋ชจ๋ ๋ฃจํธ ์์ด์ ํธ์ ์ ์ฉ๋ฉ๋๋ค. ์ ์์ ์ผ๋ก ์งํํ๋ ค๋ฉดNone์ ๋ฐํํฉ๋๋ค.
๋ค์ ์ฝ๋ ์์๋ ์ด ์ฝ๋ฐฑ์ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์ ๋ณด์ฌ์ค๋๋ค.
async def before_run_callback(
self, *, invocation_context: InvocationContext
) -> Optional[types.Content]:
...
```
=== "TypeScript"
```typescript
async beforeRunCallback(invocationContext: InvocationContext): Promise<Content | undefined> {
// ์ฌ๊ธฐ์ ๊ตฌํ์ ์์ฑํฉ๋๋ค
}
```
```java
@Override
public Maybe<Content> beforeRunCallback(InvocationContext invocationContext) {
return Maybe.empty();
}
์์ด์ ํธ ์คํ ์ฝ๋ฐฑ¶
์์ด์ ํธ ์คํ ์ฝ๋ฐฑ(before_agent, after_agent)์ Runner ๊ฐ์ฒด๊ฐ ์์ด์ ํธ๋ฅผ ํธ์ถํ ๋ ๋ฐ์ํฉ๋๋ค. before_agent_callback์ ์์ด์ ํธ์ ์ฃผ์ ์์
์ด ์์๋๊ธฐ ์ง์ ์ ์คํ๋ฉ๋๋ค. ์ฃผ์ ์์
์ ๋ชจ๋ธ ๋๋ ๋๊ตฌ ํธ์ถ์ ํฌํจํ ์ ์๋ ์์ฒญ ์ฒ๋ฆฌ์ ์ ์ฒด ์์ด์ ํธ ํ๋ก์ธ์ค๋ฅผ ํฌ๊ดํฉ๋๋ค. ์์ด์ ํธ๊ฐ ๋ชจ๋ ๋จ๊ณ๋ฅผ ์๋ฃํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ค๋นํ ํ after_agent_callback์ด ์คํ๋ฉ๋๋ค. Python์์๋ ์์ด์ ํธ ์คํ์์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด after_agent_callback ๋์ on_agent_error_callback(*, agent, callback_context, error)์ด ์คํ๋ฉ๋๋ค. ์ด ์ฝ๋ฐฑ์ ์คํจ๋ง ๊ด์ฐฐํ๋ฉฐ ๋ฐํ ๊ฐ์ ๋ฌด์๋๊ณ ์๋ ์์ธ๊ฐ ๊ทธ๋๋ก ๋ฐ์ํฉ๋๋ค.
์ฃผ์: ์ด๋ฌํ ์ฝ๋ฐฑ์ ๊ตฌํํ๋ ํ๋ฌ๊ทธ์ธ์ ์์ด์ ํธ ์์ค ์ฝ๋ฐฑ์ด ์คํ๋๊ธฐ ์ ์ ์คํ๋ฉ๋๋ค. ๋ํ ํ๋ฌ๊ทธ์ธ ์์ค ์์ด์ ํธ ์ฝ๋ฐฑ์ด None ๋๋ null ์๋ต ์ด์ธ์ ๋ค๋ฅธ ๊ฐ์ ๋ฐํํ๋ฉด ์์ด์ ํธ ์์ค ์ฝ๋ฐฑ์ ์คํ๋์ง ์์ต๋๋ค (๊ฑด๋๋).
์์ด์ ํธ ๊ฐ์ฒด์ ์ผ๋ถ๋ก ์ ์๋ ์์ด์ ํธ ์ฝ๋ฐฑ์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ฝ๋ฐฑ ์ ํ์ ์ฐธ๊ณ ํ์ธ์.
๋ชจ๋ธ ์ฝ๋ฐฑ¶
๋ชจ๋ธ ์ฝ๋ฐฑ **(before_model, after_model, on_model_error)**์ ๋ชจ๋ธ ๊ฐ์ฒด๊ฐ ์คํ๋๊ธฐ ์ ํ ๋๋ ๋ชจ๋ธ ํธ์ถ์ด ์คํจํ ๋ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ์ํฉ๋๋ค.
- ์์ด์ ํธ๊ฐ AI ๋ชจ๋ธ์ ํธ์ถํด์ผ ํ๋ ๊ฒฝ์ฐ
before_model_callback์ด ๋จผ์ ์คํ๋ฉ๋๋ค. - ๋ชจ๋ธ ํธ์ถ์ด ์ฑ๊ณตํ๋ฉด
after_model_callback์ด ๋ค์์ผ๋ก ์คํ๋ฉ๋๋ค. - ๋ชจ๋ธ ํธ์ถ์ด ์์ธ์ ํจ๊ป ์คํจํ๋ฉด
on_model_error_callback์ด ๋์ ํธ๋ฆฌ๊ฑฐ๋์ด ์ ์์ ์ธ ๋ณต๊ตฌ๋ฅผ ํ์ฉํฉ๋๋ค.
์ฃผ์: before_model ๋ฐ after_model ์ฝ๋ฐฑ ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ ํ๋ฌ๊ทธ์ธ์ ๋ชจ๋ธ ์์ค ์ฝ๋ฐฑ์ด ์คํ๋๊ธฐ ์ ์ ์คํ๋ฉ๋๋ค. ๋ํ ํ๋ฌ๊ทธ์ธ ์์ค ๋ชจ๋ธ ์ฝ๋ฐฑ์ด None ๋๋ null ์๋ต ์ด์ธ์ ๋ค๋ฅธ ๊ฐ์ ๋ฐํํ๋ฉด ๋ชจ๋ธ ์์ค ์ฝ๋ฐฑ์ ์คํ๋์ง ์์ต๋๋ค (๊ฑด๋๋).
๋ชจ๋ธ ์ค๋ฅ ์ ์ฝ๋ฐฑ ์ธ๋ถ ์ ๋ณด¶
๋ชจ๋ธ ๊ฐ์ฒด์ ๋ํ ์ค๋ฅ ์ ์ฝ๋ฐฑ์ ๋ค์๊ณผ ๊ฐ์ด ์๋ํฉ๋๋ค.
- ์คํ ์์ : ๋ชจ๋ธ ํธ์ถ ์ค์ ์์ธ๊ฐ ๋ฐ์ํ ๋.
- ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก: ์ ์์ ์ธ ์ค๋ฅ ์ฒ๋ฆฌ, ํน์ ์ค๋ฅ ๋ก๊น ๋๋ "AI ์๋น์ค๋ ํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค."์ ๊ฐ์ ๋์ฒด ์๋ต ๋ฐํ.
- ํ๋ฆ ์ ์ด:
LlmResponse๊ฐ์ฒด๋ฅผ ๋ฐํํ์ฌ ์์ธ๋ฅผ ์ต์ ํ๊ณ ๋์ฒด ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํฉ๋๋ค.None์ ๋ฐํํ์ฌ ์๋ ์์ธ๊ฐ ๋ฐ์ํ๋๋ก ํ์ฉํฉ๋๋ค.
์ฐธ๊ณ : ๋ชจ๋ธ ๊ฐ์ฒด์ ์คํ์ด LlmResponse๋ฅผ ๋ฐํํ๋ฉด ์์คํ
์ ์คํ ํ๋ฆ์ ์ฌ๊ฐํ๊ณ after_model_callback์ด ์ ์์ ์ผ๋ก ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค.
๋ค์ ์ฝ๋ ์์๋ ์ด ์ฝ๋ฐฑ์ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์ ๋ณด์ฌ์ค๋๋ค.
async def on_model_error_callback(
self,
*,
callback_context: CallbackContext,
llm_request: LlmRequest,
error: Exception,
) -> Optional[LlmResponse]:
...
```
=== "TypeScript"
```typescript
async onModelErrorCallback(
context: Context,
llmRequest: LlmRequest,
error: Error
): Promise<LlmResponse | undefined> {
// ์ฌ๊ธฐ์ ๊ตฌํ์ ์์ฑํฉ๋๋ค
}
```
```java
@Override
public Maybe<LlmResponse> onModelErrorCallback(
CallbackContext callbackContext, LlmRequest.Builder llmRequest, Throwable error) {
return Maybe.empty();
}
๋๊ตฌ ์ฝ๋ฐฑ¶
ํ๋ฌ๊ทธ์ธ์ ๋ํ ๋๊ตฌ ์ฝ๋ฐฑ **(before_tool, after_tool, on_tool_error)**์ ๋๊ตฌ ์คํ ์ ํ ๋๋ ์ค๋ฅ ๋ฐ์ ์ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ์ํฉ๋๋ค.
- ์์ด์ ํธ๊ฐ ๋๊ตฌ๋ฅผ ์คํํ๋ฉด
before_tool_callback์ด ๋จผ์ ์คํ๋ฉ๋๋ค. - ๋๊ตฌ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์คํ๋๋ฉด
after_tool_callback์ด ๋ค์์ผ๋ก ์คํ๋ฉ๋๋ค. - ๋๊ตฌ๊ฐ ์์ธ๋ฅผ ๋ฐ์์ํค๋ฉด
on_tool_error_callback์ด ๋์ ํธ๋ฆฌ๊ฑฐ๋์ด ์คํจ๋ฅผ ์ฒ๋ฆฌํ ๊ธฐํ๋ฅผ ์ ๊ณตํฉ๋๋ค.on_tool_error_callback์ด dict๋ฅผ ๋ฐํํ๋ฉดafter_tool_callback์ด ์ ์์ ์ผ๋ก ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค.
์ฃผ์: ์ด๋ฌํ ์ฝ๋ฐฑ์ ๊ตฌํํ๋ ํ๋ฌ๊ทธ์ธ์ ๋๊ตฌ ์์ค ์ฝ๋ฐฑ์ด ์คํ๋๊ธฐ ์ ์ ์คํ๋ฉ๋๋ค. ๋ํ ํ๋ฌ๊ทธ์ธ ์์ค ๋๊ตฌ ์ฝ๋ฐฑ์ด None ๋๋ null ์๋ต ์ด์ธ์ ๋ค๋ฅธ ๊ฐ์ ๋ฐํํ๋ฉด ๋๊ตฌ ์์ค ์ฝ๋ฐฑ์ ์คํ๋์ง ์์ต๋๋ค (๊ฑด๋๋).
๋๊ตฌ ์ค๋ฅ ์ ์ฝ๋ฐฑ ์ธ๋ถ ์ ๋ณด¶
๋๊ตฌ ๊ฐ์ฒด์ ๋ํ ์ค๋ฅ ์ ์ฝ๋ฐฑ์ ๋ค์๊ณผ ๊ฐ์ด ์๋ํฉ๋๋ค.
- ์คํ ์์ : ๋๊ตฌ์
run๋ฉ์๋ ์คํ ์ค์ ์์ธ๊ฐ ๋ฐ์ํ ๋. - ๋ชฉ์ : ํน์ ๋๊ตฌ ์์ธ(
APIError์ ๊ฐ์)๋ฅผ ํฌ์ฐฉํ๊ณ , ์คํจ๋ฅผ ๋ก๊น ํ๊ณ , LLM์ ์ฌ์ฉ์ ์นํ์ ์ธ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ค์ ์ ๊ณตํฉ๋๋ค. - ํ๋ฆ ์ ์ด:
dict๋ฅผ ๋ฐํํ์ฌ ์์ธ๋ฅผ ์ต์ ํ๊ณ ๋์ฒด ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํฉ๋๋ค.None์ ๋ฐํํ์ฌ ์๋ ์์ธ๊ฐ ๋ฐ์ํ๋๋ก ํ์ฉํฉ๋๋ค.
์ฐธ๊ณ : dict๋ฅผ ๋ฐํํ๋ฉด ์คํ ํ๋ฆ์ด ์ฌ๊ฐ๋๊ณ after_tool_callback์ด ์ ์์ ์ผ๋ก ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค.
๋ค์ ์ฝ๋ ์์๋ ์ด ์ฝ๋ฐฑ์ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์ ๋ณด์ฌ์ค๋๋ค.
async def on_tool_error_callback(
self,
*,
tool: BaseTool,
tool_args: dict[str, Any],
tool_context: ToolContext,
error: Exception,
) -> Optional[dict]:
...
```
=== "TypeScript"
```typescript
async onToolErrorCallback(
tool: BaseTool,
toolArgs: { [key: string]: any },
context: Context,
error: Error
): Promise<{ [key:string]: any } | undefined> {
// ์ฌ๊ธฐ์ ๊ตฌํ์ ์์ฑํฉ๋๋ค
}
```
```java
@Override
public Maybe<Map<String, Object>> onToolErrorCallback(
BaseTool tool, Map<String, Object> toolArgs, ToolContext toolContext, Throwable error) {
return Maybe.empty();
}
์ด๋ฒคํธ ์ฝ๋ฐฑ¶
์ด๋ฒคํธ ์ฝ๋ฐฑ(on_event_callback)์ ์์ด์ ํธ๊ฐ ํ
์คํธ ์๋ต ๋๋ ๋๊ตฌ ํธ์ถ ๊ฒฐ๊ณผ์ ๊ฐ์ ์ถ๋ ฅ์ ์์ฑํ ๋ Event ๊ฐ์ฒด๋ก ์ถ๋ ฅํ ๋ ๋ฐ์ํฉ๋๋ค. on_event_callback์ ๊ฐ ์ด๋ฒคํธ์ ๋ํด ์คํ๋์ด ํด๋ผ์ด์ธํธ์ ์คํธ๋ฆฌ๋ฐ๋๊ธฐ ์ ์ ์ด๋ฒคํธ๋ฅผ ์์ ํ ์ ์๋๋ก ํฉ๋๋ค.
- ์คํ ์์ : ์์ด์ ํธ๊ฐ
Event๋ฅผ ์์ฑํ ํ ์ฌ์ฉ์์๊ฒ ๋ณด๋ด๊ธฐ ์ ์. ์์ด์ ํธ ์คํ์ ์ฌ๋ฌ ์ด๋ฒคํธ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. - ๋ชฉ์ : ์ด๋ฒคํธ ์์ ๋๋ ๋ณด๊ฐ(์: ๋ฉํ๋ฐ์ดํฐ ์ถ๊ฐ) ๋๋ ํน์ ์ด๋ฒคํธ์ ๋ฐ๋ผ ๋ถ์์ฉ ํธ๋ฆฌ๊ฑฐ์ ์ ์ฉํฉ๋๋ค.
- ํ๋ฆ ์ ์ด: ์๋ณธ ์ด๋ฒคํธ๋ฅผ ์ฌ์ ์ํ
Event๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. Python์์ ADK๋ ๋ฐํ๋ ์ด๋ฒคํธ๋ฅผ ์๋ณธ ์ด๋ฒคํธ์ ๋ณํฉํฉ๋๋ค. ์ฆ, ์ค์ ํ ํ๋๋ง ์ ์ฉ๋๋ฉฐid,invocation_id,timestamp๋ ํญ์ ์๋ณธ ์ด๋ฒคํธ์์ ๊ฐ์ ธ์ต๋๋ค.
๋ค์ ์ฝ๋ ์์๋ ์ด ์ฝ๋ฐฑ์ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์ ๋ณด์ฌ์ค๋๋ค.
async def on_event_callback(
self, *, invocation_context: InvocationContext, event: Event
) -> Optional[Event]:
...
```
=== "TypeScript"
```typescript
async onEventCallback(
invocationContext: InvocationContext,
event: Event
): Promise<Event | undefined> {
// ์ฌ๊ธฐ์ ๊ตฌํ์ ์์ฑํฉ๋๋ค
}
```
```java
@Override
public Maybe<Event> onEventCallback(InvocationContext invocationContext, Event event) {
return Maybe.empty();
}
๋ฌ๋ ์ข ๋ฃ ์ฝ๋ฐฑ¶
๋ฌ๋ ์ข
๋ฃ ์ฝ๋ฐฑ **(after_run_callback)**์ ์์ด์ ํธ๊ฐ ์ ์ฒด ํ๋ก์ธ์ค๋ฅผ ์๋ฃํ๊ณ ๋ชจ๋ ์ด๋ฒคํธ๊ฐ ์ฒ๋ฆฌ๋๋ฉด Runner๊ฐ ์คํ์ ์๋ฃํ ๋ ๋ฐ์ํฉ๋๋ค. after_run_callback์ ์ ๋ฆฌ ๋ฐ ์ต์ข
๋ณด๊ณ ์ ์๋ฒฝํ ์ต์ข
ํํฌ์
๋๋ค.
- ์คํ ์์ :
Runner๊ฐ ์์ฒญ ์คํ์ ์์ ํ ์๋ฃํ ํ. - ๋ชฉ์ : ์ฐ๊ฒฐ ๋ซ๊ธฐ ๋๋ ๋ก๊ทธ ๋ฐ ์ธก์ ํญ๋ชฉ ๋ฐ์ดํฐ ์ต์ข ํ์ ๊ฐ์ ์ ์ญ ์ ๋ฆฌ ์์ ์ ์ด์์ ์ ๋๋ค.
- ํ๋ฆ ์ ์ด: ์ด ์ฝ๋ฐฑ์ ํด์ฒด ์ ์ฉ์ด๋ฉฐ ์ต์ข ๊ฒฐ๊ณผ๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
๋ค์ ์ฝ๋ ์์๋ ์ด ์ฝ๋ฐฑ์ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์ ๋ณด์ฌ์ค๋๋ค.
async def after_run_callback(
self, *, invocation_context: InvocationContext
) -> None:
...
```
=== "TypeScript"
```typescript
async afterRunCallback(invocationContext: InvocationContext): Promise<void> {
// ์ฌ๊ธฐ์ ๊ตฌํ์ ์์ฑํฉ๋๋ค
}
```
```java
@Override
public Completable afterRunCallback(InvocationContext invocationContext) {
return Completable.complete();
}
Python์์ ADK๋ ํ๋ฌ๊ทธ์ธ์ ๋ ๊ฐ์ง ์๋ช ์ฃผ๊ธฐ ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐ๋ก ์๋ฆฝ๋๋ค.
on_run_error_callback(*, invocation_context, error): ์ฒ๋ฆฌ๋์ง ์์ ์์ธ๋ก ์ธํด ์คํ์ด ์คํจํ ๋after_run_callback๋์ ์คํ๋ฉ๋๋ค. ์ด ์ฝ๋ฐฑ์ ์คํจ๋ง ๊ด์ฐฐํ๋ฉฐ ๋ฐํ ๊ฐ์ ๋ฌด์๋๊ณ ์๋ ์์ธ๊ฐ ๊ทธ๋๋ก ๋ฐ์ํฉ๋๋ค.close(): ์คํ๋น ํ ๋ฒ์ด ์๋๋ผawait runner.close()๋กRunner๋ฅผ ๋ซ์ ๋ ํ๋ฌ๊ทธ์ธ๋น ํ ๋ฒ ์คํ๋ฉ๋๋ค. HTTP ํด๋ผ์ด์ธํธ๋ ์ธก์ ํญ๋ชฉ ๋ด๋ณด๋ด๊ธฐ(exporter)์ ๊ฐ์ด ํ๋ฌ๊ทธ์ธ์ด ์์ ํ ๋ฆฌ์์ค๋ฅผ ํด์ ํ๋ ๋ฐ ์ฌ์ฉํ์ธ์. ๊ฐclose()ํธ์ถ์ ๋ฌ๋์plugin_close_timeout(๊ธฐ๋ณธ๊ฐ 5์ด)์ผ๋ก ์ ํ๋ฉ๋๋ค.
์ธ์ด๋ณ ๋น ๋ฅธ ์ฐธ๊ณ ¶
ํ๋ฌ๊ทธ์ธ ์ฝ๋ฐฑ์ ์ธ์ด๋ณ๋ก ํ ๋ฒ ๋ ์ ๋ฆฌํด ๋๋ฉด, English ์๋ฌธ๊ณผ์ ํญ ๊ตฌ์กฐ๋ ๋ ๋น์ทํด์ง๋๋ค.
์ฌ์ฉ์ ๋ฉ์์ง ์ฝ๋ฐฑ ์์¶
๋ฌ๋ ์ข ๋ฃ ์ฝ๋ฐฑ ์์¶
๋ค์ ๋จ๊ณ¶
ADK ํ๋ก์ ํธ์ ํ๋ฌ๊ทธ์ธ์ ๊ฐ๋ฐํ๊ณ ์ ์ฉํ๊ธฐ ์ํ ๋ค์ ๋ฆฌ์์ค๋ฅผ ํ์ธํ์ธ์.
- ๋ ๋ง์ ADK ํ๋ฌ๊ทธ์ธ ์ฝ๋ ์์๋ ADK Samples ์ ์ฅ์๋ฅผ ์ฐธ๊ณ ํ์ธ์.
- ๋ณด์ ๋ชฉ์ ์ผ๋ก ํ๋ฌ๊ทธ์ธ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์ ๋ณด๋ ๋ณด์ ๊ฐ๋๋ ์ผ์ ์ํ ์ฝ๋ฐฑ ๋ฐ ํ๋ฌ๊ทธ์ธ์ ์ฐธ๊ณ ํ์ธ์.