Oathra

OATHRA / DEVELOPER LAB

発言を変えて、
判定の境界を知る。

公開済みの証拠ラボと、保存済みのArena交渉記録です。下の発言を編集して判定を確かめられます。このページの操作で実電話は発信されません。

v0.1.19の導入手順 · コピーボタンはGitHub Release版を起動します。npm版は0.1.0です。

この体験は、この製品の証拠エンジンそのものです。AIは「ご予約承りました」と言い切っていますが、店が確定していないので確定だけが未確認のまま残ります。返事を差し替えると判定が変わります。入力はブラウザ内に留まり、電話は発信されません。

判定が変わるところを、26秒で見る。

上のラボを実際に操作した画面録画です。店の返事を差し替えるたびに、同じ判定コードが走り直します。カメラの寄りとカーソルと字幕は編集で足したもので、画面と判定は編集していません。

26秒 · 画面録画 · 音声なし

画面が小さいと録画内の文字は読めません。再生後、全画面にすると判定の項目まで読めます。

0 / 10,000店員役の変異 1 万通り(シミュレーション)での誤完了
約0.4秒3件目の実電話で観測した最初の返答(平均・p95ではありません)
1コマンドGitHub Releaseのコマンドで AI 同士の通話まで
回線は Twilio のみ検証Plivo・SIP は実装済みだが実回線 (PSTN) では未検証

いまの音声AIに、判定だけを加える。

電話会社やモデルはそのまま。v0.1.19の oathra verify で保存済みの文字起こしをローカル検査し、日時・人数・金額・確定の根拠をJSONで取り出せます。ActionProofで会話・確認・システム・結果の証拠レベルも統一できます。仮押さえ・未確定・承認待ちを確定と扱いません。APIキーは不要です。

oathra/evidence のTypeScript SDKとLiveKit接続例も公開しています。

インストールせずにログを検証 →

自分の文字起こしで使う → · 更新を追うためにGitHubでStar

対応済みの発言規則に基づく判定です。店舗の予約台帳は確認しません。LiveKit接続例は型検査済み、実通話では未検証です。

25秒で見る:交渉ログから検証結果へ

英語画面の実操作を収録。公開済みのGPT-4o-mini/ホテルシミュレーター記録を検証しています。実電話の録音ではありません。 自分でも試す →

追加で聞くときも、相手のペースを守る。

必要な予約情報が確定した後に目的を伝えて同意を一度だけ確認し、同意後は契約に書いた質問を1回に1つだけ尋ねます。拒否・保留・曖昧な返答ならその場で終了し、明示回答だけを intake.json と summary.md に残します。

契約の書き方と保存形式を見る →

48秒で見る:同意付きの追加聞き取り

実際の Arena シミュレーターで、予約確定 → 同意 → 2項目の明示回答 → intake.json を収録。APIキー不要、実電話ではありません。シナリオを見る →

成功だけでなく、取り消しも見せる。

30秒 · 実エンジンの操作録画 · 字幕付き・音声なし。ブラウザ画面を4fpsで取得し30fpsの動画に編集。実電話の録音ではありません。

自分の言葉で判定を試す →

用途と判定をDiscussion #14で共有 →

追加聞き取りは startAfter・dependsOn・choices でシーンに合わせて分岐できます。拒否・保留・曖昧な返答・選択肢に一致しない返答は保存せず終了します。

実モデルによる交渉の記録

GPT-4o mini がシミュレーター内の仮想ホテル(定価 23,500 円)と交渉した記録。実店舗への発信ではありません。保存されたイベントを 3 倍速で描き直しています。録画ではありません。

無理難題ホテル · openai:gpt-4o-mini再生
00:00 / 01:26

3つのAIの対戦を、音声付きの録画で見る →

作った理由

AIに電話をさせる仕組みは、作ろうと思えば一晩で動きます。厄介なのはその先で、席が取れていないのに「予約できました」と言い切る。留守番電話に向かって予約を依頼し続ける。値段が予算を超えているのに、話の流れで受けてしまう。どれも実際に起きました。

そこで、完了の判定をモデルから取り上げてコードに移しました。日時、人数、金額、そして「確定したか」は、相手の発言から取り出した証拠が揃ったときだけ埋まります。AI 側がいくら「確定しました」と言っても、それは記録されるだけで証拠にはなりません。

