はじめに
LLM(大規模言語モデル)に「JSONで返して」「SQLを書いて」「Mermaidで図にして」と頼むと、だいたいうまくいきますが、たまに壊れたものが返ってきます。
- 末尾にカンマが残っていて、JSONとして読み込めない
- 存在しないテーブル名やカラム名をSQLに書いてくる
- Mermaidの図が、
endという予約語のせいで描画できない
プログラムから使っていると、この「たまに」が地味に厄介です。そこで、壊れた出力を直して返すAPIを3つ作り、RapidAPIで公開しました。
作ったもの
3つとも、POST /v1/repair に壊れた文字列を送ると、直した結果と「何を直したか」を返します。
| API | 直すもの |
|---|---|
| FixMyJSON | 壊れたJSONの構文を直し、指定したJSON Schemaに合わせる |
| FixMySQL | SQLの引用符の間違いや、存在しないテーブル・カラム名を検出する |
| FixMyMermaid | Mermaidの図の構文エラー(予約語、特殊文字など)を直す |
大事にした点は、直せないものを直せたふりで返さないことです。推測でデータを作らず、直せなかった部分は unresolved_errors に理由付きで返します。
実行例
以下は、RapidAPIのテスト画面で実際に動かした結果です(見やすいよう一部を省略しています)。
FixMyJSON
末尾にカンマが付いた壊れたJSONを送ります。
{
"data": "{\"a\": 1,}",
"schema": {"type": "object"}
}
結果:
{
"success": true,
"repaired": {"a": 1},
"changes": ["repaired malformed JSON syntax (quotes/commas/braces)"],
"unresolved_errors": [],
"syntax_was_broken": true
}
FixMySQL
カラム名の打ち間違い(toatl)と、文字列を二重引用符で囲んだSQLを送ります。テーブル定義も一緒に渡します。
{
"schema": {"tables": {"orders": ["order_id", "total", "status", "created_at"]}},
"sql": "SELECT order_id, toatl FROM orders WHERE status = \"paid\""
}
結果では、二重引用符が文字列として扱われ、カラム名の間違いは「もしかして total?」という候補付きで指摘されます。
{
"success": false,
"repaired": "SELECT order_id, toatl FROM orders WHERE status = 'paid'",
"unresolved_errors": ["references unknown column \"toatl\" on table \"orders\" (not in the supplied schema) -- did you mean \"total\"?"]
}
success が false なのは、カラム名の間違いは人の判断が必要なので、自動では直さないためです。
FixMyMermaid
end をノード名に使った、描画できないフローチャートを送ります。
{
"diagram": "flowchart TD\n A[Start (v2)] --> B{OK?}\n B -->|Yes| end"
}
結果では、括弧を含むラベルが引用符で囲まれ、end が別のIDに置き換わります。表示するテキストはそのまま残ります。
{
"success": true,
"repaired": "flowchart TD\n A[\"Start (v2)\"] --> B{OK?}\n B -->|Yes| end_node[\"end\"]",
"changes": [
"quoted label of node \"A\" because it contains special characters: Start (v2)",
"renamed node id \"end\" to \"end_node\" (\"end\" is a reserved word in Mermaid flowcharts; display text kept)"
],
"syntax_was_broken": true
}
壊れ方の典型と、直し方の考え方
作ってみて分かったのは、「壊れ方」にはパターンがあるということでした。同じ問題に当たった方の参考になればと思い、まとめます。
JSON
-
構文の崩れ(末尾のカンマ、引用符の欠け、閉じ括弧の不足など): オープンソースの
json-repairで直します。 -
構文は正しいのに、形が違う(型が違う、必須項目がない、想定外の項目がある、配列のはずが単体のオブジェクトになっている): 構文の修復だけでは直りません。JSON Schemaと照らし合わせて検証し、安全に直せるものだけを直します。必須項目が抜けている場合は、値を推測して作らず、
unresolved_errorsに「この項目がない」と返します。
SQL
-
Markdownのコードブロックが付いたまま返ってくる、括弧が閉じていない、出力の上限で途中で切れている、装飾付きの引用符(‘ ’ など)が混ざっている、といった壊れ方は、構文解析の前に取り除きます。SQLの解析には
sqlglotを使っています。 -
文字列を二重引用符で囲んでしまう(
name = "bob")のが、いちばん厄介でした。SQLの標準では、二重引用符は「文字列」ではなく「列名などの識別子」を表します。そのため、構文エラーにならず、意味だけが静かに変わります。テーブル定義が渡されていて、その名前の列が実在しないと確認できたときだけ、文字列として直します。 -
存在しないテーブル・カラム名(いわゆる幻覚)は、自動では書き換えません。打ち間違いに近い候補があれば「もしかして
total?」と指摘するだけにしています。推測で書き換えると、別のカラムを指してしまう危険があるためです。
Mermaid
- 判定の基準は、自作のルールではなく、本物のMermaidのパーサーが受け付けるかどうかです。
success: trueは、Mermaid自身がその出力を受け付けたことを意味します。 - すでに正しい入力には手を加えません。
- 直し方は、見た目が変わらない方法を優先します。たとえば、括弧を含むラベルを引用符で囲んでも、表示は変わりません。
endのような予約語は、IDだけを置き換えて表示テキストを残します。 - 最後の行が途中で切れている場合など、内容を削る修正だけは、
content_removedとwarningsで明示します。黙って削ることはしません。
全体を通して、「直せたように見えて、実は意味が変わっている」出力がいちばん危ないと考え、確信が持てない場合は直さずに報告する方針にしています。
使い方と料金
RapidAPIに登録すると、各APIのページからコードのサンプル(cURL、Python、JavaScriptなど)をコピーして試せます。
- 無料プラン: 月100リクエストまで
- 従量課金プラン: 1リクエストあたり$0.001
注意点
- 無料の小さなサーバーで動かしているため、しばらく使われていないと、最初の1回だけ返事に30〜60秒ほどかかることがあります。
- 直せるのは、よくある壊れ方に限られます。直せないものは
unresolved_errorsに理由を返します。 - このAPI自体は、送られた内容を保存していません(利用回数を数えるだけです)。間に入るRapidAPI側のログの扱いは、RapidAPIの規約をご確認ください。
- 直した結果の正しさは保証できません。本番で使う場合は、結果を確認したうえでお使いください。
おわりに
「たまに壊れる」を、リトライではなく修復で吸収できれば、LLMを使ったプログラムの安定感はかなり違ってきます。使ってみて気づいたこと、直してほしい壊れ方があれば、コメントで教えていただけると励みになります。
この記事について
この記事は、AI(Claude)に下書きを手伝ってもらい、私が確認・修正して公開しています。