ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

agent-core-java 工具描述对象详解:ToolInfo 与 McpToolInfo 如何支撑大模型函数调用

agent-core-java 工具描述对象详解:ToolInfo 与 McpToolInfo 如何支撑大模型函数调用
  • 人工智能
  • AI Agent
  • Agent 框架
  • 工具调用
  • Agent 工作流
  • RAG
  • MCP Clients
  • 强化学习

【免费下载链接】agent-core-java

openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。

项目地址:https://gitcode.com/openJiuwen/agent-core-java
点击查看免费下载

在 agent-core-java 中,com.openjiuwen.core.foundation.tool.schema包负责定义“把工具描述给大模型看”的核心数据结构:供模型函数调用(Function Calling)消费的ToolInfo,以及在此基础上追加服务端名称的 MCP 扩展类型McpToolInfo。本文基于 schema 包 API 文档 展开,结合 ToolInfo.java、McpToolInfo.java 两个源码文件及其在ToolCard、McpToolCard、AbilityManager中的实际消费链路,帮助读者掌握:这两个 DTO 的完整字段与默认值、JSON Schema 参数的书写方式、Lombok 构建器与 Jackson 序列化细节,以及ToolCard.toolInfo()/McpToolCard.toolInfo()如何把它们构造出来供上层使用。

一、schema 包的定位:模型函数调用的统一描述对象

按 schema.README.md 的定义,com.openjiuwen.core.foundation.tool.schema提供供模型函数调用消费的工具描述对象,以及带服务端名称的 MCP 扩展描述对象。包内只有两个类型:

类型说明
McpToolInfo在ToolInfo基础上补充serverName。
ToolInfo通用工具描述对象,包含类型、名称、描述和参数 Schema。

从源码结构看,这两个类的 Javadoc 都标注了“Follows the OpenAI function calling format”,并且分别镜像 Python 版openjiuwen/core/foundation/tool/schema.py中的ToolInfo与McpToolInfo实现(见 ToolInfo.java 的类注释)。也就是说,ToolInfo的字段设计直接对齐 OpenAI 函数调用协议中tools数组的元素形态:type(固定为function)+function的name/description/parameters。这是智能体把本地函数、MCP 远端工具、工作流或子智能体“注册”给大模型时的统一出口格式。

二、ToolInfo 字段全解析

2.1 字段与默认值

ToolInfo.md 声明其为“工具描述对象,供模型函数调用或上层工具注册流程使用”,源码通过 Lombok 生成访问器与构建器,显式声明字段如下:

字段类型默认值说明
typeString"function"工具类型。
nameString""工具名称。
descriptionString""工具描述。
parametersMap<String, Object>Map.of()参数 JSON Schema。

对照 ToolInfo.java 的源码,每个字段上的默认值都通过@Builder.Default显式声明,这正是上表“默认值”列的来源。类上的注解组合值得注意:

@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) public class ToolInfo { @Builder.Default private String type = "function"; // name / description / parameters 同理 }
  • @SuperBuilder而非@Builder:这是为了支持McpToolInfo extends ToolInfo的继承链上也能使用链式构建器(McpToolInfo.builder()...build()可以一路设置父类字段),是ToolInfo可被安全扩展的关键设计。
  • @JsonInclude(JsonInclude.Include.NON_NULL):序列化时丢弃null字段。这对McpToolInfo.serverName为null的场景很关键——序列化结果不会多出无意义的"server_name": null。
  • Javadoc 中标注@since 0.1.7,说明ToolInfo与parameters字段自 0.1.7 版本引入,属于工具子系统的基础设施。

2.2 parameters:一份标准 JSON Schema

parameters的类型是Map<String, Object>,遵循 JSON Schema 格式。ToolInfo.java 的 Javadoc 给出的最简示例为:

{"type": "object", "properties": {"query": {"type": "string"}}}

一个更贴近实战、带required约束的完整写法,可直接参考 ToolCardTest.java 中的测试数据:

Map<String, Object> inputParams = Map.of("type", "object", "properties", Map.of("a", Map.of("description", "first arg", "type", "integer"), "b", Map.of("description", "second arg", "type", "integer")), "required", new String[]{"a", "b"});

ToolCardTest中还专门用一个“复杂嵌套参数”用例(ToolCardTest.java)验证了parameters支持任意深度的 JSON Schema 结构——type、string、array、items、number、default等键值都能无损承载:

ToolInfo info = ToolInfo.builder().name("summarize").description("汇总商品信息").parameters(parameters).build(); // parameters 中包含 array 类型的 products 字段,其 items 为嵌套 object schema

这说明ToolInfo本身不做 Schema 校验,只是透明地传递描述,真正的约束语义由模型侧遵循 JSON Schema 解析。另外,ToolCardTest.java 的 equality 用例表明,两个字段完全一致的ToolInfo判定为相等(Lombok@Data生成的值比较),可用于工具注册流程中的“等价声明复用检查”。

三、McpToolInfo:只追加一个 serverName 的 MCP 扩展

McpToolInfo.md 指出,McpToolInfo继承自ToolInfo,是“在ToolInfo的基础上追加服务端名称字段”的 MCP 工具描述对象。显式声明字段只有一项:

字段类型默认值说明
serverNameStringnullMCP 服务端名称,对应序列化键server_name。

源码印证见 McpToolInfo.java:

@Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = true) @JsonInclude(JsonInclude.Include.NON_NULL) public class McpToolInfo extends ToolInfo { /** The MCP server name this tool belongs to. */ @JsonProperty("server_name") private String serverName; }