同じランタイムをシミュレータでも本物の電話でも動かせるようにしたので、まずはブラウザで AI 同士に交渉させて遊び、納得したら電話会社を繋いでください。

Arena の画面。GPT-4o mini がホテルと交渉中。ミッションの金額は未確定のまま 21,100 と表示
交渉の途中。ホテルが 21,100 円を出した直後で、「金額 ≤ 20,000」はまだ埋まらない。証拠は相手の発話ごとに右側へ積まれていく。
Arena の画面。ホテルの「ご予約承りました」で確定に✓が付き、証拠に confirmed = はい(相手)が並ぶ
ホテルが「1泊19,900円でご予約承りました」と言った瞬間。「確定」に✓が付き、証拠の先頭に confirmed = はい(相手)が入る。AI 側の発言では、この行は絶対に埋まらない。

まず遊ぶ。AI同士か、自分が店員になるか。

シナリオは10本。19時が満席のレストラン(日本語版と英語版、同意付きの追加聞き取り版)、底値を隠しているホテル、まとめ買いの値引き交渉、シリアル番号の復唱、全時間帯が満席で「取れませんでした」と言うのが唯一の正解になる罠、そして「たぶん行ける!」が約束にならない友達との会話が3本。モデル同士を同じ条件で戦わせて、カードにして共有できます。

$ npx oathra battle impossible-hotel \
    --agent scripted --agent openai --agent gemini \
    --png card.png --json run.json

Impossible Hotel
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
scripted                    ████████████████████    6540
openai:gpt-4o-mini          ███████████████████▋    6444
gemini:gemini-flash-latest  ███████████████████▌    6410

                            SUCCESS  TIME   COST  SCORE
scripted                    ✓         69s  $0.00   95.4
openai:gpt-4o-mini          ✓         95s  $0.00   89.5
gemini:gemini-flash-latest  ✓         79s  $0.00   90.1

False completions: 0

上の動画の元になった実行です。定価23,500円のホテルを、組み込みAI・GPT-4o mini・Gemini Flash がそれぞれ2万円以下まで交渉し、成立価格は 19,900 / 19,900 / 20,000 円。得点の差は価格と所要時間の差です。ホテル側の「ご予約承りました」が出た通話だけが成立と数えられます。勝ち負けより、その一行のほうが大事だと思っています。

この実行で、最初は誤完了が1件出ました。ホテルが値段を言い直しただけの発話を「はい」と数えていたからです。証拠エンジンを直し、同じ3通話を流し直して0にしました。そういう見つけ方をするための対戦機能です。

63秒 · 画面録画 · 音声あり

3つのAIが同時に電話した記録(63秒・音声あり)。3つのウィンドウは Arena の再生画面そのまま、声は記録された発話を読み上げたもの。

同じ仕組みで、本物の電話。電話会社とモデルは別々に選ぶ。

Twilio はメディアストリーム直結の最短経路をそのまま使います。Plivo や手持ちの SIP 回線は SIP ゲートウェイ(初期実装は LiveKit、Cloud でもセルフホストでも可)を経由します。音声モデルは別軸で、テスト通話で一番自然だった GPT-Live を既定にし、Deepgram + LLM + TTS のパイプラインも残しています。

$ pnpm oathra setup phone
# cloneしている場合。公開版は上のv0.1.19コマンドを使用

音声エンジンを選択
❯ GPT-Live        推奨 · 会話が最も自然
  Gemini Live     gemini-3.8-live · 全二重
  Pipeline        Deepgram + 任意のLLM + OpenAI TTS

電話会社を選択
❯ Twilio          直結 · 実通話で検証済み
  Plivo           SIP経由
  Custom SIP

Twilio を設定中
  ✓ 認証情報を確認             account · Full
  ✓ 音声発信できる番号を検出    +1 947 ···
  ✓ 日本向け発信の許可を確認
  ✓ Media Streams              通話ごとに設定
✓ Twilio の準備ができました。

