# Z.ai SDK Java - Architecture Documentation ## Overview The Z.ai SDK Java provides a service-oriented architecture that offers clean separation of concerns, comprehensive configuration management, and support for both synchronous and streaming operations. The SDK is built around a client-service pattern with reactive programming support. ## Architecture Components ### 1. Core Client Architecture #### ZaiClient The main client class that serves as the entry point for all AI services: ```java public class ZaiClient extends AbstractClientBaseService { // Service instances private ChatService chatService; private AgentService agentService; private EmbeddingService embeddingService; // ... other services // Constructor public ZaiClient(ZaiConfig config) { // Initialize HTTP client and Retrofit } // Service accessors public synchronized ChatService chat() { /* ... */ } public synchronized AgentService agents() { /* ... */ } // ... other service accessors } ``` #### Base Request and Response Models **ClientRequest Interface**: Base interface for all service requests ```java public interface ClientRequest { // Marker interface for type safety } ``` **ClientResponse Interface**: Base interface for all service responses ```java public interface ClientResponse { T getData(); void setData(T data); void setCode(int code); void setMsg(String msg); void setSuccess(boolean success); void setError(ChatError error); } ``` **FlowableClientResponse Interface**: Extended interface for streaming responses ```java public interface FlowableClientResponse extends ClientResponse { void setFlowable(Flowable stream); } ``` ### 2. Configuration Management #### ZaiConfig Main configuration class that contains all SDK settings: ```java @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ZaiConfig { private String baseUrl; private String apiSecretKey; private String apiKey; private String apiSecret; private int expireMillis = 30 * 60 * 1000; // 30 minutes private String alg = "HS256"; private boolean disableTokenCache; // Connection pool settings private int connectionPoolMaxIdleConnections = 5; private long connectionPoolKeepAliveDuration = 1; private TimeUnit connectionPoolTimeUnit = TimeUnit.SECONDS; // Timeout settings private int requestTimeOut; private int connectTimeout; private int readTimeout; private int writeTimeout; private TimeUnit timeOutTimeUnit; private String source_channel; } ``` #### Configuration Features 1. **Authentication Settings** - API secret key in format `{apiKey}.{apiSecret}` - JWT token expiration and algorithm configuration - Token caching control 2. **Network Configuration** - Base URL for API endpoints - Connection pool settings (max idle connections, keep-alive duration) - Timeout configurations (request, connect, read, write) 3. **Token Management** - JWT token generation and caching - Configurable expiration times - Option to disable token caching for direct API key usage ### 3. Service Implementations #### ChatService Provides chat completion functionality with support for synchronous, asynchronous, and streaming operations: ```java public interface ChatService { /** * Creates a chat completion, either streaming or non-streaming based on the request configuration. */ ChatCompletionResponse createChatCompletion(ChatCompletionCreateParams request); /** * Creates an asynchronous chat completion. */ ChatCompletionResponse asyncChatCompletion(ChatCompletionCreateParams request); /** * Retrieves the result of an asynchronous model operation. */ QueryModelResultResponse retrieveAsyncResult(AsyncResultRetrieveParams request); } ``` #### Service Implementation Pattern All services follow a consistent implementation pattern: ```java public class ChatServiceImpl implements ChatService { private final ZaiClient zAiClient; private final ChatApi chatApi; public ChatServiceImpl(ZaiClient zAiClient) { this.zAiClient = zAiClient; this.chatApi = this.zAiClient.retrofit().create(ChatApi.class); } @Override public ChatCompletionResponse createChatCompletion(ChatCompletionCreateParams request) { // Parameter validation String paramMsg = validateParams(request); if (StringUtils.isNotEmpty(paramMsg)) { return new ChatCompletionResponse(-100, String.format("invalid param: %s", paramMsg)); } // Route to streaming or synchronous execution if (request.getStream()) { return streamChatCompletion(request); } else { return syncChatCompletion(request); } } } ``` ## Usage Examples ### Basic Configuration ```java // Simple configuration with API secret key ZaiConfig config = new ZaiConfig("your.api.key.your.api.secret"); ZaiClient client = new ZaiClient(config); // Or using separate API key and secret ZaiConfig config = new ZaiConfig("your.api.key", "your.api.secret"); ZaiClient client = new ZaiClient(config); ``` ### Builder Pattern Configuration ```java // Using the Builder pattern for advanced configuration ZaiClient client = new ZaiClient.Builder("your.api.key.your.api.secret") .enableTokenCache() .networkConfig( 300, // request timeout 100, // connect timeout 100, // read timeout 100, // write timeout TimeUnit.SECONDS ) .connectionPool( 10, // max idle connections 5, // keep alive duration TimeUnit.MINUTES ) .tokenExpire(3600000) // 1 hour in milliseconds .build(); ``` ### Custom Configuration with ZaiConfig ```java ZaiConfig config = ZaiConfig.builder() .apiSecretKey("your.api.key.your.api.secret") .baseUrl("https://custom.api.endpoint") .requestTimeOut(60) .connectTimeout(30) .readTimeout(30) .writeTimeout(30) .timeOutTimeUnit(TimeUnit.SECONDS) .disableTokenCache(false) .expireMillis(7200000) // 2 hours .connectionPoolMaxIdleConnections(10) .connectionPoolKeepAliveDuration(5) .connectionPoolTimeUnit(TimeUnit.MINUTES) .build(); ZaiClient client = new ZaiClient(config); ``` ### Service Usage ```java // Get service instance ChatService chatService = client.chat(); // Create chat request ChatCompletionCreateParams request = ChatCompletionCreateParams.builder() .model("glm-4") .messages(Arrays.asList( ChatMessage.builder() .role(ChatMessage.Role.USER) .content("Hello, world!") .build() )) .stream(false) // Set to true for streaming .temperature(0.7f) .maxTokens(1024) .build(); // Execute request try { ChatCompletionResponse response = chatService.createChatCompletion(request); if (response.isSuccess()) { ModelData data = response.getData(); if (data != null && data.getChoices() != null && !data.getChoices().isEmpty()) { String content = data.getChoices().get(0).getMessage().getContent(); System.out.println("Response: " + content); } } else { System.err.println("Error: " + response.getMsg()); if (response.getError() != null) { System.err.println("Error details: " + response.getError().getMessage()); } } } catch (Exception e) { System.err.println("Request failed: " + e.getMessage()); } ``` ### Streaming Usage ```java // Create streaming request ChatCompletionCreateParams streamRequest = ChatCompletionCreateParams.builder() .model("glm-4") .messages(Arrays.asList( ChatMessage.builder() .role(ChatMessage.Role.USER) .content("Tell me a story") .build() )) .stream(true) // Enable streaming .temperature(0.7f) .maxTokens(1024) .build(); // Execute streaming request ChatCompletionResponse response = chatService.createChatCompletion(streamRequest); if (response.isSuccess() && response.getFlowable() != null) { response.getFlowable().subscribe( data -> { // Handle streaming chunk if (data.getChoices() != null && !data.getChoices().isEmpty()) { String content = data.getChoices().get(0).getDelta().getContent(); if (content != null) { System.out.print(content); } } }, error -> System.err.println("\nStream error: " + error.getMessage()), () -> System.out.println("\nStream completed") ); } else { System.err.println("Failed to start streaming: " + response.getMsg()); } ``` ### Asynchronous Usage ```java // Create async request ChatCompletionCreateParams asyncRequest = ChatCompletionCreateParams.builder() .model("glm-4") .messages(Arrays.asList( ChatMessage.builder() .role(ChatMessage.Role.USER) .content("Generate a long document") .build() )) .build(); // Execute async request ChatCompletionResponse asyncResponse = chatService.asyncChatCompletion(asyncRequest); if (asyncResponse.isSuccess()) { String taskId = asyncResponse.getData().getTaskId(); System.out.println("Async task started with ID: " + taskId); // Poll for results AsyncResultRetrieveParams retrieveParams = new AsyncResultRetrieveParams(); retrieveParams.setId(taskId); QueryModelResultResponse result = chatService.retrieveAsyncResult(retrieveParams); // Handle result... } ``` ## Available Services The ZaiClient provides access to multiple AI services: ```java ZaiClient client = new ZaiClient(config); // Chat completion service ChatService chatService = client.chat(); // Agent service for agent-based completions AgentService agentService = client.agents(); // Embedding service for text embeddings EmbeddingService embeddingService = client.embeddings(); // File management service FileService fileService = client.files(); // Audio processing service AudioService audioService = client.audio(); // Image generation service ImageService imageService = client.images(); // Batch processing service BatchService batchService = client.batches(); // Fine-tuning service FineTuningService fineTuningService = client.fineTuning(); // Web search service WebSearchService webSearchService = client.webSearch(); // Video processing service VideosService videosService = client.videos(); // Knowledge base service KnowledgeService knowledgeService = client.knowledge(); // Document management service DocumentService documentService = client.documents(); // Assistant service AssistantService assistantService = client.assistants(); ``` ## Request and Response Models ### Common Request Structure All requests extend `CommonRequest` which provides common fields: ```java @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor public class CommonRequest { @JsonProperty("request_id") private String requestId; @JsonProperty("user_id") private String userId; // Additional common fields... } ``` ### Chat Request Example ```java @Data @SuperBuilder @NoArgsConstructor @AllArgsConstructor public class ChatCompletionCreateParams extends CommonRequest implements ClientRequest { private String model; private List messages; private Boolean stream; private Float temperature; @JsonProperty("max_tokens") private Integer maxTokens; private List stop; private List tools; // ... other fields } ``` ### Response Structure All responses implement `ClientResponse` or `FlowableClientResponse`: ```java @Data public class ChatCompletionResponse implements FlowableClientResponse { private int code; private String msg; private boolean success; private ModelData data; private Flowable flowable; // For streaming responses private ChatError error; } ``` ## Error Handling ### Response Error Handling ```java ChatCompletionResponse response = chatService.createChatCompletion(request); // Check if the request was successful if (!response.isSuccess()) { int errorCode = response.getCode(); String errorMessage = response.getMsg(); System.err.println("Request failed with code: " + errorCode); System.err.println("Error message: " + errorMessage); // Check for detailed error information if (response.getError() != null) { ChatError error = response.getError(); System.err.println("Error code: " + error.getCode()); System.err.println("Error details: " + error.getMessage()); // Handle specific error types switch (errorCode) { case 400: System.err.println("Bad request - check your parameters"); break; case 401: System.err.println("Authentication failed - check your API key"); break; case 429: System.err.println("Rate limit exceeded - please retry later"); break; case 500: System.err.println("Server error - please try again"); break; default: System.err.println("Unexpected error occurred"); } } return; } // Process successful response ModelData data = response.getData(); if (data != null) { // Handle successful response data System.out.println("Request completed successfully"); } ``` ### Exception Handling ```java try { ChatCompletionResponse response = chatService.createChatCompletion(request); // Process response... } catch (ZAiHttpException e) { // Handle HTTP-specific errors System.err.println("HTTP Error: " + e.getMessage()); System.err.println("Status Code: " + e.statusCode); System.err.println("Error Code: " + e.code); } catch (Exception e) { // Handle other exceptions System.err.println("Unexpected error: " + e.getMessage()); e.printStackTrace(); } ``` ## Extension Points ### Custom Service Implementation ```java public class CustomService implements AIService { @Override public CustomResponse execute(CustomRequest request) throws Exception { // Implementation } @Override public CompletableFuture executeAsync(CustomRequest request) { // Implementation } @Override public Flowable executeStream(CustomRequest request) throws Exception { // Implementation } @Override public void validateRequest(CustomRequest request) throws IllegalArgumentException { // Validation logic } @Override public String getServiceType() { return "CUSTOM_SERVICE"; } } // Register custom service client.registerService("CUSTOM_SERVICE", new CustomService()); ``` ### Custom Configuration ```java // Extend configuration for custom needs ZaiConfiguration customConfig = ZaiConfigurationBuilder.newBuilder() .apiSecretKey("your.api.key") .baseUrl("https://custom.endpoint") // Add custom settings .build(); // Add custom metadata to configuration customConfig.getAuth().addMetadata("customAuth", "value"); customConfig.getNetwork().addMetadata("customNetwork", "value"); ``` ## Best Practices ### Configuration Management ```java // Use builder pattern for configuration ZaiConfig config = ZaiConfig.builder() .apiSecretKey("your.api.key.your.api.secret") .baseUrl("https://open.bigmodel.cn/") .requestTimeOut(60) .connectTimeout(30) .readTimeout(30) .writeTimeout(30) .timeOutTimeUnit(TimeUnit.SECONDS) .disableTokenCache(false) .expireMillis(3600000) // 1 hour .connectionPoolMaxIdleConnections(10) .connectionPoolKeepAliveDuration(5) .connectionPoolTimeUnit(TimeUnit.MINUTES) .build(); ZaiClient client = new ZaiClient(config); ``` ### Request Building ```java // Use builder pattern for creating requests ChatCompletionCreateParams request = ChatCompletionCreateParams.builder() .model("glm-4") .messages(Arrays.asList( ChatMessage.builder() .role(ChatMessage.Role.USER) .content("Hello, world!") .build() )) .temperature(0.7f) .maxTokens(1000) .stream(false) .build(); ``` ### Error Handling ```java // Comprehensive error handling ChatCompletionResponse response = chatService.createChatCompletion(request); if (!response.isSuccess()) { System.err.println("Request failed: " + response.getMsg()); if (response.getError() != null) { System.err.println("Error details: " + response.getError().getMessage()); } return; } // Process successful response ModelData data = response.getData(); if (data != null && data.getChoices() != null && !data.getChoices().isEmpty()) { String content = data.getChoices().get(0).getMessage().getContent(); System.out.println("Response: " + content); } ``` ### Streaming Best Practices ```java // Handle streaming responses properly ChatCompletionCreateParams streamRequest = request.toBuilder() .stream(true) .build(); ChatCompletionResponse response = chatService.createChatCompletion(streamRequest); if (response.isSuccess() && response.getFlowable() != null) { response.getFlowable() .observeOn(Schedulers.io()) .subscribe( data -> { // Process each streaming chunk if (data.getChoices() != null && !data.getChoices().isEmpty()) { String content = data.getChoices().get(0).getDelta().getContent(); if (content != null) { System.out.print(content); } } }, error -> { System.err.println("Streaming error: " + error.getMessage()); }, () -> { System.out.println("\nStreaming completed"); } ); } ``` ### Resource Management ```java // Properly manage client lifecycle try { ZaiClient client = new ZaiClient(config); ChatService chatService = client.chat(); // Use the service... ChatCompletionResponse response = chatService.createChatCompletion(request); } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } finally { // Clean up resources if needed } ``` ### Asynchronous Processing ```java // Use async operations for long-running tasks ChatCompletionResponse asyncResponse = chatService.asyncChatCompletion(request); if (asyncResponse.isSuccess()) { String taskId = asyncResponse.getData().getTaskId(); // Poll for results AsyncResultRetrieveParams retrieveParams = new AsyncResultRetrieveParams(); retrieveParams.setId(taskId); // Implement polling logic with backoff CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); // Wait before polling return chatService.retrieveAsyncResult(retrieveParams); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } }).thenAccept(result -> { // Handle result if (result.isSuccess()) { System.out.println("Async task completed"); } }); } ``` ### Security Best Practices 1. **API Key Management**: Store API keys securely, never hardcode them 2. **Token Caching**: Enable token caching to reduce authentication overhead 3. **Request Validation**: Always validate input parameters 4. **Error Logging**: Log errors but never log sensitive information 5. **Timeout Configuration**: Set appropriate timeouts to prevent hanging requests 6. **Connection Pooling**: Configure connection pools for optimal performance 7. **Rate Limiting**: Implement client-side rate limiting to respect API limits ## Migration Guide ### Upgrading to Latest Version This guide helps you migrate from older versions of the Z-AI SDK to the current architecture. #### Key Changes in Current Version 1. **Unified Client Architecture**: All services are now accessed through `ZaiClient` 2. **Improved Configuration**: `ZaiConfig` with builder pattern for better flexibility 3. **Standardized Request/Response**: All requests implement `ClientRequest`, responses implement `ClientResponse` 4. **Enhanced Streaming**: Better support for streaming responses with `FlowableClientResponse` 5. **Comprehensive Service Coverage**: Support for Chat, Agents, Embeddings, Files, Audio, Images, and more #### Configuration Migration ```java // If you were using basic configuration // Old approach (if applicable) String apiKey = "your-api-key"; String apiSecret = "your-api-secret"; // New approach ZaiConfig config = ZaiConfig.builder() .apiKey(apiKey) .apiSecret(apiSecret) .baseUrl("https://open.bigmodel.cn/") .enableTokenCache(true) .tokenExpiredSeconds(3600) .build(); ZaiClient client = new ZaiClient(config); ``` #### Service Usage Migration ```java // Modern service usage ChatService chatService = client.chat(); EmbeddingService embeddingService = client.embeddings(); FileService fileService = client.files(); AudioService audioService = client.audio(); ImageService imageService = client.images(); // ... and more services ``` #### Request Building Migration ```java // Use builder pattern for all requests ChatCompletionCreateParams chatRequest = ChatCompletionCreateParams.builder() .model("glm-4") .messages(Arrays.asList( ChatMessage.builder() .role(ChatMessage.Role.USER) .content("Hello, world!") .build() )) .temperature(0.7f) .maxTokens(1000) .build(); ``` #### Response Handling Migration ```java // Standardized response handling ChatCompletionResponse response = chatService.createChatCompletion(chatRequest); if (response.isSuccess()) { ModelData data = response.getData(); // Process successful response } else { System.err.println("Error: " + response.getMsg()); if (response.getError() != null) { System.err.println("Details: " + response.getError().getMessage()); } } ``` #### Streaming Migration ```java // Enhanced streaming support ChatCompletionCreateParams streamRequest = chatRequest.toBuilder() .stream(true) .build(); ChatCompletionResponse streamResponse = chatService.createChatCompletion(streamRequest); if (streamResponse.isSuccess() && streamResponse.getFlowable() != null) { streamResponse.getFlowable() .subscribe( data -> { // Process streaming data }, error -> { // Handle streaming errors }, () -> { // Streaming completed } ); } ``` ### Best Practices for Migration 1. **Update Dependencies**: Ensure you're using the latest version of the SDK 2. **Review Configuration**: Update your configuration to use `ZaiConfig.builder()` 3. **Update Service Access**: Use `ZaiClient` to access all services 4. **Standardize Error Handling**: Use the new response structure for error handling 5. **Test Thoroughly**: Test all functionality after migration 6. **Update Documentation**: Update your internal documentation to reflect the new patterns This architecture provides a solid foundation for future enhancements while maintaining backward compatibility where possible.