どうも、マイクです。おはようございます。
七月二日、木曜日の朝七時を回りました。「zenncast」、今日も元気にお届けしていきます。

この番組では、Zennに上がっているトレンドの記事の中から、気になる技術ネタや開発の知見を、ゆるっと、でも中身はしっかりめにご紹介していきます。通勤・通学のおともに、コーヒー片手に、ゆるりとお付き合いください。

さて、きょう紹介する記事は、ぜんぶで五本。
ローカルのAIエージェント構築から、ダウンロードフォルダの自動整理、Claudeのコスト見える化、CシャープとUnityのメモリ解放のお話、そして機械学習コンペの評価設計の話まで、かなりバラエティ豊かです。

ではさっそく、一本目にいきましょう。

一つ目は、「クラウドのエージェントはお金もプライバシーも不安だから、自分で“Piっぽいエージェント環境をローカルで作っちゃおう」という記事です。
筆者がやっているのは、ローカルLLMとDockerのサンドボックスを組み合わせて、「壊せない、勝手に増設できない」自前エージェント環境を作る、というアプローチなんですね。

使っているモデルは、Qwenスリー・ポイント・シックス・サンジュウゴビー、Mixture of Experts版。これを、llamaドットcppで立ち上げて、そこまで強くないGPUでも実用的に動かせるように工夫しています。
その上で、Dockerコンテナの中をかなり要塞化しているのがポイントで、一般ユーザーで動かしたり、権限をガッツリ剥奪したり、ルートファイルシステムを読み取り専用にしたり、一時領域をtmpfsにしたりして、「中のエージェントが暴れてもホストは壊せない」「勝手にストレージを食い潰せない」ようにしています。

さらに面白いのが、インターネット検索の部分。
SearXNGというメタサーチエンジンと、CrawlフォーAIというクロール用の仕組みを、それぞれ別コンテナで動かしておいて、Pythonスクリプト経由でPiエージェントから呼び出せるようにしているんですね。
こうすることで、インターネットにはちゃんと出ていきつつも、自分のローカルデータをクラウドAPIに直接渡さずに済む。「検索というスキル」だけを外付けしているイメージです。

ローカルLLMだと、どうしても生の知識量は商用クラウドのモデルに比べると少なめなんですが、検索とクロールで外部情報を取り込みながら開発を進められる。
筆者は、「自分がメインで開発をしつつ、サブタスクをこのエージェントに任せて並行開発する」スタイルなら、スピードはクラウドに劣っても十分実用的だと話しています。
お金とプライバシーを守りながら、でも“賢い相棒”は欲しい、という人にはかなり刺さる構成だと思います。

。。.。。.。.

続いて二本目。
これは、macOS向けの「Downloadsフォルダを、ファイル名じゃなくて“中身をAIに読ませて”自動分類してくれるツール」の紹介記事です。

仕組みとしては、ユーザー側で「請求書」「写真」みたいな、入ってほしいフォルダだけ用意しておきます。あとは、ダウンロードフォルダにファイルを置いておくと、このツールが中身を読んで、「これは請求書だね」「これは画像だね」と判断して、自動的に最適なフォルダに移動してくれる、というものです。
どのフォルダにも当てはまらないものは、無理に動かさず、その理由付きで「未分類レポート」に一覧化してくれます。
そして各フォルダには、「このフォルダにはこういうファイルを入れてね」と説明を書いた、ドットゴーレム・エムディーというメモファイルを置いておけるようになっていて、それをAIが読んで分類精度を高めてくれる、という工夫もあります。

このツールの肝は、「AIをエージェントとして暴れさせない」という設計にあります。
つまり、AIにファイル操作の権限を直接持たせないで、「入力を渡したら、分類結果のJSONだけ返す純粋関数」に閉じ込めているんですね。
なので、もしAIが間違えても、被害はせいぜい「分類ミス」だけ。変なプロンプトインジェクションを食らっても、ファイルを消されたり、外に送られたり、っていうところまでは行かない。影響範囲をかなり小さく抑えています。

