🛡️
AIエージェント×スキーマバリデーションでドキュメント生成を堅牢にする
概要
AIエージェントにドキュメントを生成させたら「思い通りのフォーマットにならない」ということがあります。ここでは Markdown → YAML → CUE の 3 段階でバリデーション強度を高めながら、同一のアウトプット品質 を実現する方法を紹介します。
- 1️⃣ まず“テンプレのみ”の Markdown 生成の弱点を確認
- 2️⃣ YAML スキーマで最小限の保証をかけ、Markdown へ変換
- 3️⃣ CUE で 検証と Markdown 出力を 1 ファイルで完結 させる方法を紹介
それぞれサンプルコード付きで解説します。
1. Markdown(バリデーションなし)
説明
- 自然言語テンプレ×AI でそのまま Markdown を生成する最短手段。
- 速いものの揺らぎ・抜け漏れが頻発し、CI で検知できない。
- ユースケース: ワンショットメモ・軽量ドキュメント。
プロンプト
以下のフォーマットで Markdown を生成してください
ファイル名は `YYYY-MM-DD-todo.md` としてください
タグは最低2つ、タスクは最低3つ必要です
```markdown
# YYYY-MM-DD の ToDo
[[YYYY-MM-DD]]
#tag1 #tag2
- 朝会で進捗共有
- PRレビュー
- スキーマバリデーション記事執筆
```
簡易的なものであれば成功率は高いですが、複雑になってくると抜けてくる項目が目立ってきます。()
2. YAML スキーマ
説明
-
YAML Schema +
ajv
で必須項目と型を厳密保証。 - Markdown への整形は別スクリプトで行う 2 ステップ構成。
- 利点: コマンド実行時に型不整合を弾ける。
- 課題: 変換スクリプト維持コスト。
サンプルコード
schema.yaml
$schema: "http://json-schema.org/draft-07/schema#"
title: "Daily ToDo Schema"
type: "object"
required:
- title
- date
- tags
- tasks
additionalProperties: false
properties:
title:
type: "string"
date:
type: "string"
pattern: "^\\d{4}-\\d{2}-\\d{2}$"
tags:
type: "array"
minItems: 2
items:
type: "string"
tasks:
type: "array"
minItems: 3
items:
type: "string"
todo.yaml(中間生成物)
title: "Daily Work Tasks"
date: "2024-06-21"
tags:
- "work"
- "urgent"
tasks:
- "Reply to client emails"
- "Prepare project report"
- "Team meeting at 15:00"
コマンド
バリデーション (ajv 使用)
npx ajv validate -s schema.yaml -d todo.yaml --strict=true
YAML → Markdown 変換は別途スクリプトを用意
プロンプト
以下の YAML Schema を満たす `todo.yaml` を生成してください。
以下のコマンドでスキーマを検証します。
```sh
npx ajv validate -s schema.yaml -d todo.yaml
```
3. CUE ― 検証と生成を 1 ファイルで
説明
- CUE は「スキーマ+データ+テンプレート」を 1 ファイルに統合できる宣言的 DSL。cuelang.org
-
cue cmd … gen
で 検証&Markdown 生成をワンショット。 - YAML Schema では煩雑な条件・計算ロジックをシンプルに表現可能。
サンプルコード(note_tool.cue)
※ cue cmd
を使う時は、*tool.cue
のようにファイル名を指定する必要があります。
import (
"strings"
"text/template"
"tool/file"
)
// ------------------------------
// To‑Do データ + バリデーション
// ------------------------------
item: {
title: string @tag(title)
date: =~"^\\d{4}-\\d{2}-\\d{2}.*$" @tag(date)
rawTags: string @tag(tags)
tagList: strings.Split(rawTags, ",")
taglistLength: {len(tagList) >= 2}
tags: tagList
rawTasks: string @tag(tasks)
taskList: strings.Split(rawTasks, ",")
taskListLength: {len(taskList) >= 1}
tasks: taskList
}
// ------------------------------
// Markdown テンプレート
// ------------------------------
mdTmpl: """
# {{ .title }}
[[{{ .date }}]]
{{ range .tags }}#{{ . }} {{ end }}
{{ range .tasks }}- {{ . }}
{{ end }}
"""
// ------------------------------
// Markdown 生成コマンド
// ------------------------------
command: gen: {
write: file.Create & {
filename: "\(item.date)_todo.md"
contents: template.Execute(mdTmpl, item)
}
}
コマンド
cue cmd \
--inject title="2025-05-06 の ToDo" \
--inject date="2025-05-06" \
--inject tags="work,ai,validation" \
--inject tasks="朝会で進捗共有,PRレビュー,スキーマバリデーション記事執筆" \
gen note_tool.cue
プロンプト
`cue cmd` を使って TODOファイルを生成してください
以下例
```sh
cue cmd \
--inject title="2025-05-06 の ToDo" \
...
```
まとめ
手法 | 構造保証 | 変換ステップ | 運用コスト | おすすめ用途 |
---|---|---|---|---|
Markdownのみ | なし | 0 | ★ | メモ・ドラフト |
YAML Schema | 必須 & 型 | 1 (検証) + 1 (変換) | ★★ | 中規模ドキュメント |
CUE | 必須 & 型 & 高度ロジック | 1 (検証+生成) | ★★★ | 継続運用する記事生成 |
Takeaway: “AI だから壊れる”はもう古い。CUE まで踏み込めば、指示→検証→完成 を 1 コマンドで自動化し、エージェントドリブンなドキュメント生成を安全にスケールできます。
Discussion