LlmAgent
LlmAgent는 추론 및 의사 결정을 위해 대규모 언어 모델을 사용하는 ADK-Rust의 핵심 Agent 유형입니다.
빠른 시작
새 프로젝트를 생성합니다:
cargo new llm_agent
cd llm_agent
Cargo.toml에 종속성을 추가합니다:
[dependencies]
adk-rust = "0.2.0"
tokio = { version = "1.40", features = ["full"] }
dotenvy = "0.15"
serde_json = "1.0"
API 키와 함께 .env 파일을 생성합니다:
echo 'GOOGLE_API_KEY=your-api-key' > .env
src/main.rs를 다음으로 교체합니다:
use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
let agent = LlmAgentBuilder::new("my_agent")
.instruction("You are a helpful assistant.")
.model(Arc::new(model))
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
실행합니다:
cargo run
Agent와 상호작용하기
다음과 같은 대화형 프롬프트가 표시됩니다:
🤖 Agent ready! Type your questions (or 'exit' to quit).
You: Hello! What can you help me with?
Assistant: Hello! I'm a helpful assistant. I can help you with:
- Answering questions on various topics
- Explaining concepts clearly
- Having a conversation
What would you like to know?
You: exit
👋 Goodbye!
지침으로 Agent 동작 형성하기
instruction() 메서드는 Agent의 성격과 동작을 정의합니다. 이는 모든 응답을 안내하는 시스템 프롬프트입니다.
// A formal business assistant
let formal_agent = LlmAgentBuilder::new("formal_assistant")
.instruction("You are a professional business consultant. \
Use formal language. Be concise and data-driven.")
.model(Arc::new(model))
.build()?;
// A friendly coding tutor
let tutor_agent = LlmAgentBuilder::new("code_tutor")
.instruction("You are a friendly coding tutor for beginners. \
Explain concepts simply. Use examples. \
Encourage questions. Never make the user feel bad for not knowing.")
.model(Arc::new(model))
.build()?;
// A creative storyteller
let story_agent = LlmAgentBuilder::new("storyteller")
.instruction("You are a creative storyteller. \
Craft engaging narratives with vivid descriptions. \
Use plot twists and memorable characters.")
.model(Arc::new(model))
.build()?;
출력 예시
사용자 프롬프트: "Rust란 무엇인가요?"
공식 비즈니스 비서:
Rust is a systems programming language focused on performance, memory safety,
and concurrency. Key metrics: 0 runtime overhead, 0 garbage collection.
Adoption growing 30% YoY in enterprise. Recommended for performance-critical
applications where reliability is paramount.
친근한 코딩 튜터:
Great question! 🎉 Rust is a programming language that helps you write fast
and safe code. Think of it like a helpful friend who stops you from making
mistakes before they happen!
Here's a simple example:
let name = "Alice"; // This creates a variable
What makes Rust special is that it catches bugs at compile time, not when
your program is running. Pretty cool, right? Want me to explain more?
창의적인 이야기꾼:
In the twilight of 2010, in a secret Mozilla laboratory, a lone developer
named Graydon Hoare breathed life into something extraordinary—a language
that would challenge the old gods of C and C++.
They called it Rust, named for a fungus that survives against all odds.
Like a phoenix rising from the ashes of segmentation faults and memory
leaks, Rust promised a new era: speed without sacrifice, power without peril.
And so, the revolution began...
지침 템플릿화
지침은 {var} 구문을 사용하여 변수 삽입을 지원합니다. 변수는 런타임에 세션 상태에서 확인됩니다.
let agent = LlmAgentBuilder::new("personalized")
.instruction("You are helping {user_name}. Their role is {user_role}. \
Tailor your responses to their expertise level.")
.model(Arc::new(model))
.build()?;
템플릿 사용을 위한 단계별 가이드:
- 지침에 템플릿 변수가 있는 Agent를 생성합니다.
- 상태를 관리하도록 Runner와 SessionService를 설정합니다.
- 템플릿과 일치하는 상태 변수를 사용하여 세션을 생성합니다.
- Agent를 실행합니다. - 템플릿은 자동으로 교체됩니다.
완전한 작업 예시는 다음과 같습니다.
use adk_rust::prelude::*;
use adk_rust::runner::{Runner, RunnerConfig};
use adk_rust::session::{CreateRequest, InMemorySessionService, SessionService};
use adk_rust::futures::StreamExt;
use serde_json::json;
use std::collections::HashMap;
use std::sync::Arc;
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
// 1. Agent with templated instruction
let agent = LlmAgentBuilder::new("personalized")
.instruction("You are helping {user_name}. Their role is {user_role}. \
Tailor your responses to their expertise level.")
.model(Arc::new(model))
.build()?;
// 2. Create session service and runner
let session_service = Arc::new(InMemorySessionService::new());
let runner = Runner::new(RunnerConfig {
app_name: "templating_demo".to_string(),
agent: Arc::new(agent),
session_service: session_service.clone(),
artifact_service: None,
memory_service: None,
run_config: None,
})?;
// 3. Create session with state variables
let mut state = HashMap::new();
state.insert("user_name".to_string(), json!("Alice"));
state.insert("user_role".to_string(), json!("Senior Developer"));
let session = session_service.create(CreateRequest {
app_name: "templating_demo".to_string(),
user_id: "user123".to_string(),
session_id: None,
state,
}).await?;
// 4. Run the agent - instruction becomes:
// "You are helping Alice. Their role is Senior Developer..."
let mut response_stream = runner.run(
"user123".to_string(),
session.id().to_string(),
Content::new("user").with_text("Explain async/await in Rust"),
).await?;
// Print the response
while let Some(event) = response_stream.next().await {
let event = event?;
if let Some(content) = event.content() {
for part in &content.parts {
if let Part::Text { text } = part {
print!("{}", text);
}
}
}
}
Ok(())
}
템플릿 변수 유형:
| 패턴 | 예시 | 출처 |
|---|---|---|
{var} | {user_name} | 세션 상태 |
{prefix:var} | {user:name}, {app:config} | 접두사가 붙은 상태 |
{var?} | {user_name?} | 선택 사항 (누락 시 비어 있음) |
{artifact.file} | {artifact.resume.pdf} | 아티팩트 콘텐츠 |
출력 예시:
템플릿: "You are helping {user_name}. Their role is {user_role}."
결과: "You are helping Alice. Their role is Senior Developer."
그러면 Agent는 사용자의 이름과 전문성 수준에 따라 개인화된 콘텐츠로 응답할 것입니다!
도구 추가하기
도구는 에이전트에게 대화 이상의 능력을 제공합니다. 즉, 데이터를 가져오거나, 계산을 수행하거나, 웹을 검색하거나, 외부 API를 호출할 수 있습니다. LLM은 사용자의 요청에 따라 언제 도구를 사용할지 결정합니다.
도구 작동 방식
- 에이전트가 사용자 메시지 수신 → "도쿄 날씨는 어때요?"
- LLM이 도구 호출 결정 →
{"city": "Tokyo"}로get_weather선택 - 도구 실행 →
{"temperature": "22°C", "condition": "sunny"}반환 - LLM이 응답 형식 지정 → "도쿄의 날씨는 맑고 22°C입니다."
FunctionTool로 도구 생성하기
FunctionTool은 도구를 생성하는 가장 간단한 방법입니다. 어떤 async Rust 함수라도 래핑하면 LLM이 이를 호출할 수 있습니다. 이름, 설명, 그리고 JSON 인수를 받아 JSON 결과를 반환하는 핸들러 함수를 제공합니다.
let weather_tool = FunctionTool::new(
"get_weather", // Tool name (used by LLM)
"Get the current weather for a city", // Description (helps LLM decide when to use it)
|_ctx, args| async move { // Handler function
let city = args.get("city") // Extract arguments from JSON
.and_then(|v| v.as_str())
.unwrap_or("unknown");
Ok(json!({ "city": city, "temperature": "22°C" })) // Return JSON result
},
);
⚠️ 참고: 현재 제한사항:
GoogleSearchTool과 같은 내장 도구는 현재 동일한 에이전트 내에서FunctionTool과 호환되지 않습니다. 내장 도구 또는 사용자 지정FunctionTool중 하나를 사용해야 하며, 둘 다 함께 사용할 수 없습니다. 💡 해결 방법: 각각 고유한 도구 유형을 가진 별도의 하위 에이전트를 생성하고, 마스터 LlmAgent, 워크플로 에이전트 또는 다중 에이전트 패턴을 사용하여 이들을 조정합니다.
다중 도구 에이전트 구축하기
새 프로젝트 생성:
cargo new tool_agent
cd tool_agent
Cargo.toml에 종속성 추가:
[dependencies]
adk-rust = { version = "0.2.0", features = ["tools"] }
tokio = { version = "1.40", features = ["full"] }
dotenvy = "0.15"
serde_json = "1.0"
.env 생성:
echo 'GOOGLE_API_KEY=your-api-key' > .env
src/main.rs를 세 가지 도구를 가진 에이전트로 교체:
use adk_rust::prelude::*;
use adk_rust::Launcher;
use serde_json::json;
use std::sync::Arc;
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
// Tool 1: Weather lookup
let weather_tool = FunctionTool::new(
"get_weather",
"Get the current weather for a city. Parameters: city (string)",
|_ctx, args| async move {
let city = args.get("city").and_then(|v| v.as_str()).unwrap_or("unknown");
Ok(json!({ "city": city, "temperature": "22°C", "condition": "sunny" }))
},
);
// Tool 2: Calculator
let calculator = FunctionTool::new(
"calculate",
"Perform arithmetic. Parameters: a (number), b (number), operation (add/subtract/multiply/divide)",
|_ctx, args| async move {
let a = args.get("a").and_then(|v| v.as_f64()).unwrap_or(0.0);
let b = args.get("b").and_then(|v| v.as_f64()).unwrap_or(0.0);
let op = args.get("operation").and_then(|v| v.as_str()).unwrap_or("add");
let result = match op {
"add" => a + b,
"subtract" => a - b,
"multiply" => a * b,
"divide" => if b != 0.0 { a / b } else { 0.0 },
_ => 0.0,
};
Ok(json!({ "result": result }))
},
);
// Tool 3: Built-in Google Search (Note: Currently unsupported in ADK-Rust)
// let search_tool = GoogleSearchTool::new();
// Build agent with weather and calculator tools
let agent = LlmAgentBuilder::new("multi_tool_agent")
.instruction("You are a helpful assistant. Use tools when needed: \
- get_weather for weather questions \
- calculate for math")
.model(Arc::new(model))
.tool(Arc::new(weather_tool))
.tool(Arc::new(calculator))
// .tool(Arc::new(search_tool)) // Currently unsupported
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
에이전트 실행:
cargo run
상호작용 예시
You: 250의 15%는 얼마야?
Assistant: [a=250, b=0.15, operation=multiply로 calculate 도구 사용]
250의 15%는 37.5입니다.
You: 도쿄 날씨는 어때?
Assistant: [city=Tokyo로 get_weather 도구 사용]
도쿄의 날씨는 맑고 기온은 22°C입니다.
You: 최신 Rust 기능 찾아줘
Assistant: 현재 검색 기능에 접근할 수 없지만, Rust에 대한 다른 질문에 답하거나 계산을 수행하는 데는 도움을 드릴 수 있습니다!
JSON 스키마를 사용한 구조화된 출력
구조화된 데이터가 필요한 애플리케이션의 경우, output_schema()를 사용합니다:
use adk_rust::prelude::*;
use serde_json::json;
use std::sync::Arc;
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
let extractor = LlmAgentBuilder::new("entity_extractor")
.instruction("Extract entities from the given text.")
.model(Arc::new(model))
.output_schema(json!({
"type": "object",
"properties": {
"people": {
"type": "array",
"items": { "type": "string" }
},
"locations": {
"type": "array",
"items": { "type": "string" }
},
"dates": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["people", "locations", "dates"]
}))
.build()?;
println!("Entity extractor ready!");
Ok(())
}
JSON 출력 예시
입력: "John met Sarah in Paris on December 25th"
출력:
{
"people": ["John", "Sarah"],
"locations": ["Paris"],
"dates": ["December 25th"]
}
고급 기능
콘텐츠 포함
대화 기록 가시성을 제어합니다:
// 전체 기록 (기본값)
.include_contents(IncludeContents::Default)
// 상태 비저장 - 현재 입력만 확인
.include_contents(IncludeContents::None)
출력 키
Agent 응답을 세션 상태에 저장합니다:
.output_key("summary") // 응답이 state["summary"]에 저장됩니다
동적 지침
런타임에 지침을 계산합니다:
.instruction_provider(|ctx| {
Box::pin(async move {
let user_id = ctx.user_id();
Ok(format!("You are assisting user {}.", user_id))
})
})
콜백
Agent 동작을 가로챕니다:
.before_model_callback(|ctx, request| {
Box::pin(async move {
println!("About to call LLM with {} messages", request.contents.len());
Ok(BeforeModelResult::Continue)
})
})
빌더 참조
| 메서드 | 설명 |
|---|---|
new(name) | Agent 이름으로 빌더를 생성합니다 |
model(Arc<dyn Llm>) | LLM을 설정합니다 (필수) |
description(text) | Agent 설명 |
instruction(text) | 시스템 프롬프트 |
tool(Arc<dyn Tool>) | Tool을 추가합니다 |
output_schema(json) | 구조화된 출력을 위한 JSON 스키마 |
output_key(key) | 응답을 상태에 저장합니다 |
include_contents(mode) | 기록 가시성 |
build() | Agent를 생성합니다 |
전체 예시
여러 도구(날씨, 계산기, 검색)를 사용하고 출력을 세션 상태에 저장하는 프로덕션 준비 에이전트:
use adk_rust::prelude::*;
use adk_rust::Launcher;
use serde_json::json;
use std::sync::Arc;
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
// Weather tool
let weather = FunctionTool::new(
"get_weather",
"Get weather for a city. Parameters: city (string)",
|_ctx, args| async move {
let city = args.get("city").and_then(|v| v.as_str()).unwrap_or("unknown");
Ok(json!({
"city": city,
"temperature": "22°C",
"humidity": "65%",
"condition": "partly cloudy"
}))
},
);
// Calculator tool
let calc = FunctionTool::new(
"calculate",
"Math operations. Parameters: expression (string like '2 + 2')",
|_ctx, args| async move {
let expr = args.get("expression").and_then(|v| v.as_str()).unwrap_or("0");
Ok(json!({ "expression": expr, "result": "computed" }))
},
);
// Build the full agent
let agent = LlmAgentBuilder::new("assistant")
.description("A helpful assistant with weather and calculation abilities")
.instruction("You are a helpful assistant. \
Use the weather tool for weather questions. \
Use the calculator for math. \
Be concise and friendly.")
.model(Arc::new(model))
.tool(Arc::new(weather))
.tool(Arc::new(calc))
// .tool(Arc::new(GoogleSearchTool::new())) // Currently unsupported with FunctionTool
.output_key("last_response")
.build()?;
println!("✅ Agent '{}' ready!", agent.name());
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
다음 프롬프트를 시도해 보세요:
You: What's 25 times 4?
Assistant: It's 100.
You: How's the weather in New York?
Assistant: The weather in New York is partly cloudy with a temperature of 22°C and 65% humidity.
You: Calculate 15% tip on $85
Assistant: A 15% tip on $85 is $12.75, making the total $97.75.
관련 항목
- 워크플로우 에이전트 - Sequential, Parallel, Loop 에이전트
- 다중 에이전트 시스템 - 에이전트 계층 구조 구축
- 함수 도구 - 사용자 지정 도구 생성
- 콜백 - 에이전트 동작 가로채기
이전: 빠른 시작 | 다음: 워크플로우 에이전트 →