Jido版本迁移:从1.x升级到2.x的完整指南
Jido版本迁移从1.x升级到2.x的完整指南【免费下载链接】jido Autonomous agent framework for Elixir. Built for distributed, autonomous behavior and dynamic workflows.项目地址: https://gitcode.com/GitHub_Trending/ji/jidoJido 2.x是一个重大的架构升级带来了更强大的自主代理框架功能。这个版本迁移指南将帮助您平滑地从1.x版本升级到2.x充分利用新的特性并避免常见的陷阱。为什么需要升级到Jido 2.xJido 2.x引入了革命性的架构改进使您的Elixir代理系统更加强大和可靠。新版本的核心变化包括实例化运行时从全局单例迁移到实例化的监督树架构纯函数式代理完全分离决策逻辑与副作用执行CloudEvents信号标准化的消息传递格式Zoi模式验证更强大的类型验证系统Splode错误处理结构化错误管理这些改进让Jido代理框架在分布式系统和多代理协作场景中表现更出色升级前的准备工作在开始升级之前请确保您的环境满足以下要求Elixir版本确保使用Elixir~ 1.18或更高版本备份代码创建当前代码的备份测试套件确保测试套件能够正常运行依赖更新更新mix.exs中的Jido依赖# mix.exs defp deps do [ {:jido, ~ 2.0} ] end第1步添加Jido到监督树2.x版本最重要的变化是引入了实例化运行时。您需要创建一个Jido实例模块并将其添加到应用程序的监督树中。创建实例模块在lib/my_app/jido.ex中创建您的Jido实例defmodule MyApp.Jido do use Jido, otp_app: :my_app end配置实例在config/config.exs中添加配置config :my_app, MyApp.Jido, max_tasks: 1000, agent_pools: []添加到监督树更新lib/my_app/application.exdefmodule MyApp.Application do use Application def start(_type, _args) do children [ # 添加Jido作为监督子进程 MyApp.Jido, # 您的其他子进程... MyApp.Repo, MyAppWeb.Endpoint ] opts [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) end end第2步更新代理启动方式在2.x版本中代理启动方式有了显著变化。不再直接调用start_link而是通过实例模块来管理。1.x版本旧方式# 直接启动代理 {:ok, pid} MyAgent.start_link(id: agent-1) # 或通过AgentServer启动 {:ok, pid} Jido.AgentServer.start_link( agent: MyAgent, agent_opts: [id: agent-1] )2.x版本新方式# 通过实例模块启动 {:ok, pid} MyApp.Jido.start_agent(MyAgent, id: agent-1) # 带额外选项 {:ok, pid} MyApp.Jido.start_agent(MyAgent, id: agent-1, initial_state: %{counter: 0}, strategy: Jido.Strategy.Direct )第3步采用指令系统处理副作用2.x版本引入了指令系统将纯状态转换与副作用执行完全分离。这是最重要的架构改进1.x版本混合副作用defmodule MyAgent do use Jido.Agent def handle_result(agent, result) do # 副作用与状态逻辑混合 Phoenix.PubSub.broadcast(MyApp.PubSub, events, result) # 外部API调用 HTTPoison.post!(https://api.example.com/webhook, result) # 更新状态 %{agent | state: Map.put(agent.state, :last_result, result)} end end2.x版本声明式指令defmodule MyAgent do use Jido.Agent alias Jido.Agent.Directive alias Jido.Signal def cmd(agent, %Signal{type: result.received} signal) do result signal.data # 纯状态更新 updated_agent %{agent | state: Map.put(agent.state, :last_result, result) } # 指令描述效果不执行它们 directives [ Directive.emit( Signal.new!(result.processed, result, source: /agent), {:pubsub, topic: events} ), Directive.emit( Signal.new!(webhook.send, result, source: /agent), {:http, url: https://api.example.com/webhook} ) ] {updated_agent, directives} end end核心指令类型指令用途示例Emit通过适配器分发信号Directive.emit(signal, {:pubsub, topic: events})Spawn生成通用BEAM进程Directive.spawn({Task, fn - work() end})SpawnAgent生成子代理Directive.spawn_agent(ChildAgent, :child_1, opts: %{id: child-1})StopChild停止跟踪的子代理Directive.stop_child(child-1)Schedule调度延迟消息Directive.schedule(5_000, signal)Stop停止代理进程Directive.stop(:normal)Error发出错误信号Directive.error(:validation_failed)第4步迁移到CloudEvents信号2.x版本使用CloudEvents兼容的信号代替了临时的消息格式。1.x版本临时消息# 发送消息 send(pid, {:task_complete, %{id: 123, result: done}}) GenServer.cast(pid, {:process, data}) # 在代理中处理 def handle_info({:task_complete, payload}, state) do # 处理逻辑... {:noreply, state} end2.x版本结构化信号alias Jido.Signal # 创建信号 signal Signal.new!( task.completed, %{id: 123, result: done}, source: /workers/processor-1 ) # 分发到特定代理同步 {:ok, agent} Jido.AgentServer.call(pid, signal) # 或异步分发 :ok Jido.AgentServer.cast(pid, signal) # 在代理中处理通过cmd/2 def cmd(agent, %Signal{type: task.completed} signal) do result signal.data.result {update_state(agent, result), []} end第5步从Actions迁移到ToolsJido.Actions.*命名空间已重命名为Jido.Tools.*。1.x版本Actionsdefmodule MyApp.Actions.SendEmail do use Jido.Action, name: send_email, description: 发送电子邮件, schema: [ to: [type: :string, required: true], subject: [type: :string, required: true] ] impl true def run(params, _context) do # 发送邮件... {:ok, %{sent: true}} end end2.x版本Toolsdefmodule MyApp.Tools.SendEmail do use Jido.Tool, name: send_email, description: 发送电子邮件 schema Zoi.struct(__MODULE__, %{ to: Zoi.string(description: 收件人邮箱), subject: Zoi.string(description: 邮件主题) }) impl true def run(params, _context) do {:ok, %{sent: true}} end end第6步采用Zoi模式验证2.x版本使用Zoi进行模式定义替代了NimbleOptions。1.x版本NimbleOptionsdefmodule MyAgent do use Jido.Agent, name: my_agent, schema: [ name: [type: :string, required: true], count: [type: :integer, default: 0], tags: [type: {:list, :string}, default: []] ] end2.x版本Zoi模式defmodule MyAgent do use Jido.Agent, name: my_agent schema Zoi.struct(__MODULE__, %{ name: Zoi.string(description: 代理名称), count: Zoi.integer(default: 0), tags: Zoi.list(Zoi.string()) | Zoi.default([]) }, coerce: true) type t :: unquote(Zoi.type_spec(schema)) enforce_keys Zoi.Struct.enforce_keys(schema) defstruct Zoi.Struct.struct_fields(schema) endZoi的优势单一事实来源类型、默认值和验证的统一管理自动类型规范生成减少样板代码强制转换支持更灵活的数据处理更好的错误信息更清晰的验证反馈第7步迁移到Splode错误处理2.x版本使用Splode进行结构化错误处理。1.x版本临时元组def process(data) do case validate(data) do :ok - {:ok, result} :error - {:error, :validation_failed} {:error, reason} - {:error, {:processing_error, reason}} end end2.x版本Splode错误defmodule MyApp.Errors do use Splode, error_classes: [ validation: MyApp.Errors.Validation, processing: MyApp.Errors.Processing ] end defmodule MyApp.Errors.Validation.InvalidInput do use Splode.Error, fields: [:field, :reason], class: :validation def message(%{field: field, reason: reason}) do 无效的 #{field}: #{reason} end end # 使用 def process(data) do case validate(data) do :ok - {:ok, result} {:error, field, reason} - {:error, MyApp.Errors.Validation.InvalidInput.exception( field: field, reason: reason )} end end2.x版本的新特性可选这些是2.x版本的新特性可以根据需要采用父子代理层次结构def cmd(agent, %Signal{type: spawn.worker} signal) do {agent, [ Directive.spawn_agent(WorkerAgent, id: worker-#{signal.data.id}, parent: agent ) ]} end # 子代理可以向父代理发送信号 Directive.emit_to_parent(child_agent, signal)插件系统defmodule MyAgent do use Jido.Agent, plugins: [ MyApp.Plugins.WebSearch, MyApp.Plugins.DataAnalysis ] end策略模式# 直接执行默认 MyApp.Jido.start_agent(MyAgent, strategy: Jido.Strategy.Direct ) # 基于有限状态机的执行 MyApp.Jido.start_agent(MyAgent, strategy: Jido.Strategy.FSM, strategy_opts: [initial_state: :idle] )常见迁移模式模式1渐进式运行时拥有的效果采用您不需要将所有副作用都移到指令后面。从运行时应该拥有的效果开始比如信号分发、调度和生成的工作def cmd(agent, signal) do # 新代码将运行时拥有的效果作为指令返回 result process(signal) # 即时工作仍然可以在操作/命令边界发生 LegacyNotifier.notify(result) {%{agent | state: result}, [ Directive.emit(Signal.new!(processed, result, source: /agent), :default) ]} end模式2旧版代理的包装器如果您有很多代理您的实例模块已经提供了包装器# 定义您的实例模块一次 defmodule MyApp.Jido do use Jido, otp_app: :my_app end # 然后在整个应用程序中使用它 MyApp.Jido.start_agent(MyAgent, id: agent-1) MyApp.Jido.stop_agent(agent-1)模式3旧版消息的信号适配器将旧的消息格式桥接到信号def handle_info({:legacy_event, payload}, state) do signal Signal.new!(legacy.event, payload, source: /legacy) handle_info(signal, state) end故障排除代理未找到错误确保使用正确的Jido实例名称# 错误 Jido.start_agent(Jido, MyAgent, id: test) # 正确 Jido.start_agent(MyApp.Jido, MyAgent, id: test)指令未执行指令只在从cmd/2返回时执行。确保正确返回它们# 错误 - 创建了指令但没有返回 def cmd(agent, signal) do Directive.emit(signal, :default) {agent, []} end # 正确 def cmd(agent, signal) do {agent, [Directive.emit(signal, :default)]} end模式验证错误如果从NimbleOptions迁移确保标记了必需字段# Zoi没有required: true字段默认是必需的 # 使用Zoi.optional()表示可选字段 schema Zoi.struct(__MODULE__, %{ name: Zoi.string(), # 必需 description: Zoi.string() | Zoi.optional() # 可选 })升级检查清单✅ 更新mix.exs中的Jido依赖到~ 2.0✅ 创建Jido实例模块并添加到监督树✅ 将所有start_link调用替换为实例模块的start_agent✅ 将生命周期调用更新为实例模块函数✅ 将副作用迁移到指令系统✅ 将消息格式更新为CloudEvents信号✅ 将Actions重命名为Tools✅ 将NimbleOptions模式迁移到Zoi✅ 将错误处理迁移到Splode✅ 运行测试套件验证迁移总结Jido 2.x带来了现代化的代理架构通过清晰的关注点分离和更强的类型安全使您的Elixir代理系统更加可靠和可维护。虽然迁移需要一些工作但收益是显著的更好的可测试性纯函数式代理使单元测试更简单更强的类型安全Zoi模式提供编译时验证更好的可观察性结构化错误和信号提供更好的调试体验更清晰的架构指令系统明确分离了决策与执行按照本指南的步骤您可以平滑地完成迁移并充分利用Jido 2.x的所有新功能。如果您遇到问题请查阅官方文档和迁移指南获取更多帮助。祝您迁移顺利【免费下载链接】jido Autonomous agent framework for Elixir. Built for distributed, autonomous behavior and dynamic workflows.项目地址: https://gitcode.com/GitHub_Trending/ji/jido创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考