今日已更新 248 条资讯 | 累计 38105 条内容
关于我们

标签:#elixir

找到 5 篇相关文章

AI 资讯

Learning Elixir: Project Structure

When an Elixir project outgrows a handful of modules, the habit of pasting definitions into IEx starts to break down — redefinition warnings pile up, names collide, and nothing survives the session. One way to picture what comes next is a workshop: it begins as a single shelf of drawers and, as the work grows, turns into a whole room with labeled aisles and a storage room for materials that are not tools at all. In the last few articles I filled those drawers — modules — and learned how to reach between them with alias , import , and require . A project structure is the map of that room: it tells me where each module lives on disk, how file names line up with module names, and which aisles other people are allowed to walk into. In this article, we will build a real Mix project from scratch and watch it grow: starting from mix new , adding directories like lib , test , priv , and config , naming modules so they mirror their paths, and drawing boundaries so the project stays navigable as it grows. Note : The examples in this article use Elixir 1.20.1. While most operations should work across different versions, some functionality might vary. This is also a small turning point for the series: instead of pasting examples into iex , everything from now on lives in real files inside a Mix project. Each code block shows the file path, and every example is verified with mix run , with the output shown right after — and when we just want to poke at our functions, iex -S mix brings back the interactive shell, now with the project compiled from its files. Table of Contents Introduction Starting From Mix New The Anatomy of the Default Project Growing Lib: Modules That Mirror Paths Running the Project: Scripts and the Shell Namespaces and Boundaries The Priv Directory Configuration and Environments Practical Guidelines Conclusion Further Reading Next Steps Introduction In the previous articles, every example was self-contained: one or two defmodule blocks pasted into an iex sess

2026-08-30 原文 →
AI 资讯

Orquestração de Agentes de IA no Direito: Construindo Workflows de Triagem e Resumo de Casos sem Perder a Validação Humana

A inteligência artificial no setor jurídico ultrapassou a fase dos chatbots genéricos de pergunta e resposta. Quando lidamos com o Direito, o custo de uma "alucinação" de IA não é apenas um incômodo — pode significar a perda de um prazo fatal, uma tese fundamentada em jurisprudência inexistente ou a violação de sigilo. Para resolver esse problema, a engenharia de software aplicada a LegalTechs está migrando para os Agentic AI Workflows (Workflows de IA Agêntica). Em vez de depender de um único prompt gigantesco para resolver um problema complexo, orquestramos múltiplos agentes especializados. Neste artigo, vamos detalhar como arquitetar uma esteira de triagem, busca vetorial e sumarização de processos, utilizando ferramentas maduras e garantindo que o advogado permaneça como o orquestrador final no Quality Gate . 1. Dividir para Conquistar: A Arquitetura Multi-Agente A premissa da orquestração de agentes é a especialização. Cada agente no sistema possui um escopo restrito, ferramentas específicas ( tool use ) e um objetivo claro. Em um cenário de entrada de um novo processo longo (ex: um PDF de 500 páginas), o workflow se divide em três estágios: Agente 1: Classificação de Intenção e Roteamento O primeiro agente atua como o recepcionista. Ele não lê o documento para extrair teses; ele apenas analisa as primeiras páginas para responder: O que é isso? É uma Inicial Trabalhista? Uma intimação de prazo? Uma contestação? A partir dessa classificação, o workflow roteia o documento para a fila correta de processamento. Agente 2: RAG (Retrieval-Augmented Generation) e Busca Vetorial O segundo agente é o pesquisador. Ele quebra o documento em fragmentos ( chunks ) e cruza as alegações da parte contrária com o acervo interno do escritório. No ecossistema Elixir, por exemplo, podemos utilizar o PostgreSQL com pgvector e Ecto para armazenar os embeddings de casos passados e jurisprudências vencedoras do próprio escritório. O agente busca semelhanças e recupera o contexto estrit

2026-08-29 原文 →
AI 资讯

Building Distributed Systems in Elixir: Part 6 — Named Processes

In the previous part of this series, we built a tiny supervisor from scratch. When a worker crashed, the supervisor started a replacement. That replacement had a new PID: old worker -> #PID<0.102.0> new worker -> #PID<0.105.0> This reveals an important limitation of sharing PIDs as a public interface. A PID identifies one running incarnation of a process. It is excellent for sending a reply, setting up a monitor, or creating a link. It is not a stable address for a service that may stop and later be replaced. In this part, we'll use named processes to give a worker a discoverable address: :worker We'll build three small examples using: Process . register / 2 Process . whereis / 1 :global . register_name / 2 :global . whereis_name / 1 send / 2 No GenServer . No OTP Registry . The goal is to understand the lookup problem that registries solve before reaching for those abstractions. The PID-Sharing Problem Suppose one process starts a worker and gives its PID to a client: worker = spawn ( fn -> worker_loop () end ) send ( client , { :worker_started , worker }) The client can now send work directly: send ( worker , { :work , self (), "hello" }) This works while that particular worker process is alive. But process IDs are temporary. If the worker exits, the PID is no longer a route to the service: Client Worker holds #PID<0.102.0> #PID<0.102.0> | | | X exits | | send(#PID<0.102.0>, work) |------------------------------> no worker receives it Sending to a dead local PID does not raise an error and does not restart a process. The message is simply not delivered to a living worker. One answer is to tell every client about every new PID after a restart. That spreads lifecycle knowledge throughout the system. Another answer is to make clients depend on a name and resolve that name when sending. Registering a Local Name Our first worker waits for a stop message: defmodule Worker do def start do spawn ( fn -> receive do :stop -> :ok end end ) end end Starting it gives us a PID:

2026-08-19 原文 →
AI 资讯

Zenoh's put is fire-and-forget, get isn't — a read-after-write race in Elixir

This English version is an AI translation of my original article on Qiita (in Japanese) . Background I've been experimenting with Zenoh via its Elixir bindings, Zenohex , not for its usual pub/sub use case but for its put / get storage feature. It mostly worked, except every so the state I picked back up was one step behind. Digging into why turned into a fun rabbit hole, so here's the writeup. Reproducing it To keep things simple, strip out the GenServer part entirely and just loop put immediately followed by get on the same key: { :ok , session_id } = Zenohex . Session . open ( config ) Enum . each ( 1 .. 2000 , fn i -> payload = Integer . to_string ( i ) :ok = Zenohex . Session . put ( session_id , key , payload ) { :ok , replies } = Zenohex . Session . get ( session_id , key , 3_000 , consolidation: :latest ) case Enum . find ( replies , & match? (% Zenohex . Sample {}, &1 )) do % Zenohex . Sample { payload: ^ payload } -> :ok % Zenohex . Sample { payload: other } -> IO . puts ( "stale! put #{ payload } but got #{ other } " ) nil -> IO . puts ( "no reply at all" ) end end ) Out of 2000 iterations, a small fraction print stale! — about 78 (3.9%) in one run. The interesting part: querying again immediately afterward almost always returns the correct value (the fastest I measured was a single extra get about 1ms later). So it's not that the value disappears — there's just a small window of lag before the write is actually visible. Why Zenohex.Session.put/4 is a thin Rustler wrapper around zenoh-rust's put . Looking at the NIF implementation : fn session_put ( ... ) -> rustler :: NifResult < rustler :: Atom > { ... publication_builder .apply_opts ( opts ) ? .wait () // <- only waits for the local publish to be queued ... Ok ( rustler :: types :: atom :: ok ()) } .wait() only waits for the local session to finish handing the message off — not for the remote side (the zenohd router backing the storage) to actually receive and apply it. session_get , on the other hand,

2026-08-16 原文 →