実は以前もDifyでSEO記事作成を試していました。その模様は「DifyでSEO記事作成を試してみる」に記載しています。ただ、このときはワークフローでの作成はあきらめ、エージェントを使用しています。理由は、当時ワークフローにIteration(ループ処理)がなかったためです。
しかし、2024年5月31日にDifyのv0.6.9がリリースされ、Iterationが実装されました!早速、Iterationを使用してSEO記事作成をやってみたいと思います。結論としてはできたのですが、実用レベルのものができたかというと、、、微妙なところです。
ただ、Iterationの使い方は伝わるんじゃないかと思いますので、ぜひ記事をご覧いただければと思います!
実は、今回Difyのワークフローでやろうとしていた仕組みはすでに弊社で持っていて、それを利用した「AI記事制作代行サービス」というものを提供しています。ちょうどいい値段で高品質の記事を継続的に作成したいという方はぜひご利用ください!
準備
Difyの環境を作る
今回はMacOSのローカルPC上で動作することを前提とします。
ローカルPC上にDifyを立ち上げる方法は、「DifyでSEO記事作成を試してみる」に詳しく記載していますので、そちらをご覧ください。
また、DifyはかなりアクティブなOSSで頻繁に更新されるため、最新のソースコードに更新しておく必要があります。その方法は「ローカル環境上のDifyでGPT-4oを使えるようにする」をご覧ください。
最新のDifyの仕様を理解する
Difyのワークフローで記事作成するためには、Iterationの機能が必要です。
プロンプト一撃で長い記事作成をしても質のいいものはできず、タスクを分解してなるべく小さい仕事をさせることが、LLMの出力の質を上げるための鉄則ですが、記事作成の場合もまずは見出し構成を決め、各見出しごとの小さく区切った記事作成を順次LLMに依頼するということをします。
そのため、「見出しごとに記事を出力する」という部分にループ処理が必要になり、そこにIterationを使用したいということです。
ということで、Iterationの使い方を調べてみましたが、、、全く情報がでてこない!なんで!?公式ドキュメントは情報の更新が追いついていないのでしょうか。この記事を書いている2024/06/14時点でワークフローのNodeにIterationがまだ追記されていません。
あるのはリリースを告知する動画のみ。ということで、かなり試行錯誤しながら進めました。結果だけを以下にまとめていますが、めちゃめちゃ大変でした。
Dify上でワークフローを設計する
入力と出力を決める
ワークフローは様々な処理をできる「ブロック」をつなぎ合わせて一連の処理を作成するというものです。そのワークフローを通して、最終的に何ができるようになるのかを、まず簡単に定義するところから始めます。
本記事では、以下を前提としてワークフローを作っていきたいと思います。
- 入力
- リライト元参考URL
- 上位表示したいキーワード
- 共起語
- サジェストワード
- 対象読者
- タイトル
- 導入文
- 記事作成の際の注意点
- 出力
- 見出し構成
- 各見出しの文章
つまり、既存の記事をもとに、キーワードや対象読者などある程度の情報は決めていることを前提に、既存の記事を要約して、リライトする形で記事作成をするワークフローを作成していきます。
処理プロセスを設計する
大まかに以下の処理プロセスで記事作成を目指していきます。
- 与えられたURLをスクレイピングして、記事の内容を取得
- 記事の内容をすべて要約し、それを端的に表現できる見出し構成を作る
- LLMで記事の要約を箇条書きで作成
- LLMで箇条書きを見出し構成に変換
- LLMで見出し構成を作成
- 各見出し毎に記事を作成
- テンプレートを作成し記事としてまとめる
Dify上でワークフローの各ブロックを作成する
全体像はこんな感じです。一つ一つのブロックで何をしているかを以下で説明します。
「え、、、記事作成するためにこんなに設定必要なの・・・?」と感じられた方、そうなんです・・・!実用的なAgentやワークフローを作るには、結構たいへんな設定をする必要があります。それをできるためには生成AIそのものやDifyの仕様に関する学習コストがそれなりに掛かります。
Difyを導入したいけど、そういう面倒なのはすべて任せてしまいたいというご要望がございましたら、ぜひお気軽にご連絡ください!
Step.1 Start
- ブロック Start
- 入力 上記入力項目すべて
- 出力 なし
ここは先程列挙した入力項目を指定するだけです。
Step.2 参照元URLの配列を作成
- ブロック Code
- 入力 URLの文字列
- 出力 文字列配列
Step.1でURLのリストを改行ありの文字列で入力されるため、それをPythonで配列に変換しています。これが必要な理由は、その後で使用するIterationの入力が配列形式である必要があるためです。
Step.3 全URLをスクレイピング
- ブロック Iteration
- 入力 URLの文字列配列
- 出力 文字列(スクレイピング結果)
Iterationはいわゆるループ処理を行うためのものです。Iterationを使用する場合は、Iterationそのものへの入力と、Iterationからの出力を指定する必要があります。
Step.3-1 各URLをスクレイピング
- ブロック Web Scraper
- 入力 item(Iterationのループ処理内で、各ループ毎に参照される配列の要素。ここでは一つ一つのURL)
- 出力 文字列(スクレイピング結果)
以前の記事ではCrawlerというToolを使用してURL内のコンテンツを取得しましたが、今回はCrawlerがなぜか動作しなかったため、Web Scraperという別のToolを使用しました。URLを渡せば、その内容を取得してくれます。
Step.4 スクレイピング結果をすべて結合
- ブロック Code
- 入力 スクレイピング結果の文字列配列
- 出力 文字列
このあとのステップで、与えたURLの内容をすべてマージして要約したいので、単純に全URLの記事の内容を結合してしまいます。
Step.5 記事の見出し構成をGPT-4oで作成
- ブロック LLM(モデルはGPT-4oを指定)
- 入力 文字列(前記事の内容を結合したもの)
- 出力 文字列(見出し構成案)
前記事の内容をGPT-4oに与え、それを箇条書きで要約し、それをもとにこれから作成する記事の見出し構成案を作ってもらいます。
Step.6 記事の見出し構成をGPT-4oがレビュー、修正
- ブロック LLM(モデルはGPT-4oを指定)
- 入力 文字列(見出し構成案)
- 出力 文字列(見出し構成最終案)
全Stepで作成した見出し構成案をGPT-4oにレビューさせ、修正させることで最適化します。このステップをいれることで結構質が上がります。
Step.7 見出し構成をPythonの配列の構成にする
- ブロック LLM(モデルはGPT-4oを指定)
- 入力 文字列(見出し構成最終案)
- 出力 文字列(配列型に整形した文字列)
このあたりからだいぶゴリ押しになってくるのですが、、、Iterationの制約として、A)ネストできない(2重以上のループができない)、B)入力が配列である必要がある(JSONを渡せない)というものがあり、これがネックになって「1:nの関係にある見出し1と見出し2を、見出し1のループを回して、その中で見出し2のループを回して記事作成する」ということがどうしてもできませんでした。
ちょっと伝わりづらいと思いますが、
[
["見出し1: 1つ目の見出し1", "見出し2: 1つ目の見出し2", "概要: 見出し2に対応する概要"],
["見出し1: 1つ目の見出し1", "見出し2: 2つ目の見出し2", "概要: 見出し2に対応する概要"],
["見出し1: 2つ目の見出し1", "見出し2: 1つ目の見出し2", "概要: 見出し2に対応する概要"],
...
["見出し1: n個目の見出し1", "見出し2: 1つ目の見出し2", "概要: 見出し2に対応する概要"],
["見出し1: n個目の見出し1", "見出し2: 2つ目の見出し2", "概要: 見出し2に対応する概要"],
...
["見出し1: n個目の見出し1", "見出し2: n個目の見出し2", "概要: 見出し2に対応する概要"]
]
みたいな配列をGPT-4oに作らせ、一旦文字列形式で出力します。
Step.8 「配列っぽい」文字列型のデータを配列型にする
- ブロック Code
- 入力 文字列(配列型に整形した文字列)
- 出力 文字列配列
LLMブロックは文字列しか出力できないため、前Stepでは配列っぽい構造を持ったデータを作って文字列として出力しました。これをPyhtonのプログラムで無理やり配列に変換し、Iterationに渡せるようにします。
Step.9 全見出しの記事を作成する
- ブロック Iteration
- 入力 文字列配列
- 出力 文字列配列(記事本文)
見出しの配列をループ処理で回しながら各見出しの記事本文を作成します。
Step.9-1 各見出しの記事を作成する
- ブロック LLM(モデルはGPT-4oを指定)
- 入力 item(Iterationのループ処理内で、各ループ毎に参照される配列の要素。ここでは見出し1、見出し2を組み合わせた文字列)
- 出力 文字列(記事本文)
Iterationから渡される見出し1と見出し2、その他Startで入力された情報などを下に、GPT-4oが記事本文を作成します。記事本文作成にあたっては、ほしい内容が出力されるように、結構細かい条件を指定しています。
Step.10 テンプレートを適用する
- ブロック Template
- 入力 文字列配列(記事本文)
- 出力 文字列
これはおまけのようなものですが、一応記事っぽく整形するために、タイトル、導入文、見出し、本文をテンプレートを使ってまとめます。DifyのTemplateはJinja2を使用しています。
出力を確認
よくわからない・・・笑
まとめ
工夫した点
- GPT-4oで見出し構成を作成したあとに、GPT-4oで見出し構成をレビューして修正させると結構いいものに仕上がります。
- Iterationで多重ループが使えないことと、JSONを入力できないという制約があるため、GPT-4oにPythonの配列っぽい文字列を作らせるという暴挙(?)により、一応全文ワークフローで出力することはできました。大変だった。。。
改善点、今回できなかった点
- GPT-4oに配列を作らせたりしているので、出力が安定せず、たまに配列構造ではないものが出力され、Pythonのエラーが吐かれることがあります。
- 見出し1 > 見出し2 > 本文、見出し2 > 本文、… > 本文、見出し1 > 見出し2 > … という構造に作成したかったのですが、これがどうしてもできませんでした。もっとワークフローを極めているかた、もしいいアイデアがあればぜひご連絡ください・・!