Phase 1 — 現断面を安定化
A/Bを再実行し、契約と成果物最低条件が連続して通ることを確認。チェックポイントコミットを作る。
契約駆動型マルチエージェント・コンテンツ生産基盤
現状設計書 — 2026年7月15日時点
本システムは、Dify上の複数AIエージェント、n8n、ComfyUIを連携させ、記事・X投稿・タグ・画像を一体の成果物パッケージとして生成するローカルAI基盤である。
従来は「Workflowが正常終了したか」が成功判定の中心だった。しかし、Planning / Researchが部分スキーマしか返さなくてもWritingが偶然本文を作り、空のX投稿や無関係な固定タグを含む成果物が成功扱いされる事象が発生した。これを契機に、工程成功・契約成功・成果物成功を分離して扱う設計へ移行している。
ローカル環境で、複数のAIエージェントが担当工程を分担し、再現性・監査性・拡張性を備えたコンテンツ生産ラインを構築する。
記事本文、X投稿、タグ、画像生成プロンプト、メタデータ。
handoff trace、artifact、logs、各工程DTO、契約状態、正規化履歴。
Dify → n8n → ファイル保存 / ComfyUI画像生成。
SEO、動画、翻訳、YouTube、SNS展開などの追加Agent。
Agentが何を主張するかは役割の範囲内で自由。ただし、機械が読むキー・型・階層はIF契約に従う。
後続工程はraw textではなく、契約整形済みDTOだけを参照する。
Normalizeは階層・型・既定の空値を整える。欠けた調査結果や成功条件を勝手に作文しない。
固定タグ、別項目からの意味転用、過剰な救済パースで異常を隠さない。
PlanningがfailedならResearchへ進めず、ResearchがfailedならWritingへ進めない。
記事・X投稿・タグ等の最低限成果物が揃って初めてパッケージ成功とする。
| 工程 | 主責務 | やってはいけないこと | 現状 |
|---|---|---|---|
| 入力正規化 | Start入力をWorkflow内部の確定値へ変換 | topicを勝手に生成する | 実装済み |
| 01 Planning | 企画、成功条件、構成、Researchへの問いを作る | handoffだけを返して外側DTOを省略する | 契約化済み |
| 02 Research | 調査結果、確認事項、リスク、Writing材料を作る | 企画情報を確認済み事実として転用する | 契約化済み |
| 03 Writing | 記事・X投稿・タグ・画像プロンプトを生成 | 本文だけ出して成果物一式を空で通す | 安定化中 |
| 04 Review | 成果物を評価し、修正要否を判定 | 本文や付随成果物を勝手に上書きする | 専用DTO導入済み |
| 05–06 | 必要な修正・画像関連の中間処理 | 前工程の契約違反を隠す | 既存実装 |
| 07 Audit | 最終品質・禁止事項・証跡を監査 | 成果物を上書きして辻褄を合わせる | 専用DTO導入済み |
| Package Output | 成果物と証跡を組み立て、最低条件を検査 | 固定タグや意味フォールバックで空を埋める | 最終防波堤を追加中 |
UI入力は任意欄を含むが、Workflow内部ではStart直後の入力正規化ノードで確定値にする。後続はStart Nodeを直接読まず、正規化済み値を参照する。
| 項目 | ユーザー未指定時 | 空許容 | 備考 |
|---|---|---|---|
| topic | デフォルトなし | 不可 | 空ならPlanning前にfailed |
| target_reader | 一般層 | 内部では不可 | 明示デフォルト |
| tone | 標準 | 内部では不可 | ユーザー指定優先 |
| article_length | 2000字前後 | 内部では不可 | ユーザー指定優先 |
{
"original": {"target_reader": "", "tone": "", "article_length": ""},
"normalized": {
"target_reader": "一般層",
"tone": "標準",
"article_length": "2000字前後"
},
"defaults_applied": ["target_reader", "tone", "article_length"]
}
DTO(Data Transfer Object)は、Agent間の受け渡し専用データ構造であり、内部API仕様に相当する。
| 属性 | 意味 |
|---|---|
| type | string / array[string] / object など、機械処理上の型 |
| required | キーまたは項目の存在が必須か |
| empty_allowed | 空文字・空配列・空objectを許すか |
| used_by | 実際に参照する後続ノード |
| violation_action | 正規化、警告、failedのどれにするか |
{
"raw": { "...": "LLMが実際に返した内容" },
"normalized": { "...": "規格化されたDTO" },
"contract": {
"status": "ok | normalized | failed",
"schema_valid_before_normalization": false,
"missing_required": [],
"defaulted_optional": [],
"fallback_from_start": [],
"moved_fields": [],
"invalid_types": [],
"notes": []
}
}
| field | type | 必須 | 空可 | 違反時 |
|---|---|---|---|---|
| stage | string | Yes | No | 欠落はnormalized、異なる値はfailed |
| task_summary | string | Yes | No | start.topicから補完可 |
| target_reader | string | Yes | No | 入力正規化値から補完 |
| tone | string | Yes | No | 入力正規化値から補完 |
| article_length | string | Yes | No | 入力正規化値から補完 |
| success_criteria | array[string] | No | Yes | []へ正規化。意味生成禁止 |
| sections | array[string] | No | Yes | []へ正規化 |
| assumptions | array[string] | No | Yes | []へ正規化 |
| handoff | object | Yes | No | 子項目を取得不能ならfailed |
| handoff.research_questions | array[string] | Yes | No | トップレベルから移動可。空ならfailed |
| handoff.writing_requirements | array[string] | Yes | No | トップレベルから移動可。空ならfailed |
| handoff.image_direction | string | No | Yes | ""へ正規化 |
| field | type | 必須 | 空可 | 違反時 |
|---|---|---|---|---|
| stage | string | Yes | No | 欠落はnormalized、異なる値はfailed |
| research_summary | string | Yes | No | 他項目からの転用禁止。空ならfailed |
| confirmed_points | array[string] | No | Yes | []へ正規化 |
| local_or_general_knowledge | array[string] | No | Yes | []へ正規化 |
| needs_external_verification | array[string] | No | Yes | []へ正規化 |
| source_notes | array[string] | No | Yes | []へ正規化 |
| risks | array[string] | No | Yes | []へ正規化 |
| handoff | object | Yes | No | 主要材料なしならfailed |
| handoff.usable_material | array[string] | Yes | No | トップレベルから移動可。空ならfailed |
| handoff.claims_to_avoid | array[string] | No | Yes | []へ正規化 |
research_summary = planning.task_summaryconfirmed_points = planning.success_criteria| status | 条件 | 後続 |
|---|---|---|
| ok | rawが最初から期待スキーマ・型・階層を満たす | 進行 |
| normalized | stage欠落、handoff階層移動、任意項目空値化、確定入力値による補完 | 進行可能。証跡・警告を残す |
| failed | JSON解釈不能、異なるstage、必須項目空、必須配列空、修復不能な型異常 | 次のAgentへ進ませない |
Planning Agent → Planning Normalize → Planning Contract Gate → Research Agent → Research Normalize → Research Contract Gate → Writing Agent
Planning failed時にResearchを走らせない。Research failed時にWritingを走らせない。これにより、壊れた部分情報を後続が「それっぽく」利用して成果物を作るサイレントフェイルを防ぐ。
Planning / Research契約が正常でも、Writingが空成果物を返すケースが確認された。Package Outputに最低限チェックを置き、空の正常成果物を禁止する。
| 成果物 | 最低条件 | 不正例 |
|---|---|---|
| article_markdown | string、trim後に空不可 | "" |
| x_posts | array[string]、1件以上、空要素不可 | [], ["x_posts"] |
| tags | array[string]、1件以上、空要素不可 | [], ["tags"], 別テーマ固定タグ |
"x_posts" / "tags"というキー名を拾った。契約整形により、元のAgent出力と後続が参照したデータを区別して残す。
| 情報 | 目的 |
|---|---|
| raw | LLMが実際に返した内容。原因追跡とモデル挙動確認。 |
| normalized | 後続が参照した規格DTO。 |
| contract.status | ok / normalized / failedの判定。 |
| raw_keys | 元出力に存在したキー一覧。 |
| moved_fields | トップレベルからhandoffへ移動した項目。 |
| fallback_from_start | 確定入力値から補完した項目。 |
| defaulted_optional | 任意欠落を空値へ正規化した項目。 |
| missing_required / invalid_types | 契約違反の原因。 |
証跡はhandoff_trace / artifact / logs / Audit DTO / Package Outputへ渡し、後から「Agentが自力で契約を守ったか、構造整形が発動したか」を確認可能にする。
Planning:handoffだけ返却(外側スキーマ欠落) Research:handoffだけ返却(外側スキーマ欠落) Writing:部分情報だけで本文を生成 Review / Audit:通過 Package:成功 結果:本文は良いが、X投稿は ["x_posts"]、タグは別テーマ固定値
構文上正しいJSONや自然な本文が生成されるため、クラッシュより発見が難しい。契約ゲートと成果物最低条件の両方が必要である。
| ケース | 入力特性 | 主目的 |
|---|---|---|
| A:メトロイド | 具体的・レトロゲーム・明示指定あり | 従来正常系の回帰、Research完全DTO、成果物一式 |
| B:AIの素晴らしさ | 抽象的・任意入力空 | 入力デフォルト、JSON遵守揺れ、タグ/X投稿の誤救済 |
["x_posts"]、["tags"]を拒否。A/Bを再実行し、契約と成果物最低条件が連続して通ることを確認。チェックポイントコミットを作る。
article_markdown / x_posts / tags / image_promptの型・必須・空許容・救済範囲を定義。Writing直後にNormalize / Gateを配置。
成果物パッケージのIF、Review判定、Audit判定を仕様書として統一。
error_code、retry戦略、timeout、needs_human_check、trace_id、DTO versionを導入。
固定テストデータと期待契約をリポジトリ管理し、新Agent追加時も既存ラインを保護。
| 判断 | 理由 |
|---|---|
| 入力デフォルトはStart直後に確定 | 契約整形ノードが場当たり的に意味を作ることを防ぐ。 |
| 生LLM出力を後続が直接読まない | 入力形状の揺れを1か所で吸収し、責務を限定する。 |
| 任意欠落は空値へ、必須空はfailed | 構造の安定と意味不足の検出を両立する。 |
| Planning情報をResearch結果へ転用しない | 企画条件と確認済み事実は意味が異なる。 |
| プロンプト補強と機械ゲートを併用 | プロンプトは遵守確率を上げるだけで、保証にはならない。 |
| 固定タグフォールバックを削除 | 欠落を隠し、別テーマ情報を混入させるサイレントフェイルになる。 |
| Packageを最終防波堤にする | 上流契約が正常でも、最終成果物が空になる可能性がある。 |
| 将来はWriting直後へゲートを前倒し | Review / Auditへ空成果物を渡さず、障害点の近くで止める。 |