调用 Claude API 并不只是把一段文字发给模型。一个可维护的 Python 集成至少要处理三件事:正确使用 Anthropic SDK、区分系统指令与用户输入,以及把模型返回的文本转换成经过验证的数据结构。
下面通过一个“小测验批改器”串起这些概念,并说明哪些地方最容易出错。
先建立正确的消息模型
一次典型调用包含两类输入:
system:定义模型的角色、约束和输出规则。messages:保存用户与助手之间的对话内容。
例如,“你是一名 Python 教师”属于长期行为约束,应放在 system 中;“Pydantic 的作用是什么?”才是本轮用户问题。
这种分离不只是代码风格问题。它能避免业务规则与用户输入混在一起,也方便复用同一套系统提示词处理多次请求。
在 Python 中,核心调用形态如下:
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=300,
system="你是一名严谨的 Python 教师。",
messages=[
{
"role": "user",
"content": "请用两句话解释 Pydantic 的主要用途。",
}
],
)
print(response.content[0].text)
Anthropic() 默认可以从 ANTHROPIC_API_KEY 环境变量读取密钥。模型名称可能随账号权限和 API 版本变化,因此生产项目最好把它放进配置,而不是散落在代码中。
可运行示例:让 Claude 返回可验证的测验结果
模型生成 JSON,不代表 JSON 一定满足业务要求。字段可能缺失,数字可能越界,甚至整段响应可能不是合法 JSON。Pydantic 的价值在于把这些问题变成明确的验证错误。
下面是一份可以直接改造的最小项目。
1. 安装依赖
python -m venv .venv
source .venv/bin/activate
python -m pip install anthropic pydantic
export ANTHROPIC_API_KEY="替换为你的_API_Key"
export CLAUDE_MODEL="claude-sonnet-4-5"
Windows PowerShell 可使用:
.venv\Scripts\Activate.ps1
$env:ANTHROPIC_API_KEY="替换为你的_API_Key"
$env:CLAUDE_MODEL="claude-sonnet-4-5"
如果你的账号不支持示例中的模型,请将 CLAUDE_MODEL 换成可用的 Claude 模型标识。
2. 创建 quiz.py
import json
import os
import sys
from anthropic import Anthropic
from pydantic import BaseModel, Field, ValidationError
class QuizResult(BaseModel):
answer: str = Field(min_length=1)
confidence: float = Field(ge=0.0, le=1.0)
concepts: list[str] = Field(min_length=1, max_length=3)
def ask_claude(question: str) -> QuizResult:
schema = json.dumps(QuizResult.model_json_schema(), ensure_ascii=False)
system_prompt = f"""你是一名 Python API 教师。
回答用户的技术问题,并且只输出一个 JSON 对象。
不要添加 Markdown 代码围栏、标题或解释性前缀。
输出必须符合以下 JSON Schema:
{schema}
"""
client = Anthropic()
response = client.messages.create(
model=os.getenv("CLAUDE_MODEL", "claude-sonnet-4-5"),
max_tokens=500,
temperature=0,
system=system_prompt,
messages=[
{
"role": "user",
"content": question,
}
],
)
raw_text = "".join(
block.text
for block in response.content
if block.type == "text"
)
return QuizResult.model_validate_json(raw_text)
if __name__ == "__main__":
question = (
sys.argv[1]
if len(sys.argv) > 1
else "在 Claude API 调用中,system prompt 和 user message 有什么区别?"
)
try:
result = ask_claude(question)
print(result.model_dump_json(indent=2))
except ValidationError as exc:
print("模型返回了 JSON,但没有通过结构验证:", file=sys.stderr)
print(exc, file=sys.stderr)
raise SystemExit(1)
运行:
python quiz.py
python quiz.py "为什么不能直接信任大模型返回的 JSON?"
输出形态类似:
{
"answer": "system prompt 定义全局角色和行为约束,而 user message 表示用户在当前轮次提出的具体请求。",
"confidence": 0.98,
"concepts": [
"system prompt",
"user message",
"角色分离"
]
}
这里的关键不是让模型“看起来像”在输出结构化数据,而是执行 QuizResult.model_validate_json()。只有 JSON 语法、字段类型和取值范围都满足模型定义,程序才会得到 QuizResult 对象。
三个容易答错的检查题
system prompt 应不应该塞进第一条 user message?
技术上可以把说明写进用户文本,但这会混淆职责。稳定的角色、语气、边界和输出规范更适合放在 system 参数中;每轮变化的问题放在 messages 中。
response.content[0].text 永远安全吗?
简单示例中经常这样写,但更稳妥的实现应遍历内容块并只提取文本块。响应未来可能包含不同类型的内容,业务代码不应默认第一个块一定是文本。
有了 Pydantic,模型就一定返回正确答案吗?
不会。Pydantic 验证的是结构与约束,而不是事实正确性。confidence 位于 0 到 1 之间,不代表模型对置信度的判断可靠;answer 是字符串,也不代表答案没有事实错误。
因此需要区分三层质量:
- JSON 是否可解析。
- 数据是否满足 schema。
- 内容是否真实、相关并符合业务规则。
Pydantic主要解决前两层中的结构验证问题,第三层通常还需要规则检查、检索、人工审核或测试样例。
从演示代码走向生产环境
这个示例采用“提示模型输出 JSON,再由 Pydantic 验证”的实践方式。它清晰易懂,但仍要为失败路径做设计:
- 捕获 API 超时、限流和认证错误。
- 对验证失败设置有限次数的重试,而不是无限重试。
- 重试时把验证错误反馈给模型,要求只修正格式。
- 记录请求 ID、模型名、耗时和验证结果,但不要泄露密钥或敏感提示词。
- 为提示词和 Pydantic 模型建立版本号,避免升级字段后无法解释旧数据。
- 对用户输入设置长度限制,并根据数据敏感程度决定是否允许发送给外部模型。
一个实用的上线检查表是:密钥是否来自环境或密钥管理服务,模型名是否可配置,输出是否经过验证,异常是否可观测,重试是否有上限,关键答案是否还有业务层校验。
掌握 Anthropic SDK 的调用只是起点。真正可靠的 Claude 应用,会把 system prompt 当作行为契约,把用户消息当作动态输入,再用 Pydantic 把自然语言输出收束为程序可以安全处理的数据。