📌 内容摘要

  • 使用 Anthropic 官方 Python SDK,10行代码完成第一次调用。
  • 覆盖7个核心场景:基础调用、System Prompt、多轮对话、流式输出、异步调用、图片理解、错误处理。
  • 所有代码示例均可直接复制运行,附详细注释说明每个参数的作用。
  • 文末附生产环境最佳实践:重试机制、并发控制、成本优化。

一、环境准备

Python 版本要求

Anthropic Python SDK 要求 Python 3.8 及以上版本。推荐使用 Python 3.11+。

python --version  # 确认版本 ≥ 3.8

安装 SDK

pip install anthropic

# 如果需要异步支持(已包含在主包中,无需单独安装)
# 如果使用图片处理,建议同时安装
pip install httpx

配置 API Key

推荐使用环境变量存储 Key,不要写死在代码里:

# 方式一:终端临时设置(仅当前会话有效)
export ANTHROPIC_API_KEY="sk-ant-api03-你的key"

# 方式二:写入 .env 文件(推荐,配合 python-dotenv)
# .env 文件内容:
# ANTHROPIC_API_KEY=sk-ant-api03-你的key

# 安装 dotenv
pip install python-dotenv
from dotenv import load_dotenv
import os

load_dotenv()  # 自动读取 .env 文件
api_key = os.environ.get("ANTHROPIC_API_KEY")

二、基础调用

最简示例(10行代码)

import anthropic

# 初始化客户端(自动读取环境变量 ANTHROPIC_API_KEY)
client = anthropic.Anthropic()

# 发送消息
message = client.messages.create(
    model="claude-sonnet-4-6",       # 模型名称
    max_tokens=1024,                  # 最大输出 token 数
    messages=[
        {"role": "user", "content": "你好,请用一句话自我介绍"}
    ]
)

# 获取回复文本
print(message.content[0].text)

完整响应对象说明

print(message.id)                      # 请求唯一ID
print(message.model)                   # 实际使用的模型
print(message.role)                    # 始终是 "assistant"
print(message.content[0].text)         # 回复文本内容
print(message.stop_reason)             # 停止原因:end_turn / max_tokens
print(message.usage.input_tokens)      # 输入消耗 token 数
print(message.usage.output_tokens)     # 输出消耗 token 数

三、System Prompt 设置

System Prompt 在整个对话中持续生效,用于设定角色、风格、规则:

message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=2048,
    system="""你是一名资深 Python 工程师,专注于代码质量和最佳实践。
回答规则:
- 优先给出可运行的代码示例
- 代码加上类型注解
- 指出潜在的性能问题或安全隐患
- 回答简洁,避免不必要的废话""",
    messages=[
        {"role": "user", "content": "如何安全地读取一个可能不存在的配置文件?"}
    ]
)

print(message.content[0].text)

四、多轮对话

Claude API 是无状态的,每次请求需要把完整对话历史传入:

import anthropic
from typing import List, Dict

client = anthropic.Anthropic()

class ChatSession:
    def __init__(self, system: str = ""):
        self.system = system
        self.history: List[Dict] = []

    def chat(self, user_input: str) -> str:
        # 追加用户消息到历史
        self.history.append({
            "role": "user",
            "content": user_input
        })

        # 发送完整历史
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=2048,
            system=self.system,
            messages=self.history
        )

        assistant_reply = response.content[0].text

        # 追加 AI 回复到历史
        self.history.append({
            "role": "assistant",
            "content": assistant_reply
        })

        return assistant_reply

    def clear(self):
        self.history = []


# 使用示例
session = ChatSession(system="你是一个友善的 AI 助手,记住用户说过的信息。")

print(session.chat("我叫小明,是一名后端工程师"))
print(session.chat("我主要用什么语言?"))   # Claude 会记住上文
print(session.chat("给我推荐一个适合我的项目管理工具"))

五、流式输出(Streaming)

流式输出让内容逐字符实时显示,适合构建聊天界面:

import anthropic

client = anthropic.Anthropic()

# 方式一:使用 stream 上下文管理器(推荐)
with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=2048,
    messages=[
        {"role": "user", "content": "写一篇300字的关于秋天的散文"}
    ]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

print()  # 换行

# 获取完整响应统计(流结束后可用)
final_message = stream.get_final_message()
print(f"\n输入 tokens: {final_message.usage.input_tokens}")
print(f"输出 tokens: {final_message.usage.output_tokens}")
# 方式二:手动处理事件流(更精细的控制)
with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "写一首短诗"}]
) as stream:
    for event in stream:
        if event.type == "content_block_delta":
            if event.delta.type == "text_delta":
                print(event.delta.text, end="", flush=True)
        elif event.type == "message_stop":
            print("\n[生成完毕]")

六、异步调用(AsyncAnthropic)

在异步应用(如 FastAPI、aiohttp)中使用异步客户端:

import asyncio
import anthropic

client = anthropic.AsyncAnthropic()

async def ask_claude(question: str) -> str:
    message = await client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": question}]
    )
    return message.content[0].text

async def main():
    # 并发发送多个请求(比顺序发送快得多)
    questions = [
        "Python 的 GIL 是什么?",
        "解释一下装饰器",
        "什么是上下文管理器?"
    ]

    tasks = [ask_claude(q) for q in questions]
    answers = await asyncio.gather(*tasks)

    for q, a in zip(questions, answers):
        print(f"Q: {q}")
        print(f"A: {a[:100]}...")  # 只打印前100字
        print()

asyncio.run(main())

七、图片理解(Vision)

import anthropic
import base64
from pathlib import Path

client = anthropic.Anthropic()

# 方式一:传入本地图片(base64编码)
def ask_about_image(image_path: str, question: str) -> str:
    image_data = Path(image_path).read_bytes()
    base64_image = base64.standard_b64encode(image_data).decode("utf-8")

    # 根据文件扩展名判断媒体类型
    ext = Path(image_path).suffix.lower()
    media_type_map = {
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".png": "image/png",
        ".gif": "image/gif",
        ".webp": "image/webp"
    }
    media_type = media_type_map.get(ext, "image/jpeg")

    message = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": media_type,
                            "data": base64_image,
                        },
                    },
                    {
                        "type": "text",
                        "text": question
                    }
                ],
            }
        ],
    )
    return message.content[0].text

# 使用示例
# result = ask_about_image("screenshot.png", "图片里有什么内容?")
# print(result)

# 方式二:传入图片 URL(更简单)
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "url",
                        "url": "https://example.com/image.jpg",
                    },
                },
                {"type": "text", "text": "描述这张图片"}
            ],
        }
    ],
)
print(message.content[0].text)

八、错误处理

import anthropic
import time

client = anthropic.Anthropic()

def call_claude_with_retry(
    messages: list,
    model: str = "claude-sonnet-4-6",
    max_tokens: int = 1024,
    max_retries: int = 3
) -> str:
    """带重试机制的 Claude 调用"""

    for attempt in range(max_retries):
        try:
            message = client.messages.create(
                model=model,
                max_tokens=max_tokens,
                messages=messages
            )
            return message.content[0].text

        except anthropic.AuthenticationError:
            # API Key 无效,不需要重试
            raise Exception("API Key 无效,请检查 ANTHROPIC_API_KEY 环境变量")

        except anthropic.RateLimitError as e:
            # 频率限制,等待后重试
            wait_time = 2 ** attempt  # 指数退避:1s, 2s, 4s
            print(f"频率限制,{wait_time}秒后重试(第{attempt+1}次)")
            time.sleep(wait_time)

        except anthropic.APIStatusError as e:
            if e.status_code == 529:  # 服务器过载
                wait_time = 2 ** attempt
                print(f"服务器过载,{wait_time}秒后重试")
                time.sleep(wait_time)
            else:
                raise  # 其他 API 错误直接抛出

        except anthropic.APIConnectionError:
            # 网络连接问题
            if attempt < max_retries - 1:
                print(f"网络连接失败,重试中...")
                time.sleep(1)
            else:
                raise Exception("网络连接持续失败,请检查网络环境")

    raise Exception(f"重试{max_retries}次后仍然失败")

