# Imp: Cổng chuyển đổi DSPy sang BEAM, mang lập trình LLM khai báo đến với Elixir

- Nguồn: Hacker News: AI bài nổi bật
- Thời gian phát hành: 2026-09-28 02:28 (giờ Việt Nam)
- Điểm AI: 43/100
- Link AIHOT.vn: https://aihot.vn/items/40d32e913976f419
- Nguồn dữ liệu AI HOT: https://aihot.news/items/cmuknbscq1y11ro9httvhjqxp
- Link gốc: https://github.com/deepfates/imp

## Tóm tắt AI

Imp là bản chuyển đổi đầy đủ của DSPy cho hệ sinh thái Elixir, cho phép lập trình viên xây dựng các ứng dụng LLM tự tối ưu hóa thông qua các module và optimizer như MIPROv2. Dự án hỗ trợ chạy agent dưới dạng tiến trình OTP và tích hợp sẵn MCP/ACP.

## Thân bài

![GitHub - deepfates/imp: declarative self-improving language-model programs for Elixir 😇](https://opengraph.githubassets.com/3f60448518c2ce6022398db72fc7c3501bb62a05b1ac740437e96cc2999140b4/deepfates/imp)

Các chương trình mô hình ngôn ngữ có khả năng tự cải thiện và khai báo dành cho Elixir.

![An imp studies a hand of cards through a lens while a smaller imp springs from its tail.](https://github.com/deepfates/imp/raw/main/assets/imp-with-cards.jpg)

Imp là bản port đầy đủ của [DSPy](https://dspy.ai/) sang BEAM. Bạn mô tả đầu vào và đầu ra của từng bước mô hình ngôn ngữ, chọn cách thức tư duy của nó, và để trình tối ưu hóa cải thiện dựa trên các ví dụ mẫu chuẩn. Bạn sẽ nhận được các signature, module, trình tối ưu hóa, vòng lặp agent và khả năng truy xuất, tất cả vận hành với độ tin cậy và tính đồng thời của OTP.

DSPy biến mỗi lệnh gọi mô hình thành một hàm có kiểu dữ liệu rõ ràng, cho phép bạn đo lường và cải thiện. Trên BEAM, một agent là một tiến trình (process): nó duy trì trạng thái riêng, nhận tin nhắn và chạy dưới sự giám sát (supervisor) cùng với phần còn lại của ứng dụng. Với cả hai, bạn có thể xây dựng mọi thứ từ một lệnh gọi đơn lẻ đến nhiều agent chạy dài hạn, đồng thời cải thiện từng phần bằng cách đo lường chúng.

### Khai báo tác vụ

```
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."}
```

Bạn không bao giờ phải viết prompt hay trình phân tích cú pháp (parser). Imp tự xây dựng prompt từ signature, kiểm tra phản hồi dựa trên đó và cung cấp cho bạn các trường dữ liệu có kiểu cụ thể: giá trị trả về luôn nằm trong ba lựa chọn, nếu không lệnh gọi sẽ báo lỗi. Để tác vụ đó suy luận trước, hãy dùng Imp.chain_of_thought/2; để cung cấp công cụ, hãy dùng Imp.react/3. Signature vẫn giữ nguyên.

### Đo lường và cải thiện

Cung cấp cho Imp các ví dụ đã dán nhãn và một chỉ số đo lường (metric), nó sẽ chấm điểm chương trình và tối ưu hóa. Bạn cần ba danh sách dữ liệu đã dán nhãn: trainset để trình tối ưu hóa học hỏi; valset để nó lựa chọn giữa các chương trình thử nghiệm; và testset để bạn chấm điểm trước và sau khi tối ưu. strong_lm là một mô hình mạnh mẽ hơn mà GEPA sử dụng để đọc các lỗi và viết lại các chỉ dẫn mới.

```
# Each set is a list of labeled issues like this one:
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 chạy chương trình, đọc các điểm thất bại và viết lại chỉ dẫn của nó. Các trình tối ưu hóa khác chọn các ví dụ đã thực hiện (LabeledFewShot, BootstrapFewShot), tìm kiếm trên các tổ hợp chỉ dẫn và ví dụ (MIPROv2), học các quy tắc và ví dụ từ chính những lần thử tốt hơn hoặc tệ hơn của chương trình (SIMBA), hoặc huấn luyện trọng số của mô hình (fine-tuning, GRPO). Kết quả là một chương trình mới với các chỉ dẫn và ví dụ mà bạn có thể đọc, lưu dưới dạng JSON và xem xét dưới dạng diff.

### Xây dựng các agent

Một công cụ (tool) là một hàm Elixir. Imp.react/3 xây dựng một agent gọi các công cụ cho đến khi có câu trả lời. Ví dụ này đọc các trang web bằng Req. Imp phụ thuộc vào Req; nếu mã của bạn gọi nó, như công cụ này đang làm, hãy thêm {:req, "~> 0.6"} vào phần dependencies:

```
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"
```

### Chạy các agent dưới dạng tiến trình

Imp.call/2 chạy một chương trình trong tiến trình hiện tại của bạn. Imp.start_run/3 chạy nó như một tiến trình được giám sát riêng biệt, giúp bạn có thể theo dõi, dừng và quyết định các lệnh gọi công cụ mà nó có thể thực hiện:

```
{: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 cũng bao gồm:

- MCP: nhập các công cụ từ bất kỳ máy chủ MCP nào bạn phê duyệt, và chúng hoạt động như công cụ của riêng bạn.
- ACP: phục vụ bất kỳ chương trình Imp nào dưới dạng một agent cho Zed và các ACP client khác.
- OTP: một lần chạy là một tiến trình mà bạn có thể theo dõi, dừng và giới hạn, và lần chạy sẽ kết thúc khi tiến trình khởi tạo nó kết thúc. Các yêu cầu mô hình bị cắt theo thời hạn bạn đặt. Một lệnh gọi công cụ có thể đã có hiệu lực sẽ được báo cáo là không xác định (unknown), không bao giờ tự động thử lại âm thầm.
- Nhiều hình thái hơn: RLM cho các đầu vào lớn hơn nhiều so với cửa sổ ngữ cảnh (context window), CodeAct và program of thought, vốn tính toán với các biểu thức nhỏ trong môi trường sandbox, và các module của riêng bạn được tạo thành từ những thành phần này.

Các trình tối ưu hóa cũng hoạt động trên các agent. GEPA suy ngẫm về toàn bộ quá trình chạy của agent và viết lại các chỉ dẫn điều hướng chúng. Optimize Anything viết lại bất kỳ văn bản hoặc JSON nào bạn có thể chấm điểm, chẳng hạn như mô tả công cụ của agent.

### Cài đặt

```
{:imp, "~> 0.5"}
```

Imp yêu cầu Elixir 1.19 trở lên và trình biên dịch C/C++, cho mã nguồn gốc trong hai phụ thuộc (jaxon và erlexec). Lần biên dịch đầu tiên cần truy cập mạng vì quá trình build của erlexec sẽ tải các plugin rebar3. Nó kết nối với các mô hình thông qua [ReqLLM](https://hex.pm/packages/req_llm), vì vậy bất kỳ nhà cung cấp nào được ReqLLM hỗ trợ đều hoạt động.

Imp 0.5 là bản thử nghiệm và là bản phát hành đầu tiên trên Hex. API của nó có thể thay đổi và các trình tối ưu hóa cần được benchmark trên quy mô lớn. Các báo cáo lỗi và pull request luôn được hoan nghênh.

### Học tập

- [Bắt đầu](https://github.com/deepfates/imp/blob/main/docs/getting-started/index.md) xây dựng một chương trình từng bước, từ lệnh gọi đầu tiên đến một máy chủ được giám sát, với điểm số thực tế.
- [Chuyển từ DSPy](https://github.com/deepfates/imp/blob/main/docs/coming-from-dspy.md) ánh xạ các tên gọi từ DSPy sang Imp.
- [Hướng dẫn](https://github.com/deepfates/imp/tree/v0.5.0/livebooks) là các Livebook notebook bạn có thể chạy ngoại tuyến hoặc với một khóa API.
- [Bảng tra cứu](https://github.com/deepfates/imp/blob/main/docs/cheatsheet.cheatmd) chứa các lệnh gọi phổ biến trên một trang duy nhất.

Imp được cấp phép theo giấy phép MIT.
