[Dify]メモ書きからQiita記事を作るAIエージェント作ってみた

# はじめに
近年、生成AIの分野は急速に進化しており、中でもAIエージェントの分野は注目を集めています。業務上AIエージェントを利用する機会があり、学習もかねて、記事テーマを指定したメモをもとにQiitaの記事を作成するAIエージェントを作成してみました。

あるあるだと思いますが、なにかアイデアは思いついても記事に起こすのが億劫で、気づいたら何を書こうとしていたか忘れていて・・といった経験が私はよくあります。
その点、箇条書きのメモさえ用意すれば、そこからある程度記事っぽい文章を起こしてくれるツールがあれば少しは執筆が捗るのでは？との思いから、記事作成エージェントの作成に至りました。

# 利用環境
AIエージェント作成にはDifyを使用しました。DifyはGUI上でワークフローを構築しながらAIエージェントの作成ができるツールであり、SaaS版とオープンソース版が提供されており、今回はSaaS版を使用しています。
ほかにもチャットボットを作ったり、手軽にRAGを構築したりと、Difyの活用方法は多岐にわたります。詳細は以下をご覧ください。

なお、ワークフロー内のモデルはすべてGPT-4oを使用しています。

https://dify.ai/jp
# 要件
今回目指した要件は以下の通りです。
- 記事テーマを指定したメモをインプットすると、記事らしい文章構成になったテキストが出力される
- メモの内容(メモの本文や、明示されたリンク)からのみ情報を参照する。LLMの判断で他のサイトを調査したりすることを認めない(アイデアは人間が考えて、それを記事の形に起こすことだけをAIにさせたい)
- 図や表が必要であれば後で手動で作成・挿入するため、AIエージェントに図表の作成等は求めない
- 出力されるテキストの文体は過去の自分の記事と似たものになる
- 最終的には手動で編集を加えることが前提なので、7、8割程度完成されたテキストが出力されればよい

# ワークフローの概要
以下が構築したワークフローの全容です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/81c97262-f91f-4364-b610-c3a05ec59ddb.png)


かなり見づらくなってしまったので最初から順にみていきます。



## メモ入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/d2848224-9f61-4124-915e-de344d82ba00.png)

まず開始部分では、記事テーマを指定したメモをテキストとして入力します。

## テキストの分割
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/f58c0ba4-dbc8-4955-af83-46720ed0ea48.png)



次に、LLMでこのテキストを読んでもらい、「はじめに」「本論」「所感」の3つにテキストを分割します。
過去の自分の記事はだいたい「はじめに」「本論(調べたものの詳細は作ったものの説明)」「所感」の構成にしているので、それに沿った構成にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/56690bc7-74e6-4f4f-bdf8-074d9803b07e.png)

工夫として、ここではJSON Schemaを使用しています。これを利用することで、あらかじめ定めたJSONの構造に合った出力を確実にさせることができます。
「JSON Parse」ツールを使用して、出力されたJSONから指定のデータを取得することで、3つのテキストのまとまりをそれぞれ確実に個別の変数に格納できます。


## 並列でのテキスト生成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/1a39e37e-4e2d-4113-b0c3-4e4e370b8e36.png)
上記で分割した3つのテキストから、それぞれ文章を生成します。ここで箇条書きの羅列から、技術記事っぽい文章が生まれることになります。

ここで文章生成するLLMには、以下のシステムプロンプトを与えています。
重要なのは「制約」の部分です。はじめは入力したメモに書かれていないことも勝手に書き足したり、勝手に要約して出力してしまっていたので、それを防ぐために追加したプロンプトです。
```
あなたは技術ブログのライターです。

与えられたテキストから、技術ブログにふさわしい文章を考え、出力します。
文章作成に当たり、以下の制約を必ず守ってください。

制約：
・受け取ったテキストに含まれる情報を一切削ぎ落としてはならない
・受け取ったテキストに含まれない情報を一切付け足してはならない
```

## テキスト結合と文体変換ワークフローへの入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/8797e71e-e9e7-4da9-a527-e3a4b2d2e25d.png)

ここでは並列で生成したテキストを「はじめに」「本論」「所感」の順で結合し、「文体変換」ワークフローに渡します。文体変換ワークフローから出力された結果を受け取り、そのまま終了します。
処理としては以上です。

あとはこの文体変換ワークフローがどのような処理か、中身を説明していきます。
# 文体変換ワークフロー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/ad1df056-1c99-4bbd-8f32-2a81775517b0.png)

