用 Python 调用 Claude API:系统指令、响应控制与结构化 JSON

2026-09-22 15 预计阅读时间: 1 分钟
来源: realpython.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

Claude API 的基础调用并不复杂:安装 Python SDK、发送一组消息,再从响应中读取文本即可。真正影响应用稳定性的,是如何划分系统指令与用户输入、如何限制输出规模,以及如何把自然语言响应转换成程序可以继续处理的结构化数据。

下面从一个可直接运行的脚本开始,再逐步补上生产环境中需要考虑的边界。

从最小调用开始

安装官方 Python SDK:

python -m pip install anthropic
export ANTHROPIC_API_KEY="your-api-key"

将下面代码保存为 app.py。如果你的账户使用其他模型,可通过 CLAUDE_MODEL 环境变量替换示例模型名。

import os
from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

message = client.messages.create(
    model=os.getenv("CLAUDE_MODEL", "claude-sonnet-4-5"),
    max_tokens=500,
    messages=[
        {
            "role": "user",
            "content": "请用三个要点解释什么是幂等 API。",
        }
    ],
)

text = "".join(
    block.text
    for block in message.content
    if block.type == "text"
)

print(text)

运行:

python app.py

这里有两个值得注意的参数:

  • max_tokens 控制本次响应最多生成多少 token,可防止回答无限扩展,也直接影响延迟和成本。
  • messages 保存当前请求中的对话内容。多轮会话通常由应用自行保存历史消息,并在下一次调用时重新提交。

不要假设响应永远只有一个文本块。示例通过遍历 message.content 收集所有 text 类型内容,比直接读取第一个元素更稳妥。

用系统指令固定模型的工作方式

用户消息描述“这次要做什么”,系统指令则定义“始终应该怎样做”。例如,一个代码审查服务可以要求 Claude 始终关注安全性,并限制回答格式:

message = client.messages.create(
    model=os.getenv("CLAUDE_MODEL", "claude-sonnet-4-5"),
    max_tokens=800,
    temperature=0,
    system=(
        "你是一名资深 Python 代码审查工程师。"
        "优先检查安全漏洞、资源泄漏和异常处理。"
        "不要改写整份代码,只列出问题、风险等级和修复建议。"
    ),
    messages=[
        {
            "role": "user",
            "content": "请审查以下代码:\n\n"
                       "def load(path):\n"
                       "    return open(path).read()",
        }
    ],
)

把长期规则放在顶层 system 参数中,而不是混入每一条用户消息,有几个实际好处:职责更清晰、模板更容易复用,也能降低用户输入意外覆盖业务规则的概率。

不过,系统指令不是传统意义上的权限隔离机制。API 密钥、数据库凭据和内部令牌不应放进提示词;真正的授权、输入校验和数据访问控制仍要由应用代码完成。

让响应成为可解析的 JSON

聊天界面可以直接展示自然语言,但后端通常需要明确字段。例如,工单分类服务可能希望得到类别、优先级、摘要和标签。

下面是一份完整示例。它通过系统指令声明 JSON 结构,并在本地使用 json.loads 做强制校验:

import json
import os
import sys
from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
model = os.getenv("CLAUDE_MODEL", "claude-sonnet-4-5")

SYSTEM_PROMPT = """
你是工单分类器。只返回一个合法 JSON 对象,不要返回 Markdown、解释或代码围栏。
对象必须符合以下结构:
{
  "category": "billing | account | bug | other",
  "priority": "low | medium | high",
  "summary": "不超过 50 个汉字的摘要",
  "tags": ["字符串标签"]
}
如果信息不足,使用最接近的 category,并在 tags 中加入 "needs-review"。
""".strip()


def classify_ticket(ticket: str) -> dict:
    response = client.messages.create(
        model=model,
        max_tokens=300,
        temperature=0,
        system=SYSTEM_PROMPT,
        messages=[{"role": "user", "content": ticket}],
    )

    raw_text = "".join(
        block.text
        for block in response.content
        if block.type == "text"
    ).strip()

    try:
        result = json.loads(raw_text)
    except json.JSONDecodeError as exc:
        raise RuntimeError(f"Claude 返回了无效 JSON:{raw_text}") from exc

    required = {"category", "priority", "summary", "tags"}
    missing = required - result.keys()
    if missing:
        raise RuntimeError(f"响应缺少字段:{sorted(missing)}")

    if result["category"] not in {"billing", "account", "bug", "other"}:
        raise RuntimeError("category 值不在允许范围内")

    if result["priority"] not in {"low", "medium", "high"}:
        raise RuntimeError("priority 值不在允许范围内")

    if not isinstance(result["tags"], list):
        raise RuntimeError("tags 必须是数组")

    return result


if __name__ == "__main__":
    ticket = " ".join(sys.argv[1:]) or "付款成功,但专业版功能仍然没有开通。"
    result = classify_ticket(ticket)
    print(json.dumps(result, ensure_ascii=False, indent=2))

运行时可以直接传入工单内容:

python app.py "登录后一直返回 500,团队成员都无法进入控制台"

可能得到:

{
  "category": "bug",
  "priority": "high",
  "summary": "团队登录控制台时持续出现 500 错误",
  "tags": [
    "login",
    "server-error",
    "team-impact"
  ]
}

关键点不只是要求模型“返回 JSON”,而是同时定义字段、枚举值、长度约束和信息不足时的行为。即便如此,提示词约束也不能替代程序校验。模型响应可能被截断、字段可能缺失,或者上游输入可能诱导模型偏离格式,因此必须在业务边界执行解析和验证。

如果当前使用的 Claude API 版本和模型支持原生结构化输出或 JSON Schema,可以进一步将结构约束交给 API;具体参数应以所安装 SDK 版本为准。即使使用原生约束,业务枚举、权限和数据一致性仍建议在服务端再次检查。

从示例脚本走向生产服务

把调用嵌入真实系统时,可以按下面的清单补齐工程能力:

  • 密钥管理:通过环境变量或密钥管理服务注入,不要提交到 Git,也不要打印到日志。
  • 超时与重试:只对限流、网络抖动和部分服务端错误做带退避的有限重试;避免对所有错误无限重放。
  • 输出上限:根据任务设置合理的 max_tokens,并处理响应因长度限制而不完整的情况。
  • 结构校验:使用 json.loads、Pydantic 或 JSON Schema 验证类型、必填字段和枚举值。
  • 可观测性:记录请求耗时、模型名、token 使用量和错误类型,但对用户内容及模型输出做脱敏。
  • 提示词版本化:像管理代码一样管理系统指令,记录版本并使用固定测试集回归验证。
  • 人工兜底:涉及付款、账户封禁、医疗或法律判断时,不要让模型输出直接触发不可逆操作。

Claude API 可以很快接入,但稳定的 AI 功能并不等于一次成功的文本生成。更可靠的设计是:用系统指令约束职责,用参数控制响应范围,用结构化格式连接后续程序,再用普通后端工程手段验证、监控和兜底。


相关推荐