ACES エンジニアブログ

ACESのエンジニアブログです。

認可基盤の移行を安全に進める- Cerbosの選定から新旧基盤の並行稼働、切り替えまで

はじめに

こんにちは、株式会社ACES でソフトウェアエンジニアをしている中野です!
最近シャクティマットを購入し、寝る前に悶えながら楽しんでます。

私が所属するチームでは、オンライン商談や会議を高精度に記録・文字起こし・要約・解析する、AI議事録・セールスイネーブルメントツール「ACES Meet」を開発・運用しています。 私はACES Meetの認可基盤を刷新するプロジェクトで、バックエンドとインフラの設計/開発を担当しました。新しい認可基盤は8月中旬にリリースされ、無事に移行を完了しています。

本記事では、このプロジェクトにおける認可エンジンの選定から、新旧認可基盤の並行稼働、安全に新認可基盤へ切り替えるまでの取り組みを紹介します。

support-meet.acesinc.co.jp

認可基盤を移行することになった背景

ACES Meetでは従来、アプリケーション内に直接記述した権限チェックによって認可を行っていました。従来は、テナント管理に関するロールが「管理者」と「メンバー」の2種類に限られていました。また、会議にアクセスできるユーザーの操作権限も一律で、閲覧のみ・編集のみといった区別ができませんでした。

この仕組みでは「誰が・どのデータにアクセスでき、どの操作を行えるか」を細かく制御できません。 そのため厳格な権限管理が求められるエンタープライズ企業では、内部統制上の要件を満たせず、ACES Meetを導入できないケースがありました。

より多くの企業にACES Meetを利用していただくためには、アクセス権限をより厳密に管理できるよう、認可基盤を刷新する必要がありました。

認可エンジンの選定と、会議一覧の認可フィルタ設計

Cerbosを選んだ理由

当初は、認可エンジンとしてOpenFGAを選定していました。主な理由は、複数サービスの認可データを一元管理できること、特定のクラウドへのロックインを避けられること、そしてReBAC(ユーザーと対象との関係性に基づいてアクセスを制御する仕組み)に対応できることでした。

しかし、認可基盤の利用を想定していた別サービスの提供が終了し、利用対象がACES Meetのみになったことで、認可データを一元管理する必要性が薄れました。その結果、OpenFGAを選定した当初の前提が変わったため、認可エンジンを改めて選定することにしました。

再選定では、OpenFGA、AWS Verified Permissions(AVP)、Cerbosを最終候補とし、以下の評価軸で比較・検討しました。

評価軸 OpenFGA AVP Cerbos
権限データの置き場所 エンジン側に関係タプルを持つ
→ 二重管理
アプリ側 アプリ側
一覧のフィルタリング ListObjects
(グラフ探索)
BatchIsAuthorized
最大30件
条件生成なし
PlanResources APIが条件を返す
大規模データへの適合性 関係データ量が運用負荷に直結 推移的親 100件
(引き上げ不可)
認可データを保持しないため
関係データ量による制約を受けにくい
インフラ適合 中央集権ストアの追加運用 AWS依存が強い 既存ECSにサイドカー追加のみ

最終的に、認可エンジンとしてCerbosを採用しました。決め手は、認可データの二重管理を避けられることと、一覧取得に必要な認可条件を生成できることです。

OpenFGAのように認可専用のデータストアを持つ構成では、アプリケーションDBとの二重書き込みや、データの整合性を担保するための仕組みが必要になります。一方、Cerbosはステートレスな認可エンジンであり、アプリケーション側のデータをリクエストに含めて認可判定を行えます。

AVPも認可データをアプリケーション側に保持できる点では同様でしたが、一覧取得ではBatchIsAuthorizedの最大30件という上限が制約となりました。以上から、今回の要件にはCerbosが最も適していると判断しました。

会議一覧をどう認可フィルタするか

Cerbosで認可を実装するうえで、課題の一つとなったのが会議一覧です。 ACES Meetでは、会議一覧の検索・絞り込みにElasticsearchを利用しています。 そのため、閲覧可能な会議だけが検索結果に含まれるよう、認可条件をElasticsearchの検索クエリへ組み込む必要がありました。

ここで鍵となるのが、CerbosのPlanResources APIです。リソースごとにアクセス可否を問い合わせるのではなく、指定したユーザーがアクセス可能なリソースの条件を取得できます。

例えば、あるユーザーについて問い合わせると、単純な許可・拒否ではなく、 「公開範囲がテナント全体である」または「参加者に本人が含まれている」といった 条件式が返されます。レスポンスは次の3種類です。

レスポンス 意味 処理
KIND_ALWAYS_ALLOWED 無条件に許可 フィルタなし
KIND_ALWAYS_DENIED 無条件に拒否 空結果
KIND_CONDITIONAL 条件付き ASTをクエリに変換

無条件の許可・拒否に該当しない場合は、KIND_CONDITIONALとして、認可条件が抽象構文木(AST)の形式で返されます。会議一覧へ適用するには、このASTをElasticsearchのクエリへ変換する必要があります。そこで、変換方法として次の3案を検討しました。

案1:閲覧可能な会議IDをDBから取得し、Elasticsearchへ渡す(見送り)

Cerbosでは、認可条件をクエリへ変換する公式アダプターがいくつか提供されています。この案では公式のSQLアダプターを利用できる点がメリットでした。

一方、閲覧範囲が広いユーザーではIDリストが巨大になり、Elasticsearchのtermsクエリの上限や性能面で問題が生じる可能性がありました。また、DBで先に絞り込んだ大量のIDをElasticsearchへ渡す構成になるため、Elasticsearchによる検索・絞り込みの利点も活かしにくくなります。以上の理由から、この案は見送りました。

案2:Elasticsearchで検索した後、Cerbosで閲覧できない会議を除外する(見送り)

実装上は単純に見えますが、この方式ではページネーションと総件数の整合性を保てません。 例えば、1ページ50件で3ページ目を取得するためにElasticsearchから150件を取得しても、認可判定後に80件まで減れば、3ページ目を返せなくなります。総件数についても、Elasticsearch上では10万件でも、実際に閲覧できるのは3,000件といった不一致が生じます。以上の理由から、この案も見送りました。

案3:認可条件そのものをElasticsearchクエリへ変換する(採用)

Cerbosが返した認可条件をElasticsearchクエリへ変換し、検索条件の一部として組み込む方式です。認可条件を含めて検索するため、ヒット件数とページネーションをElasticsearch側で正しく計算できます。案1のようなIDリストの肥大化や、案2のようなページネーションの不整合を構造的に回避できるため、この案を採用しました。

ただし、Cerbosが公式に提供しているアダプターはSQLAlchemy、Prisma、Mongooseなどを対象としており、Elasticsearch向けのものはありませんでした。既存アダプターの実装はいずれも数百行程度と比較的シンプルだったため、それらを参考にElasticsearchアダプターを自作することにしました。

全体の流れは次のようになります。

PoCによる設計の具体化

Cerbosの採用を決め、認可フローの大枠を整理した段階で、実際の構成や実装方法を具体化するためのPoCを作成しました。 PoCでは、Cerbosによる認可判定を既存APIへ組み込む流れや、PlanResources APIが返す認可条件をElasticsearchのクエリへ変換する方法を検証しました。さらに、実装を通じて認可に必要なデータを洗い出し、データモデルや各コンポーネントの責務についてチームで議論しました。

この検証により、机上の設計だけでは見えにくかった影響範囲や実装上の難所を、 早い段階で具体化できました。PoCで得られた結果をもとに設計と計画を見直し、 本実装へ進みました。

データの移行、新旧並行稼働、新認可への切り替え

Cerbosを採用し、認可フローの設計と実装方針を固めた後、新しい認可基盤への切り替えを進めました。移行に伴うリスクを段階的に減らすため、プロセスを次の4つのフェーズに分けました。

パラレルランまでに、新旧モデル間のデータ整合性と、新旧の認可判定が一致することを確認します。 これにより、実際にユーザー影響が生じる新認可へ切り替えでは、切り替えそのものに集中できるようにしました。

フェーズ やること この時点の判定 ユーザー影響
デュアルライト
(新旧二重書き込み)
新規・更新を旧・新の両モデルへ書く 旧認可 なし
データ移行 既存データを新モデルへ揃える(DB → Elasticsearch) 旧認可 なし
パラレルラン
(新旧認可の並行検証)
新認可を影で評価し、一致率を計測 旧認可 なし
新認可へ切り替え 新認可へ切り替え、API+UI実装、デュアルライト廃止 新認可 あり

デュアルライト(新旧二重書き込み)

最初に、認可に関わるデータを旧モデルと新モデルの両方へ書き込む、デュアルライトを導入しました。会議の作成・共有、公開範囲の変更、メンバーの招待・削除、管理系処理など、認可結果に影響する書き込み経路を洗い出しました。そのうえで旧モデルを作成・更新する際に、後方互換性を保つ形で新モデルも作成・更新するようにしました。

デュアルライトをデータ移行より先に導入したのは、稼働中のサービスでは、移行処理の実行中にもデータが更新され続けるためです。既存データを先に移行しても、その間に発生した変更が新モデルへ反映されなければ、移行が完了した時点ですでに新旧モデル間に差分が生じます。 そこで、まずデュアルライトによって「これから発生する変更」を両方のモデルへ反映できるようにし、その後のデータ移行で「それ以前に作られたデータ」を新モデルへ反映しました。

新旧モデルへの書き込みを同一トランザクションに含めれば、データの不整合は防ぎやすくなります。しかし今回は、あえてトランザクションを分けました。 新認可へ切り替えるまでは旧モデルを正とし、新モデルを実際の認可判定には利用しないためです。新モデルへの書き込み失敗によって既存機能まで利用できなくなることを避けました。 万が一、不整合が発生した場合のためにデータの差分をRedashで監視し、差分が生じた場合はその都度対応する方針を取りました。

データ移行

次に、既存データを新モデルへ移行しました。一括変換には、繰り返し実行しても結果が変わらない冪等なワンショットスクリプトを用意し、ドライラン、本番実行、検証の順に進めました。 まずDBのデータを移行し、その結果をもとにElasticsearchのデータも移行しました。

1回目:深夜帯に実施したものの、途中で中止

DBのマイグレーションは、本番環境のコンテナでメモリが不足し、途中で失敗しました。sandboxとstagingでは正常に完了していましたが、本番環境とはデータ量に大きな差があり、本番規模で初めて生じる課題を事前に洗い出せていませんでした。 原因は、移行スクリプトが一度に多くのデータをメモリへ読み込んでいたことです。必要なメモリ量を見積もったうえで、コンテナのメモリを一時的に4GBから16GBへ増やして再実行し、DBのデータ移行を完了しました。

一方、Elasticsearchのマイグレーションは当初順調に進んでいたものの、想定以上に時間がかかり、深夜帯には完了しない見通しとなりました。さらに、処理中にデータノードのストレージ空き容量が急速に減少したため、継続するリスクが高いと判断し、処理を中止しました。

sandboxとstagingでの検証時にエラーが頻発したことから、バッチサイズを必要以上に小さくしていたことも、処理時間が長引いた一因でした。検証環境と本番環境ではElasticsearchのスペックが大きく異なるため、その差を考慮してバッチサイズを設計すべきでした。

ただし、バッチサイズを大きくしていればストレージ消費の問題がより早く顕在化していたと考えられるため、いずれにしても1回目の処理は中止する必要があったと考えています。

2回目:Elasticsearchのデータ移行を日中帯に実施し、完了

1回目の結果からストレージ容量の不足が判明したため、事前にElasticsearchのストレージを増設しました。

また、1回目はバッチサイズを大きくして深夜帯に短時間で完了させる想定で実施したのですが、方針を変更しました。 バッチサイズをサービスに影響が出ないレベルに抑え、日中帯に時間をかけて処理することにしました。通常時より負荷は高まりましたが、サービスへの影響はなく、最後まで実行できました。

2回目はメンテナンスモードを使用しなかったため、処理中の更新によってデータに差分が生じる可能性がありました。そこで、移行後に新旧データの整合性を検証し、差分が見つかった場合にアラートを出す仕組みを用意しました。

パラレルラン(新旧認可の並行検証)

データ移行後は、本番トラフィックを利用して新旧の認可判定を比較するパラレルランを実施しました。認可を行うすべてのAPIを修正し、ユーザーへの応答には従来どおり旧認可の判定を使用しながら、同じ入力を新認可でも評価して、その結果をログへ記録しました。これにより、ユーザーへ影響を与えることなく、新旧の判定が一致しているかを検証できるようにしました。 さらに、判定の一致率を継続的に確認できるよう、Redash上に監視環境を構築しました。

この段階でパラレルランを実施したことで、デュアルライトやデータ移行に起因する不整合を、新認可へ切り替える前に検知・修正できました。その結果、ユーザー影響を抑えながら、安全に切り替えを進めることができました。

新認可への切り替えと、ロールバックを前提としない判断

パラレルランによって新旧の認可判定が一致することを確認した後、実際の判定を旧認可から新認可へ切り替えました。このとき、大きな論点となったのがロールバック方針です。

当初は「新認可への切り替え → API・UIのリリース → デュアルライトの廃止」という順序で進め、切り替え後もしばらくデュアルライトを維持する想定でした。リリース後、致命的な問題が発生した場合に、旧認可へ戻せる状態を残すためです。

しかし、実際に検討すると、次の課題がありました。

  • リリース後もデュアルライトを維持するためには、書き込み方向を「旧 → 新」から「新 → 旧」へ切り替える必要があり、実装コストが大きい
  • 新モデルで導入した概念には旧モデルに対応する表現がなく、完全に巻き戻すのは現実的ではない

これらを踏まえ、今回のリリースはロールバックを前提とせず、問題が発生した場合は新認可側を修正する方針を採用しました。この方針をもとに、新認可への切り替えと同時に、ロールバックのために残していたデュアルライトと旧モデルへの参照も廃止しました。

うまくいった点と反省点

うまくいった点

今回の移行で特に効果的だったのは、事前調査とPoCで得た知見を、早い段階からプロジェクト計画へ反映できたことです。技術的な不確実性や影響範囲をチームで共有したことで、リスクの高い工程を把握し、状況に応じて計画を見直しながら進められました。

また、移行をデュアルライト、データ移行、パラレルラン、新認可への切り替えという段階に分けたことも、安全性を高めるうえで有効でした。特にパラレルランでは、本番トラフィックを使って新旧の認可判定を比較することで、デュアルライトやデータ移行に起因する不整合を、ユーザーへ影響が及ぶ前に検知・修正できました。

反省点

本番と同等のデータ量やインフラ条件を前提とした検証が不足していました。 sandboxやstagingでは正常に動作していても、本番ではDBのデータ移行時にメモリが不足し、Elasticsearchのデータ移行では処理時間やストレージ消費が想定を上回りました。 いずれも、本番規模で初めて顕在化した問題です。 事前に対象件数からメモリ使用量、処理時間、ストレージ使用量を見積もり、本番相当の負荷試験や小さな単位での試行を行っていれば、より精度の高い実行計画を立てられたはずです。

また、デュアルライトは想定以上に影響範囲が広く、書き込み経路の洗い出しと見積もりが不十分でした。実装後の監視によって抜け漏れを検知・修正できたものの、会議の作成・更新だけでなく、共有、グループ、メンバー管理、管理系処理など、認可データへ影響する経路を事前に体系立てて整理する必要がありました。今後、横断的なデータ変更を伴う移行を行う際は、機能やデータを起点とした調査だけでなく、API、バッチ処理、管理機能など複数の観点から書き込み経路を洗い出し、影響範囲を段階的に検証する必要があります。

加えて、新しい認可モデルへの移行に伴って一部の既存機能を対象外としましたが、 その機能が想定以上に利用されていたことをリリース後に把握しました。 技術的に安全な切り替えだけでなく、利用実態の把握と仕様変更によるユーザー影響の確認も移行計画に含めるべきでした。アクセスログや問い合わせ履歴の確認、対象ユーザーへのヒアリングなどを通じて、変更・廃止する機能の利用状況を事前に確認し、必要に応じて代替手段や段階的な移行期間を用意する必要がありました。

おわりに

今回は、認可エンジンの選定から、Elasticsearchの会議一覧へ認可条件を組み込む方法、デュアルライト、データ移行、パラレルランを経て新しい認可基盤へ切り替えるまでの取り組みを紹介しました。PoCとパラレルランによって不確実性を早期に減らせた一方で、本番規模を想定した検証と、仕様変更によるユーザー影響の調査には改善の余地がありました。今回得た知見を今後の移行計画にも取り入れ、より安全で予測可能な形でプロジェクトを進めていきたいと考えています。

ACESでは現在、複数のエンジニアポジションで採用を行っています。本シリーズを読んでACESの開発に興味を持っていただけた方は、ぜひカジュアル面談でお話ししましょう!

recruit.acesinc.co.jp

open.talentio.com

音声認識を題材に見る、基盤モデル時代の構造化AI開発

1. はじめに

こんにちは。株式会社ACESでAIエンジニアのEMをしている阿久澤(@kei_akuzawa)です。最近新しく遊んだボードゲームは『サンレンタン』です。左脳ばかりでなく右脳も鍛える必要がありそうです。

さて、今回は「音声認識」を題材に、構造化AIに対しての個人的なポジションを語る記事となります。ここで構造化AIとは、「音声認識」「ドキュメント構造化」「物体検知」といった、非構造化データをLLMが理解しやすい形式に変換するアルゴリズム全般を指す弊社の造語です。

ACESは2022年3月ごろから『ACES Meet』というAI議事録SaaSを運営していますが、この内部では自社開発した音声認識システムが使われ続けてきました。音声認識に限らず、松尾研究室の出自を活かした構造化AIモデルの開発力は、長らく弊社のコアコンピタンスの一つでした。

しかし現在、Whisper、GPT等の「基盤モデル」が伸長する中で、「音声認識システムをどこまで内製するべきか」が問い直されています。基盤モデルとはインターネット上の膨大なデータを用いて事前学習され、幅広いタスクに転用できるAIモデルのことです。基盤モデルの発展に伴い、書き起こしのような汎用タスクはAPI call一発で実行可能になるため、一見すると音声認識システムの開発は不要・または非常に簡単に見えると思います。

