跳到主要内容

Plugin Packages

AI4J 的 plugin package 解决的是:第三方开发者把工具、命令、Skill、Prompt、Guardrail 等运行时资源打包成一个普通 Java 依赖,使用者通过 classpath 引入后再检查、启用、授权和暴露

它不是应用商店,也不是远程下载安装器。当前稳定路径是 Maven / Gradle 依赖 + ServiceLoader 发现 + ExtensionRegistry 安全门禁。

1. 它和 provider extension 不是一回事

AI4J 现在有两类容易混淆的扩展:

类型解决什么接入方式当前状态
Provider / model / service extension把新平台、新模型字段或新顶层服务接进核心 SDK修改核心工厂、配置和 starter 主链显式代码接线
Plugin package把工具、命令、Skill、Prompt、Guardrail 等资源交给 runtime 使用第三方 jar + ServiceLoader + 显式 enable/expose独立扩展 API

如果你要新增一个模型平台,仍然看 Provider Extension。 如果你要给 agent 或 coding agent 增加一组可复用工具、提示词或规则,才看这一页。

2. 使用者路径

普通 Java 使用者的完整路径分四步。

2.1 引入插件依赖

插件包就是普通 jar。使用 Maven 时,把插件加入应用依赖即可:

<dependency>
<groupId>com.example</groupId>
<artifactId>weather-ai4j-plugin</artifactId>
<version>1.0.0</version>
</dependency>

AI4J 不会自动远程拉取插件,也不会把插件写进你的项目依赖。依赖由你的构建系统管理。

2.2 发现并启用插件

ExtensionRegistry registry = ExtensionRegistry.discover()
.enable("weather-pack");

discover() 只负责从 classpath 发现实现。发现不等于启用。

enable(...) 是对这个插件包的运行时资源做整包信任:它会调用插件 apply(...) 注册 command、Skill、Prompt、Guardrail 和 tool 定义。为了兼容旧代码,默认模式下 command、Skill、Prompt 和 Guardrail 会随插件启用进入运行时;tool 仍然必须再经过 exposeTool(...) 才会给模型。

如果你要接入第三方插件,建议启用显式资源授权模式:

ExtensionRegistry registry = ExtensionRegistry.discover()
.enable("weather-pack")
.requireExplicitResourceActivation()
.allowCommand("weather.status")
.allowSkill("weather-skill")
.allowPrompt("weather-summary")
.allowGuardrail("weather-policy");

开启 requireExplicitResourceActivation() 后,未列入 allowlist 的 command、Skill、Prompt 和 Guardrail 不会进入 ExtensionRuntimeSnapshot。配置了不存在的资源名时,snapshot() 会 fail-fast,避免宿主以为已经授权成功。

2.3 显式暴露工具

ExtensionRegistry registry = ExtensionRegistry.discover()
.enable("weather-pack")
.exposeTool("weather.search");

启用也不等于把工具交给模型。只有 exposeTool(...) 后,工具才会进入 agent tool registry。

exposeTool(...)allowCommand(...) 不是一回事:

API影响范围
exposeTool("weather.search")让指定 tool 进入模型可见工具列表
allowCommand("weather.status")允许人工 / 宿主显式执行插件 command
allowSkill("weather-skill")允许 Skill 被读取或投影到 Coding Agent 上下文
allowPrompt("weather-summary")允许 Prompt 被读取或投影到 Coding Agent 上下文
allowGuardrail("weather-policy")允许 Guardrail 接入 tool execution 前置判断

2.4 Spring Boot 配置路径

Spring Boot 项目可以用配置完成同一件事:

ai:
extensions:
enabled:
- weather-pack
tools:
expose:
- weather.search

如果要启用显式资源授权:

ai:
extensions:
enabled:
- weather-pack
explicit-resource-activation: true
tools:
expose:
- weather.search
commands:
allow:
- weather.status
skills:
allow:
- weather-skill
prompts:
allow:
- weather-summary
guardrails:
allow:
- weather-policy

