LlmAgent

O LlmAgent é o tipo de agente central em ADK-Rust que utiliza um Modelo de Linguagem Grande para raciocínio e tomada de decisão.

Início Rápido

Crie um novo projeto:

cargo new llm_agent
cd llm_agent

Adicione as dependências ao Cargo.toml:

[dependencies]
adk-rust = "0.2.0"
tokio = { version = "1.40", features = ["full"] }
dotenvy = "0.15"
serde_json = "1.0"

Crie o arquivo .env com sua chave de API:

echo 'GOOGLE_API_KEY=your-api-key' > .env

Substitua 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(())
}

Execute-o:

cargo run

Interagindo com Seu Agent

Você verá um prompt interativo:

🤖 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!

Modelando o Comportamento do Agente com Instruções

O método instruction() define a personalidade e o comportamento do seu agente. Este é o prompt do sistema que guia cada resposta:

// Um assistente de negócios formal
let formal_agent = LlmAgentBuilder::new("formal_assistant")
    .instruction("Você é um consultor de negócios profissional. \
                 Use linguagem formal. Seja conciso e baseado em dados.")
    .model(Arc::new(model))
    .build()?;

// Um tutor de programação amigável
let tutor_agent = LlmAgentBuilder::new("code_tutor")
    .instruction("Você é um tutor de programação amigável para iniciantes. \
                 Explique conceitos de forma simples. Use exemplos. \
                 Incentive perguntas. Nunca faça o usuário se sentir mal por não saber.")
    .model(Arc::new(model))
    .build()?;

// Um contador de histórias criativo
let story_agent = LlmAgentBuilder::new("storyteller")
    .instruction("Você é um contador de histórias criativo. \
                 Crie narrativas envolventes com descrições vívidas. \
                 Use reviravoltas na trama e personagens memoráveis.")
    .model(Arc::new(model))
    .build()?;

Exemplos de Saída

Prompt do usuário: "O que é Rust?"

Assistente de Negócios Formal:

Rust é uma linguagem de programação de sistemas focada em desempenho, segurança de memória
e concorrência. Métricas chave: 0 sobrecarga de tempo de execução, 0 coleta de lixo.
A adoção cresce 30% ano a ano no setor empresarial. Recomendada para aplicações de
desempenho crítico onde a confiabilidade é primordial.

Tutor de Programação Amigável:

Ótima pergunta! 🎉 Rust é uma linguagem de programação que ajuda você a escrever código
rápido e seguro. Pense nela como um amigo prestativo que impede você de cometer
erros antes que eles aconteçam!

Aqui está um exemplo simples:
  let name = "Alice";  // Isso cria uma variável

O que torna Rust especial é que ela captura bugs em tempo de compilação, não quando
seu programa está rodando. Bem legal, né? Quer que eu explique mais?

Contador de Histórias Criativo:

No crepúsculo de 2010, em um laboratório secreto da Mozilla, um único desenvolvedor
chamado Graydon Hoare deu vida a algo extraordinário — uma linguagem
que desafiaria os antigos deuses de C e C++.

Eles a chamaram de Rust, em homenagem a um fungo que sobrevive contra todas as adversidades.
Como uma fênix ressurgindo das cinzas de falhas de segmentação e vazamentos de memória,
Rust prometeu uma nova era: velocidade sem sacrifício, poder sem perigo.

E assim, a revolução começou...

Criação de Modelos de Instrução

As instruções suportam injeção de variáveis usando a sintaxe {var}. As variáveis são resolvidas a partir do estado da sessão em tempo de execução:

let agent = LlmAgentBuilder::new("personalized")
    .instruction("Você está ajudando {user_name}. O papel deles é {user_role}. \
                 Adapte suas respostas ao nível de experiência deles.")
    .model(Arc::new(model))
    .build()?;

Guia passo a passo para usar a criação de modelos:

  1. Crie o agente com variáveis de modelo na instrução
  2. Configure o Runner e o SessionService para gerenciar o estado
  3. Crie a sessão com variáveis de estado que correspondem ao seu modelo
  4. Execute o agente - os modelos são substituídos automaticamente

Aqui está um exemplo completo e funcional:

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. Agente com instrução com modelo
    let agent = LlmAgentBuilder::new("personalized")
        .instruction("Você está ajudando {user_name}. O papel deles é {user_role}. \
                     Adapte suas respostas ao nível de experiência deles.")
        .model(Arc::new(model))
        .build()?;

    // 2. Crie o serviço de sessão e o 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. Crie a sessão com variáveis de estado
    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. Execute o agente - a instrução se torna:
    // "Você está ajudando Alice. O papel dela é Desenvolvedora Sênior..."
    let mut response_stream = runner.run(
        "user123".to_string(),
        session.id().to_string(),
        Content::new("user").with_text("Explain async/await in Rust"),
    ).await?;

    // Imprima a resposta
    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(())
}

Tipos de Variáveis de Modelo:

PatternExampleSource
{var}{user_name}Estado da sessão
{prefix:var}{user:name}, {app:config}Estado prefixado
{var?}{user_name?}Opcional (vazio se ausente)
{artifact.file}{artifact.resume.pdf}Conteúdo do artefato

Exemplo de Saída:

