Imp 是 DSPy 到 BEAM 的完整移植版
摘要
Imp 是 DSPy 到 BEAM 的完整移植版,使得在 Elixir 中能够利用 OTP 的可靠性和容错性,创建声明式的、自我改进的语言模型程序。
查看缓存全文
缓存时间: 2026/09/27 22:41
deepfates/imp 来源:https://github.com/deepfates/imp
Imp
用于 Elixir 的声明式、自我改进的语言模型程序。 Imp 是 DSPy (https://dspy.ai) 到 BEAM 的完全移植。 你只需描述每个语言模型步骤的输入输出,选择其思考方式,然后让优化器根据示例进行改进。 你将获得签名、模块、优化器、智能体循环和检索功能,并以 OTP 的可靠性和并发性运行。
DSPy 将每次模型调用都变为一个声明式的、带类型的函数,你可以对其进行测量和改进。 在 BEAM 上,一个智能体就是一个进程:它维护自己的状态、接收消息,并在监督者下与你的应用程序的其他部分一起运行。 结合两者,你可以构建从单个类型化调用到多个长期运行智能体的任何应用,并通过测量来改进每个部分。
声明任务
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 with ** (KeyError) key :lm not found"})
{Imp.get(prediction, :kind), Imp.get(prediction, :summary)}
#=> {"bug", "App crashes on startup since version 0.4 with a KeyError for `:lm` not found."}
你无需编写提示词或解析器。Imp 根据签名构建提示词,对照签名检查回复,并为你提供带类型的字段:kind 总是三个值之一,否则调用返回错误。
若要使同一任务先进行推理,请使用 Imp.chain_of_thought/2;若要赋予其工具,请使用 Imp.react/3。签名保持不变。
测量并改进
给 Imp 标注好的示例和一个度量标准,它就会对程序进行评分并优化。
你需要三个已标注的问题列表:trainset(优化器从中学习),valset(用于在它尝试的程序之间进行选择),以及 testset(你在优化前后用于评分的)。
strong_lm 是一个更强大的模型,GEPA 用来读取失败案例并撰写新的指令。
# 每个集合都是一个类似此例的已标注问题列表:
example = Imp.example(%{issue: "Please add a dark mode 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 运行程序,读取其失败之处,并重写其指令。 其他优化器会选择已验证的示例(LabeledFewShot, BootstrapFewShot),在指令和示例的组合中搜索(MIPROv2),从程序自身更好和更差的尝试中学习规则和示例(SIMBA),或训练模型的权重(微调,GRPO)。 最终得到一个新程序,其指令和示例你可以阅读、保存为 JSON,并以差异对比形式查看。
构建智能体
工具就是一个 Elixir 函数。Imp.react/3 构建一个智能体,它会调用工具直到能够回答问题。这个工具用 Req 读取网页。
Imp 依赖于 Req;如果你自己的代码也调用它(如此工具所示),请在依赖中添加 {:req, "~> 0.6"}:
fetch = Imp.tool(:fetch, "Read a web page 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 version does https://raw.githubusercontent.com/elixir-lang/elixir/v1.18.0/VERSION say? " <> "Reply with just the version."
{:ok, prediction} = Imp.call(researcher, %{question: question})
Imp.get(prediction, :answer)
#=> "1.18.0"
将智能体作为进程运行
Imp.call/2 在你的进程中运行一个程序。
Imp.start_run/3 则将其作为自己的监督进程运行,这样你就可以监视它、停止它,并决定它可以进行哪些工具调用:
{: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 还包括:
- MCP: 导入任何你批准的 MCP 服务器的工具,它们就像你自己的工具一样工作。
- ACP: 将任何 Imp 程序作为智能体提供给 Zed 和其他 ACP 客户端。
- OTP: 一次运行就是一个你可以监视、停止和限制的进程,并且当启动它的进程结束时,运行也就结束。
- 模型请求会按你设定的截止时间进行切割。
- 一个可能已经生效的工具调用会被报告为未知状态,永远不会静默重试。
- 更多形式: RLM(用于输入远大于上下文窗口的情况),CodeAct 和思维程序(用小型沙箱表达式进行计算),以及由这些组合而成的你自己的模块。 优化器也适用于智能体。GEPA 会反思整个智能体运行过程,并重写引导它们的指令。Optimize Anything 会重写任何你可以评分的文本或 JSON,例如智能体的工具描述。
安装
{:imp, "~> 0.5"}
Imp 需要 Elixir 1.19 或更高版本,以及 C 和 C++ 编译器,用于两个依赖(jaxon 和 erlexec)中的原生代码。首次编译需要网络访问,因为 erlexec 的构建会获取 rebar3 插件。 它通过 ReqLLM (https://hex.pm/packages/req_llm) 连接模型,因此任何 ReqLLM 支持的提供商都可以使用。 Imp 0.5 是实验性的,也是它在 Hex 上的首次发布。其 API 仍可能更改,其优化器需要大规模基准测试。 欢迎提交错误报告和拉取请求。
学习
- 入门指南 从第一步调用到监督服务器,逐步构建一个程序,并给出真实分数。
- 来自 DSPy 将 DSPy 的名称映射到 Imp 的名称。
- 教程 (https://github.com/deepfates/imp/tree/v0.5.0/livebooks) 是你可以离线或使用密钥运行的 Livebook 笔记本。
- 速查表 将常用调用放在一页上。
Imp 采用 MIT 许可证。
相似文章
@0xtotem: 已将 PEEK 移植到 @DSPyOSS。你可以将任何 DSPy 代理(ReAct、RLM 等)封装到这个新模块中,以受益于更好的性能……
已将 PEEK 方法移植到 DSPy,使任何 DSPy 代理都能受益于如论文所示的改进性能和成本降低。
我尝试将BEAM风格的并发模型应用于代码智能体——结果令人惊讶
一项将BEAM风格并发(Erlang VM模型)应用于代码智能体的实验得到了令人惊讶的结果,暗示了在智能体协调和容错方面的潜在改进。
@DSPyOSS:说到底就是签名(规范)、模块(“测试台”、“推理扩展”)和优化器(学习算法…
一篇回顾 DSPy 框架架构的帖子,该框架围绕签名、模块和优化器构建,并指出它自 2022 年以来仍在持续增长。
Sipp - 一个基于 llama.cpp 的浏览器内推理开源库
Sipp 是一个开源库,利用 llama.cpp 实现浏览器内推理,使 AI 模型能够直接在浏览器中运行。
为Bluesky DataPlane选择Elixir:我们未曾预料的抉择
这篇博客文章详细说明了为什么团队选择Elixir而不是Go、Rust或Node来构建高性能的Bluesky DataPlane,利用BEAM的并发性处理热路径,并将计算密集型操作卸载到Rust NIF上。