数GBのLLMモデルを、LambdaでLinuxシステムコールを駆使して本番水準で動かす

はじめに

お疲れ様です。2357giです。先日のre:Inventで参加したセッション「Build high-performance inference APIs with Lambda SnapStart」にて、「数GB級のLocal LLMをサーバレスで、本番環境の要求水準で動かす」方法を学んできました。
(その際のセッション形式が「チョークトーク」というもので、めちゃめちゃ良い体験だったのですがその話はこちら )

llama.cppなどの比較的軽量なLLM(1GB~5GB)や、それらと同程度のサイズの自作モデルをLambdaを用いて動かすというものです。
bedrockにカスタムモデルインポートがある現在、本アーキテクチャに優位性があるケースは多くないと思います。セッション中でも「YOLOなどの画像認識や、10 GBに収まる言語モデル、文字起こしなどのモデル組織に合わせてカスタム化されたモデルで、且つ高スループットと低レイテンシーを必要とするケースに適している」と語られていました。
が、Lambdaのパッケージサイズ制限に収まらないモデルを動かす方法や、そのLambdaを本番環境レベルのレイテンシ(1~2s)で動かす方法など技術的面白ポイントが多かったので、そういった点を中心にレポートしていきたいと思います。

正月休みの自由研究として、公式のサンプル実装を先に見ずにまず実際に手元で実装し検証してきたので、そこで得た躓きポイントも含めてレポートしていきたいと思います💪
AWSによるサンプル実装はこちら
AWSによる関連ブログはこちら (車輪の再発明にはなりますが、長期休みの自由研究なので😎 )

セッションの中で、数GB級のLocal LLMをサーバレスかつ本番環境の要求水準で動かすにあたって、大きく以下3つのポイントとして語られていました。

  • 数GBのモデルと、Lambdaパッケージサイズ制限
  • コールドスタートの問題
  • LLMに求められるストリーミングの実現

それぞれ解説していきます🙌

(*情けない前置きと保険になってしまいますが、本記事内で出てくる「セッションの内容を元にした情報や説明」は筆者の乏しい英語力と、LLMによる文字起こしを根拠にしているので、誤情報が含まれる可能性があります。ご容赦ください 🙇️)

数GBのモデルと、Lambdaパッケージサイズ制限

Lambdaのパッケージサイズには厳しいサイズ制限が存在します。zip Lambdaの場合は250MB、 OCI(Open Container Initiative)の場合は10GBです。数GBのモデルを動かそうとする場合、zip Lambdaではまず不可能です。しかし、無邪気にOCI Lambdaを使用して数GBのモデルをLambdaに乗せようとするとコールドスタートが長くなる可能性があります。10秒以上のコールドスタート時間が発生するケースもあります。
この問題について、re:inventのセッションでは、「モデルをS3に配置し、実行時にLambdaの実行環境にロードする」というアプローチが紹介されていました。
ただ、シンプルにS3からロードしようとすると、Lambdaの /tmp ディレクトリが512MBに制限されているという、また別の壁が立ちはだかります。

通常、Lambdaの /tmp (エフェメラルストレージ)は最大10GBまで拡張することができますが、本番環境で求められる水準で動かすとなると、コールドスタートによる遅延に対処するために後述するSnapStartを有効化する必要があります。
しかし、SnapStartは512MBを超えるエフェメラルストレージに対応していない為、この制限が出てきます。

この/tmp制限を回避するために、S3 SDKのPython Boto Streamを使用して、メモリに直接ストリーミングする方法があります。
しかし、llama.cppなどlocal llmで推論を用いるためにはファイルディスクリプタ、つまりファイルパス必要になります
これを解決するために、Linuxのシステムコールであるmemfd_createを利用して、インメモリファイルを作成し、次にS3ファイルをダウンロード、そのmemfdへ直接書き込みを行います。
非常に面白いハックで、S3からダウンロードしたモデルデータをディスク(/tmp)を介さず、直接メモリ上に「仮想ファイル」として作成する仕組みです。
これにより、ディスクI/Oのオーバーヘッドをゼロにし、/tmpをバイパスしてファイルを読み込むことで容量制限を完全に回避できます。

memfd_createでインメモリファイルの作成

    libc = ctypes.CDLL("libc.so.6", use_errno=True)
    MFD_CLOEXEC = 1  # Close the fd when executing a new program
    
    memfd_create = libc.memfd_create  # インメモリファイルの作成
    memfd_create.argtypes = [ctypes.c_char_p, ctypes.c_uint]
    memfd_create.restype = ctypes.c_int
    
    fd = memfd_create(b"model", MFD_CLOEXEC)

サンプル実装リンク

S3 マルチパートダウンロードを用いてmemfdへ書き込み

    # Create memory file
    fd = create_memfd()
    
    # Pre-allocate the full file size
    try:
        os.ftruncate(fd, file_size)
    except OSError as e:
        logger.error(f"Failed to allocate {file_size/1024/1024:.2f}MB in memory: {e}")
        cleanup_fd(fd)
        raise RuntimeError(f"Not enough memory to load model of size {file_size/1024/1024:.2f}MB")
    
    # Calculate parts for parallel download
    parts = []
    for start in range(0, file_size, chunk_size):
        end = min(start + chunk_size - 1, file_size - 1)
        parts.append({'start': start, 'end': end})
    
    logger.info(f"Downloading {file_size/1024/1024:.2f}MB in {len(parts)} parts")
    
    # Download parts concurrently using ThreadPoolExecutor
    download_func = partial(download_part, s3, bucket, key, fd)
    with ThreadPoolExecutor(max_workers=multiprocessing.cpu_count()) as executor:
        executor.map(download_func, parts)
    
    # Create a path that can be used to access the file
    fd_path = f"/proc/self/fd/{fd}"
    return fd, fd_path

サンプル実装リンク

LambdaからLinuxのシステムコールを呼び出すという概念が無かったので流石に痺れました。

実際にこの手法を試し、ファイルサイズが4.5GBもあるllama-2-7b-chatモデルをLambda上でロードすることに成功しました。

コールドスタートの問題

memfd_createでモデルのロードは成功したものの、そのまま呼び出すとコールドスタートの所要時間が絶望的に長い状態でした。
サンプル実装よりも使用しているモデルサイズが大きいこともありますが、以下のような計測値になっていました😇

フェーズ 所要時間
S3ダウンロード(4.5GB) 62-63秒
推論など 20-25秒
合計 84-87秒

そこで、セッション中で紹介されていた解決策である「Lambda SnapStart」を導入しました。 これは、関数の初期化フェーズ(今回のケースではモデルのS3ダウンロードとメモリへのロード)を完了した状態をスナップショットとして保存し、次回以降はそのスナップショットから高速に復元する仕組みです。
スナップショット時の処理はモジュールレベルで、ハンドラーの外側に記述しておくことで、Lambda関数のデプロイ時(厳密にはalias発行時)に行われます。

SnapStartの適用により、S3ダウンロードの時間をまるまる削減することに成功しました。

フェーズ 所要時間
スナップショット復元時間 4.1-4.4秒
推論時間 17.1-17.2秒
合計 21-22秒

間話: 推論の高速化

推論時間に20秒もかかるのはとても辛いのでパラメータチューニングを行い、8秒ほどに短縮しました。
これはモデル固有のチューニングであるので詳細は省きますが、割り当てられたCPUリソースを使い切るthreads数を指定していなかったというオチでした😇

LLMに求められるストリーミングの実現

次なる目標は、LLMチャットなどに不可欠な「レスポンスのストリーミング」の実現です。 re:Inventセッションでは「Lambda Web Adapter + FastAPI」というアーキテクチャが紹介されていました。これはLambda内でWebサーバーを動かし、Lambda Function URLs経由でストリーミングを実現するものです。 Lambda内でLLMの回答生成が完了するまでバッファリングすることなく、逐次回答していくことにより、結果として最初の1トークン目がクライアントに届くまでの時間(TTFT[^Time To First Tokenの略])を、Warm Start時には 1~3秒 ほどまで短縮することに実現しました🎉

