LlmAgent
Le LlmAgent est le type d'agent principal dans adk-rust qui utilise un Large Language Model pour le raisonnement et la prise de décision.
Démarrage rapide
Créez un nouveau projet :
cargo new llm_agent
cd llm_agent
Ajoutez les dépendances à Cargo.toml :
[dependencies]
adk-rust = "0.2.0"
tokio = { version = "1.40", features = ["full"] }
dotenvy = "0.15"
serde_json = "1.0"
Créez un fichier .env avec votre clé API :
echo 'GOOGLE_API_KEY=your-api-key' > .env
Remplacez 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(())
}
Exécutez-le :
cargo run
Interagir avec votre Agent
Vous verrez une invite interactive :
🤖 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!
Façonner le comportement de l'Agent avec des instructions
La méthode instruction() définit la personnalité et le comportement de votre Agent. C'est le system prompt qui guide chaque réponse :
// 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()?;
Exemples de sorties
Requête utilisateur : "What is Rust?"
Assistant d'affaires formel :
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.
Tuteur de code amical :
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?
Conteur créatif :
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...
Modélisation des instructions
Les instructions prennent en charge l'injection de variables à l'aide de la syntaxe {var}. Les variables sont résolues à partir de l'état de la Session au moment de l'exécution :
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()?;
Guide étape par étape pour utiliser la modélisation :
- Créer l'Agent avec des variables de modèle dans l'instruction
- Configurer le Runner et le SessionService pour gérer l'état
- Créer une Session avec des variables d'état qui correspondent à votre modèle
- Exécuter l'Agent - les modèles sont remplacés automatiquement
Voici un exemple complet et fonctionnel :
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(())
}
Types de variables de modèle :
| Modèle | Exemple | Source |
|---|---|---|
{var} | {user_name} | État de la Session |
{prefix:var} | {user:name}, {app:config} | État préfixé |
{var?} | {user_name?} | Optionnel (vide si manquant) |
{artifact.file} | {artifact.resume.pdf} | Contenu de l'Artifact |
Exemple de sortie :
Modèle : \"You are helping {user_name}. Their role is {user_role}.\"
Devient : \"Vous aidez Alice. Leur rôle est Senior Developer.\"
L'Agent répondra ensuite avec un contenu personnalisé basé sur le nom de l'utilisateur et son niveau d'expertise !
Ajout d'Outils
Les Tools confèrent à votre Agent des capacités au-delà de la conversation — ils peuvent récupérer des données, effectuer des calculs, rechercher sur le web ou appeler des API externes. Le LLM décide quand utiliser un Tool en fonction de la demande de l'utilisateur.
Comment les Outils Fonctionnent
- L'Agent reçoit le message de l'utilisateur → "Quel temps fait-il à Tokyo ?"
- Le LLM décide d'appeler un Tool → Sélectionne
get_weatheravec{"city": "Tokyo"} - Le Tool s'exécute → Renvoie
{"temperature": "22°C", "condition": "sunny"} - Le LLM formate la réponse → "Le temps à Tokyo est ensoleillé avec une température de 22 °C."
Création d'un Outil avec FunctionTool
FunctionTool est le moyen le plus simple de créer un Tool — enveloppez n'importe quelle fonction async Rust et le LLM pourra l'appeler. Vous fournissez un nom, une description et une fonction de gestionnaire qui reçoit des arguments JSON et renvoie un résultat JSON.
let weather_tool = FunctionTool::new(
"get_weather", // Nom du Tool (utilisé par le LLM)
"Obtenir la météo actuelle pour une ville", // Description (aide le LLM à décider quand l'utiliser)
|_ctx, args| async move { // Fonction de gestionnaire
let city = args.get("city") // Extrait les arguments du JSON
.and_then(|v| v.as_str())
.unwrap_or("unknown");
Ok(json!({ "city": city, "temperature": "22°C" })) // Renvoie le résultat JSON
},
);
⚠️ Note : Limitation Actuelle : Les Tools intégrés comme
GoogleSearchToolsont actuellement incompatibles avecFunctionToolau sein du même Agent. Utilisez soit les Tools intégrés, soit lesFunctionTools personnalisés, mais pas les deux ensemble. 💡 Solution de contournement : Créez des subagents séparés, chacun avec son propre type de Tool, et coordonnez-les à l'aide d'un LlmAgent maître, d'Agents de workflow ou de schémas multi-agents.
Construire un Agent Multi-Tool
Créez un nouveau projet :
cargo new tool_agent
cd tool_agent
Ajoutez les dépendances à Cargo.toml :
[dependencies]
adk-rust = { version = "0.2.0", features = ["tools"] }
tokio = { version = "1.40", features = ["full"] }
dotenvy = "0.15"
serde_json = "1.0"
Créez .env :
echo 'GOOGLE_API_KEY=your-api-key' > .env
Remplacez src/main.rs par un Agent qui possède trois Tools :
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 : Recherche météo
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 : Calculatrice
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 : Google Search intégré (Note : Actuellement non pris en charge dans ADK-Rust)
// let search_tool = GoogleSearchTool::new();
// Construire l'Agent avec les Tools de météo et de calculatrice
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)) // Actuellement non pris en charge
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
Exécutez votre Agent :
cargo run
Exemple d'Interaction
Vous : Qu'est-ce que 15 % de 250 ?
Assistant : [Utilise l'outil calculate avec a=250, b=0.15, operation=multiply]
15 % de 250 est 37,5.
Vous : Quel temps fait-il à Tokyo ?
Assistant : [Utilise l'outil get_weather avec city=Tokyo]
Le temps à Tokyo est ensoleillé avec une température de 22 °C.
Vous : Cherche les dernières fonctionnalités de Rust
Assistant : Je n'ai pas accès à la fonctionnalité de recherche pour le moment, mais je peux vous aider avec d'autres questions sur Rust ou effectuer des calculs !
Sortie structurée avec JSON Schema
Pour les applications qui nécessitent des données structurées, utilisez 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(())
}
Exemple de sortie JSON
Entrée: "John met Sarah in Paris on December 25th"
Sortie:
{
"people": ["John", "Sarah"],
"locations": ["Paris"],
"dates": ["December 25th"]
}
Fonctionnalités avancées
Inclure le contenu
Contrôlez la visibilité de l'historique de conversation:
// Historique complet (par défaut)
.include_contents(IncludeContents::Default)
// Sans état - ne voit que l'entrée actuelle
.include_contents(IncludeContents::None)
Clé de sortie
Enregistre les réponses de l'Agent dans l'état de session:
.output_key("summary") // La réponse est enregistrée dans state["summary"]
Instructions dynamiques
Calcule les instructions à l'exécution:
.instruction_provider(|ctx| {
Box::pin(async move {
let user_id = ctx.user_id();
Ok(format!("Vous assistez l'utilisateur {}.", user_id))
})
})
Callbacks
Intercepte le comportement de l'Agent:
.before_model_callback(|ctx, request| {
Box::pin(async move {
println!("Sur le point d'appeler le LLM avec {} messages", request.contents.len());
Ok(BeforeModelResult::Continue)
})
})
Référence du constructeur
| Méthode | Description |
|---|---|
new(name) | Crée le constructeur avec le nom de l'Agent |
model(Arc<dyn Llm>) | Définit le LLM (obligatoire) |
description(text) | Description de l'Agent |
instruction(text) | Prompt système |
tool(Arc<dyn Tool>) | Ajoute un Tool |
output_schema(json) | Schéma JSON pour la sortie structurée |
output_key(key) | Enregistre la réponse dans l'état |
include_contents(mode) | Visibilité de l'historique |
build() | Crée l'Agent |
Exemple complet
Un agent prêt pour la production avec plusieurs outils (météo, calculatrice, recherche) et une sortie enregistrée dans l'état de la session :
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(())
}
Essayez ces invites :
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.
Rubriques connexes
- Agents de workflow - SequentialAgent, ParallelAgent et LoopAgent
- Systèmes multi-agents - Construction de hiérarchies d'agents
- Outils de fonction - Création d'outils personnalisés
- Rappels - Interception du comportement d'agent
Précédent: Démarrage rapide | Suivant: Agents de workflow →