llm_xml_caster 0.1.0

An XML caster for LLM structured output in Rust.
Documentation

llm_xml_caster: Robust XML Caster for LLM Structured Output in Rust

Crates.io Version License Docs.rs

llm_xml_caster is a powerful and reliable Rust library designed to simplify the process of extracting structured data from Large Language Models (LLMs) via XML. By leveraging Rust's type system and procedural macros, it enables developers to define data structures once and automatically generate precise XML schemas and prompts for LLMs, ensuring high-fidelity data casting.

Features

  • Schema Generation: Automatically generates detailed XML schemas (including descriptions) from Rust structs and enums for precise LLM prompting.
  • Type Safety: Integrates seamlessly with serde for safe and efficient deserialization.
  • Rich Type Support: Supports basic types, nested structs, enums, Vec<T>, Option<T>, and more.
  • LLM Integration: Provides utilities like generate_as and generate_as_with_retries for direct interaction (requires setting up the genai dependency).

Installation

Add the following to your Cargo.toml:

[dependencies]

llm_xml_caster = "0.1.0" # Current version, check crates.io for the latest

serde = { version = "1.0", features = ["derive"] }

Usage Example: Defining and Using Prompts

The core functionality is provided by the #[llm_prompt] procedural macro and the LlmPrompt trait.

1. Define Your Structure

Use #[llm_prompt] on your struct, and use #[prompt("...")] on fields to provide descriptions that guide the LLM's output.

use llm_xml_caster::{llm_prompt, LlmPrompt};
use serde::Deserialize;

#[llm_prompt]
#[derive(Deserialize, Debug, PartialEq)]
pub struct SimpleStruct {
    #[prompt("The name of the person")]
    name: String,
    #[prompt("The age of the person")]
    age: i32,
    #[prompt("Whether the person is a student (true/false, yes/no)")]
    is_student: bool,
}

2. Generate the XML Schema for LLM Prompting

The LlmPrompt trait is automatically implemented, allowing you to retrieve the schema required by the LLM:

let schema = SimpleStruct::get_prompt_schema();
// The schema output will be a detailed XML structure with descriptions:
// <SimpleStruct>
//   <name> <!-- The name of the person --> </name>
//   <age> <!-- The age of the person --> </age>
//   <is_student> <!-- Whether the person is a student (true/false, yes/no) --> </is_student>
// </SimpleStruct>

// Also get the root element name:
let root_name = SimpleStruct::root_name(); // "SimpleStruct" 

3. Deserialize the LLM's XML Output

Use quick-xml (or similar deserializers) with the output generated by the LLM:

use quick_xml::de::from_str;

let xml_output = r#"
<SimpleStruct>
    <name><![CDATA[John Doe]]></name>
    <age>30</age>
    <is_student>yes</is_student>
</SimpleStruct>
"#;

let decoded: SimpleStruct = from_str(xml_output).unwrap();

assert_eq!(decoded.name, "John Doe".to_string());
assert_eq!(decoded.is_student, true); // Custom casting logic handles 'yes'

Advanced Types (Enums and Collections)

The macro handles complex types automatically:

Nested Structs

// Requires SimpleStruct to also implement LlmPrompt
#[llm_prompt]
#[derive(Deserialize, Debug, PartialEq)]
struct NestedStruct {
    #[prompt("The person details")]
    person: SimpleStruct,
    #[prompt("The score of the person")]
    score: f32,
}

Collections (Vectors and Options)

#[llm_prompt]
#[derive(Deserialize, Debug, PartialEq)]
struct CollectionsStruct {
    #[prompt("A list of strings")]
    tags: Vec<String>, // Automatically generates repeated <item> elements
    #[prompt("An optional description")]
    description: Option<String>, // Automatically handles optional presence
}

Enums (Sum Types)

#[llm_prompt]
#[derive(Deserialize, Debug, PartialEq)]
enum TestEnum {
    #[prompt("A simple variant")]
    Simple, // Generated as <Simple/>
    #[prompt("A variant with data")]
    WithData {
        #[prompt("The value of the variant")]
        value: i32,
    }, // Generated as <WithData><value>...</value></WithData>
}

Contributing

We welcome contributions! Please check the issues and pull requests on GitHub.

License

This project is licensed under the MIT License. See the LICENSE file for details.