こんにちは。
「Today I Learned(今日学んだこと)」を記録するTIL、6月は新マシンが納品され、GPU仮想化からローカルLLM環境の構築まで、いろいろ試行錯誤しました。ローカルLLMや画像生成、Difyを本格的に試した話は来月に。Claude Codeを使った「Vibe Coding」を体験したので、そちらも紹介します。
2025年6月のピックアップ
AIマシンセットアップ編 – GPUパススルーとUbuntu環境構築 (06/11〜06/13)
納品されたAIマシンにはProxmox VEを導入。GPUには、VRAM 16GBを搭載しながら比較的お手頃な価格のRTX 5060 Tiを選択しました。そこそこのローカルAIを動かすには十分なスペックです。
高性能なホストになったことで、GPUパススルーした仮想マシン以外にも様々なサービスを動かせるようになりました。メモリカツカツだった他のPVEからいくつかのサービスを引っ越しできて、運用面でもかなり楽になりました。
(1)GPUドライバのあれこれ (06/11)
GPUパススルーを設定した仮想マシン(Ubuntu Desktop 24.04)でGPUを認識させる作業から。
ubuntu-drivers devices
で推奨ドライバ(nvidia-driver-575)をインストールしたものの、nvidia-smi
を実行してもGPU情報が表示されない。試行錯誤の末、nvidia-driver-575-open
に切り替えたら動作しました。
ネット上では「-openドライバは要注意」という情報もあるけど、バージョンとグラボの組み合わせ次第みたい。その後も問題なく動いています。
(2)CPU命令セットの設定 (06/12)
ゲスト内でCPUの命令セットが足りないというエラーが発生。
Proxmox VEのデフォルトCPU設定「x86-64-v2-AES」を「Host」に変更して解決。ゲスト設定 → ハードウェア → プロセッサ → 種別から変更できます。これでホストCPUの全機能がゲストで使えるようになりました。異なるCPUを持つホスト間でのマイグレーションには影響があるかもしれないけど、単一ホストの運用なので問題なし。
(3)GPU監視環境の構築 (06/12〜06/13)
GPUを酷使する前に監視環境を整備。
ゲストにGPUをパススルーしているため、ホスト側からはGPU情報を取得できません。ゲスト上でDCGM Exporter(Prometheus用Exporter)を動かし、Grafanaで可視化する構成に。Dockerで動かすので、ゲスト側で実行するのがちょうどよかったです。
NVIDIA/dcgm-exporter: https://github.com/NVIDIA/dcgm-exporter
GPU温度のアラートも設定。これで安心してGPUを使い倒せます。

