Appearance
Java SDK
官方 Java SDK,封装 AI 应用开发平台的 OpenAPI(/v1/openapi/*)。
- Java 21+(virtual threads、sealed interfaces、records、pattern matching)
- 零运行时依赖(除 Jackson)——
HttpClient、System.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 / parametersAsyncjava
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()));HistoryItem 含 query / 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:invokeAsyncjava
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 流式
- TTS:
TtsStream迭代TtsChunk,isFinal()标记结束。 - STT:
SttSession边推送音频边接收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 / InvalidBaseUrlException | Builder.build() 校验失败 |
ApiKeyExpiredException / ApiKeyDisabledException / InvalidApiKeyTokenException | 401 + 对应 message |
MissingApiKeyException / InvalidAuthFormatException | 401 + 对应 message |
InvalidPathException | 403 + 对应 message |
NotFoundException / RateLimitedException | 404 / 429 |
AuthServiceUnavailableException / AuthServiceInitException | 503 / 500 + 特定 message |
ApiException 兜底 | 其他 4xx/5xx 或业务 code != 200 |
TransportException | 网络 IO / 编解码 / 中断 |
错误码与文案以网关/服务实际返回为准,详见 错误处理。
示例
完整可运行示例见 SDK 仓库的 src/main/java/com/hxsyai/aiadp/examples/:
| 示例 | 功能 |
|---|---|
AppListExample | 应用列表 |
ChatBlockingExample | 阻塞式对话 |
ChatStreamingExample | 流式对话 + 模式匹配分发事件 |
ChatResumeExample | HITL 中断 + ResumeResponse.choice |
ChatStopExample | task-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。