starter 会自动创建两个 bean:

Bean作用
ExtensionRegistry保存 classpath 发现、显式启用、资源授权和工具 allowlist 状态
ExtensionRuntimeSnapshot保存已启用 / 已授权资源和已暴露工具的只读快照

如果配置了不存在的插件包,或者只配置 tools.expose / commands.allow / skills.allow / prompts.allow / guardrails.allow 却没有启用贡献该资源的插件包,应用启动会失败。这是刻意设计的安全边界:Spring Boot 配置也不能绕过 discover / enable / allow / expose 门禁。

starter 不会自动创建 Agent 或 Coding Agent。需要 Agent 时,仍然把 ExtensionRegistry 传给 Agent builder:

@Bean
public Agent agent(ModelClient modelClient, ExtensionRegistry extensionRegistry) {
return Agents.react()
.modelClient(modelClient)
.model("glm-4.5-flash")
.extensions(extensionRegistry)
.build();
}

2.5 CLI 检查路径

CLI 可以先查看 classpath 上的插件:

ai4j-cli extension list
ai4j-cli extension inspect weather-pack --runtime
ai4j-cli extension validate weather-pack
ai4j-cli extension plan weather-pack --enable \
--expose-tool weather.search \
--allow-command weather.status \
--allow-skill weather-skill \
--allow-prompt weather-summary \
--allow-guardrail weather-policy \
--strict
ai4j-cli extension check weather-pack --enable \
--expose-tool weather.search \
--allow-command weather.status \
--allow-skill weather-skill \
--allow-prompt weather-summary \
--allow-guardrail weather-policy \
--strict

plan 用来预览某个插件在当前授权参数下的激活状态。它会列出每个 tool、command、Skill、Prompt、Guardrail 是 active 还是 inactive,并给出原因,例如 not exposednot allowednot registered by extension。它适合放在“依赖已经加入 classpath,但还没接入 Agent”之前做人工检查。

validate 会像 inspect --runtime 一样临时调用插件 apply(...) 做 runtime inspection,并把 manifest、capability 声明、工具 schema、Skill / Prompt classpath 资源和 apply(...) 失败情况整理成校验报告。它只报告问题,不会把工具暴露给模型,也不会执行插件 command。

check 是可脚本化门禁。它会先执行 validation;validation 有 error 时直接返回非零,不再继续 activation plan。validation 通过后,它会启用插件并套用本次 --expose-tool / --allow-* / --strict 参数,只要显式请求的资源没有进入 active 状态就返回非零。没有被请求的插件资源不会导致失败,这样使用者仍然可以保留最小授权 recipe。

因此插件作者要把 apply(...) 写成轻量注册函数:只注册 spec、executor、classpath resource 和 guardrail,不要在 apply(...) 里连接远程服务、发起网络请求、写文件、读取用户密钥或执行长耗时初始化。真实副作用应该放到 tool executor、command handler 或宿主显式初始化流程里。

如果要检查当前 classpath 上所有插件:

ai4j-cli extension validate --all

返回值语义:

结果含义
status=pass没有发现 error 或 warning
status=warn没有阻断性错误,但存在建议修正项,例如缺少 manifest vendor 或 command usage
status=fail存在会影响接入的错误,例如 tool schema 不可用、资源不存在或 apply(...) 失败

有 error 时 CLI 返回非零退出码。插件作者可以把它放进插件项目的本地测试或 CI;使用者也可以在引入第三方 jar 后先校验,再决定是否在宿主应用里启用。

2.6 CLI 命令执行路径

如果插件声明了 command,可以显式启用插件后执行:

ai4j-cli extension run --enable weather-pack --allow-command weather.status weather.status beijing