フェーズ 所要時間
ColdStart時のスナップショット復元時間 4.1-4.6秒
TTFT 1.1-3.8秒
合計 1.1-8.4秒

この辺り、筆者は5GB近いサイズのモデルを利用しているためこの時間ですが、モデルの選択やスペックによってはもっと早くいけると思います。実際にサンプル実装では1GBほどのモデルにより1~2秒でのレスポンス速度を実現してるとのことです。

ハマりポイントとして、Lambda Web Adapte(LWA)を有効化したところ、SnapStartのためのINIT処理が失敗するようになりました。具体的にはモデルのロード中に失敗してしまう状態です。 原因はLWAがモデルロードの完了を待たずに初期化処理を完了していた点でした。 LWAは同期/非同期2種類の初期化モードを持ちます。非同期モードの場合、LWA自身のReadiness Check(/health等への応答確認)が成功した時点で、Lambdaサービスに対して「INITフェーズ完了」を報告してしまいます。
AWS_LWA_ASYNC_INIT='false'(同期初期化モード)を使用することにより、モデルのロードを待ってINITフェーズの完了とすることになります。この辺りは自前実装をしないと理解に繋がらないポイントだと思うので、良い学びでした。

まとめ

今回はLocal LLMをLambdaで実行するという少し珍しいケースでしたが、この検証を通じて得られた知見は、他の多くのケースでも応用できる汎用的なものばかりでした。

  • memfd_createは、LLMに限らず、機械学習のモデルファイルや遅延呼び出し可能なライブラリなど、GB級のファイルをLambdaで扱う際の強力なテクニックになりそう
  • SnapStartは、モデルのロードだけでなく、DBコネクションの確立や重いライブラリの初期化など、初期化処理が重いあらゆるLambda関数で有効なコールドスタート対策
  • Lambda Web Adapterは、PythonランタイムのLambdaでFastAPIなどの標準的なWebアプリケーションフレームワークを動かすための非常に強力なツールであり、ストリーミング以外にも様々なユースケースが考えられる

ちなみに余談ですが、本セッションの登壇者はLWAの開発者でもありました。
「Pythonランタイムは、今のところ応答ストリーミングを公式にはサポートしていません。幸いなことに、私が作成したLambda Web Adapterというツールがあります。」はウケました(会場もウケてた)。
いやー本当に良い経験をしました。チョークトークに参加して良かったとしみじみ思います。

それではみなさん、良きサーバーレスライフを👋

業務を無くすため、Opsファースト開発という選択肢

この記事は、ニーリーアドベントカレンダー2025 の25日目の記事です。

ニーリーCTOの三宅です。今年もトリを担当します。 去年はDXCriteriaで一年を振り返りました。 今年も振り返りを書くつもりでしたが、振り返ってみると、一番伝えたいのは別でした。

採用で最も苦戦したプロダクトマネージャーの面白さです。

この記事では、ニーリーのプロダクトマネージャーの役割と面白さを1つ紹介します。 テーマは、「業務を無くす」プロダクトマネジメントです。


ニーリーのプロダクトマネージャーとは

ニーリーのプロダクトマネージャー(以下、PdM)は、ミッションを「顧客とマーケットに向き合い、価値提供を創造し続けること」としています。 役割は「特定領域のPLや事業KPIに、裁量と責任を持つこと」と定義しています。 いわゆるmini CEOに近い役割です。

そして、ニーリーのPdMの特徴は、「価値を作るレバーはプロダクトだけじゃない」 という点に尽きます。

ニーリーには「プロダクトエンジニア」という役割があります。

プロダクトエンジニアは事業に染み出します。その結果、PRDを書くようなPdM業務の一部を、プロダクトエンジニアが担う場面があります。開発スケジュールの管理も、プロダクトエンジニア側で対応します。だからこそニーリーのPdMは、さらに事業へ染み出すことを推奨しています。

note.nealle.com

さらに「事業へ染み出す」とは何か。 それは、「プロダクト × マーケ × オペレーション」、あらゆる手段を使って価値を作ることです。手段を限定せず、使えるものを全部使います。

ニーリーはいま、3つの事業を展開しています。 どの事業でも、価値はプロダクトだけで作っていません。「プロダクト × マーケ × オペレーション」を組み合わせて作っています。

そのため、ニーリーのPdMはレバーを幅広く持つ必要があります。 それもただ、持つだけではなく、使いこなすことが求められます。

そしてこの記事では、「プロダクト × オペレーション」にフォーカスしてお話しします。


機能がないなら、まず自分たちで業務を引き受けるという選択肢

SaaSプロダクトを開発していると、機能要望への対応は避けて通れません。個社カスタマイズの要求。ロードマップにはあるが「今ほしい」という声。対応すべきか、優先順位を変えるべきか、迷う場面は少なくありません。 ニーリーでは、機能がないとき、開発ロードマップの見直しはもちろん検討します。ただ、それに加えて「機能がないなら、まず自分たちで業務を引き受ける」という選択肢を持っています。 プロダクトで解決できないなら、Ops(オペレーション)でカバーする。業務を回しながら、プロダクト化の道筋を探る。私たちはこれを「Opsファースト開発」と呼んでいます。(今、命名しました笑)このアプローチがVertical SaaSで急成長してこれた秘訣の1つだと思っています。


なぜOpsファースト開発を選択するのか

「プロダクトがないのに業務を引き受ける」と聞くと、非効率に見えるかもしれません。 人手がかかる。スケールしない。その通りです。 それでも私たちがOpsファーストを選ぶ理由は、3つあります。

1. 顧客への価値提供を最速最大にできる

SaaSを導入しても、システムを操作する業務は残るため、顧客の業務は楽になれどゼロになることは少ないです。また、データ移行、運用フローの変更、社内への説明など、SaaSを導入するまでにも時間がかかります。 業務がゼロか、少しでも残るか。この差は大きいと考えています。私たちが業務を引き受ければ、顧客は「導入した瞬間から業務がなくなる」状態に近づきます。 私たちは、顧客の業務を最速でゼロにすることを目指しています!

2. 変更をコントローラブルにできる

一度導入されたシステムを変えるのは大変です。 「このフローを変えてください」と頼んでも、顧客側にも事情があります。 結果として、よい機能を作ってもリリースしづらくなります。 現場にとって、業務変更は負担です。通常業務を回しながら、新しいやり方に切り替える必要があります。そのため「今の業務に合わせてほしい」というカスタマイズ要望が増えがちです。 ここにジレンマが生まれます。 一方で、業務を私たちが引き受けていると話が変わります。 やるべきことさえ満たせば、業務フローは自由に変えられます。新機能のリリースも社内で完結します。フォローもしやすく、出しやすくなります。 つまり、価値提供のスピードを上げるためには、「”システム”や”業務”を変えられる側に立つ」ことが重要になります。

3. いいプロダクトを早く作れる

プロダクト開発で一番むずかしいのは、業務解像度を上げることです。 ヒアリングだけでは限界があります。顧客の言葉と、実際の業務にはズレが出ます。 そのズレを埋める最短ルートは、自分達で業務をやることです。 Opsを引き受けると、業務解像度が一気に上がります。 社内に実務者がいるので、いつでも聞けます。自分でも体験できます。 リリースの刻み方も変わります。 外部の顧客向けは、ある程度作り込まないと出せません。 一方、社内ユーザー向けなら相談できます。 「このエッジケースは一旦外してOpsで耐える」、「70点の完成度でも先にリリースして価値検証する」など、小さく出して、早く学べます。


