Imp is a complete harbor of DSPy to the BEAM

Hacker News by 5 min read 58x views
Imp is a complete harbor of DSPy to the BEAM

Share Post

Declarative, self-improving language-model programs for Elixir.

An imp studies a hand of cards through a lens during a smaller imp springs from its tail.

Imp is a complete harbor of DSPy to the BEAM. You depict what each language-model stage takes and returns, choose how it thinks, and let an optimizer enhance it against examples of what fine looks like. You get signatures, modules, optimizers, delegate loops and retrieval, operating alongside the reliability and concurrency of OTP.

DSPy makes all call to a example a declared, typed function that you can measure and improve. On the BEAM, an delegate is a process: it keeps its own state, receives messages, and runs under a supervisor alongside the rest of your application. With both, you can build item from one typed call to many long-running agents, and enhance all part by measuring it.

lm = Imp.req_llm("openai:gpt-5.4-mini", api_key: System.fetch_env!("OPENAI_API_KEY")) triage = "issue -> kind: enum[bug,feature,question], summary" |> Imp.signature("Triage a GitHub issue.") |> Imp.predict(lm: lm) {:ok, prediction} = Imp.call(triage, %{issue: "App crashes on startup since 0.4 alongside ** (KeyError) key :lm not found"}) {Imp.get(prediction, :kind), Imp.get(prediction, :summary)} #=> {"bug", "App crashes on startup since type 0.4 alongside a KeyError for `:lm` not found."}

You never compose a immediate or a parser. Imp builds the immediate from the signature, checks the answer against it, and gives you typed fields: benevolent is always among the three values, or the call returns an error. To create the same project logic first, use Imp.chain_of_thought/2; to provision it tools, use Imp.react/3. The signature stays the same.

Measure it and enhance it

Give Imp tagged examples and a metric, and it scores the program and optimizes it. You need three lists of issues you have already labeled: trainset, which the optimizer learns from; valset, which it uses to choose between the programs it tries; and testset, which you mark on before and after. strong_lm is a additional capable example that GEPA uses to peruse failures and write new instructions.

# Each set is a catalog of tagged issues akin this one: example = Imp.example(%{issue: "Please add a dreary manner to the dashboard", kind: "feature"}) |> Imp.with_inputs([:issue]) metric = Imp.exact_match(:kind) Imp.evaluate(triage, testset, metric).score optimizer = Imp.Optimizer.GEPA.new(metric, reflection_lm: strong_lm, max_metric_calls: 300) improved = Imp.optimize!(triage, optimizer, trainset, valset) Imp.evaluate(improved, testset, metric).score

GEPA runs the program, says anywhere it failed, and rewrites its instructions. Other optimizers choose worked examples (LabeledFewShot, BootstrapFewShot), search complete combinations of instructions and examples (MIPROv2), study rules and examples from the program's own improved and worse attempts (SIMBA), or train the model's weights (fine-tuning, GRPO). The outcome is a new program whose instructions and examples you can read, preserve as JSON, and assessment as a diff.

A tool is an Elixir function. Imp.react/3 builds an delegate that calls tools until it can answer. This one says web pages alongside Req. Imp depends on Req; if your own code calls it, as this tool does, add {:req, "~> 0.6"} to your dependencies:

fetch = Imp.tool(:fetch, "Read a web leaf as text.", fn %{"url" => url} -> Req.get!(url).body end, schema: %{"type" => "object", "properties" => %{"url" => %{"type" => "string"}}, "required" => ["url"]} ) researcher = Imp.react("question -> answer", [fetch], lm: lm) question = "What type does https://raw.githubusercontent.com/elixir-lang/elixir/v1.18.0/VERSION say? " <> "Reply alongside fair the version." {:ok, prediction} = Imp.call(researcher, %{question: question}) Imp.get(prediction, :answer) #=> "1.18.0"

Imp.call/2 runs a program in your process. Imp.start_run/3 runs it as its own supervised procedure instead, so you can observe it, halt it, and decide which tool calls it may make:

{:ok, run} = Imp.start_run(researcher, %{question: question}, authorize: fn call -> url = call.arguments["url"] || "" if String.starts_with?(url, "https://raw.githubusercontent.com/"), do: :allow, else: {:deny, :untrusted_host} end ) {:ok, prediction} = Task.await(run.task, :infinity) for event <- Imp.Run.events(run), do: event.kind #=> [:run_started, :tools_sent, :model_request, :model_response, :tool_call, # :tool_result, :model_request, :model_response, :run_finished]

Imp additionally includes:

  • MCP: import the tools of any MCP server you approve, and they activity like your own.
  • ACP: assist any Imp program as an delegate to Zed and another ACP clients.
  • OTP: a run is a procedure you can watch, halt and limit, and a run ends when the procedure that started it does. Model requests are cut to a deadline you set. A tool call that may already have taken consequence is reported as unknown, never silently retried.
  • More shapes: RLM for inputs far larger than a environment window, CodeAct and program of thought, which compute alongside small sandboxed expressions, and your own modules composed from these.

The optimizers activity on agents too. GEPA reflects on entire delegate runs and rewrites the instructions that steer them. Optimize Anything rewrites any text or JSON you can score, specified as an agent's tool descriptions.

Imp needs Elixir 1.19 or afterward and a C++ compiler for one dependency (erlexec). It reaches models through ReqLLM, so any provider ReqLLM supports works.

Imp 0.5 is experimental and is its archetypal publish on Hex. Its API may still change, and its optimizers need large-scale benchmarking. Bug reports and pull requests are welcome.

  • Getting started builds one program stage by step, from the archetypal call to a supervised server, alongside genuine scores.
  • Coming from DSPy maps DSPy's names to Imp's.
  • Tutorials are Livebook notebooks you can run offline or alongside a key.
  • The cheatsheet has the average calls on one page.

Imp is MIT licensed.

Other Article Hacker News
↑
Close Right Ads
Close Left Ads