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 功能并不等于一次成功的文本生成。更可靠的设计是:用系统指令约束职责,用参数控制响应范围,用结构化格式连接后续程序,再用普通后端工程手段验证、监控和兜底。