आर्टिफैक्ट्स

आर्टिफैक्ट्स आपके एजेंट अनुप्रयोगों के भीतर बाइनरी डेटा (छवियां, पीडीएफ, ऑडियो फ़ाइलें, आदि) को स्टोर और पुनः प्राप्त करने का एक तरीका प्रदान करते हैं। आर्टिफैक्ट सिस्टम सत्रों में डेटा के संस्करण, नेमस्पेस स्कोपिंग और दृढ़ता को संभालता है।

अवलोकन

ADK-Rust में आर्टिफैक्ट सिस्टम में शामिल हैं:

  • Part: मुख्य डेटा प्रतिनिधित्व जो MIME प्रकारों के साथ टेक्स्ट या बाइनरी डेटा रख सकता है
  • ArtifactService: आर्टिफैक्ट स्टोरेज ऑपरेशंस को परिभाषित करने वाला ट्रेट
  • InMemoryArtifactService: विकास और परीक्षण के लिए एक इन-मेमोरी कार्यान्वयन
  • ScopedArtifacts: एक रैपर जो सत्र संदर्भ को स्वचालित रूप से संभालकर आर्टिफैक्ट ऑपरेशंस को सरल बनाता है

आर्टिफैक्ट्स को एप्लिकेशन, उपयोगकर्ता और सत्र द्वारा स्कोप किया जाता है, जो अलगाव और संगठन प्रदान करता है। फ़ाइलें सत्र-स्कोपेड (डिफ़ॉल्ट) या उपयोगकर्ता-स्कोपेड ( user: उपसर्ग का उपयोग करके) हो सकती हैं।

Part प्रतिनिधित्व

Part एनम उस डेटा का प्रतिनिधित्व करता है जिसे आर्टिफैक्ट्स के रूप में संग्रहीत किया जा सकता है:

pub enum Part {
    Text { text: String },
    InlineData { mime_type: String, data: Vec<u8> },
    FunctionCall { name: String, args: serde_json::Value },
    FunctionResponse { name: String, response: serde_json::Value },
}

आर्टिफैक्ट्स के लिए, आप मुख्य रूप से उपयोग करेंगे:

  • Part::Text टेक्स्ट डेटा के लिए
  • Part::InlineData MIME प्रकारों के साथ बाइनरी डेटा के लिए

बुनियादी उपयोग

आर्टिफैक्ट्स के साथ काम करने का सबसे सरल तरीका Artifacts ट्रेट के माध्यम से है, जो एजेंट संदर्भों पर उपलब्ध है:

use adk_rust::prelude::*;

// In an agent tool or callback
async fn save_report(ctx: &ToolContext) -> Result<Value> {
    let artifacts = ctx.artifacts();
    
    // Save text data
    let version = artifacts.save(
        "report.txt",
        &Part::Text { text: "Report content".to_string() }
    ).await?;
    
    // Save binary data
    let image_data = vec![0xFF, 0xD8, 0xFF]; // JPEG header
    artifacts.save(
        "chart.jpg",
        &Part::InlineData {
            mime_type: "image/jpeg".to_string(),
            data: image_data,
        }
    ).await?;
    
    Ok(json!({ "saved": true, "version": version }))
}

ArtifactService ट्रेट

ArtifactService ट्रेट आर्टिफैक्ट प्रबंधन के लिए मुख्य संचालन को परिभाषित करता है:

#[async_trait]
pub trait ArtifactService: Send + Sync {
    async fn save(&self, req: SaveRequest) -> Result<SaveResponse>;
    async fn load(&self, req: LoadRequest) -> Result<LoadResponse>;
    async fn delete(&self, req: DeleteRequest) -> Result<()>;
    async fn list(&self, req: ListRequest) -> Result<ListResponse>;
    async fn versions(&self, req: VersionsRequest) -> Result<VersionsResponse>;
}

Save ऑपरेशन

स्वचालित या स्पष्ट संस्करण के साथ एक आर्टिफैक्ट को सेव करें:

use adk_artifact::{InMemoryArtifactService, SaveRequest};
use adk_core::Part;

let service = InMemoryArtifactService::new();

let response = service.save(SaveRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_456".to_string(),
    file_name: "document.pdf".to_string(),
    part: Part::InlineData {
        mime_type: "application/pdf".to_string(),
        data: pdf_bytes,
    },
    version: None, // Auto-increment version
}).await?;

println!("Saved as version: {}", response.version);

Load ऑपरेशन

नवीनतम संस्करण या एक विशिष्ट संस्करण लोड करें:

use adk_artifact::LoadRequest;

// Load latest version
let response = service.load(LoadRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_456".to_string(),
    file_name: "document.pdf".to_string(),
    version: None, // Load latest
}).await?;

