deepfates/imp: declarative self-improving language-model packages for Elixir 馃槆 路 GitHub


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

Imp is a full port of DSPy to the BEAM. You describe what
every language-model step takes and returns, select the way it thinks, and let an
optimizer enhance it in opposition to examples of what attractiveness like. You get
signatures, modules, optimizers, agent loops and retrieval, working with the
reliability and concurrency of OTP.

DSPy makes every name to a mannequin a declared, typed perform which you could
measure and enhance. On the BEAM, an agent is a course of: it retains its personal
state, receives messages, and runs underneath a supervisor alongside the remainder
of your utility. With each, you possibly can construct something from one typed name
to many long-running brokers, and enhance every half by measuring it.

lm = Imp.req_llm("openai:gpt-5.4-mini", api_key: System.fetch_env!("OPENAI_API_KEY"))

triage =
  "challenge -> variety: enum[bug,feature,question], abstract"
  |> Imp.signature("Triage a GitHub challenge.")
  |> Imp.predict(lm: lm)

{:okay, prediction} =
  Imp.name(triage, %{challenge: "App crashes on startup since 0.4 with ** (KeyError) key :lm not discovered"})

{Imp.get(prediction, :variety), Imp.get(prediction, :abstract)}
#=> {"bug", "App crashes on startup since model 0.4 with a KeyError for `:lm` not discovered."}

You by no means write a immediate or a parser. Imp builds the immediate from the
signature, checks the reply in opposition to it, and provides you typed fields: variety is
at all times one of many three values, or the decision returns an error. To make the
similar job motive first, use Imp.chain_of_thought/2; to present it instruments, use
Imp.react/3. The signature stays the identical.

Measure it and enhance it

Give Imp labeled examples and a metric, and it scores this system and
optimizes it. You want three lists of points you’ve already labeled:
trainset, which the optimizer learns from; valset, which it makes use of to decide on
between the packages it tries; and testset, which you rating on earlier than and
after. strong_lm is a extra succesful mannequin that GEPA makes use of to learn failures and
write new directions.

# Each set is a listing of labeled points like this one:
instance =
  Imp.instance(%{challenge: "Please add a darkish mode to the dashboard", variety: "function"})
  |> Imp.with_inputs([:issue])

metric = Imp.exact_match(:variety)

Imp.consider(triage, testset, metric).rating

optimizer = Imp.Optimizer.GEPA.new(metric, reflection_lm: strong_lm, max_metric_calls: 300)
improved = Imp.optimize!(triage, optimizer, trainset, valset)

Imp.consider(improved, testset, metric).rating

GEPA runs this system, reads the place it failed, and rewrites its directions.
Other optimizers select labored examples (LabeledFewShot, BootstrapFewShot),
search over combos of directions and examples (MIPROv2), be taught guidelines
and examples from this system’s personal higher and worse makes an attempt (SIMBA), or
practice the mannequin’s weights (fine-tuning, GRPO). The result’s a brand new program
whose directions and examples you possibly can learn, save as JSON, and overview as a
diff.

A software is an Elixir perform. Imp.react/3 builds an agent that calls instruments
till it could reply. This one reads internet pages with Req. Imp is dependent upon Req;
if your individual code calls it, as this software does, add {:req, "~> 0.6"} to your
dependencies:

fetch =
  Imp.software(:fetch, "Read an online web page as textual content.", fn %{"url" => url} -> Req.get!(url).physique finish,
    schema: %{"sort" => "object", "properties" => %{"url" => %{"sort" => "string"}}, "required" => ["url"]}
  )

researcher = Imp.react("query -> reply", [fetch], lm: lm)

query =
  "What model does https://raw.githubusercontent.com/elixir-lang/elixir/v1.18.0/VERSION say? " <>
    "Reply with simply the model."

{:okay, prediction} = Imp.name(researcher, %{query: query})
Imp.get(prediction, :reply)
#=> "1.18.0"

Imp.name/2 runs a program in your course of. Imp.start_run/3 runs it as its
personal supervised course of as a substitute, so you possibly can watch it, cease it, and resolve
which software calls it could make:

{:okay, run} =
  Imp.start_run(researcher, %{query: query},
    authorize: fn name ->
      url = name.arguments["url"] || ""

      if String.starts_with?(url, "https://raw.githubusercontent.com/"),
        do: :enable,
        else: {:deny, :untrusted_host}
    finish
  )

{:okay, prediction} = Task.await(run.job, :infinity)

for occasion <- Imp.Run.occasions(run), do: occasion.variety
#=> [:run_started, :tools_sent, :model_request, :model_response, :tool_call,
#    :tool_result, :model_request, :model_response, :run_finished]

Imp additionally contains:

  • MCP: import the instruments of any MCP server you approve, they usually work like
    your individual.
  • ACP: serve any Imp program as an agent to Zed and different ACP purchasers.
  • OTP: a run is a course of you possibly can watch, cease and restrict, and a run ends
    when the method that began it does. Model requests are reduce to a
    deadline you set. A software name that will have already got taken impact is
    reported as unknown, by no means silently retried.
  • More shapes: RLM for inputs far bigger than a context window, CodeAct
    and program of thought, which compute with small sandboxed expressions, and your individual modules
    composed from these.

The optimizers work on brokers too. GEPA displays on entire agent runs and
rewrites the directions that steer them. Optimize Anything rewrites any
textual content or JSON you possibly can rating, comparable to an agent’s software descriptions.

Imp wants Elixir 1.19 or later and a C++ compiler for one dependency
(erlexec). It reaches fashions by way of
ReqLLM, so any supplier ReqLLM helps
works.

Imp 0.5 is experimental and is its first launch on Hex. Its API should still
change, and its optimizers want large-scale benchmarking. Bug experiences and
pull requests are welcome.

  • Getting started builds one program step by
    step, from the primary name to a supervised server, with actual scores.
  • Coming from DSPy maps DSPy’s names to Imp’s.
  • Tutorials are Livebook notebooks
    you possibly can run offline or with a key.
  • The cheatsheet has the widespread calls on one web page.

Imp is MIT licensed.



Source link