皆さんこんにちは、横浜で清掃業をしているヤスです。
前回はAIツールを1つずつ使うのをやめました。「AIを会社にする」という考え方というワークフローの設計思想についてお話ししました。今回はその実装編です。実際にDifyの画面でどのノードを置き、どこでつまずいたのかを、作業ログのまま実況形式でお伝えします。
[スクショ:完成したワークフロー全体図(開始→AI広報部長→ループ→出力)]
結論から:3周のループで、URL付きの投稿が「リプライ案内」に直った
先に完成形をお見せします。作ったのは、X投稿を自動生成し、検品LLMが不合格を出したら修正指示を添えて作り直させるワークフローです。
検品なしだと、AIが作った投稿をそのまま使うしかなく、質が安定しませんでした。検品ありにしてからは、不合格なら指摘を踏まえて自動で修正し、今回は3周で公開できる品質に到達しました。
実際のテストでは、1周目に作った投稿の末尾にUdemyのURLが入っていました。検品LLMはこれを不合格と判定し、「URLを削除し、詳細はリプライで案内する導線に直すこと」という修正指示を返しました。2〜3周目でAI X社員がこれを反映し、最終的にこうなりました。
「プログラミングは無理」と思っていた49歳の私が、AIアプリを作れるようになりました。
IT未経験からDifyを独学し、30分かかっていたエラー文作成が5分に。
この実体験をもとに、初心者向けのUdemy講座を作りました。
始めるのに遅すぎることはありません。詳細はリプライでご案内します。
URLが本文から消え、運用ルールに沿った締めに変わっています。ここからは、この仕組みをどう組んだかを順番に書いていきます。
作り方:ループの中に「社員」と「検査担当」を分けて置く
全体の骨格を組む
まず「開始 → AI広報部長 → ループ → 出力」という流れを作りました。ループの中身は「AI X社員が投稿を作る → 検品LLMが判定する → IF/ELSEで合格・不合格を分ける」の並びです。検品と条件分岐はループの外の親ワークフローに置いています。仕事をする社員と、品質をチェックする検査担当の役割を分けるためです。
AI X社員をツール化する
AI X社員は「開始→LLM①→回答」だけの、極めてシンプルなツールにしました。判定や分岐のロジックをツールの中に持ち込むと、何が起きているか追えなくなるためです。
ループ変数を2つ用意する
ループブロックの設定画面で、周回をまたいで持ち越したい情報を登録します。previous_post(String/Constant/初期値は空)とrevision_feedback(String/Constant/初期値は空)の2つを作りました。初期値を空にしておくことで、1周目は新規作成、2周目以降は前回の内容が入る形になります。
[スクショ:ループブロックの変数設定画面]
検品LLMに構造化出力を設定する
IF/ELSEで機械的に判定するには、検品LLMが「判定」を明確な形で返す必要があります。judgment(合格/不合格)、score(35点満点)、good_points、problems、revision_feedbackの5項目を構造化出力として設定しました。ループ終了条件は「検品LLM→structured_output→judgmentが『合格』である」に設定しています。
最大ループ回数を下げる
初期値の10から、3〜5に下げました。検品でLLMを毎回動かすとコストと時間がかかるためです。10回連続で不合格になるようなら、それは検品基準かプロンプト側に問題があるサインだと考えています。
不合格ルートに変数代入ノードを追加する
IF/ELSEのELSE(不合格)の先に、変数代入ノードを置きました。previous_postにはAI X社員のtext(今回作った投稿)を、revision_feedbackには検品LLMのstructured_outputの中のrevision_feedbackだけを指定します。ここでループを回すだけでは検品の指摘が活きないため、次の周回に「何を直すべきか」を渡す仕組みが必要でした。
[スクショ:変数代入ノードの設定画面(子項目まで掘り下げた状態)]
AI X社員側に受け口を作る
保存した情報を受け取る入口がなければ意味がありません。AI X社員Toolの開始ブロックに、previous_postとrevision_feedbackの入力フィールドを追加しました。どちらも必須のチェックは外しています。初回は空で来るためです。あわせてプロンプトにも、前回の投稿と修正指示が空なら新規作成、内容があれば指摘を反映して改善版を作る、というルールを追加しました。
合格ルートにも変数代入を置く
IF(合格)の先にも変数代入ノードを追加し、previous_postにAI X社員のtextを保存するようにしました。これで合格でも不合格でも、最新の投稿が必ずprevious_postに入る状態になります。
出力ブロックでループ変数を指定する
最後に、出力ブロックで「ループ/previous_post」を指定して完成です。
つまずきポイント:ここが一番生々しい
①判定用の変数を間違えていた
最初、IF/ELSEの条件がreasoning_content(LLMの内部推論用の出力)を見ていました。判定用の変数としては不適切です。構造化出力のjudgmentを見るように直しました。
②構造化出力で400エラー
テスト実行したら、こんなエラーが出ました。
[models] Bad Request Error, Error code: 400 Invalid schema for response_format 'llm_response': 'required' is required to be supplied and to be an array including every key in properties. Missing 'judgment'.
原因は、構造化出力のスキーマで全フィールドをrequired(必須)に指定していなかったことでした。使っているモデルが、全項目の必須指定を求めていたのです。required配列にすべてのフィールド名を書いて解決しました。
"required": ["judgment", "score", "good_points", "problems", "revision_feedback"]
③2つの箱に同じものを入れてしまった
変数代入で、previous_postとrevision_feedbackの両方に「検品LLM/text」を指定してしまったことがありました。これでは2つの箱に同じ内容が入り、区別がつきません。前回の投稿はAI X社員の出力、修正指示は検品LLMの出力と、別々のものを入れる必要があります。
④Object全体を指定してしまったstructured_output(Object全体)をそのまま指定してしまい、judgmentもscoreも全部ひとまとめに入ってしまったこともありました。変数選択パネルで「>」を押して子項目まで掘り下げ、revision_feedbackだけを選ぶ必要がありました。
⑤受け口がなく、修正指示が活きていなかった
一度は「構成が複雑になるから」とprevious_postとrevision_feedbackをAI X社員の入力から外していました。しかし修正ループを機能させるには必須で、結局戻すことになりました。
⑥合格しても出力が空になるところだった
ループを抜けた後、出力ブロックで合格した投稿を出そうとしたら、選べる変数が「previous_post」と「revision_feedback」しかありませんでした。ループの外からはループ内のノードを直接参照できない、というDifyの仕様です。合格ルートにも変数代入を追加して、初めて出力できるようになりました。
⑦検品が甘くて平凡な投稿が素通りした
最初のテストでは、質の低い投稿が合格してしまいました。基準を「32〜35点なら合格」という明確な点数に変更し、URLが含まれる場合や冒頭のフックが弱い場合は高得点でも不合格にする、という例外ルールを加えました。厳しくすると周回数は増えますが、最大ループ回数で止まるので暴走はしません。今回は3周で合格に着地し、バランスは悪くなかったと感じています。
[スクショ:実行追跡でloop_countとrevision_feedbackが更新されていく様子]
まとめ:まず「ループ変数を2つ作る」ところから
今回作ったのは、AI X社員(作る)・検品LLM(採点する)・ループ変数(前回の内容と修正指示を橋渡しする)の3つを組み合わせた仕組みです。
これから同じものを作るなら、いきなり全体を組もうとせず、まずループブロックにprevious_postとrevision_feedbackという2つのループ変数を作るところから始めてみてください。この2つの箱があることで、初めて「不合格なら直す」が成立します。
次回はさらに失敗した話をさらけだしちゃいますので参考にしてもらえればと思います。
今回のピックアップ記事はこちらです
【完全自動化】MakeとDifyを連携!SEO順位チェック→AI改善提案ループの作り方
次回もお楽しみに!


コメント