「受ける・受けない」の判断軸

「Opsで受ける」といっても、何でも受けていいわけではありません。 やったことがない業務を正確に見積もるのは難しいです。 しかも、始めるのは簡単です。また、どうしても目先の目標や要望に引っぱられやすくなります。 しかし、判断を誤ると、業務量が膨れ負債となり、 最悪予算を逼迫してプロダクト開発が減衰します。 だから私たちは、受ける・受けないの判断の時に、アウトカム効率(効果と対応コスト)に加えて、次の2軸で判断します。

軸①:トップラインへの影響度合い

この軸は、受ける・受けないの判断以外にも、「受けたOpsをいつ自動化するか」を決めるときにも使います。 優先順位は、次のとおりです。

  1. トップラインや重要KPIに直結するもの
  2. 業務効率化を通じてトップラインや事業KPIに効くもの
  3. 業務効率化でコストが下がるもの

1は分かりやすいです。ポイントは同じ業務効率化でも2と3を分け、基本は1,2を優先することです。コスト削減も重要です。ただし私たちは、事業成長に効く開発を優先しています。

軸②:将来、自動化しやすいか

トップラインに効くなら何でも受けるかというと違います。すべての業務をずっとOpsで対応するわけにはいきません。だからこそ、将来システムで自動化できる見込みを必ず見ます。

ただし、この判断は事業フェーズで変わります。 たとえばパークダイレクトには、貸与物(機械式駐車場の鍵など)の管理ニーズがあります。現物を扱うので、システム化しづらい業務です。私たちは当初、この要望へは対応していませんでした。

いまはフェーズが進み、Opsの体制も整いました。その結果、オプションサービスとして対応しています。「業務を無くす」という価値提供を優先し、受ける判断に切り替えました。

自動化できないなら受けないではなく、理想とする世界観を目指して、その時の事業や組織状況を踏まえて、バランスをとるのが大事です。


プロダクトだけではなくOps組織をマネジメントする

Opsで受けるなら、業務設計が要ります。 組織の構築だったり、メンバー育成も要ります。日々の業務管理も発生します。 ニーリーの特徴は、Ops管理にPdMが深く関わることです。

現在、お金周りのオペレーションを司るPAYグループとそれ以外のオペレーションを司るOpsグループ、それぞれの責任者をPdMが担当しています。PdMが実務の組織を管轄するのは、珍しい構造かもしれません。 しかし、PdMがOps組織を管轄することで、「受ける/受けない」の意思決定スピードを速められ、さらに、業務で得た学びをプロダクトへフィードバックし、プロダクト開発の速度も上げられています。


出口戦略なきOps受けは沼になる

ここまでOpsファースト開発や、PdMがOps管理に関わるメリットを語ってきました。ただ、いい話ばかりではありません。

出口戦略がないと、Opsから抜け出せません。

事業が伸びるほど、業務は増えます。急成長を狙うほど、増え方も急になります。「増える量」より「減らす量(効率化)」を上回らせることが重要です。 でも、引き受けた業務は止められません。必ず回す必要があります。そのため、PdMがOpsに染み出している場合、時間は「回す」側に寄ります。その結果、プロダクト開発に割ける時間が減り、効率化が遅れ、より詰まります。悪循環です。 このループに入ると、抜け出すのは難しいです。だからこそ、受けるなら最初に出口を用意することが重要です。たとえば、効率化のロードマップを先に引き、追加の開発リソースも確保します。


当事者だから味わえる、速さと手触り感の面白さ

プロダクトマネジメントや開発をやってきた人ほど、Opsは「面倒で楽しくない」と感じるかもしれません。自分もそうでした。エンジニアの道を選んだ理由の1つは、「できるだけ楽したい」だったので、その気持ちはよく分かります。

でも、実際にやってみると印象は変わります。Opsは、想像よりずっと面白いです。

わたしは、前職はITコンサルで、業務効率化の案件を多くやっていました。 仕事自体はやりがいがあり、楽しかったです。ただ、不満もありました。業務を変えるスピードが遅いことと、変わった実感を持ちづらいことです。

金融のように業務の正確性が重要な領域では、業務変更に慎重になるのは当然です。 それでも自分は、もっと速く業務を変えたかった。 また、システム導入で「楽になった」と言われたときは嬉しいですが、当事者ではない自分にとっては手応えが薄い、そんな感覚が残りました。

けど、今は違います。 自分の裁量で決められるので、変えるスピードが速い。遅いなら自分の責任です。 変化もダイレクトに返ってきます。自分次第で、業務変革のダイナミックさを手に入れられる。それが、いちばんの面白さです。


さいごに

ニーリーのPdMの役割と面白さの1つとして、Opsファースト開発を紹介しました。 PdMがOpsへ染み出し、業務を引き受け、業務を無くしていく。そんなプロダクトマネジメントの話です。

「業務効率化」と聞くと地味に見えるかもしれません。 でも実際は、変化の速さと手触り感があります。しかも、インパクトも出ます。だから面白いです。

最近はプロダクトAI開発チームと組み、AIで業務の完全自動化にも挑戦しています。 ビジネスだけでなく、技術的にも面白いフェーズです。

業務効率化の余地は、まだまだあります。 業務を減らし、可処分時間を増やし、社会をよくしていきましょう。 少しでも興味を持っていただけたら、カジュアル面談で話しましょう。

カジュアル面談はこちらから!

nealle.notion.site

Claude Code hooksでMacの通知を出して、通知から適切なtmuxペインに飛ぶ

お疲れ様です。@2357gi です。
筆者環境では、Terminal.app で開いた tmux の複数のセッション・ペインで同時並行に Claude Code を動かしてます。
Terminal.app 以外を開いてたり、Terminal.app を開いても裏画面の tmux ウィンドウ/セッションで動いている Claude Code の待機状態に気づかないことが多々あります。 そこで、受付状態になった時にいい感じにMacの通知を出してくれるやつと、その通知から直接待機状態の Claude Code が開かれている tmux ペインを開くやつを作りました。

Claude Code にお願いすればサクッと作れるとは思いますが、後者の 通知から該当の tmux ペインを開くスクリプト の実装で若干はまりどころがあり試行錯誤したので、勘所のまとめとスクリプトそのものを共有します。
(*ただし、筆者環境ではVS codeでも Claude Code を開く為、それ用の設定も入っています )

自分の試行錯誤分、あなたのtokenを節約できたら幸いです🫰

実際に使用しているScriptとインストール方法

以下のスクリプトはgistに纏めてあります。
claude-notification.sh · GitHub

上記のファイルを ~/.claude/hooks/ に配置し実行権限を付与、以下のようにhooksの設定を行えば完成です。

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/claude-notification.sh"
          }
        ]
      },
      {
        "matcher": "idle_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/claude-notification.sh"
          }
        ]
      },
      {
        "matcher": "tool_permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/claude-notification.sh"
          }
        ]
      },
      {
        "matcher": "user_question_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/claude-notification.sh"
          }
        ]
      }
    ]
  }
}

terminal-notifierが寂しかったので $HOME/.claude/icons/claude-ai-icon.png に画像を配置して使ってます。
該当ファイルが存在しなくても動きますが、よしなにやってください。

実装の全体像

Claude Codeのhooksを使用して、受付状態になった時に通知を出すスクリプトを実行しています。 通知をクリックすると特定のコマンドが実行されるようになっており、 通知クリック時のフォーカス処理は以下の流れで実装されています。
通知は定番の terminal-notifier を使用しています。-execute オプションを使用することで通知が押下された時に任意のコマンドを実行できます。

Claude Codeが待受状態になり、hook が発火する
  ↓
terminal-notifier によって通知が出る
  ↓
通知クリック
  ↓
terminal-notifier の -execute オプションによってコマンドを実行
  ↓
