Skip to content

Java SDK

官方 Java SDK,封装 AI 应用开发平台的 OpenAPI(/v1/openapi/*)。

  • Java 21+(virtual threads、sealed interfaces、records、pattern matching)
  • 零运行时依赖(除 Jackson)—— HttpClientSystem.Logger 全用 JDK 原生
  • 类型化异常树(ApiKeyExpiredException 等)—— catch 类型,不写字符串匹配
  • 同步 + CompletableFuture 异步双重入口
  • SSE 流式 —— sealed ChatEvent + pattern matching switch
  • HITL Resume —— 静态工厂 ResumeResponse.choice(...) / .confirm(...)
  • 文件上传三入口 —— fromPath / fromBytes / fromStream

安装

仓库配置(消费方 pom.xml):

xml
<repositories>
    <repository>
        <id>hxsy-snapshots</id>
        <url>https://repo.i.huaxisy.com/repository/maven-snapshots/</url>
        <snapshots><enabled>true</enabled></snapshots>
    </repository>
    <repository>
        <id>hxsy-releases</id>
        <url>https://repo.i.huaxisy.com/repository/maven-releases/</url>
    </repository>
</repositories>

依赖(release 版本):

xml
<dependency>
    <groupId>com.hxsyai</groupId>
    <artifactId>aiadp-sdk</artifactId>
    <version>0.3.3</version>
</dependency>

如需最新开发版(snapshot):

xml
<dependency>
    <groupId>com.hxsyai</groupId>
    <artifactId>aiadp-sdk</artifactId>
    <version>0.3.4-SNAPSHOT</version>
</dependency>

要求 Java 21+。

快速开始

java
try (var client = AiAdpClient.builder()
        .apiKey("sk-xxx")
        .baseUrl("https://runtime-api.invalid/v1/openapi")
        .build()) {

    var r = client.chat().send(SendMessagesRequest.builder()
        .appId("<your-app-id>")
        .userId("user-1")
        .query("你好")
        .build());

    System.out.println(r.output().content());
}

AiAdpClient 仅负责通信,业务能力分布在子服务:

服务用途
app()应用列表 / 详情 / 运行参数
chat()Agent 对话(send / resume blocking & streaming,stop,会话 / 消息历史)
files()Agent 工作空间文件操作(upload / list / tree / edit / copy / move / delete / mkdir / search)
knowledge()知识库列表 / 详情 / 检索
workflow()工作流执行(blocking & streaming)
thirdParty()三方服务列表 / 工具列表 / 调用
voice()语音合成 / 识别 / 音色列表(含 WebSocket 流式)

配置

java
AiAdpClient.builder()
    .apiKey(...).baseUrl(...)
    .timeout(Duration.ofSeconds(30))
    .connectTimeout(Duration.ofSeconds(10))
    .streamConnectTimeout(Duration.ofSeconds(10))
    .retry(RetryPolicy.exponential(3, Duration.ofSeconds(1)))
    .userAgent("my-app/1.0")
    // .httpClient(myCustomHttpClient)    // 可选:自带 HttpClient
    // .asyncExecutor(myCustomExecutor)   // 可选:自定义异步执行器
    .build();

build() 阶段做凭证校验,失败抛 InvalidApiKeyException / InvalidBaseUrlException

AiAdpClient 实现 AutoCloseable,用 try-with-resources 自动释放底层 HttpClient 和 vthread executor。

异步 API

chat()workflow()app()voice() 的核心方法都有 xxxAsync(...) 重载,返回 CompletableFuture<T>,底层 virtual-thread executor,大并发零成本:

java
CompletableFuture<SendMessagesResult> f = client.chat().sendAsync(req);
CompletableFuture<InvokeResult> wf = client.workflow().invokeAsync(req);

应用 app

java
AppsResult              apps(AppsRequest req);
Map<String, Object>     detail(String appId);            // 可选 detail(appId, version)
AppParameters           parameters(String appId);        // 可选 parameters(appId, version)
// 对应 async:appsAsync / detailAsync / parametersAsync
java
AppsResult list = client.app().apps(
    new AppsRequest(null, null, 1, 20));
list.record().forEach(a ->
    System.out.println(a.id() + " " + a.name()));

// 应用详情:完整 app_schema 以 Map 返回(模型 / 提示词 / 工具 / 知识库 / 记忆 / 交互配置)
Map<String, Object> detail = client.app().detail(appId);

// 运行参数:结构化的交互配置(开场白、建议问题、语音 TTS/ASR、运行约束)
AppParameters params = client.app().parameters(appId);
System.out.println(params.voice().tts().code() + " " + params.runtimeSetting().maxSteps());

detail(...) 的 app_schema 字段多且会演进,Java 端以 Map<String, Object> 原样返回;需要结构化的运行配置用 parameters(...)

对话 chat

java
SendMessagesResult  send(SendMessagesRequest req);
ChatStream          sendStream(SendMessagesRequest req);
SendMessagesResult  resume(ResumeRequest req);
ChatStream          resumeStream(ResumeRequest req);
void                stop(String taskId);
ConversationsResult conversations(ConversationsRequest req);
List<HistoryItem>   history(HistoryRequest req);
// 对应 async:sendAsync / resumeAsync / stopAsync / conversationsAsync / historyAsync

请求用 builder 构造,响应是 record:

java
var r = client.chat().send(SendMessagesRequest.builder()
    .appId(appId).userId(userId).query("你好")
    .build());

// SendMessagesResult: conversationId / messageId / taskId / status / duration / output
// BlockingOutput:     content / finishReason / tokens
System.out.println(r.output().content());

response_mode 由 SDK 自动注入,请勿自行设置。

流式响应

支持三种消费方式,任挑:

java
// 1) for-each + sealed switch(最 idiomatic)
try (var stream = client.chat().sendStream(req)) {
    for (var ev : stream) {
        switch (ev) {
            case Start s         -> conversationId = s.data().conversationId();
            case Chunk c         -> System.out.print(c.data().content());
            case ThinkingStart t -> System.out.print("<think>");
            case Thinking t      -> System.out.print(t.data().content());
            case ThinkingEnd t   -> System.out.print("</think>");
            case Interrupt i     -> handleInterrupt(i);
            case TokenUsage tu   -> recordUsage(tu.data().usage());
            case Completed c     -> {}
            default -> {}
        }
    }
}

// 2) 函数式 stream() / forEach
client.chat().sendStream(req).stream()
    .filter(Chunk.class::isInstance)
    .map(Chunk.class::cast)
    .forEach(c -> System.out.print(c.data().content()));

// 3) 显式 next() —— EOF 返回 null
try (var s = client.chat().sendStream(req)) {
    ChatEvent ev;
    while ((ev = s.next()) != null) { /* ... */ }
}

