Upgrade to Pro — share decks privately, control downloads, hide ads and more …

【Gen-AX】20260530開催_JJUG CCC 2026 Spring

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

【Gen-AX】20260530開催_JJUG CCC 2026 Spring

2026.05.30に開催された、JJUG CCC 2026 SpringのGen-AX株式会社の登壇資料です。

Avatar for Gen-AX株式会社

Gen-AX株式会社

June 05, 2026

More Decks by Gen-AX株式会社

Other Decks in Technology

Transcript

  1. J J U G C C C 2 0 2

    6 S P R I N G Realtime 音声イベント 処理の最前線 AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す 松田 一樹 / Gen-AX 2026-05-30
  2. 本日お話しするのは、Gen-AX 株式会社が開発する、自律型AIオペレーター「X-Ghost(クロス ゴースト) 」の、Re-design プロジェクトに関する内容です。 このサーバは、全く性質が違う4方向からのイベントをリアルタイムに処理し、会話状態を更新し 続けながら、AI が人間と会話するためのものです。 この複雑なサーバを、JVM/Kotlin 上で

    lock free に再実装した事例を紹介させて頂きます。 この形にたどり着くまでに、3 回の PoC を経て、問題の認識を Backend の 並行 Programming から聴覚 UI/UX 問題としてリフレームする必要がありました。 サービスインから1年未満かつ変化の激しい領域ではありますが、lock free 以外にも構造由来の コストを減らすための設計と、実装の工夫をお話しします。 スポンサーセッションではありますが、Engineering に振り切った内容になっています。 どうぞ最後までお付き合頂き、音声 AI プロダクトの最前線をお楽しみください。 Abstract - セッション概要 Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30
  3. > Gen-AX & X-Ghost とは > 我々が解く必要があった問題 > 3 回の

    Try を経て、Backend 問題 → UI/UX 問題へのリフレーム > 新しい Design — 2 つの柱 - Multithreading をやめて Race Condition を構造的に排除 - TLA+ で状態遷移の正しさを検証 > Closing - Future Work & Open Challenges ── 我々がまだ解けていない問題 Agenda Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 1
  4. Gen-AX(ジェナックス)は、生成AI・自律型AIを活用した SaaS 事業を展 開する、ソフトバンクグループのスタートアップです。 主力プロダクトは、企業のコールセンター向け AI 電話応対サービス X-Ghost(クロスゴースト) 。 本日は、X-Ghost

    の中核サーバを Kotlin で 再実装・ReDesign している話を紹介させていただきます。 スポンサーセッションですが、Engineering に振り切った内容です。 Gen-AX ── ソフトバンクグループの AI スタートアップ Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 2
  5. X-Ghost 音声 stream (双方向, 20ms) WebSocket append / commit /

    cancel HTTP / function call 結果 JSON (数百ms〜数秒後) 非同期 event 1 本の通話に対して、電話・Realtime AI・業務 API・Control Plane の 4 方向から event を捌 く。 本日お話しするのは、この Orchestrator の Re-Design です。 Orchestrator ── 4 つの event stream の交差点 Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 4
  6. The Problem ── 普通の Web API と何が違う のか Realtime 音声イベント処理の最前線

    — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 5
  7. 実際の通話で常に起きること: 人「明日の飛行機、東京発大阪行きの午前の便はありますか?」 > AI「東京発大阪行き、明日の午前中の便ですね、少々おm」 > 人「あ、やっぱり午後の便も調べてほしい」 - 人間の発話開始を検知 > AI「──おまちください」

    - AI の音声出力を止める - 既に流した分だけ会話履歴に残す - ユーザーの発話が終わる - それを踏まえて次の AI 応答を生成。 > AI「承知しました、明日の便全体で空きをお調べします。少々お待ち下さい」 What's 自然な対話? — AI が話している間に人間が割り込む Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 7
  8. 4 つの独⽴した EventSource > 4 つの EventSource は互いの完了を待たない — Orchestrator

    は交差点で「採用 / 破棄 / 順 序」を決め続ける > cancel しても audio は届く / ack なしで送る / API は数秒後に返る — 時間差そのものを扱う 仕組みが要る 何故 Realtime 音声 AI の割り込みは難しいか? Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 8
  9. Incorrect: REST mental model Correct: WebSocket reality request1 response1 request2

    response2 request3 response3 neat pairs — request/response が対応する input_audio_buffer.append response.output_audio.delta response.cancel delta (cancel 前に dispatch 済) response.done (cancelled) input_audio_buffer.append response.output_audio.delta (new) 独⽴した event stream — 対応関係がない 「cancel した = もう来ない」ではない。 > response.cancel 後も、dispatch 済み audio chunk は届く > stale な responseId の event は 明示的に破棄 する必要がある 非同期 Operation Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 9
  10. Pipelining ack を待たずに 3 event を流す Strict Ordering ack を確認してから次へ進む

    time event 1 event 2 event 3 result 1 result 2 result 3 no ack wait 3 events are in flight before results return time event 1 ack 1 round 1 wait ack event 2 ack 2 round 2 3rd round trip continues outside this Realtime window event 3 > Pipeline 型: ack を待たずに複数 event を流し、結果も event stream として返る > Strict Ordering 型: ack を確認してから次の event を送る。往復数ぶん時間を消費する Pipeline v.s. Strict Ordering Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 10
  11. ReDesign 前の PR のうち、Bug Fix / Refactor を抽出し、上位の原因を T1-T3 で分類。

    ラベル 具体例 T1: Type Safety 動的型 / 不変条件未表現 型の取り違え、フィールド有無判定の typo T2: State Transition a) 並行制御 / Race b) 複雑な状態遷移 a) 読み取り → 処理の間に書き込みが発生 b) 状態が想定外の状態になる T3: Runtime Safety 内部 RPC retry / fallback 設計上不要な Retry の追加コード T1・T3 は型付き言語で書き直し、リアーキテクチャリングすれば消える。T2 は? Bug Fix / Refactor の上位原因 Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 12
  12. 実例: 負荷試験で発覚 ── タイマー Thread と外部 API 呼び出し Thread の

    race タイマー の流れ T = 40.675s タイマー発⽕ response.create 送信 created 受信 → state 反映 T = 43.077s ← この間 ~2.4 秒、response.create 送信済みだが応答未着 ── state にはまだ反映されていない → 外部 API 呼び出し Thread API 呼び出し完了 + state 読む 「id 無い → 競合なし」と誤判断 ⾃分も response.create 送信 T = 40.682–40.683s 結果: response が 2 つ衝突 → ID 不⼀致エラー → AI が無応答に → セッション切電 2 つの Thread が一つの state を触ると、タイミング次第でこうなる。 送信中は未確定状態。読まれないためには Lock / Mutex が必要。 T2 の実例 ── 2 つの Thread が一つの state を触る Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 13
  13. PoC (Python) 2025 前半 V1 (Python) 2025 後半 V2 (

    進⾏中) 2026 〜 Python Kotlin ( 移⾏済) ★ 新規 / 書換 > PoC 時代は Orchestrator と Context Eng. Tool のみ。運用コンソールは無い > 製品化のタイミングで Ops Console + 認証基盤を Kotlin で新規開発。 型付き言語の導入 > V2 で中心部分 ── Orchestrator の Re-Design を実施 なぜ今 Re-Design なのか ── 段階的な書き換え戦略 Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 14
  14. # 何を試したか 残った問題 #1 Go 再実装 Go (goroutine) で書き直したら? 勢いでは無理

    #2 Kotlin Kotlin / Channel コントロールプレーンの副作用 #3 Python 型 + 責務分離 mypy strict + リファクタリング 負荷試験で race 残存 社内の声 「綺麗に解けそうにならなかったので諦めました」 「並列処理が増えすぎると脳みそに収まらないので、デフォルト直列のほうが親切」 なぜ「収まらない」のか? — 他スレッドで変数が変わったら? → 全組み合わせを制御? → Lock → Deadlock / Lock 忘れ → 制御自体が無理な次元 → どう Multithreading を強化するかが中心課題 3 の Try と学び Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 16
  15. しかし、最終的なデザインはこうなった - セッションごとにイベントキュー + 1 本の処理ループ - 状態更新は処理ループのみ - 送信は

    destination ごとの single-writer sender に委譲 x_ghost/apps/orchestrator/docs/SESSION_DESIGN.md 「UI 制御っぽい問題って、結局『状態更新は single-thread に寄せる』で解くことが多いので。 」 UI 制御の問題だったの? New Design ── Multithreading をやめる Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 17
  16. Backend と捉えると > 通話 = 非同期音声ストリーム > 4 方向 event

    をリアルタイムに捌く = 複数 client + control plane > state = 共有データ > 並列 + lock / actor? を探しに行く > 20ms ごとに届く音声チャンク UI/UX と捉えると > 通話 = 聴覚 UI > ユーザー発話 / AI 発話 / API 結果 ~ Mobile UI: touch / gesture / fetch > state full = 当然 > Single Thread で更新(iOS/Android) > 60fps (17ms) で画面を更新 「UI 制御っぽい問題って、結局『状態更新は single-thread に寄せる』で解くことが多いので」 Multithreading を許さない、というのが、世界の UI Engineer と Platform (Apple / Google) が、10 年以上にわたって磨いてきた解だった。 開発してるのは Multithreaded Backend ではなく、聴覚 UI/UX Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 18
  17. X-Ghost ⾳声 stream ( 双⽅向, 20ms) WebSocket append / commit

    / cancel HTTP / function call 結果 JSON ( 数百ms 〜数秒後) ⾮同期 event 再掲:X-Ghost = 我々が Engineering している世界 Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 19
  18. Mobile App Action / render (gesture ↔ State) Action: platform

    event Effect: request Action: result (async / delayed) Flow / save Mobile UI (iOS / Android) が10年間解いてきた問題空間 Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 20
  19. New Design ── Lock free の割り込み Realtime 音声イベント処理の最前線 — AI

    が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 21
  20. // event loop 内で呼ばれる。並列処理を考えなくてよい。 private suspend fun handleBargeIn( output: AudioOutput.AiRealtime,

    ) { state.aiResponse.markBargedIn(output.responseId) ... mediaSender.enqueue(MediaCommand.StopPlayback) openAiOutboundAdapter.enqueue(ResponseCancel()) functionCallCoordinator.cancelPending(output.responseId) } > lock は 1 つもない。mark / enqueue だけ。 > 順序が大事な処理を、順序通りに書く だけで読める handleAiBargeIn ── lock が 1 つもない Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 22
  21. 前提:AI の音声は非同期に届き続ける Main Thread // ③ barge-in 検知 → 止めたい

    state.aiResponse.markBargedIn(...) mediaBuffer.clear() Audio Receiver Thread // ① AI 音声 chunk を受信 if (state.isBargedIn) { return } // ② ↑ まだ false … 通過 // ←← ③ この間に左が clear() mediaBuffer.enqueue(audioChunk) // ④ クリアした後に積まれる 結果: ユーザーが割り込んだのに、AI の音声が積まれる。 「再現しないバグ」の正体。 普通こう書くとどうなるか? Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 23
  22. 電話 Control Plane AI 応答 対応 (Thread ごと) Thread A

    Thread B Thread C L L L L L L L L ! ! ! ! ! state 不整合 AI が黙る ⼆重応答 Thread ごとに独⽴して state を更新 → Lock が必要 → それでも race state state state state state Lock で守ろうとした。それでも race が残った。 Before ── V1: 複数 loop が同時に state を更新する Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 24
  23. 電話 Control Plane AI 応答 Channel 直列実⾏ (Single-Writer) #1 #2

    #3 #4 #5 #6 #7 #8 #9 #10 #11 #12 #13 #14 #15 #16 #17 #18 #19 #20 受け付け順 → → 完結してから次へ Lock 不要 受け付け順に 1 つずつ → Lock 不要 → 同じ⼊⼒ → 同じ結果 Lock が要らない構造にした。→ race が構造的に起きない。 After ── ① 小分け ② 直列化 Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 25
  24. V2: 時間のかかる処理は「依頼 → 別の担当が実⾏ → 完了報告」に分割される 受付担当 (event loop) #1

    #2 #3 依頼 #4 #5 #6 #7 #8 #9 結果反映 #10 #11 #12 依頼 (kick-off) 受付担当は #3 を atomic に 処理して即「次」へ 完了報告 結果は新しい event として queue に戻る ( 受付順を守る) 実務担当 ( 時間がかかる仕事) 実⾏中… ( お客様情報の照会 / 外部 API 呼び出し / DB 書き込み 等) 受付担当は⽌まらない ── 実務が⾛っている間も #4 〜#8 を atomic に処理し続ける → V1 の race ( 実⾏中に他が state を壊す) は構造的に起きない / 同期 I/O で event loop が詰まらない 時間 → > state を書けるのは event loop だけ > dispatch 先は結果を返すだけ > 受領可否は最新 state で判断。古ければ捨てる 時間がかかる処理は delegate する Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 26
  25. sealed interface AudioOutput { data object None : AudioOutput data

    class AiRealtime(...) : AudioOutput data class System(...) : AudioOutput data class Other(...) : AudioOutput } private suspend fun interruptCurrentAudioOutput(now: Instant) { when (val output = state.audio.output) { is AudioOutput.None -> {} is AudioOutput.AiRealtime -> handleAiBargeIn(output, now) is AudioOutput.System -> stopSystemAudio() is AudioOutput.Other -> handleOtherBargeIn(output) } } sealed なので、variant 追加時に対応漏れの when が コンパイルエラー になる。 sealed types ── 型で状態を表す Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 28
  26. 型で書けるのは「どんな状態が存在するか」まで。 『状態の遷移列』は型には書けない。 例) > 『同時に喋らない』はその時の状態なので型で表現できる。 (こともある) > 割り込みがあっても、割り込みが終わったら AI が喋る、というのは型では表現できない。

    比較 Type Safety State Transition Correctness 守るもの その時、状態が存在できる・できない いつかはその状態になる・決してならない どうやって保証? 型とコンパイラ ? 第 2 の柱 ── 状態『遷移』は正しいか? Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 29
  27. 1. 重い処理をしている場合は、Loading Dialog を出そう。 2. 処理が完了したら、Loading Dialog を消して、結果を表示しよう。 3. 処理が失敗したら、Error

    Dialog を出そう。 -> 失敗しても(Error Dialog の裏に)Loading が出っぱなし。アプリを Kill するしかない。 > Web は再読み込みしてくれる(かも) 、 > Mobile はアプリ再起動してくれる(かも) 、 > でも電話はかけ直すしかない。 だから、電話の UI/UX では、状態遷移の正しさが特に重要。 検証・保証したいこと『 (状態が進めば)いつかは必ず Loading Dialog が消える』 状態『遷移』とは何を言っている? UI の場合 Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 30
  28. 論理を扱う中でも、時相論理(Temporal Logic)が 「いつかは」 を扱っている > 普段の論理 A → B は、

    「A ならば B」 > 時相論理 A →◇ B は、 「A ならば、いつか B」 証明は難しいが、限られた範囲内で検証を行うツールがある(TLA+) 。 状態を順次リストアップして、 『起こりえない』and/or『この手順で起きる(反例 trace) 』を出す。 ref: AWS が S3 の状態遷移を証明。 『いつかは』を証明する Engineering − TLA+ Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 31
  29. UserVoiceDetected ResponseCancel response.output_audio.d elta Media playback S0 AI が発話中 S1

    人間が割り込む S2 cancel を送る S3 遅延 audio delta 到着 V1 は stale 判定できない VIOLATION User と AI が同時に聞こえる 実装を元に LLM に翻訳させて TLA+ を生成 そうしたら、race の正体が 1 枚の trace で出た。 X-Ghost の状態探索例 scan 境界 探索状態 結果 割り込み / response depth 15 45M states violation 0 Function Calls 別 scan 240,481 states violation 0 実例:再現しないバグが、理解可能な反例 trace としてでてきた Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 32
  30. 「Kotlin に変えれば品質が自動で上がる」 「型が全てを救う」── そんなことはない 設計をどう拡張するか Event Base の考え方は慣れない。 (後から悩むよりいい が)

    TLA+ モデル維持コスト 何か調べたいときに、その部分の Model を毎回 LLM に 生成して貰っている suspending function で書いていいのか? await = 即死の世界では、逆に non suspending function が良い。await = 待ってしまう。 Retry を強制できないか? BlockHound と同じ発想で、Retry / Observability が CallStack に入っていない RPC を一律禁止する。 型で守る but 実験的な拡張 『ほとんど動かなくていいので、API を差し替えてデモ したいです』みたいなのがたまにある。 状態遷移の型保証 状態遷移のルールも型で保証する書き方が一部ではあ る。状態数が多くそのままでは現実的でないが、状態数 を整理すれば入れる余地があるかも。 Future Work & Open Question Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 34
  31. 我々は AI Backend を開発していると思っていました。 でも、割り込みを真剣に考えたら 音声 UI/UX の問題だった。 解法が広がった。 Kotlin

    で Lock free に組み直す Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 36
  32. 複雑性には、 「本質的な複雑性」と「偶有的な複雑性」がある。 (Brooks, 1987; 人月の神話) > 本質的な複雑性は、問題の性質から来るもので、避けられない。 - 音声 UI/UX

    の複雑性は、音声という物理現象あるいはそもそもコミュニケーションの曖昧さやリア ルタイム性などから来るもので、避けられない。 - かじりついて、解く必要があるもの。 > 偶有的な複雑性は、解決策の選択や実装の方法から来るもので、減らすことができる。 - マルチスレッドプログラミングの複雑性は、解決策の選択や実装の方法から来るもので、減らすこと ができる。 - こっちは、設計判断で減らせるもの。 - そもそも Single Thread で書く、状態遷移を検証する、などの設計判断で減らせるもの。 リアルタイム処理なら、マルチスレッドでしょ、 というのは、解決策に引っ張られた見方でした。 複雑性は何から来るのか? Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 37
  33. 我々の Design の核になっている道具は、以前からあったものです。 > Coroutines ─ Conway, 1963 > CSP

    / Channel ─ Hoare, 1978 > Algebraic Types (Sealed Class) ─ Hope / ML, 1970s > TLA+ ─ Lamport, 1990s > Mobile UI, Unidirected Data Flow ─ 2010s 最先端の AI を社会実装するための道具は目の前に転がっている Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 38
  34. > 本日はお時間をいただきありがとうございました。 > 本発表のベースとなるアイデアを生み出し、発表のフィードバックを提供してくれた同僚たち に感謝します。 - 25% の Issue と戦いながらも

    main ブランチを未来に向かって押し上げ、3 つの PoC を回し、 TLA+ で設計を証明した Gen-AX チーム全員に。 ありがとうございました
  35. Q: Single-Writer にしても、event loop 上で blocking I/O を書いてしまったら全停止ではないか? A: BlockHound

    を導入済みになります > BlockHound は、event loop 上で blocking I/O を書いてしまうのを一律禁止するツールです。 > もし書いてしまったら、開発環境では例外となる。 - (Android 等 Mobile OS のデフォルトの挙動に相当) FAQ: Event Loop を間違って Block してしまう問題は? Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 39
  36. Q: 形式検証ツールは TLA+ 以外にもある。なぜ TLA+ を選んだのか? A: 知っていたのが TLA+ でした。

    > チーム内に偶然 TLA+ に関する書籍( 『実践TLA+』 )を読んだ事があるメンバーがいて、TLA+ を知っていたのが選定の理由でした。 - 後から調べると、LLM (Claude) が一番正確に書けるのは TLA+ とのこと > AWS の事例 (S3, DynamoDB) があり、エンジニアリング文脈での実績が豊富です FAQ: TLA+ は何故? 他の選択肢は? Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 40
  37. Q: 4 方向のイベントを「途中で割り込めない最小単位」にするには? A: I/O を挟む必要があればそこで分割となります、そうでなければ基本的には別けずに最小単位 として扱って大丈夫です。 > 音声チャンク: 最初から

    chunk になっている > OpenAI Realtime API: WebSocket メッセージ単位。1 メッセージ = 1 イベント > Function Call / 外部 API: 「I/O をリクエストする」ところまでが 1 イベント。レスポンスは別 イベントとして queue に戻る > Control Plane: 同様 原則: I/O の前後を 1 つのイベントにすると await が入るので、await したくなったばあい、そこ でイベントを分割するのが自然なことが多いです。 FAQ: どうやって細かい Event に分割するのか? Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 41
  38. Q: Event Loop / Single-Writer パターンは何で実装したか? フレームワークやライブラリは? A: Kotlin Coroutines

    の launch + Channel で普通に書きました。 val channel = Channel<Entry>() // sealed interface Entry. 色々なイベントがこれに入る launch { for (event in channel) { when (event) { ... } // state 更新はここだけ } } > Actor 的なことをやるには launch + Channel で十分。 - Kotlin には actor coroutine builder があったが @ObsoleteCoroutinesApi 。 > Akka 等の Actor フレームワークも検討したが、標準 primitives で足りており、外部依存を増 やすメリットを見出しにくかった。 FAQ: 実装方法は? ライブラリを使った? Realtime 音声イベント処理の最前線 — AI が話している間に人間が割り込むサーバを Kotlin で Lock free に組み直す @ JJUG CCC 2026 Spring, 2026-05-30 42
  39. Gen-AX は、AI が電話に出る世界を一緒に作るエンジニアを探しています。 > Software Engineer ── AI 電話応対の基盤を設計・実装する -

    Kotlin / Spring Boot ── Orchestrator の設計・実装 - TLA+ / 形式検証 ── 状態遷移の正しさを機械に守らせる - Realtime Audio / WebSocket ── 4 方向 event の交差点を扱う > Infrastructure Engineer ── マルチテナント SaaS ^ 基幹システム接続有 > Forward Deployed Engineer ── 顧客の現場で、AI 電話応対の未来を作る > AI / LLM Engineer ── 最先端の AI を、企業の電話応対に社会実装する > Telephony / VoIP / SIP Engineer ── 電話の UI/UX を、AI 時代に再発明する etc... Developer / SRE / QA など、幅広く募集しています。 今日の話に興味を持った方、ぜひお声がけください。 by Gen-AX Engineers 一同 (コーヒースポンサーやってます!) We Are Hiring