Solon v4.0.2

talents - Gateway 三件套:OpenApi / Tool / MCP

</> markdown
2026年6月17日 上午8:56:32

Gateway 网关是 Solon AI 生态中解决"工具过多导致上下文溢出"的核心机制。提供三个独立的网关 Talent,分别对接 REST API、本地工具、MCP 服务,均内置四阶段自适应发现模式,可根据工具数量自动切换策略,平衡模型推理精度与 Token 消耗。

相关依赖包: solon-ai-talent-gateway

1、架构概览

网关 Talent适用场景工具来源管理粒度
OpenApiGatewayTalent对接海量 WebAPI,自动解析 OpenAPI / Swagger 文档远程或本地的 OpenAPI / Swagger 定义文件API 源 为单位增删
ToolGatewayTalent治理代码侧 FunctionTool 数量膨胀(本地工具与 MCP Tool 都可纳管)FunctionTool(本地工具,或已接入的 MCP Tool)运行时单个 Tool 命令式增删
McpGatewayTalent按服务整体接入并治理 MCP 服务端工具MCP Client 连接整条 MCP 连接 增删;连接内的工具用白/黑名单做开放控制

三者共享相同的四阶段自适应模式和 API 风格,可独立使用,也可组合挂载到同一个 Agent 上。

如何选? 看两点——接入方式和增删单位:

  • 工具以 OpenAPI / Swagger 文档 形式存在 → OpenApiGatewayTalent
  • 工具是 代码里注册的 FunctionTool,需要在运行时逐个动态增删(命令式,精确到单个 Tool)→ ToolGatewayTalent
  • 工具来自 MCP 服务端,按服务整体接入更顺手 → McpGatewayTalent

这里有个容易被误解的点:「想精确控制 MCP 暴露哪些工具」并不等于「必须用 ToolGatewayTalent」McpGatewayTalent 在接入每条连接时,可通过 McpServerParametersallowedTools(白名单,空表示全部)/ disallowedTools(黑名单,空表示不禁)做工具级开放控制,精确到该服务暴露哪几个工具。

所以两者的真正分野不是「能不能管到单个工具」,而是控制方式ToolGatewayTalent运行时、命令式、按单个 Tool 动态增删McpGatewayTalent接入时声明式配置白/黑名单,工具集随连接生命周期管理,变更名单后需调用 refreshMcpServer() 生效。工具来源杂、需要运行时灵活拼装就用前者;按 MCP 服务整体接入、用名单声明式收敛工具面就用后者。

2、四阶段自适应发现机制

三个网关 Talent 使用完全一致的阈值切换逻辑:

