action 管理模块设计
action 管理模块设计文档¶
1. 概述¶
1.1 功能描述¶
action 管理模块是 DataAgent 的 action space 网关,负责统一管理所有可被 Agent 调用的工具(Action/Tool),包括:
- 本地函数工具:直接调用 Python 函数的工具
- MCP 远程工具:通过 Model Context Protocol 暴露的远程工具
- A2A 远程工具:通过 Agent-to-Agent 协议暴露的其他 Agent 工具
模块对上层的 Planner、Executor 等组件屏蔽底层工具来源与协议差异,提供统一的 注册 / 发现 / 调用 / 查询 接口。上层只需关心"工具能做什么",而不必关心"工具在哪里、如何通信"。
2. 设计描述¶
2.1 设计思路¶
Per-Agent 隔离
每个 Agent 实例拥有独立的工具管理上下文,内部聚合多类工具注册表。不同 Agent 之间的工具集合、发现缓存、Schema 缓存完全隔离,互不污染。
统一工具抽象
所有来源的工具——无论是本地函数、MCP 服务还是 A2A Agent——在被注册或发现后,均被包装为统一的工具抽象实例。该抽象定义了调用接口、Schema 获取、参数校验、以及与 LangChain 生态的互操作能力,使上层无需区分工具来源。
Schema 与元数据驱动
每个工具在注册或发现时,会生成一份结构化的 Schema 描述,包含工具名、参数列表(名称、类型、是否必填、默认值)、工具描述等。通过 Schema,模块可以: - 为 LLM function calling 生成 OpenAI 兼容的工具定义; - 为前端管理界面提供结构化的工具信息; - 在调用前进行参数校验。
多源工具发现与懒加载
远程工具(MCP/A2A)支持两种发现时机:
- 启动时全量发现:在 Agent 初始化阶段,对所有已注册的远程服务进行一次批量工具发现;
- 运行时按需懒加载:当首次通过带前缀的名称(如 server_id.tool_name)尝试获取工具时,若本地尚未缓存该服务器的工具,则触发一次针对该服务器的增量发现。
懒加载由"已尝试发现"缓存保证幂等性——同一远程服务不会重复发起发现请求,也不会在发现失败时反复重试。
配置驱动与解耦
工具管理模块的初始化由 Agent 配置文件驱动。配置文件声明了本地函数列表、MCP 服务器列表、A2A Agent 列表等,模块解析配置后自动完成三类工具的注册与远程工具的发现。上层只需维护 YAML 中的工具配置段,Flex 运行时在构建 Agent 环境时会自动初始化 action space。
2.2 模块结构¶
2.2.1 核心组件与职责¶
- 工具管理器(Per-Agent 入口)
-
作为每个 Agent 实例的工具操作入口,负责:
- 维护当前 Agent 的工具实例缓存与 Schema 缓存;
- 持有本地工具注册表、MCP 注册表、A2A 注册表的引用;
- 执行配置驱动的初始化、远程工具发现、懒加载调度;
- 对外暴露统一调用接口(同步/异步)和查询接口(工具列表、Schema 获取、LLM 工具定义、分类汇总等)。
-
统一工具抽象
- 定义所有工具实例必须遵循的契约:调用执行、Schema 暴露、LangChain 兼容转换、参数校验;
-
各来源类型的工具子类负责实现具体适配逻辑(如 MCP 工具负责将 JSON Schema 转换为内部 Schema,A2A 工具负责 HTTP 调用与结果解析)。
-
本地工具包装器
-
将普通 Python 可调用对象(函数)包装为统一工具抽象,自动从函数签名和类型标注生成参数 Schema。
-
注册表组件
- 本地工具注册表:管理工具名到工具实例的映射,支持注册、注销、按分类查询;
- MCP 注册表:管理 MCP 服务器的注册、连接、健康检查与工具列表拉取;
- A2A 注册表:管理远程 Agent 的注册、连接、认证与工具列表拉取。
2.2.2 关键数据结构¶
- 工具实例缓存:
工具名 → 工具实例的映射。Key 命名规则: - 本地工具:
"tool_name"(如"bash"、"read_file") - MCP 工具:
"{server_id}.{tool_name}" -
A2A 工具:
"{agent_id}.{tool_name}" -
工具 Schema 缓存:
工具名 → Schema的映射。所有查询操作基于此缓存,避免重复生成 Schema。 -
发现缓存:记录已尝试过工具发现的远程服务标识(server/agent ID),保证懒加载幂等,防止失败后重复请求远程服务。
-
工具类型枚举:区分
本地函数、MCP 工具、A2A 工具及自定义四种工具来源类别。
2.3 关键流程¶
2.3.1 本地工具注册流程¶
- Agent 配置文件的工具段中声明本地函数工具,指定模块路径、函数名等;
- 初始化时,模块根据配置动态导入指定模块中的可调用对象;
- 若为普通可调用对象,则由本地工具包装器封装为统一工具抽象;若本身已是工具抽象的子类,则直接实例化;
- 包装后的工具实例写入本地工具注册表,同时生成 Schema 并写入缓存。
2.3.2 MCP 服务器注册与工具发现¶
- 注册阶段:通过配置文件声明 MCP 服务器(含服务标识、传输类型、启动命令/连接参数等),由 MCP 注册表管理服务器的连接配置;
- 发现阶段:通过显式调用或在懒加载路径中按需触发,由 MCP 注册表向目标服务器拉取工具列表,将远程工具定义包装为统一工具抽象后写入本 Agent 的工具实例缓存和 Schema 缓存。
2.3.3 A2A Agent 注册与工具发现¶
- 注册阶段:通过配置文件声明远程 A2A Agent(含 Agent 标识、服务地址、认证令牌、超时时间等),由 A2A 注册表管理连接信息;
- 发现阶段:与 MCP 类似,通过显式或懒加载方式拉取远程 Agent 暴露的工具列表,包装后写入本地缓存。
2.3.4 配置驱动初始化流程¶
- DataAgent 构建时读取并合并配置;
- Flex 运行时构建 Agent 环境时,为每个 Agent 创建独立的工具管理器实例,并传入其配置段进行初始化:
- 解析本地函数列表:逐个导入模块与函数,依次注册;
- 解析MCP 服务器配置:注册服务器,必要时启用自动发现;
- 解析A2A Agent 配置:注册远程 Agent,必要时启用自动发现;
- 解析内置工具:注册预设的常用本地工具(如文件读写、命令执行等);
- 解析技能(Skill):发现并加载内置与用户自定义技能的元数据。
- 若已注册 MCP 或 A2A 服务,初始化阶段会触发全量工具发现,远程工具进入当前 Agent 的工具缓存。
2.3.5 工具调用与查询流程¶
- 调用:
- 通过工具名获取工具实例(此过程可能触发懒加载);
- 调用工具实例的执行方法,传入参数;
- 若为异步调用且工具支持异步,走异步路径;否则回退到同步执行(在线程池中运行);
-
返回统一的结果结构(含成功标志、数据、错误信息、错误类型及重试策略)。
-
查询:
- 按条件列出工具:支持按分类、工具类型过滤;
- 获取 Schema:从缓存中返回指定工具的完整参数 Schema;
- 获取 LLM 工具定义:将指定工具的 Schema 批量转换为 OpenAI function calling 格式;
- 获取工具详情/汇总/健康状态:用于诊断、监控和管理界面展示。
2.3.6 错误处理与重试¶
- 工具执行异常被统一分类(参数校验错误、网络错误、超时、限流、内部错误等),并关联预设的重试策略(是否可重试、最大重试次数、退避方式);
- 调用失败时抛出统一的工具异常,上层可通过异常携带的错误类型和重试标记决定是否重试。
3. 规格约束¶
- 工具命名规范
- 本地工具名称在单个 Agent 的工具管理器实例内必须唯一;
-
MCP/A2A 工具必须使用
"{服务标识}.{工具名}"的前缀命名方式,避免与本地工具冲突。 -
懒加载与缓存约束
- 懒加载仅在首次访问某个远程服务标识时触发,重复访问以缓存命中处理;
-
若发现失败,该服务标识被标记为"已尝试",阻止后续重复尝试,避免频繁请求不可达的远程服务。
-
线程安全与生命周期
- 每个 Agent 的工具管理器实例在 Agent 的完整生命周期内持有工具注册表;
- 工具的注册与发现通常在 Agent 启动阶段完成,避免运行中并发修改;
-
资源清理(关闭远程连接、清空缓存)在 Agent 销毁时触发。
-
异常处理
- 未找到工具或 Schema 时统一抛出工具异常,由上层统一处理;
-
远程服务不可达或发现超时等异常在懒加载过程中被静默处理并标记失败,调用方通过工具是否存在或调用是否成功来感知。
-
配置兼容性
- 工具管理器支持多版本的配置格式,对老版本的配置字段保持向后兼容;
- 配置文件中的工具声明建议显式指定工具名称,避免与函数名变更耦合。