--enable 是必填项。--allow-command 会让本次命令进入显式 command 授权模式;没有 --allow-command 时,CLI 保持兼容行为:启用插件后可执行它注册的 command。classpath 发现插件不会自动执行命令,也不会把工具暴露给模型。extension run 是人手动调用插件 command 的 CLI 入口;Agent / Coding Agent 的模型可见工具仍然只走 .exposeTool(...) 或 Spring Boot ai.extensions.tools.expose

2.7 CLI 资源读取路径

插件声明的 Skill / Prompt 是 classpath 资源。开发者可以先用 inspect --runtime 查看资源名和路径,再显式启用插件读取内容:

ai4j-cli extension resource --enable weather-pack --allow-skill weather-skill skill weather-skill
ai4j-cli extension resource --enable weather-pack --allow-prompt weather-summary prompt weather-summary

--allow-skill / --allow-prompt 会让本次资源读取进入显式资源授权模式;没有 allow 参数时,CLI 保持兼容行为:启用插件后可读取它注册的 Skill / Prompt。这个命令只打印 UTF-8 文本资源,不会执行插件工具,也不会把工具暴露给模型。它的主要用途是让插件作者和使用者确认 jar 内资源是否可被 AI4J 正确读取。

3. 接入 Agent

插件工具可以直接进入通用 Agent loop:

Agent agent = Agents.react()
.modelClient(modelClient)
.model("glm-4.5-flash")
.extensions(registry)
.build();

运行时会做两件事:

  • 把已暴露的 ExtensionToolSpec 转成 AI4J 现有的 Tool
  • 把已暴露的 ExtensionToolExecutor 路由到现有 ToolExecutor

Agent 主循环不用认识插件实现类。模型看到的是普通 tool schema,调用时走同一套 tool result 回传流程。

3.1 Guardrail 执行点

默认兼容模式下,已启用插件注册的 Guardrail 会在 Agent 执行 tool call 之前评估。如果 registry 开启了 requireExplicitResourceActivation(),只有 allowGuardrail(...) 列出的 Guardrail 会进入执行链。AI4J 当前给插件 Guardrail 的请求语义是:

字段
actiontool.execute
targettool name,例如 weather.searchbashread_file
attributes.toolNametarget
attributes.arguments模型给出的原始 tool arguments 字符串
attributes.callId当前 tool call id
attributes.type当前 tool call type,存在时传入

如果任意 Guardrail 返回 GuardrailDecision.deny("reason"),AI4J 不会调用后续 tool executor,而是把拒绝原因作为普通 TOOL_ERROR 回写给 Agent loop。这样插件既可以约束自己暴露的 extension tools,也可以约束宿主已经开放给 Agent 的其他工具。

4. 接入 Coding Agent

Coding Agent 也使用同一个入口:

CodingAgent agent = CodingAgents.builder()
.modelClient(modelClient)
.model("glm-4.5-flash")
.workspaceContext(workspaceContext)
.extensions(registry)
.build();

插件工具会和内置 workspace 工具一起进入 coding session:

  • read_file
  • write_file
  • apply_patch
  • bash
  • 已暴露的 extension tools
  • 已配置的 delegate / subagent tools

这意味着插件作者可以提供“项目扫描”“代码生成辅助”“业务规则检查”等工具,但执行权限仍然由宿主应用决定。插件不会绕过 Coding Agent 原有的 workspace、tool policy、approval 和执行边界。

已授权插件注册的 Guardrail 也会覆盖 Coding Agent 的 tool execution。它不仅能拦截已暴露的 extension tools,也能拦截内置 workspace tools,例如 bashread_filewrite_fileapply_patch,前提是宿主已经把这些工具交给当前 Coding Agent 会话。Guardrail 的判断发生在实际工具执行前;被拒绝的调用不会触发 shell、文件写入或 extension tool executor。