模式名称触发条件对 LLM 的表现暴露的工具
FULL(全量)数量 <= dynamicThreshold(默认 8)直接看到所有工具完整定义原始工具(OpenAPI 为 call_api
SUMMARY(摘要)8 < 数量 <= listThreshold(默认 30/40)展示"工具名 + 功能描述 + Endpoint"清单get_*_detail + call_*(无搜索)
LIST(名字)30/40 < 数量 <= searchThreshold(默认 100)仅展示分组及工具名列表,需按需检索search_* + get_*_detail + call_*
SEARCH(搜索)数量 > 100清单完全折叠,强制关键词检索search_* + get_*_detail + call_*

核心设计思想:接口/工具数量少时,直接将完整 Schema 嵌入 Instruction,LLM 可一步到位调用;数量增多后,逐步折叠信息,通过中转工具引导 LLM 先搜索、再查看详情、最后执行。

3、OpenApiGatewayTalent — 对接海量 WebAPI

3.1 核心特性

  • 双版本解析:内置自适应解析器,自动识别 Swagger 2.0 和 OpenAPI 3.0 规范(通过 JSON 中是否存在 openapi 字段判断版本)。
  • 多源 API 整合:支持从多个不同的 Swagger 节点(http://classpath:)并行加载接口,按 tag 自动分组。
  • $ref 递归解析:深度展开 $ref 引用(含嵌套对象、数组内部引用),自动处理循环引用(输出 _Circular_Reference_ 标记)。
  • 全自动代理:AI 仅需下达意图,由网关自动完成 Path 占位符替换(含 URL 编码)、Query/Body 序列化、Header 注入及 Multipart 提交。
  • 上下文保护:内置响应结果截断(默认 8000 字符,可通过 maxContextLength 配置),防止庞大的业务数据撑爆 AI 上下文。
  • 细粒度权限控制:每个 API 源支持独立的 allowedTools(白名单)和 disallowedTools(黑名单),运行时可在 ApiSourceClient 副本上动态修改,不影响原始配置。
  • 失败重试:内置 RetryUtil 重试机制(默认 3 次),可全局或按源配置超时时间。
  • 禁用接口自动忽略:解析时自动跳过 Swagger 中标记为 @Deprecated 的接口,保持 Agent 技能树整洁。

3.2 应用示例

// 1. 初始化 Talent
OpenApiGatewayTalent apiTalent = new OpenApiGatewayTalent()
        .dynamicThreshold(5)      // 超过 5 个接口开启摘要模式
        .listThreshold(30)        // 超过 30 个接口开启名字列表模式
        .searchThreshold(100)     // 超过 100 个接口开启强制搜索模式
        .maxContextLength(10000)  // 结果截断长度
        .defaultTimeout(Duration.ofSeconds(30))
        .defaultAuthenticator((http, tool) -> {
             http.header("Authorization", "Bearer your-token"); // 全局认证
        });

// 2. 挂载多个业务模块的 API(支持 http 或 classpath)
apiTalent.addApi("http://order-service:8081/v3/api-docs", "http://order-service:8081");
apiTalent.addApi("classpath:swagger/user-api.json", "http://user-service:8082");

// 2.1 也可使用 ApiSource 对象精细配置(支持独立认证、权限过滤、超时等)
ApiSource source = new ApiSource();
source.setDocUrl("http://pay-service:8083/v3/api-docs");
source.setApiBaseUrl("http://pay-service:8083");
source.setAllowedTools(Arrays.asList("createPayment", "queryPayment")); // 仅加载 2 个接口
source.setAuthenticator(ApiAuthenticator.bearer("pay-service-token"));
source.setTimeout(Duration.ofSeconds(60));
apiTalent.addApi(source);

// 3. 构建智能体
ReActAgent agent = ReActAgent.of(LlmUtil.getChatModel())
        .role("高级业务助理")
        .instruction("请优先使用提供的业务 API 解决问题,不要猜测接口参数。")
        .defaultTalentAdd(apiTalent)
        .build();

// 4. 运行时动态管理
apiTalent.removeApi("http://order-service:8081/v3/api-docs");  // 移除某个源
apiTalent.refreshApi("http://pay-service:8083/v3/api-docs");   // 刷新权限过滤
apiTalent.refreshApiAll();                                      // 刷新所有源

3.3 内置工具说明

根据当前阶段模式,AI 会自动调用以下工具(工具名以全量场景为例):

工具名可用模式功能说明
call_api全部模式执行 REST API 调用。支持路径参数替换({name} 格式,自动 URL 编码)、Query/Body 序列化、Multipart 提交
get_api_detailSUMMARY/LIST/SEARCH获取指定接口的完整参数 Schema(Header、Path、Query、Body)及返回值结构
search_apisLIST/SEARCH通过多关键词(空格分隔,AND 逻辑匹配)在海量 API 库中模糊搜索接口,返回分组、描述及 Endpoint

3.4 内置认证策略

ApiAuthenticator 是一个函数式接口,支持灵活的认证扩展:

// 方式 1:Bearer Token
apiTalent.defaultAuthenticator(ApiAuthenticator.bearer("your-token"));

// 方式 2:自定义 Header
apiTalent.defaultAuthenticator(ApiAuthenticator.apiKey("X-Api-Key", "your-key"));

// 方式 3:完全自定义(如动态签名)
apiTalent.defaultAuthenticator((http, tool) -> {
    http.header("X-Timestamp", String.valueOf(System.currentTimeMillis()));
    http.header("X-Signature", HmacUtils.sign(tool.getPath(), secretKey));
});

认证优先级:源级 Authenticator > 全局 defaultAuthenticator

3.5 运行时权限管理

每个 API 源通过 ApiSourceClient 维护独立的权限副本:

ApiSourceClient client = apiTalent.getApiSource("http://pay-service:8083/v3/api-docs");

// 在 client 副本上动态修改(不影响 ApiSource 原始配置)
client.setAllowedTools(Arrays.asList("createPayment"));  // 运行时缩小范围
client.getDisallowedTools().add("queryRefund");           // 运行时追加黑名单

// 刷新使权限生效
apiTalent.refreshApi("http://pay-service:8083/v3/api-docs");

4、ToolGatewayTalent — 通用工具网关(本地工具 + MCP Tool)

4.1 核心特性

  • 通用工具网关:适用于任意 FunctionTool,既能纳管代码注册的本地工具、第三方 SDK 工具,也能纳管 MCP Tool。
  • 以单个 Tool 为单位治理:动态添加/移除的颗粒度是单个 FunctionTool;这也是它与 McpGatewayTalent 的核心区别——后者以整条 MCP Client 连接为单位增删。两者在管理 MCP Tool 上能力重叠,按所需的治理颗粒度选择即可。
  • 分类管理:支持按 category 分组注册工具,在 Instruction 中按分组展示,帮助 LLM 定位。
  • 代理执行:通过内置 call_tool 代理工具透明执行底层业务工具,支持上下文传导。

4.2 应用示例

ToolGatewayTalent toolGateway = new ToolGatewayTalent()
        .dynamicThreshold(8)
        .listThreshold(40)
        .searchThreshold(100);

// 添加工具(支持按分组注册)
toolGateway.addTool("财务工具", financeToolProvider);
toolGateway.addTool("HR工具", hrToolProvider);
toolGateway.addTool("常规工具", singleFunctionTool);

// 构建智能体
ReActAgent agent = ReActAgent.of(LlmUtil.getChatModel())
        .role("企业业务助手")
        .defaultTalentAdd(toolGateway)
        .build();

4.3 内置工具说明

工具名可用模式功能说明
call_toolSUMMARY/LIST/SEARCH代理执行指定的业务工具,传入 tool_nametool_args
get_tool_detailSUMMARY/LIST/SEARCH获取指定工具的完整参数 Schema(含 JSON Schema 定义)
search_toolsLIST/SEARCH通过多关键词(空格分隔,AND 逻辑)搜索匹配的工具名和描述

注意:FULL 模式下,原始业务工具直接暴露给 LLM,不经过代理。

5、McpGatewayTalent — 管理多 MCP 服务端

5.1 核心特性

  • 多服务管理:按配置名(如 "weather""database")管理多个 MCP 服务端连接,支持动态添加与移除。
  • 工具级开放控制:通过 McpServerParametersallowedTools(白名单,空表示全部)/ disallowedTools(黑名单,空表示不禁)声明式筛选每个 MCP 服务端实际暴露哪些工具——所以它不是只能整条连接「全开全关」,同样能精确到单个 MCP Tool 的开放控制。变更名单后调用 refreshMcpServer() 生效。
  • 影子交换策略:刷新工具列表时采用"先加新、再删旧"的原子替换,避免调用中的线程因工具短暂丢失而失败。
  • 生命周期管理:移除服务时自动关闭底层连接;禁用服务仅从工具索引移除,保留 Provider 不关闭连接。
  • 按需依赖:MCP 功能依赖 solon-ai-mcp 模块,如果项目不使用 MCP,可排除该依赖。

5.2 应用示例

McpGatewayTalent mcpGateway = new McpGatewayTalent()
        .dynamicThreshold(8)
        .listThreshold(40)
        .searchThreshold(100);

// 方式 1:通过 McpServerParameters 添加
mcpGateway.addMcpServer("weather", new McpServerParameters().then(e->{
            e.setTransport("stdio");
            e.setCommand("npx");
            e.addArgVar("-y");
            e.addArgVar("@modelcontextprotocol/server-weather");
        }));
        
// 方式 1+:接入时做工具级开放控制(只暴露该服务的部分工具)
mcpGateway.addMcpServer("database",new McpServerParameters().then(e-> {
            e.setTransport("stdio");
            e.setCommand("npx");
            e.setArgs(Arrays.asList("-y", "@modelcontextprotocol/server-database"));
            e.setAllowedTools(Arrays.asList("query", "list_tables"));
            e.setDisallowedTools(Arrays.asList("drop_table", "execute_raw"));
        }));

// 方式 2:通过 McpClientProvider 添加
McpClientProvider provider = McpClientProviders.fromMcpServer(params);
mcpGateway.addMcpServer("database", provider);

// 运行时管理
mcpGateway.removeMcpServer("weather");       // 移除并关闭连接
mcpGateway.refreshMcpServer("database");      // 刷新工具列表(权限变更后)
mcpGateway.refreshMcpServerAll();             // 刷新所有 MCP 服务

// 查询
Set<String> serverNames = mcpGateway.getMcpServerNames();
boolean exists = mcpGateway.hasMcpServer("database");

5.3 内置工具说明

与 ToolGatewayTalent 使用相同的工具名称和逻辑:

工具名可用模式功能说明
call_toolSUMMARY/LIST/SEARCH代理执行指定的 MCP 工具,传入 tool_nametool_args,支持上下文传导
get_tool_detailSUMMARY/LIST/SEARCH获取指定 MCP 工具的完整参数 Schema
search_toolsLIST/SEARCH通过关键词搜索匹配的 MCP 工具

6、OpenAPI 解析器详解

6.1 解析器架构

ApiResolver(接口)
  └── OpenApiResolver(自适应路由,自动判断 v2/v3)
        ├── OpenApiV2Resolver(Swagger 2.0,基于 swagger-parser 1.x)
        └── OpenApiV3Resolver(OpenAPI 3.0,基于 swagger-parser 2.x)

6.2 解析能力矩阵

能力Swagger 2.0OpenAPI 3.0说明
Path 参数解析自动识别为必填,Schema 带完整类型定义
Query 参数解析支持枚举(enum)、required 标记
Header 参数解析独立的 headerSchema 输出
Body 参数解析V2 通过 BodyParameter/definitions;V3 通过 RequestBody/content
FormData 解析自动识别为 Multipart
RequestBody 解析根据 Content-Type 自动识别 JSON/Multipart
$ref 引用展开递归解析 components/schemas 和 definitions
循环引用保护输出 _Circular_Reference_ 标记,防止无限递归
数组类型展开Array 内部 items 引用深度平铺
Response 解析优先 200,回退 201/default
BaseUrl 提取V2 从 host+schemes+basePath;V3 从 servers 节点(支持相对路径补全)
Deprecated 过滤标记为废弃的接口自动跳过,不注册到工具表
分组(Tags)按 OpenAPI 的 tags 字段自动分组,首个 tag 作为 category

6.3 自定义解析器

可通过 resolver() 方法替换默认解析器(实现 ApiResolver 接口即可):

apiTalent.resolver(new MyCustomApiResolver());

7、通用配置参数

以下参数三个网关 Talent 共享(方法名一致,仅阈值默认值略有差异):

配置方法默认值说明
dynamicThreshold(n)8全量平铺模式的上限
listThreshold(n)OpenAPI: 30,其他: 40摘要模式的上限
searchThreshold(n)100名字列表模式的上限
retryConfig(maxRetries)3失败重试次数
retryConfig(maxRetries, retryDelayMs)3, 1000失败重试次数 + 初始延迟(仅 McpGatewayTalent 支持延迟参数)
maxContextLength(n)8000响应截断长度(仅 OpenApiGatewayTalent)

8、注意事项

  • 接口唯一性:不同数据源加载的接口/工具,其名称(OperationId)不能重复。网关内部统一转为小写存储,调用时大小写不敏感。
  • 路径占位符:确保 Swagger 定义中的路径参数使用 {name} 格式,网关会自动完成 URLEncoder 编码替换。如果调用时路径中仍存在 {xxx},网关会返回明确的错误提示。
  • 过时接口:标记为 @Deprecated 的接口会被自动忽略,不进入工具表。
  • 禁用源ApiSource.setEnabled(false)McpClientProvider.setEnabled(false) 的源仅注册到管理表,不加入工具索引。可通过 setEnabled(true) + refreshApi()/refreshMcpServer() 重新激活。
  • 权限变更刷新:在 ApiSourceClient 副本上修改 allowedTools/disallowedTools 后,需调用 refreshApi() 才能生效。
  • Maven 依赖:MCP 功能依赖 solon-ai-mcp;OpenAPI 解析依赖 swagger-parser(v1 和 v3 两个版本),如果不需要可排除。