このような状況下にあって、弊社では音声認識を含むデータ構造化AIを開発・技術資産化することについて、方針の見直しや注力ポイントの変更を絶えず迫られてきました。現在のACESは、大規模な予算や計算基盤を必要とする基盤モデル層のプレイヤーではありません。しかし今現在でも、基盤モデルとは別のレイヤーで構造化AIの開発を続けています。本記事では、その理由と内容について簡単にご紹介します。

2. なぜやるか

2.1 システム全体の最適化により、優れた体験を提供する

さて、基盤モデルの進化によって、一定品質の書き起こしを得ること自体はかなり容易になっています。今後も、汎用的な音声認識モデルの性能は上がり続け、モデル単体の性能差で差別化をすることは難しくなると考えています。

一方で現在の基盤モデルのAPI call単体では、実際のプロダクトや顧客業務で求められる要件や品質を満たすことは困難な場合が多いです。例えばACES Meetであれば、①文字起こしをその発言者・発言時刻とセットで表示する、②一時間を超える長尺の会議を処理する、といった要件が発生します。これに対して、Hugging FaceのWhisper(オープンソースで誰でも利用可能な音声認識モデル)では、30秒程度の音声を書き起こしに変換する機能しか持たないために、単体で要件を満たすことは不可能です。*1

ACES Meetでは、文字起こしをその発言者・発言時刻とセットで表示します。例えば発言時刻があることは、文字起こしと動画再生の間で相互参照を可能にし、効率的な会議振り返りをサポートします

この例は、我々がプロダクト上で稼働させている音声認識のアルゴリズムが「一つのモデル」ではなく、複数の処理を組み合わせた「システム」であることを示唆しています。音声区間検知、話者照合、書き起こし生成など、いくつかのコンポーネントをパイプラインとして構築し、ユーザー体験を支えるのに必要な機能・品質を実現しています。

ここに、ACESが構造化AIを開発・改善し続ける理由があります。基盤モデルを外部サービスをそのまま使うだけでは実現できない機能要件・届かない品質要件は、システム全体の設計と統合によって達成する必要があるのです。基盤モデルや外部APIを否定することはなく、むしろコンポーネントの一部としては積極的に採用しています*2。その上で、各コンポーネントの精度が高いことを前提に、システム全体としての最適化=「すり合わせ / インテグラル」は最終的な差別化にとってクリティカルである、というのが現在の私の肌感覚です。

ただし注意点として、基盤モデルや外部サービスが代替可能な領域は徐々に広がっていくはずです。例えば音声区間検知と書き起こし生成をセットで行うAPIなども存在します。そうした流れの中で、外部サービスで十分な領域はブラックボックス的に任せて使いつつ、より広範なシステム全体の最適化に仕事の力点が移っていくことにはなるでしょう(極端な例では、高級言語の誕生によってプログラマーの仕事が変わったのと似たような構図と考えています)。

2.2 企業のAI OSとインテグレートする

それでは、音声認識システムが近い将来に求められる「より広範なシステム全体で最適化された状態」についても、現在から見据えておけるとよいでしょう。私は、「音声認識システムが企業のAI OSにインテグレートされた状態」だと考えています。AI OSとは、ACESの定義だと「企業のAI活用基盤」、すなわち各部門・各業務に散在するデータとAI Agentをサイロ化させず、適切なガバナンスのもとで多様なユースケースを高速に実装・運用するための共通基盤を指します*3