Terminal.appのアクティブ化 & tmuxセッション・ペインへのフォーカス

通知側(claude-notification.sh)での呼び出しは以下のようになります:

terminal-notifier \
    -title "Claude Code" \
    -message "$rich_message" \
    -subtitle "$subtitle" \
    -group "claude-code-$SESSION_NAME-$PANE_ID" \
    -contentImage "$ICON_PATH" \
    -activate "com.apple.Terminal" \
    -execute "$HOME/.claude/hooks/focus-tmux-pane.sh '$SESSION_NAME' '$PANE_ID' '$TMUX_SOCKET'"

実装の勘所

-execute オプションでパスが通らない

terminal-notifier-executeオプションで起動されるスクリプトは、最小限の環境変数しか持たないプロセスとして実行されます。通常のシェルセッションとは異なり、/usr/local/bin/opt/homebrew/binなどのパスが含まれていません。

スクリプトの冒頭で明示的にPATHを設定する必要があります。

#!/bin/bash

# Set PATH to ensure tmux is found
export PATH="/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:$PATH"

tmux のソケットに接続できない

複数のtmuxサーバーが動作している環境や、非標準的なソケットパスを使用している場合、tmuxコマンドはデフォルトソケット(/tmp/tmux-$UID/default)に接続しようとします。しかし、実際のClaude Codeセッションは別のソケットで動作している可能性があります。

そこで、hookが発火した時に$TMUX環境変数からソケットパスを抽出し、-Sオプションで明示的に指定します。

通知スクリプト側:

# Extract tmux socket path from $TMUX variable (format: /path/to/socket,pid,session_id)
TMUX_SOCKET=$(echo "$TMUX" | cut -d',' -f1)

フォーカススクリプト側:

SESSION_NAME="$1"
PANE_ID="$2"
TMUX_SOCKET="$3"

# Use the tmux socket to connect to the server
tmux -S "$TMUX_SOCKET" switch-client -t "$SESSION_NAME" -c "$client_tty"

switch-clientが複数クライアントで正しく動作しない

単一のtmuxクライアントでは動作するものの、同じセッションに複数のクライアントが接続している場合に正しくフォーカスできませんでした。

tmux switch-clientコマンドは、どのクライアントを切り替えるか指定しないと、現在接続されているクライアントに対して動作します。しかし、通知クリック時のスクリプトはtmuxセッションの外部から実行されるため、「現在のクライアント」という概念が存在しません。

全てのクライアントを列挙し、それぞれに対して明示的に操作を実行することで解決しました。パワーです。

# Get all tmux clients and switch each one
clients=$(tmux -S "$TMUX_SOCKET" list-clients -F '#{client_tty}' 2>&1)

if [ -n "$clients" ] && [ "$clients" != "error"* ]; then
    echo "$clients" | while read -r client_tty; do
        # Switch the client to the target session
        tmux -S "$TMUX_SOCKET" switch-client -t "$SESSION_NAME" -c "$client_tty" 2>/dev/null
        # Select the target pane (use pane ID directly)
        tmux -S "$TMUX_SOCKET" select-pane -t "$PANE_ID" 2>/dev/null
    done
fi

私は日毎単一のターミナルを用い、そこで tmux を運用しているためこの仕様を落とし所としました。
複数のターミナルを開き、一つのセッションへ複数のクライアントから接続している場合は問題が発生する可能性があります🙇‍♂️


それでは以上とさせていただきます。
良いClaude Code Lifeを👋

ニーリー初のMeetupイベントを開催!〜準備不足を反省してポストモーテムを書く〜

この記事はニーリーアドベントカレンダー2025の24日目の記事です。

こんにちは、菊地(@_tinoji)です。今年のアドカレもクリスマスイブを担当させてもらいます!🎄

1ヶ月前に、ニーリー初となるMeetupイベントを開催し、予定枠を増枠するほど多くの方にお越しいただきました。

nealle.connpass.com

当日の様子(撮影許可はいただいてますが参加者には一応ぼかしを、、)

ご来場の皆さんにはかなり楽しんでいただけたとは思う一方、僕の不手際でかなりご迷惑をおかけしてしまったので、会の終わりに「アドカレでポストモーテム書きます!」と宣言しましたw

ニーリーで普段使っているポストモーテムのテンプレートを一部流用して、それっぽく書いてみます。完全にネタ枠ですので安心してご笑覧ください!

※一部、会場の設備について触れていますが、全くもってお店側に瑕疵はありません!完全にこちらの準備不足ですmm

基本情報

項目 内容
ポストモーテム作成日 2025/12/24
著者 @菊地弘晃
レビュアー ブログを読んでいる皆さん
本番環境への影響の有無 あり
インパクト 運営16名 当日参加者21名、合計37名のUXに影響。

サマリ

  • 何がおきたのか、影響は?
    ①ニーリーメンバーの決起集会が実施できない
    ②プロジェクターとマイクが利用できない
    ③Q&Aコンテンツが実施できない
  • 原因は?
    圧倒的準備不足、会場の下見不足。
  • 教訓を一言で
    時間には余裕を持て。会場は下見せよ。

検知

いずれも会場に到着してからの検知。監視ツール等のスコープ外。

影響・原因・暫定対応

サマリに記載の①〜③について詳細を記載する。

①ニーリーメンバーの決起集会が実施できない

「初めての取り組みだし、事前にニーリー側の心得をインプットしたり、話して欲しい参加者を連携した方がいいのでは?」という提案があったので、受付開始の30分前にお店に集合して決起集会を実施しようと思ってました。

会場に着き座席のセッティングなどを終え、いざ決起集会をやろうと思ったところ、1人目の参加者の方が受付開始より早く到着されたので、決起集会は断念することに、、、
よくよく考えると自分もイベントに参加するときは記載されている時間より早く行くので、「受付開始時間」を記載しても、それよりも早く来られる方がいることは容易に想像できたことです。

ニーリーメンバーの心得は事前に資料も展開していたので、全員読んでいることを信じてそのままイベントへ突入。結果として大きな問題とはなりませんでした。

↓資料は有志のメンバーが作成し、パックマンルールなどを記載してくれていました。感謝。

②プロジェクターとマイクが利用できない

スライドを使って説明したいことがあったので、プロジェクターとマイクの設備があるお店を利用させていただいたのですが、プロジェクターは僕が持ち込んだコネクタとの相性が悪いのか画面がチラついてしまい、マイクは40人近い参加者に届かせるには音量が心許ない、ということが当日判明しました。

繰り返しですがお店側に不手際はなく、事前に伺って機材確認をしなかった僕の責任です🙇‍♂️ プロジェクターは普段は使えている設備ですし、マイクはもっと少人数であれば問題ない音量だと思いました。

暫定対応としては、スライドは使わず口頭のみで説明して、音量はでかい声を出すというパワー解決に。皆さんのご清聴により致命的な問題にはならず、むしろ一体感が生まれた、かもしれません(希望的観測)。

③Q&Aコンテンツが実施できない

事前に参加フォームで「ニーリーに聞いてみたいこと」をヒアリングしていたのと、当日の話題提供なども含めてSlidoを使ったコンテンツを設けていたのですが、②の影響で実施が難しくなりました。

用意していたスライド

フォームを記入いただいていた皆さんには申し訳なかったのですが、結果として交流の時間が長くなったので、その中で会話できた可能性が高いと思っています。

(補足) 人数が多くてビリヤード台が利用できない

これはとあるメンバーへの懺悔としてw

ダーツとビリヤードができるバーを利用させてもらったので、ビリヤード好きのメンバーがわざわざキューを持参していたのですが、人数が予定より多くなったのでビリヤード台は食事を置くテーブルとして利用することに。
しかもそのメンバーは地方在住なので、新幹線でキューを運んできてくれてました。いやーごめん😇

