Dify Agenton 用户指南:用 Layer 图组合可复用 Agent 计划与可恢复会话 Dify Agenton 用户指南用 Layer 图组合可复用 Agent 计划与可恢复会话【免费下载链接】difyBuild Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.项目地址: https://gitcode.com/GitHub_Trending/di/difyAgenton 是 Dify 仓库dify-agent包中的核心框架它以LayerNode和LayerProvider组成可复用的图层图计划把系统提示词、用户提示词和工具的定义从 Agent 主循环中解耦出来。读完本篇你将掌握如何在 Dify 的 Agenton 中定义带配置校验的 Layer、构建Compositor并在运行时注入配置、通过deps建立图层间直接依赖、聚合 prompt/tool 素材以及用会话快照session snapshot实现跨调用的状态挂起与恢复——这些能力正是 dify-agent 运行时 驱动 Agent 执行所依赖的底层机制。Agenton 的核心设计原则是state-only仅状态Compositor本身不保存任何存活的 layer 实例、客户端、清理栈或运行状态。每次Compositor.enter(...)调用都会创建一个全新的CompositorRun包含新的 layer 实例、直接的依赖绑定、生命周期状态以及一个可选的已水合hydrated会话快照。这一设计可以从 compositor 核心实现 的模块 docstring 中得到印证Compositor 只存储不可变的图节点和可选的聚合 transformer因此它可以被安全地反复甚至并发地 enter每一次进入都产生独立的CompositorRun。配置与运行时状态的四类划分Agenton 严格区分四种数据这是理解整个框架的钥匙也是它state-only承诺的来源Graph config图配置可序列化的拓扑描述包括节点name、providertype、依赖映射deps和元数据metadata。对应的 DTO 是 LayerNodeConfig它故意不包含任何 per-run 的 layer 配置——节点只描述这个节点是什么类型、依赖谁而不描述这一次怎么构造。Per-run layer config每次运行的层配置通过Compositor.enter(configs...)传入以节点名为键的映射。Provider 会在任何工厂函数运行之前用该 layer 的config_type逐一校验这些值见 _validate_layer_configs它注释明确说明在任何 provider 工厂被调用之前校验所有节点配置。Runtime state运行时状态挂在layer.runtime_state上的可序列化、逐层的调用状态。会话快照只持久化生命周期状态和这份 JSON 安全的数据。Live Python resources存活 Python 资源客户端、文件句柄、socket、进程句柄等一律留在 Agenton 核心之外由应用代码或包裹 compositor 进入逻辑的集成层 context manager 持有。LayerNodeConfig、CompositorConfig、CompositorSessionSnapshot等 DTO 均启用了extraforbid且图配置与快照是两个刻意分离的边界前者只描述可复用的组合状态schema 版本、有序节点名、provider type id、依赖映射、元数据后者只携带有序的生命周期状态与可序列化 runtime_state。外部 DTO 即使已经是构造好的 Pydantic 模型实例也会被重新 dump 再校验见 _validate_config_model_input防止构造后的变更绕过 compositor 入口校验器。定义一个配置驱动的 Layer为 per-run 配置使用LayerConfig模型并继承一个带类型的 layer 家族如PlainLayer这样Layer.__init_subclass__就能从泛型基类推断出 schema。base 层抽象 中__init_subclass__会依次推断deps_type、config_type与runtime_state_type无法推断时才需要子类显式声明。一个完整的例子如下from dataclasses import dataclass from pydantic import ConfigDict from typing_extensions import Self, override from agenton.layers import LayerConfig, NoLayerDeps, PlainLayer class GreetingConfig(LayerConfig): prefix: str model_config ConfigDict(extraforbid) dataclass(slotsTrue) class GreetingLayer(PlainLayer[NoLayerDeps, GreetingConfig]): type_id example.greeting prefix: str classmethod override def from_config(cls, config: GreetingConfig) - Self: return cls(prefixconfig.prefix) property override def prefix_prompts(self) - list[str]: return [self.prefix]要点解析type_id是可序列化图配置中引用该 layer 的注册标识。Compositor.from_config通过它把LayerNodeConfig.type解析为 provider见 _build_provider_type_map未声明type_id的 provider 会直接报错。from_config钩子LayerProvider.from_layer_type会用config_type校验原始配置然后调用这个类方法构造实例见 Layer.from_config。没有配置的 layer 走默认的无参构造路径有具体配置 schema 的 layer 必须覆写它来消费带类型的 Pydantic 模型否则默认实现会抛出TypeError。省略的 schema 槽位如果 layer 未指定配置或运行时状态则默认落到EmptyLayerConfig和EmptyRuntimeState见 base 层中的默认定义。生命周期钩子on_context_create / on_context_resume / on_context_suspend / on_context_delete都是 layer 实例上的无参方法应通过self.deps读取依赖、通过self.runtime_state读写可序列化的可变状态。存活资源Agenton 不替你清理但你可以在边界处确定性地清理Agenton 不拥有资源清理。把存活资源留在外围应用中显式地传给能力方法即可dataclass(slotsTrue) class ClientUserLayer(PlainLayer[NoLayerDeps]): def make_client_user(self, *, http_client: httpx.AsyncClient) - ClientUser: return ClientUser(http_client) compositor Compositor([LayerNode(client_user, ClientUserLayer)]) async with httpx.AsyncClient() as http_client: async with compositor.enter() as run: layer run.get_layer(client_user, ClientUserLayer) user layer.make_client_user(http_clienthttp_client)这样做的好处是把确定性清理保留在集成边界同时让 Agenton 的快照只包含可序列化的 runtime state。值得一提的是Agenton 并非完全没有资源作用域概念Layer.resource_context 提供了一个对称的 active-scope 异步上下文Agenton 会在on_context_create/on_context_resume之前进入它在on_context_suspend/on_context_delete之后退出它即使后续钩子或 run 主体失败也会保证确定性地拆除。但正如 run 模块 docstring 所强调的resource_context()中获取的资源只属于 active 作用域永远不会出现在任何快照 DTO 中。构建 Compositor从可序列化图配置出发对配置驱动的 layer使用 provider并在进入时传入 per-run 配置from agenton.compositor import Compositor, CompositorConfig, LayerNodeConfig, LayerProvider from agenton_collections.layers.plain import PromptLayer, PromptLayerConfig providers ( LayerProvider.from_layer_type(PromptLayer), LayerProvider.from_layer_type(GreetingLayer), ) compositor Compositor.from_config( CompositorConfig( layers[ LayerNodeConfig(nameprompt, typeplain.prompt), LayerNodeConfig(namegreeting, typeexample.greeting), ] ), providersproviders, ) async with compositor.enter( configs{ prompt: PromptLayerConfig(userAnswer with examples.), greeting: GreetingConfig(prefixHi), } ) as run: prompts run.prompts其中PromptLayer是agenton_collections提供的现成 layer位于 plain basic 实现接受prefix、user、suffix三个配置字段可直接产出三段式系统提示词素材。构建 API 的几条规则均可在 compositor core 源码 中验证CompositorConfig只支持schema_version 1其他版本在进入时直接抛错。providers按 type id 解析_build_provider_type_map会拒绝未声明type_id或重复注册type_id的 provider节点type找不到对应 provider 时抛出带 type id 的KeyError。LayerProvider.from_factory(...)当构造需要 Python 对象或可调用对象时使用。Provider 工厂只能拿到已校验的配置拿不到图节点数据并且必须为每次调用返回全新的 layer 实例——providers 模块 通过一个基于弱引用的全局注册表_claim_fresh_layer_instance强制这一点复用旧实例会在依赖绑定和生命周期钩子运行之前被拒绝。node_providers{node_name: provider}配合Compositor.from_config使用按节点名覆盖 type id 选出的 provider实现节点级定制构造而不必把节点数据塞进工厂传入未知节点名会在构建期报错。依赖方向有约束_validate_nodes会检查节点名唯一、依赖键必须声明在 layer 的 deps schema 中、依赖目标必须存在且依赖目标必须指向图序中更早的节点dependencies must target preceding layer nodes in compositor order这样才能让资源作用域按依赖顺序嵌套。图层依赖直接把上游 layer 实例绑到 self.deps图层依赖把直接的 layer 实例绑定到self.deps作用域仅限一次 run。依赖映射以依赖字段名为键、以compositor 节点名为值class ModelDeps(LayerDeps): plugin: PluginLayer dataclass(slotsTrue) class ModelLayer(PlainLayer[ModelDeps]): def make_model(self) - Model: return self.deps.plugin.make_provider()底层机制见 LayerDeps 与 bind_depsdeps_type子类中每个带注解的成员必须是一个具体的Layer子类或形如SomeLayer | None的现代可选依赖。绑定时的三类失败全部发生在生命周期钩子运行之前缺失必需依赖Missing layer dependencies未知的依赖键Unknown layer dependencies依赖目标的 layer 类型不匹配抛出TypeError提示期望类型与实际类型。可选依赖LayerSubclass | None在缺席时会被显式赋值为None而不是缺失属性。Compositor侧的绑定入口是 _bind_deps把每个节点的deps映射解析为节点名到 layer 实例的直连映射再逐个调用layer.bind_deps(...)。系统提示词、用户提示词与工具的四个创作面每个 layer 暴露四个 authoring surface定义于 Layer 基类的四个 property创作面含义聚合顺序prefix_prompts系统提示词片段按层序先声明者在前suffix_prompts系统提示词片段按逆层序先声明者在后user_prompts用户消息片段按层序tools工具条目按层序聚合结果可以在活动CompositorRun上通过run.prompts、run.user_prompts、run.tools读取。聚合顺序在 run 的 prompts 属性实现 中有精确体现先正序收集所有prefix_prompts再逆序收集所有suffix_prompts每个 item 都经过 layer 的wrap_prompt包装user_prompts与tools同理按图序收集。接入 pydantic-ai 时导入agenton_collections.transformers.pydantic_ai.PYDANTIC_AI_TRANSFORMERS并传给Compositor(...)或Compositor.from_config(...)让带 tag 的 layer 条目被转换为 Pydantic AI 的 prompt、user prompt 和 tool 值。这个常量定义在 transformers 模块它作为prompt_transformer/user_prompt_transformer/tool_transformer三个后聚合钩子工作——run 模块 docstring 说明它们只在 layer 级包装和 run 级聚合完成之后运行未安装 transformer 时包装后的条目原样返回。PlainLayer与PydanticAILayer两个 typed 家族分别把原生值包装为PlainPromptType、PydanticAIPromptType等带 tag 的类型见 layers/types.py使不同家族的条目可以在同一图中共存而不互相污染。会话快照与恢复显式的跨调用状态核心 Agenton 的 run 槽位默认是delete-on-exitrun 退出时调用on_context_delete槽位进入CLOSED。当希望下一次快照可恢复时在活动上下文中调用run.suspend_on_exit()或run.suspend_layer_on_exit(name)async with compositor.enter(configsconfigs) as run: run.suspend_on_exit() snapshot run.session_snapshot async with compositor.enter(configsconfigs, session_snapshotsnapshot) as restored_run: restored_layer restored_run.get_layer(stateful, StatefulLayer)这套机制对应的源码事实生命周期状态机LifecycleState 有NEW、ACTIVE、SUSPENDED、CLOSED四态其中ACTIVE是内部专用状态LayerSessionSnapshot 的校验器 会拒绝它出现在外部快照中LifecycleState.ACTIVE is internal-only。退出意图ExitIntent.DELETE/ExitIntent.SUSPEND控制退出时调用on_context_delete还是on_context_suspend意图只能在槽位处于ACTIVE时修改见 _set_layer_exit_intent。快照生成时机run.session_snapshot在上下文退出之后才被填充见 _exit_layers内容为有序 layer 名 非 ACTIVE 生命周期状态 各层 JSON 化 runtime_state。快照中不含配置、依赖、prompt、工具或任何存活资源。恢复约束恢复时必须把快照传给一个具有相同 layer 名称和顺序的后续Compositor.enter(...)调用——_validate_session_snapshot 会逐项比对名称序列同时 _ensure_layers_can_enter 保证ACTIVE状态无法进入、CLOSED的 layer 无法再次进入。水合时 runtime state 通过runtime_state_type.model_validate(...)重新校验见 _create_run。失败语义若on_context_create/on_context_resume抛错该层永远不会成为ACTIVE且那次失败的进入尝试不会运行正常的on_context_suspend/on_context_delete钩子——enter 钩子自己负责对部分副作用做业务补偿或幂等处理Agenton 只保证resource_context()的清理不保证钩子回滚。延伸阅读与源码索引可运行示例对应原文档的 See alsobasics.py——基础组合用法pydantic_ai_bridge.py——pydantic-ai 桥接session_snapshot.py——会话快照与恢复。核心实现compositor core图计划构建、配置校验、快照水合与 enter 上下文DTO 与边界校验CompositorConfig、CompositorSessionSnapshot及 ACTIVE 拒绝逻辑Layer 基类LayerConfig、LayerDeps、生命周期钩子与 schema 推断CompositorRun槽位生命周期、退出意图、快照与 prompt 聚合LayerProvider配置校验、工厂调用与全新实例强制typed 家族PlainLayer与PydanticAILayer的 prompt/tool 包装契约。【免费下载链接】difyBuild Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.项目地址: https://gitcode.com/GitHub_Trending/di/dify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考