Elixir port of DSPy. Declarative LM programming with typed signatures, composable modules, prompt-as-data optimization, and BEAM-native concurrency.
Add dsxir to your dependencies:
def deps do
[{:dsxir, "~> 0.1"}] # x-release-please-version
endConfigure the LM at boot:
Dsxir.configure(
lm: {Dsxir.LM.Sycophant, [model: "openai:gpt-4o-mini"]},
adapter: Dsxir.Adapter.Chat
)Credentials are NEVER passed to Dsxir.configure/1 — they flow through
Dsxir.context/2 per request (see Multi-tenant).
Declare a typed signature, compose it into a module, and run it:
defmodule MyApp.AnswerQuestion do
use Dsxir.Signature
signature do
instruction "Answer the user's question with a single short fact."
input :question, :string
output :answer, :string
end
end
defmodule MyApp.QA do
use Dsxir.Module
predictor :answer, Dsxir.Predictor.Predict,
signature: MyApp.AnswerQuestion
def forward(prog, %{question: q}) do
call(prog, :answer, %{question: q})
end
end
prog = Dsxir.Program.new(MyApp.QA)
{_prog, pred} = MyApp.QA.forward(prog, %{question: "Capital of France?"})
pred[:answer]- Signatures and Modules — typed contracts and how to compose them into programs.
- Inference-time wrappers —
BestOfNandRefinereward-sampling wrappers. - Optimizers —
LabeledFewShot,BootstrapFewShot,MIPROv2, andCOPRO. - Runtime Programs — author programs as data instead of code.
- Multi-tenant — per-request credentials,
context, and
call_plugs. - Telemetry — the canonical event vocabulary and cost measurements.
- Email Information Extraction
— classify, extract, summarize, and propose action items over an
inbox, then compile a few-shot version with
Dsxir.Optimizer.BootstrapFewShot. Livebook:livebook server guides/tutorials/email_extraction.livemdfrom a checkout. - Inference-time Wrappers
— trade per-call budget for reliability with
BestOfN,Refine,Ensemble, andMultiChainComparison, worked over a single Cognitive-Reflection-Test question.
dsxir mirrors DSPy's surface where reasonable; some shapes differ:
| DSPy | dsxir |
|---|---|
dspy.configure(lm=...) |
Dsxir.configure(lm: {Impl, config}) |
dspy.Signature (Pydantic) |
use Dsxir.Signature (Spark + Zoi) |
signature.demos = [...] (mutation) |
%Dsxir.Program{} with per-predictor %State{} |
metric(example, pred, trace=None) |
(example, pred, trace) -> number() |
dspy.inspect_history |
Dsxir.History.enable/0 + last/1 |
dspy.History value type |
Dsxir.Primitives.History |