$ npx oathra phone doctor --to +81…
Carrier        ✓ 認証 · 有効 · 発信元番号 · 日本向け発信 OK
Media          · 実通話が必要 — oathra phone test
Voice Engine   ✓ GPT-Live (gpt-live-1)
Latency        Oathra → api.twilio.com   244 ms
Cost           日本の携帯 · twilio · $0.185/分
READY ✓
  • 自動化できない所は、案内する発信元番号の本人確認や海外発信の許可など、人の操作が必要な手順はリンク付きの一手順として表示し、終わるまで待ちます。「ワンクリック」と言い張るより、正直なほうが使いやすいと考えました。
  • 通話料を払わずにテストするoathra phone test は Local(電話料0円・API使用)→ Gateway(¥0)→ PSTN(有料)の3段階。開発中のバグ1つごとに1分¥28を払わずに済みます。
  • どの層が壊れたかを doctor が言う電話会社 · SIPゲートウェイ · 音声 · 音声モデル · 遅延 · 料金を段ごとに確認し、失敗した項目には直し方を添えます。

実際に電話してみた記録

1回目Deepgram + GPT-4o-mini + TTS の三段構成。会話は成立したが最初の返答まで 11.8秒。「聞こえますか?」と何度も聞き返された。店員役が「大丈夫です」としか言わなかったので、結果は正しく INCOMPLETE。AIは「確定です」と言ったが、証拠にはならなかった。
2回目TTS のストリーミング化で応答は 2.2秒に。ただし最初の2分間は留守番電話に予約を頼み続けていた。雑音を割り込みと誤認して13回も話を止めた。留守電検出と、相槌を割り込みにしない判定を追加。
3回目GPT-Live(全二重)に切り替え。「もしもし」から返答まで 約0.4秒。6分25秒、112ターン、エラーなしで雑談が成立。「バイバイ」で切れない問題が残ったので、終話ツールと無音25秒の安全装置を入れた。

通話料は Twilio で日本の携帯宛 ¥28.78/分、GPT-Live はセッション $0.05/分。この記録の総額は数百円です。

「予約できました」は、証拠ではない。

返ってくるのは VerifiedResult です。各項目は相手側の発話(実電話では音声区間)に紐づき、完了はコードが判定します。意地悪な店員を1万通り生成して回すと、誤完了はゼロ。ワンコマンドで再現できます。

{
  "field": "time",
  "value": "19:30",
  "source": "callee",
  "transcript": "19時はいっぱいですが、19時半でしたら空いております。",
  "span": "19時半",
  "explicit": true,
  "verified": true,
  "note": "accepted with value restated by caller",
  "audio": { "startMs": 14210, "endMs": 18960 }
}

完了 = 接続済み
     ∧ 日付.検証済み ∧ 時刻.検証済み
     ∧ 人数.検証済み ∧ 確定.検証済み
     ∧ 制約を満たす

$ npx oathra eval --adversarial 10000
never-confirm · wrong-restate · negate-then-offer
silent-hangup · caller-echo-trap · tentative-hold
echo-question · confirm-then-change · cancel-after-confirm
hold-then-reply · voicemail · transfer · ask-back · dialect-confirm
False Completion: 0 / 10000 adversarial runs  6.2s
  • 断りは提示にならない「19時はいっぱいですが」から 19:00 の証拠は作られない。
  • 言い直しは上書き「13日、いや14日」なら14日が残り、上書きの履歴が付く。
  • 曖昧な返事は確定にならない「たぶん大丈夫」は同意でも確定でもない。
  • 確定できるのは相手だけAI が「予約しました」と言っても記録されるだけ。
  • 確定は古くなる「承りました」の後に金額が変われば、確定し直しが必要。
  • 引き下がりは受諾ではない「わかりました、他を探します」で何も検証されない。

組み合わせは自由

電話会社
Twilio direct実通話で検証済み
Plivo sipゲートウェイ経由 · PSTN 未検証
Custom SIP sip任意のトランク
Telnyx · Wavix · Sinch · didlogicv0.2
自分で追加oathra provider create phone <id>
音声モデル
GPT-Live 推奨全二重 · $0.05/分
Gemini Livegemini-3.8-live · 全二重 · 実回線は未検証
PipelineDeepgram + 任意のLLM + TTS
LLMOpenAI · Gemini · Ollama · 組み込み
ローカル実験段階