// Load specific version
let response = service.load(LoadRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_456".to_string(),
    file_name: "document.pdf".to_string(),
    version: Some(2), // Load version 2
}).await?;

match response.part {
    Part::InlineData { mime_type, data } => {
        println!("Loaded {} bytes of {}", data.len(), mime_type);
    }
    _ => {}
}

List ऑपरेशन

एक Session में सभी आर्टिफैक्ट्स की सूची बनाएं:

use adk_artifact::ListRequest;

let response = service.list(ListRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_456".to_string(),
}).await?;

for file_name in response.file_names {
    println!("Found artifact: {}", file_name);
}

Delete ऑपरेशन

एक विशिष्ट संस्करण या सभी संस्करणों को डिलीट करें:

use adk_artifact::DeleteRequest;

// Delete specific version
service.delete(DeleteRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_456".to_string(),
    file_name: "document.pdf".to_string(),
    version: Some(1), // Delete version 1
}).await?;

// Delete all versions
service.delete(DeleteRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_456".to_string(),
    file_name: "document.pdf".to_string(),
    version: None, // Delete all versions
}).await?;

Versions ऑपरेशन

एक आर्टिफैक्ट के सभी संस्करणों की सूची बनाएं:

use adk_artifact::VersionsRequest;

let response = service.versions(VersionsRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_456".to_string(),
    file_name: "document.pdf".to_string(),
}).await?;

println!("Available versions: {:?}", response.versions);
// Output: [3, 2, 1] (sorted newest first)

संस्करण प्रबंधन

Artifacts स्वचालित संस्करण प्रबंधन का समर्थन करते हैं:

  • जब कोई संस्करण निर्दिष्ट किए बिना सहेजा जाता है, तो सिस्टम नवीनतम संस्करण से स्वतः वृद्धि करता है
  • पहले सहेजने पर संस्करण 1 असाइन किया जाता है
  • प्रत्येक बाद का सहेजना संस्करण संख्या में वृद्धि करता है
  • आप विशिष्ट संस्करणों को लोड कर सकते हैं, हटा सकते हैं या क्वेरी कर सकते हैं
// First save - becomes version 1
let v1 = service.save(SaveRequest {
    file_name: "data.json".to_string(),
    part: Part::Text { text: "v1 data".to_string() },
    version: None,
    // ... other fields
}).await?;
assert_eq!(v1.version, 1);

// Second save - becomes version 2
let v2 = service.save(SaveRequest {
    file_name: "data.json".to_string(),
    part: Part::Text { text: "v2 data".to_string() },
    version: None,
    // ... other fields
}).await?;
assert_eq!(v2.version, 2);

// Load latest (version 2)
let latest = service.load(LoadRequest {
    file_name: "data.json".to_string(),
    version: None,
    // ... other fields
}).await?;

// Load specific version
let old = service.load(LoadRequest {
    file_name: "data.json".to_string(),
    version: Some(1),
    // ... other fields
}).await?;

नेमस्पेस स्कोपिंग

Artifacts को दो स्तरों पर स्कोप किया जा सकता है:

सेशन-स्कोपड (डिफ़ॉल्ट)

डिफ़ॉल्ट रूप से, Artifacts एक विशिष्ट सेशन तक ही सीमित होते हैं। प्रत्येक सेशन का अपना पृथक Artifact नेमस्पेस होता है:

// Session 1
service.save(SaveRequest {
    session_id: "session_1".to_string(),
    file_name: "notes.txt".to_string(),
    // ... other fields
}).await?;

// Session 2 - different artifact with same name
service.save(SaveRequest {
    session_id: "session_2".to_string(),
    file_name: "notes.txt".to_string(),
    // ... other fields
}).await?;

// These are two separate artifacts

यूजर-स्कोपड

user: प्रीफ़िक्स वाले Artifacts एक यूजर के सभी सेशन में साझा किए जाते हैं:

// Save in session 1
service.save(SaveRequest {
    session_id: "session_1".to_string(),
    file_name: "user:profile.jpg".to_string(), // user: prefix
    // ... other fields
}).await?;

// Load in session 2 - same artifact
let profile = service.load(LoadRequest {
    session_id: "session_2".to_string(),
    file_name: "user:profile.jpg".to_string(),
    // ... other fields
}).await?;

user: प्रीफ़िक्स सक्षम बनाता है:

  • कई वार्तालापों में डेटा साझा करना
  • स्थायी यूजर प्राथमिकताएं
  • यूजर-स्तर की कैशिंग

InMemoryArtifactService

InMemoryArtifactService डेवलपमेंट और टेस्टिंग के लिए उपयुक्त एक इन-मेमोरी कार्यान्वयन प्रदान करता है:

