OATHRA / DEVELOPER LAB
発言を変えて、
判定の境界を知る。
公開済みの証拠ラボと、保存済みのArena交渉記録です。下の発言を編集して判定を確かめられます。このページの操作で実電話は発信されません。
v0.1.19の導入手順 · コピーボタンはGitHub Release版を起動します。npm版は0.1.0です。
この体験は、この製品の証拠エンジンそのものです。AIは「ご予約承りました」と言い切っていますが、店が確定していないので確定だけが未確認のまま残ります。返事を差し替えると判定が変わります。入力はブラウザ内に留まり、電話は発信されません。
判定が変わるところを、26秒で見る。
上のラボを実際に操作した画面録画です。店の返事を差し替えるたびに、同じ判定コードが走り直します。カメラの寄りとカーソルと字幕は編集で足したもので、画面と判定は編集していません。
画面が小さいと録画内の文字は読めません。再生後、全画面にすると判定の項目まで読めます。
いまの音声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の動画に編集。実電話の録音ではありません。
追加聞き取りは startAfter・dependsOn・choices でシーンに合わせて分岐できます。拒否・保留・曖昧な返答・選択肢に一致しない返答は保存せず終了します。
実モデルによる交渉の記録
GPT-4o mini がシミュレーター内の仮想ホテル(定価 23,500 円)と交渉した記録。実店舗への発信ではありません。保存されたイベントを 3 倍速で描き直しています。録画ではありません。
作った理由
AIに電話をさせる仕組みは、作ろうと思えば一晩で動きます。厄介なのはその先で、席が取れていないのに「予約できました」と言い切る。留守番電話に向かって予約を依頼し続ける。値段が予算を超えているのに、話の流れで受けてしまう。どれも実際に起きました。
そこで、完了の判定をモデルから取り上げてコードに移しました。日時、人数、金額、そして「確定したか」は、相手の発言から取り出した証拠が揃ったときだけ埋まります。AI 側がいくら「確定しました」と言っても、それは記録されるだけで証拠にはなりません。
同じランタイムをシミュレータでも本物の電話でも動かせるようにしたので、まずはブラウザで AI 同士に交渉させて遊び、納得したら電話会社を繋いでください。


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にしました。そういう見つけ方をするための対戦機能です。
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ゲートウェイ · 音声 · 音声モデル · 遅延 · 料金を段ごとに確認し、失敗した項目には直し方を添えます。
実際に電話してみた記録
通話料は 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 · didlogic | v0.2 |
| 自分で追加 | oathra provider create phone <id> |
| 音声モデル | |
|---|---|
| GPT-Live 推奨 | 全二重 · $0.05/分 |
| Gemini Live | gemini-3.8-live · 全二重 · 実回線は未検証 |
| Pipeline | Deepgram + 任意のLLM + TTS |
| LLM | OpenAI · Gemini · Ollama · 組み込み |
| ローカル | 実験段階 |
使い方
- ブラウザで見る上のv0.1.19起動コマンドをターミナルへ貼り付けて実行すると、アプリが練習モードで開きます(ログイン・APIキー不要)。「練習」で AI の電話を見るか、「自分が相手役」で店員として AI の電話に答えられます。
- ターミナルで回す
oathra play impossible-hotel --fastで一瞬、oathra evalで全シナリオと誤完了の数、oathra eval --callee openaiで店員役を GPT-4o mini に任せた評価(数円)、oathra replay <id> --at 00:18でその時点の状態に戻れます。 - 電話会社を繋ぐ
oathra setup phoneが選んだエンジンに必要なAPIキーを取得先付きで案内します。oathra phone doctorで各層を確認し、oathra phone test --level localは電話料0円(API使用)です。 - 本物の番号に電話する
oathra call --to +81… --scenario restaurant-reservation。録音と全イベントが.oathra/calls/に残り、結果は相手が実際に確定したときだけcompletedになります。
誤完了を誘ってみる
「練習」の「自分が相手役」で、店員として次のような返事を試せます。判定エンジン単体では、どれも確定として扱いません。画面の結果は前後の会話によって変わります。
- レストランで「たぶん大丈夫ですが、まだ確定ではありません」→ 確定にならない
- レストランで「19時は満席です。19時半なら空いています」→ 19時は採用されず、19時半は AI が受諾するまで未確定
- ホテルで「ご予約承りました」の後に「料金は2万3500円になります」→ 確定が失効し、取り直しになる
判定が抜ける言い回しを見つけたら Issue で教えてください。それが一番助かります。
API SETUP
必要なキーだけ、取得先付きで案内する。
最初はブラウザの証拠ラボか oathra demo を API キーなしで試せます。実電話へ進むときは、setup phone が選んだ音声エンジンのキーを先に確認し、電話会社ごとの設定を続けます。
- キーを入力OpenAI、Deepgram、Twilio、Plivo、LiveKit の取得先を表示。入力値は
.envに保存し、秘密値は端末に表示しません。 - 診断する
oathra doctorとoathra phone doctorが不足項目と直し方を示します。 - 段階的にテスト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同士に電話させてみてください。
自社の予約・受付・確認電話で使えるか、実通話での検証を含めて相談したい方は 電話業務の試験導入を相談する →(内容を公開しない問い合わせフォーム)
決定事項は、根拠つきで残す。
通話を保存すると、確認済みの決定事項と根拠を人が読める summary.md と intake.json にもまとめます。明示回答から作る業務上のプロファイルは残せますが、電話相手の属性やセンシティブ情報を推測するプロファイルは作りません。追加の聞き取りは、目的・項目・質問上限・同意・拒否時の停止を契約に明示した場合だけ、必要情報が確定した後に行います。同意と回答は発話ID・時刻に紐づき、拒否・保留・曖昧な返答ならその場で停止します。