こうやって純粋関数にしておくと、モック化してテストしやすい、というメリットもありますし、「どこまで権限を与えるか」といった複雑なエージェント基盤や権限設計をやらなくて済みます。
実装としても、`claude -p`を一回呼ぶだけで済むようになっていて、別途APIキーを仕込んだり、キーチェーンに登録したりも不要。軽量で、安全で、でもちゃんとダウンロードフォルダを自動整理してくれるツールになっています。
「AIエージェントは便利だけど、なんでもかんでも任せるのは怖いよね」という人にとって、「AIは分類だけして、手を動かすのは人間側のプロセス」という割り切りは、かなり気持ちいい設計かもしれません。

。。.。。.。.

三本目は、「Claude Codeのサブスクを、VSCodeの中から常に“見える化”してくれる拡張機能、claude-cost」を紹介している記事です。

Claudeのコード補完とかチャット、ついつい使い過ぎちゃう、という人もいると思うんですが、この拡張を入れると、VSCodeのステータスバーに「五時間の上限」と「週次の使用率」が常に表示されます。
そこをクリックすると詳細パネルが開いて、「もしこれをAPIで使っていたら、これくらいの金額になるよ」とか、「サブスクの上限を超えちゃった分をAPIでまかなったと仮定したら、どれくらいの追加コストになりそうか」といった推定コストを、モデル別・日別のグラフ付きで確認できるようになっています。

実装面で工夫しているのが、サブスク使用率の取得方法です。
VSCodeのローカルには、その情報がそもそもないので、裏側で公式CLIのスラッシュユージッジ、使用状況コマンドを実行して、その結果だけを読みに行くようになっています。
さらに安全面として、環境変数から課金関連の設定をわざと削除して、「誤った課金経路では絶対に動かないようにする」という配慮もされています。CLIを使うとはいえ、うっかり別のAPIキーで変な課金が走らないようにしているわけですね。

パフォーマンス面では、巨大なログファイルを毎回ゼロから読み直さないように、差分キャッシュで集計を高速化しています。
更新のトリガーも工夫されていて、ファイル更新をきっかけにした「活動ベースの更新」と、拡張機能が実際に利用されているときだけ動く条件付きポーリングを組み合わせて、無駄なアクセスや負荷を抑えています。
結果として、「VSCodeの片隅で、さりげなく“今月どのくらい使ってるか”を教えてくれる、賢い家計簿」みたいな拡張になっている、というお話でした。

。。.。。.。.

四本目は、CシャープとUnityでの「メモリやリソースの破棄」を整理した記事です。
GCって何してるのか、DisposeとDestroy、Releaseって何が違うのか、けっこうごちゃっとしてしまいがちなところを、分けて説明しています。

まずCシャープのGC、ガーベジコレクタですが、「参照がゼロになった瞬間にオブジェクトを消している」わけではなくて、GCルーツと呼ばれる起点から、たどれないオブジェクトを「候補」として見つけて、タイミングを見て回収する仕組みになっています。
なので、「参照をnullにしたら即解放」みたいな感覚は、ちょっと違うんですね。

また、ファイナライザ、チルダクラスネーム括弧閉じ、いわゆるデストラクタっぽい見た目のものも、「すぐ動く後片付け」ではなく、あくまで「最後の保険」的な扱いに過ぎません。
一方でDisposeは、「メモリそのものを消す魔法」というよりも、「ファイルハンドルやネイティブメモリなど、GCには見えない外部リソースの寿命を、コード上で明示的に閉じる契約」だと説明しています。
つまり、GCが拾えないものを、自分で「もう使いません」と片付けるためのインターフェイス、という考え方ですね。

ここにUnityが絡むと、さらに話が複雑になります。
UnityEngineドットオブジェクトは、Cシャープのオブジェクトだけじゃなくて、エンジン内部のネイティブオブジェクトやGPUリソースをラップしています。なので、Cシャープ側でGCコレクトを呼んだところで、そのネイティブ側のリソースは解放されません。
自分で生成して所有しているTextureやMaterial、GameObjectなんかはDestroyで明示的に壊す必要がありますし、NativeArrayのような構造体はDisposeで片付ける必要があります。
さらにAddressablesでロードしたアセットは、ReleaseやReleaseInstanceで「このハンドルはもういらないよ」と教えてあげないといけない。