插件 Skill / Prompt 也会进入 Coding Agent 的上下文装配:

  • 默认兼容模式下,已启用插件贡献的 Skill / Prompt 会被物化成只读文件;显式资源授权模式下,只有 allowSkill(...) / allowPrompt(...) 列出的资源会被物化。
  • Skill 会进入 <available_skills> 清单;Prompt 会进入 <available_prompts> 清单。
  • Agent 不会在系统提示里直接塞入完整资源正文,而是先看到资源名、描述和可读路径,再按任务需要用 read_file 读取。
  • 这些物化文件只加入 allowedReadRoots,不会扩大 workspace 写入权限。

这和本地 / 全局 .ai4j/skills 的使用方式一致:资源是给 agent 按需读取的工作流和模板,不是安装后自动执行的代码。

5. 开发者路径

第三方插件至少包含三个部分。

如果你还没有项目骨架,可以先用 CLI 生成一个最小 Maven 项目:

ai4j-cli extension init weather-ai4j-plugin \
--id weather-pack \
--package com.example.ai4j.weather \
--name "Weather Pack"

如果你是使用者,建议接着看 Plugin Recipes,那里把 Java、Spring Boot、CLI 和多插件组合写成可复制接入路径。如果你是第三方插件作者,建议完整走一遍 Plugin Author Cookbook。那里按 scaffold、替换业务逻辑、校验、发布说明和常见错误组织,比本页更适合作为动手流程。

这个命令只写入一个不存在或空的本地目录。它不会把插件依赖安装到宿主应用,不会拉取远程插件,也不会启用插件。生成后目录结构类似:

weather-ai4j-plugin/
pom.xml
README.md
src/main/java/com/example/ai4j/weather/WeatherPackExtension.java
src/main/resources/META-INF/services/io.github.lnyocly.ai4j.extension.Ai4jExtension
src/main/resources/skills/weather-pack/SKILL.md
src/main/resources/prompts/weather-pack-summary.md
src/test/java/com/example/ai4j/weather/WeatherPackExtensionTest.java

本地验证:

cd weather-ai4j-plugin
mvn test

生成的测试会调用 ExtensionValidator,先证明 manifest、runtime 贡献、Skill / Prompt classpath 资源和 schema contract 能被 AI4J 稳定读取。插件作者再把示例 Tool / Command / Skill / Prompt / Guardrail 替换成真实业务逻辑。

可选参数:

参数作用默认值
--group-idMaven groupId--package
--artifact-idMaven artifactId--id
--versionMaven 和 manifest 版本1.0.0
--class-nameAi4jExtension 实现类名--id 派生
--vendormanifest vendorexample

5.1 实现 Ai4jExtension

public final class WeatherExtension implements Ai4jExtension {
public ExtensionManifest manifest() {
return ExtensionManifest.builder()
.id("weather-pack")
.name("Weather Pack")
.capability(ExtensionCapability.TOOL)
.build();
}

public void apply(ExtensionContext context) {
context.tools().register(
ExtensionToolSpec.builder()
.name("weather.search")
.description("Search weather by city")
.inputSchema("{\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\"}},\"required\":[\"city\"]}")
.build(),
new ExtensionToolExecutor() {
public String execute(ExtensionToolCall call) {
return "weather result";
}
}
);
}
}

5.2 注册 ServiceLoader

在插件 jar 中加入:

META-INF/services/io.github.lnyocly.ai4j.extension.Ai4jExtension

文件内容写实现类全名:

com.example.ai4j.weather.WeatherExtension

5.3 给工具写清楚输入 schema

ExtensionToolSpec.inputSchema(...) 使用 JSON Schema 的核心字段:

  • type
  • properties
  • required
  • description
  • enum
  • items

AI4J 会把这些字段映射成现有 OpenAI-compatible tool schema。不要把大段自然语言塞进 description 代替结构化参数。

Validator 会做最小结构检查:

  • schema 必须是合法 JSON object。
  • type 必须是非空字符串,当前要求为 object
  • properties 如果存在,必须是 object;每个 property value 也必须是 object。
  • requiredenum 如果存在,必须是只包含非空字符串的 array。
  • items 如果存在,必须是 object。

