LLM 에이전트¶
LlmAgent
(종종 Agent
로 별칭됨)는 ADK의 핵심 구성 요소로, 애플리케이션의 "사고" 부분 역할을 합니다. 거대 언어 모델(LLM)의 힘을 활용하여 추론하고, 자연어를 이해하며, 결정을 내리고, 응답을 생성하고, 도구와 상호 작용합니다.
미리 정의된 실행 경로를 따르는 결정론적인 워크플로 에이전트와 달리, LlmAgent
의 동작은 비결정론적입니다. LLM을 사용하여 지침과 컨텍스트를 해석하고, 어떻게 진행할지, 어떤 도구를 사용할지(사용하는 경우), 또는 다른 에이전트로 제어권을 이전할지 동적으로 결정합니다.
효과적인 LlmAgent
를 구축하려면 그 정체성을 정의하고, 지침을 통해 행동을 명확하게 안내하며, 필요한 도구와 기능을 갖추는 것이 포함됩니다.
에이전트의 정체성과 목적 정의하기¶
먼저, 에이전트가 무엇이며 무엇을 위한 것인지 설정해야 합니다.
-
name
(필수): 모든 에이전트에는 고유한 문자열 식별자가 필요합니다. 이name
은 내부 작업, 특히 에이전트가 서로를 참조하거나 작업을 위임해야 하는 멀티 에이전트 시스템에서 매우 중요합니다. 에이전트의 기능을 반영하는 설명적인 이름(예:customer_support_router
,billing_inquiry_agent
)을 선택하세요.user
와 같은 예약된 이름은 피하세요. -
description
(선택 사항, 멀티 에이전트에 권장): 에이전트의 기능에 대한 간결한 요약을 제공하세요. 이 설명은 주로 다른 LLM 에이전트가 이 에이전트에게 작업을 라우팅해야 하는지 여부를 결정하는 데 사용됩니다. 동료와 구별될 수 있도록 충분히 구체적으로 작성하세요(예: "현재 청구서에 대한 문의 처리"이지 "청구 에이전트"만이 아님). -
model
(필수): 이 에이전트의 추론을 담당할 기본 LLM을 지정하세요. 이는"gemini-2.0-flash"
와 같은 문자열 식별자입니다. 모델 선택은 에이전트의 기능, 비용 및 성능에 영향을 미칩니다. 사용 가능한 옵션 및 고려 사항은 모델 페이지를 참조하세요.
에이전트 안내하기: 지침 (instruction
)¶
instruction
매개변수는 LlmAgent
의 행동을 형성하는 데 있어 가장 중요한 요소라고 할 수 있습니다. 이는 에이전트에게 다음을 알려주는 문자열(또는 문자열을 반환하는 함수)입니다:
- 핵심 작업 또는 목표.
- 성격 또는 페르소나 (예: "당신은 도움이 되는 어시스턴트입니다.", "당신은 재치 있는 해적입니다.").
- 행동에 대한 제약 (예: "X에 대한 질문에만 답변하세요.", "Y는 절대 공개하지 마세요.").
tools
를 어떻게 그리고 언제 사용해야 하는지. 각 도구의 목적과 호출되어야 하는 상황을 설명하여 도구 자체 내의 설명을 보완해야 합니다.- 출력의 원하는 형식 (예: "JSON으로 응답하세요.", "글머리 기호 목록으로 제공하세요.").
효과적인 지침을 위한 팁:
- 명확하고 구체적으로: 모호함을 피하세요. 원하는 행동과 결과를 명확하게 기술하세요.
- 마크다운 사용: 제목, 목록 등을 사용하여 복잡한 지침의 가독성을 향상시키세요.
- 예제 제공 (소수 샷): 복잡한 작업이나 특정 출력 형식의 경우, 지침에 직접 예제를 포함하세요.
- 도구 사용 안내: 도구를 나열하는 것뿐만 아니라, 에이전트가 언제 그리고 왜 사용해야 하는지 설명하세요.
상태:
- 지침은 문자열 템플릿이며,
{var}
구문을 사용하여 동적 값을 지침에 삽입할 수 있습니다. {var}
는 var라는 이름의 상태 변수 값을 삽입하는 데 사용됩니다.{artifact.var}
는 var라는 이름의 아티팩트의 텍스트 내용을 삽입하는 데 사용됩니다.- 상태 변수나 아티팩트가 존재하지 않으면 에이전트는 오류를 발생시킵니다. 오류를 무시하려면
{var?}
와 같이 변수 이름에?
를 추가할 수 있습니다.
# 예제: 지침 추가
capital_agent = LlmAgent(
model="gemini-2.0-flash",
name="capital_agent",
description="주어진 국가의 수도에 대한 사용자 질문에 답변합니다.",
instruction="""당신은 국가의 수도를 제공하는 에이전트입니다.
사용자가 국가의 수도를 물을 때:
1. 사용자의 쿼리에서 국가 이름을 식별합니다.
2. `get_capital_city` 도구를 사용하여 수도를 찾습니다.
3. 수도를 명확하게 언급하며 사용자에게 응답합니다.
예제 쿼리: "{country}의 수도는 어디인가요?"
예제 응답: "프랑스의 수도는 파리입니다."
""",
# tools는 다음에 추가됩니다.
)
// 예제: 지침 추가
LlmAgent capitalAgent =
LlmAgent.builder()
.model("gemini-2.0-flash")
.name("capital_agent")
.description("주어진 국가의 수도에 대한 사용자 질문에 답변합니다.")
.instruction(
"""
당신은 국가의 수도를 제공하는 에이전트입니다.
사용자가 국가의 수도를 물을 때:
1. 사용자의 쿼리에서 국가 이름을 식별합니다.
2. `get_capital_city` 도구를 사용하여 수도를 찾습니다.
3. 수도를 명확하게 언급하며 사용자에게 응답합니다.
예제 쿼리: "{country}의 수도는 어디인가요?"
예제 응답: "프랑스의 수도는 파리입니다."
""")
// tools는 다음에 추가됩니다.
.build();
(참고: 시스템의 모든 에이전트에 적용되는 지침의 경우, 루트 에이전트에서 global_instruction
을 사용하는 것을 고려하세요. 자세한 내용은 멀티 에이전트 섹션을 참조하세요.)
에이전트 장착하기: 도구 (tools
)¶
도구는 LLM의 내장 지식이나 추론 능력을 넘어서는 기능을 LlmAgent
에 제공합니다. 이를 통해 에이전트는 외부 세계와 상호 작용하고, 계산을 수행하며, 실시간 데이터를 가져오거나, 특정 작업을 실행할 수 있습니다.
tools
(선택 사항): 에이전트가 사용할 수 있는 도구 목록을 제공하세요. 목록의 각 항목은 다음 중 하나일 수 있습니다:- 네이티브 함수 또는 메서드 (
FunctionTool
로 래핑됨). Python ADK는 네이티브 함수를 자동으로FunctionTool
로 래핑하는 반면, Java 메서드는FunctionTool.create(...)
를 사용하여 명시적으로 래핑해야 합니다. BaseTool
을 상속하는 클래스의 인스턴스.- 다른 에이전트의 인스턴스 (
AgentTool
, 에이전트 간 위임 가능 - 멀티 에이전트 참조).
- 네이티브 함수 또는 메서드 (
LLM은 함수/도구 이름, 설명(독스트링 또는 description
필드에서), 매개변수 스키마를 사용하여 대화와 지침에 따라 어떤 도구를 호출할지 결정합니다.
# 도구 함수 정의
def get_capital_city(country: str) -> str:
"""주어진 국가의 수도를 검색합니다."""
# 실제 로직으로 교체 (예: API 호출, 데이터베이스 조회)
capitals = {"france": "Paris", "japan": "Tokyo", "canada": "Ottawa"}
return capitals.get(country.lower(), f"죄송합니다, {country}의 수도를 모릅니다.")
# 에이전트에 도구 추가
capital_agent = LlmAgent(
model="gemini-2.0-flash",
name="capital_agent",
description="주어진 국가의 수도에 대한 사용자 질문에 답변합니다.",
instruction="""당신은 국가의 수도를 제공하는 에이전트입니다... (이전 지침 텍스트)""",
tools=[get_capital_city] # 함수를 직접 제공
)
// 도구 함수 정의
// 주어진 국가의 수도를 검색합니다.
public static Map<String, Object> getCapitalCity(
@Schema(name = "country", description = "수도를 가져올 국가")
String country) {
// 실제 로직으로 교체 (예: API 호출, 데이터베이스 조회)
Map<String, String> countryCapitals = new HashMap<>();
countryCapitals.put("canada", "Ottawa");
countryCapitals.put("france", "Paris");
countryCapitals.put("japan", "Tokyo");
String result =
countryCapitals.getOrDefault(
country.toLowerCase(), "죄송합니다, " + country + "의 수도를 찾을 수 없습니다.");
return Map.of("result", result); // 도구는 맵을 반환해야 합니다
}
// 에이전트에 도구 추가
FunctionTool capitalTool = FunctionTool.create(experiment.getClass(), "getCapitalCity");
LlmAgent capitalAgent =
LlmAgent.builder()
.model("gemini-2.0-flash")
.name("capital_agent")
.description("주어진 국가의 수도에 대한 사용자 질문에 답변합니다.")
.instruction("당신은 국가의 수도를 제공하는 에이전트입니다... (이전 지침 텍스트)")
.tools(capitalTool) // 함수를 FunctionTool로 래핑하여 제공
.build();
도구에 대한 자세한 내용은 도구 섹션을 참조하세요.
고급 구성 및 제어¶
핵심 매개변수 외에도 LlmAgent
는 더 세밀한 제어를 위한 여러 옵션을 제공합니다:
LLM 생성 미세 조정 (generate_content_config
)¶
generate_content_config
를 사용하여 기본 LLM이 응답을 생성하는 방식을 조정할 수 있습니다.
generate_content_config
(선택 사항):google.genai.types.GenerateContentConfig
의 인스턴스를 전달하여temperature
(무작위성),max_output_tokens
(응답 길이),top_p
,top_k
, 안전 설정과 같은 매개변수를 제어합니다.
데이터 구조화 (input_schema
, output_schema
, output_key
)¶
LLM 에이전트
와 구조화된 데이터 교환이 필요한 시나리오를 위해 ADK는 스키마 정의를 사용하여 예상 입력 및 원하는 출력 형식을 정의하는 메커니즘을 제공합니다.
-
input_schema
(선택 사항): 예상 입력 구조를 나타내는 스키마를 정의합니다. 설정하면 이 에이전트에 전달되는 사용자 메시지 콘텐츠는 반드시 이 스키마를 준수하는 JSON 문자열이어야 합니다. 지침은 그에 따라 사용자 또는 이전 에이전트를 안내해야 합니다. -
output_schema
(선택 사항): 원하는 출력 구조를 나타내는 스키마를 정의합니다. 설정하면 에이전트의 최종 응답은 반드시 이 스키마를 준수하는 JSON 문자열이어야 합니다.- 제약:
output_schema
를 사용하면 LLM 내에서 제어된 생성이 가능하지만 에이전트가 도구를 사용하거나 다른 에이전트로 제어권을 이전하는 기능은 비활성화됩니다. 지침은 LLM이 스키마와 일치하는 JSON을 직접 생성하도록 안내해야 합니다.
- 제약:
-
output_key
(선택 사항): 문자열 키를 제공합니다. 설정하면 에이전트의 최종 응답 텍스트 콘텐츠가 이 키 아래의 세션 상태 딕셔너리에 자동으로 저장됩니다. 이는 에이전트 간 또는 워크플로 단계 간에 결과를 전달하는 데 유용합니다.- Python에서는
session.state[output_key] = agent_response_text
와 같이 보일 수 있습니다. - Java에서는
session.state().put(outputKey, agentResponseText)
입니다.
- Python에서는
입력 및 출력 스키마는 일반적으로 Pydantic
BaseModel입니다.
from pydantic import BaseModel, Field
class CapitalOutput(BaseModel):
capital: str = Field(description="국가의 수도입니다.")
structured_capital_agent = LlmAgent(
# ... 이름, 모델, 설명
instruction="""당신은 수도 정보 에이전트입니다. 국가가 주어지면 수도를 포함하는 JSON 객체로만 응답하세요. 형식: {"capital": "capital_name"}""",
output_schema=CapitalOutput, # JSON 출력 강제
output_key="found_capital" # 결과를 state['found_capital']에 저장
# 여기서 tools=[get_capital_city]를 효과적으로 사용할 수 없음
)
입력 및 출력 스키마는 google.genai.types.Schema
객체입니다.
private static final Schema CAPITAL_OUTPUT =
Schema.builder()
.type("OBJECT")
.description("수도 정보에 대한 스키마입니다.")
.properties(
Map.of(
"capital",
Schema.builder()
.type("STRING")
.description("국가의 수도입니다.")
.build()))
.build();
LlmAgent structuredCapitalAgent =
LlmAgent.builder()
// ... 이름, 모델, 설명
.instruction(
"당신은 수도 정보 에이전트입니다. 국가가 주어지면 수도를 포함하는 JSON 객체로만 응답하세요. 형식: {\"capital\": \"capital_name\"}")
.outputSchema(capitalOutput) // JSON 출력 강제
.outputKey("found_capital") // 결과를 state.get("found_capital")에 저장
// 여기서 tools(getCapitalCity)를 효과적으로 사용할 수 없음
.build();
컨텍스트 관리 (include_contents
)¶
에이전트가 이전 대화 기록을 받는지 여부를 제어합니다.
include_contents
(선택 사항, 기본값:'default'
):contents
(기록)가 LLM으로 전송되는지 여부를 결정합니다.'default'
: 에이전트가 관련 대화 기록을 받습니다.'none'
: 에이전트가 이전contents
를 받지 않습니다. 현재 지침과 현재 턴에 제공된 입력만으로 작동합니다(상태 비저장 작업 또는 특정 컨텍스트 강제에 유용).
계획 및 코드 실행¶
여러 단계를 포함하거나 코드를 실행하는 더 복잡한 추론의 경우:
planner
(선택 사항):BasePlanner
인스턴스를 할당하여 실행 전에 다단계 추론 및 계획을 활성화합니다. (멀티 에이전트 패턴 참조).code_executor
(선택 사항):BaseCodeExecutor
인스턴스를 제공하여 에이전트가 LLM의 응답에서 찾은 코드 블록(예: Python)을 실행할 수 있도록 합니다. (도구/내장 도구 참조).
종합 예제¶
코드
다음은 완전한 기본 capital_agent
입니다:
# --- Full example code demonstrating LlmAgent with Tools vs. Output Schema ---
import json # Needed for pretty printing dicts
from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
from pydantic import BaseModel, Field
# --- 1. Define Constants ---
APP_NAME = "agent_comparison_app"
USER_ID = "test_user_456"
SESSION_ID_TOOL_AGENT = "session_tool_agent_xyz"
SESSION_ID_SCHEMA_AGENT = "session_schema_agent_xyz"
MODEL_NAME = "gemini-2.0-flash"
# --- 2. Define Schemas ---
# Input schema used by both agents
class CountryInput(BaseModel):
country: str = Field(description="The country to get information about.")
# Output schema ONLY for the second agent
class CapitalInfoOutput(BaseModel):
capital: str = Field(description="The capital city of the country.")
# Note: Population is illustrative; the LLM will infer or estimate this
# as it cannot use tools when output_schema is set.
population_estimate: str = Field(description="An estimated population of the capital city.")
# --- 3. Define the Tool (Only for the first agent) ---
def get_capital_city(country: str) -> str:
"""Retrieves the capital city of a given country."""
print(f"\n-- Tool Call: get_capital_city(country='{country}') --")
country_capitals = {
"united states": "Washington, D.C.",
"canada": "Ottawa",
"france": "Paris",
"japan": "Tokyo",
}
result = country_capitals.get(country.lower(), f"Sorry, I couldn't find the capital for {country}.")
print(f"-- Tool Result: '{result}' --")
return result
# --- 4. Configure Agents ---
# Agent 1: Uses a tool and output_key
capital_agent_with_tool = LlmAgent(
model=MODEL_NAME,
name="capital_agent_tool",
description="Retrieves the capital city using a specific tool.",
instruction="""You are a helpful agent that provides the capital city of a country using a tool.
The user will provide the country name in a JSON format like {"country": "country_name"}.
1. Extract the country name.
2. Use the `get_capital_city` tool to find the capital.
3. Respond clearly to the user, stating the capital city found by the tool.
""",
tools=[get_capital_city],
input_schema=CountryInput,
output_key="capital_tool_result", # Store final text response
)
# Agent 2: Uses output_schema (NO tools possible)
structured_info_agent_schema = LlmAgent(
model=MODEL_NAME,
name="structured_info_agent_schema",
description="Provides capital and estimated population in a specific JSON format.",
instruction=f"""You are an agent that provides country information.
The user will provide the country name in a JSON format like {{"country": "country_name"}}.
Respond ONLY with a JSON object matching this exact schema:
{json.dumps(CapitalInfoOutput.model_json_schema(), indent=2)}
Use your knowledge to determine the capital and estimate the population. Do not use any tools.
""",
# *** NO tools parameter here - using output_schema prevents tool use ***
input_schema=CountryInput,
output_schema=CapitalInfoOutput, # Enforce JSON output structure
output_key="structured_info_result", # Store final JSON response
)
# --- 5. Set up Session Management and Runners ---
session_service = InMemorySessionService()
# Create separate sessions for clarity, though not strictly necessary if context is managed
session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID_TOOL_AGENT)
session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID_SCHEMA_AGENT)
# Create a runner for EACH agent
capital_runner = Runner(
agent=capital_agent_with_tool,
app_name=APP_NAME,
session_service=session_service
)
structured_runner = Runner(
agent=structured_info_agent_schema,
app_name=APP_NAME,
session_service=session_service
)
# --- 6. Define Agent Interaction Logic ---
async def call_agent_and_print(
runner_instance: Runner,
agent_instance: LlmAgent,
session_id: str,
query_json: str
):
"""Sends a query to the specified agent/runner and prints results."""
print(f"\n>>> Calling Agent: '{agent_instance.name}' | Query: {query_json}")
user_content = types.Content(role='user', parts=[types.Part(text=query_json)])
final_response_content = "No final response received."
async for event in runner_instance.run_async(user_id=USER_ID, session_id=session_id, new_message=user_content):
# print(f"Event: {event.type}, Author: {event.author}") # Uncomment for detailed logging
if event.is_final_response() and event.content and event.content.parts:
# For output_schema, the content is the JSON string itself
final_response_content = event.content.parts[0].text
print(f"<<< Agent '{agent_instance.name}' Response: {final_response_content}")
current_session = session_service.get_session(app_name=APP_NAME,
user_id=USER_ID,
session_id=session_id)
stored_output = current_session.state.get(agent_instance.output_key)
# Pretty print if the stored output looks like JSON (likely from output_schema)
print(f"--- Session State ['{agent_instance.output_key}']: ", end="")
try:
# Attempt to parse and pretty print if it's JSON
parsed_output = json.loads(stored_output)
print(json.dumps(parsed_output, indent=2))
except (json.JSONDecodeError, TypeError):
# Otherwise, print as string
print(stored_output)
print("-" * 30)
# --- 7. Run Interactions ---
async def main():
print("--- Testing Agent with Tool ---")
await call_agent_and_print(capital_runner, capital_agent_with_tool, SESSION_ID_TOOL_AGENT, '{"country": "France"}')
await call_agent_and_print(capital_runner, capital_agent_with_tool, SESSION_ID_TOOL_AGENT, '{"country": "Canada"}')
print("\n\n--- Testing Agent with Output Schema (No Tool Use) ---")
await call_agent_and_print(structured_runner, structured_info_agent_schema, SESSION_ID_SCHEMA_AGENT, '{"country": "France"}')
await call_agent_and_print(structured_runner, structured_info_agent_schema, SESSION_ID_SCHEMA_AGENT, '{"country": "Japan"}')
if __name__ == "__main__":
await main()
// --- Full example code demonstrating LlmAgent with Tools vs. Output Schema ---
import com.google.adk.agents.LlmAgent;
import com.google.adk.events.Event;
import com.google.adk.runner.Runner;
import com.google.adk.sessions.InMemorySessionService;
import com.google.adk.sessions.Session;
import com.google.adk.tools.Annotations;
import com.google.adk.tools.FunctionTool;
import com.google.genai.types.Content;
import com.google.genai.types.Part;
import com.google.genai.types.Schema;
import io.reactivex.rxjava3.core.Flowable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class LlmAgentExample {
// --- 1. Define Constants ---
private static final String MODEL_NAME = "gemini-2.0-flash";
private static final String APP_NAME = "capital_agent_tool";
private static final String USER_ID = "test_user_456";
private static final String SESSION_ID_TOOL_AGENT = "session_tool_agent_xyz";
private static final String SESSION_ID_SCHEMA_AGENT = "session_schema_agent_xyz";
// --- 2. Define Schemas ---
// Input schema used by both agents
private static final Schema COUNTRY_INPUT_SCHEMA =
Schema.builder()
.type("OBJECT")
.description("Input for specifying a country.")
.properties(
Map.of(
"country",
Schema.builder()
.type("STRING")
.description("The country to get information about.")
.build()))
.required(List.of("country"))
.build();
// Output schema ONLY for the second agent
private static final Schema CAPITAL_INFO_OUTPUT_SCHEMA =
Schema.builder()
.type("OBJECT")
.description("Schema for capital city information.")
.properties(
Map.of(
"capital",
Schema.builder()
.type("STRING")
.description("The capital city of the country.")
.build(),
"population_estimate",
Schema.builder()
.type("STRING")
.description("An estimated population of the capital city.")
.build()))
.required(List.of("capital", "population_estimate"))
.build();
// --- 3. Define the Tool (Only for the first agent) ---
// Retrieves the capital city of a given country.
public static Map<String, Object> getCapitalCity(
@Annotations.Schema(name = "country", description = "The country to get capital for")
String country) {
System.out.printf("%n-- Tool Call: getCapitalCity(country='%s') --%n", country);
Map<String, String> countryCapitals = new HashMap<>();
countryCapitals.put("united states", "Washington, D.C.");
countryCapitals.put("canada", "Ottawa");
countryCapitals.put("france", "Paris");
countryCapitals.put("japan", "Tokyo");
String result =
countryCapitals.getOrDefault(
country.toLowerCase(), "Sorry, I couldn't find the capital for " + country + ".");
System.out.printf("-- Tool Result: '%s' --%n", result);
return Map.of("result", result); // Tools must return a Map
}
public static void main(String[] args){
LlmAgentExample agentExample = new LlmAgentExample();
FunctionTool capitalTool = FunctionTool.create(agentExample.getClass(), "getCapitalCity");
// --- 4. Configure Agents ---
// Agent 1: Uses a tool and output_key
LlmAgent capitalAgentWithTool =
LlmAgent.builder()
.model(MODEL_NAME)
.name("capital_agent_tool")
.description("Retrieves the capital city using a specific tool.")
.instruction(
"""
You are a helpful agent that provides the capital city of a country using a tool.
1. Extract the country name.
2. Use the `get_capital_city` tool to find the capital.
3. Respond clearly to the user, stating the capital city found by the tool.
""")
.tools(capitalTool)
.inputSchema(COUNTRY_INPUT_SCHEMA)
.outputKey("capital_tool_result") // Store final text response
.build();
// Agent 2: Uses an output schema
LlmAgent structuredInfoAgentSchema =
LlmAgent.builder()
.model(MODEL_NAME)
.name("structured_info_agent_schema")
.description("Provides capital and estimated population in a specific JSON format.")
.instruction(
String.format("""
You are an agent that provides country information.
Respond ONLY with a JSON object matching this exact schema: %s
Use your knowledge to determine the capital and estimate the population. Do not use any tools.
""", CAPITAL_INFO_OUTPUT_SCHEMA.toJson()))
// *** NO tools parameter here - using output_schema prevents tool use ***
.inputSchema(COUNTRY_INPUT_SCHEMA)
.outputSchema(CAPITAL_INFO_OUTPUT_SCHEMA) // Enforce JSON output structure
.outputKey("structured_info_result") // Store final JSON response
.build();
// --- 5. Set up Session Management and Runners ---
InMemorySessionService sessionService = new InMemorySessionService();
sessionService.createSession(APP_NAME, USER_ID, null, SESSION_ID_TOOL_AGENT).blockingGet();
sessionService.createSession(APP_NAME, USER_ID, null, SESSION_ID_SCHEMA_AGENT).blockingGet();
Runner capitalRunner = new Runner(capitalAgentWithTool, APP_NAME, null, sessionService);
Runner structuredRunner = new Runner(structuredInfoAgentSchema, APP_NAME, null, sessionService);
// --- 6. Run Interactions ---
System.out.println("--- Testing Agent with Tool ---");
agentExample.callAgentAndPrint(
capitalRunner, capitalAgentWithTool, SESSION_ID_TOOL_AGENT, "{\"country\": \"France\"}");
agentExample.callAgentAndPrint(
capitalRunner, capitalAgentWithTool, SESSION_ID_TOOL_AGENT, "{\"country\": \"Canada\"}");
System.out.println("\n\n--- Testing Agent with Output Schema (No Tool Use) ---");
agentExample.callAgentAndPrint(
structuredRunner,
structuredInfoAgentSchema,
SESSION_ID_SCHEMA_AGENT,
"{\"country\": \"France\"}");
agentExample.callAgentAndPrint(
structuredRunner,
structuredInfoAgentSchema,
SESSION_ID_SCHEMA_AGENT,
"{\"country\": \"Japan\"}");
}
// --- 7. Define Agent Interaction Logic ---
public void callAgentAndPrint(Runner runner, LlmAgent agent, String sessionId, String queryJson) {
System.out.printf(
"%n>>> Calling Agent: '%s' | Session: '%s' | Query: %s%n",
agent.name(), sessionId, queryJson);
Content userContent = Content.fromParts(Part.fromText(queryJson));
final String[] finalResponseContent = {"No final response received."};
Flowable<Event> eventStream = runner.runAsync(USER_ID, sessionId, userContent);
// Stream event response
eventStream.blockingForEach(event -> {
if (event.finalResponse() && event.content().isPresent()) {
event
.content()
.get()
.parts()
.flatMap(parts -> parts.isEmpty() ? Optional.empty() : Optional.of(parts.get(0)))
.flatMap(Part::text)
.ifPresent(text -> finalResponseContent[0] = text);
}
});
System.out.printf("<<< Agent '%s' Response: %s%n", agent.name(), finalResponseContent[0]);
// Retrieve the session again to get the updated state
Session updatedSession =
runner
.sessionService()
.getSession(APP_NAME, USER_ID, sessionId, Optional.empty())
.blockingGet();
if (updatedSession != null && agent.outputKey().isPresent()) {
// Print to verify if the stored output looks like JSON (likely from output_schema)
System.out.printf("--- Session State ['%s']: ", agent.outputKey().get());
}
}
}
(이 예제는 핵심 개념을 보여줍니다. 더 복잡한 에이전트는 스키마, 컨텍스트 제어, 계획 등을 포함할 수 있습니다.)
관련 개념 (나중에 다룰 주제)¶
이 페이지에서는 LlmAgent
의 핵심 구성을 다루지만, 몇 가지 관련 개념은 더 고급 제어를 제공하며 다른 곳에서 자세히 설명합니다: