DESIGN / CODE / INFRA / AI

解説

JSONLはJSONと何が違う?AIへ渡す一覧を一行ずつ確かめよう

JSON Linesの一行一値、UTF-8、空行と文字列内改行を小さなPython例で確認。JSONの配列やAPI固有の入力仕様との違いも整理。

JSONLはJSONと何が違う?AIへ渡す一覧を一行ずつ確かめよう
保存リストを見る →
この記事の道しるべ 4項目

AIへ渡すデータに.jsonlが指定されていた。JSONの配列を保存するだけでよいのかな。JSON Linesは、一行ごとにJSONの値を置くテキスト形式だよ。

今回は架空の短い文を二件使い、Python 3で作って読み直す。AIへのアップロードや有料APIの呼出しは行わない練習だよ。

外側の配列で全部を囲まない

{"id":1,"text":"練習の文"}
{"id":2,"text":"次の文"}

これはJSONLとして一行ずつ読む例。ファイル全体を一つのJSONとして読むと、二つ目の値で余分なデータになる。値の間へカンマを付けた、JSONの配列とは形が違うんだ。

一行の値はオブジェクトに限らず、配列やnullなど、有効なJSONの値を使える。ただし、AIサービスが受け付ける行の項目は、そのサービス固有の仕様を確認する必要があるよ。

空行と、文字列内の改行を分ける

JSON Linesの案内では、一行は有効なJSONの値でなければならず、空行は値ではない。末尾へ通常の改行を付けることと、間へ空の行を入れることを区別しよう。

本文の文字列に改行がある場合は、JSONとしてエスケープする。自分で引用符や改行をつなぐより、JSONを出力するライブラリを使うと条件を揃えやすいね。

Pythonで作り、行番号を残して読む

import io
import json

def reject_constant(value):
    raise ValueError("JSONの数値ではない: " + value)

def read_jsonl(text):
    result = []
    for number, line in enumerate(io.StringIO(text), 1):
        try:
            result.append(json.loads(line, parse_constant=reject_constant))
        except ValueError as error:
            raise ValueError(f"line {number}: {error}") from error
    return result

values = [{"id": 1, "text": "一行目\n続き"}, {"id": 2, "text": "二行目"}]
source = "\n".join(json.dumps(v, ensure_ascii=False) for v in values) + "\n"
loaded = read_jsonl(source)
print(len(loaded))
print(loaded[0]["text"] == "一行目\n続き")

期待する表示は2とTrue。文字列の中の改行は保ちながら、JSONLの行としては二件に分けて読める。

この関数は、すでに文字列へ読んだ内容を検査する例。JSON標準にないNaNなどは受け付けず、エラーの行を示す。実ファイルではUTF-8で保存・読込みし、BOMを付けないことも確認しよう。

形式が合っても、AI用の項目が合うとは限らない

一行ずつ読めても、APIに必要な項目、IDの一意性、ファイル容量、対象モデルなどの条件は別。この関数だけで、どんなAIサービスの入力も検証できるわけではないよ。

まず練習用の少量データで、行数、元の文字列、エラー時の行番号を確認し、サービスの仕様と対応させよう。

編集部ではPython 3.12で二行の復元、途中の空行の拒否、nullなどの値とエラー行を確認した。AIサービスでの取込みを試した記録ではないよ。項目の条件はJSONの検証、別の表形式はCSVの引用符とレコードも参考になるね。

参考・出典

公開と変更の記録
  • :初回公開

日時は日本時間です。記載のある変更は、確認できた編集記録に基づきます。更新日の違いだけから変更内容を推測して載せることはありません。

更新・訂正の方針 →

みんなのコメント 0

感想や、試してみたことを聞かせてね。コメント・返信は承認後に公開されます。

最初のコメントをどうぞ。