三个细节与文档一一对应:

  1. 序列化键是server_name而非serverName:字段上的@JsonProperty("server_name")决定了 JSON 输出中该字段使用 snake_case 键名,这与 MCP 生态的命名习惯保持一致。消费方按server_name解析即可正确区分工具来自哪个 MCP 服务端。
  2. @EqualsAndHashCode(callSuper = true):与父类不同,McpToolInfo显式启用了包含父类字段的相等性比较——两个McpToolInfo相等当且仅当type/name/description/parameters和serverName全部相等,避免继承导致的比较盲区。
  3. 默认值为null:serverName未设值时保持null,配合@JsonInclude(NON_NULL),序列化时直接省略该键。

四、构造入口:ToolCard.toolInfo() 与 McpToolCard.toolInfo()

schema.README.md 的关键结论是:ToolCard.toolInfo()与McpToolCard.toolInfo()都会构造本包中的 DTO 供上层使用。二者的实现分别位于:

ToolCard.java:

@Override public ToolInfo toolInfo() { return ToolInfo.builder() .name(getName()) .description(getDescription()) .parameters(inputParams != null ? inputParams : Map.of()) .build(); }

McpToolCard.java:

@Override public McpToolInfo toolInfo() { return McpToolInfo.builder() .name(getName()) .description(getDescription()) .parameters(getInputParams()) .serverName(serverName) .build(); }

两者差异一目了然:McpToolCard.toolInfo()利用@SuperBuilder继承的构建器额外写入serverName,返回类型收窄为McpToolInfo。同时二者都不显式设置type,因此产出对象走@Builder.Default的"function"默认值——这正是 schema 文档中“ToolInfo.type默认值为function”这一条在使用链路上的体现。

ToolInfo.md还记录了一条使用说明:ToolCardTest验证了“无参 builder 默认会产生type=function、空名称、空描述和空参数表”。对应的断言在 ToolCardTest.java:

ToolInfo info = ToolInfo.builder().build(); assertEquals("function", info.getType()); assertEquals("", info.getName()); assertEquals("", info.getDescription()); assertNotNull(info.getParameters()); assertTrue(info.getParameters().isEmpty());

而同文件 testToolInfoFromCard 用例则验证了卡片到描述对象的映射:卡片名local_sub、描述local function for sub、带required的inputParams会被原样搬运到ToolInfo的name/description/parameters中。参数表中列出的相关测试ToolCardTest、LocalFunctionTest.java 均位于core/src/test/java/com/openjiuwen/core/foundation/tool/下,后者还验证了基于ToolCard.inputParams(即最终会进入ToolInfo.parameters的那份 JSON Schema)按default值格式化调用入参的行为,是 Schema 语义实际生效的佐证。

五、下游消费:AbilityManager 如何批量产出 ToolInfo

ToolInfo不只是卡片方法的返回值,也是智能体注册工具时的统一出口。从源码结构看,AbilityManager.java 的listToolInfo(...)会把本地工具、工作流、子智能体和 MCP 工具分别转换为ToolInfo列表(经toolInfo(card)、workflowToolInfo(card)、agentToolInfo(card)、appendMcpToolInfos(...)四个转换入口),再按名称去重后返回。

其中 appendMcpToolInfos 展示了 MCP 场景下ToolInfo的实际拼装方式:MCP 工具名会被重写为mcp_{serverName}_{originalName}前缀形式以在多服务端共存时保持唯一,描述对象则用 builder 逐项填充:

ToolInfo emittedTool = ToolInfo.builder() .type(Objects.toString(mcpTool.getType(), "function")) .name(mcpToolName) .description(Objects.toString(mcpTool.getDescription(), "")) .parameters(parameters) .build();

这里Objects.toString(mcpTool.getType(), "function")的兜底逻辑再次印证了type缺省即"function"的约定。此外 ExternalTool.java 中外部工具也是直接委托card.toolInfo()产出ToolInfo,可见该 DTO 是“卡片(Card)→ 模型描述(Info)”这条注册管线的公共末端。

六、小结与实践建议

  • ToolInfo是 4 字段(type/name/description/parameters)的轻量 DTO,字段默认值为function、""、""、Map.of(),parameters承载任意复杂度的 JSON Schema。
  • McpToolInfo仅追加serverName(序列化键server_name),用于区分工具所属 MCP 服务端,且启用父类参与的值比较。
  • 构建对象统一走@SuperBuilder构建器;最常见的生产路径是ToolCard.toolInfo()与McpToolCard.toolInfo(),也可在AbilityManager等上层逻辑中按需手工组装。
  • 序列化时null字段自动省略,跨语言(Java 与 Python 版 openjiuwen)字段语义一致,可直接对接遵循 OpenAI 函数调用格式的大模型。

如需继续深入,可参考同目录的 ToolCard.md、mcp 包文档(其中说明McpTool.invoke(...)先按inputParams格式化输入再调用远端,正是ToolInfo.parameters的消费端),以及测试文件 ToolCardTest.java 获取完整的断言级行为依据。

  • 人工智能
  • AI Agent
  • Agent 框架
  • 工具调用
  • Agent 工作流
  • RAG
  • MCP Clients
  • 强化学习

【免费下载链接】agent-core-java

openJiuwen agent core Java是 openJiuwen Core的 Java版本,提供AI Agent开发、运行、调优与演进相关的全套SDK能力。

项目地址:https://gitcode.com/openJiuwen/agent-core-java
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进