diff --git a/README.md b/README.md index 54194a42..4a6f7b84 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The DashScope Python SDK is the official client for [Alibaba Cloud Model Studio | Entry point | Module-level static classes: `Generation.call(...)` | A resource-style client: `client.chat.completions.create(...)` | | One-liner | — | `dashscope.chat("qwen-plus", "Tell me a joke")` | | Response | Raw dict-like; check `status_code == HTTPStatus.OK` | Typed object; read `resp.output_text`, `resp.usage.total_tokens` | -| Errors | Inspect `resp.code` / `resp.message` by hand | Typed `DashScopeError` exceptions raised by default | +| Errors | Inspect `resp.code` / `resp.message` by hand | Typed `DashScopeError` exceptions raised by default *(evolving)* | | Streaming | Generator of raw frames | `ChatStream` with `.text_stream`, `.reasoning_stream`, `.get_final_message()` | | Protocols | DashScope native + a separate compatible-mode entry | One client speaks `native`, `openai`, or `anthropic` via `protocol=` | | Async | Separate `Aio*` classes | `dashscope.AsyncClient()` mirrors the whole sync surface | @@ -26,13 +26,11 @@ The DashScope Python SDK is the official client for [Alibaba Cloud Model Studio pip install -U dashscope ``` -The base install covers SDK API calls and the `dashscope` CLI command. Python 3.9+ is required. Optional feature groups are available as extras: +The base install covers SDK API calls, the `dashscope` CLI command, Agentic RL fine-tuning and the local tokenizer. Python 3.9+ is required. One optional feature group remains: | Extra | Provides | Install | |-------|----------|---------| | `acli` | Interactive AI assistant (DashScope SDK Expert) | `pip install "dashscope[acli]"` | -| `rl` | Agentic RL fine-tuning | `pip install "dashscope[rl]"` | -| `tokenizer` | Local tokenizer without downloads | `pip install "dashscope[tokenizer]"` | To install from a source checkout: @@ -191,6 +189,8 @@ By default each frame is incremental. Pass `incremental_output=False` to receive ### Errors +> **Still evolving.** The 2.0 typed error surface is under active development — new exception classes may be added and the API-error-code → exception mapping may be refined. Catch the base `errors.DashScopeError` if you need to stay forward-compatible. + Failures raise a typed `DashScopeError` by default (both non-2xx HTTP statuses and HTTP-200-with-a-business-error land here): ```python diff --git a/README_zh.md b/README_zh.md index 31cec0b6..eb6ad822 100644 --- a/README_zh.md +++ b/README_zh.md @@ -13,7 +13,7 @@ DashScope Python SDK 是[阿里云百炼(Model Studio)](https://help.aliyun. | 入口 | 模块级静态类:`Generation.call(...)` | 资源风格客户端:`client.chat.completions.create(...)` | | 一行调用 | —— | `dashscope.chat("qwen-plus", "讲个笑话")` | | 响应 | 裸字典;需判断 `status_code == HTTPStatus.OK` | 类型化对象;直接读 `resp.output_text`、`resp.usage.total_tokens` | -| 错误 | 手动检查 `resp.code` / `resp.message` | 默认抛出类型化的 `DashScopeError` 异常 | +| 错误 | 手动检查 `resp.code` / `resp.message` | 默认抛出类型化的 `DashScopeError` 异常 *(完善中)* | | 流式 | 裸帧生成器 | `ChatStream`,提供 `.text_stream`、`.reasoning_stream`、`.get_final_message()` | | 协议 | DashScope 原生 + 单独的 compatible-mode 入口 | 一个客户端通过 `protocol=` 讲 `native`、`openai` 或 `anthropic` | | 异步 | 独立的 `Aio*` 类 | `dashscope.AsyncClient()` 完整镜像同步接口 | @@ -26,13 +26,11 @@ DashScope Python SDK 是[阿里云百炼(Model Studio)](https://help.aliyun. pip install -U dashscope ``` -基础安装包含 SDK API 调用和 `dashscope` CLI 命令,要求 Python 3.9+。可选功能组通过 extras 安装: +基础安装包含 SDK API 调用、`dashscope` CLI 命令、Agentic RL 微调和本地 tokenizer,要求 Python 3.9+。仅剩一个可选功能组: | Extra | 提供的能力 | 安装命令 | |-------|----------|---------| | `acli` | 交互式 AI 助手(DashScope SDK Expert) | `pip install "dashscope[acli]"` | -| `rl` | Agentic RL 微调 | `pip install "dashscope[rl]"` | -| `tokenizer` | 本地 tokenizer(无需下载) | `pip install "dashscope[tokenizer]"` | 从源码安装: @@ -191,6 +189,8 @@ for text in stream.text_stream: # 内容增量 ### 错误 +> **仍在完善中。** 2.0 的类型化错误体系正在持续开发 —— 可能新增异常类,API 错误码到异常类的映射也可能调整。若需要向前兼容,请捕获基类 `errors.DashScopeError`。 + 失败默认抛出类型化的 `DashScopeError`(非 2xx 的 HTTP 状态码,以及 HTTP 200 但业务报错,都会归入这里): ```python diff --git a/dashscope/cli/__init__.py b/dashscope/cli/__init__.py index 93de0d15..244d227b 100644 --- a/dashscope/cli/__init__.py +++ b/dashscope/cli/__init__.py @@ -489,13 +489,13 @@ def _register_rl_app(): def _rl_unavailable_detail(exception: Exception) -> str: """Render a deferred rl import failure as an actionable message.""" - # The message quotes a literal 'dashscope[rl]'; unescaped, rich reads - # [rl] as a style tag and prints an install command with no extras. + # Unescaped, rich reads a bracketed run in the exception text as a style + # tag and drops it from the printed output. detail = escape(str(exception)) if "pip install" not in detail: detail += ( - ". Install the optional dependencies with: " - "[bold]pip install 'dashscope\\[rl]'[/bold]" + ". Reinstall to pull in the missing dependencies: " + "[bold]pip install -U dashscope[/bold]" ) return detail diff --git a/dashscope/finetune/reinforcement/__init__.py b/dashscope/finetune/reinforcement/__init__.py index cbe8d459..bd4d16c5 100644 --- a/dashscope/finetune/reinforcement/__init__.py +++ b/dashscope/finetune/reinforcement/__init__.py @@ -5,8 +5,8 @@ import yaml # noqa: F401 except ImportError as _rl_dep_err: raise ImportError( - "Agentic RL fine-tuning needs optional dependencies. " - "Install them with: pip install 'dashscope[rl]'", + "Agentic RL fine-tuning dependencies are missing from this " + "install. Reinstall with: pip install -U dashscope", ) from _rl_dep_err from dashscope.finetune.reinforcement.common.constants import ( diff --git a/dashscope/finetune/reinforcement/component/observability/processor_span.py b/dashscope/finetune/reinforcement/component/observability/processor_span.py index 95b3005d..65fc3824 100644 --- a/dashscope/finetune/reinforcement/component/observability/processor_span.py +++ b/dashscope/finetune/reinforcement/component/observability/processor_span.py @@ -102,12 +102,9 @@ def _run_with_span( if tracer is None or not _OTEL_SPAN_API: if is_tracing_enabled() and tracer is None: logger.warning( - ( - "ENABLE_TRAJECTORY is set but " - "OpenTelemetry is not " - "installed. " - "pip install 'dashscope[agentic_rl_tracing]'" - ), + "ENABLE_TRAJECTORY is set but " + "OpenTelemetry is not installed. " + "Reinstall the SDK with: pip install -U dashscope", ) return fn(self, input_data, *args, **kwargs) diff --git a/dashscope/finetune/reinforcement/component/observability/tracing.py b/dashscope/finetune/reinforcement/component/observability/tracing.py index 8c65d3c8..1da284b7 100644 --- a/dashscope/finetune/reinforcement/component/observability/tracing.py +++ b/dashscope/finetune/reinforcement/component/observability/tracing.py @@ -2,8 +2,7 @@ """ OpenTelemetry tracing for rollout / reward processors. -Enable tracing (install OpenTelemetry, e.g. -``pip install 'dashscope[agentic_rl_tracing]'``): +OpenTelemetry ships with the SDK; enable tracing with: - ``ENABLE_TRAJECTORY=true`` @@ -752,8 +751,8 @@ def trace_processor_process( if not _OTEL_AVAILABLE: logger.warning( "ENABLE_TRAJECTORY is set but " - "OpenTelemetry is not installed. Install with: " - "pip install 'dashscope[agentic_rl_tracing]'", + "OpenTelemetry is not installed. Reinstall the SDK with: " + "pip install -U dashscope", ) return processor.process(input_data) @@ -796,8 +795,8 @@ async def async_trace_processor_process( if not _OTEL_AVAILABLE: logger.warning( "ENABLE_TRAJECTORY is set but " - "OpenTelemetry is not installed. Install with: " - "pip install 'dashscope[agentic_rl_tracing]'", + "OpenTelemetry is not installed. Reinstall the SDK with: " + "pip install -U dashscope", ) return await processor.process(input_data) diff --git a/dashscope/finetune/reinforcement/examples/observability/smoke_observability.py b/dashscope/finetune/reinforcement/examples/observability/smoke_observability.py index 73fdcaa5..d34cc349 100644 --- a/dashscope/finetune/reinforcement/examples/observability/smoke_observability.py +++ b/dashscope/finetune/reinforcement/examples/observability/smoke_observability.py @@ -13,7 +13,7 @@ - `trace_tool(...)`: tool instrumentation (one canonical shape) Prerequisites (example): - pip install -e ".[agentic_rl_tracing]" + pip install -e . pip install loongsuite-util-genai Run: diff --git a/requirements-test.txt b/requirements-test.txt index 8cc6117f..e034ab94 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -9,7 +9,7 @@ coverage pydantic>=2.0,<3.0 tenacity typing_extensions -# Optional extras exercised by tests/unit (cli, acli, rl) +# Optional extras exercised by tests/unit (cli, acli) typer>=0.9.0 rich>=13.0.0 prompt-toolkit>=3.0 diff --git a/requirements.txt b/requirements.txt index 79ae6161..62c1e161 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,10 @@ rich>=13.0.0 httpx>=0.27.0 httpx-sse>=0.4.0 typing_extensions>=4.16.0 +tiktoken +pydantic>=2.0 +tenacity +PyYAML>=6.0 +fastapi>=0.100 +uvicorn>=0.20 +opentelemetry-sdk>=1.20 diff --git a/setup.py b/setup.py index e3fbb8ef..12345c1b 100644 --- a/setup.py +++ b/setup.py @@ -101,7 +101,6 @@ def run(self): install_requires=get_dependencies(), include_package_data=True, extras_require={ - "tokenizer": ["tiktoken"], # Interactive AI assistant (dashscope.acli); typer/rich are core deps "acli": [ "prompt-toolkit>=3.0", @@ -124,15 +123,6 @@ def run(self): "numpy>=1.20", "opencv-python-headless>=4.5", ], - # Agentic RL fine-tuning (dashscope.finetune.reinforcement) - "rl": [ - "pydantic>=2.0", - "tenacity", - "PyYAML>=6.0", - "fastapi>=0.100", - "uvicorn>=0.20", - "opentelemetry-sdk>=1.20", - ], }, zip_safe=False, cmdclass=cmdclass, diff --git a/tests/unit/test_cli_main.py b/tests/unit/test_cli_main.py index 22f9c341..aac880ae 100644 --- a/tests/unit/test_cli_main.py +++ b/tests/unit/test_cli_main.py @@ -267,15 +267,15 @@ def test_rl_import_failure_is_silent_until_the_command_is_used( monkeypatch, capsys, ): - # `rl` is an optional extra, so importing dashscope.cli must not tell + # The rl import is deferred, so importing dashscope.cli must not tell # the user about a dependency they may never ask for. monkeypatch.setattr(dashscope.cli, "_RL_IMPORT_ERROR", None) monkeypatch.setitem( sys.modules, "dashscope.cli.agentic_rl", _ImportErrorOnApp( - "Agentic RL fine-tuning needs optional dependencies. " - "Install them with: pip install 'dashscope[rl]'", + "Agentic RL fine-tuning dependencies are missing from this " + "install. Reinstall with: pip install -U dashscope", ), ) @@ -284,16 +284,19 @@ def test_rl_import_failure_is_silent_until_the_command_is_used( assert capsys.readouterr().err == "" assert isinstance(dashscope.cli._RL_IMPORT_ERROR, ImportError) - def test_rl_command_keeps_the_extras_name(self, monkeypatch, capsys): - # rich reads a literal [rl] as a style tag and drops it, which used to - # print `pip install 'dashscope'` — a command that installs none of - # the extras the message is about. + def test_rl_command_prints_the_install_command_verbatim( + self, + monkeypatch, + capsys, + ): + # The error already carries its own remedy, so the fallback hint in + # _rl_unavailable_detail must not be appended a second time. monkeypatch.setattr( dashscope.cli, "_RL_IMPORT_ERROR", ImportError( - "Agentic RL fine-tuning needs optional dependencies. " - "Install them with: pip install 'dashscope[rl]'", + "Agentic RL fine-tuning dependencies are missing from this " + "install. Reinstall with: pip install -U dashscope", ), ) monkeypatch.setattr(sys, "argv", ["dashscope", "rl", "list"]) @@ -303,8 +306,8 @@ def test_rl_command_keeps_the_extras_name(self, monkeypatch, capsys): assert exception_info.value.code == 1 err = " ".join(capsys.readouterr().err.split()) - assert "pip install 'dashscope[rl]'" in err - assert err.count("Install") == 1 + assert "pip install -U dashscope" in err + assert err.count("Reinstall") == 1 def test_rl_command_adds_a_hint_when_the_error_has_none( self, @@ -323,9 +326,9 @@ def test_rl_command_adds_a_hint_when_the_error_has_none( err = " ".join(capsys.readouterr().err.split()) assert "No module named 'typer_x'" in err - assert "pip install 'dashscope[rl]'" in err + assert "pip install -U dashscope" in err - def test_unrelated_command_is_not_told_about_missing_rl_extras( + def test_unrelated_command_is_not_told_about_missing_rl_dependencies( self, monkeypatch, capsys, @@ -333,7 +336,7 @@ def test_unrelated_command_is_not_told_about_missing_rl_extras( monkeypatch.setattr( dashscope.cli, "_RL_IMPORT_ERROR", - ImportError("pip install 'dashscope[rl]'"), + ImportError("Reinstall with: pip install -U dashscope"), ) monkeypatch.setattr(sys, "argv", ["dashscope"]) monkeypatch.setattr(