Skip to content

v0.1.0

Choose a tag to compare

@dimamik dimamik released this 30 Dec 13:16
· 25 commits to main since this release
4bffb6e

Legion

Legion is an Elixir-native framework for building AI agents. Agents are plain modules and tools are plain functions. Agents could return sandboxed code that essentially could do anything: call tools, spawn other agents, exchange messages, and react to events in real-time.

Quick Start

1. Define your tools

Tools are regular Elixir modules that expose functions to your agents:

defmodule MyApp.Tools.ScraperTool do
  use Legion.Tool

  @doc "Fetches recent posts from HackerNews"
  def fetch_posts do
    Req.get!("https://hn.algolia.com/api/v1/search_by_date").body["hits"]
  end
end

defmodule MyApp.Tools.DatabaseTool do
  use Legion.Tool

  @doc "Saves a post title to the database"
  def insert_post(title), do: Repo.insert!(%Post{title: title})
end

2. Define an Agent

defmodule MyApp.ResearchAgent do
  @moduledoc """
  Fetch posts, evaluate their relevance and quality, and save the good ones.
  """
  use Legion.AIAgent, tools: [MyApp.Tools.ScraperTool, MyApp.Tools.DatabaseTool]
end

3. Run the Agent

{:ok, result} = Legion.call(MyApp.ResearchAgent, "Find cool Elixir posts about Advent of Code and save them")
# => {:ok, "Found 3 relevant posts and saved 2 that met quality criteria."}

How It Works

When you ask an agent: "Find cool Elixir posts about Advent of Code and save them"

The agent first fetches and filters relevant posts:

ScraperTool.fetch_posts()
|> Enum.filter(fn post ->
  title = String.downcase(post["title"] || "")
  String.contains?(title, "elixir") and String.contains?(title, "advent")
end)

The LLM reviews the results, decides which posts are actually "cool", then saves them:

["Elixir Advent of Code 2024 - Day 5 walkthrough", "My first AoC in Elixir!"]
|> Enum.each(&DatabaseTool.insert_post/1)

Traditional function-calling would need dozens of round-trips. Legion lets the LLM write expressive pipelines and make subjective judgments at the same time.

Main features

  • Code Generation over Function Calling - Agents write expressive Elixir pipelines instead of making dozens of tool-call round-trips. This makes your agents smarter and reduces amount of tokens being used. See anthropic post about this.
  • Sandboxed Execution - Generated code runs in a restricted environment with controlled access to tools. You can define memory, time, and call limits.
  • Simple Tool Definition - Expose any Elixir module as a tool with use Legion.Tool. You can reuse your existing app logic.
  • Authorization baked in - The safest way to authorize tool calls via Vault library. Put all data needed to authorize LLM call before starting Agent, and validate it inside the tool call. Everything will be available due to the Vault's nature.
  • Long-lived Agents - Maintain context across multi-turn conversations with start_link/2.
  • Multi-Agent Systems - Agents can orchestrate other agents, letting you create complex systems that will manage themselves.
  • Human in the Loop - Pause execution to request human input when needed
  • Structured Output - Define schemas to get typed, validated responses from agents, or omit types and operate on plain text. You have full conrol over prompts and schemas.
  • Configurable - Global defaults with per-agent overrides for model, timeouts, and limits
  • Telemetry - Built-in observability with events for calls, iterations, LLM requests, and more