这不是完整 JSON Schema 引擎,但足够提前拦住 AI4J 当前 tool mapper 无法稳定消费的 schema。

5.4 打包 Skill / Prompt 资源

插件可以把 Skill 和 Prompt 放在 src/main/resources 下,再在 apply(...) 中注册资源路径:

public void apply(ExtensionContext context) {
context.skills().register(ExtensionSkillResource.builder()
.name("weather-skill")
.description("Weather workflow")
.resourcePath("skills/weather/SKILL.md")
.build());

context.prompts().register(ExtensionPromptResource.builder()
.name("weather-summary")
.description("Weather summary prompt")
.resourcePath("prompts/weather-summary.md")
.build());
}

对应 jar 结构:

src/main/resources/
skills/weather/SKILL.md
prompts/weather-summary.md

资源路径默认按 classpath 查找,也可以写成 classpath:skills/weather/SKILL.md。资源路径不能包含 ..,避免插件把 resource contract 伪装成任意文件读取。

5.5 写插件本地校验

插件作者可以直接在测试里调用公共 validator,不必依赖 CLI 文本输出:

ExtensionRegistry registry = ExtensionRegistry.of(new WeatherExtension());
ExtensionValidationReport report = ExtensionValidator.validate(registry, "weather-pack");

if (!report.isValid()) {
throw new IllegalStateException("extension validation failed: " + report.getIssues());
}

这套校验关注“插件包是否能被 AI4J 稳定消费”,不是第三方代码安全审计。它会检查:

  • manifest 是否有 id / capability,并建议补齐 name、version、vendor
  • 声明的 capability 是否真的贡献了对应资源
  • tool 是否有基本可用的 input schema
  • command 是否有描述和 usage
  • Skill / Prompt 的 classpath 资源是否存在
  • apply(...) 在 runtime inspection 中是否失败

它会调用插件 apply(...) 收集运行时贡献,但不会执行插件 command,不会把 tool 暴露给模型,也不会替宿主判断第三方插件是否可信。

6. 安全门禁

插件生态的默认语义是三段式门禁:

阶段会发生什么不会发生什么
discover从 classpath 找到插件 manifest不执行工具,不暴露给模型
enable调用插件 apply(...) 注册资源工具仍不会进入模型可见列表
allowCommand / allowSkill / allowPrompt / allowGuardrail在显式资源授权模式下允许非 tool 资源进入运行态不会让 tool 进入模型可见列表
exposeTool指定工具名进入 agent/coding tool registry只暴露被点名的工具

这个设计故意不做“安装后自动可用”。原因很直接:tool 一旦暴露给模型,就可能触发网络、文件系统、业务系统或工作区操作。AI4J 要求宿主应用明确决定哪些工具能进入模型上下文。

为了兼容旧代码,enable(...) 默认仍会激活 command、Skill、Prompt 和 Guardrail。需要更严格边界时,调用 requireExplicitResourceActivation(),或在 Spring Boot 中设置 ai.extensions.explicit-resource-activation=true。开启后,非 tool 资源必须通过对应 allow* API 或配置项逐项进入运行态。

CLI 的 extension runextension resource 是人手动触发的命令 / 资源读取路径,不属于 Agent tool loop,因此当前不走 tool.execute Guardrail。它们可以通过 --allow-command--allow-skill--allow-prompt 使用同一套显式资源授权语义。

7. 命名建议

插件 ID 和工具名应该稳定、可读、可冲突排查:

weather-pack
weather.search
repo.scan
ticket.create
guardrail.prompt-policy

公共 ID / name 的硬性规则是:必须以英文字母或数字开头,只能包含英文字母、数字、点、下划线和连字符。这个规则适用于 extension id、tool name、command name、Skill name、Prompt name 和 Guardrail name。

Command name 本身不要带 //weather-check <city> 这种写法只放在 usage 文本里。CLI 为了兼容人工输入,会接受 ai4j-cli extension run --enable weather-pack /weather-check beijing,内部会去掉开头的 / 后再按 command name 查找。