use adk_artifact::InMemoryArtifactService;
use std::sync::Arc;

let service = Arc::new(InMemoryArtifactService::new());

// Use with agents
let agent = LlmAgentBuilder::new("my_agent")
    .model(model)
    .build()?;

// The service can be passed to runners or used directly

ध्यान दें: डेटा डिस्क पर स्थायी रूप से सहेजा नहीं जाता है। उत्पादन उपयोग के लिए, डेटाबेस या क्लाउड स्टोरेज द्वारा समर्थित एक कस्टम ArtifactService को लागू करने पर विचार करें।

ScopedArtifacts

ScopedArtifacts रैपर सेशन संदर्भ को स्वचालित रूप से इंजेक्ट करके Artifacts ऑपरेशंस को सरल बनाता है:

use adk_artifact::{ScopedArtifacts, InMemoryArtifactService};
use std::sync::Arc;

let service = Arc::new(InMemoryArtifactService::new());

let artifacts = ScopedArtifacts::new(
    service,
    "my_app".to_string(),
    "user_123".to_string(),
    "session_456".to_string(),
);

// Simple API - no need to specify app/user/session
let version = artifacts.save("file.txt", &Part::Text {
    text: "content".to_string()
}).await?;

let part = artifacts.load("file.txt").await?;
let files = artifacts.list().await?;

यह वही इंटरफ़ेस है जो ToolContext::artifacts() और CallbackContext::artifacts() के माध्यम से उपलब्ध है।

सामान्य पैटर्न

मल्टीमॉडल मॉडल के साथ इमेज विश्लेषण

जब आप किसी LLM से एक artifact के रूप में संग्रहीत इमेज का विश्लेषण करवाना चाहते हैं, तो आपको इमेज को सीधे LLM अनुरोध में इंजेक्ट करने के लिए एक BeforeModel callback का उपयोग करना होगा। यह adk-go पैटर्न का अनुसरण करता है।

किसी tool का उपयोग क्यों न करें? LLM APIs में Tool प्रतिक्रियाएँ JSON टेक्स्ट होती हैं। यदि कोई tool इमेज डेटा (यहां तक कि base64-encoded भी) लौटाता है, तो मॉडल इसे टेक्स्ट के रूप में देखता है, वास्तविक इमेज के रूप में नहीं। सही मल्टीमॉडल विश्लेषण के लिए, इमेज को वार्तालाप सामग्री में Part::InlineData के रूप में शामिल किया जाना चाहिए।

use adk_rust::prelude::*;
use adk_rust::artifact::{ArtifactService, InMemoryArtifactService, SaveRequest, LoadRequest};
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<()> {
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.5-flash")?);

    // Create artifact service and save an image
    let artifact_service = Arc::new(InMemoryArtifactService::new());
    let image_bytes = std::fs::read("photo.png")?;

    artifact_service.save(SaveRequest {
        app_name: "image_app".to_string(),
        user_id: "user".to_string(),
        session_id: "init".to_string(),
        file_name: "user:photo.png".to_string(),  // user-scoped for cross-session access
        part: Part::InlineData {
            data: image_bytes,
            mime_type: "image/png".to_string(),
        },
        version: None,
    }).await?;

    // Clone for use in callback
    let callback_service = artifact_service.clone();

    let agent = LlmAgentBuilder::new("image_analyst")
        .description("Analyzes images")
        .instruction("You are an image analyst. Describe what you see in the image.")
        .model(model)
        // Use BeforeModel callback to inject image into the request
        .before_model_callback(Box::new(move |_ctx, mut request| {
            let service = callback_service.clone();
            Box::pin(async move {
                // Load the image artifact
                if let Ok(response) = service.load(LoadRequest {
                    app_name: "image_app".to_string(),
                    user_id: "user".to_string(),
                    session_id: "init".to_string(),
                    file_name: "user:photo.png".to_string(),
                    version: None,
                }).await {
                    // Inject image into the last user content
                    if let Some(last_content) = request.contents.last_mut() {
                        if last_content.role == "user" {
                            last_content.parts.push(response.part);
                        }
                    }
                }

                // Continue with the modified request
                Ok(BeforeModelResult::Continue(request))
            })
        }))
        .build()?;

    // Now when users ask "What's in the image?", the model will see the actual image
    Ok(())
}

मुख्य बिंदु:

  • संशोधित अनुरोध को मॉडल को पास करने के लिए BeforeModelResult::Continue(request) का उपयोग करें
  • यदि आप इसके बजाय एक cached प्रतिक्रिया वापस करना चाहते हैं तो BeforeModelResult::Skip(response) का उपयोग करें
  • इमेज को Part::InlineData के रूप में इंजेक्ट किया जाता है, जिसे Gemini वास्तविक इमेज डेटा के रूप में व्याख्या करता है
  • ऐसे artifacts के लिए user: उपसर्ग का उपयोग करें जो सत्रों में सुलभ होने चाहिए

