odiak.net

Cloudflare Agentsで自分をマイクロマネジメントするAIを作った

Cloudflare Agentsで、自分をマイクロマネジメントしてくれるAIエージェント「Kuro」を作っている。

朝、ぼんやりしたまま一日が始まることがよくある。

やることはある。やった方がいいことも分かっている。Obsidianのdaily notesにタスクも書いてある。
それなのに、朝の時点でちゃんと今日やることを決めないまま、なんとなく目についたタスクから始めてしまう。
あるいは、ぐだぐだしているうちに午前中が溶ける。

決めても忘れる。途中で脱線する。やりたくないことは先延ばしする。

全部です。

なので、自分には「優しい秘書」よりも、多少うるさくても毎日やることを確認してくれるマイクロマネージャーが必要なのでは? そう思って作ったのがKuroだ。

KuroはObsidianのdaily notesを読み、最近の会話や未完了タスクを見ながら、今日やることを一緒に決めたり、途中で「それ進んでる?」と話しかけてきたりする。

この記事では、Kuroをなぜ作ったのか、Cloudflare Agentsでどういう構成にしたのか、そして「向こうから自然に話しかけてくるエージェント」を作ってみてどうだったかを書いてみる。

自分にはマイクロマネージャーが必要だった

僕はもともとObsidianのdaily notesを使っている。

今日のタスク置き場でもあり、日記でもあり、メモ帳でもある。
仕事のことも個人のことも、思いついたことも雑多に書いていて、一般的な使い方ではないかもしれないが、自分にとっては生活と仕事のログの中心になっている。

ただ、さっきも書いたように、書いてあるからといって実行できるわけではない。

そこで、Obsidianに書いたタスクやメモを読んで、「今日はこれをやろう」「これは昨日から残っている」「これは確認だけでも進めよう」と言ってくれるエージェントが欲しくなった。

Kuroは、まさにそういう用途のために作っている。

例えば、Kuroはこんな感じで話しかけてくる。

そろそろ16時。〇〇の申請、今週引きずってた分をここで畳めそう?週末の重り、ここで外せたら最高だね。

別のときには、脱線しそうになっているところで、こんなふうに言ってきた。

割り込みあるあるだよね。一旦その別件をノートに書き留めて「あとで」にすると、頭がスッキリしてチャット機能に戻れるかも。15分だけやってみる?

こういうメッセージは、一瞬「うざ」と思うこともある。
でも、自分にはそれくらいがちょうどいい。

「今日はこのタスクを終わらせるだけでもOK」とか、「確認だけでもいいからやってみよう」とか、タスクのハードルをかなり下げてくれるのも助かっている。
やりたくないタスクを、完了ではなく「15分だけ」「確認だけ」という形に分解してくれると、少しだけ動きやすくなる。

Obsidianを唯一の情報源にする

Kuroは、新しいTODOアプリとして作ったわけではない。

僕の場合、タスクやメモはすでにObsidianのdaily notesにあるので、Kuroもその上に乗せることにした。

KuroはバックエンドからObsidian Syncに接続してVaultのコピーをCloudflare側に持ち、そのMarkdownを読み・検索してAIの応答生成に使う。
daily notesの場所も、Obsidian側の設定を見ながら解決する。

この同期まわりはけっこう大変だったが、詳しく書くと長くなるので、Obsidian Sync連携の話は別の記事にしようと思う。

とにかく、自分のメモも、今日のタスクも、昨日のやり残しも、最近の考えごとも、すでにdaily notesに入っている。
AIのために新しいデータベースを用意しなくても、Kuroはそこを読めば自分の文脈をかなり自然に理解できるわけだ。

Cloudflare Agentsで作る

KuroはCloudflare上で動いている。
使っているのは、Cloudflare Workers、Cloudflare Agents、Durable Objects、D1、R2、Vectorize、Workers AI / AI Gatewayなど。

Cloudflareを選んだ理由はかなり単純で、Cloudflareのプラットフォームが好きだったのと、Cloudflare Agentsを試してみたかったからである。

エージェントを作ろうとすると、チャットの状態、ユーザーごとの永続化、スケジューリング、通知、検索、モデル呼び出しなど、必要なものが意外と多い。
Cloudflareだと、それらをかなり低いインフラコストでまとめて扱える。

Workers AIでいろいろなモデルを気軽に試せるのもよかった。
支払いもCloudflareにまとまるので、個人開発として始めるハードルが低い。

フロントエンドもバックエンドも、Codexにかなり書いてもらった。
正直、自分で全部のコードを細かく読んでいるわけではないが、Reactの画面とWorkers側のAPI、Durable Objectの状態管理をまとめて作っていく体験はわりとスムーズだった。

一方で、大変なのはCloudflare Agents特有の問題というより、AIエージェント全般の問題だと思う。

AIは想定外の出力をする。
ツール呼び出しが変な形になったり、返答が中途半端になったり、書き込み承認の流れが壊れたり。原因を調べてプロンプトや実装を直す、その繰り返しである。

でも、Cloudflare上でこの一連の実行環境を作れること自体はかなり楽だった。

向こうから話しかけてくる仕組み

Kuroで必ず入れたかったのが、エージェントの方から話しかけてくる仕組みである。

普通のチャットAIは、こちらが質問したら答えてくれる。
でも、自分が欲しかったのはそれだけではない。

朝に「おはよう、昨日はこれをやり残してたね。他に今日やることは?」と聞いてほしい。
午後に「さっき言っていた作業は進んでる?」と確認してほしい。
何日も残っているタスクがあれば、そっと引っ張り出してほしい。