Classpath resource path 不是公共 name,仍然使用路径语义,例如 skills/weather/SKILL.md。路径可以带 /,但不能包含 ..

避免使用过宽的名字:

search
run
create
check

工具名进入模型上下文后,也会进入执行路由。名字过宽会让调用意图和冲突排查都变困难。

8. 官方样板插件

AI4J 当前提供一个官方样板插件:

ArtifactExtension id能力文档
ai4j-plugin-ask-userask-usertool + command + Skill + PromptAsk User Plugin

它的作用不是替代第三方插件,而是给插件作者一个可编译、可测试、可通过 ServiceLoader 发现的参考模块。它展示的重点是:

  • 官方插件也只是普通 Maven jar。
  • 插件启用后不自动把工具暴露给模型。
  • tool / command 可以返回宿主可识别的结构化 envelope。
  • Skill / Prompt 可以随 jar 分发,再由 Agent / Coding Agent 按需读取。

9. 发布建议

插件包发布时至少给出:

  • Maven / Gradle 坐标
  • 支持的 AI4J 版本范围
  • manifest id
  • 注册的 tools / commands / skills / prompts / guardrails 清单
  • 每个 tool 的输入 schema
  • 是否触发网络、文件系统、数据库或外部 API
  • 所需环境变量名,不要要求用户把密钥写进代码
  • 本地 smoke test 命令,例如 ai4j-cli extension validate <extension-id>ai4j-cli extension check <extension-id> --enable ... --strict

AI4J 当前不维护远程插件市场。推荐做法是让插件作者用自己的包管理、README 和版本策略维护插件。

10. 当前边界

当前已经可用:

  • ai4j-extension-api 定义 manifest、discovery、enable、expose 和 runtime snapshot
  • ai4j-extension-api 提供 ExtensionActivationPlan,并支持 command、Skill、Prompt、Guardrail 的显式 allowlist
  • ai4j-extension-api 会在公共 ID / name 构造时执行格式校验,并在 ExtensionValidator 中检查 tool schema 的基础 JSON 结构
  • ai4j-plugin-ask-user 提供官方样板插件,展示 host-mediated 用户提问 tool / command / Skill / Prompt
  • ai4j-extension-api 提供 ExtensionValidator,插件作者可以复用同一套 validation report 做本地测试
  • CLI 可以 extension list / inspect / plan / validate / check 查看、预览、校验和门禁 classpath 上的插件,也可以 extension run --enable <id> [--allow-command <name>] <command> 显式执行插件 command
  • CLI 可以 extension resource --enable <id> [--allow-skill <name>|--allow-prompt <name>] <skill|prompt> <name> 显式读取插件 Skill / Prompt 资源
  • Agent 可以通过 .extensions(registry) 调用暴露的插件工具,并在 tool execution 前应用已启用插件注册的 Guardrail
  • Coding Agent 可以通过 .extensions(registry) 在 coding session 中调用暴露的插件工具,把已启用插件贡献的 Skill / Prompt 投影成只读可读资源,并在内置 / extension tool execution 前应用 Guardrail
  • Spring Boot starter 可以通过 ai.extensions.enabledai.extensions.tools.exposeai.extensions.{commands,skills,prompts,guardrails}.allow 装配 ExtensionRegistry / ExtensionRuntimeSnapshot

当前不包含:

  • 远程 marketplace
  • CLI 自动安装插件依赖
  • 运行时热加载 jar
  • provider 自动注册

这些能力可以继续演进,但不应该在文档里暗示已经存在。

11. 推荐阅读顺序

  1. Extension 总览
  2. 本页:Plugin Packages
  3. Plugin Recipes
  4. Ask User Plugin
  5. Plugin Author Cookbook
  6. Tools
  7. Agent Tools and Registry
  8. Coding Agent Tools and Approvals