横に長くて見づらいので、こちらも順に説明します。
## 過去のQiita記事を取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/5e5eb542-9eb4-4529-a860-28c1e9568161.png)
開始ブロックで文体変換前のテキストを受け取るのですが、まだ使用しません。
ここではJina Reader APIを使用して、過去の筆者のQiita記事にアクセスし、記事本文を取得しています。
Jina Reader APIはWebサイトの情報をLLMに入力しやすい形に変換して返してくれます。

https://jina.ai/reader/

コードブロックに配列としてQiita記事のURLを持たせて、そのURLの数だけ「Jina Reader APIでアクセス→レスポンスから本文だけを抽出」というループを回しています。

:::note info
ちなみにここで取得しているQiita記事は以下の4本です。
いずれもブロックチェーンに関する記事で、AIとは関連しないのですが、よければ見ていただけると嬉しいです。

- [Worldcoin・World IDの概要
](https://qiita.com/somk_2301/items/a3996a67bc974a75937b)
- [【ERC4337】Thirdwebを使用したアカウント抽象化(Account Abstraction)を理解する](https://qiita.com/somk_2301/items/68e389bf047e0221f5ba)
- [【Ethereum】メッセージ署名について調べてみた
](https://qiita.com/somk_2301/items/1db499752b7858a6c8ee)
 - [【Ethereum】revertしたトランザクションのデバッグ方法](https://qiita.com/somk_2301/items/a39d6baf681f07fbcf69)
:::

## 文体の分析と変換
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/8c30f826-3f51-45c0-9f30-f174d4917cb9.png)

次に取得した記事をすべてLLMに入力し、文体の特徴を分析し、箇条書きで出力します。出力された特徴をもとに、開始ブロックで受け取ったテキストを文体変換しています。

文体分析では、以下のシステムプロンプトを入力しています。
```
あなたは与えられたテキストの文体や特徴を分析する専門家です。

あなたが出力した文体や特徴に沿って、後続の他のエージェントがテキスト生成を行います。そのために、あなたは分析結果を明確で理解可能な形式にまとめる必要があります。

ただし、以下の制約を必ず守ってください。
制約：
・一人称や語尾、語彙、言い回しなどの文体のみを分析対象とする
・テキストの技術的な内容については分析対象外とする
```
ここも「制約」の内容がポイントです。これがないと、入力したテキストの内容まで学習してしまいます（今回はブロックチェーンに関する技術記事を入力したので、制約なしの場合、文体変換時にブロックチェーン関連の話題を変に付け足してしまうことが多かったです）。

補足ですが、文体の分析と変換はわざわざ別のステップに分けずに、一つのLLMで行うことも可能です。実際それも試しましたが、感覚的にはやはり処理内容が異なるタスクは分けたほうが精度が上がりそうです。
また、この手法はAnthropicが公開している「Building effective agents」でも、「Prompt chaining」として紹介されています。

https://www.anthropic.com/engineering/building-effective-agents



## 変換結果の評価
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/01c9d59d-0df6-49fc-abba-b1e1cc9979eb.png)
文体変換後のテキストのブラッシュアップ機構です。
文体分析の結果をそのまま評価基準としてLLMに入力し、基準に沿った変換がなされているか評価しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/22385ca2-628c-4865-902c-c8b425d9f48f.png)
評価結果は1~10の得点と、その採点をした理由、合格/不合格(得点が5以上なら合格)で出力するようにしています。それをパラメータ抽出ブロックで上記のように設定し、それぞれ変数に格納しています。

ちなみに、パラメータ抽出ブロックを使用しなくても、先述した[JSON Schema](#テキストの分割)を使用して、はじめからLLMの出力を固定すれば同じことが実現できますが、今回はDify学習の意図もあったので、あえてこのやり方をとっています。

## 評価結果による分岐
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3673338/46c1f94e-8def-43a6-ac22-652d53542f10.png)
評価結果には「合格/不合格」のいずれかが含まれているので、その内容に応じて処理を分岐させています。
「合格」なら、一定以上の品質で文体変換が行われていることがわかるので、ワークフローを終了します。
「不合格」なら、再度文体変換を行い、ブラッシュアップしてから終了します。この時、評価理由も渡すことで、改善すべきポイントを明確に指示できるよう工夫しています。

本来であれば、改善作業の部分はループ化し、合格となるまで（あるいは一定回数以上やっても改善が見られないとわかるまで）ループさせるようにフローを組むつもりでした。ただ記事執筆時点のループブロックは使い勝手が悪く(ループ終了後のテキストを終了ブロックに渡せない？)、実装が大変そうだったのでこの形としました。

# 実行してみる
以下のテキストを入力してみます。Difyについての簡易調査記事という設定です。
```
Difyについて

・オープンソースのAIアプリ開発プラットフォーム

・今後業務で扱うので先立って調査した

・Difyの概要
	・ローコード・ノーコードツール
	・SaaS or コミュニティ版(Dockerでセルフホスト)
	・SaaS料金はプラン制(https://dify.ai/jp/pricing)
	SANDBOX：無料、PROFESSIONAL:$59/月、TEAM:＄159/月
	・開発元はLangGenius.inc(https://github.com/langgenius)
	・Difyの活用事例(https://dify.tdse.jp/post_column/234/)
	マーケティングの分析作業、幅広い業務に対応できるチャットボット、広告用のバナー作成など10選
・機能の特徴
	・GUIで直感的に操作できる(ワークフローの画像添付)
	・チャットボット/エージェント/テキスト生成/チャットフロー/ワークフローの機能あり
	・RAGも構築可能(ナレッジ機能の画像添付)
	

・RAG構築までできるのは便利そう
・Langchain等で作成するよりかなりお手軽に見える
・セルフホストできるのは良い。SaaSだけの展開より扱いやすい

気になったこと
・実際どれくらい操作しやすい？
・固有知識はどれくらい必要？学習コストは？
→試したい。SaaS版の無料プランを使ってみる

```
これをQiita記事として起こしてもらったのが以下です。
なお、ワークフローの内のLLMモデルはすべてGPT-4oを使用しています。
```
# はじめに
近年、AI技術が飛躍的に進化する中、オープンソースのAIアプリ開発プラットフォームである「Dify」に注目が集まっています。
本記事では、業務でDifyを扱う予定があるため、その機能や特徴について調査した結果を共有します。Difyの導入を検討している方や、AIアプリ開発に興味がある方々にとって有益な情報を提供できれば幸いです。

## Difyの概要
Difyはローコード・ノーコードツールとして、技術的なハードルを下げた開発を可能にするプラットフォームです。提供形態はSaaSとしてクラウド上で利用する方法と、コミュニティ版としてDockerを用いたセルフホスティングの2つがあります。
SaaS版の料金プランは複数存在し、SANDBOXは無料で利用可能で、PROFESSIONALプランは月額$59、TEAMプランは月額$159で提供されています。
Difyの開発元はLangGenius.incであり、その詳細はGitHubリポジトリでも確認できます。
## 活用事例
Difyの活用事例としては、マーケティングの分析作業やチャットボットを活用した幅広い業務、さらには広告用のバナー作成など、多岐にわたる利用用途が挙げられています。これらの事例に関する詳細情報はこちらで提供されています。
## 機能の特徴
Difyには直感的なGUIを用いた操作ができる機能が備わっており、ユーザーは簡単にワークフローを構築できます。以下はワークフローについての図です。また、チャットボットやエージェント、テキスト生成、チャットフロー、さらにワークフローの構築が可能です。
さらに、RAG（Retrospective Analysis of Generations）も構築可能であり、ナレッジ機能に関しての情報は以下の画像に示されています。
## 所感
今回の記事を通じて、RAG構築が非常に手軽に行える点が魅力的だと感じました。特にLangchainなどの他の選択肢と比較しても、より簡単に取り組めるように見える点は大きな利点です。また、セルフホスティングが可能であるという点もSaaSのみの展開に比べて柔軟性があり、利用しやすさにつながるでしょう。
今後の展望としては、実際の操作性や要求される固有の知識、および学習コストについてさらに理解を深めていきたいと思います。これを試す一つの方法としてSaaS版の無料プランを利用してみることを検討しています。このように手軽に試行できる環境があることは非常にありがたいですね。
```
記事の構成としては問題なさそうです。「以下の画像に示されています」のような、あとで手動で画像を添付することが前提の書き方をしてるのも期待通りでした。

ただ、文体の変換に関しては正直微妙でした。
特に所感の、
「利用しやすさにつながるでしょう」
「このように手軽に試行できる環境があることは非常にありがたいですね。」
これは自分ではまず使わない表現です(ここら辺の感覚は筆者自身しかわからないものですが)。

そもそも特徴的な文体ではない(普通のですます調)、学習させた記事の量が少ないなど、いくつか原因は考えられますが、ここは改善の余地があると思いました。
# 所感
とりあえず使えなくはないものが作れた、といった結果でした。精度はまだまだ改善の余地がありますが、どちらかといえばDifyの学習という意図で作ったものでもあるので、まあ良しとしています。

また、次はもう少し複雑なタスクを処理するエージェントを作ってみたいなと思いました。
この程度であれば、エージェントを用意しなくてもChatGPT等と何ラリーか会話すればすぐにできそうな気もしたので・・
画像や音声を使ったマルチモーダルな処理を含んだり、実行するべきタスクを動的に変化させるようなワークフローであればよりAIエージェントならではの利点が見えそうなので、取り組んでみます。