自然言語の経費パーサーを削除した
ルールベースのパーサーは1週間しか持たず、4つの平凡な文が金額を誤った人物に割り当て、1つの拒否ルールがガードの積み重ね全体を置き換えました。
書き終えたばかりのパーサーを削除しました。Dimesum が最初に試みた自然言語の経費入力はルールエンジンで、4つの平凡な文がそれを引退させました。dinner 12-08 400 は ¥12 と読み取られ、ravioli 600 は Ravindra という名前のメンバーを割り勘に入れ、kirana 500 は Kiran という名前のメンバーに請求し、refund -12000 は ¥12,000 の請求になりました。
文を理解することはモデルの仕事であり、他の何の仕事でもありません。ルールエンジンを置き換えたのは amount_only と呼ばれる1つの段です。テキストに曖昧さのない金額候補がちょうど1つあるときだけ返される単一の数字であり、人物についての主張は決してしません。候補が2つあれば金額はありません。1つのルールが、積み上がっていくガードの山を置き換えました。
4つの文がルールパーサーを終わらせた
削除されたパーサーは、私たちの AI 設計ドキュメントが定めるエンティティ一式をすべて扱っていました。メンバーとニックネームの照合、除外辞書、支払者の推定、カテゴリ辞書、そしてフィールドごとに調整された信頼度です。以下の4つの失敗にはいずれも明白な修正策がありました。どの修正策も、それ自身の死角を持つ新しいガードでした。
| ユーザーが入力したもの | パーサーがしたこと | なぜ起きたか |
|---|---|---|
dinner 12-08 400 | 金額を ¥12 と読み取った | 人間は日付と合計を見る。正規表現は3つの数字を見て、最初のものを取る。 |
ravioli 600 | Ravindra という名前のメンバーを割り勘に加えた | あいまいなニックネーム照合が、料理を人物として採点した。 |
kirana 500 | Kiran という名前のメンバーに請求した | 同じ照合器で、今度は店名だった。 |
refund -12000 | ¥12,000 の請求を登録した | 数字は残り符号は消えたので、金額は逆向きを指した。 |
4つのうち2つは、違う服を着た1つのバグです。あいまい照合は料理と人物、店と人物を区別できません。文字レベルでは ravioli と Ravindra は本当によく似ているからです。より長い接頭辞の一致を求めれば ravi が壊れますが、それこそ照合器が存在する目的の事例です。
ガードを1つ足すたびに、言い回しが2つ現れる
ルールパーサーは特定の形で失敗します。自信を持って、しかも誤って答えるのです。空欄のフィールドはユーザーにタップ1回の手間をかけます。誤った割り勘は台帳への信頼を損ないますし、お金を分け合うトラッキングアプリでは台帳こそが製品です。上の4行は惜しい失敗ではなく、金額のバグです。
本当の論点は個々の欠陥ではなく、この終わりのない繰り返しです。日付ガードを足せば注文番号の事例が来ます。注文番号ガードを足せば部屋番号が来て、次に数量、次にテーブル番号が来ます。ガードの一覧は増え続けて収束しません。自然言語には列挙し切れる有限の言い回しの集合が存在しないからです。
自然言語の入力は AI の機能であり、Dimesum のリポジトリのパターンにはどれも一致しません。この判断は 2026-08-20 に、4つの失敗とともに書き留められました。誰かがうっかりガードを作り直さないためです。
出荷したのは1つの数字と拒否
amount_only は、私たちの AI 設計ドキュメントにある劣化時の段を文字どおり実装したものです。その段には「クライアント側の金額正規表現で事前入力した素のフォーム」とあり、ティアは金額だけを返して他は何も返しません。説明も、カテゴリも、支払者も、参加者も、除外もありません。何のコストもかからず誰も呼び出さないので、テストと CI はこれを使って動きます。
曖昧さは拒否であって、勝敗の決着ではない
ルール全体は extract_amount_minor という1つの関数の中にあります。テキストにその候補がちょうど1つあるときだけ数字が返るので、order 90210 dinner 400 や flat 402 rent 15000 は勝者を選ばず空欄を返します。通貨記号の付いた数字は、裸の数字と並んでいても曖昧でないと見なされます。だから split 3 ways ¥1,200 はいまも ¥1,200 と読み取られます。
符号を打ち消された数字は、その絶対値ではなく、そもそも金額ではありません。-500、minus 200、そして会計士の書く (500) はいずれも空で返ります。このフィールドは請求であり、数字を残して符号を落とせば、金額はテキストと逆向きを指すからです。括弧は数字そのもので閉じるときだけ数えられるので、(500 each) は括弧の注記のままです。
通貨が計算を決める
Dimesum で金額が取る表現は最小単位だけなので、ティアは 100 倍のハードコードではなく ISO 4217 の指数表で変換します。日本円には補助単位がまったく無く、×100 は ¥1,200 のレシートを百倍に膨らませます。通貨の最小単位より細かい数字は、丸めるのではなく拒否されます。誰かが入力した金額を丸めることは、金額を捏造することだからです。
インドの数の単位表記は、数字の書き方の一部であって、文を理解することの一部ではありません。1.2k、2 lakh、500/- はいずれも 1,200 と同じように解決されます。台帳の最大金額を超えるものは空で返るので、打ち間違えた数字は、下流で整数をあふれさせる代わりに1つのフィールドを空欄にします。
| フィールド | ルールパーサー(削除済み) | amount_only(稼働中) | モデルティア(配線済み、鍵なし) |
|---|---|---|---|
| 金額 | 複数の数字から推測 | 曖昧さのない数字1つ、なければ空欄 | 文脈で読み取る |
| 説明、カテゴリ | 辞書照合 | 常に null | 文から抽出 |
| 参加者、除外 | あいまいな名前照合 | 常に空 | 実在のメンバー ID に解決 |
| 支払者 | 言い回しから推定 | 常に空 | 名前付き、金額は null 可 |
| 全体の信頼度 | フィールドごとに調整 | 0.3 固定 | パースごと |
| 報告されるプロンプト | 存在しなかった | null、プロンプトは読まれなかった | プロンプト ID とバージョン |
稼働中の段は 0.6 の実用ゲートを決して越えない
私たちのパース契約は、全体の信頼度が 0.6 を下回るパースを放棄し、ユーザーを素のフォームに落とします。amount_only はどの回答でも 0.3 を報告し、この定数は調整されたものではなく構造的なものです。単独の金額はパースではないので、何を見つけようとこの段はゲートの半分に位置します。すべての回答で1つの定数を使うことが、それをそこに留めます。事例ごとのスコアは、いずれ誰かが上へ押し上げるスコアだからです。
このティアはプロンプトもまったく報告しません。prompt_id も prompt_version も null で返ります。この段はプロンプトを読まなかったからです。名前を付ければ、ティアが一度も見ていないプロンプトのバージョンにすべての評価結果を帰することになります。そして、ある段をワンタップの提案に昇格させてよい唯一の道具は評価ハーネスであり、金額と参加者を合わせて 95% の精度を条件とします。
さらに2つのティアが宣言されていますが、どちらも稼働していません。cheap-fast ティアには openai/gpt-oss-120b 向けの Groq アダプターがありますが鍵はありません。中位のティアにはアダプターがありません。どちらを選んでも、ユーザーの最初のリクエスト時ではなく起動時に失敗します。LLM は呼び出しごとに課金され、課金対象の依存はフェイルクローズでなければならないからです。
自動では何も登録されないので、空欄はタップ1回で済む
空欄のフィールドの代償がこれほど小さいのは、Dimesum のどのキャプチャも金額を書き込めないからです。キャプチャは提案を作り、人がそれを確認し、その確認が経費を作ります。ブリーフの決定 D5 がこのルールを述べ、.go-arch-lint.yml がそれを強制します。取り込みコンテキストには expense や ledger への依存が一切許されないので、キャプチャが誤って仕訳を登録することはできません。CI は取り込みを失敗させます。私たちは実際に1つ追加して確かめました。
キャプチャはパーサーが何をしようと生のテキストを保持し、どのフィールドが未解決かを示します。クライアントは捏造した下書きを見せる代わりにその空欄を強調します。これが、何も言わないパーサーと推測するパーサーの違いです。確認は経費 ID を提案 ID から導くので、二度タップしても二重に請求されるのではなく再生されます。
盗む価値のあるルール
バグではなく、ガードを数えてください。毎週増えていくガードの一覧は、その仕事が理解であることを告げています。そして理解はモデルのものです。私たちの次の一歩は、contracts/parse_expense/eval/ にあるゴールデンセットを実際のモデルティアに対して走らせることです。その判定なしには、ここにあるものは何もワンタップの提案にはならないからです。
よくある質問
Dimesum はなぜルールベースの経費パーサーを削除したのですか?
4つの平凡な文が金額のバグを生み、追加したガードはどれも新たな言い回しを2つ表面化させたため、Dimesum はそれを削除しました。dinner 12-08 400 は ¥12 と読み取られ、ravioli 600 は Ravindra というメンバーを加え、kirana 500 は Kiran というメンバーに請求し、refund -12000 は ¥12,000 の請求になりました。文を理解するのはモデルの仕事です。
amount_only ティアは実際に何を返すのですか?
amount_only ティアは1つの数字だけを返し、他には何も返しません。テキストに曖昧さのない金額候補がちょうど1つあるときだけ金額で答え、参加者、支払者、説明、カテゴリを名指すことは決してありません。候補が2つあれば金額はまったく返りません。パース契約の残りはすべてモデルティアを待ちます。
amount_only の信頼度はなぜ 0.3 固定で本当のスコアではないのですか?
0.3 は調整値ではなく構造的な値です。私たちのパース契約は 0.6 を下回るパースを放棄してユーザーを素のフォームに落としますが、単独の金額はパースではないので、何を見つけようとこの段はそのゲートの半分に位置します。すべての回答で固定の定数を1つ使うことで、事例ごとのスコアが後から押し上げられるのを防ぎます。
自然言語のキャプチャは人の確認なしに台帳へ書き込めますか?
いいえ。キャプチャは提案を作り、人がそれを確認します。ブリーフの決定 D5 のとおりです。このルールは .go-arch-lint.yml で強制され、取り込みコンテキストに expense や ledger への依存を一切許さないので、キャプチャが仕訳へ手を伸ばせば CI が取り込みを失敗させます。経費を作るのは確認です。
モデルティアが使えないとき自然言語の経費パースはどうなりますか?
Dimesum は amount_only に劣化し、空欄を表示します。cheap-fast ティアは Groq の openai/gpt-oss-120b に配線されていて鍵なしで出荷され、中位のティアにはアダプターがないので、どちらを選んでもユーザーの最初のリクエスト時ではなく起動時に失敗します。いずれの場合もキャプチャは生のテキストを保持します。
人気の記事
- 割り勘の残高を正確に保つ追記専用の台帳読了 約6分
- 共有費用を編集するときに分担をやり直す理由読了 約5分
- 多通貨の割り勘に潜む6つの金額バグ読了 約6分
- 精算:グループの費用を少ない送金で清算する方法読了 約6分
- 取り分けなかった一皿がある割り勘の精算方法読了 約6分