Claude API 教程:在 Ubuntu VPS 上构建日志诊断工具
学习获取 Claude API key,并在 Ubuntu 24.04 上安全存储。用约 60 行 Python 实现支持流式输出、类型化异常、systemd 和成本限制的日志解释器。
构建内容
在全新的 Ubuntu 24.04 VPS 上构建一个命令行工具。您可以将错误消息或一段日志通过管道传入,工具会返回一份简明的英文诊断:journalctl -u nginx -n 50 | explain。整个工具大约只有 60 行 Python 代码,但涵盖了真实 Claude API 应用所需的全部基础知识:正确存储密钥、使用 virtualenv、处理 SDK 的响应结构、使用流式传输、处理类型化异常链,以及配置 systemd unit 让工具无需人工操作即可运行。
我有意选择了这个项目。大多数“第一个 API 应用”教程都会让您构建一个以后再也不会打开的聊天机器人。日志解释器从第一天起就能在服务器上发挥作用,还会迫使您掌握初学者最容易出错的两点:正确读取响应对象,以及控制开支。API 按 token 计费,费用上限只取决于您设置的限制。因此,成本控制是本项目的设计输入,而不是事后补救;当您进一步学习在同一台 VPS 的 tmux 中 运行 Claude Code 时,也必须遵循同样的纪律。
从 Console 获取 API key
API 访问权限在 Anthropic Console(platform.claude.com)中管理。注册后,进入 Settings → API Keys 创建 key(文档会直接链接到 platform.claude.com/settings/keys)。key 只显示一次,以 sk-ant- 开头,之后无法再次获取。请立即复制;如果没有保存,只能删除并重新签发。
费用方面,截至 July 2026,API 没有持续提供的免费层级。Anthropic 的定价文档说明,新用户会获得少量免费额度用于测试;具体额度以注册时 Console 显示的内容为准。额度用完后,必须先为账户充值,请求才能成功。这与 claude.ai 订阅分开计算。Pro 或 Max plan 不包含 API 额度,API key 也不能用于聊天应用。如果您正在比较订阅和 API,这个取舍属于另一个主题:您实际需要哪个 Claude plan。
将 key 的权限范围限定为一个项目或一台服务器。key 泄露后,随着时间推移迟早会发生。此时您应能够撤销该 key,而不会影响您拥有的其他资源。
不要将密钥放入 .bashrc
常见做法是在 export ANTHROPIC_API_KEY=sk-ant-... 中设置 ~/.bashrc。不要这样做。这里有三个独立的问题:
- 每个进程都会继承它。 登录 shell 中导出的环境变量会传递给你启动的所有程序,包括 Web 应用、会将环境变量写入错误报告的崩溃报告程序,以及有人忘记禁用的
phpinfo()页面。密钥的暴露面会变成“该用户运行过的所有程序”。 - 输入内容会写入
~/.bash_history。 手动执行一次 export 后,密钥就会永久保存在明文文件中,并同步到主目录的每个备份。 - systemd 需要它时却找不到。 服务不会读取你的
.bashrc,因此当你将脚本提升为 systemd unit 时,这种做法会直接失效,通常表现为清晨 6 点出现一个难以解释的 401 错误。
服务器上的正确做法是创建一个权限为 600 的专用环境文件,只由需要该密钥的进程加载:
sudo mkdir -p /opt/explain
sudo install -m 600 -o root -g root /dev/null /etc/claude-explain.env
printf 'ANTHROPIC_API_KEY=sk-ant-YOUR-KEY-HERE\n' | sudo tee /etc/claude-explain.env >/dev/null如果希望避免密钥写入编辑器的交换文件,可以通过 printf 使用 tee,而不是编辑器;无论采用哪种方式,都应使用 ls -l /etc/claude-explain.env 验证它读取的是 -rw-------,且文件归 root 所有。交互式 shell 通过包装脚本(见下文)在每次调用时获取密钥;systemd 则通过 EnvironmentFile= 获取密钥。root 会在降权前读取该文件,因此服务用户无需拥有读取权限。密钥不会出现在代码、git、ps 输出或 shell 历史记录中。
在 venv 中安装 SDK
Ubuntu 24.04 随附的 Python 3.12 启用了 PEP 668 强制机制,因此直接对系统解释器执行 pip install anthropic 会失败,并显示 error: externally-managed-environment。这是操作系统的预期行为,请使用 virtualenv:
sudo apt update && sudo apt install -y python3-venv
sudo python3 -m venv /opt/explain/venv
sudo /opt/explain/venv/bin/pip install anthropic服务器上无需执行激活操作:直接调用 /opt/explain/venv/bin/python 始终会使用 venv 中的软件包。
首次调用,并正确读取响应
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from the environment
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1000,
messages=[{"role": "user", "content": "Explain what a systemd unit file is in three sentences."}],
)
for block in response.content:
if block.type == "text":
print(block.text)这 12 行代码体现了该 API 的两个核心工作方式。第一,anthropic.Anthropic() 不带参数时会从环境变量读取密钥,不要将密钥直接写成字符串字面量。第二,response.content 是内容块列表,而不是字符串。直接打印它时,初学者通常会看到下面这种输出:
[TextBlock(citations=None, text='A systemd unit file is...', type='text')]这不是错误,而是对象的 repr。响应可能包含多种内容块类型(文本、工具调用、思考内容),因此应遍历这些内容,并在访问 .text 前检查 block.type == "text"。从第一天起就加入这个循环,可以避免整类“输出内容无法识别”的问题。
使用确切的模型 ID claude-opus-4-8。当前版本的 ID 不包含日期。不要凭习惯或旧博客文章在末尾追加日期后缀;这样会导致 404,下面会介绍这一点。
实际工具:explain
以下是完整程序:从 stdin 读取输入,以流式方式输出诊断结果,并处理错误:
#!/usr/bin/env python3
"""explain: pipe an error or log excerpt in, get a diagnosis out."""
import sys
import anthropic
MODEL = "claude-opus-4-8"
def main() -> int:
text = sys.stdin.read().strip()
if not text:
print("usage: journalctl -u nginx -n 50 | explain", file=sys.stderr)
return 1
client = anthropic.Anthropic()
try:
with client.messages.stream(
model=MODEL,
max_tokens=1500,
system=(
"You are a senior Linux sysadmin. The user pipes you server "
"logs or error output. Name the most likely cause outright, "
"then give the commands to confirm and fix it. Be terse."
),
messages=[{"role": "user", "content": text}],
) as stream:
for chunk in stream.text_stream:
print(chunk, end="", flush=True)
print()
except anthropic.RateLimitError as e:
retry_after = e.response.headers.get("retry-after", "60")
print(f"rate limited; retry in {retry_after}s", file=sys.stderr)
return 2
except anthropic.APIStatusError as e:
print(f"API error {e.status_code}: {e.message}", file=sys.stderr)
return 2
except anthropic.APIConnectionError:
print("network error reaching the API", file=sys.stderr)
return 2
return 0
if __name__ == "__main__":
sys.exit(main())将其保存为 /opt/explain/explain.py,然后添加一个用于交互式使用的包装脚本来加载密钥:
sudo tee /usr/local/bin/explain >/dev/null <<'EOF'
#!/bin/sh
set -a; . /etc/claude-explain.env; set +a
exec /opt/explain/venv/bin/python /opt/explain/explain.py "$@"
EOF
sudo chmod 755 /usr/local/bin/explain(该包装脚本需要通过 sudo 运行;或者,让环境文件所属的组包含您的管理员用户。请有意选择其中一种方式,不要为了放宽权限而将文件权限改为 644。)
为什么使用流式传输。 client.messages.stream 会在令牌到达时立即打印,而不是在完整生成结束前保持静默。它还可以避免长输出导致的 HTTP 超时;出于同样的原因,SDK 在非流式调用中实际上会拒绝非常大的 max_tokens 值。如果之后需要组装好的对象,请在 with 块中调用 stream.get_final_message()。
为什么按此顺序处理异常。 SDK 会抛出类型化异常,顺序应从最具体的异常开始:RateLimitError 表示 429 响应,并携带 retry-after 标头,告知您需要等待多长时间;APIStatusError 覆盖其他非 2xx 响应(检查 e.status_code >= 500 以判断是否存在服务器端问题);APIConnectionError 表示请求完全没有收到响应。在编写重试循环之前还要注意:SDK 已经会自行重试 429 和 5xx 错误,默认使用指数退避重试两次(客户端上的 max_retries)。当您的 except 运行时,重试次数已经用尽。因此,在 CLI 中,正确做法是报告错误并退出,而不是休眠后继续发送请求。
成本控制
这一点需要单独说明,因为除非您自行配置,否则 API 没有内置的月度上限,而且这里的每个错误都会在无提示的情况下持续放大。
max_tokens 是每次调用的费用上限。 输出 token 的价格更高。在 Opus 4.8 中,输出价格是输入价格的 5 倍,而 max_tokens 会硬性限制模型最多生成的输出 token 数。失控的提示词不会导致输出费用超过您设置的上限。应根据任务设置该值:日志诊断使用 1,500 就足够;分类任务只需要 100。如果响应因 stop_reason: "max_tokens" 在句子中途停止,说明该值设置得过低。请有意识地调高,不要默认设置为很大。
发送前先统计。 输入也会产生费用,而日志通常很大。API 提供了一个免费使用的 token 统计端点,但它有独立于消息创建接口的速率限制:
count = client.messages.count_tokens(
model="claude-opus-4-8",
messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)使用它可以避免意外通过工具传输 2 GB 的日志。不要为此使用 tiktoken,它是 OpenAI 的 tokenizer。在典型文本中,它统计的 Claude token 数量大约少 15–20%,对代码的低估幅度还会更大。
按任务选择模型,不要固定使用某个模型。 截至 July 2026,Opus 4.8(claude-opus-4-8)的价格为每百万输入 token $5、每百万输出 token $25;Haiku 4.5(claude-haiku-4-5)为 $1/$5,并支持 200K 上下文;Sonnet 5(claude-sonnet-5)处于两者之间,价格为 $3/$15,且在 2026 年 8 月 31 日前提供 $2/$10 的初始价格。具体来说,包含 2,000 个 token 的日志摘录和 500 个 token 的回答,在 Opus 上的费用约为 $0.0225,在 Haiku 上约为 $0.0045。评估输出质量时先使用 Opus,然后使用相同的提示词测试 Haiku。对于高频、简单的转换任务,Haiku 的效果通常难以区分,但价格只有五分之一。在将这些价格写入预算前,请先到定价页面确认当前数值。
可延迟的任务使用批处理。 Batches API 会异步处理请求,价格为标准价格的 50%,大多数批次会在 1 小时内完成。夜间摘要、历史数据回填、批量分类,以及所有不需要人工等待的任务,都应使用该 API。
对重复上下文使用提示词缓存。 如果每次调用都会重新发送相同的大型系统提示词或运行手册,请将其标记为可缓存:
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1000,
system=[{
"type": "text",
"text": RUNBOOK_TEXT, # the same 30K tokens on every call
"cache_control": {"type": "ephemeral"},
}],
messages=[{"role": "user", "content": question}],
)
print(response.usage.cache_read_input_tokens) # non-zero from the second call on缓存写入费用约为输入价格的 1.25 倍,缓存读取费用约为输入价格的 0.1 倍,缓存 TTL 为 5 分钟。因此,在该时间窗口内发起的第 2 次调用就已经可以抵消首次缓存写入的费用。需要注意两点。缓存前缀必须达到每个模型的最低长度要求。Opus 的最低长度为几千个 token,因此较短的系统提示词根本不会触发缓存,而且不会明确提示。另一个问题是,如果相同调用中的 cache_read_input_tokens 始终为 0,说明您的前缀在每次请求中都有变化,最常见的原因是包含了时间戳。
注意哪些内容会计入输入。 系统提示词、工具定义,以及多轮对话中每轮重新发送的完整历史记录,都会作为输入 token 计费。完全不裁剪历史记录的聊天循环会使费用按平方增长。在构建任何对话式应用前,都应先了解完整的计费方式:Claude token 使用量和计费的实际计算方式。
在 systemd 下运行
环境文件管理规范带来的好处是:可以使用一个计时器每天早晨汇总前一天的错误。
# /etc/systemd/system/log-digest.service
[Unit]
Description=Daily error-log digest via the Claude API
[Service]
Type=oneshot
User=explain
Group=systemd-journal
EnvironmentFile=/etc/claude-explain.env
ExecStart=/bin/sh -c 'journalctl -p err --since yesterday | /opt/explain/venv/bin/python /opt/explain/explain.py >> /var/log/log-digest.txt'# /etc/systemd/system/log-digest.timer
[Unit]
Description=Run the log digest every morning
[Timer]
OnCalendar=06:15
Persistent=true
[Install]
WantedBy=timers.targetsudo useradd -r -s /usr/sbin/nologin explain
sudo touch /var/log/log-digest.txt && sudo chown explain /var/log/log-digest.txt
sudo systemctl daemon-reload
sudo systemctl enable --now log-digest.timer
sudo systemctl start log-digest.service # test it once, right now请注意 EnvironmentFile= 的作用:systemd 会在切换到非特权 explain 用户之前,先读取由 root 拥有且权限为 600 的文件,因此进程可以获取该变量,而该用户无法读取密钥文件。systemd-journal 组授予日志访问权限。使用手动 systemctl start 进行测试,并读取 journalctl -u log-digest.service,不要等到 06:15 才发现拼写错误。当这种模式超出 shell 管道的处理能力后,同样的密钥环境文件方案可以直接用于同一台主机上的由 Claude 驱动的 n8n 工作流。
故障模式及对应的错误信息
可用密钥返回 401。 异常信息如下:
anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}如果密钥在 shell 中可用,但服务返回 401,说明服务根本没有收到该密钥。请记住,systemd 不会读取 .bashrc;检查 EnvironmentFile= 是否指向正确的路径。其他原因包括:将引号一起粘贴到了环境文件中(ANTHROPIC_API_KEY="sk-ant-...";systemd 会去掉引号,但如果 shell 包装脚本中的 . file 使用了不恰当的引号,值中会保留引号)、末尾空格,或者使用了上周在 Console 中撤销的密钥。
模型名称拼写错误导致 404。 最常见的情况,是为当前模型 ID 添加日期后缀:
anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-opus-4-8-20260115'}, 'request_id': 'req_011CSJqymAvNw4bT3qmDdMbA'}当前版本的 ID 必须与文档中的写法完全一致:claude-opus-4-8、claude-haiku-4-5、claude-sonnet-5。请从模型文档中复制,不要凭记忆输入,也不要使用旧教程中的内容。
429 rate_limit_error。 错误类型字符串为 rate_limit_error,响应中包含 retry-after 标头,其中给出了需要等待的秒数。在抛出异常前,SDK 已经使用退避策略重试了 2 次。因此,持续出现 429 表示你的持续请求速率确实超过了当前层级的限制。请将任务分批处理或分散执行,不要缩短重试间隔。
输出的是对象,而不是文本。 输出类似 [TextBlock(citations=None, text='...', type='text')]。你打印了 response.content,而不是遍历各个块,并从满足 block.type == "text" 的块中读取 .text。上面的每个 SDK 示例都采用了正确写法;请直接复制循环代码。
error: externally-managed-environment。 你在 Ubuntu 24.04 的系统 Python 中运行了 pip install。请使用 venv;在需要维护的服务器上不要使用 --break-system-packages。
回答被截断。 response.stop_reason == "max_tokens" 表示模型在生成过程中达到了输出上限。这是预期行为;请根据需要提高上限。
第一个应用运行正常后,使用 Claude 构建 AI 代理可以将相同的 API 调用转换为能够使用工具的代理。
FAQ
试用 Claude API 的成本是多少?
对于这类工具,实际成本很低。截至 2026 年 7 月,Opus 4.8 的价格是每百万输入令牌 $5、每百万输出令牌 $25。因此,一次典型的日志诊断通常输入几千个令牌、输出几百个令牌,成本约为两美分;使用 Haiku 4.5($1/$5)时则低于半美分。每天生成摘要一个月的成本低于一杯咖啡。真正的风险不在于单次调用价格,而在于无界循环和无界 max_tokens,因此本指南会明确设置这两项。
Claude API 有免费层吗?
截至 2026 年 7 月,没有持续提供的免费层。Anthropic 的定价文档说明,新用户会获得少量免费额度用于测试 API,这是一次性试用额度;具体金额会在注册时显示在 Console 中,之后需要为账户充值。如果您的目标是让每次请求的边际成本为零,而不是追求前沿模型的质量,另一种方案是使用 Ollama 自行托管开放权重模型,用 RAM 代替令牌付费。
如何在服务器上保护 API 密钥?
密钥绝不能放在代码中,绝不能提交到 git,绝不能从 .bashrc 导出,也绝不能直接输入到会保留历史记录的 shell 中。应将密钥放在 root 拥有的文件中,并设置 600 权限;按进程加载:交互式使用时通过包装脚本加载,systemd 使用 EnvironmentFile= 加载。为每台服务器或每个项目使用单独的密钥,这样密钥泄露后可以撤销,而不必扩大影响范围。如果密钥曾出现在粘贴站点或 git 提交中,应立即在 Console 中撤销;删除提交并不能消除已经泄露的密钥。
应该从哪个 Claude 模型开始?
在评估输出是否足以作为后续工作的基础时,从 claude-opus-4-8 开始。这样可以在完整质量下判断方案是否可行;在业余规模的使用量下,成本差异只有几美分。提示词确定后,再用真实输入通过 claude-haiku-4-5 重新运行;对于摘要、分类和日志分诊,它的效果通常相当于前者的五分之一价格。应根据测量结果切换到 Haiku 或 Sonnet,而不是默认切换。