第一次调用大模型 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 和对话记忆。它们解决的问题不同,不能只用一个“模型会查资料”带过。