ChatStream 实现 Iterable<ChatEvent>AutoCloseable

HITL Resume

java
client.chat().resume(ResumeRequest.builder()
    .appId(appId).userId(userId)
    .conversationId(conversationId).checkpointId(checkpointId)
    .respond(interruptId1, ResumeResponse.choice("staging"))
    .respond(interruptId2, ResumeResponse.confirm(true))
    .respond(interruptId3, ResumeResponse.text("..."))
    .build());

ResumeResponse 6 种静态工厂:confirm / text / choice / choices / form / edited

停止生成

java
client.chat().stop(taskId); // taskId 来自流中的 Start 事件

会话与消息历史

java
ConversationsResult conv = client.chat().conversations(
    new ConversationsRequest(appId, "demo-user", 1, 20));
conv.record().forEach(c -> System.out.println(c.id() + " " + c.name()));

List<HistoryItem> items = client.chat().history(
    new HistoryRequest(appId, conversationId, 1, 20));
items.forEach(m -> System.out.println(m.query() + " -> " + m.content()));

HistoryItemquery / content / thinking / toolCalls / items(子 Agent 与工具调用明细)等完整执行轨迹。

文件 files

java
UploadOperation upload(String userId); // 链式:.path(p).fromPath/fromBytes/fromStream
ListResult      list(ListRequest req);
TreeResult      tree(TreeRequest req);    // 递归文件树
void            edit(EditRequest req);
FileObject      copy(CopyRequest req);
FileObject      move(MoveRequest req);   // 对应网关 rename
void            delete(DeleteRequest req);
FileObject      mkdir(MkdirRequest req);
SearchResult    search(SearchRequest req);

上传三种入口:

java
// 1) Path —— 自动管理流的打开和关闭
client.files().upload("u1").path("/data/hello.txt")
    .fromPath(Paths.get("./hello.txt"));

// 2) byte[]
client.files().upload("u1").fromBytes("hello".getBytes(UTF_8), "hello.txt");

// 3) 任意 InputStream
try (var is = url.openStream()) {
    client.files().upload("u1").fromStream(is, "remote.bin");
}

// 列目录
ListResult ls = client.files().list(new ListRequest("u1", "/data"));
ls.files().forEach(f -> System.out.println(f.path() + " " + f.size()));

请求都是 record,例如 new CopyRequest(userId, sourcePath, targetPath)new SearchRequest(userId, keyword, path)

知识库 knowledge

java
ListResult     list(ListRequest req);
Detail         detail(String knowledgeId);
RetrieveResult retrieve(String knowledgeId, RetrieveRequest req);
java
ListResult list = client.knowledge().list(new ListRequest(null, 1, 10));
Knowledge first = list.items().get(0);

Detail detail = client.knowledge().detail(first.id());
System.out.println(detail.retrieverConfig().topK());

RetrieveResult res = client.knowledge().retrieve(first.id(),
    new RetrieveRequest("高血压患者能不能吃布洛芬?", null));
res.records().forEach(r ->
    System.out.printf("score=%.3f %s%n", r.score(), r.content()));

第二个参数传 RetrievalModelOverride 可覆盖单次检索的 topK / scoreThreshold,传 null 用知识库默认配置。

工作流 workflow

