SYNX 3.7:SYNXL が AI データセットに型付きレコードストリームをもたらす
by APERTURESyndicate · 2026年8月1日
SYNX 3.7 を公開しました。言語に演算子をひとつ加え、その隣にまったく新しいファイル形式を用意しています。SYNXL——データセット向けのレコードストリーム形式で、JSONL と CSV がふだん押しつけられ、うまくこなせていない二つの仕事のために作りました。
要点はこうです。フィールドは一度だけ宣言し、あとは型付きのレコードを流し込む。入れ子も複数行テキストもそのまま扱え、壊れた行は黙って消えるのではなく報告されます。
データセットで JSONL と CSV がつらい理由
JSONL の学習データを何でもいいので開いて、実際に何に費用を払っているのかを見てください。レコードごとにキーも波かっこも引用符も繰り返されます。数十万件のチャット例からなるコーパスでは、フィールド名だけでモデルに与えるトークンの無視できない割合を占め、しかも最初の一行以降は何の情報も運びません。
複数行のテキストはさらに厄介です。プロンプトも、コードの断片も、モデルの回答も、すべてが \n でエスケープされたノイズに潰れます。人間は読まず、diff は毎回それを壊します。
CSV は繰り返しを避けますが、代わりにほとんどすべてを手放します。型はなく、入れ子もなく、どの CSV パイプラインもいずれ突き当たる未解決の問いが残ります——空のセルは空文字列なのか、値が無いのか。フィールドにカンマをひとつ足せば、方言ごとに異なる引用符の規則の中です。
SYNXL を一画面で
!synxl 1
!fields id[type:int] ; score[type:float] ; messages[block]
1 ; 0.91
messages
- role system
content You are a helpful assistant.
- role user
content |+
def f(x):
return x + 1
2 ; 0.74
messages
- role user
content Приветフィールドの一覧は一度だけ宣言します。レコードは 0 桁目から始まり、スカラーのフィールドは ; で区切ります。[block] と指定したフィールドは、レコードの下に完全な SYNX として展開され、リストも入れ子のオブジェクトも複数行テキストも書けます。チャット形式のデータを、エスケープした文字列に潰さずそのまま表現できるのはこのためです。
この例はふつうの JSON に写せます。
[{"id":1,"messages":[{"content":"You are a helpful assistant.","role":"system"},
{"content":"def f(x):\n return x + 1","role":"user"}],"score":0.91}, …]この形式が実際に保証すること
型はあるべき場所に。
[type:int]、[required]、[enum:a|b|c]はヘッダーに置かれます。別のスキーマファイルでもなければ、行ごとに推論し直すものでもありません。空は「無」ではありません。 空のフィールドは
nullです。空文字列は""と書きます。CSV の曖昧さは仕組みの上で存在しません。黙って落とさない。 SYNX は壊れた構造を黙って読み飛ばします。SYNXL は報告します——欠けたフィールド、余分なフィールド、失敗した型変換、未知のブロックキーを、レコード番号と行番号つきで。何も言わずに列を落とすデータセットは、大きな音を立てて失敗するものより質が悪いのです。
レコードは独立しています。 レコードの境界は 1 バイトで判定できるため、安全に追記でき、きれいに分割でき、並列に解析できます。
ファイルの途中でスキーマを変えられる。 列が増えたら、新しい
!fields行を書いて追記を続けるだけです。それ以前のレコードは有効なまま、元の形を保ちます。
メモリに収まらないファイルのために
SYNX が文書に課している 16 MiB の入力上限は、SYNXL ではレコードごとに適用されます。データセットはふつうにギガバイト級になり、レコードは互いに独立しているため、ファイル全体の上限はレコードごとの上限以上には何も守りません。
ストリーミングの読み取りは、同時に 1 レコードしか保持しません。CLI で 142 MB・240 万レコードのファイルを実測したところ、validate、parse、split のいずれでもピークメモリはおよそ 10 MB で平坦なままでした。同じファイルをまるごとメモリに読み込めば、少なくともファイル自身の大きさぶんはかかります。
3.7 のもう半分:|+
言語そのものに増えたのはひとつだけです。|+——インデントを保つ複数行の開始記号です。ふつうの | は継続行の字下げを削ります。散文なら問題ありませんが、空白に意味がある内容では破壊的です。|+ は最初の本文行で基準となる字下げを固定し、それより右をそのまま保ちます。コードも ASCII 図もプロンプトの雛形も、値の中で無傷のまま残ります。
SYNX 3.6 は凍結された相互運用の基準であり続けます。3.7 は加算的で、3.7 固有の記法を使わない文書であれば、3.6 のパーサーは適合したままです。
コードから読む
SYNXL は現在四つの実装があり、いずれの背後にも同じ意味論があります。
// Rust
let doc = synx_core::synxl::parse_lines(&text)?;
for record in &doc.records { /* … */ }
// TypeScript
import { parseSynxl, streamSynxlFile } from '@aperturesyndicate/synx-format'
for (const record of streamSynxlFile('dataset.synxl')) { /* … */ }
# Python
import synx_native as synx
for record in synx.synxl_stream_file("dataset.synxl"):
train(record["messages"])シェルからも同様で、双方向のコンバーターも用意しています。
synx synxl parse dataset.synxl --format ndjson
synx synxl validate dataset.synxl --constraints
synx synxl convert corpus.jsonl # jsonl → synxl
synx synxl split dataset.synxl -n 500000 # shards that are valid on their own提供状況
3.7.1 は crates.io、npm、PyPI、NuGet で公開しています。
SYNXL 自体は Rust、TypeScript、Python、そして CLI に実装されています。C++、Dart、.NET、Go、Java、Swift のネイティブパーサーは |+ を含む SYNX 3.7 に対応していますが、.synxl はまだ読めません。それまでは CLI で変換するか、四つの実装のいずれかで読んでください。
仕様と適合性
SYNXL は独自の軸でバージョンを刻みます。言語のバージョンとは無関係な形式バージョン 1 です。SYNXL 文書は SYNX 文書ではなく、最上位がオブジェクトではなくレコードの並びだからです。
規範となる文書は SYNXL-1-NORMATIVE.md で、その裏づけは、いかなる実装にも依存せずその文書から導いた 67 件の適合性ケースです。Rust のランナーはさらに、受理された全ケースを三つのリーダーすべてで読み直し、結果が食い違えば失敗とします。
詳しいドキュメントと実際に試せるプレイグラウンドはこちら:synx.aperturesyndicate.com
次に来るもの
残りのパーサーへの SYNXL 対応を、Go と .NET から進めます。仕様は安定し、適合性テストも書き終えているので、第二波は探索ではなく機械的な作業です。実装より先にテストを書く意味は、まさにそこにあります。