後から聞いたら3次会(タフ過ぎる)で無事ビリヤードはできたみたいでした。一度も使わずに持ち帰ることにならなくてよかった、、、

再発防止策

結論、①は時間に余裕を持つこと(あるいは決起集会は事前に実施しておく)、②③は会場を下見することで再発防止が可能、というなんとも当たり前の振り返りとなります。
「当たり前のことを当たり前にやる」というのはソフトウェア開発のポストモーテムでも振り返られることが非常に多く、結局それを続けることが大切だよなぁとしみじみ。

準備チェックリストを作成したりJIRAのチケット化を行うことで、属人化せずに改善ができる想定です。Meetupイベントは今後頻繁に行っていきたいので、一時の反省にせず、次回以降のイベントをより良くするために尽力していきます!

よかったこと・幸運だったこと

ちょっとポストモーテム感が強くなってしまったので、ポジティブなことも書きます😇 (この項目は元のポストモーテムにもあります)

結論から言うと自社のMeetupイベントはやって良いことしかないと思いました。
ブログやnoteでは伝わらないニーリーの生の雰囲気を感じてもらえる、カジュアル面談や食事よりも参加の心理的ハードルが低い、しばらく会っていない知り合いをラフに招待できる、参加者同士の交流も楽しんでもらえる、普通に技術の話で盛り上がることもできる etc... メリットはいくらでも挙げられますが、デメリットは今のところ思いつきません。

初回ということもあって、Connpassからオーガニックに流入していただいた方よりも、メンバーの知り合いや過去カジュアル面談をしたことがある方などが多かったですが、結果としては「いい感じに採用色の薄いイベント」になったと思います。

「採用感が出過ぎて引かれたらどうしよう」「知り合い同士で話して排他的な印象を与えてしまったらどうしよう」というのが企画側の最大の懸念だったのですが、参加者同士の交流も多く、まさにMeetup(= 共通の興味・目的を持つ人々が交流や情報交換をするカジュアルなイベント)という雰囲気でした。

やはり普段からテックイベント等によく参加されている方たちは「場を楽しむ力」が強いなと思いました。改めて、参加していただいた皆さんありがとうございました!!

↓Q&Aコンテンツがなくなり、開き直ってダーツを楽しむ僕を貼っておきます。

おわりに

現在ニーリーでは開発組織の多くのポジションを積極採用中です!
ぜひ次のMeetupに来てください!
と言いたいところですが次回の日程はまだ未定なので、次の開催を待ちつつ、まずはカジュアル面談へお越しください!

nealle.notion.site

手を広げて気づいた、集中の本質—「捨てない」という選択

手を広げて気づいた、集中の本質—「捨てない」という選択

こんにちは、株式会社ニーリーの中村です。
昨年アドカレでランニングを宣言したわけですが、見事継続し、今年の区民マラソン完走を果たすことができました! 最初はほんと足が痛くて辛すぎましたし、大会1ヶ月前にコケて、1週間近く走れない、1週間前に熱が出て直前まで走れない、なんてこともありましたが、ほんとよかったです。

さて気づけば、ニーリーに入社して3年が経ちました(2022年8月入社です)。 この3年間、私はサクセスエンジニアとして様々な経験を積んできましたが、振り返ると「集中する」ことの意味を、少しずつ学んできた3年間だったと思います。

皆さんも、「集中したいけど、色々な仕事が降ってくる」という経験、ありませんか? この記事では、手を広げた経験があったからこそ気づけた「集中の本質」について書きたいと思います。

はじめに

いつものことながら、そもそもサクセスエンジニアリングって何?と思われた方もいると思います。 サクセスエンジニアリングの面白さについては、いつもカジュアル面談でも語り尽くせないぐらいなのですが、そんなあなたにピッタリのnoteがこちらにありますので、ぜひ御覧ください。(1年ぶり2回目)

note.nealle.com

昨年のアドベントカレンダーでは、サクセスエンジニアリングだけでなく、プロジェクトマネージャー、アカウントマネージャー、セキュリティ担当など、様々な役割を兼務していることを「事業成長にコミットできる良い経験」として書きました。(マラソンのことも冒頭で触れてます)

nealle-dev.hatenablog.com

あれから1年。私は「集中」ということについて考え続けてきました。

手を広げる

2024年、私は本当に多くのことを経験しました。
そもそもサクセスエンジニアリングは全部署とのコミュニケーションが必要な部隊です。 1つ1つの部署にヒアリングに行って、「そうですね」なんてできればいいのですが、そんな時間はありません。
そこで私はできる限り何かあったときに声をかけてもらう戦略を導入しました。名付けて「何でも屋」。 もうほんとなんでもいいから聞いて、DMでもいいから連絡してと言い続けました。 また、プロジェクトマネージャーやアカウントマネージャーなどで学んだことは昨年のアドカレの通りです。プロダクトやその周りのオペレーションをいろいろな視点から見ることができました。

一方でこの頃から、少し自分の中でもやもやが出始めます。

いろんな経験はできた。でも、大きな成果を出せただろうか?

自分は様々なことに関わっていたし、解決もしてきたけれど、「これで大きな成果を出せた」と胸を張れるものがありませんでした。広く浅く、という表現が適切かもしれません。

集中する

そこで、2025年に向けて「集中する」と決めました。

2024年にできなかった"大きな成果"を、2025年こそ成し遂げたい。
自身の主戦場であるサクセスエンジニアに集中するため、兼務の業務を段階的に外していきました。また、サクセスエンジニアの中でも集中する領域を決め、特定の施策の遂行に注力するようにしました。(これまではプロダクトや他のメンバーが手を出していないところをすべてやっていました)
7月にはもともとやっていたリーダー業務も分担し、より「集中できる環境」を整えていきました。

でも、集中できない

ただ、ここで一つ問題がありました。
ニーリーは急成長を続けている会社です。事業は日々動いており、予期しない依頼や急なトピックが発生します。

サクセスエンジニアリングチームには事業を成長させるというミッションがあります。 自身の施策に集中しようと思っていても、より事業に重要なアジェンダが流れてくる、自身の施策が止まる、みたいなことが何度か続きました。

結果として、事業のためとは言えど、「集中すると決めたのに、結局できていない」という、少しもやもやが残るような状態になっていました。

集中しているけど、捨てない

その思いをいろいろな方に相談したときに原因がわかりました。
一般的に「集中」というと、「一つのことに専念し、それ以外を断ち切る」という意味で使われます。 最初、私も0か100かの思考になっており、片方の施策を止めることを選んでいました。

しかし、事業をより成長させるための「集中」はそうではない。 どちらかを選ぶのではなく、「どちらもできないか」を考える。

急な依頼が来たとき、「このプロジェクトを進めつつ、こちらの依頼にも対応できる方法はないか」と考えるようにしました。

  • 時間配分を工夫する(朝の時間を集中施策に使う、急ぎの対応は夕方の時間を使うなど)
  • 誰かに一部を任せる(全部は無理でも、調査だけお願いする、レビューだけ自分がやる)
  • やり方を変える(会議ではなく非同期でドキュメントベースで対応する、Slackのスレッドで完結させる)
  • スコープを調整する(今週は70%を集中施策、30%を緊急対応に。来週は比率を戻す)

0か100かではなく、70と30、80と20でもいい。欲をいえば、週によって80と50でもいい、次の週はもちろん100と0でもいい。
トータルで事業を前に進められるなら、両方に手をつける。
集中することが1つに絞ることと無意識に行動していた自分にハッとし、私の思う「集中の本質」に辿り着くことができました。

手を広げたからこそ得た集中

振り返ってみると、2024年に手を広げた経験があったからこそ、この考え方に辿り着けたのだと思います。

