#prompt #structured #prompting #ai #llm #renderable

bin+lib promptkit_rs

LLM structured prompting library

4 releases

new 0.1.3 Oct 31, 2024
0.1.2 Oct 31, 2024
0.1.1 Oct 29, 2024
0.1.0 Oct 29, 2024

#218 in Machine learning

Download history 215/week @ 2024-10-24

215 downloads per month

MIT license

20KB
288 lines

promptkit-rs

promptkit-rs is a Rust library for structured prompting, designed to create expressive, reusable prompts and structured output, ideal for AI model interactions.

Features

  • 🔧 Custom Prompts – Easily define prompts with clear, structured syntax.
  • 🎨 rsx_2! Macro – Write JSX-like prompt templates for easy nesting and readability.
  • 📊 Structured Output – Define custom output types for predictable responses.
  • 🔌 Composable Components – Use Renderable to build prompts from reusable parts.

Quick Start

use promptkit_rs::{
    executors::{Executor, OpenAI},
    Prompt, Renderable, rsx_2
};

#[derive(Clone)]
struct AuthorReviewPrompt {
    authors: Vec<String>,
}

#[derive(Clone, Serialize, Deserialize, JsonSchema)]
struct AuthorReviewResult {
    #[schemars(description = "...")]
    best_author_name: String,

    #[schemars(description = "Rationale for description in a short sentence.")]
    reason: String,
}

impl Prompt for AuthorReviewPrompt {
    type Output = AuthorReviewResult;


    fn render(&self) -> String {
        rsx_2! {
            "You're a turbo book worm. You live in a hole with nothing but books. "
            "I'm going to give you a list of authors and their books. "
            "Your job is to determine who is best."

            {self.authors}
        }
    }
}

fn main() {
    let input_data = AuthorReviewPrompt { authors: vec!["J.K. Rowling".to_string(), "George R.R. Martin".to_string()]};
    let author_review: AuthorReviewResult = OpenAI::execute(input_data).await.unwrap();

    let expected = AuthorReviewResult {
        best_author_name: "George R.R. Martin",
        reason: "George R.R. Martin wins for his intricate world-building and morally complex characters, creating a narrative depth that keeps readers hooked."
    };

    assert_eq!(author_review, expected);
}

Anything that implements promptkit_rs::Renderable can be automatically rendered from brackets. By default all the primitives, String, Vec<impl Renderable>, &[impl Renderable] are all also Renderable.

Building Modular Components

Use Renderable to create structured sub-components, then include them in prompts:

use promptkit_rs::{Renderable, rsx_2};

struct Author {
    name: String,
    age: u64,
}

impl Renderable for Author {
    fn render(&self) -> String {
        rsx_2! { 
            "<name>" {self.name} "</name>"
            "<age>" {self.age} "</age>"
        }
    }
}

Combine Author components into a prompt:

struct AuthorReviewPrompt {
    authors: Vec<Author>,
}

impl Prompt for AuthorReviewPrompt {
    type Output = AuthorReviewResult;

    fn render(&self) -> String {
        rsx_2! {
            "You're a turbo book worm. You live in a hole with nothing but books. "
            "I'm going to give you a list of authors and their books. "
            "Your job is to determine who is best."
            {self.authors}
        }
    }
}

Execution

With the prompt ready, execute it using OpenAI or any custom executor:

#[tokio::main]
async fn main() {
    let authors = vec![
        Author { name: "J.K. Rowling".to_string(), age: 55 },
        Author { name: "George R.R. Martin".to_string(), age: 72 },
    ];

    let input_data = AuthorReviewPrompt { authors };
    let author_review: AuthorReviewResult = OpenAI::execute(input_data).await.unwrap();

    println!("{:?}", author_review);
}

Dependencies

~30–47MB
~681K SLoC