使い方

  1. ブラウザで見る上のv0.1.19起動コマンドをターミナルへ貼り付けて実行すると、アプリが練習モードで開きます(ログイン・APIキー不要)。「練習」で AI の電話を見るか、「自分が相手役」で店員として AI の電話に答えられます。
  2. ターミナルで回すoathra play impossible-hotel --fast で一瞬、oathra eval で全シナリオと誤完了の数、oathra eval --callee openai で店員役を GPT-4o mini に任せた評価(数円)、oathra replay <id> --at 00:18 でその時点の状態に戻れます。
  3. 電話会社を繋ぐoathra setup phone が選んだエンジンに必要なAPIキーを取得先付きで案内します。oathra phone doctor で各層を確認し、oathra phone test --level local は電話料0円(API使用)です。
  4. 本物の番号に電話するoathra call --to +81… --scenario restaurant-reservation。録音と全イベントが .oathra/calls/ に残り、結果は相手が実際に確定したときだけ completed になります。

誤完了を誘ってみる

「練習」の「自分が相手役」で、店員として次のような返事を試せます。判定エンジン単体では、どれも確定として扱いません。画面の結果は前後の会話によって変わります。

判定が抜ける言い回しを見つけたら Issue で教えてください。それが一番助かります。

API SETUP

必要なキーだけ、取得先付きで案内する。

最初はブラウザの証拠ラボか oathra demo を API キーなしで試せます。実電話へ進むときは、setup phone が選んだ音声エンジンのキーを先に確認し、電話会社ごとの設定を続けます。

  1. キーを入力OpenAI、Deepgram、Twilio、Plivo、LiveKit の取得先を表示。入力値は .env に保存し、秘密値は端末に表示しません。
  2. 診断するoathra doctor と oathra phone doctor が不足項目と直し方を示します。
  3. 段階的にテストLocal(電話料0円・API使用)→ Gateway(電話料0円)→ PSTN(実通話・有料)の順で進めます。

セットアップ手順を読む →

$ pnpm oathra setup phone
# cloneしている場合。公開版は上のv0.1.19コマンドを使用

Choose voice engine
❯ GPT-Live       needs OPENAI_API_KEY
  Pipeline       needs DEEPGRAM_API_KEY + OPENAI_API_KEY

OpenAI API key
  Get it at: https://platform.openai.com/api-keys
  (入力内容は表示されません)

How would you like to make calls?
❯ Twilio         direct media streams
  Plivo          SIP via gateway
  Custom SIP     SIP via gateway

✓ .env updated · run `oathra phone doctor` next

判定がおかしいときは、発言の順序と結果を報告する →

企業に紹介できること。これから検証すること。

現状:L1 · 技術紹介と検証の相談

予約・確認電話を実装するOSSと、失敗を完了扱いしない証拠判定を紹介できます。実電話は3件の開発記録があり、100件での成功率・p95応答・通話単価はまだ測定していません。

有償PoC(L2)には録音同意・保持期間・発信制御・テナント分離など、本番導入(L3)には監視・障害対応などの追加検証が必要です。本番サービスとしてのSLAは提供していません。

検証範囲と次の合格条件 →

データはどこへ行く?

このページの文字入力 → ブラウザ内の証拠エンジン。入力本文は外部送信しません。

実電話の音声 → 選択した電話会社 → Oathra → 選択した音声・AIプロバイダー。録音とイベントは実行端末の .oathra/calls/ に保存します。構成に応じて外部プロバイダーへ音声・文字が渡ります。

自社業務での検証・実装を相談する →

検証済みの範囲と残る課題は 検証記録 にまとめています。シミュレーションの評価値と、3件の実電話の開発記録は別の指標です。

まず、AI同士に電話させてみてください。

→ github.com/FORIFOR/oathra Star

自社の予約・受付・確認電話で使えるか、実通話での検証を含めて相談したい方は 電話業務の試験導入を相談する →(内容を公開しない問い合わせフォーム)

決定事項は、根拠つきで残す。

通話を保存すると、確認済みの決定事項と根拠を人が読める summary.md と intake.json にもまとめます。明示回答から作る業務上のプロファイルは残せますが、電話相手の属性やセンシティブ情報を推測するプロファイルは作りません。追加の聞き取りは、目的・項目・質問上限・同意・拒否時の停止を契約に明示した場合だけ、必要情報が確定した後に行います。同意と回答は発話ID・時刻に紐づき、拒否・保留・曖昧な返答ならその場で停止します。

相手が忙しい・時間がないと伝えた場合も、追加質問を続けず、その場で聞き取りを終了します。

技術紹介・導入の相談へ →