手を広げたからこそ事業にとって大事な観点は何かを様々なところで経験できたし、それがなければ今の観点は生まれなかったと思います。
もし最初から「一つのことだけをやりなさい」と言われていたら、ほんとに1つしかやらなかったと思いますし、他にも気づけてないと思います。

様々な役割を経験したからこそ、「どうやったら両方できるか」を考える引き出しが増えましたし、それによって事業に貢献できている実感もあります。
そして、「集中する」という言葉の意味も変わりました。

  • 大きな成果を出すためには集中することも必要。
  • 一方で集中するとは、すべてを捨てることではない。
  • 自分が最も価値を出せる場所に時間とエネルギーを集中させながら、事業のために必要なことには柔軟に対応すること。

それが、成長企業で働く上での「集中の本質」なのだと思います。

マルチタスクに悩んでいる方へ

もし、この記事を読んでいる方で、マルチタスクに悩んでいる方がいたら、こう考えてみてください。

「今、自分が一番時間を使うべきことは何だろう?」

「集中したいのに、割り込みタスクが多すぎる」と感じることもあるでしょう。
でも、手を広げることは悪いことではありません。むしろ、手を広げたからこそ見える景色があります。ただ、どこかのタイミングで「今、自分は何に集中すべきか」を問い直すことが必要です。 そして、それ以外のことを「捨てる」のではなく、「関わり方を変える」「誰かに任せる」「時間配分を変える」などの様々な選択肢があることを思い出してください。

私自身、2025年12月からアカウントマネージャーの役割にシフトすることになりました。これは「集中」を選んだ結果でもあり、同時に「サクセスエンジニアとしての経験を活かせる新しい場所」でもあります。手を広げて気づいた「集中の本質」を大切にしながら、これからも事業に貢献していきたいと思っています。

最後に

ニーリーは、急成長を続ける会社です。その中で、様々な役割を経験できる、チャレンジできる環境があります。 もし、「いろんなことに挑戦したい」「事業成長に貢献したい」と思っている方がいたら、ぜひカジュアル面談でお話しさせてください。
一緒に、事業を伸ばしていきましょう!

re:Inventに参加してきました!参加にあたって目標としたことと、その振り返り

お疲れ様です!SREの大木 @2357gi です。そろそろ冬なのでスノボのために身体を温めています。
re:Invent 2025 へ参加してきたので、早速レポートをしていきたいと思います!
今回は弊社とAWSのリセール契約を結んでいる Megazoneさんに招待していただきました。大感謝です🔥
具体的なセッションのレポートや、「準備してよかったもの・いらなかったもの・しておけばよかったものまとめ」などはまた別のテックブログとしてアウトプットする予定です🙌

ざっくり前提:re:Inventとはなんぞや

ざっくりre:Inventについて説明しますと、AWSが毎年ラスベガスで開催するクラウドサービス最大規模のカンファレンスです。 基調講演や技術セッション、ワークショップで最新サービス・ベストプラクティスなどが発表され、多くの学びを得ることができます。 また、それ以外にも大規模なExpoやランニングイベント(!?)などコンテンツが目白押しで、とてもエキサイティングなイベントとなっております🔥🔥

re:Inventで目標としたこと

今回のre:Inventに参加するにあたり、ただラスベガス行って帰ってくるのは避けたいなと思い、「チャレンジすること・持ち帰りたいもの」を明確に決めて挑むことにしました。 具体的には以下になります。

  • 技術的なディスカッションを行う
  • 最新アプデで熱いのがあったら追加情報を持ち帰る
  • 5k Raceに挑戦し、走り切る
  • Expoで日本未上陸のAWSパートナーのプロダクトの情報を得て、かつディスカッションを行う
  • 日本人とばかり話さない(コンフォートゾーンを抜ける!)
  • そこでしかできない体験をする!

ちなみに、英会話前提で目標が組まれていますが、私の英語力は中学英語に毛が生えたぐらいです。 毎日Duolingoをやっているので行ける気はします(最近チェスにハマってます)。

結果

技術的なディスカッションを行う & 最新アプデで熱いのがあったら追加情報を持ち帰る

→ややできた

いくつかのセッションで直接登壇者・サポートへ質問を行い、追加で得るものがありました。 例えば、今回のre:Inventで発表されたDevOps Agentに関してはハンズオンに参加したのですが、そこでベストプラクティスについていくつかやり取りを行うことができました。
ただ、総じてディスカッションというほどガッツリ話込めたか?と言われると微妙なくらいだったので「ややできた」としています。 文法がガバガバでも質問を行うことはできるのですが、返答を100%理解できたかと言われると怪しく、ボキャブラリの乏しさを痛感しました。

5k Raceに挑戦し、走り切る

→達成!

re:Inventには、5k Raceという「ラスベガスの路上を封鎖しての5kmマラソン大会」が存在します。 トンチキイベントだなとは思いつつ、まさに re:Inventでしかできない体験 だと強く感じたので参加してきました🏃‍♂️ 5kmのランニング自体はスノボのための日ごろの体力作りの甲斐もありそこまで苦ではなかったのですが、何よりre:Inventの4日間歩き回っていたことも相まってしっかり筋肉痛にはなりました😇

ただ、封鎖されたラスベガスの路上を走る機会はまたとないと思うので、とても良い経験になりました。 路上封鎖につき警察の方も多く出ていたのですが、SUVタイプのパトカーが中央分離帯にズカンと乗り上げていてアメリカを感じました。

完走記念メダルも貰いました🏅

(同行したFindyの原さんと)

Expoで日本未上陸のAWSパートナーのプロダクトの情報を得て、かつディスカッションを行う

→達成できず

未上陸のAWSパートナーとプロダクトについての話ができたかと言われると正直難しかったなと思います。 セッションなどの場合、登場するサービスに対する理解や下調べができるので英語のリスニングもある程度できるのですが、全然知らんプロダクトのブースに行って話しかける分にはなかなかリスニングが難しく、断念しました...。
(英語が出来ないことに悔しさと恥ずかしさが込み上げる一幕があり、心が折れかけたりもしました、、、)

初日のみExpo会場にバーカウンターやフードが出てお祭りのようになります

日本人とばかり話さない(コンフォートゾーンを抜ける!)

→達成!

Expoで心折れかけたりもしましたが、トータルで見ると日本人以外の方と多くコミュニケーションを取れたと感じます。 会場移動中のバスや、何らかの待機列で積極的に隣の方に話しかけ、行ったセッションの話や今から何しに行くかといったコミュニケーションをとることができました。 また、re:Play帰りのバスで仲良くなったAWSの方が大企業からAWSへ転職された方だったので、AWSのカルチャーの話や、まさにこれからニーリーが直面するであろう会社の規模が大きくなる上でカルチャーを希釈させないためにどうすれば良いのか、といったディスカッションをすることができたのは良い経験でした。

日本に比べて他の人に話しかけるハードルが低い文化圏に最初は面食らったりもしたのですが、早い段階で「ここはこれに順応しなければ勿体無いぞ」と切り替えることができ、いろいろな方と話すことができてよかったです。

re:Playで仲良くなった陽気な奴ら。こんなにはしゃいでるのにトイレ一緒に並んだ時にIaCは何が一番良いか、みたいなtech話をできてオモロだった

そこでしかできない体験をする!

→達成!が、悔しさも

5k Raceなどもここに当てはまりますが、数多の re:Inventでしかできない経験 を得ることができました。 特に、非常に良い経験をしたと感じたのが Chalk Talk(チョークトーク) という形式のセッションです。 スピーカーに対して聴講者が20-30人ほどと参加者を絞ったセッションで、聴講者がセッション中に自由に質問をしてよい、対話式のセッションでした。

ホワイトボードにその場で図を書きながら質問者へ回答する一幕