Modelo: "Você está ajudando {user_name}. O papel deles é {user_role}." Torna-se: "Você está ajudando Alice. O papel dela é Desenvolvedora Sênior."

O agente responderá então com conteúdo personalizado com base no nome do usuário e no nível de experiência!


Adicionando Ferramentas

Ferramentas dão ao seu Agent habilidades além da conversação — elas podem buscar dados, realizar cálculos, pesquisar na web ou chamar APIs externas. O LLM decide quando usar uma ferramenta com base na solic solicitação do usuário.

Como as Ferramentas Funcionam

  1. Agent recebe a mensagem do usuário → "Qual é a previsão do tempo em Tóquio?"
  2. LLM decide chamar a ferramenta → Seleciona get_weather com {"city": "Tokyo"}
  3. A ferramenta executa → Retorna {"temperature": "22°C", "condition": "sunny"}
  4. LLM formata a resposta → "O tempo em Tóquio está ensolarado com 22°C."

Criando uma Ferramenta com FunctionTool

FunctionTool é a maneira mais simples de criar uma ferramenta — envolva qualquer função async Rust e o LLM poderá chamá-la. Você fornece um nome, descrição e função de handler que recebe argumentos JSON e retorna um resultado 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
    },
);

⚠️ Nota: Limitação Atual: Ferramentas integradas como GoogleSearchTool são atualmente incompatíveis com FunctionTool no mesmo Agent. Use ferramentas integradas OU FunctionTools personalizados, mas não ambos juntos. 💡 Solução: Crie subagents separados, cada um com seu próprio tipo de ferramenta, e coordene-os usando um master LLMAgent, Agents de fluxo de trabalho ou padrões multi-agent.

Crie um Agente Multi-Ferramenta

Crie um novo projeto:

cargo new tool_agent
cd tool_agent

Adicione dependências ao Cargo.toml:

[dependencies]
adk-rust = { version = "0.2.0", features = ["tools"] }
tokio = { version = "1.40", features = ["full"] }
dotenvy = "0.15"
serde_json = "1.0"

Crie .env:

echo 'GOOGLE_API_KEY=your-api-key' > .env

Substitua src/main.rs por um Agent que possui três ferramentas:

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(())
}

Execute seu Agent:

cargo run

Exemplo de Interação

Você: What's 15% of 250?
Assistant: [Using calculate tool with a=250, b=0.15, operation=multiply]
15% of 250 is 37.5.

Você: What's the weather in Tokyo?
Assistant: [Using get_weather tool with city=Tokyo]
The weather in Tokyo is sunny with a temperature of 22°C.

Você: Search for latest Rust features
Assistant: I don't have access to search functionality at the moment, but I can help with other questions about Rust or perform calculations!

Saída Estruturada com JSON Schema

Para aplicações que precisam de dados estruturados, use 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(())
}

Exemplo de Saída JSON

Entrada: "John met Sarah in Paris on December 25th"

Saída:

{
  "people": ["John", "Sarah"],
  "locations": ["Paris"],
  "dates": ["December 25th"]
}

Recursos Avançados

Include Contents

Controle a visibilidade do histórico da conversa:

// Histórico completo (padrão)
.include_contents(IncludeContents::Default)

// Sem estado - vê apenas a entrada atual
.include_contents(IncludeContents::None)

Output Key

Salva as respostas do Agent no estado da Session:

.output_key("summary")  // Resposta salva em state["summary"]

Dynamic Instructions

Calcule as instruções em tempo de execução:

.instruction_provider(|ctx| {
    Box::pin(async move {
        let user_id = ctx.user_id();
        Ok(format!("You are assisting user {}.", user_id))
    })
})

Callbacks

Intercepta o comportamento do Agent:

.before_model_callback(|ctx, request| {
    Box::pin(async move {
        println!("About to call LLM with {} messages", request.contents.len());
        Ok(BeforeModelResult::Continue)
    })
})

Referência do Builder

MétodoDescrição
new(name)Cria o builder com o nome do Agent
model(Arc<dyn Llm>)Define o LLM (obrigatório)
description(text)Descrição do Agent
instruction(text)Prompt do sistema
tool(Arc<dyn Tool>)Adiciona uma Tool
output_schema(json)JSON schema para saída estruturada
output_key(key)Salva a resposta no estado
include_contents(mode)Visibilidade do histórico
build()Cria o Agent

Exemplo Completo

Um Agent pronto para produção com múltiplas ferramentas (clima, calculadora, busca) e saída salva no estado da 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(())
}

Experimente estes prompts:

You: What's 25 times 4?
Assistant: It's 100.

Você: Quanto é 25 vezes 4?
Assistente: É 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.

Você: Como está o clima em Nova York?
Assistente: O clima em Nova York está parcialmente nublado com uma temperatura de 22°C e 65% de umidade.

You: Calculate 15% tip on $85
Assistant: A 15% tip on $85 is $12.75, making the total $97.75.

Você: Calcule uma gorjeta de 15% sobre $85
Assistente: Uma gorjeta de 15% sobre $85 é $12.75, totalizando $97.75.

Relacionado


Anterior: Início Rápido | Próximo: Agents de Fluxo de Trabalho →