LLM のための Family BASIC リファレンス(2)|中古マニュアルと AI OCR でリファレンスを作る

LLMのためのFamily BASICリファレンス(2)|引用ベースの設計と著作権法32条 — LLM, 引用, 著作権法 AIテキスト

こんにちは、パレイド技術部の橘です。

前回 (第 1 回) は「Claude にいきなりファミベのコードを書かせるとボロボロになる」現実から 始めて、LLM 向けのリファレンスが必要だという結論に着地しました。

今回はそのリファレンスの作成を試してみます。

本記事は LLM による自動執筆パイプラインで生成されました。現在は人間が補助していますが、pareido.jp では最終的に AI が自律的にコンテンツを制作できる仕組みの構築を目指しています。

中古でも、マニュアルがちゃんと手に入る

今回の準備で難しかったのは、Family BASICの公式マニュアルの入手です。

カートリッジに紙マニュアルが同梱されていた時代の品で、状態の良いもので数千円台で流通しています。 任天堂が公式に再販する見込みのない 40 年前の冊子が、今でも個人取引で普通に手に入るのはありがたい話。

ROM/カートリッジ本体だけなら手元に既にあった人も多いはずです。問題はそれに付属していたマニュアルだけ別経路で追えるかどうか、というところで、ここが現実的に越えられる、という事実が今回の前提です。

メルカリで検索した例。それなりの流通量。

OCR環境は劇的に改善

マニュアルが手元にあっても、これを LLM が読める形に起こす段階には、壁があります。

Family BASIC マニュアルの本文は明朝混じり、表組み、罫線、コード例 (等幅、カタカナ + 記号) が同居していて、Tesseract 系の従来 OCR では認識はかなり厳しい。 スキャンした画像データを流し込んでも、スペースが混ざり込んだり、半角記号と全角の判別、$S の取り違え、表の構造崩れで、後工程で人間が直す量が原文書き写しに匹敵する、というのが実態でした。

ここが、ここ最近の AIベースのVision LLM (Claude / GPT-4o 系) で劇的に改善した ところです。 ページ画像をそのまま渡して「このページの内容を構造化テキストにしてください」と頼むと、表は表として、コード例はコードとして、注釈は注釈として返ってきます。

また、専用のスキャナがなくとも、スマホのカメラでもOCRに十分な画質が確保できるのも大きな変化です。 100 ページ超のマニュアルですが、必要な部分に限れば半分ぐらいで済みます。

誤認識が無くなったわけではありませんが、直す量が桁違いに減りました。 詳しい OCR ワークフローは次回 (第 3 回) で扱いますが、ともかく「個人でもデータに起こせる」フェーズに入っています。

マニュアルのPRINT文の一部引用。人間には読みやすいがOCRは厳しい。

つまり、何が可能になったのか

整理すると、レトロ言語のリファレンスを LLM 向けに作るための条件は次の 3 つです。

  1. 当時のマニュアル本体 — 中古市場で入手可能
  2. 読み起こし手段 — スマホ等で取り込み、AI(Vision LLM) で一定の精度
  3. 構造化スキーマ — 後述

数年前までは (2) が番人向けとは言えず、専用のスキャナが必要だったり、OCR も参考程度にしか使えず相当な労力が要求されました。今は (1)(2) が個人レベルで揃うので、ROM/マニュアル所有者なら、 自分のためのリファレンスを自分で組み上げられる 時代になっています。本連載はその実例です。

なお、インターネット上にも有志がまとめた情報が海外中心に散在していますが、法的な取り扱いが明確ではありません。 マニュアルのスキャンも含め、収集したデータは個人的な利用にとどめるのが鉄則でしょう。

エントリの構造 (YAML スキーマ)

OCRで読み込んだテキストデータは、構造化しておくと LLM も解釈しやすくなります。

まずはページ単位で整理しておき、1 つの予約語・関数・エラーコード・メモリ位置 = 1 エントリ。最終的には reference.yaml に集約します。

例えばPRINT文なら下記のような感じです。