自分も実際にLambdaに関するセッションへ参加し、ディープな内容のセッションを聞くことができました。 スピーカーがまさにLambdaの開発者で、そんな方に直接質問ができる機会はまたとないと思うのでとても熱かったです。 対話式のセッション、かなり学びがあって面白いので、是非ともAWS Summitとかでもやってほしいですね...!!

英語がそこまで得意なわけではないので事前準備など計画して行ったのですが、それでも質問者の英語やディスカッションをリスニングすることができず、とても歯痒い思いをしましたが、本当に良い経験になりました。次回こそは...!

詳しくはこちら

nealle-dev.hatenablog.com

終わりに

re:Invent、本当に人生において良い経験となりました。学びも、楽しさも、悔しさも盛りだくさんの4日間でした。 改めて、招待してくださったMegazoneさんありがとうございます。クラウドサービスのリセールが一番コスト圧縮に効く施策だと思っていますのでおすすめです。

そして、自分が一週間丸々出張している中支えてくれたチームメンバーにこの場を借りて感謝を伝えさせてください。本当にありがとうございました!

それでは、この辺で以上とさせていただきます。よきAWSライフを👋

自動化・AIワークフローのための"Scoped SSOT"という考え方

はじめに

この記事はBPaaS/AI+BPO Advent Calendar 2025 22日目の記事です。

サクセスエンジニアとして働いている増田です。

サクセスエンジニアってなんだ?

と興味を持たれた方はぜひこちらの記事を読んでください。

日々の業務では、社内ツールの開発やデータ変換システムの構築、業務設計や自動化などに取り組んでいます。

最近はAIを活用したワークフローの構築にも挑戦していますが、正直なところ、まだ大きな成果が出ているわけではありません。ただ、その過程で「自動化やAIワークフローを機能させるためには、その前段階のデータ整備が重要だ」という実感を強く持つようになりました。

本記事では、私が自動化基盤として導入した「プロダクト外にデータを集約する」というアプローチについて、その背景と考え方、そしてメリット・デメリットを共有します。

業務で起きがちな問題

自動化やAIを業務に導入しようとしたとき、まず直面するのは「データがどこにあるのか」という問題です。そして、いざワークフローを組もうとすると、データの取得、処理、書き戻し——それぞれのステップがボトルネックになっていきます。

多くの現場では、担当者ごとにエクセルやスプレッドシートが作られ、似たようなデータがあちこちに散らばっています。「最新版はどれ?」「このデータ、あのシートと合ってる?」といった確認作業が日常化しているのではないでしょうか。

エクセルやスプレッドシートは、世界一簡単にデータベースを作れるツールです。誰でも使えますし、どんな業務にも対応できる柔軟性を持っています。だからこそ、気づけば「XXX台帳」「XXXマスター」といったファイルがあちこちに生まれていきます。

しかし、これらを自動化やAIワークフローに組み込もうとすると、途端に難しくなります。

データの取得——まず、どのファイルのどのシートを見ればいいのかを特定しなければなりません。同じような情報が複数の場所にあると、どれが正しいのか判断するロジックが必要になります。スプレッドシートのAPIは存在しますが、セル範囲の指定やシート構造への依存など、ちょっとした構造の変更で壊れやすい連携になりがちです。

処理——複数のシートやファイルからデータを集めて突合する必要が出てきます。人間なら目で見て「あ、これとこれは同じだな」と判断できますが、プログラムにはそれが難しい。表記揺れや微妙なフォーマットの違いを吸収するコードが膨らんでいきます。

書き戻し——処理結果をどこに保存するかも曖昧になります。元のシートに書き戻すのか、別のシートに出力するのか。複数の場所に同じ情報があると、一箇所だけ更新して整合性が崩れる事故も起きます。

私も何度もこれに苦しめられてきました。結局、スプレッドシートをハブにしたワークフローは、作るたびに個別対応が増え、メンテナンスコストが膨らんでいきます。

この状態で自動化やAIを導入しようとしても、うまくいきません。だからこそ、自動化やAI活用の前に「情報源の集約」が大前提になります。では、情報源の集約とは具体的にどうあるべきなのでしょうか。

SSOTの理想と現実

情報源の集約といえば、SSOT(Single Source of Truth)という考え方があります。「信頼できる唯一の情報源」という意味で、あるデータについて参照すべき場所を一つに定めるという原則です。

理想を言えば、SSOTはプロダクトのデータベース内に集約されているべきです。プロダクトが業務のすべてをカバーし、必要なデータはすべてそこにある。これが最も整合性を保ちやすい形です。

しかし現実はそう簡単ではありません。

業務は常に変化します。

新しい業務フローが生まれ、既存のフローも改善され続ける。

一方で、プロダクトの開発には色々な要因で時間がかかることがあります。

プロダクトは顧客に見えている面でもあります。データ構造の変更やスキーマの追加は、既存機能への影響を慎重に検討しなければなりません。場合によっては、業務上は必要だとわかっていても、影響範囲の大きさから変更を決断できないケースもあります。

このように業務の変化スピードとプロダクト開発のスピードには、どうしてもギャップが生まれます。

このギャップをどう埋めるか。私が選んだのは「プロダクト外に業務特化のデータベースを持つ」というアプローチでした。

Scoped SSOTという考え方

このアプローチを説明するにあたって、ちょうどいい言葉が見つからなかったのですが、今日風呂に入っていたら「Scoped SSOT」という言葉を思いつきました。造語です。

Scoped SSOTとは、「特定の業務スコープにおける唯一の情報源」という考え方です。

厳密に言えば、プロダクトDBの外に別のデータベースを持つ時点で、「Single」ではなくなります。情報源が複数存在すれば、矛盾が生じるリスクがある。これはSSOTの本質に反しています。

しかし、スコープを明確に区切ることで、この問題を緩和できます。ポイントは「プロダクトDBに存在しないデータ」と「プロダクトDBから同期するデータ」を分けて考えることです。

たとえば、プロダクトで管理していないクライアントごとの設定値やデフォルト値。「このクライアントへの請求書はPDFではなくエクセルで送る」「連絡はメールではなく電話優先」「月末は担当者が忙しいので連絡を避ける」といった情報です。プロダクトの機能としては存在しないが、業務を回すうえでは必要な情報。これらはそもそもプロダクトDBに存在しないので、業務特化DBに持っていても矛盾のしようがありません。業務特化DBがそのままSSOTになります。

一方で、プロダクトDBにも存在するデータを業務特化DBでも扱う場合は、同期の仕組みで整合性を担保する必要があります。

この棲み分けができると、なぜ作業者は迷わなくなるのか。

身近な例で考えてみます。会社全体の情報は社内ポータルにあるけれど、自分のチームの業務に必要な情報だけが一つのNotionページにまとまっている状態を想像してください。日常業務ではそのNotionだけ見ればいい。社内ポータルを毎回探し回る必要がない。

Scoped SSOTも同じです。「この業務に必要な情報は、ここに全部ある」という場所を作る。プロダクトDBから必要なデータは同期されているし、プロダクトにない業務固有の情報もここにある。だから作業者は一箇所だけ見ればいいし、自動化やAIも参照・更新すべき場所が一つに定まる。

では、このScoped SSOTを実現するために、どんなツールを選ぶべきでしょうか。

技術選定の観点

Scoped SSOTとして業務特化DBを構築するなら、どんなツールを選ぶべきか。私が重視しているポイントは3つあります。

1. スキーマ変更の容易性

試行錯誤ができることが重要です。カラムの追加や型の変更が、画面上の操作だけで完結するか。マイグレーションスクリプトを書かなくても済むか。この手軽さが、改善のスピードに直結します。

2. APIの充実度

自動化やAIワークフローと連携するには、APIでデータを読み書きできることが必須です。REST APIがあるか、認証は扱いやすいか、レートリミットは十分か。また、Webhookに対応していると、データ更新をトリガーにした処理も組みやすくなります。