AI OS のイメージ画像(https://acesinc.co.jp/technologies より)。音声認識は Data Layer に位置付けられる。

音声認識システムとAI OSの間には、「双方向のシナジー」が存在すると考えています。一つ目の方向は、書き起こしの品質向上が後段のAI業務活用の質を底上げする流れです。書き起こしは企業活動の中で生み出されるデータの中で大きな比重を占め、AI OS上で様々な業務に接続されていく可能性があります(商談ログから顧客ナレッジを抽出して別商品の提案可能性を探る、顧客の声を製品開発にフィードバックするなど)。このときに固有名詞の表記揺れや発言者名の取り間違えがあると、後続業務でのAI活用の品質にも波及するため、書き起こし品質はAI OSにとって重要です。

二つ目の方向は、AI OS上に蓄積された企業データが書き起こし品質を継続的に高める流れです。例えば会議参加者の名前やニックネーム、あるいは製品名や社内用語といった企業固有の単語リストを使うことで、汎用モデルが知らない単語や苦手なレアワードの認識精度が上がるかもしれません。あるいは、特定発言の話者がシステム上取得できないときに、他の参加メンバー・対象会議と紐づくプロジェクト等がわかっていれば、そうしたコンテキストから発言者を推測することは容易になりそうです。

ACES は AI OS を事業の中心に据えています。そして、「業務の中で蓄積される企業データが書き起こしを賢くし、その書き起こしが企業文脈としてさらに業務活用される」というFBループの構築は、チャレンジの価値があると考えています。

3. 何をやるか

こうした考えのもと、ACESでは音声認識開発の重点項目を以下の三つに置いています。

3.1 より早く・より少ない工数で、基盤モデルの進展に追従する

一つ目は、基盤モデルの進展に追従し続けることです。先に述べた通り、弊社はAPI、オープンウェイト問わず、使えるものは積極的に採用します。必要に応じてfinetuningを行いますが、独自モデルを持つこと自体を目的にはしていません。しかし2026年現在も基盤モデルの進化は速く、基盤モデルの選定は一度決めたら終わる技術選定というよりも、継続的な運用課題となっています。

このような状況のもと、「より早く・より少ない工数」で基盤モデルの進展に追従するため、弊社では最新モデルの性能を簡単に計測することのできるベンチマーク/リーダーボード開発や、モデルに対する互換性を高める音声認識パイプラインのリファクタリングを行っています。

3.2 企業固有のコンテキストを取り入れる

二つ目は、企業ごとのコンテキストを取り込むことです。ACES Meetでは、ユーザーが登録した単語の認識精度を高める辞書機能や、事前に登録された声紋と会議音声データ上の話者を対応させる機能などを開発しています。

ここで重要なのは、単に「辞書登録機能を提供する」ことではありません。そもそもコンテキストとして利用できる情報は何か、辞書登録された単語が認識されなかったときにユーザーが修正できるか、その修正を次回以降に活かせるかまで含めて、一つの体験として設計する必要があります*4。こうした音声認識に関わる広範な体験が、音声認識システム開発の扱うスコープになっています。

3.3 細かいことをちゃんとやる

三つ目は、ざっくりした言い方にはなってしまいますが、「細かいことをちゃんとやる」ことを意識しています。前述の通り現行の音声認識システムは、複数の処理が積み重なったパイプライン的なシステムです。このようなシステムでは、各処理では小さな誤差であっても、それらが堆積し最終出力では大きな違いを生むことがあります。また前述の通り、システム内部のスコープからさらに広げて、人間の修正・学習ループを含めた利用シナリオ全体においても、随所に工夫の余地があります。「(大前提として基盤モデルの精度は全体精度に対して支配的な貢献をしているものの)競合とベースモデルの条件が揃った下では細かい工夫の積み上げが依然として優位性につながる」というのが、現状の手応えです。

4. 終わりに

現在は、基盤モデルの発展により、高性能なモデルを多くの企業が利用できます。しかし、音声認識システムの開発が不要になったわけではありません。基盤モデルを適切に選択し、差し替え可能な形で組み込み、企業固有の文脈を学習させ、UXまで踏み込んでシステムとして成立させる。そのための開発としてやるべきことは多くあります。

この構図は、ドキュメント構造化、物体検知など、「構造化AI=非構造データをLLMが扱える形に変換する技術」の多くにおいても共通すると考えています。プロダクト/顧客価値を左右する部分について、その時々で最適な技術選定ができる状態を保ち、またモデル外延を含めたシステム全体を最適化する能力は、ラストワンマイルの差別化に繋がると考えています。

最後に、ACESでは現在、複数のエンジニアポジションで採用を行っています。ACESの開発に興味を持っていただけた方は、ぜひカジュアル面談でお話ししましょう!

ACESの採用情報はこちら↓

recruit.acesinc.co.jp

open.talentio.com

*1:ACES Meetで求められる他の要求/要件、例えば「書き起こしの可読性」、「企業固有単語の認識率」、「誤りをユーザーが修正しやすいUX」などについても、同様と考えています。

*2:外部APIとして利用する、オープンウェイトのモデルを利用する、オープンウェイトのモデルをfinetuneした上で利用する、といった採用形態の実績があります。

*3:ACESにおけるAI OSの考え方の詳細についてはこちら: 株式会社ACES インタビュー/「AI OS」とは何か──1社で100個のAIを動かすために企業が準備すべきこと | AXIS Insights, わたしたちの技術|AI OSとは|株式会社ACES

*4:AIとUXの設計については以前のブログで詳細に語っています: AIのUXは『Guidelines for Human-AI-Interaction』に基づいて決めよう——ACES Meetの事例を添えて—— - ACES エンジニアブログ

ソフトウェアサプライチェーン攻撃にどう向き合うか:ACESの8つの対応方針

はじめに

こんにちは、株式会社ACES の共同創業者 / ソフトウェアエンジニアの三田村です。

2024〜2026年にかけて、OSS パッケージや CI/CD を経由したソフトウェアサプライチェーン攻撃が増加しています。当社は Python と JavaScript/TypeScript を主な開発言語として使用し、CI/CD パイプラインやクラウドサービスに依存しているため、以前からこの問題を認識していました。

直接的なきっかけとなったのは、2026年初頭に発生した Trivy(セキュリティスキャナ)の侵害と axios(HTTP クライアントライブラリ)のメンテナー権限悪用の 2 件です。Trivy の件はセキュリティツール自体が攻撃対象になりうることを示し、axios の件は広く利用されている有名パッケージであっても依存関係の改変リスクがあることを示しました。いずれも当社の開発環境に直接関係するツール・ライブラリであったため、個別対応ではなく全社のガイドラインとして整備することにしました。

本記事では、その内容を紹介します。同程度の規模・技術スタックの開発組織にとって、参考になる部分があれば幸いです。

背景:攻撃手法の変化

従来のサプライチェーン攻撃は、タイポスクワッティング(名前を似せた悪意あるパッケージの登録)が主でした。近年は、信頼済みの経路そのものを利用した攻撃が増えています。

  • OSS メンテナーのアカウント乗っ取りによる正規パッケージの改変
  • GitHub Actions のタグ書き換え(tag poisoning)
  • postinstall / preinstall を経由した不正コード実行
  • CI トークン等を起点としたワーム型の横展開
  • セキュリティスキャナ自体の侵害

近年のインシデントから得た教訓

  • xz-utils(2024年): 数年にわたるソーシャルエンジニアリングで上流コンポーネントにバックドアが混入された。長期間利用されている OSS であっても安全とは限らない。
  • tj-actions/changed-files(2025年): GitHub Actions のタグが書き換えられ、利用者が意図せず改変済みコードを実行した。@v1 等の可変タグ指定にはリスクがある。
  • npm/PyPI のワーム型攻撃(2025〜2026年): CI の秘密情報を起点に自己増殖的に感染が拡大した。単一のトークン漏洩がリポジトリ横断の問題に発展しうる。
  • セキュリティツールの侵害(2026年): セキュリティツール自体が攻撃対象になり、スキャン処理中に認証情報が窃取された。検査ツールもゼロトラストで扱う必要がある。

標準化した 8 つのルール

これらの状況を踏まえ、以下を全社の標準ルールとして導入しました。

1. 依存関係のゼロトラスト

利用実績の長さや知名度に関わらず、すべての外部依存を侵害されうるものとして扱います。

2. ロックファイルの必須化

以下のロックファイルをリポジトリにコミットし、CI ではロックファイルに基づくインストールのみ許可しています。

  • uv.lock(uv)
  • poetry.lock(Poetry)
  • package-lock.json(npm)
  • yarn.lock(Yarn)

CI での実行コマンドは以下の通りです。

# Python (uv)
uv sync --locked

# JavaScript/TypeScript (npm)
npm ci --ignore-scripts

# JavaScript/TypeScript (Yarn Berry)
yarn install --immutable

3. インストールスクリプトの原則無効化

npm / Yarn のライフサイクルスクリプトは既定で無効としています。

  • postinstall / preinstall を無効化
  • ネイティブ拡張等で必要なパッケージのみ個別に許可

設定例:

# .npmrc
ignore-scripts=true
save-exact=true
# .yarnrc.yml (Yarn Berry)
enableScripts: false

4. GitHub Actions の SHA 固定

第三者アクションは可変タグではなくフルコミット SHA で固定しています。

  • @v1 / @v3 等のタグ指定は禁止
  • フルコミット SHA にピン留め
# NG
- uses: some-org/some-action@v1

# OK
- uses: some-org/some-action@a3fcfb04bbe59c91f973cb6447e1bb1523abcb0b

既存ワークフローは pinact で一括変換し、CI に漏れ検知ステップを追加しています。SHA 固定後のバージョン追従は Dependabot で管理しています。

5. CI/CD 権限の最小化

GITHUB_TOKEN は既定で読み取り専用とし、必要なジョブにのみ最小限の権限を付与しています。本番環境へのアクセスは OIDC ベースへの移行を進めています。

permissions:
  contents: read

jobs:
  deploy:
    permissions:
      contents: read
      id-token: write  # OIDC

6. 検疫期間の設置

新規リリースのパッケージを即時反映せず、48〜72 時間のクールダウン期間を設けています。

  • Python: uvexclude-newer を利用。v0.9.17 以降、 "3 days" のような相対指定にも対応している
  • JavaScript/TypeScript: Renovate の minimumReleaseAge で同等の運用

設定例:

# Python (uv) - pyproject.toml
[tool.uv]
exclude-newer = "3 days"
// JavaScript/TypeScript (Renovate) - renovate.json
{
  "minimumReleaseAge": "3 days"
}

7. SBOM / 脆弱性スキャンの標準化

全リリースで SBOM を生成し、PR・main・release の各段階で依存関係スキャンを実施する方針です。脆弱性管理ツールの選定は現在進行中です。

8. 新規依存関係の導入ルール

新しいパッケージの導入時は、以下を確認するプロセスを設けています。

  • 保守状況・メンテナー体制
  • 代替可能性
  • ライセンス
  • install script の有無
  • 認証・暗号・通信に関わるライブラリかどうか

上記のうち、特にリスクの高い条件に該当する場合は追加の精査を行います。

技術スタック別の対応

Python

新規プロジェクトでは uv を第一候補としています。exclude-newer による検疫や、locked / frozen オプションによる厳格なインストール制御が利用できます。既存の Poetry プロジェクトは即時移行を求めず、いずれの場合もロックファイルと監査の運用を必須としています。

JavaScript/TypeScript

インストール時のライフサイクルスクリプトが主なリスクです。

  • 既定でスクリプトを無効化
  • 必要なパッケージのみ allowlist 方式で許可

GitHub Actions / CI/CD

SHA ピン留め、最小権限の permissions 設定、build/test とデプロイの分離を基本方針としています。pull_request_target の利用は原則禁止です。

インシデント対応

対策を講じても侵害を完全に防ぐことはできないため、発生時の対応フローも整備しています。

検知・トリアージ(0〜2 時間)→ 封じ込め(2〜24 時間)→ 根絶(24〜72 時間)→ 復旧 → 事後分析の各フェーズで対応内容を定義しています。サプライチェーン攻撃では CVE の有無よりも悪性挙動の有無を判断基準としています。

おわりに

サプライチェーンセキュリティは特定のツール導入で完了するものではなく、開発プロセス全体の運用を継続的に見直す取り組みです。当社でも脆弱性管理ツールの選定やプライベートレジストリの導入など、未着手の項目が残っています。

同様の課題に取り組んでいる開発組織の参考になれば幸いです。

#6|1チームの実践を組織の力に変える — AI駆動型の組織をどう作るか

はじめに

こんにちは、株式会社ACES でテックリードをしている福澤 (@fuku_tech) です!

本シリーズでは、AI駆動開発における人間とAIの役割分担を、自動運転になぞらえた4つのPhaseで整理してきました(詳細は以下を参照)。

tech.acesinc.co.jp

ここまで5回にわたってお届けしてきたのは、ACES Meet開発チームという1つのチームの実践録です。最終回となる今回は、この実践を組織全体に広げる話と、6回かけてたどり着いた一つの結論をお伝えします。

1チームだけ速くなっても、組織は変わらない

パフォーマンスチューニングの経験がある方なら実感があると思いますが、ある処理のレイテンシーを半分にしても、その先のボトルネックが詰まっていれば全体のスループットは変わりません。組織も同じで、開発チームだけがAIを駆使して速くなっても、ボトルネックが別の場所に移るだけです。

シリーズ1回目の記事で書いたCursorのような組織、つまり職種や部門の垣根を超えてAI活用が全体に浸透し、事業そのものがスケールする状態を、ACESでも実現しようとしています。

自チームから全社への展開

自チームへの浸透

展開にあたって最初にやったのは、ツールの説明ではありませんでした。「なぜ今これをやるのか」を、事業背景ごとチームに話すことから始めました。課題、目指す姿、そこに至るステップとスケジュールを事前に共有したのは、全体像が見えないまま動き始めることへの不安を、あらかじめ取り除きたかったからです。

大上段の共有と並行して進めたのが、業務プロセスの細分化と可視化です(詳細はシリーズ2回目の記事を参照)。サブプロセス単位まで分解して「ここは人間が判断する」「ここはAIに任せる」を明確にし、どこがボトルネックかを図に落としました。優先度の高いサブプロセスからスラッシュコマンドを整備しながら、構想と進捗を随時共有することで「今自分たちは全体のどこにいるか」を常に見えるようにしていきました。

その上でPilot-Tower開発への移行にあたっては、モブプログラミング会を90分×4回実施しました(詳細はシリーズ4回目の記事を参照)。振り返ってみると、AI活用の文脈で最も重要で、かつ最も難しいのは、AIに運転席を譲ることへの抵抗感を越えてもらうことだったと感じています。「自分でやった方が正確で早い」「本当に任せて大丈夫なのか」という感覚は、言葉でいくら説明しても拭いきれません。実際に動くものを目の前で見て触れてもらうことで、思った以上に早く「任せてみよう」という空気が生まれました。AIに任せる文化は、言葉ではなく体験から醸成されると実感しています。

元々は3ヶ月かけて段階的に浸透させる計画でしたが、メンバーのモチベーションが想定以上に高く、自分自身も楽しくなって全力でアクセルを踏んだ結果、想定の倍近いスピードで改善サイクルが回りました。メンバーが感じた使いにくさや改善ポイントがすぐ自分に届く仕組みを整えていたことも、このサイクルを速める一因だったと思っています。今では自分がいなくてもメンバーが自発的にコマンドやガイドラインの改善を回せるレベルになりつつあります。

他チームへの横展開

自チームが自走し始めたことで、自分のリソースをチームに張り付ける必要がなくなりました。次の展開先として選んだのは、社内のプロジェクト型の開発チームです。前提が異なる部分もあり、全体に一斉に声をかけるのは非効率だと判断したため、まずリーダー層のキーマンを捕まえて現状をヒアリングしながら進めることにしました。

ACES Meet開発チームと大きく違ったのは、開発プロセスが可視化・標準化されておらず、各プロジェクトの特性に応じて都度適切な進め方が取られていた点です。そのため、自チームへの展開と同様にAIに何を任せるかを定義していく前に、まずプロジェクト横断で共通する開発プロセスの洗い出しと可視化から始めました。

一方で、プロジェクト型特有のボトルネックの所在も見えてきました。顧客とのやり取りやPMの仮説といった1次情報をどう扱うか、AIモデル出力に関するレポートの正確性をどう担保するか、ナレッジをプロジェクト横断で再利用できる形にするには開発プロセスのどのタイミングでどんな工程やアウトプットを定義しておくべきかを整理する必要もありました。

そうした中で、PM側でもAI駆動のプロジェクトマネジメントに取り組む動きが生まれており、開発側との合流が始まっていました。PMが持つ情報と開発側の成果物が一貫してつながることで、プロセス全体の精度が上がる可能性があると考えています。その整理がようやく終わり、まさに本格運用が始まるところです。

全社への展開

全社の開発チームがAI駆動開発を始めやすい環境として、汎用的に利用可能なAgents SkillsやAI向けドキュメントの雛形をGitHubで社内に公開しており、setupコマンド一発で既存リポジトリに適用できる設計にしました。今後いかに質の高いAgents Skillsを量産しフィードバックサイクルを回せるかが競争優位性に直結すると考えており、まずは自分の肌感のある開発文脈での共通基盤を整えるところから始めました。開発の文脈で得た知見を、ゆくゆくはBizサイドへの展開にも活かしていけないか、模索していくつもりです。

ただ、仕組みだけでは広がりません。2026年2月、全社向けの勉強会を開催しました。冒頭で伝えたのはシンプルな話で、AI活用を組織全体に広げてACESをスケールさせたいという想いと、自分一人では実現できないから一緒に取り組んでほしいということです。ライブデモでAI駆動開発の現在地を実演し、AIがオーケストレートする体験を共有しました。

勉強会後、PM・CS・Bizの各方面から個別に相談が届くようになり、全社横断のAI活用チャンネルが立ち上がるなど、共感してくれる人が増えて波を感じ始めています。こうした活動が呼び水となり、ACESではChatGPT / Claude / CursorのEnterprise版を職種・雇用形態を問わず全員に標準整備する動きへとつながりました(詳細は以下の記事を参照)。

tech.acesinc.co.jp

4月からはBizサイド向けに週次で計8回以上のAI活用勉強会を開催予定です。#1で書いた「個人の2倍よりチーム全体の底上げ」、つまり一人ひとりの能力を劇的に高めるより全員が少しずつ底上げされる方が組織全体のアウトプットは大きくなるという考え方を全社に広げ、まずは100人×1.1倍を最速で実現しにいきます。

AI OSの社内実装

1チームの実践を組織全体に広げながら、ずっと頭にあった問いがあります。「そもそも、AIを本当に活かせている組織とそうでない組織の違いは何か」ということです。ツールを入れているかどうかではなく、AIが活躍しやすいようにプロセスそのものを再設計できているかどうか、それが本質的な差だと考えるようになりました。AIを前提として業務の構造そのものを作り直した組織のことを、自分はAIネイティブな組織と呼んでいます。

DORAの2025年レポートは、約5,000人の技術者を対象にした調査でこう結論づけています。AIはチームを修復しない、すでにあるものを増幅する、と。良い土台があればAIはその組織を良い方向に増幅し、土台のない組織はいくらツールを入れても変わらない。このシリーズで6回かけてやってきたことの意味が、この一文に集約されていると感じています。

dora.dev

振り返ってみると、自分たちがやってきたことは、代表の田村が語る「AI OS」の社内実装の一つの形だったと思っています。AI OSとは、どのモデルを使うかではなく、組織・文化・業務プロセスを含めてAIが動く前提を設計すること。1チームの実践から始まり、他チームへの横展開、全社への浸透へと広げてきた取り組みは、まさにそのOSを組織にインストールしていく作業でした。

note.com

ただ、OSはまだ完成していません。AIが活躍しやすい構造へと組織を再定義していく作業は続きます。開発領域から始めたこの取り組みをBizサイドも含めた事業全体に広げ、組織そのものをAIネイティブに作り替えていくことが、自分が次に向き合っていくテーマです。

おわりに

正直、まだ道半ばです。Phase 4は構想段階ですし、組織全体の最適化もこれからです。ただ、#1で「完成した成功事例ではなく、進行中の実践のリアルな姿をお伝えできれば」と書いた約束は、6回を通じて果たせたのではないかと思っています。

このシリーズでやってきたことは、1チームの小さな実践から始まり、AI OSを組織にインストールしていく取り組みへと広がりました。その先にある、組織全体がAIで動く世界の構想については、代表の田村が近日ブログで公開予定です。AIの力で組織がどう変わっていくかに興味がある方はぜひそちらも読んでみてください。

もしこのシリーズを読んで「自分のチームでもやってみたい」と思っていただけたなら、まず目の前の業務プロセスを言語化するところから始めてみてほしいと思っています。

この旅はまだ続きます。一緒に切り拓いていく仲間を探しています。

ACESでは現在、複数のエンジニアポジションで採用を行っています。本シリーズを読んでACESの開発に興味を持っていただけた方は、ぜひカジュアル面談でお話ししましょう!

ACESの採用情報はこちら↓

recruit.acesinc.co.jp

open.talentio.com

ACES、AIを全員の標準装備へ - ChatGPT Enterprise / Claude Enterprise / Cursor Enterpriseを全員に導入しました

はじめに

こんにちは、株式会社ACES の共同創業者 / ソフトウェアエンジニアの三田村です。

ACESではこのたび、ChatGPT Enterprise / Claude Enterprise / Cursor Enterprise を、職種・業務形態を問わず全員が業務で使える環境として整備しました。これまでもChatGPTは全員に付与しており、ClaudeやCursorはエンジニアを中心に配布・活用を進めてきました。今回、対象をさらに広げ、Bizメンバーを含む全職種、正社員・インターン・業務委託を含む約150名のメンバーが利用できる体制にしています。

今回の整備で重視したのは、AIを一部の人だけが使うものにしないことです。個人ごとの工夫に任せるのではなく、実際の業務の中で使える環境を会社として整えています。

全員付与

AIツールの価値は、個人の作業が速くなることに加えて、チームで使い方が共有され、職種をまたいで知見が回り、仕事の進め方そのものが変わっていくところにあります。

そのためには、希望者だけが触れられる状態よりも、全員が同じスタートラインに立てる状態の方が強いと考えています。ライセンスの有無で試行機会が分かれると、活用は局所的になりやすく、組織としての再現性も育ちにくくなります。

ACESでは、AIを個人の持ち込みに任せず、会社が整えた環境の中で活用を広げていきます。エンジニア、Bizメンバー、インターン、業務委託まで含めて共通の土台を持つことで、役割を越えた連携や知見共有も進めやすくなります。

利用環境

今回、ChatGPT / Claude / Cursor の3サービスはいずれも Enterprise 契約とし、会社管理の利用環境を整えました。活用を広げることと、安心して使える利用環境を整えることの両立を重視したためです。

こうしたサービスの導入にあたっては、社内のセキュリティ・法務観点での確認や所定の審査を行った上で、利用可否を判断しています。その上で、生成AIサービスでは、入力データがモデル学習に利用されない利用環境であることも重視しています。個人契約や設定の違いに依存せず、会社が管理する環境を整えることで、全員が同じ条件で使い始めやすくなります。

契約体系上も、固定のシート課金に加えて利用量に応じた課金を組み合わせられるものがあり、全員向けに利用環境を用意しつつ、利用状況に応じたコスト管理がしやすい形になっています。

加えて、Google Workspace上で利用可能な Gemini も含め、業務内容に応じて複数のAIツールを組み合わせて使える環境を整えています。

ルール整備

全員が使える環境とあわせて、ルールと手順も整備しました。

社内では「生成AIサービス利用ガイドライン」や「AIコーディングツール利用手順」などのマニュアルを用意し、利用環境、入力情報の扱い、判断に迷いやすいケース、相談先を整理しています。

これらのルールは、社内での検討に加えて、顧問弁護士とともに法的観点の確認を行いながら整備しています。

特に意識したのは、入力してよい情報、確認が必要な情報、入力を避ける情報を明確にすることです。たとえば、公開情報やACES自社データは、利用環境の要件を満たす範囲で活用できます。一方で、クライアントに関する情報は、契約や法務・セキュリティ上の条件を確認した上で慎重に扱う前提としています。認証情報や不要な個人情報は入力しないこととしています。

あわせて、会社が管理する環境で利用すること、判断に迷うケースは都度確認すること、生成結果は利用者自身で確認することといった前提もそろえています。こうした運用を通じて、AI活用を個人の判断に依存しない形で進めていきます。

AI駆動開発

エンジニア組織では、以前からAIを前提にした開発の進め方を進めてきました。重視しているのは、個人の作業速度を上げることだけではなく、AIを組み込んだ開発フローをチームで再現できる形にすることです。

この考え方は、先日公開した「#1|AI駆動開発の4フェーズと私たちの現在地 — AIに運転席を譲れるか」にもつながっています。そこで示しているのは、AI活用を個人の補助にとどめず、チームの開発プロセスに組み込み、さらに組織全体へ広げていくための段階です。

今回の全員付与も、こうした考え方をエンジニア組織の外へ広げていく流れの中にあります。AI活用を開発チームの中にとどめず、会社全体の業務プロセスの中に組み込んでいきます。

活用

実際に、社内の各職種で活用の広がりが見え始めています。

Bizチームでは、提案資料やサマリ資料のたたき台作成、関連情報の整理など、日々のアウトプットを進める場面でAIを使うケースが増えています。ゼロからすべてを作り始めるのではなく、最初の構成や下書きをAIに任せ、人が判断や修正に時間を使う形が少しずつ定着し始めています。

エンジニアリングでは、共通のコマンドや運用の工夫を共有しながら、PR作成やレビュー準備を含む日常の開発フローにAIを組み込む動きが進んでいます。個人の工夫にとどめず、チームで再利用できる形にしていくことを意識している点が特徴です。

また、幅広い職種に向けた実践機会づくりも始まっており、職種をまたいで知見を共有する流れが出てきています。

おわりに

株式会社ACESでは、「アルゴリズムで、社会はもっとシンプルになる」というビジョンを掲げ、テクノロジーで社会課題の解決を目指す仲間を積極的に募集しています。

ACESでは、AIを前提に開発や業務の進め方を見直し、それを価値提供につなげていく仲間を求めています。重視しているのは、AIで個人の作業を速くすることに加えて、AIを業務や開発の進め方に組み込み、その知見をチームで蓄積し、お客様への価値提供につなげていくことです。

ChatGPT / Claude / Cursor を全員が使える環境と、活用を支えるルールや運用の土台を整えた上で、実践を進めています。個人の工夫をチームの力に変えたい方、AIと一緒に仕事の進め方を磨いていきたい方は、ぜひACESの採用情報をご覧ください。

ACESの採用情報はこちら↓

recruit.acesinc.co.jp

open.talentio.com

#5|AIが書いたコードをどう本番に出すか — リリース安全基盤の設計と展望

はじめに

こんにちは、株式会社ACES でテックリードをしている福澤 (@fuku_tech) です!

本シリーズでは、AI駆動開発における人間とAIの役割分担を、自動運転になぞらえた4つのPhaseで整理しています(詳細は下図を参照)。

本記事は#3#4で整備した品質ゲートの上に、リリース安全基盤を積み上げる話のため、以下を先にお読みいただくとよりスムーズです。

tech.acesinc.co.jp

tech.acesinc.co.jp

前回の記事では、AIが自律的に実装を回し人間は要所でレビューする開発スタイルを実際にチームで運用してみた成果と摩擦を率直にお伝えしました。品質ゲート(Lint・Tests・セルフレビュー・別LLMレビュー)による予防が機能し運用開始以来AI実装起因のインシデントは0件という実績を積めた一方で、AIが品質ゲートを通過したPRを量産しても人間側のレビューが追いつかず「これ本当に出して大丈夫か?」という不安も拭えないという課題が残りました。暫定的にタスク分解やPR分割で凌いではいるものの、これは人間の介入を増やす方向の対処であり、スケールする解ではないと感じていました。

シリーズ初回で「壊れたときどう直すか」として予告した問いを、ここで回収します。「壊れないようにする」だけでは限界がある。発想を転換して「壊れても速く直せる」仕組みを作ることで、AIへの委譲範囲をさらに広げていく。この記事では、その設計と構築の現在地をお伝えします。

発想の転換: 「壊れないようにする」から「壊れても速く直せる」へ

#3#4で整備した品質ゲート(Lint・Tests・セルフレビュー・別LLMレビュー)は、コードレベルの予防策として確かに機能しています。E2Eテストなど統合レベルの検証強化も今後の投資対象ですが、本記事ではその先のレイヤー、つまりリリース後の検知・復旧の仕組みに焦点を当てます。

さらに、本番トラフィックでのみ顕在化するパフォーマンス劣化や、長時間稼働で初めて現れるメモリリークといった、コードレビューだけでは見えないリスクもあります。AIが書いたコードが機能テストを通過していても、本番環境で想定外の負荷を生むかもしれません。これは人間が書いたコードでも同じですが、AI生成コードの量が増えるほどリスクの総量も増えていきます。

ここで発想を転換しました。安全の判断基準を「人間の目」から「データとシステム」に移す。具体的には、壊れないようにすることに全力を注ぐのではなく、壊れたときに速く検知し速く戻せる仕組みを作ることで、「これ出して大丈夫か?」という不安を「なんとなく怖い」から数値に基づく判断に置き換えていきます。そうすれば、人間がコードの一行一行を見なくても、AIへの委譲範囲をさらに広げていけるはずです。

リリース安全基盤の現在地

この発想の転換を実現するために、私たちはリリース安全基盤を段階的に積み上げています。すでに運用実績のあるものから、まだ手をつけていないものまで成熟度に差があります。現在地を正直にお伝えします。

01 Progressive Delivery: Feature Flagで段階ロールアウト

Feature Flagサービス(DevCycle)は、AI活用が本格化する以前から導入済みです。自社テナントのみに先行公開し、エラーレートなどを監視しながら段階的にロールアウトしていく、いわゆるProgressive Deliveryの運用がすでに回っています。ロールアウトのステップは「自社テナントのみ → 一部顧客 → 全体」で、判断基準は「一定期間、関連する不具合が0件であること」としています。

直近の実績として、コア機能である音声解析周りの改修でこの仕組みが効きました。自社テナントのみに先行リリースしたところエラーを検知し、修正後に改めてロールアウトを進めて安全にリリースを完了しています。この事例はAI生成コードによるものではありませんが、すでに回っている運用をAI生成コードのリリースにもそのまま適用できるという確信を持てました。現在、AI生成コードのリリースにFeature Flagをどう組み込むかの検討を始めたところです。

02 Observability: アラートの信頼性確保と異常検知

監視・検知の基盤が機能するには、まずアラートが信頼できる状態でなければなりません。Sentryのアラートノイズ撲滅から着手し、ClaudeのSlack連携を使ってノイズアラート(対応不要なのに繰り返し発火するアラート)をコツコツ潰しているところです。地味ですが、ここを丁寧に整えることが安全基盤の土台になります。

その上で、SentryのTrace機能を使ったN+1クエリの検知など、新たな検知の追加を進めています。これはAI生成コード固有の話ではなく、プロダクト全体の検知能力を底上げする取り組みですが、AI駆動開発の安全基盤としてもこの基盤が効いてきます。

03 Error Triage Automation: 検知から修正PRまでの自動化

アラートの信頼性確保と並行して、検知から修正提案までを一気通貫で回すワークフローの構築を進めています。GitHub Actionsで定期的にSentryを監視し、新規エラーを検知したらIssueを自動作成します。その際にClaude APIでエラーの原因調査と修正方針の起案を行い、改善PRの生成まで自動化する設計で、最終的には人間がPRをレビューして判断します。

まだ検証段階ですが、このパイプラインが回り始めれば、エラーの検知から修正PRの作成までの時間を大幅に短縮できる見込みです。

04 SLO / Error Budget: データ駆動のリリース判断

ここまで述べた仕組みが揃ってきたとき、次に必要になるのはリリース可否の判断基準です。現在のロールアウト判断は不具合0件かどうかのオール・オア・ナッシングですが、これだけではリリース速度と安定性のバランスを柔軟にコントロールできません。そこで目指しているのが、SLO(サービスレベル目標)とエラーバジェットの導入です。たとえば可用性99.9%とSLOを設定すると、月あたり約43分のダウンタイムが許容されます。この許容される余白がエラーバジェットです。余白が十分残っていればリリース速度を上げ、減ってきたら安定化に集中する。リリース判断を感覚ではなく数字で行えるようにする仕組みです。これをAI駆動開発の文脈で設計していく段階です。

これで何が変わるのか

前回の記事で悩んでいた課題に、ここまで述べたリリース安全基盤がどう答えるのかを整理します。

まず、巨大PR問題です。PRの粒度を小さく保つ努力は引き続き重要ですが、Feature Flagによる段階ロールアウトと高速ロールバックの仕組みが整えば、仮にPRが大きくなっても致命傷にはなりません。PRの粒度だけに安全を依存しない構造を作ることが狙いです。

次に、レビューが追いつかない問題です。リリース安全基盤が整うと、レビューの焦点がコードの一行一行から、段階ロールアウトの各ステップの判断に移ります。人間の介入ポイントが減ることで、AIへの委譲範囲を広げられます。

そして、出して大丈夫かという不安です。品質ゲートを通過していて、段階ロールアウトで実際の挙動も確認できていれば、Go判断はずっとしやすくなります。さらにSLO/エラーバジェットが整えば、その判断を数字で裏付けることもできるようになります。まだこの段階には到達していませんが、目指している方向はここです。

その先に見える世界

ここまで述べたリリース安全基盤が整った先には、さらなる自動化が見えています。

1つは、Feature Flagの操作自体をAIに委ねることです。AIが段階ロールアウトの各ステップをメトリクスに基づいて自律的に判断し、異常を検知したら自動でロールバックする*1。まずは既存機能のロールアウト拡大のような定型的な判断から段階的に自動化し、不確実性の高い判断は人間が行うという線引きで、自律性の範囲を慎重に広げていく方針です。

もう1つは、AIが生ログに瞬時にアクセスできる環境の整備です。SentryだけでなくCloudWatchやGrafanaなど、複数の監視基盤のログをAIがリアルタイムに確認できるようになれば、sandbox環境でのリリース前検証でも本番環境でのリリース後監視でも、AIが自律的にフィードバックサイクルを回せるようになります。

この2つが揃うと、AIが自分でコードを書き、自分で検証し、自分でリリースし、問題があれば自分で直すというループが成立します。人間に残るのは最終承認と、ループ自体の設計・改善です。

おわりに

シリーズ初回からここまで振り返ると、一つのストーリーが見えてきます。Phase 1→2で何をAIに任せるかを整理し、Phase 2→3でどうすれば安全に任せ切れるかを設計し、そしてPhase 3→4で壊れたときどう直すかに向き合っています。各Phaseで手放してきたのは、全部自分で書く、自分がやった方が早い、壊れないようにする、という、それぞれの段階で当たり前だった前提です。

そして今、人間がコードを見なければ安全は担保できないという前提を手放そうとしています。この前提が手放せたとき、AIが長時間自律的に稼働するPhase 4への道が開けます。データとシステムに安全の判断を委ねられれば、AIへの委譲範囲はさらに広がります。そのための基盤づくりはまだ始まったばかりで、正直まだまだ足りないことだらけです。ただ、この記事で語ったFeature Flagやアラート整備は、AI時代に突然必要になったものではなく、ずっと大事だったものがAI時代にさらに重要になっただけです。まっとうなエンジニアリングプラクティスこそが、最大の武器だと考えています。

ここまで語ってきたのは、1つのチームの実践です。次回の #6|1チームの実践を組織の力に変えるでは、この実践を組織全体に横展開するために何が必要かを語ります。

tech.acesinc.co.jp

ACESでは現在、複数のエンジニアポジションで採用を行っています。本シリーズを読んでACESの開発に興味を持っていただけた方は、ぜひカジュアル面談でお話ししましょう!

ACESの採用情報はこちら↓

recruit.acesinc.co.jp

open.talentio.com

*1:AI時代のFeature Flagの未来像についてはこちらの考察が示唆に富んでいます。

#4|Pilot-Tower開発を回してみた — 成果と摩擦のリアル

はじめに

こんにちは、株式会社ACES でテックリードをしている福澤 (@fuku_tech) です!

本シリーズでは、AI駆動開発における人間とAIの役割分担を、自動運転になぞらえた4つのPhaseで整理しています(詳細は下図を参照)。前回の記事(以降、「#3」と呼称)では、AIに運転席を譲るPhase 3の設計思想として「Pilot-Tower開発(P&T開発)」を紹介しました。plan.md をSSoTとしたループ構造、AIが判断に迷ったときだけ停止するDecision Required(DR)、そしてAIに任せない領域を定めるガードレール。この3つの仕掛けで自走と統制を両立する、という話でした。

思想については前回語りました。本記事では plan.md、DR、ガードレールなど以下の#3の記事で導入した概念を前提としているため、先にお読みいただくとよりスムーズです。では実際にこの思想で開発を回してみてどうだったか。今回は、P&T開発の実践の手触りと、そこで起きたつまずきを語ります。

tech.acesinc.co.jp

/plan-execute の実際: 1本のPRができるまで

/plan-execute は、plan.md を入力にAIが自律的に実装→品質ゲート(Lint・Tests)→レビュー→PR作成の4フェーズを回すコマンドです。

Phase 1: 実装
  └→ plan.mdに沿って実装
  └→ 適宜worklog.mdに作業のサマリーを記録
  └→ DRが必要なら停止して開発者にエスカレーション(暴走防止)

Phase 2: 品質ゲート
  └→ Lint / Format 自動実行
  └→ テスト自動実行
  └→ 失敗したらまずは自己修正
  └→ 自己修正では解消が難しい場合は Codex CLI 等を使って別の LLM に修正を依頼
  └→ エラーがなくなるまで or 上限回数に到達するまで繰り返す

Phase 3: レビュー
  └→ セルフレビュー
  └→ Codex CLI 等を使って別の LLM にレビューを依頼
  └→ 指摘があれば自動修正
  └→ 修正すべき指摘項目がなくなるまで or 上限回数に到達するまで繰り返す

Phase 4: PR作成
  └→ PRタイトル・説明を自動生成

「張り付き」から「離れられる」へ

シリーズ第二回目の記事(以降、「#2」と呼称)で解説したPhase 2の運用では、コマンド実行→出力レビュー→次のコマンド選択の繰り返しで、AIが動いている間ずっと人間が張り付いている必要がありました。AIの処理待ち時間そのものは短くても、次に何をさせるかを判断して指示を出す工程が常に発生していました。

tech.acesinc.co.jp

Phase 3では、この体験が大きく変わりました。/plan-execute に投げたら30分から2時間は離れられます。会議の裏で仮実装や本実装が進み、戻ってきたらDRに答えるかPRを確認するだけです。/plan-execute コマンドの内部にworklogの記録、DRでの停止、ガードレール領域での報告といった複雑さが隠蔽されたことで、エンジニアの認知負荷が下がりました。「planを作って育てて /plan-execute を実行する」というシンプルな運用に収束しています。

ただし、これは#2で整えたガイドライン・ガードレールという土台があってこそ回っている点は強調しておきたいと思います。

実際の事例

具体的なイメージを持ってもらうために、実際のタスクをベースに一連の流れを追ってみます。題材は、複数のSpeech(文字起こし)テキストを一括更新するAPIの実装です。以下はバックエンド側の plan.md を例に、一連の流れを追っていきます。

最初に人間がやることは、plan.md の「種」を書くことです。この段階ではGoalとざっくりした制約だけで構いません。

## Goal
複数のSpeech(文字起こし)テキストを一括更新するAPIを実装し、
フロントエンドのキーワード一括置換機能を実現する。

## Constraints
- サーバーサイドの実装のみ(フロントエンドは対象外)
- 既存のSpeech単体更新APIには変更を加えない

## Definition of Done
- 一括更新APIが正常に動作し、テストが通ること

この種を /plan-refine でAIと対話しながら育てます。CursorのPlanモードやClaude CodeのPlan機能を使ったことがある方にはおなじみの体験ですが、ポイントはその対話結果が plan.md というファイルに永続化され、後続の /plan-execute が参照するSSoTになることです。以下は /plan-refine を経て育った plan.md の抜粋です(社内固有の情報はマスキングしています)。

## Goal
複数のSpeech(文字起こし)テキストを一括更新するAPIを実装し、
フロントエンドのキーワード一括置換機能を実現する。

## Constraints
- サーバーサイドの実装のみ(フロントエンドは対象外)
- 既存のSpeech単体更新APIには変更を加えない
- 既存のbulk_executeパターンを踏襲
- All-or-Nothing(部分成功なし): 不正が1件でも含まれる場合、
  1件も更新せず4xxを返す

## Definition of Done
- 一括更新サービスが実装されている
- 空文字や最大文字数超過のバリデーションが実装されている
- 存在しないIDが含まれる場合は404を返す
- 他テナントのリソースが指定された場合はテナント隠蔽のため404を返す
- All-or-Nothing: 上記いずれかに該当するIDが1件でも含まれる場合、
  更新を1件も行わない
- DB更新と検索インデックス更新・キャッシュ削除が整合する順序で
  実行される
- 単体テストカバレッジ100%

なお、今回のように実装の方向性が見えている場合は /plan-refine の対話だけで十分ですが、要件レベルでも技術的にもふわっとしていて人間にもイメージがついていない場合は、/plan-spike(仮実装による技術検証)でカジュアルに探索的な実装をさせてみることで、制約やDoDをクリアにしていけます。

/plan-execute を実行すると、AIが自走し、実装→品質ゲート(Lint、Tests)→セルフレビュー→PR作成の一連が人間の介在なしに回ります。途中でAIが判断に迷った場合、DRを発行して停止します。このタスクでは2件のDRが発行されました。

### DR-001: バルク更新の上限件数

- Priority: P0
- Context: 一回のバルクアップデートで更新できる件数の上限
- Options:
  - A: 100件(既存のバルク操作と同じ)
  - B: 1000件(長時間会議に対応)
- Recommendation: B
- Decision: B(1000件)

### DR-002: エンドポイント設計

- Priority: P1
- Context: 新APIを既存の汎用バルク実行エンドポイントに統合するか、
  独立したエンドポイントにするか
- Options:
  - A: 既存のバルク実行エンドポイントに新オペレーションを追加
  - B: 独立した専用エンドポイントを新設
- Recommendation: B
- Decision: A(既存エンドポイントに統合)

DR-001ではAIの推奨(B: 1000件)をそのまま採用し、DR-002ではAIの推奨(B: 独立エンドポイント)とは異なるA(既存エンドポイントに統合)を選択しました。人間はDRを読んでA/Bのどちらかを書き込むだけです。選択肢と推奨案がすでに提示されているので、背景を一から調べる必要がなく、判断のコストが大幅に下がります。DR-002でAIの推奨を覆したのは、既存のバルク処理APIの実装パターンとの一貫性を優先したためです。こうしたプロダクト全体のコンテキストに基づく判断は人間が担う方が適切で、DRの仕組みがあるからこそ判断ポイントが自然に浮上し、見落とされずに済みます。

DRに答えるとAIが再走し、残りの実装を完了させます。

チームで見えてきた変化

この一括置換機能(APIと画面)の開発 (設計からmainブランチへのマージまでの全工程) は、従来であれば2〜3日と見積もっていた規模感でした。P&T開発で回した結果、人間の実稼働時間は2〜3時間で完了しました。これは私個人の体感だけではなく、API認証のClient Credentials対応など他のタスクでも同様の短縮効果がチーム内で報告されています。

AIに自走させている間に別のタスクのplanを作れるようになったことで、2〜3プロジェクトを同時並行で進められるようになったというメンバーもいます。Phase 2では人間がAIに張り付いていたため、基本的に1タスクずつの直列作業でした。Phase 3では人間の役割がDRへの判断回答に絞られたことで、並列度が上がりました。

設計判断が難しい箇所はDRでその都度判断しながら進められるため、後からAIが書いたコードを大きく手戻りさせるといったことがなくなったという実感もあります。#3で「DRのログ蓄積によってAIの自律判断範囲が拡大し、人間の介入がさらに減っていく」と書きましたが、実際にその兆候は出始めています。似たような設計判断が過去のdecision-logに蓄積されることで、以前はDRに上がっていた判断がAI側で自律的に処理されるケースが増えてきました。

エンジニアだけでなく、非エンジニアによる実践事例も出てきています。例えば、PdMがP&T開発を用いてスマホアプリの不具合修正を自ら完結させたケースです。これまでエンジニアの工数を待たなければならなかった微細な修正が、PdMの手によって迅速に解消されるようになりました。この事例における具体的な実装ロジックはほとんどAIの生成結果そのままであり、コードレビューこそエンジニアが最終確認として実施したものの、品質担保の軸は実機での動作確認に置かれていました。P&T開発の仕組みが、個人のコード執筆能力とは別のレイヤーで品質を担保しているからこそ成り立っている、象徴的な事例だと考えています。

つまずきとその乗り越え方

成果だけを並べると順風満帆に聞こえるかもしれませんが、もちろんつまずきもありました。ここでは、実際に起きた失敗エピソードとその対処を率直に共有します。

git reset --hard で数時間分の作業が消えた

初期に起きた分かりやすい失敗です。AIが自走中に git reset --hard を実行し、数時間分の作業が消えました。実際には git reflog で復元できたので事なきを得ましたが、破壊的な操作を勝手に判断して実行されると、心理的にAIに任せにくくなります。

対処はシンプルで、 settings.json に禁止操作として明記しました。ルールに書けば再発しない。AIのやらかしは仕組みで潰す、という原則を最初に教えてくれたエピソードです。

コンテキスト蓄積による精度低下

AIが長時間稼働すると、コンテキストウィンドウに情報が積み上がりすぎて判断精度が落ちるという課題もあります。後半のタスクでガードレール領域に不用意に手を出しそうになったり、前半で合意した方針と矛盾する実装をしたりすることがありました。

現状では、セッションを意図的に切り替えて plan.md で状態を復元する運用と、SubAgentsの活用で緩和しています。plan.md がSSoTとして機能しているからこそ、セッションを切っても文脈を失わずに再開できます。ただ、完全な解はまだ見つかっていません。

「手放す怖さ」をどう越えたか

技術的なつまずき以上に大きかったのは、心理的な壁です。「AIに任せて大丈夫なのか」「本番に出して問題ないのか」という不安は、仕組みの説明だけでは払拭できませんでした。

この不安を越えるために、モブプログラミング会(90分×4回)を実施しました。チームメンバーが実際に一緒にP&T開発を動かす場を設け、DRできちんと停止すること、ガードレール領域に触ったらAIから報告が来ること、Lint→Tests→セルフレビュー→別LLMによるレビューを通過した上でPRが作られること、この一連を目の当たりにしてもらいました。百聞は一見にしかずという諺の通り、品質ゲートが実際に機能する様子を確認できたことで、不安が払拭され大きな手応えを得ることができました。

ここ数ヶ月の運用で、AIの実装に起因するインシデントは0件です。#2で整えた土台(ガイドライン・品質ガードレール・AI向けドキュメント)が効いている結果だと考えています。皮肉なことに、この間にヒヤリハット*1が起きたのはむしろ人間が書いたコードの方でした。

今いちばんの悩み: 巨大PRとレビューの限界

一方で、まだ乗り越えられていない課題もあります。AIが自走してくれるのはいいのですが、1つのPRに大量の変更を詰め込んでくるケースが頻発します。品質ゲート(lint・テスト・セルフレビュー・別LLMレビュー)は通っているものの、変更差分の大きなPRが量産されると、人間側のレビューが追いつきません。「これ本当に出して大丈夫か?」という不安が残り続けます。

暫定策としては、タスクを設計段階で小さく分解してから /plan-execute に渡すことでPR粒度を制御したり、PRを意味のある単位に分割するスラッシュコマンドで事後的に対処したりしています。ただ、これらはいずれも人間の介在を増やす方向の対処です。#1で「人間が運転席に座り続ける限り、AIの稼働時間は人間の稼働時間に縛られる」と書きましたが、タスク分解やレビューについても同じ構造が当てはまります。人間の介入を増やすことでしか品質を担保できない状態では、ボトルネックが別の場所に移るだけで、AIの自律稼働時間を最大化するという当初の目的はスケールしません。

この問題は、タスク分解自体をAIに動的にやらせることで緩和できる可能性もあります。Claude CodeのTask Systemのように、AIが実装中にサブタスクを切り出して並列処理する仕組みを応用すれば、結果的にPRの粒度も小さくなることが期待できます。現在試験的に導入を始めていますが、本格運用はこれからです。

さらに言えば、そもそもこの問題自体が一過性のものかもしれません。GitHub元CEOのThomas Dohmke氏が新会社Entireを立ち上げた際にXで発信していたように、コードを理解してレビューするという行為自体が死にゆくパラダイムだとすれば、意図と成果を検証するワークフローへの移行が進み、人間がコードを逐一レビューする前提自体が変わりうる。そうなれば、PR粒度の問題も構造ごと解消される可能性もあります。

とはいえ、その日まで待つわけにはいきません。本命は、人間の目視に頼らなくても安全にリリースできる仕組みです。「壊れないようにする」だけではなく「壊れても速く直せる」リリース安全網が整えば、レビューで事前に品質を担保しなければならないという不安を感じにくくなる効果があると考えています。次回の#5|AIが書いたコードをどう本番に出すかでは、そのアプローチについて語ります。

tech.acesinc.co.jp

おわりに

P&T開発を数ヶ月回してみて、planを作って /plan-execute を投げるというシンプルな運用に収束し、人間はAIの自走中に別のタスクを進められるようになりました。一方で、AIの暴走やコンテキスト蓄積、巨大PRのレビュー負荷といったつまずきも経験しました。ルールに書けば再発しないものは仕組みで潰し、構造的に解決できないものは投資先を見極めて手を打つ。そして、その仕組みが本当に機能することをチームで一緒に体験して初めて、次のステップに進めます。その積み重ねが、小さなチームで大きなことをやる力になると考えています。

ACESでは現在、複数のエンジニアポジションで採用を行っています。本シリーズを読んでACESの開発に興味を持っていただけた方は、ぜひカジュアル面談でお話ししましょう!

ACESの採用情報はこちら↓

recruit.acesinc.co.jp

open.talentio.com

*1:デプロイ直後に検知し、影響ユーザー0人で即revert