Vibe Codingはじめました (06/13〜06/19)
6月中旬、Claude Codeを使った開発を本格的に試しました。社内の新規プロジェクトを題材に、ほぼ全てのコードをAIエージェントに書いてもらう「Vibe Coding」に挑戦。
(1)計画立案と初日の成果 (06/13)
モックアップレベルで作っていたアプリを本格始動させることに。人間が丸1日かけて仕様書を作成し、この仕様書とモックを見せて開発計画を立ててもらいました。
計画段階だけはClaude CodeをOpusモデルに切り替えて実行。仕様書の意図を的確に汲み取り、技術選定から実装順序まで、とても勘よく計画を立ててくれました。やはりOpusは計画立案が得意。
初日は半日で全体の1/3程度が進行。自分が書いたコードは片手で数えられる程度。ヤバい。
(2)驚異的な開発速度 (06/16〜06/17)
一週間かかると見積もっていたAPIバックエンドとNuxtフロントエンドの実装が、二日でほぼ完成。アイコンが欲しいと言ったらSVGで描いてくれたり、モックには無かった新機能も仕様を伝えるだけで実装してくれたり。
コードは書かなかったけど、細かな指示は必要でした:
- 「その処理はあっちに置いた方がいいと思う」
- 「ここ見て、考え直して」
- 「そんな場当たり的な対応はやめて」
- 「ここ修正忘れてるよ」
レート制限でフロント機能の調整中に力尽きたものの、結局三日で全実装が完了。”コンパクト機能”を使うと過去のことを忘れがちなので、会話の中で決めたことは早めにCLAUDE.md
に記録するよう伝えておくのがコツ。
(3)Cloudflare Workers移行 (06/18〜06/19)
当初はHono(Node.js)+ Prisma + PM2でデプロイしようとしたけど、依存関係の問題で断念。tscでのビルドではモジュール解決が失敗、Viteでバンドルしてもprisma-clientのパスが解決できず。
思いつきでCloudflare Workers + D1に方針転換。Prisma(MySQL)からD1(SQLite)への書き換えもClaudeにお任せし、2時間弱で移行完了。コマンド一発でデプロイできる手軽さがいい。自分がよく作る規模のアプリなら無料枠で収まるので、今後は積極的に使っていく予定。
Zodで条件に応じた動的な検証を実装する (06/03)
フォームでよくある「チェックボックスをONにしたら必須になる項目」のような条件付き検証。z.discriminatedUnion
を使えばスマートに実装できます。
Defining schemas | Zod: https://zod.dev/api?id=discriminated-unions
const base = z.object({
checked: z.boolean(),
value: z.string(),
});
const scheme = z.discriminatedUnion('checked', [
base.extend({
checked: z.literal(false),
}),
base.extend({
checked: z.literal(true),
value: z.string().nonempty({
message: '値は必須項目です',
}),
}),
]);
TypeScriptの型と連動するのがポイント。実際の型もユニオン型になります。
実際のユースケース:
- 「その他」を選択した時だけ詳細入力欄が必須になるフォーム
- 配送先を「別の住所」にした時だけ住所入力が必須になるECサイト
- 支払い方法によって必要な情報が変わる決済フォーム
従来は関数を書いていた処理が、宣言的に書けるようになります。保守性も向上し、仕様変更にも強い実装に。
Grafana Alloyのファイル読み込み権限問題 (06/27)
新しい環境でGrafana Alloyがログファイルを読み込めない問題に遭遇しました。他の環境では同じ設定で動いていたのに、なぜか新環境だけ読めない。
最終的にLinuxのCapabilityで特権を付与することで解決:
setcap CAP_DAC_READ_SEARCH+ep /usr/bin/alloy
ただし、この方法は推奨しません。セキュリティ的に好ましくない方法ですし、本来はファイルのパーミッションやグループ設定で解決すべき問題です。他にも様々な方法を試しましたが、この環境では結局これしか動作しませんでした。あくまで最終手段として、参考程度に留めておいてください。
Gemini APIでの構造化出力とストリーミング併用の試み (06/30)
Gemini APIで構造化出力とストリーミングを同時に使いたいケースがありました。ユーザーには応答を逐次表示しつつ、最終的にはきちんとした構造化データとして扱いたいという要望。
技術的には、Google公式ライブラリ(@google/genai)のgenerateContentStream
メソッドを使いながら、レスポンススキーマを設定することで実現可能:
const result = await model.generateContentStream({
contents: [{ role: 'user', parts: [{ text: prompt }] }],
generationConfig: {
responseMimeType: 'application/json',
responseSchema: schema,
},
});
実際に試してみると以下の問題に直面:
- チャンクサイズが大きすぎる: 2〜3回の出力で全データが揃ってしまい、ストリーミングの意味がない
- 不完全なJSONのパースエラー: 途中段階でJSONとして不完全なデータが送られてくるため、エラーハンドリングが複雑に
- LangChainでは機能制限: LangChainのGemini実装では、この併用がそもそもサポートされていない
結果として、ストリーミングによるUX向上というメリットよりも、実装の複雑さとエラー頻度の増加というデメリットの方が大きいことが判明。
以下与太話
この結論に至るまでに、ライブラリを5回も書き換えました:
- モックアップ → LangChainでお試し(OpenAIモデル使用)
- 本格開発 → OpenAI公式ライブラリに全面書き換え
- モデル変更 → 「Geminiの方が速くて安い!」ということで乗り換え決定、マルチモデル対応のLangChainに出戻り
- 機能制限にぶつかる → Google公式ライブラリに再度書き換え
- 使い勝手が悪い → 「なかったことにしよう」とLangChainに再々度戻る
Geminiに乗り換えてから気づいたけど、Geminiの出力速度はOpenAIと比べて圧倒的に速い。そもそもストリーミングにこだわる必要があったのか🤔という。
救いだったのは、これが前述のVibe Codingで開発したプロジェクトだったこと。初期段階でレイヤードアーキテクチャを提案し、Claude Codeがきちんと実装していたおかげで、何回もライブラリを書き換えたのに影響範囲は驚くほど小さく済みました。LLMプロバイダーの処理が適切に抽象化されていたため、インフラ層の修正だけで対応できたわけです。
得た教訓:最初から妥協点を見つけておくべきだった(そしてClaude Codeは優秀)。
おわり
AIマシンのセットアップで環境も整ったので、いよいよ本格的にローカルLLMや画像生成に挑戦しています。次回は実際にこれらを活用した事例を紹介できたらと思います。