Multi-Agent-Systeme
Erstelle anspruchsvolle Anwendungen, indem du spezialisierte Agenten zu Teams kombinierst.
Übersicht über die Agentenhierarchie
Was du erstellen wirst
In diesem Leitfaden erstellst du ein Kundenservice-System, in dem ein Koordinator Anfragen an Spezialisten weiterleitet:
┌─────────────────────┐
User Query │ │
────────────────▶ │ COORDINATOR │
│ "Route to expert" │
└──────────┬──────────┘
│
┌───────────────┴───────────────┐
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ BILLING AGENT │ │ SUPPORT AGENT │
│ │ │ │
│ 💰 Payments │ │ 🔧 Tech Issues │
│ 📄 Invoices │ │ 🐛 Bug Reports │
│ 💳 Subscriptions│ │ ❓ How-To │
└──────────────────┘ └──────────────────┘
Wichtige Konzepte:
- Koordinator – Empfängt alle Anfragen und entscheidet, wer sie bearbeitet
- Spezialisten – Fokussierte Agenten, die in bestimmten Fachgebieten besonders leistungsfähig sind
- Weiterleitung – Nahtlose Übergabe vom Koordinator an einen Spezialisten
Portable TeamSpec
Verwende TeamSpec, wenn dasselbe Team in generierten
Projekten, im CLI, in der Studio-Vorschau und in Enterprise-Bereitstellungen
identisch ausgeführt werden muss. Die Spezifikation besteht aus serialisierbaren Daten; compile
verknüpft jeden deklarierten Namen mit einer beliebigen vorhandenen Agent-
Implementierung und gibt einen ausführbaren CompiledTeam-Stamm zurück. Sie fügt keine
neue Art atomarer Agenten hinzu.
use adk_agent::{
Agent, RelationshipKind, TeamMemberSpec, TeamRelationship, TeamSpec,
};
use std::sync::Arc;
let spec = TeamSpec {
name: "support_team".into(),
description: "Customer support routing".into(),
coordinator: "coordinator".into(),
members: vec![
TeamMemberSpec::new("coordinator"),
TeamMemberSpec::new("billing_agent"),
TeamMemberSpec::new("research_agent"),
],
relationships: vec![
TeamRelationship::new(
"coordinator", "billing_agent", RelationshipKind::Handoff,
),
TeamRelationship::new(
"coordinator", "research_agent", RelationshipKind::Delegate,
),
],
policy: Default::default(),
};
let root = spec.compile(vec![
Arc::new(coordinator) as Arc<dyn Agent>,
Arc::new(billing_agent),
Arc::new(research_agent),
])?;
Für die direkte Verwendung des Crates aktiviere das Feature team-tools von adk-agent, wenn die Spezifikation
Delegate enthält. Aktiviere beim übergeordneten Crate tools (oder die Stufe standard).
Spezifikationen, die nur Weiterleitungen enthalten, werden mit dem Basis-Feature-Set adk-agent kompiliert.
| Beziehung | Steuerungsverhalten | Abgesenkter Mechanismus |
|---|---|---|
Handoff | Der Aufrufer überträgt die Kontrolle und nimmt die Ausführung nicht wieder auf | Runner transfer_to_agent |
Delegate | Der Aufrufer ruft ein Mitglied auf, erhält dessen Ergebnis und nimmt die Ausführung wieder auf | AgentTool |
Ziele gelten exakt pro Mitglied. Der Compiler lehnt doppelte Mitglieder und Kanten, fehlende Endpunkte, Zyklen, nicht erreichbare Mitglieder, ungültige Grenzen, fehlende Agentenbindungen und zusätzliche Bindungen ab. Delegationskanten können Eingabe-/Ausgabe-JSON-Schemas, Kontext- und Verlaufsprojektion, exakte Zustandsschlüssel, Anforderungen an Zeitüberschreitungen und Genehmigungen, Wiederholungs-/Fallback-Verhalten sowie einen Circuit Breaker enthalten. Übergabekanten unterstützen begrenzte Wiederholungen/Fallbacks beim Start; ausschließlich für Delegationen vorgesehene Felder werden abgelehnt, anstatt stillschweigend ignoriert zu werden. Fallbacks müssen als separate Kanten deklariert werden; die Validierung erweitert deren Berechtigungen niemals.
Richtlinien auf Teamebene begrenzen die Tiefe von Übergaben/Delegationen, die Nebenläufigkeit, Ereignisse, Modell- und Tool-Aufrufe, Token, Kosten, Beziehungsanzahlen und die verstrichene Zeit. Beendigungsregeln können bei einer Eskalation, einem exakt festgelegten finalen Autor oder einer Textmarkierung abbrechen. Jedes Ereignis enthält in __adk_team_execution_v1 einen serialisierbaren Ausführungsnachweis, einschließlich des eingefrorenen Mitgliederbestands, der kausalen Delegations-/Übergabekanten, der aggregierten Nutzung und des terminalen Status. Verwenden Sie CompiledTeam::execution_snapshot, um ihn zu untersuchen, und restore_execution_snapshot, bevor Sie mit derselben Aufruf-ID fortfahren.
Eine aktive Übergabe wird am eingefrorenen Ziel fortgesetzt. Eine nicht aufgelöste Delegation wird nicht automatisch erneut abgespielt, da der generische Vertrag Agent nicht nachweisen kann, dass ein Tool-Aufruf idempotent ist; die Laufzeit gibt stattdessen einen handlungsorientierten Fehler zurück. Setzen Sie diese Delegation über ihren eigenen Checkpoint-Mechanismus fort oder schlagen Sie die Operation ausdrücklich fehl bzw. starten Sie sie neu.
Für wiederverwendbare Architekturen reduziert TeamArchitectureTemplate Supervisor-, Router- und hierarchische Voreinstellungen auf explizite TeamSpec-Daten. WorkflowArchitectureTemplate kompiliert sequenzielle, parallele, Fan-out/Fan-in- und begrenzte Review-Schleifen-Voreinstellungen aus vorhandenen Workflow-Agenten. Eine fähigkeitsbasierte Auflösung ist über TeamAgentRegistry verfügbar; die Auswahl ist deterministisch, kann Integritäts-, Versions-, Digest- und Vertrauenskennzeichnungen voraussetzen, und die ausgewählte Zusammenstellung wird im Ausführungsbeleg eingefroren.
Fähigkeiten der Ausführungsebene
Die Kompilierung überprüft die vom Quellagenten deklarierten AgentCapabilities. Eine Delegate-Quelle muss aufrufungsbezogene Laufzeitwerkzeuge verwenden, eine Handoff-Quelle muss Transfers ausgeben, und ein genehmigter Delegate muss eine Bestätigung für exakte Aufrufe unterstützen. LlmAgent und CodeActAgent deklarieren ihre unterstützten Laufzeitfähigkeiten; benutzerdefinierte Agenten behalten konservative Standardwerte bei und können capabilities() überschreiben.
Teams behalten das standardmäßige ADK-Verhalten bei: Runner-Plugins, Agenten-/Modell-/Werkzeug-Callbacks, Leitplanken, Abbruch, Anfrageidentität, Speicher, Artefakte, Sitzungen und Ereignispersistenz umschließen weiterhin die vorhandenen Mitgliedsagenten. compile_with_hooks fügt geordnete asynchrone TeamLifecycleHook-Callbacks für die Team-, Mitglieds- und exakten Beziehungsgrenzen hinzu. Hooks können Erfolg oder Fehler beobachten oder eine ausstehende Operation ablehnen, ohne deren Zielbereich zu erweitern. Runner ruft außerdem den asynchronen govern_transfer-Hook der Wurzel unmittelbar vor einer validierten Übergabe auf.
Native team.run-, team.member.run- und team.relationship.execute-Tracing-Spans übertragen Team-/Mitglieds-/Kantenidentität, Status und Beziehungsdauer über den normalen adk-telemetry-Exporter. Laufzeitfehler verwenden stabile strukturierte Codes wie agent.team.policy_denied, agent.team.budget_exceeded und agent.team.resume_unsafe.
Delegationsverträge unterscheiden Zustandslesevorgänge (stateKeys) von Schreibvorgängen
(stateWriteKeys). stateMerge: rejectConflicts weist einen Schreibvorgang eines untergeordneten Agents zurück, wenn
sich der übergeordnete Wert während der Delegation geändert hat, und artifactPrefixes begrenzt
Artefaktnamen. Das eigenständige AgentTool stellt dieselben Steuerungsmöglichkeiten bereit. Die
Standardeinstellung bleibt aus Kompatibilitätsgründen „der letzte Schreibvorgang gewinnt“;
Beziehungen zwischen Teams verwenden standardmäßig die Ablehnung von Konflikten.
CompiledTeam::resume_plan beschreibt die einzig sichere nächste Aktion nach der Wiederherstellung
einer Empfangsbestätigung: Koordinator, Übergabeziel, prüfpunktbewusster Delegate oder eine
unsichere, bei Fehlern geschlossene Delegation. validate_team_replay überprüft die Integrität der kausalen
Empfangsbestätigung, während analyze_execution die providerfreie Abdeckung der Topologie, Fehler und
die maximale kausale Tiefe für Tests und Evaluierungspipelines meldet.
BlackboardSpec behandelt gesteuertes Round-Robin und durch einen Selektor gesteuerten Gruppenchat. Es
begrenzt Runden und die Projektion des Transkripts, und bei Selektorübergängen werden exakte
Zulassungslisten verwendet. Die bestehende
sub_agent-Komposition wird aus Gründen der Abwärtskompatibilität weiterhin unterstützt, ist
jedoch ein In-Memory-Baum und keine portable Teamdefinition.
Schnellstart
1. Projekt erstellen
cargo new multi_agent_demo
cd multi_agent_demo
Füge Abhängigkeiten zu Cargo.toml hinzu:
[dependencies]
adk-rust = "2.1.0"
tokio = { version = "1", features = ["full"] }
dotenvy = "0.15"
Erstelle .env mit deinem API-Schlüssel:
echo 'GOOGLE_API_KEY=your-api-key' > .env
2. Beispiel für einen Kundenservice
Hier ist ein vollständiges, funktionierendes Beispiel:
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 = Arc::new(GeminiModel::new(&api_key, "gemini-3.7-flash")?);
// Specialist: Billing Agent
let billing_agent = LlmAgentBuilder::new("billing_agent")
.description("Handles billing questions: payments, invoices, subscriptions, refunds")
.instruction("You are a billing specialist. Help customers with:\n\
- Invoice questions and payment history\n\
- Subscription plans and upgrades\n\
- Refund requests\n\
- Payment method updates\n\
Be professional and provide clear information about billing matters.")
.model(model.clone())
.build()?;
// Specialist: Technical Support Agent
let support_agent = LlmAgentBuilder::new("support_agent")
.description("Handles technical support: bugs, errors, troubleshooting, how-to questions")
.instruction("You are a technical support specialist. Help customers with:\n\
- Troubleshooting errors and bugs\n\
- How-to questions about using the product\n\
- Configuration and setup issues\n\
- Performance problems\n\
Be patient and provide step-by-step guidance.")
.model(model.clone())
.build()?;
// Coordinator: Routes to appropriate specialist
let coordinator = LlmAgentBuilder::new("coordinator")
.description("Main customer service coordinator")
.instruction("You are a customer service coordinator. Analyze each customer request:\n\n\
- For BILLING questions (payments, invoices, subscriptions, refunds):\n\
Transfer to billing_agent\n\n\
- For TECHNICAL questions (errors, bugs, how-to, troubleshooting):\n\
Transfer to support_agent\n\n\
- For GENERAL greetings or unclear requests:\n\
Respond yourself and ask clarifying questions\n\n\
When transferring, briefly acknowledge the customer and explain the handoff.")
.model(model.clone())
.sub_agent(Arc::new(billing_agent))
.sub_agent(Arc::new(support_agent))
.build()?;
println!("🏢 Customer Service Center");
println!(" Coordinator → Billing Agent | Support Agent");
println!();
Launcher::new(Arc::new(coordinator)).run().await?;
Ok(())
}
Beispielinteraktion:
You: I have a question about my last invoice
[Agent: coordinator]
Assistant: I'll connect you with our billing specialist to help with your invoice question.
[Agent: billing_agent]
Assistant: Hello! I can help you with your invoice. What specific question do you have about your last invoice?
You: Why was I charged twice?
[Agent: billing_agent]
Assistant: I understand your concern about the duplicate charge. Let me help you investigate this...
So funktioniert die Übergabe zwischen mehreren Agents
Der Überblick
Wenn du einem übergeordneten Agent untergeordnete Agents hinzufügst, erhält der LLM die Möglichkeit, die Kontrolle zu übergeben:
┌─────────────────────┐
User Message │ │
─────────────────▶ COORDINATOR │
│ │
└──────────┬──────────┘
│
"This is a billing question..."
│
┌────────────────┴────────────────┐
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ billing_agent │ │ support_agent │
│ 💰 Payments │ │ 🔧 Tech Issues │
│ 📄 Invoices │ │ 🐛 Bug Reports │
└──────────────────┘ └──────────────────┘
Ablauf der Übergabe Schritt für Schritt
Hier ist genau beschrieben, was geschieht, wenn ein Benutzer eine Frage zur Abrechnung stellt:
┌──────────────────────────────────────────────────────────────────────┐
│ STEP 1: User sends message │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ User: "Why was I charged twice on my invoice?" │
│ │
│ ↓ │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ COORDINATOR AGENT │ │
│ │ Receives message first │ │
│ └──────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────────────┐
│ STEP 2: LLM analyzes and decides to transfer │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 🧠 LLM thinks: "This is about an invoice charge..." │
│ "Invoice = billing topic..." │
│ "I should transfer to billing_agent" │
│ │
│ 📞 LLM calls: transfer_to_agent(agent_name="billing_agent") │
│ │
└──────────────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────────────┐
│ STEP 3: Runner detects transfer and invokes target │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ transfer event ┌─────────────────┐ │
│ │ Runner │ ─────────────────────▶ │ billing_agent │ │
│ └─────────┘ (same user message) └─────────────────┘ │
│ │
│ • Runner finds "billing_agent" in agent tree │
│ • Creates new context with SAME user message │
│ • Invokes billing_agent immediately │
│ │
└──────────────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────────────┐
│ STEP 4: Target agent responds │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ billing_agent responds │ │
│ │ │ │
│ │ "I can help with your duplicate │ │
│ │ charge. Let me investigate..." │ │
│ └─────────────────────────────────────────┘ │
│ │
│ ✅ User sees seamless response - no interruption! │
│ │
└──────────────────────────────────────────────────────────────────────┘
Was macht dies möglich
| Komponente | Rolle |
|---|---|
.sub_agent() | Registriert Spezialisten unter dem übergeordneten Element |
transfer_to_agent Werkzeug | Wird automatisch eingefügt, wenn Unteragenten vorhanden sind |
| Agentenbeschreibungen | Hilft LLM zu entscheiden, welcher Agent welche Aufgabe übernimmt |
| Ausführer | Erkennt Übertragungsereignisse und ruft den Zielagenten auf |
| Gemeinsame Sitzung | Status und Verlauf bleiben bei Übertragungen erhalten |
Vorher vs. Nachher beim Hinzufügen von Unteragenten
Ohne Unteragenten – Ein Agent erledigt alles:
User ──▶ coordinator ──▶ Response (handles billing AND support)
Mit Unteragenten – Spezialisten kümmern sich um ihren jeweiligen Bereich:
User ──▶ coordinator ──▶ billing_agent ──▶ Response (billing expert)
──▶ support_agent ──▶ Response (tech expert)
Hierarchische Multi-Agenten-Systeme
Für komplexe Szenarien können Sie mehrstufige Hierarchien erstellen. Jeder Agent kann eigene Unteragenten haben, wodurch ein Baum entsteht:
Visualisierung: Content-Team mit 3 Ebenen
┌─────────────────────┐
│ PROJECT MANAGER │ ← Level 1: Top-level coordinator
│ "Manage projects" │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ CONTENT CREATOR │ ← Level 2: Mid-level coordinator
│ "Coordinate R&W" │
└──────────┬──────────┘
│
┌────────────────┴────────────────┐
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ RESEARCHER │ │ WRITER │ ← Level 3: Specialists
│ │ │ │
│ 📚 Gather facts │ │ ✍️ Write content │
│ 🔍 Analyze data │ │ 📝 Polish text │
│ 📊 Find sources │ │ 🎨 Style & tone │
└──────────────────┘ └──────────────────┘
So werden Anfragen weitergeleitet
User: "Create a blog post about electric vehicles"
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PROJECT MANAGER: "This is a content task" │
│ → transfers to content_creator │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ CONTENT CREATOR: "Need research first, then writing" │
│ → transfers to researcher │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ RESEARCHER: "Here's what I found about EVs..." │
│ → provides research summary │
└─────────────────────────────────────────────────────────────┘
Vollständiger Beispielcode
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 = Arc::new(GeminiModel::new(&api_key, "gemini-3.7-flash")?);
// Level 3: Leaf specialists
let researcher = LlmAgentBuilder::new("researcher")
.description("Researches topics and gathers comprehensive information")
.instruction("You are a research specialist. When asked to research a topic:\n\
- Gather key facts and data\n\
- Identify main themes and subtopics\n\
- Note important sources or references\n\
Provide thorough, well-organized research summaries.")
.model(model.clone())
.build()?;
let writer = LlmAgentBuilder::new("writer")
.description("Writes polished content based on research")
.instruction("You are a content writer. When asked to write:\n\
- Create engaging, clear content\n\
- Use appropriate tone for the audience\n\
- Structure content logically\n\
- Polish for grammar and style\n\
Produce professional, publication-ready content.")
.model(model.clone())
.build()?;
// Level 2: Content coordinator
let content_creator = LlmAgentBuilder::new("content_creator")
.description("Coordinates content creation by delegating research and writing")
.instruction("You are a content creation lead. For content requests:\n\n\
- If RESEARCH is needed: Transfer to researcher\n\
- If WRITING is needed: Transfer to writer\n\
- For PLANNING or overview: Handle yourself\n\n\
Coordinate between research and writing phases.")
.model(model.clone())
.sub_agent(Arc::new(researcher))
.sub_agent(Arc::new(writer))
.build()?;
// Level 1: Top-level manager
let project_manager = LlmAgentBuilder::new("project_manager")
.description("Manages projects and coordinates with content team")
.instruction("You are a project manager. For incoming requests:\n\n\
- For CONTENT creation tasks: Transfer to content_creator\n\
- For PROJECT STATUS or general questions: Handle yourself\n\n\
Keep track of overall project goals and deadlines.")
.model(model.clone())
.sub_agent(Arc::new(content_creator))
.build()?;
println!("📊 Hierarchical Multi-Agent System");
println!();
println!(" project_manager");
println!(" └── content_creator");
println!(" ├── researcher");
println!(" └── writer");
println!();
Launcher::new(Arc::new(project_manager)).run().await?;
Ok(())
}
Agentenhierarchie:
project_manager
└── content_creator
├── researcher
└── writer
Beispielanfragen:
- „Erstelle einen Blogbeitrag über KI im Gesundheitswesen“ → Projektmanager → Content-Ersteller → Autor
- „Recherchiere Elektrofahrzeuge“ → Projektmanager → Content-Ersteller → Rechercheur
Konfiguration von Unteragenten
Fügen Sie jedem LlmAgent mit der sub_agent()-Builder-Methode Unteragenten hinzu:
let parent = LlmAgentBuilder::new("parent")
.description("Coordinates specialized tasks")
.instruction("Route requests to appropriate specialists.")
.model(model.clone())
.sub_agent(Arc::new(specialist_a))
.sub_agent(Arc::new(specialist_b))
.build()?;
Wichtige Punkte:
- Jeder Agent kann mehrere Unteragenten haben
- Unteragenten können eigene Unteragenten haben (mehrstufige Hierarchien)
- Agentennamen müssen innerhalb der Hierarchie eindeutig sein
- Beschreibungen helfen LLM bei der Entscheidung, an welchen Agenten die Anfrage weitergeleitet werden soll
Effektive Anweisungen zur Weiterleitung verfassen
Stellen Sie für erfolgreiche Agentenweiterleitungen klare Anweisungen und Beschreibungen bereit:
Anweisungen für den übergeordneten Agenten
let coordinator = LlmAgentBuilder::new("coordinator")
.description("Main customer service coordinator")
.instruction("You are a customer service coordinator. Analyze each request:\n\n\
- For BILLING questions (payments, invoices, subscriptions):\n\
Transfer to billing_agent\n\n\
- For TECHNICAL questions (errors, bugs, troubleshooting):\n\
Transfer to support_agent\n\n\
- For GENERAL greetings or unclear requests:\n\
Respond yourself and ask clarifying questions")
.model(model.clone())
.sub_agent(Arc::new(billing_agent))
.sub_agent(Arc::new(support_agent))
.build()?;
Beschreibungen der Unteragenten
let billing_agent = LlmAgentBuilder::new("billing_agent")
.description("Handles billing questions: payments, invoices, subscriptions, refunds")
.instruction("You are a billing specialist. Help with payment and subscription issues.")
.model(model.clone())
.build()?;
let support_agent = LlmAgentBuilder::new("support_agent")
.description("Handles technical support: bugs, errors, troubleshooting, how-to questions")
.instruction("You are a technical support specialist. Provide step-by-step guidance.")
.model(model.clone())
.build()?;
Bewährte Vorgehensweisen:
- Verwenden Sie aussagekräftige Agentennamen, die ihren Zweck klar erkennen lassen
- Verfassen Sie detaillierte Beschreibungen – LLM verwendet diese, um über Weiterleitungen zu entscheiden
- Fügen Sie spezifische Schlüsselwörter in die Beschreibungen ein, die zu wahrscheinlichen Benutzeranfragen passen
- Geben Sie in den Anweisungen des übergeordneten Agenten klare Delegierungsregeln an
- Verwenden Sie in den Agentenbeschreibungen eine einheitliche Terminologie
Testen Ihres Multi-Agenten-Systems
Beispiele ausführen
cargo run --manifest-path examples/tier_examples/enterprise/Cargo.toml --bin 14-enterprise-multi-agent
Beispiel-Testanfragen
Kundenservice:
- „Ich habe eine Frage zu meiner letzten Rechnung“ → Sollte an
billing_agentweitergeleitet werden - „Die App stürzt ständig ab“ → Sollte an
support_agentweitergeleitet werden - „Wie kann ich meinen Tarif upgraden?“ → Sollte an
billing_agentweitergeleitet werden - „Hallo, ich brauche Hilfe“ → Sollte zur Klärung bei
coordinatorbleiben
Hierarchisch:
- „Erstelle einen Blogbeitrag über KI im Gesundheitswesen“ → PM → Content Creator → Writer
- „Recherchiere die Geschichte von Elektrofahrzeugen“ → PM → Content Creator → Researcher
- „Wie ist der Status unserer aktuellen Projekte?“ → Sollte bei
project_managerbleiben
Probleme bei der Weiterleitung beheben
Wenn Weiterleitungen nicht wie erwartet funktionieren:
- Agentennamen überprüfen – Sie müssen in Weiterleitungsaufrufen exakt übereinstimmen
- Beschreibungen überprüfen – Formuliere sie spezifischer und mit relevanten Schlüsselwörtern
- Anweisungen präzisieren – Lege ausdrücklich fest, wann weitergeleitet werden soll
- Grenzfälle testen – Probiere mehrdeutige Anfragen aus, um das Weiterleitungsverhalten zu beobachten
- Auf Weiterleitungsindikatoren achten –
[Agent: name]zeigt, welcher Agent antwortet
Globale Anweisung
Grundlegende Verwendung
let agent = LlmAgentBuilder::new("assistant")
.description("A helpful assistant")
.global_instruction(
"You are a professional assistant for Acme Corp. \
Always maintain a friendly but professional tone. \
Our company values are: customer-first, innovation, and integrity."
)
.instruction("Help users with their questions and tasks.")
.model(model.clone())
.build()?;
Globale Anweisung vs. Agentenanweisung
- Globale Anweisung: Wird auf alle Agenten in der Hierarchie angewendet und legt die übergreifende Persönlichkeit sowie den Kontext fest
- Agentenanweisung: Ist für jeden Agenten spezifisch und definiert dessen jeweilige Rolle und sein Verhalten
Beide Anweisungen werden in den Gesprächsverlauf aufgenommen, wobei die globale Anweisung zuerst erscheint.
Dynamische globale Anweisungen
Für fortgeschrittenere Szenarien kannst du einen Anbieter für globale Anweisungen verwenden, der die Anweisung dynamisch berechnet:
use adk_core::GlobalInstructionProvider;
let provider: GlobalInstructionProvider = Arc::new(|ctx| {
Box::pin(async move {
// Access context information
let user_id = ctx.user_id();
// Compute dynamic instruction
let instruction = format!(
"You are assisting user {}. Tailor your responses to their preferences.",
user_id
);
Ok(instruction)
})
});
let agent = LlmAgentBuilder::new("assistant")
.description("A personalized assistant")
.global_instruction_provider(provider)
.model(model.clone())
.build()?;
Injektion von Zustandsvariablen
Sowohl globale als auch Agentenanweisungen unterstützen die Injektion von Zustandsvariablen mithilfe der Syntax {variable}:
// Set state in a previous agent or tool
// state["company_name"] = "Acme Corp"
// state["user_role"] = "manager"
let agent = LlmAgentBuilder::new("assistant")
.global_instruction(
"You are an assistant for {company_name}. \
The user is a {user_role}."
)
.instruction("Help with {user_role}-level tasks.")
.model(model.clone())
.build()?;
Das Framework fügt automatisch Werte aus dem Sitzungszustand in die Vorlagen der Anweisungen ein.
Allgemeine Muster für mehrere Agenten
Koordinator-/Dispatcher-Muster
Ein zentraler Agent leitet Anfragen an spezialisierte Subagenten weiter:
let billing = LlmAgentBuilder::new("billing")
.description("Handles billing and payment questions")
.model(model.clone())
.build()?;
let support = LlmAgentBuilder::new("support")
.description("Provides technical support")
.model(model.clone())
.build()?;
let coordinator = LlmAgentBuilder::new("coordinator")
.instruction("Route requests to billing or support agents as appropriate.")
.sub_agent(Arc::new(billing))
.sub_agent(Arc::new(support))
.model(model.clone())
.build()?;
Beispielkonversation:
User: I have a question about my last invoice
[Agent: coordinator]
Assistant: I'll connect you with our billing specialist.
🔄 [Transfer requested to: billing]
[Agent: billing]
Assistant: Hello! I can help you with your invoice.
What specific question do you have?
User: Why was I charged twice?
[Agent: billing]
Assistant: Let me investigate that duplicate charge for you...
Wichtige Punkte:
- Der Koordinator analysiert die Anfrage und übergibt sie an den Abrechnungsagenten
- Der Abrechnungsagent antwortet sofort in derselben Runde
- Nachfolgende Nachrichten werden mit dem Abrechnungsagenten fortgesetzt
- Übergabeindikatoren (
🔄) zeigen an, wann Übergaben stattfinden
Hierarchische Aufgabenzerlegung
Mehrstufige Hierarchien zur Aufteilung komplexer Aufgaben:
// Low-level specialists
let researcher = LlmAgentBuilder::new("researcher")
.description("Researches topics and gathers information")
.model(model.clone())
.build()?;
let writer = LlmAgentBuilder::new("writer")
.description("Writes content based on research")
.model(model.clone())
.build()?;
// Mid-level coordinator
let content_creator = LlmAgentBuilder::new("content_creator")
.description("Creates content by coordinating research and writing")
.sub_agent(Arc::new(researcher))
.sub_agent(Arc::new(writer))
.model(model.clone())
.build()?;
// Top-level manager
let project_manager = LlmAgentBuilder::new("project_manager")
.description("Manages content creation projects")
.sub_agent(Arc::new(content_creator))
.model(model.clone())
.build()?;
Kombination mit Workflow-Agenten
Multi-Agenten-Systeme funktionieren gut mit Workflow-Agenten (Sequenziell, Parallel, Schleife):
use adk_agent::workflow::{SequentialAgent, ParallelAgent};
// Create specialized agents
let validator = LlmAgentBuilder::new("validator")
.instruction("Validate the input data.")
.output_key("validation_result")
.model(model.clone())
.build()?;
let processor = LlmAgentBuilder::new("processor")
.instruction("Process data if {validation_result} is valid.")
.output_key("processed_data")
.model(model.clone())
.build()?;
// Combine in a sequential workflow
let pipeline = SequentialAgent::new(
"validation_pipeline",
vec![Arc::new(validator), Arc::new(processor)]
);
// Use the pipeline as a sub-agent
let coordinator = LlmAgentBuilder::new("coordinator")
.description("Coordinates data processing")
.sub_agent(Arc::new(pipeline))
.model(model.clone())
.build()?;
Kommunikation zwischen Agenten
Agenten in einer Hierarchie kommunizieren über den gemeinsamen Sitzungsstatus:
// Agent A saves data to state
let agent_a = LlmAgentBuilder::new("agent_a")
.instruction("Analyze the topic and save key points.")
.output_key("key_points") // Automatically saves output to state
.model(model.clone())
.build()?;
// Agent B reads data from state
let agent_b = LlmAgentBuilder::new("agent_b")
.instruction("Expand on the key points: {key_points}")
.model(model.clone())
.build()?;
Die Konfiguration output_key speichert die endgültige Antwort eines Agenten automatisch im Sitzungsstatus, sodass sie nachfolgenden Agenten zur Verfügung steht.
AgentTool Status- und Artefaktweiterleitung
Bei Verwendung von AgentTool zum Verpacken von Agenten als Tools werden Statusänderungen und Artefakte von Subagenten automatisch an den übergeordneten Kontext weitergeleitet:
use adk_tool::AgentTool;
// Create a sub-agent that modifies state
let data_processor = LlmAgentBuilder::new("data_processor")
.instruction("Process the data and save results.")
.output_key("processed_data")
.model(model.clone())
.build()?;
// Wrap as a tool - state_delta and artifact_delta are forwarded
let processor_tool = AgentTool::new(Arc::new(data_processor));
// Parent agent can use the tool and see state changes
let coordinator = LlmAgentBuilder::new("coordinator")
.instruction("Use the data_processor tool, then access {processed_data}.")
.model(model.clone())
.tool(Arc::new(processor_tool))
.build()?;
AgentTool führt Subagenten intern im Nicht-Streaming-Modus (StreamingMode::None) aus, sodass der Subagent seine vollständige Antwort sammelt, bevor er sie an den übergeordneten Agenten zurückgibt. Dadurch werden Probleme verhindert, bei denen partielle Streaming-Blöcke leere Ergebnisse erzeugen könnten.
Dies ermöglicht einen nahtlosen Datenfluss zwischen übergeordneten und untergeordneten Agenten bei Verwendung des AgentTool-Musters.
Ausführen von Multi-Agenten-Systemen
Verwendung des Launchers
Launcher bietet eine einfache Möglichkeit, Multi-Agenten-Systeme auszuführen und zu testen:
use adk_rust::Launcher;
let coordinator = /* your multi-agent setup */;
Launcher::new(Arc::new(coordinator))
.run()
.await?;
Ausführungsmodi:
# Interactive console mode
cargo run --manifest-path examples/tier_examples/enterprise/Cargo.toml --bin 14-enterprise-multi-agent
# Use a generated API project when you need HTTP serving
cargo adk new multi_agent_api --template api
Funktionen:
- Agentenanzeigen: Zeigt, welcher Agent antwortet
[Agent: coordinator] - Transfervisualisierung: Zeigt Transferereignisse an
🔄 [Transfer requested to: billing_agent] - Nahtlose Übergaben: Der Zielagent antwortet unmittelbar nach dem Transfer
- Unterhaltungsverlauf: Bewahrt den Kontext über Agententransfers hinweg
Transfers testen
So überprüfen Sie, ob Ihr Multi-Agenten-System korrekt funktioniert:
- Agentennamen prüfen: Sie erscheinen in eckigen Klammern, wenn die Agenten antworten
- Nach Transferanzeigen suchen (
🔄), wenn Agenten die Bearbeitung übergeben - Unmittelbare Antworten der Zielagenten ohne erneute Aufforderung überprüfen
- Verschiedene Anfragearten testen, um eine korrekte Weiterleitung sicherzustellen
- Sonderfälle prüfen, z. B. die Übertragung an nicht vorhandene Agenten
Probleme bei Transfers beheben
Wenn Transfers nicht funktionieren:
- Überprüfen, ob Subagenten hinzugefügt wurden über
.sub_agent() - Agentenbeschreibungen prüfen – LLM verwendet diese, um Transfers zu entscheiden
- Anweisungen überprüfen – der übergeordnete Agent sollte erwähnen, wann eine Übertragung erfolgen soll
- Agentennamen prüfen – sie müssen in Transferaufrufen exakt übereinstimmen
- Protokollierung aktivieren, um Transferaktionen im Ereignisstrom zu sehen
Best Practices
- Klare Beschreibungen: Verfassen Sie aussagekräftige Agentennamen und -beschreibungen, damit LLM gute Transferentscheidungen treffen kann
- Spezifische Anweisungen: Geben Sie jedem Agenten klare, fokussierte Anweisungen für seine Rolle
- Globale Anweisung verwenden: Legen Sie eine einheitliche Persönlichkeit und einen einheitlichen Kontext für alle Agenten fest
- Zustandsverwaltung: Verwenden Sie
output_keyund Zustandsvariablen für die Kommunikation zwischen Agenten - Hierarchietiefe begrenzen: Halten Sie Hierarchien flach (2–3 Ebenen), um die Wartbarkeit zu verbessern
- Transferlogik testen: Überprüfen Sie, ob Agenten Anfragen an die richtigen Subagenten übertragen
Verwandte Inhalte
- LLM Agent – Zentrale Agentenkonfiguration
- Workflow-Agenten – Sequenzielle, parallele und Schleifen-Agenten
- Sitzungen – Verwaltung des Sitzungsstatus
Zurück: ← Workflow-Agenten | Weiter: Graph-Agenten →