---
title: "talents - Gateway 三件套：OpenApi / Tool / MCP"
---

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

相关依赖包： [solon-ai-talent-gateway](/article/1364)


### 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` 在接入每条连接时，可通过 `McpServerParameters` 的 `allowedTools`（白名单，空表示全部）/ `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 应用示例

```java
// 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_detail` | SUMMARY/LIST/SEARCH | 获取指定接口的完整参数 Schema（Header、Path、Query、Body）及返回值结构 |
| `search_apis` | LIST/SEARCH | 通过多关键词（空格分隔，AND 逻辑匹配）在海量 API 库中模糊搜索接口，返回分组、描述及 Endpoint |

#### 3.4 内置认证策略

`ApiAuthenticator` 是一个函数式接口，支持灵活的认证扩展：

```java
// 方式 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` 维护独立的权限副本：

```java
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 应用示例

```java
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_tool` | SUMMARY/LIST/SEARCH | 代理执行指定的业务工具，传入 `tool_name` 和 `tool_args` |
| `get_tool_detail` | SUMMARY/LIST/SEARCH | 获取指定工具的完整参数 Schema（含 JSON Schema 定义） |
| `search_tools` | LIST/SEARCH | 通过多关键词（空格分隔，AND 逻辑）搜索匹配的工具名和描述 |

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



### 5、McpGatewayTalent — 管理多 MCP 服务端

#### 5.1 核心特性

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

#### 5.2 应用示例

```java
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_tool` | SUMMARY/LIST/SEARCH | 代理执行指定的 MCP 工具，传入 `tool_name` 和 `tool_args`，支持上下文传导 |
| `get_tool_detail` | SUMMARY/LIST/SEARCH | 获取指定 MCP 工具的完整参数 Schema |
| `search_tools` | LIST/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.0 | OpenAPI 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` 接口即可）：

```java
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 两个版本），如果不需要可排除。