java
InvokeResult   invoke(InvokeRequest req);
WorkflowStream invokeStream(InvokeRequest req);
// 对应 async:invokeAsync
java
InvokeResult r = client.workflow().invoke(
    new InvokeRequest(workflowId, Map.of("input", "华西"), null));
System.out.println(r.finalOutput());

try (var stream = client.workflow().invokeStream(
        new InvokeRequest(workflowId, Map.of("input", "华西"), null))) {
    for (var ev : stream) {
        // WorkflowStream permits 7 种 WorkflowEvent,按需 switch
    }
}

三方服务 thirdParty

java
List<Service> listServices();
ToolsResult   tools(String serviceSlug);
InvokeResult  invoke(String serviceSlug, String toolSlug, Map<String, Object> inputs);
InvokeResult  invoke(String serviceSlug, String toolSlug); // 无入参重载
java
List<Service> services = client.thirdParty().listServices();
services.forEach(s ->
    System.out.println(s.name() + " configured=" + s.isConfigured()));

ToolsResult tools = client.thirdParty().tools(services.get(0).name());

InvokeResult res = client.thirdParty().invoke(
    services.get(0).name(), tools.tools().get(0).name(), Map.of());
System.out.println(res.output()); // JsonNode,不同工具结构不同

语音 voice

java
// 非流式
TtsResult          synthesize(SynthesizeRequest req);
SttResult          recognize(RecognizeRequest req);
List<VoiceOption>  listVoices(String provider);
// WebSocket 流式
TtsStream          synthesizeStream(SynthesizeRequest req);
SttSession         recognizeStream(RecognizeRequest req);
// 非流式三个方法均有对应 async

音频以 base64 字符串在请求/响应中传输。语音合成:

java
List<VoiceOption> voices = client.voice().listVoices("aliyun");

TtsResult tts = client.voice().synthesize(SynthesizeRequest.builder()
    .provider("aliyun")
    .text("你好,欢迎使用语音合成。")
    .voiceCode(voices.get(0).value())
    .format("mp3")
    .build());
byte[] audio = Base64.getDecoder().decode(tts.audioData());

语音识别(非流式):

java
SttResult stt = client.voice().recognize(RecognizeRequest.builder()
    .provider("aliyun")
    .audioData(Base64.getEncoder().encodeToString(bytes))
    .format("pcm")
    .sampleRate(16000)
    .build());
System.out.println(stt.text() + " " + stt.confidence());

WebSocket 流式

  • TTSTtsStream 迭代 TtsChunkisFinal() 标记结束。
  • STTSttSession 边推送音频边接收 SttFrame(含 isPartial() / isFinal())。

两者均实现 AutoCloseable,用 try-with-resources 自动释放连接。STT 流式时 RecognizeRequest 的非音频字段作为首帧配置。

错误处理

类型化异常,无字符串匹配:

java
try { client.chat().send(req); }
catch (ApiKeyExpiredException e)      { rotateKey(); }
catch (ApiException e) {
    log.error("status={} code={} trace={}", e.status(), e.code(),
              e.traceId().orElse("none"));
}
catch (TransportException e) { /* 网络/解码 */ }
异常类触发条件
InvalidApiKeyException / InvalidBaseUrlExceptionBuilder.build() 校验失败
ApiKeyExpiredException / ApiKeyDisabledException / InvalidApiKeyTokenException401 + 对应 message
MissingApiKeyException / InvalidAuthFormatException401 + 对应 message
InvalidPathException403 + 对应 message
NotFoundException / RateLimitedException404 / 429
AuthServiceUnavailableException / AuthServiceInitException503 / 500 + 特定 message
ApiException 兜底其他 4xx/5xx 或业务 code != 200
TransportException网络 IO / 编解码 / 中断

错误码与文案以网关/服务实际返回为准,详见 错误处理

示例

完整可运行示例见 SDK 仓库的 src/main/java/com/hxsyai/aiadp/examples/

示例功能
AppListExample应用列表
ChatBlockingExample阻塞式对话
ChatStreamingExample流式对话 + 模式匹配分发事件
ChatResumeExampleHITL 中断 + ResumeResponse.choice
ChatStopExampletask-id 停止流
ChatHistoryExample会话列表 + 消息历史
FilesUploadExample上传 + 列目录
KnowledgeRetrieveExample知识库 list / detail / retrieve
WorkflowInvokeExample工作流 blocking + streaming
ThirdpartyInvokeExample三方服务 list / tools / invoke
VoiceTtsExample / VoiceSttExample语音合成 / 识别(含流式)

运行:

bash
export AIADP_API_KEY=sk-xxx
export APP_ID=<uuid>
export QUERY="你好"
mvn -q compile exec:java -Dexec.mainClass=com.hxsyai.aiadp.examples.ChatStreamingExample

环境变量(各示例按需):AIADP_API_KEY / AIADP_BASE_URL / APP_ID / USER_ID / QUERY / INPUT_JSON / TASK_ID / KNOWLEDGE_ID / WORKFLOW_ID / SERVICE / TOOL / INPUTS_JSON

AI 应用开发平台 - 面向医疗场景的 AI 应用创新引擎