技術 約5分で読めます

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 initpyproject.toml を作り、uv add は依存関係をそこへ記録する。
Astralの公式ドキュメントでは、アプリケーションプロジェクトは main.pypyproject.tomlREADME.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.tomluv.lock と実行コマンドが残っていれば、少なくとも環境の復元からやり直せる。

この差は、自律実験系で特に大きい。
KarpathyのAutoresearchの記事でも uv syncuv run prepare.pyuv 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 inituv adduv runuv sync をいつもの実行手順にしてしまうほうがいい。