3. UIの使いやすさ

エンジニアだけでなく、業務担当者がデータを参照・編集することが基本になります。スプレッドシートに近い操作感で扱えると、導入のハードルが下がります。

4. 扱えるデータタイプの豊富さ

業務において扱うデータのタイプは様々です。画像データや動画データから緯度経度の情報など、様々なデータのタイプにサポートしており、制約をシステム的につけれることは業務難易度を下げたりデータクオリティを担保する上で重要になります。

これらを踏まえて、選択肢になりうるツールをいくつか挙げます。

Airtable / Notionデータベース

スキーマ変更の容易性、API、UIのバランスが良い。連携サービスも豊富。ただし、SaaS系は行数に制限があることがデメリットです。数千〜数万行なら問題ありませんが、大規模なデータを扱う場合は注意が必要です。

NocoDB / Baserow

オープンソースでセルフホスティングが可能。データを自社管理したい場合や、行数制限を回避したい場合の選択肢。Airtableに似たUIを持ちながら、自由度が高い。

私はNocoDBを採用しました。

理由は、データ保存ポリシーの都合でセルフホスティングが必要だったことと、扱うデータ量が大きかったことです。現在100万行以上のデータを格納していますが、パフォーマンス的には許容できる範囲で運用できています。

基盤となるツールが決まれば、次は実際にどう活用するかです。

自動化・AIワークフローへの応用

Scoped SSOTとして基盤を整えていたことで、自動化やAIワークフローへの応用がスムーズになりました。

自動化やAIに仕事を任せるとき、必要なのは大きく3つです。

  1. 必要な情報を渡せること
  2. 結果を書き戻せること
  3. 試行錯誤できること

まず、情報を渡す部分。AIに何かを判断させたり生成させたりするには、必要なコンテキストを渡す必要があります。情報が一箇所に集約されていれば、「このテーブルのこのレコードを渡せばいい」とシンプルになります。あちこちから情報をかき集める必要がない。

次に、結果を書き戻す部分。AIの出力を業務に反映させるには、どこかに保存する必要があります。書き戻す先が明確であれば、ワークフローの設計もシンプルになります。

そして、試行錯誤の部分。ここが意外と重要です。

AIに最適なデータ構造は、一回で正解を導き出すことは難しいです。どういう形式で情報を渡せば精度が上がるのか、どういうフィールドを追加すれば判断しやすくなるのか。やってみないとわからないことが多い。

プロダクトDBでこの試行錯誤をするのは難しい。スキーマ変更の影響が大きいし、そもそも気軽に変更できない。しかし、業務特化DBであればスキーマ変更は容易です。「この項目を追加してみよう」「この形式に変えてみよう」といった試行錯誤がすぐにできる。

自動化やAI活用においてはこの柔軟性が大きな武器になります。

ただし、当然ながらこのアプローチには見過ごせないリスクもあります。

メリットとリスク

ここまでScoped SSOTの考え方と導入について書いてきましたが、銀の弾丸ではありません。メリットとリスクの両方を理解したうえで判断すべきです。

メリット

柔軟性とスピード

プロダクトの開発サイクルに縛られず、業務の変化に素早く対応できます。スキーマ変更も気軽にできるので、試行錯誤しながら最適な形を探れます。

自動化・AI活用の基盤

情報が集約されていることで、自動化やAIワークフローの構築がシンプルになります。どこから読んで、どこに書くかが明確になる。

プロダクトへの知見還元

業務特化DBで試行錯誤した結果、「この情報はプロダクトで管理すべきだ」という知見がたまっていきます。業務が洗練されてから、その構造をプロダクトに還元できる。いきなりプロダクトに組み込むよりも、失敗のリスクが低くなります。

リスク

捨てられなくなるリスク

「数年で捨てる覚悟」と言っても、実際には難しいことが多い。ワークフローが依存し始め、「このDBがないと業務が回らない」状態になりがちです。気づけば、本来プロダクトに還元すべきものが、いつまでも外に残り続ける。

これを防ぐには、導入時に「どうなったらプロダクトに移すか」「どうなったら廃止するか」というトリガーを決めておくことが重要です。

同期コスト

プロダクトDBに存在するデータを業務特化DBでも扱う場合、同期の仕組みが必要になります。このコストは「簡単に同期できる」と軽く見積もると痛い目を見ます。

まず、継続的なメンテナンスが発生します。プロダクトのスキーマは開発とともに変化します。カラムの追加、型の変更、テーブル構造の見直し。これらの変更を検知し、業務特化DB側の構造やマッピングを追従させ続けなければなりません。

また、データの整合性を担保するためのテストも厚くする必要があります。同期処理が正しく動いているか、データの欠損や重複が起きていないか、型変換でおかしなことになっていないか。本番運用を続ける限り、このテストとモニタリングは必要です。

データ連携パターンの選択

同期の実装方法には大きく2つのパターンがあります。

ETL連携(DB to DB)

プロダクトDBから直接データを抽出し、変換して業務特化DBにロードする方式です。速度面や安定性では圧倒的に優位です。大量データの同期も効率的に行えます。

ただし、AirtableやNocoDBのようなツールを業務特化DBとして使う場合、純粋なDBとは構造が異なります。リレーションの扱い方や、特殊なフィールドタイプなど、単純なSQLでは対応できない部分があり、ETLパイプラインの構築が複雑になることがあります。

API連携

プロダクトが提供するAPIを経由してデータを読み書きする方式です。ETLに比べると速度面では劣りますが、メリットもあります。

APIを経由することで、プロダクト側で定義されたモデルベースのバリデーションを通せます。つまり、不正なデータを業務特化DB側から書き戻してしまうリスクを軽減できる。プロダクトDBに直接書き込むより安全です。

どちらを選ぶかは、データ量、更新頻度、整合性の要件によって変わります。場合によっては両方を組み合わせることもあります。

構造の柔軟性 vs 変換の柔軟性

業務特化DBの構造を柔軟にするアプローチの他に、「正規化されたきれいなSSOTを持ち、AIへの変換は軽量な変換レイヤーで吸収する」という考え方もあります。構造を変えるのではなく、変換を変える。

どちらが正解かは状況次第です。ただ、業務特化DBの構造を柔軟にしすぎると、それ自体がカオスになるリスクもある。この選択肢は頭に入れておくべきです。

まとめ

本記事では、自動化やAIワークフローの基盤として「Scoped SSOT」という考え方を紹介しました。

業務ではエクセルやスプレッドシートが乱立し、情報が散らばりがちです。この状態では自動化もAI活用もうまくいかない。だから情報源の集約が大前提になります。

理想はプロダクトDBにすべてを集約することですが、現実には業務変化のスピードとプロダクト開発のスピードにギャップがある。さらに、プロダクトは顧客に影響する面でもあり、気軽に変更できない。

そこで、プロダクト外に業務特化DBを持つという選択肢が出てきます。スコープを区切り、「この業務においてはここだけ見ればいい」という状態を作る。これがScoped SSOTです。

この基盤があることで、自動化ワークフローはシンプルになり、AIへの応用もスムーズになります。情報の取り出しと書き戻しが一箇所で完結し、試行錯誤もしやすい。

ただし、銀の弾丸ではありません。捨てられなくなるリスク、同期コスト、構造をどこまで柔軟にするかという判断。これらを理解したうえで導入すべきです。

正直なところ、私もまだ試行錯誤の途中です。AIワークフローで大きな成果が出ているわけではありません。ただ、基盤を整えておいたことで、少なくとも「どこから手をつければいいかわからない」という状態にはなっていません。

もし同じような課題を抱えている方がいれば、Scoped SSOTという考え方が何かのヒントになれば幸いです。