如何使用 GitHub Copilot SDK for Java
Using the GitHub Copilot SDK for Java
GitHub 发布 Copilot SDK for Java,以 Maven 依赖 copilot-sdk-java 1.0.7-preview.1 形式提供,让服务端 Java 代码以编程方式创建 Copilot 智能体会话、注册工具、发送提示词并接收结构化响应。
作者以 SDK 发布方身份给出完整 Jakarta EE 示例,读者可据此了解 Java 服务端如何接入智能体工具调用。
Java 开发者不再需要依赖 Java 框架特定的方法,就能从企业应用中驱动 AI。
虽然 Langchain4j 通过去中介化特定 AI 供应商赋能了开发者,但你仍然依赖于 Langchain4j。而使用 Spring AI 时,当然,你依赖于 Spring 做出的设计选择,甚至依赖于 Spring 本身。
现在,GitHub Copilot SDK for Java 是第一个真正框架无关的从 Java 驱动 AI 的方式。凭借其 BYOK 支持,GitHub Copilot SDK for Java 也是 AI 供应商中立的。
💡 尽管它叫 GitHub Copilot SDK,你可以通过传入一个带有你自己的 baseUrl + apiKey(或 bearer token)的 provider/ProviderConfig,将其与任何直接的模型提供商一起使用,例如 OpenAI、Azure、Anthropic 或 OpenAI 兼容端点。无需 Copilot 订阅。 |
GitHub Copilot SDK for Java 是一个客户端库,它赋能你的服务端 Java 代码以编程方式创建 Copilot 代理会话、注册工具、发送提示并接收结构化响应。它适用于服务器环境,包括 Jakarta EE 和 Spring。如果你已经构建企业级 Java 有一段时间了,这个 SDK 会让你感到宾至如归:CompletableFuture、注解、lambda、虚拟线程,全都在这里。
这篇文章向你展示如何使用该 SDK,带你走查一个完整的 Jakarta EE 11 示例应用,并为你留下具体的后续步骤,让你自己尝试。我为我的演示选择了 Jakarta EE 11,因为我是该版本的发布协调负责人。我相信开放标准是赋能开发者的最佳方式。有关 Jakarta EE 11 的更多信息,请参阅这篇 InfoQ 文章。
这个示例应用是一个使用 Jakarta EE 11 的代理框架。当然,开发者可以使用他们选择的知名 Java 框架和库来构建自己的代理框架。
从哪里获取
该 SDK 可作为 Maven 依赖使用:
<dependency>
<groupId>com.github</groupId>
<artifactId>copilot-sdk-java</artifactId>
<version>1.0.7-preview.1</version>
</dependency>先决条件:
- JDK 17 或 25(推荐 25——解锁虚拟线程和其他现代特性)
- Maven 3.9+
- 拥有有效 Copilot 订阅的 GitHub 账户
- 本地安装的 Copilot CLI,版本为 1.0.71 或更高。
走查示例应用
查看 SDK 实际运行的最佳方式是运行这个示例应用。
获取代码
git clone https://github.com/microsoft/Build26-BRK206-your-agent-anywhere-multiclient-multidevice-with-github-copilot-sdk.git
cd Build26-BRK206-your-agent-anywhere-multiclient-multidevice-with-github-copilot-sdk/src/java-agent-orchestrator
mvn clean package liberty:run
# Open http://localhost:9080/index.xhtmlJava 演示基于:
| 关注点 | 技术 |
|---|---|
| 运行时 | Open Liberty 26.0.0.5 |
| 平台 | Jakarta EE 11(Faces 4.1、CDI 4.1、WebSocket 2.2、Data 1.0、Persistence 3.2) |
| UI | PrimeFaces 15.0.16 |
| AI 编排 | Copilot SDK for Java 1.0.7-preview.1 |
| 数据库 | H2 内存数据库(10 条种子房产列表) |
应用做什么
该应用是一个房地产潜在客户管理代理管道。客户提交咨询(“我正在伦敦寻找一套低于 80 万英镑的三居室房子”),系统会在虚拟线程上启动一个隔离的 Copilot Agent,通过管道处理它:

该架构使用 Jakarta WebSocket 将实时状态更新从服务器推送到浏览器,因此你可以观察代理在模型调用工具时逐步推进各个阶段:

同时提交多个咨询,以查看并发的虚拟线程代理在运行。每个代理都使用自己的 Copilot 会话独立处理。


SDK 特性实战
让我们走查示例代码中出现的关键 SDK 特性。
使用 @CopilotTool 定义工具
这是头条 API。如果你曾经在 JAX-RS 中编写过 @GET 端点,或在 @MessageDriven bean 中编写过,这会让你立刻感到熟悉:
@CopilotTool(value = "Sets the current phase of the agent. Use this to report progress.",
name = "set_current_phase")
public String setCurrentPhase(
@CopilotToolParam("The phase to transition to (VALIDATING, SEARCHING, "
+ "WRITING_REPORT, REJECTED_GARBAGE, REJECTED_NO_MATCHES, or DONE)")
String phaseName) {
phase = Phase.valueOf(phaseName.trim().toUpperCase(Locale.ROOT));
notifyUi();
return "Phase set to " + phase.getLabel();
}@CopilotTool 注解将该方法声明为模型可以调用的工具。@CopilotToolParam 注解描述每个参数,以便模型知道要传递什么。SDK 处理所有 JSON Schema 生成、参数解析和分发。你只需编写一个普通的 Java 方法。
@CopilotTool 的两个构建前提条件。 基于注解的工具 API 目前是 SDK 的实验性功能,因此你需要在 Maven 构建中配置两件事:
- 启用实验性 API:将
-Acopilot.experimental.allowed=true传递给编译器。没有此标志,注解处理器将拒绝生成工具元数据。有关实验性 API 的更多详细信息,请参阅 Copilot SDK 文档。 - 注册注解处理器:将 SDK 添加为
annotationProcessorPath,以便编译器能够找到@CopilotTool处理器并在编译时生成$$CopilotToolMeta类。
两者都在 maven-compiler-plugin 中配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
<configuration>
<compilerArgs>
<arg>-Acopilot.experimental.allowed=true</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>com.github</groupId>
<artifactId>copilot-sdk-java</artifactId>
<version>1.0.7-preview.1</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>要从对象注册所有带注解的工具:
List<ToolDefinition> annotatedTools = ToolDefinition.fromObject(this);使用 ToolDefinition.from(...) 的内联 lambda 工具
当你希望在调用点定义工具而不使用专用方法时,请使用 lambda 风格:
ToolDefinition reportIntentTool = ToolDefinition
.from("report_intent",
"Reports the current intent of the agent",
Param.of(String.class, "intent", "Intent in max 4 words"),
(String intent) -> {
currentIntent = intent;
addEvent(Instant.now(), "intent", "Intent updated", intent);
notifyUi();
return "ok";
})
.overridesBuiltInTool(true);注意 .overridesBuiltInTool(true)。这告诉 SDK 我们的 report_intent 工具故意替换同名的内置工具。当你需要为模型已经了解的工具提供自定义行为时,这很有用。
跨类工具扫描
工具不必与你的代理逻辑位于同一个类中。以下是定义在单独的 CDI bean 中的 searchProperties:
@ApplicationScoped
public class PropertyDatabase {
@CopilotTool(value = "Searches the real estate listings database. "
+ "Returns up to 10 matching properties.",
name = "search_properties")
public List<Property> searchProperties(
@CopilotToolParam("Property type substring (e.g. 'flat', 'house')") String type,
@CopilotToolParam("City substring (e.g. 'London', 'Bristol')") String city,
@CopilotToolParam("Minimum number of bedrooms (0 for no minimum)") int minBedrooms,
@CopilotToolParam("Maximum price in GBP (0 for no maximum)") double maxPriceGbp) {
// ... filter and return matching properties ...
}
}你通常会将这些注册到 ToolDefinition.fromObject(propertyDatabase)。在示例应用中,我们改用 lambda 包装器,因为 CDI 客户端代理可能会掩盖注解元数据。
自定义系统消息
SDK 让你能够对系统消息进行细粒度控制。使用 SystemMessageMode.CUSTOMIZE 替换特定部分,同时保留其余部分:
SystemMessageConfig systemMessage = new SystemMessageConfig()
.setMode(SystemMessageMode.CUSTOMIZE)
.setSections(Map.of(SystemMessageSections.IDENTITY,
new SectionOverride()
.setAction(SectionOverrideAction.REPLACE)
.setContent("""
You are part of a real estate recommendation system.
You will receive enquiries from customers, and you must
carry out the following workflow...
""")));文本块("""...""")使多行提示可读,而无需字符串拼接。IDENTITY 部分覆盖仅替换模型的自我描述,同时保持安全护栏完好。如果你更喜欢简单的方法,SystemMessageMode.APPEND 会在默认系统消息之后添加你的内容,而不替换任何内容。
代理循环:sendAndWait(...)
一行代码即可启动完整的代理循环:
session = client.createSession(sessionConfig).get();
// ...
AssistantMessageEvent result = session.sendAndWait(escapedEnquiry).get();在 .get() 背后,模型进行推理、调用你的工具(可能多次),并返回其最终响应。在虚拟线程上,.get() 成本很低。等待期间不会消耗平台线程。SDK 会自动将工具调用分派到你注册的处理器,并将结果反馈给模型,直到完成。
使用 session.on(...) 进行实时事件处理
订阅会话事件以构建响应式 UI:
sessionSubscription = session.on(event -> {
captureSessionEvent(event);
uiUpdateSocket.pushDetailUpdate(id);
});每次工具调用、每个结果、每条助手消息都会触发一个事件。示例应用捕获这些事件并通过 Jakarta WebSocket 推送到浏览器,因此管道仪表板会实时更新。你可以使用模式匹配来处理特定事件类型:
if (event instanceof AssistantMessageEvent msg) {
finalReport = msg.getData().content();
} else if (event instanceof ToolExecutionStartEvent start) {
// Tool is being invoked...
}无头客户端和权限处理
客户端配置为服务器端操作:
copilotClient = new CopilotClient(
new CopilotClientOptions()
.setMode(CopilotClientMode.EMPTY)
.setCopilotHome(copilotHome)
.setExecutor(contextualVirtualThreadExecutor));CopilotClientMode.EMPTY 表示没有 IDE 集成——客户端直接与 Copilot CLI 通信。自定义 Executor(下文讨论)确保工具回调在容器上下文中运行。
对于权限处理,示例使用:
sessionConfig.setOnPermissionRequest(PermissionHandler.APPROVE_ALL);APPROVE_ALL 适用于演示和开发。在生产环境中,请实现真正的权限策略,验证模型允许调用哪些工具。
Jakarta EE 集成模式
SDK 不是框架孤岛。它与 Jakarta EE 自然组合——当然也可以与 Spring 等专有框架组合。
Executor 参数是关键集成点。Jakarta Concurrency(3.1 规范中的 §5.2)要求应用程序创建的线程必须从 ManagedThreadFactory 获取,这样容器才能:
- 跟踪线程以便生命周期关闭(
@PreDestroy/ 服务器停止) - 应用并发约束和策略
- 自动传播上下文(无需手动
contextualRunnable)
Open Liberty 26.x 通过 server.xml 中的 virtual 属性支持虚拟线程 ManagedThreadFactory。
<managedThreadFactory jndiName="concurrent/virtualThreadFactory" virtual="true" />然后,在 AppState.java 中我们注入该工厂:
@Resource(lookup = "concurrent/virtualThreadFactory")
private ManagedThreadFactory virtualThreadFactory;并用它创建我们传递给 Copilot SDK 的 Executor。
// The ManagedThreadFactory (virtual=true) creates container-managed virtual
// threads that automatically propagate CDI, JNDI, and transaction context.
Executor managedVirtualExecutor = runnable ->
virtualThreadFactory.newThread(runnable).start()
String copilotHome = Path.of(System.getProperty("user.home"), ".copilot").toString();
CopilotClientOptions copilotClientOptions = new CopilotClientOptions()
.setMode(CopilotClientMode.EMPTY)
.setCopilotHome(copilotHome)
.setExecutor(managedVirtualExecutor);
copilotClient = new CopilotClient(copilotClientOptions);这会创建携带容器上下文的虚拟线程。当 SDK 将工具调用分派到 searchProperties() 时,该方法可以 @Inject 一个 JPA 仓库并查询数据库,因为回调线程上存在容器上下文。
示例中的其他集成模式:
- CDI
@ApplicationScoped用于单例CopilotClient(每个应用程序生命周期一个客户端)。 - Jakarta Faces
f:websocket推送 通过PushContext实现浏览器实时更新。 - Jakarta Data
@Repository用于类型安全的数据库查询,无需原始 JPA 样板代码。
使用 ToolSet 进行细粒度工具访问控制。SessionConfig 允许你精确指定每个会话可以访问哪些工具:
sessionConfig.setAvailableTools(new ToolSet()
.addCustom("*") // all registered custom tools
.addBuiltIn("web_fetch")); // only the web_fetch built-in这是一个重要的生产关注点。与其暴露所有内置工具(文件系统访问、shell 执行等),你可以明确选择仅启用代理所需的功能。在示例应用中,我们允许所有自定义工具加上 web_fetch,以便代理在 Search 阶段查找实时房产信息。
总结
以下是我们涵盖的内容:
- Java 原生 API:
CompletableFuture、注解、lambda 和虚拟线程让 SDK 感觉像是地道的 Java,而不是从其他语言移植过来的事后想法。 - 三种工具定义风格:用于企业模式的注解、用于内联便利的 lambda、用于完全控制的 JSON Schema。
- 系统消息自定义:节级覆盖让你可以精确控制代理行为。
- 一行代码实现代理循环:
sendAndWait(...)自动处理完整的工具调用循环。 - 实时事件流:
session.on(...)实现响应式 UI 和可观测性。 - 无头服务器端运行:无需 IDE;可在任何有 Copilot CLI 的地方运行。
- 与 Jakarta EE 的自然组合:CDI、JPA、WebSocket 和虚拟线程都通过
Executor集成点协同工作。
接下来可以尝试
- 探索 BYOK 支持。GitHub Copilot SDK 可以直接针对模型提供商使用,例如 OpenAI、Azure、Anthropic 或 OpenAI 兼容端点,只需传入带有你自己的
baseUrl+apiKey(或 bearer token)的provider/ProviderConfig。无需 Copilot 订阅。 - 克隆示例应用并在本地运行。同时提交多个查询,以查看虚拟线程的实际运行。
- 更换模型。尝试
session.setModel(...)来体验不同的 Copilot 模型。 - 添加你自己的工具。定义一个新的
@CopilotTool方法(抵押贷款计算器、学区查询),然后观察代理发现并使用它。 - 部署到 Azure。Open Liberty 在 Azure App Service、AKS 或 Azure Container Apps 上运行良好。请参阅 Azure 上的 Jakarta EE 指南:https://aka.ms/java/ee。
适用于 Java 的 Copilot SDK 将 GitHub Copilot 的全部能力置于你的 Java 代码之后,无需 IDE,也没有框架锁定。
来源:GitHub Blog · Engineering · github.blog