- entry: PRINT
  category: statement
  summary: 文字や数値を画面に表示する
  syntax: PRINT [式リスト]
  args:
    - name: 式リスト
      type: 数値式 | 文字列 | 変数
      optional: true
  notes_for_llm: |
    - `;` 連結は値どうしを密着、`,` 連結は次のブロック先頭に揃える
    - 末尾 `;` で改行抑制 (連続 PRINT 時の常套手段)
    - 引数なし (`PRINT` 単独) は空行
  example: |
    10 PRINT "HELLO"
    20 PRINT A; B
  manual_quote: |
    > PRINT 文は、画面に印字、結果数値や、数値変数の値、
    > 文字数や文字列定数の値、文字列変数の値などを表示します。
  source:
    - { version: v2.1, page: 60 }
  tags: [出力, 基本, 必須]

ファミリーベーシックには省略形もあり、様々な情報を足したくなりますが、LLM に与える情報は絞ったほうが精度が上がります。もちろん、yamlなので後で削るのは容易です。

各フィールドの役割

  • summary / syntax / notes_for_llm / example = 連載者による創作的解説。 LLM が読んでコードを書くために必要な情報を、原文の構成順ではなく 「言語のリファレンスとして」整理したもの。
  • manual_quote = マニュアル原文からの引用。当該エントリの主張を裏付ける 必要最小限の 1 行に絞る。
  • source = 出所明示。{version, page} の配列で、どの版のどのページから来た情報かを 追跡可能にする。

この構造なら、LLM 入力時には summary + notes_for_llm + example だけを抜き出した 「軽量版」を生成でき、公開時には manual_quotesource を併記した「引用根拠付き 完全版」を出せます。同じデータから 2 形式のレンダリングが可能な設計です。

カテゴリ列挙

エントリは以下の 12 カテゴリのいずれかに分類します。

  • statement (PRINT, IF-THEN, FOR-NEXT 等の文)
  • function (ABS, RND, CHR$ 等の関数)
  • operator (+, -, AND, OR 等の演算子)
  • syscommand (NEW, RUN, LIST 等のシステムコマンド)
  • memory (ゼロページ / RAM / VRAM / I/O アドレス)
  • character_code (キャラクタコード)
  • error (エラーメッセージ)
  • control_code (制御コード $00-$1F)
  • constraint (言語仕様の制約: 変数名 2 文字、行番号など)
  • mode (GAME BASIC / MUSIC / CALC / MESSAGE モード固有)
  • idiom (よくある書き方パターン)
  • spec (ハードウェア仕様: 色数、画面サイズ等)

LLM がコード生成時に必要な情報の粒度を、このカテゴリで分けています。 たとえば「整数の表現範囲」は spec、「?PRINT の代用」は control_code、 「未初期化変数は 0」は idiom に近いが、マニュアル明記なので statement の notes に置く判断をしました。判断の粒度は連載者の裁量です。

「マニュアル外の事実」の扱い

実際に試してみると、マニュアルには明記されていないが LLM 向けには絶対に必要 な事実が出てきます。たとえば「代入に LET は使えない」「NEXT に変数を付けるとエラー」「英文字は大文字のみ」など (詳細は第 4 回で扱います)。

これらをマニュアル由来の記述と混ぜると、構造化が難しくなります。 そこで notes_for_llm を別に作り、以下のマーカーで、段落を分けて補足を書く規約にしました。

**補足 (マニュアル外)**:
- 英文字は大文字のみ。小文字は存在しない
- LLM が `print "hello"` のように小文字で書いた場合、`PRINT "HELLO"` に補正が必要

source 配列にも { type: observation, ref: "..." }{ type: testing, ref: "..." } を追加して、補足の出所も追跡できるようにしました。これで公開時にも「これは引用ではなく 連載者の補足である」が読者に明示されます。

次回

実際にスキャンを試す段階に進みます。なぜ Tesseract では駄目だったのか、 Vision LLM (Claude) でページ画像から直接構造化テキストを起こすにはどう投げればいいのか、 OCR ワークフローの実装 を次回扱います。

タイトルとURLをコピーしました