💻 源码
# ============================================================
# 示例:用 OpenAI SDK 调用阿里云百炼(通义千问)大模型
# 整体流程:导入库 → 创建客户端 → 构造消息 → 发起请求 → 流式打印
# ============================================================

# from:Python 的「从…导入…」语法,从指定模块中引入需要的类/函数
# openai:OpenAI 官方 Python 包,提供统一的 chat.completions 调用方式
# OpenAI:包里的客户端类,用来连接大模型 API 并发送请求
from openai import OpenAI

# import os:导入 Python 标准库 os,用于读取操作系统环境变量
import os

# ------------------------------------------------------------------
# 第 1 步:创建 API 客户端(client = 客户端对象,后续所有请求都通过它发起)
# ------------------------------------------------------------------
client = OpenAI(
    # api_key:API 密钥,相当于「账号密码」,服务端凭此识别你的身份并计费
    # os.getenv("DASHSCOPE_API_KEY"):从系统环境变量中读取名为 DASHSCOPE_API_KEY 的值
    # 好处:密钥不写死在代码里,更安全;若未配置环境变量,此处返回 None
    # 备选写法(仅本地调试):api_key="sk-你的百炼密钥"
    api_key=os.getenv("DASHSCOPE_API_KEY"),

    # # 不要直接把你的key写进代码,安全的方式是用环境变量保存
    # api_key = "123550090124",

    # base_url:API 服务的基础地址(根 URL)
    # 阿里云百炼提供「OpenAI 兼容模式」,所以可以用 OpenAI SDK 直接调用
    # /compatible-mode/v1 表示兼容 OpenAI v1 接口规范
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)

# ------------------------------------------------------------------
# 第 2 步:构造对话消息(messages = 消息列表,模拟多轮对话)
# ------------------------------------------------------------------
# messages:列表(list),每个元素是一条消息,用字典(dict)表示
# role:角色,常见取值:
#   - "user"     → 用户说的话
#   - "assistant"→ 模型之前的回复(多轮对话时带上,模型才能「记住」上下文)
#   - "system"   → 系统提示词,用来设定模型的人设、规则、输出格式等
# content:该条消息的具体文本内容
messages = [{"role": "user", "content": "你是谁"}]

# ------------------------------------------------------------------
# 第 3 步:发起聊天补全请求(completion = 补全/生成结果)
# client.chat.completions.create(...):OpenAI SDK 的标准聊天接口
# ------------------------------------------------------------------
completion = client.chat.completions.create(
    # model:指定要调用的模型名称,不同模型能力、价格、速度不同
    model="qwen3.6-flash",

    # messages:传入上面构造好的对话历史,模型会根据这些内容生成回复
    messages=messages,

    # extra_body:额外请求体参数,会原样附加到 HTTP 请求 JSON 中
    # enable_thinking: True → 开启「深度思考」模式,模型会先输出思考过程再给出最终答案
    # 思考内容在流式响应里通过 reasoning_content 字段返回(见下方循环)
    extra_body={"enable_thinking": True},

    # stream=True:开启流式输出(Streaming)
    # True 表示不一次性返回完整结果,而是像打字一样逐块(chunk)推送
    # 好处:用户能更快看到首字,体验更流畅;适合长回复场景
    stream=True
)

# ------------------------------------------------------------------
# 第 4 步:逐块读取流式响应并打印
# ------------------------------------------------------------------

# is_answering:布尔标志(False/True),用来区分当前处于哪个输出阶段
# False → 还在输出「思考过程」;True → 已进入「正式回复」阶段
is_answering = False

# print:向控制台输出文字
# "\n":换行符; "=" * 20:把 "=" 重复 20 次,用作分隔线,让输出更易读
print("\n" + "=" * 20 + "思考过程" + "=" * 20)

# for chunk in completion:遍历流式返回的每一个数据块
# chunk:单次推送的一小段 JSON 数据,可能只含几个 token(字/词片段)
for chunk in completion:

    # 流式结束时,服务端可能发送一个 choices 为空的 chunk(例如只含 token 用量统计)
    # 若直接访问 chunk.choices[0] 会报 IndexError,因此先判断是否为空
    # not chunk.choices:列表为空时条件为 True
    # continue:跳过本次循环,直接进入下一个 chunk
    if not chunk.choices:
        continue

    # chunk.choices:候选回复列表,通常只有 1 个元素(索引 0)
    # .delta:本次 chunk 相对于上一次的「增量变化」,不是完整内容,而是新增片段
    delta = chunk.choices[0].delta

    # ---------- 处理「思考过程」片段 ----------
    # hasattr(obj, "attr"):检查对象 obj 是否有名为 attr 的属性(防止旧版 SDK 无此字段报错)
    # delta.reasoning_content:深度思考模式下,模型内部推理过程的文本片段
    # is not None:排除字段存在但值为 None 的情况
    if hasattr(delta, "reasoning_content") and delta.reasoning_content is not None:
        # 只有还没进入正式回复阶段时,才打印思考内容
        if not is_answering:
            # end="":打印后不自动换行,让多个 chunk 的内容拼接成一行/一段
            # flush=True:立刻刷新输出缓冲区,确保文字实时显示(不等缓冲区满)
            print(delta.reasoning_content, end="", flush=True)

    # ---------- 处理「正式回复」片段 ----------
    # delta.content:模型最终回复正文的增量片段
    # and delta.content:同时排除空字符串,避免打印无意义空内容
    if hasattr(delta, "content") and delta.content:
        # 第一次收到正式回复时,打印分隔标题并切换阶段标志
        if not is_answering:
            print("\n" + "=" * 20 + "完整回复" + "=" * 20)
            is_answering = True  # 标记:此后不再打印思考内容
        print(delta.content, end="", flush=True)

# 循环结束后程序正常退出,无额外代码