Artificial ‒ typed, composable prompt engineering in Rust
Artificial is a batteries-included toy framework that demonstrates how to build strongly-typed, provider-agnostic prompt pipelines in Rust.
The code base is intentionally small—less than 3 k lines spread over multiple crates—yet it already shows how to:
- Compose reusable prompt fragments into high-level templates.
- Target multiple model providers via pluggable back-ends
(currently OpenAI, adding others is trivial). - Describe the LLM’s JSON response format in Rust and have it checked
at compile time with
schemars. - Bubble up provider errors through a single, unified error type.
- Keep all heavy dependencies optional behind feature flags.
If you are curious how the new crop of “AI SDKs” work under the hood—or you need a lean starting point for your own experiments—this repo is for you.
Table of contents
Crate layout
| Crate | Purpose |
|---|---|
artificial-core |
Provider-agnostic traits (Backend, PromptTemplate), client, error types |
artificial-prompt |
String-building helpers (PromptBuilder, PromptChain) |
artificial-types |
Shared fragments (CurrentDateFragment, StaticFragment) and output helpers |
artificial-openai |
Thin wrapper around OpenAI /v1 with JSON-Schema function calling |
artificial |
Glue crate that re-exports everything above for convenience |
Each crate lives under crates/* and can be used independently, but most
people will depend on the umbrella crate:
[]
= { = "crates/artificial", = ["openai"] }
Installation
Artificial is published as a workspace example, so you typically work against the Git repository directly:
Requirements:
- Rust 1.77 or newer (edition 2024)
- An OpenAI API key exported as
OPENAI_API_KEY - Internet access for the example back-end
Quick start
Below is a minimal “Hello, JSON” example taken from
examples/openai_hello_world.rs:
use ;
use OpenAiAdapterBuilder;
use JsonSchema;
use ;
;
async
Run it:
The program sends a request with an inline JSON-Schema and prints the deserialised reply.
Library tour
Prompt fragments
artificial-types::fragments contains small building blocks that turn into
GenericMessages—think “Current date”, “Static system instruction”, “Last user
message”. You can combine them via PromptChain:
new
.with
.with
.with
.build;
Strongly-typed outputs
Define a struct (must implement JsonSchema + Deserialize) and declare it
as PromptTemplate::Output. The OpenAI back-end automatically injects the
schema as response_format = json_schema.
Provider back-ends
A back-end only has to implement the single-method trait
Because the PromptTemplate carries the desired model, the back-end can map it
to the provider’s naming scheme (gpt-4o-mini, gpt-4o, …).
Design goals
- Minimal surface area – the framework should fit in one screenful of source code, making it easy to fork or copy-paste.
- Compile-time checks everywhere – wrong model name? missing
OPENAI_API_KEY? Incompatible JSON schema? You find out early. - Pluggable transports – swap out
artificial-openaifor an Ollama/Anthropic adapter without touching user code. - No macros – generic traits and
impls keep the magic transparent.
FAQ
Why another AI SDK?
Because many existing SDKs are either too heavyweight or hide the inner
workings behind procedural macros. Artificial aims to be the smallest possible
blueprint you can still use in production.
Does it support streaming completions?
Not yet. The Backend trait is purposely tiny; adding another method for
streaming is straightforward.
Is the OpenAI back-end production ready?
It handles basic JSON-Schema function calling, retries and streaming are
missing. Treat it as a reference implementation.
How do I add Anthropic or Ollama?
- Create
artificial-anthropic(or similar) crate. - Wrap the provider’s HTTP API in a small client struct.
- Implement
Backendfor the adapter. - Done—
ArtificialClientworks instantly with the new provider.
License
Licensed under MIT. See LICENSE for the full text.