Administrator
发布于 2026-07-18 / 1 阅读
0
0

02-用 UV 写出第一个可追踪的百炼 API 调用

English
中文

第一次调用大模型 API,真正容易出问题的并不一定是 Prompt。密钥被写进代码、模型名抄错、网络失败没有日志,这些问题都有可能会让一个能运行的示例很快变成难维护的脚本。

我们先做这个:把一句用户评价分类为“正向”“负向”或“中性”。输入固定,输出也固定,适合检查环境、认证和代码骨架。

准备 UV 项目

在空目录执行:

uv init --python 3.10
uv add openai

百炼提供 OpenAI 兼容接口,所以示例使用 OpenAI Python SDK。兼容不等于所有扩展参数都相同,后续遇到联网搜索等平台能力,仍要对照百炼文档。

把 API Key 写入当前终端环境,不要写进 Python 文件:

export DASHSCOPE_API_KEY="替换为你自己的密钥"
export DASHSCOPE_MODEL="qwen-plus"

终端关闭后变量通常会失效。需要长期配置时使用系统密钥管理或部署平台的 Secret 功能,不要把密钥提交到 Git。

写一个能排错的最小程序

创建 main.py

"""调用百炼兼容接口完成情感分类。"""

import logging
import os
import sys

from openai import APIConnectionError, APIStatusError, OpenAI


# 日志只记录运行阶段和错误类型,禁止输出 API Key 与完整请求头。
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
)
LOGGER = logging.getLogger(__name__)


def classify_sentiment(text: str) -> str:
    """分类一段文本;text 是待分析内容,返回三个允许标签之一。"""
    api_key = os.getenv("DASHSCOPE_API_KEY")
    model = os.getenv("DASHSCOPE_MODEL", "qwen-plus")

    # 认证信息缺失时立即停止,避免发出注定失败的网络请求。
    if not api_key:
        raise ValueError("缺少 DASHSCOPE_API_KEY 环境变量")
    if not text.strip():
        raise ValueError("待分类文本不能为空")

    client = OpenAI(
        api_key=api_key,
        base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
        timeout=30.0,
        max_retries=2,
    )

    # system 消息限定任务,user 消息只承载本次输入。
    response = client.chat.completions.create(
        model=model,
        temperature=0,
        messages=[
            {
                "role": "system",
                "content": "把用户评价分类为正向、负向或中性,只输出一个标签。",
            },
            {"role": "user", "content": text},
        ],
    )

    result = (response.choices[0].message.content or "").strip()
    allowed = {"正向", "负向", "中性"}

    # 模型输出属于外部输入,使用前必须验证,不能默认它遵守格式。
    if result not in allowed:
        raise ValueError(f"模型返回了未允许的标签:{result!r}")
    return result


def main() -> int:
    """运行示例并把异常转为可追踪日志;返回值交给系统作为退出码。"""
    try:
        result = classify_sentiment("包装完好,送达也很快。")
        LOGGER.info("分类完成,结果=%s", result)
        print(result)
        return 0
    except APIConnectionError as exc:
        LOGGER.error("无法连接模型服务:%s", type(exc).__name__)
    except APIStatusError as exc:
        LOGGER.error("模型服务返回错误状态:status=%s", exc.status_code)
    except (ValueError, IndexError, AttributeError) as exc:
        LOGGER.error("输入、配置或响应校验失败:%s", exc)
    except Exception:
        # 未预料异常保留堆栈,便于定位;日志仍不得包含密钥。
        LOGGER.exception("调用出现未预料异常")
    return 1


if __name__ == "__main__":
    sys.exit(main())

运行:

uv run python main.py

正常情况下,终端会输出 正向,日志里能看到分类完成。实际措辞由模型和服务版本决定,但经过校验后,程序只接受三个约定标签。

主动验证失败路径

先临时取消密钥:

unset DASHSCOPE_API_KEY
uv run python main.py

程序应记录“缺少 DASHSCOPE_API_KEY”,以非零状态退出,而不是打印一长串难懂的 SDK 堆栈。再恢复密钥,把模型变量改成一个不存在的 ID,确认服务状态错误也会进入日志。

这两个失败测试很重要。只验证成功路径,无法证明程序在密钥过期、模型下线或网络中断时还能给运维留下线索。

这份骨架还缺什么

它适合学习和小型脚本,不等于生产服务。进入线上环境前还要补充请求追踪 ID、指标、限流、并发控制、日志脱敏和按业务决定的重试策略。分类结果也应进入业务规则校验,不能因为模型返回了合法标签就自动触发高风险操作。

下一篇会在这个骨架上区分联网搜索、RAG 和对话记忆。它们解决的问题不同,不能只用一个“模型会查资料”带过。


评论