diff --git a/README_zh.md b/README_zh.md
new file mode 100644
index 0000000..8d67e21
--- /dev/null
+++ b/README_zh.md
@@ -0,0 +1,175 @@
+# dashscope-sdk-java
+
+这是 DashScope 模型的 Java SDK。
+
+## 使用方法
+
+要在您的 Java 系统中使用该 SDK,请在 pom.xml 中添加以下 Maven 依赖:
+
+```xml
+
+ com.alibaba
+ dashscope-sdk-java
+ {dashscope-sdk-java-version}
+
+```
+
+## 快速开始
+
+### 文本生成
+
+您可以通过以下方式创建文本生成客户端:
+
+```java
+Generation generation = new Generation();
+```
+
+文本生成接口支持流式和非流式查询。这些查询都接受 `GenerationParam` 作为输入,并返回 `GenerationResult` 作为输出。
+
+以下是各方法的使用示例,以 `qwen-turbo` 模型为例。
+
+#### 支持流式和非流式模式,通过回调接收输出
+
+```java
+import com.alibaba.dashscope.aigc.generation.Generation;
+import com.alibaba.dashscope.aigc.generation.GenerationParam;
+import com.alibaba.dashscope.aigc.generation.GenerationResult;
+import com.alibaba.dashscope.common.Message;
+import com.alibaba.dashscope.common.ResultCallback;
+import com.alibaba.dashscope.common.Role;
+import com.alibaba.dashscope.exception.ApiException;
+import com.alibaba.dashscope.utils.JsonUtils;
+import java.util.Arrays;
+
+public class Main {
+
+ public static void main(String[] args) {
+ Generation generation = new Generation();
+ GenerationParam param = GenerationParam.builder()
+ .apiKey(System.getenv("DASHSCOPE_API_KEY"))
+ .model(Generation.Models.QWEN_TURBO)
+ .messages(Arrays.asList(
+ Message.builder()
+ .role(Role.USER.getValue())
+ .content("Hello, how are you?").build()
+ )).build();
+
+ class ReactCallback extends ResultCallback {
+
+ @Override
+ public void onEvent(GenerationResult message) {
+ System.out.println(JsonUtils.toJson(message));
+ }
+
+ public void onComplete() {
+ // TODO 所有消息已接收
+ }
+
+ public void onError(Exception e) {
+ ApiException apiException = (ApiException) e;
+ // TODO 处理异常
+ }
+ }
+
+ generation.call(param, new ReactCallback());
+ }
+}
+```
+
+异常实例是一个 `ApiException` 实例。该异常可能包含两部分:
+
+- 一个 `Status` 实例。该实例包含 status_code(HTTP 错误码)、code(服务器错误码)、message(服务器错误信息)、请求 ID 和使用信息。
+- 如果发生异常,`ApiException` 实例可能只包含一个 `Exception` 堆栈跟踪,您可以像平常一样处理它。
+
+#### 仅流式模式,通过响应式 IO 接收
+
+```java
+import com.alibaba.dashscope.aigc.generation.Generation;
+import com.alibaba.dashscope.aigc.generation.GenerationParam;
+import com.alibaba.dashscope.aigc.generation.GenerationResult;
+import com.alibaba.dashscope.common.Message;
+import com.alibaba.dashscope.common.Role;
+import com.alibaba.dashscope.exception.ApiException;
+import com.alibaba.dashscope.exception.InputRequiredException;
+import com.alibaba.dashscope.exception.NoApiKeyException;
+import com.alibaba.dashscope.utils.JsonUtils;
+import io.reactivex.Flowable;
+import java.util.Arrays;
+
+public class Main {
+
+ public static void main(String[] args) {
+ Generation generation = new Generation();
+
+ Message systemMsg = Message.builder()
+ .role(Role.SYSTEM.getValue())
+ .content("You are a helpful assistant.")
+ .build();
+ Message userMsg = Message.builder()
+ .role(Role.USER.getValue())
+ .content("Hello!")
+ .build();
+ GenerationParam param = GenerationParam.builder()
+ .apiKey(System.getenv("DASHSCOPE_API_KEY"))
+ .model(Generation.Models.QWEN_TURBO)
+ .messages(Arrays.asList(systemMsg, userMsg))
+ .resultFormat(GenerationParam.ResultFormat.MESSAGE)
+ .build();
+
+ try {
+ Flowable result = generation.streamCall(param);
+ result.blockingForEach(msg -> System.out.println(JsonUtils.toJson(msg)));
+ } catch (ApiException | NoApiKeyException | InputRequiredException e) {
+ System.err.println("An error occurred: " + e.getMessage());
+ }
+ }
+}
+```
+
+`streamCall` 方法接受 `GenerationParam`,并返回一个 `Flowable`,您可以通过 `blockingForEach` 获取流式结果,并通过 try-catch 块捕获异常。
+
+#### 仅非流式模式
+
+```java
+import com.alibaba.dashscope.aigc.generation.Generation;
+import com.alibaba.dashscope.aigc.generation.GenerationParam;
+import com.alibaba.dashscope.aigc.generation.GenerationResult;
+import com.alibaba.dashscope.common.Message;
+import com.alibaba.dashscope.common.Role;
+import com.alibaba.dashscope.exception.ApiException;
+import com.alibaba.dashscope.exception.InputRequiredException;
+import com.alibaba.dashscope.exception.NoApiKeyException;
+import com.alibaba.dashscope.utils.JsonUtils;
+import java.util.Arrays;
+
+public class Main {
+
+ public static void main(String[] args) {
+ Generation generation = new Generation();
+
+ Message systemMsg = Message.builder()
+ .role(Role.SYSTEM.getValue())
+ .content("You are a helpful assistant.")
+ .build();
+ Message userMsg = Message.builder()
+ .role(Role.USER.getValue())
+ .content("Hello!")
+ .build();
+ GenerationParam param = GenerationParam.builder()
+ .apiKey(System.getenv("DASHSCOPE_API_KEY"))
+ .model(Generation.Models.QWEN_TURBO)
+ .messages(Arrays.asList(systemMsg, userMsg))
+ .resultFormat(GenerationParam.ResultFormat.MESSAGE)
+ .build();
+
+ try {
+ GenerationResult result = generation.call(param);
+ System.out.println(JsonUtils.toJson(result));
+ } catch (ApiException | NoApiKeyException | InputRequiredException e) {
+ System.err.println("An error occurred: " + e.getMessage());
+ }
+ }
+}
+```
+
+`call` 方法接受 `GenerationParam`,并返回 `GenerationResult`,您也可以通过 try-catch 块捕获异常。
\ No newline at end of file
diff --git a/src/main/java/com/alibaba/dashscope/protocol/DashScopeHeaders.java b/src/main/java/com/alibaba/dashscope/protocol/DashScopeHeaders.java
index 8406331..4fc171a 100644
--- a/src/main/java/com/alibaba/dashscope/protocol/DashScopeHeaders.java
+++ b/src/main/java/com/alibaba/dashscope/protocol/DashScopeHeaders.java
@@ -8,8 +8,12 @@
import com.alibaba.dashscope.utils.StringUtils;
import java.util.HashMap;
import java.util.Map;
+import java.util.UUID;
public final class DashScopeHeaders {
+ private static final String SDK_CLIENT = "java-sdk";
+ private static final String SDK_SESSION_ID = UUID.randomUUID().toString();
+
public static String userAgent() {
return userAgent(null);
}
@@ -29,6 +33,24 @@ public static String userAgent(String customUserAgent) {
return userAgent;
}
+ /** Check if SDK tracking headers are disabled via DASHSCOPE_DISABLE_SDK_HEADERS env var. */
+ private static boolean isSdkHeadersDisabled() {
+ String disable = System.getenv("DASHSCOPE_DISABLE_SDK_HEADERS");
+ return "1".equals(disable) || "true".equalsIgnoreCase(disable);
+ }
+
+ /**
+ * Add SDK tracking headers to the given map. These headers are set first so that user-supplied
+ * customHeaders can override them.
+ */
+ private static void addSdkTrackingHeaders(Map headers) {
+ if (!isSdkHeadersDisabled()) {
+ headers.put("x-dashscope-sdk-client", SDK_CLIENT);
+ headers.put("x-dashscope-sdk-version", Version.version);
+ headers.put("x-dashscope-sdk-session-id", SDK_SESSION_ID);
+ }
+ }
+
public static Map buildWebSocketHeaders(
String apiKey, boolean isSecurityCheck, String workspace, Map customHeaders)
throws NoApiKeyException {
@@ -46,6 +68,7 @@ public static Map buildWebSocketHeaders(
Map headers = new HashMap<>();
headers.put("Authorization", "Bearer " + ApiKey.getApiKey(apiKey));
headers.put("user-agent", userAgent(customUserAgent));
+ addSdkTrackingHeaders(headers);
if (workspace != null && !workspace.isEmpty()) {
headers.put("X-DashScope-WorkSpace", workspace);
}
@@ -85,6 +108,7 @@ public static Map buildHttpHeaders(
Map headers = new HashMap<>();
headers.put("Authorization", "Bearer " + ApiKey.getApiKey(apiKey));
headers.put("user-agent", userAgent(customUserAgent));
+ addSdkTrackingHeaders(headers);
if (isSecurityCheck) {
headers.put("X-DashScope-DataInspection", "enable");
}