メインコンテンツへスキップ
見出し画像

"正常に動く"より先に、AIと「異常のとき」を設計した話|AIエージェント奮闘記 #6

    設計書は、どこまで細かく書けばいいのか——。

    この回で分かること

    • 設計でいちばん効いたのは、「正常に動く道」を描くことではなく、「異常のとき、どう振る舞うか」と部品どうしの「つなぎ目」を、人間の私が先に決め切ることだった

    • 正常系を書くのは、AIのほうがずっと速い

    • AIに渡す設計の"解像度"を、基本設計と詳細設計で二段に分けた理由

    画像
    連載の縦糸の4段階。請求書編はまだ「動く」の手前。第6話は、コードを書く一歩手前の「設計」を固める回

    前回は、請求書を自動で集めるツールの「仕様書」を、AIと一緒に作った話でした。何を作り、何を作らないかを文書で固める。そこまでが前回です。

    今回は、その仕様書を、実際に動かせる「設計」へ落としていく話です。要件定義から、基本設計、そして詳細設計へ。

    コードを書く一歩手前まで、AIとどう詰めていったか。

    バラバラな6つを、同じ「型」に揃える

    このツールの相手は、6つのサービスです。しかも、取り方がてんでバラバラでした。

    2種類のメールのAPIで取るもの、ブラウザを自動で操作して取るもの、課金情報のAPIで取るもの。種類でいえば4通りの方式が入り混じっています。

    (なお、サイトを操作して取りにいく方式は、サービスによっては利用規約で自動アクセスが制限される場合があります。自分のアカウントの自分のデータに限り、規約を確かめたうえで自己責任で——という前提は、前回のとおりです。)

    このまま一つずつ思うままに作ったら、6個の似て非なるプログラムが乱立して、手がつけられなくなります。

    そこで基本設計でまずやったのは、この6つを同じ骨格に揃えることでした。

    どのサービスも、「入口(起動して全体を仕切る部分)」「認証」「取得」「ファイル管理」という4つの役割で切り分ける(サービスによっては、いくつかの役割を1つの部品にまとめています)。そして、設定値や共通の道具は、一か所(config.py と common.py)に寄せる。

    こうして、中身は違っても、外から見た形はどれも同じ——という状態にしたのです。

    画像
    6つのサービスを、入口・認証・取得・ファイル管理の4つの役割で切り分けた。設定値と共通の道具は config.py と common.py の一か所に寄せた

    この骨格は、一度で決まったわけではありません。基本設計書は4つの版を重ね、第3版で共通の道具(common.py)を切り出し、第4版で部品をサービスごとのフォルダに分ける形に組み直しています。

    骨格が同じなら、1つ作れば、残りはその横展開で済みます。1か所の直し方が、そのまま全部に効く。

    これは、組込みで何度もやってきた感覚でした。機種ごとに違うデバイスを、「共通のドライバの形」に揃えてしまう。違いを吸収して、上から見たら同じに見えるようにする。

    基本設計とは、つまり、それぞれの責務の境界と、つなぎ目を決める作業です。

    骨格を決めたら、次に私がこだわったのは、「正常系」ではありませんでした。

    「正常に動く」より先に、「異常のとき」を決めた

    基本設計書に、私は「エラー分類と対応方針」という一枚の表を作りました。うまくいかなかったとき、どう振る舞うかを、実装より先に決めてしまうための表です。

    中身は、こんな具合です。

    • 認証に失敗したら、ログにエラーを残して、その回は止める

    • メール取得のAPIがエラーを返したら、その1通だけ飛ばして、残りは続ける

    • ファイルの書き込みに失敗したら、そのファイルだけ飛ばして、続ける

    • ネットワークが切れていたり、設定が足りなかったりしたら、気づいた時点で止める(設定は起動時に確かめる)

    画像
    基本設計書の「エラー分類と対応方針」。止めるのは認証・ネットワーク・設定の3つ。1通のメール、1つのファイルの失敗は飛ばして続ける

    貫いた原則は一つです。「1通の失敗で、全体を止めない」。

    毎月いろいろなサービスから集めてくるのですから、どれか1件がこけるのは当たり前。そこで全部が止まっては、自動化の意味がありません。

    1件こけても、残りはきっちり取り切る。そういう作りにしたかった。

    同じ考え方は、詳細設計の「重複防止」にも入れました。一度取ったものを二度取らないよう、処理済みの印を記録するのですが、その印は保存に成功してからだけつける。

    途中で失敗したものには印をつけない。だから次に動かしたとき、自動でもう一度挑みにいきます。

    正常にうまくいく道は、AIに任せれば、すぐに書いてくれます。でも、「どこで止め、どこで耐えるか」という異常時の方針は、人間が決めるべき設計判断です。

    安全性が問われる現場に長くいた人間として、私はいつも、正常系より先に異常系を詰める癖があります。その癖が、ここでもそのまま出ました。

    では、その方針を、どこまで細かくAIに渡したのでしょうか。

    基本設計と詳細設計で、AIに渡す"解像度"を変えた

    ここで、もう一つ意識したことがあります。AIに渡す設計の「粒度」を、わざと二段に分けたことです。

    基本設計は、粗い解像度でいい。誰が何を担当し、どうつながり、異常のときどうするか。いわば全体の地図です。

    一方、詳細設計では、ぐっと解像度を上げます。設定値を一覧にする(取得を始める日付、保存する拡張子、メールの件名で拾うキーワード……)。

    保存するファイル名の規則も、ここで決め切りました。たとえば「日付_金額_会社名.pdf」という形にし、Windowsで使えない記号は下線に置き換え、同じ名前が来たら3桁の連番をつける、というところまでです。

    画像
    AIに渡す設計の解像度を二段に分けた。基本設計は全体の地図、詳細設計は設定値の一覧とファイル名の規則まで

    なぜ、わざわざ二段に分けるのか。

    設計が粗すぎると、AIは足りないところを推測で埋めてしまいます。これは前回書いた落とし穴です。

    かといって、何もかも細かく指定すると、それはもう自分でコードを書いているのと変わらず、AIの速さが死んでしまう。

    粗すぎず、細かすぎず。ちょうどいい解像度を見つけて渡すこと——これが、AIへの「渡し方」の技術なのだと思います。

    連載も中盤に入って、私はようやく、この距離感がつかめてきた気がしました。

    設計図は、きれいに仕上がりました。ただ、その図の中に、後で私を待ち構えるものが、ひとつ紛れていました。

    図の上では、認証はたった数行だった

    設計図の中で、認証の流れは、驚くほど簡潔に描けます。

    「キャッシュを確認する。有効なら、それを使う。なければ、デバイスコードという方式で認証して、結果を保存する」。たったこれだけ。図にすれば、数本の矢印で終わります。

    設計としては、これで正しいのです。AIも、よどみなくこの流れを描いてくれました。

    でも、個人開発でいちばん泥臭いのは、たいていこの認証まわりです。

    設計図の上ではあれだけ簡潔だったものが、実装に入ると、何日も人を悩ませる壁になる。このときの私は、それを、まだ少し軽く見ていました。

    その話は、次回にします。

    設計とは、"異常"と"つなぎ目"を決めることだった

    こうして、要件定義から基本設計、詳細設計までを、AIと一緒に仕上げました。

    振り返ると、設計の段階でいちばん大事だった私の仕事は、正常に動く道を描くことではありませんでした。異常のときの振る舞いを先に決めること。部品どうしのつなぎ目を固定すること。そして、AIに渡す設計の粒度を選ぶこと。 この三つです。

    前回書いた「AIに推測で埋めさせない」が、設計では「異常時を先に決めておく」「ちょうどいい解像度で渡す」という、もう一歩具体的な形になりました。中盤の"渡し方のコツ"が、少しずつ見えてきた感覚です。

    まとめ

    • 任せたこと:正常に動く道を描くこと

    • 握ったこと:異常のときの振る舞い、部品どうしのつなぎ目、AIに渡す設計の粒度

    • 次の課題:図の上ではわずか数行だった認証を、実際に動かすこと

    設計とは、正常系を描くことではなく、"異常"と"つなぎ目"を決めることでした。


    そして私は、このきれいな設計図を手に、意気揚々と実装へ進みました。図の上ではわずか数行だった認証(OAuth)が、最初の大きな壁として立ちはだかるとも知らずに。

    次回は、その認証の壁に、AIと二人でどう挑んだか——いちばんの山場を書きます。

    仕事の依頼(ココナラ):作業の自動化を頼む/Claude Code の使い方を教わる

    あなたへのおすすめ