uvでClaude SDKの小さなPythonエージェント実験をすぐ始める
目次
DEV Communityに出ていたuv 0.11.11でClaude SDKプロジェクトを1秒未満で立ち上げる記事を読んだ。
手元のHomebrew版は uv 0.9.21 で、原典の uv 0.11.11 とは違うので、ここでは秒数の追試ではなく運用面を見る。
Claude SDKやMCPまわりの小さいPython実験を何度も作る人には、速さより「同じ入口で作り直せる」ほうが効く。
速いpip代替より、実験用の標準入口として見る
原典の測定では、uv init claude-agent-demo が0.435秒、uv add anthropic が0.874秒、キャッシュが効いた uv sync が0.074秒だった。
この数字だけを見ると「pipより速い」で終わるが、Claude SDKの小さな実験では別の価値がある。
AIエージェントの実験は、試したいコードが先にあって、環境構築は毎回わりと雑になりがちだ。
python -m venv .venv、activate、pip install anthropic python-dotenv まで手で打つと、ブランチごと、検証ごと、別マシンごとに少しずつズレる。
ズレた環境でClaude APIの挙動を見ていると、コードの問題なのか依存関係の問題なのか切り分けが遅くなる。
uv init は pyproject.toml を作り、uv add は依存関係をそこへ記録する。
Astralの公式ドキュメントでは、アプリケーションプロジェクトは main.py、pyproject.toml、README.md、.python-version を含む形で作られる。
原典のツリー表示には .python-version が出ていなかったが、少なくとも今のuvではPythonバージョンのピン留めまで同じ流れに入る。
uv init claude-agent-demo
cd claude-agent-demo
uv add anthropic python-dotenv
uv run main.py
この4行がチーム内の「Claude SDKで何か試すときの入口」になる。
Claude Codeの運用を考えるなら、これは以前書いたClaude Code Best PracticesとAgent SDKの公式ガイドまとめの「コンテキストを与える」「検証する」という話の、Python環境側の足場になる。
uv run で仮想環境の状態を会話から外す
Claude SDKの最小コードは、AnthropicのClient SDKsドキュメントにあるように、Pythonクライアントから messages.create を呼ぶだけで始められる。
難しいのはSDK呼び出しそのものではなく、どのPythonで、どの依存関係で、どの環境変数を読んでいるかを毎回そろえるところだ。
import os
import anthropic
from dotenv import load_dotenv
load_dotenv()
client = anthropic.Anthropic(
api_key=os.environ["ANTHROPIC_API_KEY"],
)
message = client.messages.create(
model=os.environ["ANTHROPIC_MODEL"],
max_tokens=256,
messages=[
{"role": "user", "content": "uvを使う理由を1文で説明して"}
],
)
print(message.content[0].text)
uv run main.py で起動すれば、activate忘れを会話の前提にしなくてよい。
Astralのlocking and syncingの説明では、uv run は実行前にロックと環境同期を確認する。
エージェントに「このリポジトリではPythonスクリプトは uv run で実行」と渡しておくと、システムPythonに入った古いSDKを誤って使う事故を減らせる。
これはMCPサーバーを uvx で起動するBlenderMCPの設定にも近い。
MCPでは uvx blender-mcp が「このツールをこの場で起動する」入口になっていた。
Claude SDKの小さい検証では、uv run が「このプロジェクトの依存関係で実行する」入口になる。
uv.lock はエージェントに渡せる状態の記録
Claude CodeやCodexにPython実験を任せるとき、会話ログより強いのはファイルとして残った状態だ。
以前のClaude Codeセッション管理の記事では、セッションを残すよりgitに残す運用を書いた。
uvのロックファイルは、その考え方と相性がいい。
uv.lock をコミットしておけば、別マシンでは uv sync で同じ依存関係へ戻せる。
ロックファイルは説明文ではなく、解決済みの依存グラフそのものだ。
エージェントが途中でコンテキストを失っても、pyproject.toml と uv.lock と実行コマンドが残っていれば、少なくとも環境の復元からやり直せる。
この差は、自律実験系で特に大きい。
KarpathyのAutoresearchの記事でも uv sync、uv run prepare.py、uv run train.py という入口になっていた。
あれはGPUを使うML実験なので今回のClaude SDK小物とは重さが違うが、「人間やエージェントが同じコマンドで実験を再開できる」という点は同じだ。
condaが必要な領域まで置き換えない
原典も書いていたが、uvはPyPI中心のツールなので、CUDA、torch、tensorflow、conda channel前提の依存が絡む重いML環境を全部置き換えるものではない。
APIを叩くClaude SDK実験、FastAPIで小さなプロキシを書く、MCPサーバーを試す、CLIツールを組む、といった領域ではかなり相性がいい。
逆に、GPUドライバ、CUDA toolkit、conda-forge由来のネイティブ依存まで含む実験なら、uvだけに寄せると別の詰まり方をする。
その場合は、Pythonアプリ部分だけuvで閉じるか、最初からconda環境として管理するほうが読みやすい。
uvが便利なのは「Python環境構築を頑張った感」が消えるところだ。
Claude SDKで1ファイル試すくらいなら、環境構築を作業として扱わず、uv init、uv add、uv run、uv sync をいつもの実行手順にしてしまうほうがいい。