Dockerを手放したら、Agent開発が身軽になった
Agentを作っていました。
最初は、LLMに入力を渡して、structured outputを返すくらいの小さなもののつもりでした。
でも気がつくと、手元では docker compose が育っていました。
Agentを作っていたはずなのに、いつの間にかlocal stackを育てている。
Agent開発なのか、インフラ飼育なのか分からない。
ここが、この記事の入口です。
Postgres
Redis
Qdrant
Langfuse
ClickHouse
MinIO
Backend
Frontend
Worker
うおw、Agentどこいった。
もちろん、自前で立てると理解は深まります。
各componentの役割も分かるし、データの流れも見える。
ただ、ある段階を超えると、Agentを作っているのか、周辺インフラを飼育しているのか分からなくなる。
いやーきついっす。
この記事は、Docker不要論ではありません。
クラウド最高論でもありません。
Agent開発を進めるうちに、自分が本当に持つべき責務と、外に出してよい責務が分かれてきた、という話です。
クラウド化は手抜きではなく、責務境界の再配置でした。
もう少し正直に言うと、最初は on-prem / local self-host の方が安く済むと思っていました。
でも、Agent 開発では周辺責務が育ちます。
Vector DB を持てば embedding pipeline が育つ。
Observability を持てば storage / analytics DB / UI が育つ。
local stack を持てば seed / migration / volume / network の面倒を見ることになる。
気づくと、安く済ませていたはずの構成が、開発時間と注意力を食い始める。
この時点で、クラウド化は贅沢ではなくなります。
トータルコストを下げるための責務境界の再配置になる。
そして後半では、Agent開発を進めていたら、いつの間にかAgent開発そのものを支援するAgentが欲しくなった、という話にもつながります。
AgentのためのAgent。
これもうわかんねえな。
docker composeが育ちすぎて、インフラ飼育になっていた
最初は小さかったはずです。
LLMを呼ぶ。
結果をschemaでvalidateする。
必要ならtraceを見る。
UIで出力を確認する。
このくらいなら、かなり身軽です。
でも、少しずつ必要なものが増えていく。
永続化したい。
traceを残したい。
UIで見たい。
jobを分けたい。
検索用のindexも欲しい。
localで再現したい。
CIで落としたい。
そうすると、気づいたらdocker composeが育っている。
services:
app:
worker:
db:
redis:
vector-db:
object-storage:
tracing:
frontend:
これはこれで楽しいです。
自分の手元で全部立つのは気持ちいい。
localで完結する安心感もある。
ただ、気持ちよさと運用しやすさは別です。
Agent本体の挙動を見たいのに、気づくとcontainer networkやvolumeやseed dataを見ている。
この状態になると、Agent開発というよりインフラ飼育に近くなってきます。
自前で持つことは、理解には効く。
でも、持ち続けることが合理的とは限らない。
Qdrantを外したら、Agent本体ではないコードが消えた
この感覚が一番はっきり出たのは、Qdrantを外して Tavily に寄せた時でした。
最初は、Vector DB を外すというと、単に docker compose から Qdrant のコンテナが一つ消えるだけに見えます。
でも実際には、それだけではありませんでした。
Qdrant を持つということは、その周辺にかなりのコードを持つということでもあります。
たとえば:
- 記事を取得するコード
- raw article を保存するコード
- chunking するコード
- embedding を作るコード
- embedding job を再実行するコード
- index を更新するコード
- Qdrant collection を作るコード
- payload schema を管理するコード
- 古い index と新しい index の整合性を見るコード
- local seed / migration / reset 手順
うおw、Agentどこいった。
もちろん、Vector DB が悪いわけではありません。
自前 corpus を持つ必要があるなら、indexing pipeline は必要です。
ただ、この project で本当に見たかったのは、そこではありませんでした。
見たかったのは、retrieved evidence を使って、LLM の reasoning structure をどう外に出すかでした。
Qdrant を外して Tavily に寄せると、Agent本体とは関係の薄い ingestion / embedding / indexing のコードがバッサリ消えました。
これはかなり大きかったです。
もしウォーターフォール開発で、最初に設計を固めて、人間が全部のコードを書きながら進めていたら、普通に命が危なかったかもしれません。
記事取得基盤を作る。
embedding pipeline を作る。
index更新を作る。
管理画面っぽいものを作る。
それからようやく Agent Runtime に戻ってくる。
いやーきついっす。
FISIで小さく通しながら進めていたので、「これは本体ではない」と気づいた段階で切れました。
これはかなり重要でした。
Vector DB を外したことで消えたのは、Qdrant のコンテナだけではありません。
Agent本体ではない責務を、まとめて外に出せた。
という感覚があります。
同じことは Langfuse でも起きました。
local で observability backend まで持とうとすると、trace storage、分析用DB、object storage、UI などが一気に増えます。
もちろん、それぞれは必要な部品です。
ただ、Agent本体から見ると、本当に持ちたいのは observability backend の運用ではありません。
持ちたいのは、trace を出す境界と、後から読める metadata の設計です。
Langfuse Cloud に寄せると、ごつい local stack は手元から消え、Agent側に残るのは接続先を指定する数行の設定だけになりました。
うおw、差がすごい。
これも手抜きではなく、責務境界の再配置です。
observability は必要です。
でも observability backend の運用は、この project の本体ではない。
ここでも、外に出したことで、逆に本体が見えやすくなりました。
microservicesになって、視点までmicroになった
気がつくと、構成はmicroservices architectureっぽくなっていました。
Backend。
Frontend。
Worker。
Postgres。
Redis。
Qdrant。
Langfuse。
ClickHouse。
Object storage。
それぞれは合理的です。
責務も分かれている。
疎結合にも見える。
ただ、視点までmicroになっていく。
今日はRedisの設定を見る。
明日はobject storageの権限を見る。
その次はClickHouseの永続化を見る。
さらにその次はcontainer networkを見る。
うおw、Agentどこいった。
microservices architectureになった結果、設計の視点までmicroになっていました。
もちろん、microservices architecture自体が悪いわけではありません。
むしろ、ある程度の規模では自然な分解です。
ただ、その時点で自分が見たかったのは、service間の境界ではなく、Agent Runtimeの境界でした。
どこまでをworkflow stateとして持つのか。
どこからをexternal serviceに任せるのか。
何をartifactとして保存するのか。
何をtraceとして残すのか。
そこを見たいのに、気がつくとcontainerのご機嫌取りをしている。
いやーきついっす。
クラウドに逃がす、というより責務境界を再配置する
ここでクラウドサービスに寄せることを考え始めました。
ただし、これは「クラウド最高」という話ではありません。
クラウドに逃がしたいというより、自分が持つべきではない責務を外に出したかった。
たとえば:
- LLM provider
- tracing backend
- CI
- object storage
- hosting
- auth
- monitoring
こういうものを全部自前で持つと、Agentの設計に集中しにくくなる。
自分が本当に見たいのは、そこではない。
見たいのは:
- prompt boundary
- output schema
- workflow state
- skill thesis
- reflection result
- safety status
- trace readability
- UI observability
です。
クラウド化は手抜きではなく、責務境界の再配置でした。
費用面でも、この判断は個人開発としてかなり自然でした。
最初は、on-prem / local self-host の方が安く済むと思っていました。
ただ、ここでのコストはサーバー代だけではありません。
起動・停止の待ち時間。
local stack の不調対応。
volume / seed / migration の整備。
Qdrant / Langfuse / ClickHouse / MinIO の運用。
embedding pipeline の保守。
開発のフィードバックループ低下。
集中力の分断。
これらを含めると、安く済ませるために自前で持ったものが、開発速度を一番高くつかせていた。
Tavily や Langfuse は、個人の実験レポとして使う範囲なら無料枠でかなり足ります。OpenRouter も、手元で大きな計算資源を用意して運用するより、必要な分だけクラウド上のモデルを使う方が、この規模ではコスパが良い。
もちろん、規模や制約が変われば判断も変わります。大量利用、厳しい閉域要件、特殊なレイテンシ要件があるなら、自前基盤を持つ意味は出てくる。
ただ、この project で検証したかったのは、計算資源を所有することではなく、Agent Runtime の境界でした。
Qdrant も Cloud を使えば、少なくとも Vector DB の運用責務は外に出せます。
ただ、それでも embedding model は残ります。どの embedding model を使うか、どこで実行するか、いつ再埋め込みするか、chunking をどう変えたら index を作り直すか。そこはまだ自分の責務です。
途中で気づいたのは、Vector DB を自前で持ちたくないというより、embedding pipeline そのものをこの project の本体にしたくない、ということでした。
この project で見たかったのは、corpus を作ることではありません。検索された evidence をどう reasoning backbone に入れるかでした。
なので、Qdrant Cloud に逃がすのではなく、そもそも embedding / indexing を project の中心から外しました。
持つべきものを持つ。
持たなくてよいものは外に出す。
この判断ができると、Agent Runtimeの本体が見えやすくなります。
クラウド化はコスト増ではなく、見えない運用コストの圧縮だった。
少なくとも、この規模の個人開発ではそう見えています。
まぁ、問題構造としてはかなり素直です。
身軽になるとFISIが回る
身軽になると、FISIの回転が速くなります。
自分の中でFISIは F*** it, ship it の略です。
雑に投げるというより、「考えるべきことは考えたので、まず小さく出して現実に当てる」くらいの意味で使っています。
Agent開発では、これがかなり大事でした。
まずpoor E2Eを通す。
happy pathを動かす。
出力を見る。
traceを見る。
UIで違和感を見る。
次のPRで直す。
このループを回したい。
でも、周辺インフラが重いと、このループが遅くなる。
docker composeの調子を見る。
local DBを直す。
volumeを消す。
networkを見る。
seed dataを入れ直す。
うおw、FISIどころではない。
クラウドに逃がすと、少なくとも一部の責務は軽くなる。
Langfuse Cloudを見る。
OpenRouterでmodelを呼ぶ。
GitHub Actionsでtestを回す。
FastAPIでinterfaceを切る。
Streamlitでhuman-facing viewerを見る。
もちろん、全部が無料で簡単になるわけではありません。
ただ、Agent設計のループは軽くなる。
これは大きいです。
Agent開発してたら、Agentが必要になった
ここでもう一つ気づきました。
Agentを作っていると、Agentそのもの以外の作業が増えていきます。
PRを確認する。
Codexへの指示を書く。
READMEを更新する。
Notionに設計判断を残す。
Langfuse traceを見る。
Streamlit viewerで出力を確認する。
次のPRのtitle / descriptionを書く。
評価seedを整理する。
うおw、Agent開発にもAgentが必要じゃん。
AgentのためのAgent。
これもうわかんねえな。
ただし、ここで欲しいのは、勝手に全部決めるAgentではありません。
欲しいのは、開発者の判断を奪わずに、作業の境界を見えるようにしてくれるAgentです。
これは、自分が作っているcontract-question-agentのthesisとも少し似ています。
Agentはverdictを返すのではなく、verification questionsを返す。
Agent開発支援でも同じです。
全部決めてほしいわけではない。
判断するための材料を整えてほしい。
PRのdiffを見て、何が変わったかを整理する。
設計思想に反していないかを見る。
次に何を確認すべきかを出す。
Notionに残すべき判断をまとめる。
Agentに判断を渡すのではなく、判断の前提を整える。
ここはかなり一貫しています。
自律Agentではなく、判断材料を返すAgent
Agent開発支援Agent、というと少しメタすぎます。
ただ、欲しいものは意外と素朴です。
- PR確認
- Codex指示生成
- Notion更新
- README差分整理
- trace確認
- eval観点整理
- release note生成
こういう作業を、開発者の横で支援してほしい。
ここで重要なのは、自律性ではありません。
むしろ、勝手に進みすぎないことが大事です。
開発者がどの判断をしたのか。
何を次に確認すべきか。
どの設計判断をNotionに残すべきか。
そこを見えるようにする。
つまり、ここでも欲しいのはverdictではなく判断材料です。
このあたりは、普通のAgent demoとは少し違います。
「全部やってくれるAgent」ではなく、「判断の前に見るべき材料を整えるAgent」。
地味ですが、構造的に合理的な解ではあるかなと。
何を自分で持ち、何を外に出すか
結局、ずっと同じ話をしている気がします。
何を中に持つか。
何を外に出すか。
どこに境界を引くか。
RAGでは、推論構造をLLMの外に出した。
State Machineでは、状態をLLMの外に出した。
クラウド化では、Agent本体ではないインフラ責務を外に出した。
Agent開発支援では、開発判断の材料を外に出した。
全部、見えないものを外に出す話でした。
これは少し面白いです。
最初は、もっと賢いAgentを作ろうとしていた気がします。
でも実際に必要だったのは、賢さよりも境界でした。
推論の境界。
状態の境界。
責務の境界。
判断の境界。
Agent設計は、モデルの中ではなく、モデルの周りの構造にある。
この感覚がだんだん強くなっています。
おわりに
Agentを作っていたら、docker composeが育ちすぎました。
Agent開発をしていたはずなのに、いつの間にかインフラを飼育していました。
microservices architectureっぽくなった結果、視点までmicroになりました。
クラウドサービスに寄せることで、少し身軽になりました。
そして、Agent開発をしていたら、Agent開発そのものを支援するAgentが欲しくなりました。
AgentのためのAgent。
これもうわかんねえな。
でも、たぶん自然な流れです。
Agentを作るほど、周辺の判断・確認・記録・観測が増えていく。
それらを全部人間が抱えると、FISIの回転が重くなる。
だから、そこにもAgentが欲しくなる。
ただし、欲しいのは勝手に判断するAgentではない。
欲しいのは、判断の前提を整え、状態を見えるようにし、次に見るべきものを示してくれるAgentです。
ここまで来ると、Agent開発支援Agentもまた、同じthesisに戻ってきます。
verdictsではなく、判断材料を返す。
AgentのためのAgentも、結局はそこに落ちるのだと思います。
この記事を含む設計メモを、Zenn本『PoCで終わらせないAI Agent設計』としてまとめています。
作った人しか直せないAgentから、Runtimeで扱えるAgentへ。
Runtime / State / Checkpoint / MCP の責務境界を整理しています。
『PoCで終わらせないAI Agent設計』
Discussion
langchain や langSmith もある