九、生产环境最佳实践

1. Prompt Caching(节省 50-90% 输入费用)

# 对重复使用的长 System Prompt 开启缓存
# 缓存命中时,输入 token 费用降低 90%
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "你的长 System Prompt(几百到几千字)...",
            "cache_control": {"type": "ephemeral"}  # 标记为可缓存
        }
    ],
    messages=[{"role": "user", "content": "用户的问题"}]
)

2. 并发请求限速

import asyncio
import anthropic

client = anthropic.AsyncAnthropic()

async def batch_process(texts: list, concurrency: int = 5) -> list:
    """并发批量处理,限制同时请求数量避免超出速率限制"""
    semaphore = asyncio.Semaphore(concurrency)

    async def process_one(text: str) -> str:
        async with semaphore:
            msg = await client.messages.create(
                model="claude-haiku-4-5-20251001",  # 批量任务用 Haiku 省钱
                max_tokens=512,
                messages=[{"role": "user", "content": text}]
            )
            return msg.content[0].text

    tasks = [process_one(t) for t in texts]
    return await asyncio.gather(*tasks)

3. Token 使用量监控

class TokenTracker:
    """简单的 token 用量追踪器"""

    PRICES = {
        "claude-opus-4-6":              {"input": 5.0,  "output": 25.0},
        "claude-sonnet-4-6":            {"input": 3.0,  "output": 15.0},
        "claude-haiku-4-5-20251001":    {"input": 1.0,  "output": 5.0},
    }

    def __init__(self):
        self.total_input = 0
        self.total_output = 0
        self.total_cost = 0.0

    def track(self, response) -> None:
        model = response.model
        input_t = response.usage.input_tokens
        output_t = response.usage.output_tokens

        self.total_input += input_t
        self.total_output += output_t

        if model in self.PRICES:
            p = self.PRICES[model]
            cost = (input_t * p["input"] + output_t * p["output"]) / 1_000_000
            self.total_cost += cost

    def report(self) -> None:
        print(f"总输入 tokens: {self.total_input:,}")
        print(f"总输出 tokens: {self.total_output:,}")
        print(f"预估费用: ${self.total_cost:.4f}")


# 使用示例
tracker = TokenTracker()
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "你好"}]
)
tracker.track(response)
tracker.report()

常见问题

Q:max_tokens 和实际输出长度是什么关系?
max_tokens 是输出的上限,实际输出可能更短。如果 stop_reasonmax_tokens,说明输出被截断,需要增大这个值。费用只按实际输出的 token 计算,设得大一些不会多收费。

Q:对话历史太长怎么办?
有两个方向:一是定期总结历史(让 Claude 把前几轮对话总结成一段文字,替换掉原始历史);二是使用滑动窗口,只保留最近 N 轮对话。Claude Sonnet 和 Opus 支持 100 万 token 上下文,Haiku 支持 20 万,一般场景很难触及上限。

Q:Python SDK 和直接调用 HTTP API 有什么区别?
SDK 封装了认证、重试、错误处理、流式响应等细节,推荐使用 SDK。如果有特殊需求(如在不支持 pip 的环境),也可以用 requestshttpx 直接调用 https://api.anthropic.com/v1/messages 端点,请求格式和 SDK 一致。

总结

本文覆盖了 Python 调用 Claude API 的7个核心场景。日常开发建议从基础调用开始,按需加入 System Prompt 和多轮对话;需要更好用户体验时加上流式输出;处理大量任务时用异步并发提速。生产环境务必加入错误处理和重试机制,同时开启 Prompt Caching 降低成本。