『霧走町 流氷に眠る』を作っている間、独自に考えたつもりの工程がいくつもありました。 あとで調べると、ほとんどに名前があった。 検査のやり方にも、失敗の仕方にも、先に名前を付けた人がいました。
この連載の技術記事は、その名前から入ります。 今日は一覧です。 名前ごとの中身は、それぞれの記事の節で書きます。
表の「位置づけ」は三つに分かれます。
「採用」は、外にある方法をそのまま使っているもの。 「変更して採用」は、方法の骨は借りたが、このゲームの都合で形を変えたもの。 「失敗・対策」は、制作中に実際に踏んだ穴に、あとから名前を当てたものです。
採用と書いてあっても、標準の実装と完全に同じという意味ではありません。 どこが同じで、どこを変えたかは、個別の記事に書きます。 逆に、使っていない方法はこの表に載せていません。 名前を並べて賢く見せたいわけではないので。
個別の記事には、対象のコミットも書きます。 コードも数値も画面も、同じ版から取る。 過去の報告書にある所要時間や成功率を、いまの保証として載せない。 その約束で、技術記事を書いていきます。
一番外側にあるのは、generate-and-test です。 文章の候補を作り、別の仕組みで合否を出し、通ったものだけ残す。 「正しいものを一発で作る」より「作られたものが正しいか判定する」ほうが易しい場面で効きます。 この差に generator-verifier gap という名前があります。
その上流に、仕様を先に固定する spec-driven development があります。 事件の真相と、プレイヤーが知る順序を、作品データより前に決める。 生成AIに埋めさせる穴を小さく切るのが sketch-based synthesis。 決まった宣言から定型のファイル群を起こすのが schema-first codegen です。 台詞の候補を何度か生成させ、検査を通ったものだけ採るのが rejection sampling with verifier。
この四つは、どれも「AIに全部書かせる」とは逆の方向を向いています。 人が決めることを増やして、機械に任せる範囲を狭める。 そのほうが、町の人の声が残りました。
日本語の自由入力を、用意した話題へ着地させる部分です。
文字の並びで拾う疎な照合と、意味の近さで拾う密な照合を合わせるのが hybrid sparse-dense retrieval。 自由文を有限個の話題へ割り当てるのが intent classification。 返事をその場で生成せず、候補から選ぶのが retrieval-based response selection です。 この三つで、「何を打っても、返ってくるのは書かれた台詞」という形ができます。
決めきれないときに答えない判断が selective prediction。 通った・外れた・通りすぎた・通らなかったを分けて数えるのが confusion matrix。 外したあとに会話を立て直すのが conversational repair です。 聞き返し、別の相手への誘導、受け流し。 ここは、照合の精度よりも文章の仕事でした。
作品データが壊れていないかを、遊ぶ前に調べる方法です。
実行せずに参照や不変条件を調べる static analysis。 状態を決めた深さまで展開して行き止まりを探す bounded model checking。 クリア条件から必要な材料を逆算する static reachability analysis。 要求と実装と検査の対応を表にする requirements traceability matrix。
既知の入力と出力を凍結する golden master testing。 普段は見ない集合を残す holdout と、役割別に持つ evaluation set。 言い換えても同じ意図に着くかを見る metamorphic testing と、一か所壊して赤くなるかを見る mutation testing。 台本の中に期待を書く inline assertion。 何を回すかをデータで宣言する declarative test manifest。 同じ企画から起こした二作を比べる differential testing。
テスト文が辞書へ写し込まれていないかを調べる benchmark leakage detection には、w-shingling と Jaccard係数を使いました。 数字が上がったのに未知の入力に弱いまま、という状態を見つけるためのものです。
人が遊ぶ前に、AIに遊ばせて観察するのが playtesting。 その記録をAIに採点させるのが LLM-as-a-judge です。 便利ですが、採点する側が自分に近い出力を高く見る self-preference bias が残ります。
合否の主張を、測った版と日時に縛る台帳が evidence ledger。 検査を終える条件を先に決めるのが exit criteria。 後の工程で見つかった欠陥を数える escaped defect と、検査を足しても発見が減っていく saturation effect。 この四つは、「いつやめるか」を決めるための名前です。 やめる条件が無いと、直しては測り、測っては直す循環から出られませんでした。
実際に一度、その循環に入っています。 AIに遊ばせて見つかったことを全部その場で直し、直したのでまた遊ばせる。 二十回を超えても終わらなかった。 そのときの記録も、後の記事で扱います。
踏んだ穴にも、名前がありました。
指標を上げて目的を壊す Goodhart則。 検査の通過を完成と読み替える surrogation。 仕様が変わったのに期待だけ残る test rot。 目録を二か所に書いて片方だけ増える、Single Source of Truth の崩れ。 共通化しすぎて作品ごとの違いを消しかける、Don't Repeat Yourself の誤解。 古い派生物が偽の緑を作る stale artifact。 落ちたテストの期待を今の出力に合わせてしまう Guru Checks Output。 見ないはずの集合を見て直す adaptive data analysis。 何でも監視して毎回未測定に戻す over-invalidation と、無関係な変更で落ちる Fragile Test。 図の並びから答えが漏れる side channel と、近くに置いただけで因果を読ませる illusion of causality。 合格したあとも作り込み続ける gold plating。
どれも、善意で陥ります。 名前があると、次に踏んだとき「あれだ」と言えます。 それだけで、抜けるのが早くなりました。
記事の欄は、その名前を扱う技術記事です。 記事の中では、その名前の節へ飛べるようにします。
似た名前で、中身が違うものがいくつかあります。 先に分けておきます。
retrieval-based response selection と RAG。 前者は、用意した返事の候補から条件に合うものを選ぶ方式です。 後者は、検索した結果を言語モデルに渡して新しい文章を生成する方式。 このゲームは前者で、プレイ中に台詞を生成しません。
metamorphic testing と mutation testing。 前者は、入力を言い換えても出力の関係が保たれるかを見ます。 後者は、検査される側を一か所壊して、テストが赤くなるかを見ます。 変えるものが、入力か、被検査物か。 そこが違います。
golden master と holdout。 前者は、既知の入力と出力を凍結して、変化を検出するためのもの。 毎回見てよい。 後者は、普段は見ないために取っておくもの。 見た回数が増えるほど、未知ではなくなっていきます。
static reachability analysis と playtesting。 前者は、設計データの上で「届くはず」を計算します。 後者は、実際に誰かが打った文章で「届いた」を確かめます。 届くはずなのに届かない、という差が、直すべき場所でした。
自分の造語で説明すると、その場では分かった気になります。 でも外の知見につながらない。 名前があれば、同じ穴を先に踏んだ人の文章を読みに行けます。
このゲームの中身は、日本語で質問して町の人の話を聞く、それだけです。 それを壊さずに作るために、これだけの名前を借りました。
一人で作っていると、自分の工程を疑う機会が少ない。 名前を当てる作業は、その代わりになりました。 名前が見つからなかった工程もいくつかあって、それは表に載せていません。 見つかったら、そのとき足します。 技術記事は、毎日1本ずつ出します。 遊ぶ側の記事と一緒に読んでもらえれば。
この町が気になったら、Steamのウィッシュリストに入れておいてもらえるとうれしいです。
[[STEAM_LINK: https://store.steampowered.com/app/5287530/?utm_source=gamewith&utm_medium=devlog&utm_campaign=gamewith04&utm_content=03]]
フォローすると、開発ログや新作ゲームの公開が通知されます