記事のポイントは、「型で一律に考えるんじゃなくて、『自分は何を所有していて、その寿命をどのAPIで閉じるのか』をちゃんと決めて扱おう」というメッセージです。
GCに任せていい部分と、自分でDestroy・Dispose・Releaseしなきゃいけない部分を、リソースの所有権ベースで整理することが大事だよ、という、Unity開発者には刺さる内容になっています。

。。.。。.。.

最後、五本目は、機械学習コンペの参加記。
テーマは、木材の近赤外スペクトルから含水率を予測するタスクで、自分の解法や評価設計をかなり丁寧に振り返った、オピニオン寄りのTips記事になっています。

このコンペでは、「trainとtestで樹種が被らない」という条件がありました。
著者はこれを「未知の樹種への汎化問題」だとしっかり捉えて、よくあるランダムなクロスバリデーションではなく、「樹種をひとつずつ抜いて検証する」リーブ・ワン・スピーシーズ・アウト、LOSOクロスバリデーションを採用しています。
Publicのリーダーボードがあまり信用しにくい状況だったこともあって、「LOSOのCVスコアと、その安定性、つまり平均と標準偏差」を指標にハイパーパラメータ探索を行い、「自分のCVを信じる、Trust your CV」を徹底した評価設計に重きを置いています。

手法面では、SNVという前処理をかけたあと、スペクトルが「平均ゼロでノルム一定の球面上」に乗るという性質を利用して、その制約を壊さないようにデータ拡張を設計しています。
具体的には、球面上で補間するSLERP Mixup。これは、異なる樹種で、かつ含水率が近いペアを選んで混ぜる、というやり方です。
さらに、接平面方向にノイズを乗せるTangent Gaussian Noise、スペクトルの連続シフト、ゆるやかなベースラインの変動などを組み合わせて、これらの適用確率をOptunaで自動調整しています。
モデル本体には、長い受容野を持つTCN、テンポラル・コンボリューショナル・ネットワークを採用し、EMAによる重みの移動平均やシードエンSEMBLEで予測を安定化させています。

結果として、PrivateのRMSEは十三・七五で順位は中位。ただ、LOSO-CVの平均RMSE十三・七一とほぼ一致していて、「自分のCV設計は、Privateに対してもそれなりに妥当だった」と振り返っています。
一方で、樹種ごとに系統的な残差が残っていることや、近赤外が木材の表面寄りの情報しか持たないことから、「スペクトルだけでは含水率が一意に決まらないケースもあるのでは」と推測。
そうした構造的な不確実性がありそうな場面で、残差スタッキングや単純なキャリブレーションを無理に乗せるのはやめておいた、という判断も紹介されています。

最後のまとめとしては、「単なるRMSEひとつの値だけでは、分布シフト下での安定性は測りきれない」「PublicとPrivateの設計や、樹種や含水率帯といったグルーピングを意識した評価指標が重要だ」という議論があり、
「何を“良いモデル”とみなすかは、評価設計に強く依存する」というメッセージで締めくくられています。
コンペに出ている人だけじゃなくて、実務でモデルを運用している人にも響く、評価指標の話ですね。

というわけで、きょうは五本の記事をご紹介しました。
ローカルLLMとDockerで要塞化した自前Piエージェントの話。
macのDownloadsを“中身ベース”で自動整理する、AI分類ツールの話。
Claude Codeのサブスク利用状況を、VSCodeで見える化するclaude-costの話。
CシャープとUnityのメモリ・リソース解放を、「何を所有して、どう寿命を閉じるか」で整理した話。
そして、木材のNIRスペクトルコンペで、LOSO-CVと評価設計を軸に戦った参加記まで、一気に駆け足で振り返ってきました。

それぞれの記事の詳しい内容や、元の記事へのリンクは、ショーノートにまとめてありますので、気になったトピックがあれば、ぜひそちらからじっくり読んでみてください。

この「zenncast」では、番組の感想や、「こんなテーマを扱ってほしい」といったリクエストも募集しています。
普段どんなふうにZennを使っているか、どんな技術にハマっているか、ゆるいお便りからガチ相談まで、大歓迎です。

それでは、きょうはこのへんで。
お相手はマイクでした。次回の配信でまたお会いしましょう。いってらっしゃい!

Related episodes

内容の近いエピソードを推薦しています