つまり、Kuroは受け身のチャットボットではなく、少し能動的なマネージャーであってほしい。

ただし、単に一定間隔で通知するだけだと、すぐにうるさくなる。
なのでKuroでは、だいたい次のような流れにしている。

  1. Obsidian Vaultを同期する
  2. 最近のdaily notesや未完了TODOを見る
  3. 最近の会話を見る
  4. 時間帯や前回の状態を見る
  5. 今話しかけるべきかを判断する
  6. 話しかけるなら短いメッセージを作る
  7. 次にいつ確認するかを決める

この「話しかけるべきか」の判断は、通常のチャット応答とは別のLLM呼び出しにしていて、スケジューラー兼プランナーのようなものだ。

たとえば、最近返信したばかりならスキップするし、深夜なら静かにする。
前回の発言も見て同じことを繰り返さないようにし、話しかけなかった場合も、その判断を裏の履歴として残して次回に使う。

これがKuroの中で一番面白いところだと思っている。

こうやって向こうから話しかけてくるので、正直うっとうしく感じる瞬間もある。
それでも自分の場合は明らかにプラスで、少なくとも、ひとりだったら避けていたタスクに手をつけるきっかけにはなっている。

Web UIからTelegramへ

最初のKuroは、Web UIとWeb Pushで使っていた。
Webのチャット画面があって、プロアクティブなメッセージはWeb Pushで通知する、という形である。これはこれで動く。

ただ、途中でTelegram Bot連携を追加した。
これがかなりよかった。

Telegramなら通知がちゃんと届くし、そのままアプリから返信できる。
スマホで通知を見て、その場で「OK」「あとでやる」「それはもう終わった」みたいに返せるのは、Web UIだけより自然だ。

Botを作るのも思ったより簡単だった。
Telegram側でBotを作り、Webhookを設定し、Kuro側でユーザーとTelegramアカウントを紐づける。細かい部分はあるが、体験としてはかなり素直だった。

書き込みは勝手に反映しない

KuroはObsidianの内容を読むだけでなく、書き込みもできる。
今日のdaily noteにメモを追加したり、完了したTODOにチェックを入れたり。

ただし、勝手に書き換えるのは怖い。

最初は承認付きの書き込みフローを作っていたが、複数の提案があると分かりづらかったり、Telegramから承認するときに扱いづらかったりした。

今は、Kuroが直接書き込むのではなく、変更案(diff)を作る形にしている。

「このdaily noteにこう追記する」「このTODOを完了にする」といった差分を提案し、自分はそれを見てから適用できる。
元のノートがすでに変わっていたらコンフリクト扱いにして、無理に上書きはしない。

AIに書ける力を渡しつつ、最後の適用権は自分が持つ。

これは、個人のObsidian Vaultを扱ううえでかなり大事な設計だと思っている。

KimiからClaudeへ

最初、KuroのモデルにはKimi K-2.5やKimi K-2.6を使っていた。

理由は、安さと賢さのバランスがよかったから。会話もかなり自然だったし、ツール呼び出しもそれなりに動いていた。

ただ、日本語では少し気になるところがあった。

たまに漢字を間違えたり、語彙や表記揺れの理解が怪しいことがあった。
致命的ではないが、Kuroは毎日話す相手なので、細かい違和感が積み重なる。

その後、Cloudflare AI Gateway経由でClaude Sonnetに切り替えた。

一番よくなったのは、日本語の流暢さである。
Kimiも十分自然だったが、Claudeの方が漢字や言い回しの違和感が少なく、少しフレンドリーな感じになった。

ツール呼び出しも若干よくなった気がするが、これは気のせいかもしれない。
キャラクター自体はsystem promptでかなり指定しているので、モデルだけで大きく変わったわけではない。

それでも、毎日使うエージェントでは、文体の安定感はかなり大事だった。

システムプロンプトはCodexと育てた

Kuroのsystem promptは、ほぼCodexに書いてもらっている(Claudeも使ったかもしれない)。

Kuroには、かなり細かい振る舞いのルールがある。

こういうプロンプトを、人間がゼロから手で書くのはかなりつらい。

最近の会話や失敗例をCodexに渡して、「この挙動を直したい」「もっとこういう返答にしたい」と相談すると、system promptや実装をかなりいい感じに直してくれる。

エージェントを作るために、別のエージェントにエージェントの振る舞いを改善してもらう。

これは今の個人開発らしいところだと思う。
正直、人手ではもう作れんわ、という気持ちがある。

今後やりたいこと

Kuroは今のところ自分用のツールだが、将来的には一般公開のサービスにしてもいいかもしれないと思っている。

需要があるかは分からないが、少なからず「自分をマイクロマネジメントしてほしい人」はいるのではないかと思っている。

もちろん、全員が同じうるささを求めているわけではない。
今も頻度設定はあるが、厳しめのマネージャーから優しい秘書まで、キャラクターを選べるようにしても面白いかもしれない。

Kuroを作っていて感じたのは、AIエージェントは「汎用的に賢い」だけではなく、「自分の弱さに合わせて作れる」ところが面白いということだ。

自分の場合は、朝にぼんやりして、決めたことを忘れて、やりたくないことを先延ばしする。
だから、それを見越して話しかけてくれるエージェントを作った。

Cloudflare Agentsを使うと、こういう自分用エージェントをかなり低いハードルで作れる。

Kuroは、少しうるさい。
でも、自分には必要なマイクロマネージャーである。