使用 GitHub Copilot SDK for Java

作者:Edward Burns

排版:Alan Wang

企业级 Java 开发者迎来全新利器——通过符合 Java 习惯的代码、注解、虚拟线程等方式,驱动 GitHub Copilot。

在这里插入图片描述

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,但你可以将其与任意直接模型提供商结合使用,例如 OpenAI、Azure、Anthropic,或兼容 OpenAI API 的端点。只需传入包含自定义 baseUrl + apiKey(或 bearer token)的 provider/ProviderConfig 即可。无需 Copilot 订阅。

GitHub Copilot SDK for Java 是一个客户端库,可以让你的服务端 Java 代码以编程方式创建 Copilot Agent 会话、注册工具、发送提示词并接收结构化响应。它可以运行在包括 Jakarta EE 和 Spring 在内的服务端环境中。如果你已经从事企业级 Java 开发一段时间,这套 SDK 会让你感到非常熟悉:CompletableFuture、注解、lambda、虚拟线程,这些都已经包含其中。

本文将介绍如何使用这套 SDK,并通过一个完整的 Jakarta EE 11 示例应用进行演示,最后还会提供具体的后续步骤,帮助你亲自尝试。我在演示中选择 Jakarta EE 11,是因为我是该版本发布的首席发布协调员。我一直认为,开放标准是赋能开发者的最佳方式。关于 Jakarta EE 11 的更多信息,可以参阅这篇 InfoQ 文章

这个示例应用是一个基于 Jakarta EE 11 构建的 Agent Harness。当然,开发者也可以使用自己熟悉和偏好的 Java 框架与库,构建属于自己的 Agent Harness。

克隆示例应用并亲自尝试 >

在哪里获取

该 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.xhtml

这个 Java 示例基于以下技术构建:

应用实现了什么

这个应用是一个房地产客户线索管理 Agent 流水线。客户提交需求,例如“我想在伦敦寻找一套三居室、价格低于 80 万英镑的房子”,系统就会在一个虚拟线程中启动一个相互隔离的 Copilot Agent,并通过一套流水线对需求进行处理:
在这里插入图片描述

该架构使用 Jakarta WebSocket 将服务端的实时状态更新推送到浏览器,因此你可以实时查看 Agent 在模型调用工具的过程中经历的不同阶段。

在这里插入图片描述

你可以同时提交多个咨询请求,观察多个基于虚拟线程的 Agent 并发运行。每个 Agent 都会独立处理自己的请求,并拥有独立的 Copilot 会话。

在这里插入图片描述
在这里插入图片描述

SDK 核心功能实战

下面来看看示例代码中如何使用 SDK 的几个关键功能。

使用 @CopilotTool 定义工具

这是 SDK 中最核心的 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 构建中配置两项内容:

  1. 启用实验性 API:向编译器传入 -Acopilot.experimental.allowed=true。如果没有这个标志,注解处理器将拒绝生成工具元数据。关于实验性 API 的更多信息,请参阅 Copilot SDK 文档

  2. 注册注解处理器:将 SDK 添加到 annotationProcessorPath 中,这样编译器才能找到 @CopilotTool 处理器,并在编译时生成 C o p i l o t T o o l M e t a CopilotToolMeta 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 工具会有意替换一个同名的内置工具。当你需要为模型已经了解的工具添加自定义行为时,这一功能非常有用。

跨类扫描工具

工具不一定要与 Agent 逻辑位于同一个类中。下面的 searchProperties 就定义在一个独立的 CDI Bean 中:

@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 会将你的内容添加到默认系统消息之后,而不会替换任何内容。

Agent 循环:sendAndWait(...)

只需一行代码,即可启动完整的 Agent 循环:

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);
});

每次工具调用、每次调用结果以及每条 Assistant 消息都会触发一个事件。示例应用会捕获这些事件,并通过 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 获取,这样容器才能:

  1. 跟踪线程,以便在生命周期结束时关闭(@PreDestroy / 服务器停止)

  2. 应用并发限制和策略

  3. 自动传播上下文(无需手动使用 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 Repository 并查询数据库,因为容器上下文已经存在于回调线程中。

示例中的其他集成模式包括:

  • 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 执行等),不如明确选择 Agent 实际需要的工具。在示例应用中,我们允许所有自定义工具,以及 web_fetch,这样 Agent 就可以在搜索阶段查询实时的房产信息。

总结

本文介绍了以下内容:

  • Java 原生 APICompletableFuture、注解、lambda 和虚拟线程让 SDK 具备符合 Java 习惯的开发体验,而不是简单地将其他语言的实现移植过来。

  • 三种工具定义方式:使用注解适用于企业级开发模式,使用 lambda 适用于内联场景,而 JSON Schema 则提供完整的控制能力。

  • 系统消息自定义:通过分段级别的覆盖,可以精确控制 Agent 的行为。

  • 一行代码实现 Agent 循环sendAndWait(...) 会自动处理完整的工具调用循环。

  • 实时事件流session.on(...) 支持构建响应迅速的 UI,并实现可观测性。

  • 无头服务端运行:无需 IDE,只要 Copilot CLI 可用即可运行。

  • 与 Jakarta EE 自然组合:通过 Executor 集成点,CDI、JPA、WebSocket 和虚拟线程可以协同工作。

下一步可以尝试什么

  • 探索 BYOK 支持。 GitHub Copilot SDK 可以直接连接模型提供商,例如 OpenAI、Azure、Anthropic 或兼容 OpenAI API 的端点。只需传入包含自定义 baseUrl + apiKey(或 bearer token)的 provider/ProviderConfig 即可。无需 Copilot 订阅。

  • 克隆示例应用并在本地运行。同时提交多个咨询请求,观察虚拟线程的运行效果。

  • 切换模型。 尝试使用 session.setModel(...),体验不同的 Copilot 模型。

  • 添加自己的工具。 定义一个新的 @CopilotTool 方法(例如房贷计算器、学区查询工具),观察 Agent 如何发现并使用它。

  • 部署到 Azure。 Open Liberty 可以很好地运行在 Azure App Service、AKS 或 Azure Container Apps 上。关于 Jakarta EE on Azure 的更多指导,请参阅 https://aka.ms/java/ee

Copilot SDK for Java 将 GitHub Copilot 的完整能力带入你的 Java 代码中,无需 IDE,也不会被特定框架绑定。

克隆示例应用并亲自尝试 >

Logo

微软开发者社区,邀请来自微软以及技术社区专家,带来最前沿的技术干货与实践经验。在这里,您将看到深度教程、最佳实践和创新解决方案。

更多推荐