ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

使用 ADK 配置文件声明式构建 Agent 与多智能体图:from_config 与 YAML 工作流实战指南

2026/9/13 17:10:18 拓冰建站 浏览量
使用 ADK 配置文件声明式构建 Agent 与多智能体图:from_config 与 YAML 工作流实战指南 使用 ADK 配置文件声明式构建 Agent 与多智能体图from_config 与 YAML 工作流实战指南【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python本文面向希望用 YAML 配置而非 Python 代码来定义、运行 Agent 及其多智能体图Multi-agent Graph的开发者系统讲解 ADKAgent Development Kit的配置驱动能力从from_config()的加载入口、edges图语法、CLI 一键运行到底层基于类型注解的字段映射原理与安全模型。读完本文你将能够用纯配置文件搭建链式、路由、循环等各类 Agent 工作流并理解其类解析、子 Agent 解析与模块黑名单机制从而安全地将配置化 Agent 应用于 CI/CD 流水线、按租户路由、以及无需发版即可调优的线上场景。为什么用配置文件描述 AgentADK 允许你用 YAML 文件而不是 Python 代码来构建一个 Agent甚至是一整张多智能体图。核心入口是google.adk.agents.config_agent_utils中的from_config()它读取文件、把每一个字段解析到目标类上并返回一个立即可运行的 Agent 实例。from google.adk.agents import config_agent_utils root_workflow config_agent_utils.from_config(root_agent.yaml)这种方式的适用场景很明确当工作流形态的变化频率高于底层代码的变化频率时配置化具备明显优势例如CI/CD 流水线中按环境或分支切换 Agent 编排多租户场景下为不同租户定制路由与子 Agent 组合运营人员在不发布新包的前提下直接调优一张图。从源码看from_config()src/google/adk/agents/config_agent_utils.py目前以experimental(FeatureName.AGENT_CONFIG)标记属于实验性特性但其加载链路已经非常完整yaml.safe_load解析文件 → 校验顶层必须是字典 → 解析agent_class→ 交给_AgentConfigMapper做字段映射 → 构造实例并回填延迟字段。快速开始两份文件构建一个可运行工作流最小的配置化 Agent 只需要两个文件一个工作流定义以及它调用的 Agent 定义。root_agent.yamlagent_class: Workflow name: my_sample_workflow edges: - - START - my_module.functions.process_data - sub_agent.yamlsub_agent.yamlagent_class: LlmAgent name: summarizer_agent description: Summarizes incoming data payloads. instruction: Please summarize the following input concisely.root_agent.yaml声明了一个Workflow其中edges定义了一条从入口节点START出发、经过 Python 函数my_module.functions.process_data自动包装成FunctionNode、最终到达sub_agent.yaml所定义 Agent 的链路。用上面的两行 Python 加载它即可得到活的Workflow实例。从 CLI 运行零 Python 启动如果文件名为root_agent.yaml且它位于一个以 Agent 名命名的目录中那么 ADK CLI 可以完全不用 Python 代码直接找到它my_agents/ my_sample_workflow/ root_agent.yaml sub_agent.yamladk run my_agents/my_sample_workflow # 交互式终端会话 adk web my_agents # 开发界面每个目录一个入口 adk api_server my_agents # HTTP 服务器暴露所有 Agent加载器遵循明确的优先级先尝试 Python 形态——{agent_name}/__init__.py中暴露的root_agent然后是{agent_name}/agent.py——只有当两者都不存在时才回退到{agent_name}/root_agent.yaml。这意味着一个目录可以从 Python 平滑迁移到 YAML 而无需改变启动方式但反过来也需要注意只要 Python 定义还在它就会一直胜出迁移时 Python 文件必须移除。编写 edges图的三种核心语法edges是整个配置语法中自成体系的部分手工编写图之前值得先通读。列表中的每一项都是以下三种形态之一。其中前两种是简写下面给出的显式形式可以表达它们能表达的一切。链式写法chain一个节点列表相邻节点两两成边因此三个元素的链对应两条边edges: - - START - fetch.yaml - summarize.yaml # START - fetch且 fetch - summarize注意链要用上面这种块状形式书写。行内列表[a, b]永远表示扇出fan-out所以用额外的行数换取这两种语法在视觉上的区分是值得的。路由映射routing map一个以路由名route name为键的映射用于某个节点按执行结果扇出edges: - - START - classifier.yaml - refund: refund_handler.yaml question: faq_agent.yaml other: [logger.yaml, escalation_agent.yaml] # 列表表示扇出这里的键是路由值而不是字段名所以名为name的路由会被当作路由读取而不会被误认为是行内节点。唯一的例外一个仅含单个条目code、且其值为字符串的映射被解释为 Agent 引用AgentRefConfig因此恰好是这种形状的路由不可用。这与源码中_looks_like_a_node()config_agent_utils.py的判断逻辑一一对应agent_class、config_path、func_code键只可能命名节点code单键字符串映射判定为 Agent 引用。显式边explicit edge前两种简写展开后的完整形式一个包含from_node与to_node的映射当源节点需要在多条出边中选择时再附加routeedges: - - START - classifier.yaml # 引入名为 classifier 的节点 - from_node: classifier to_node: refund_handler.yaml route: refund在源码中这类映射会被解析为Edge(from_node..., to_node..., routeroute)见_resolve_edges()config_agent_utils.py。节点可以是什么任何期待一个节点的位置以下全部合法形式示例含义STARTSTART图的入口点一个名字summarizer_agent本文件中其它位置定义的节点名一个配置路径sub_agent.yaml另一个配置文件相对于当前文件解析一个函数引用my_module.functions.process_data包装成FunctionNode一个内联映射{agent_class: LlmAgent, name: x, ...}就地定义的节点实践上建议一个 Agent 一个文件并以路径引用节点定义不被内联进图时整张图的阅读体验会好很多。内联映射是为路径无法覆盖的场景准备的。关于函数引用与命名有两个关键点裸函数引用不需要name节点直接采用函数自身的名字因此my_module.functions.process_data会成为名为process_data的节点后续边就用这个名字引用它。只有当你想换一个名字或附加额外字段时才使用映射形式且此时name是必填的- name: preprocess agent_class: FunctionNode func_code: my_module.functions.process_data节点按名称和按引用双重缓存一个节点在链中定义一次后续边再次引用它时得到的是同一个对象而不是副本——这正是START和共享子图在跨边时保持身份稳定的机制对应_AgentConfigMapper._resolved_nodes_cacheconfig_agent_utils.py。同时定义必须在前一条更早的边尚未引入的名字会被直接拒绝而不是推迟到后面再解析。如果你引用了未定义的裸名字会得到形如Unknown node xxx. A node has to be defined by an earlier edge before another edge can name it.的明确报错config_agent_utils.py。工作原理from_config 的底层机制选择目标类顶层agent_class指定要构建的类默认是LlmAgent。简写Workflow、FunctionNode、LlmAgent会在google.adk.agents与google.adk.workflow两个包内解析其它任何写法都被视为全限定名并执行导入。源码中的_resolve_agent_class()config_agent_utils.py会先探测内置包、再走resolve_fully_qualified_name最终要求解析结果必须是BaseNode的子类否则抛出ValueError。注意这里对简写与全限定名采用了不同路径简写未命中只是落到下一个候选包而全限定名导入失败会以用户自己的坏模块身份直接暴露出来。填充字段基于类型注解的反射映射与「每个类各自解析自己的配置」的传统做法不同这里的映射器读取目标类的字段注解field annotations把每个 YAML 值解析为该字段所期望的类型——工具列表、回调、Schema、子 Agent、模型等一概如此。这带来一个非常优雅的性质给类新增一个字段它立即就可以被配置无需同步修改任何解析器。在map()config_agent_utils.py内部映射按注解类型分派_map_field()config_agent_utils.pyWorkflow的edges字段 →_resolve_edges()递归处理链、路由映射与显式边子 Agent 列表字段 → 逐个构造AgentRefConfig并调用resolve_agent_reference()水合工具列表字段 → 解析为 ADK 内置工具google.adk.tools中的对象或用户自定义工具类形态的工具会用ToolArgsConfig构造参数实例化_resolve_tools()config_agent_utils.py回调 / Schema / 自定义 LLM 字段 → 解析为CodeConfig并导入对应 Python 对象。键会先经过目标类的 config schema 校验所以拼写错误的键会被报告出来而不是被静默忽略。校验严格程度取决于 schema 本身内置配置类禁止未知键extraforbid而自定义 Agent 类继承BaseAgentConfig允许额外键存在以便类自行定义扩展字段。对于Workflow与FunctionNode这类根本不声明 config schema的节点类反射是唯一的闸门放不下的键会被记录为一条点名类名和键名的 warning。字段映射还支持两个后缀约定以_code结尾的键如model_code会映射到去掉后缀的字段model并作为代码引用解析以_callbacks结尾的键如before_agent_callbacks会映射到对应的单数回调字段before_agent_callback。此外对于构造函数签名不接收**kwargs的类典型如FunctionNode映射器会把放不进构造参数的合法字段暂存在deferred_fields中待构造完成后用 pydantic 的validate_assignment回填——这保证了 YAML 中写下的字段永远不会被悄悄丢弃。引用 Python_code键以_code以及_callbacks结尾的键保存的是对 Python 中某个对象的全限定引用——函数、回调、Schema 类等。每个引用在导入之前都会先经过下述模块黑名单的校验。另外以.开头的代码引用支持相对于当前 Agent 目录的包路径解析例如在contributing/samples/workflows/loop_config/root_agent.yaml中写.agent.process_input会被解析为loop_config.agent.process_input取当前配置所在目录的包名做前缀从而在sys.path已包含 agent 目录的前提下定位到agent.py中的函数。解析子 Agentsub_agents与edges通过同一个映射器水合被引用的配置文件会被像顶层文件一样完整解析。路径相对于「提及它的那个文件」解析因此一个仓库可以把 Agent 组织进writers/、critics/等文件夹并跨目录引用。例如 multi_agent_loop_config/root_agent.yaml 中通过config_path: writer_agents/initial_writer_agent.yaml引用子目录内的 Agent而config_path: loop_agent.yaml则引用同目录下的循环 Agent——后者内部又引用了writer_agents/critic_agent.yaml与writer_agents/refiner_agent.yaml形成两层嵌套的配置图。安全模型与限制因为配置内容最终会映射到 Python 对象ADK 为此内置了三层防护。模块黑名单每一个_code引用都按名字解析这如果不加约束将是一条直达任意代码执行的路径。因此在导入前引用中的顶层模块会先对照一份覆盖整个标准库加上已知具有执行/反序列化入口的第三方包的黑名单做校验_validate_module_reference()config_agent_utils.py。值得强调的是这里封锁的是整个标准库而不是一份精心挑选的危险模块清单——因为「精选清单」根本兜不住cProfile.run、timeit.timeit、trace.Trace.run都会执行你传入的字符串而且每个 Python 版本都可能在标准库中新增更多此类入口。Agent 配置对标准库没有正当需求——它们只命名 Agent 自己的包、google.adk或某个第三方集成。从源码看config_agent_utils.py黑名单由sys.stdlib_module_names | sys.builtin_module_names构成的标准库全集叠加一份显式清单组成显式清单中除了os、subprocess、ctypes、pickle、marshal、socket、http、urllib等常客外还专门点名了yaml与ruamel其unsafe_load可通过!!python/object/apply标签构造任意 Python 对象以及distutils、imp、test、_testcapi这类已移出标准库或由 CPython 自带测试包提供的执行入口。但黑名单终究是黑名单它无法覆盖所有第三方包。请把「能够命名任意模块的配置」当作可信输入对待——只加载你信任来源的配置文件。args键args仍是一个受支持的键——它是工具或工具集配置传递构造参数的方式。处于变动中的是围绕它的防护而不是键本身。因为args可以触达代码执行所以为它准备了一份键黑名单_BLOCKED_YAML_KEYS frozenset({args})但该黑名单当前默认关闭源码中_ENFORCE_YAML_KEY_DENYLIST False见 config_agent_utils.py。凡是会加载「不受自己控制的配置」的宿主应当显式调用_set_enforce_yaml_key_denylist(True)开启它把它改为默认拒绝是正在进行中的工作。路径处理文件引用中的绝对路径会被拒绝Absolute paths are not allowed in AgentRefConfig config_path因此配置只能触达兄弟文件与后代文件而非磁盘任意位置。更进一步resolve_agent_reference()会用os.path.commonpath做目录穿越检测解析后的真实路径若落在引用文件所在目录之外会抛出Path traversal detected错误config_agent_utils.py。实战用 YAML 声明循环与路由两个官方示例展示了配置语法在真实场景中的威力它们正是本文档推荐的相关样本。带反馈循环的工作流loop_configcontributing/samples/workflows/loop_config 演示如何用一个 YAML 定义带反馈回路的工作流与对应的 Python 版loop示例镜像但完全以 YAML 声明。其 root_agent.yaml 构建出五条边的图最后一条是unrelated路由回到generate_headlineagent_class: Workflow name: root_agent edges: - - START - .agent.process_input - generate_headline.yaml - evaluate_headline.yaml - .agent.route_headline - - .agent.route_headline - unrelated: generate_headline.yaml图中generate_headline.yaml与evaluate_headline.yaml是两个独立的LlmAgent配置文件其中后者通过output_schema: name: loop_config.agent.Feedback引用agent.py中的 Pydantic 模型作为结构化输出、并用output_key: feedback指定输出键见 evaluate_headline.yaml。映射器按字符串值缓存已解析节点因此同一文件名在多条边中复用时拿到的是同一个 Agent 实例——这正是循环结构得以成立的关键。注意代码引用是相对sys.path解析的运行时需要像 CLI 那样从持有 agent 文件夹的目录即contributing/samples/workflows执行。在adk web开发界面中运行该示例时可以看到左侧完整呈现START → process_input → generate_headline → evaluate_headline → route_headline的流程图右侧事件流则实时记录状态topic、feedback、生成结果与route: unrelated的回跳决策顺序 循环的多 Agent 流水线multi_agent_loop_configcontributing/samples/multi_agent/multi_agent_loop_config 展示了一个由多个配置文件组成的多 Agent 系统先由一个初始写作 Agent 起笔评论 Agent 审阅并反馈精炼 Agent 依据反馈修改然后循环回评论步骤直到评论 Agent 输出「No major issues found.」为止。其 root_agent.yaml 用SequentialAgent顺序编排两个子 Agentagent_class: SequentialAgent name: IterativeWritingPipeline description: Iterative writing pipeline agent. sub_agents: - config_path: writer_agents/initial_writer_agent.yaml - config_path: loop_agent.yaml而 loop_agent.yaml 用LoopAgent声明循环并通过max_iterations: 5限制最大迭代次数agent_class: LoopAgent name: RefinementLoop description: Refinement loop agent. max_iterations: 5 sub_agents: - config_path: writer_agents/critic_agent.yaml - config_path: writer_agents/refiner_agent.yaml可以尝试的示例查询initial topic: badminton、initial topic: the history of computers。深入阅读配置加载的完整实现src/google/adk/agents/config_agent_utils.py重点可看from_configL703、_AgentConfigMapper.mapL446与模块黑名单定义L843单元测试tests/unittests/agents/test_agent_config.py覆盖配置加载、字段映射与校验行为工作流循环配置示例contributing/samples/workflows/loop_config/README.md多 Agent 顺序与循环配置示例contributing/samples/multi_agent/multi_agent_loop_config/README.md。总而言之ADK 的配置化 Agent 走了一条「以类型注解为契约、以反射为引擎」的路线新增字段即可配置、子图按相对路径自由组织、CLI 无缝发现——同时在代码引用、args键与文件路径三个维度上内置了明确的安全闸门。对需要频繁调整工作流形态、又不想每次改动都重新发版的团队而言这是一条低成本、高可读性的声明式路径。【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考