PDF दस्तावेज़ विश्लेषण

Gemini मॉडल समान BeforeModel callback पैटर्न का उपयोग करके PDF दस्तावेज़ों को natively संसाधित कर सकते हैं। PDFs को MIME type application/pdf के साथ इंजेक्ट किया जाता है:

// Save PDF as artifact
artifact_service.save(SaveRequest {
    app_name: "my_app".to_string(),
    user_id: "user".to_string(),
    session_id: "init".to_string(),
    file_name: "user:document.pdf".to_string(),
    part: Part::InlineData {
        data: pdf_bytes,
        mime_type: "application/pdf".to_string(),
    },
    version: None,
}).await?;

// Use BeforeModel callback to inject PDF (same pattern as images)
.before_model_callback(Box::new(move |_ctx, mut request| {
    let service = callback_service.clone();
    Box::pin(async move {
        if let Ok(response) = service.load(LoadRequest {
            file_name: "user:document.pdf".to_string(),
            // ... other fields
        }).await {
            if let Some(last_content) = request.contents.last_mut() {
                if last_content.role == "user" {
                    last_content.parts.push(response.part);
                }
            }
        }
        Ok(BeforeModelResult::Continue(request))
    })
}))

Gemini PDF क्षमताएँ:

  • टेक्स्ट सामग्री निकालें और विश्लेषण करें
  • दस्तावेज़ों के बारे में प्रश्नों के उत्तर दें
  • अनुभागों या पूरे दस्तावेज़ों का सारांश दें
  • ~1000 पृष्ठों तक संसाधित करें
  • स्कैन किए गए दस्तावेज़ों के लिए OCR समर्थन

एक पूर्ण कार्यशील उदाहरण के लिए examples/artifacts/chat_pdf.rs देखें।

जेनरेट की गई इमेज को स्टोर करना

async fn generate_and_save_image(ctx: &ToolContext) -> Result<Value> {
    let artifacts = ctx.artifacts();
    
    // Generate image (pseudo-code)
    let image_bytes = generate_image().await?;
    
    let version = artifacts.save(
        "generated_image.png",
        &Part::InlineData {
            mime_type: "image/png".to_string(),
            data: image_bytes,
        }
    ).await?;
    
    Ok(json!({
        "message": "Image saved",
        "file": "generated_image.png",
        "version": version
    }))
}

दस्तावेज़ों को लोड और संसाधित करना

async fn process_document(ctx: &ToolContext, filename: &str) -> Result<Value> {
    let artifacts = ctx.artifacts();
    
    // Load the document
    let part = artifacts.load(filename).await?;
    
    match part {
        Part::InlineData { mime_type, data } => {
            // Process based on MIME type
            let result = match mime_type.as_str() {
                "application/pdf" => process_pdf(&data)?,
                "image/jpeg" | "image/png" => process_image(&data)?,
                _ => return Err(AdkError::Artifact("Unsupported type".into())),
            };
            
            Ok(json!({ "result": result }))
        }
        _ => Err(AdkError::Artifact("Expected binary data".into())),
    }
}

संस्करण इतिहास

async fn show_history(ctx: &ToolContext, filename: &str) -> Result<Value> {
    let artifacts = ctx.artifacts();
    
    // Get all files
    let files = artifacts.list().await?;
    
    if !files.contains(&filename.to_string()) {
        return Ok(json!({ "error": "File not found" }));
    }
    
    // Note: versions() is not available on the simple Artifacts trait
    // You would need access to the underlying ArtifactService
    
    Ok(json!({
        "file": filename,
        "exists": true
    }))
}

API संदर्भ

पूर्ण API दस्तावेज़ के लिए, देखें:

  • adk_core::Artifacts - एजेंट के उपयोग के लिए सरल ट्रेट
  • adk_artifact::ArtifactService - पूर्ण सेवा ट्रेट
  • adk_artifact::InMemoryArtifactService - इन-मेमोरी कार्यान्वयन
  • adk_artifact::ScopedArtifacts - स्कोप किया हुआ रैपर

संबंधित

  • सत्र - सत्र प्रबंधन और जीवनचक्र
  • कॉलबैक - कॉलबैक में आर्टिफैक्ट्स तक पहुँचना
  • टूल्स - कस्टम टूल्स में आर्टिफैक्ट्स का उपयोग करना

पिछला: ← कॉलबैक | अगला: इवेंट्स →