概要
flask-openapi3を使って、独自処理をDifyのカスタムツール化する方法のメモです。
背景
DifyはLLMアプリケーションをノーコードで作れるツールです。とても便利ですが、組み込みツールだけだと、実現できる処理の自由度に限界があります。
ローカルでAPIを作ってカスタムツールとして登録できれば、開発の自由度が高まることが期待されます。
Difyでは、OpenAPIの仕様に沿って作られたAPIは簡単にカスタムツールとして登録することができます。そこで、flask-openapi3を使って、pythonでローカル実装された関数を、Difyのカスタムツールに登録することを試みました。
環境
-
flask-openapi3 バージョン3.1.3
pip install flask-openapi3
-
M1 Mac
-
pythonは3.11.2
-
Difyのクラウド版
-
ngrok(クラウド版からローカルのサーバーに到達できるようにするために使用)
brew install ngrok
手順
ngrokの起動
ポート5000でAPIサーバを起動することを前提にngrokを実行します。このあと登場するpythonコードにngrokのURLを記載する必要があるので、先に実行します。
ngrok http 5000
実行後、Forwarding
という行に記載されたhttpsのURLをコピーしておきます。
ここでは仮に"https://ngrokaddress.app" としておきます。
flaskサーバの実行
flask-openapi3のgithubのservers_demo.pyを参考に、ユーザの入力をオウム返しするAPIを作ってみます。
from pydantic import BaseModel
from flask_openapi3 import Info, Tag
from flask_openapi3 import OpenAPI, Server
info = Info(title="Echo API", version="1.0.0")
servers = [
Server(url="https://ngrokaddress.app")
]
app = OpenAPI(__name__, info=info, servers=servers)
echo_tag = Tag(name="echo", description="echo your input")
class Query(BaseModel):
input_text: str
@app.get("/echo", tags=[echo_tag])
def echo_input(query: Query):
"""echo the text you input
to check server response
"""
return {
"code": 0,
"message": "ok",
"data": [
{"response": f"you input {query.input_text}" }
]
}
if __name__ == '__main__':
app.run(debug=True) # デフォルトポートは5000
実行します。
python app.py
エラーなく、実行できたらngrokのアドレスにブラウザからアクセスしてみます、ngrokを実行していなかったら実行してください。
ngrokのアドレス末尾に"/openapi"を付ける必要があることに注意してください。
(例:"https://ngrokaddress.app/openapi")
pypiのページにあるようなswagger, ReDocなどを選択できるページが表示されれば成功です。
"https://ngrokaddress.app/openapi/openapi.json"にアクセスするとAPIの仕様を表すjsonが見られます。Difyにはこれを登録します。
Difyのカスタムツールの作成
Dify > ツール > カスタム > カスタムツールを作成する > +URLからインポートする
と遷移し、表示されたテキストボックスに"https://ngrokaddress.app/openapi/openapi.json" を入力し、OKを押下します。その後「スキーマ」のテキストボックスにjsonが入力されたら成功です。
「利用可能なツール」のところに「echo_input_echo_get」という名前のメソッドが追加されていると思います。ソースコードの対応を整理すると先頭の"echo_input"がメソッド名、次のecho"がURLのパス、最後の"get"はリクエストのメソッド名に対応しているようです。
適当な名前をつけて、登録を完了したら、ワークフローなどの作成画面から作成したカスタムツールが選べるようになっています。
おわりに
flaskで作ったAPIをDifyのカスタムツールに登録することができました。Difyにpythonの独自関数をツールとして登録できると、やれることの幅が大きく広がるので、実装方法がわかってよかったです。flask-openopi3のお陰で、実装量を大幅に減らせたため開発者の方に感謝です。
今後の課題としては、無料版のngrokだと、URLがngrokの実行ごとに変わってしまって使いにくいので、なにか対応を考えたほうが良さそうです。
本記事がどなたかのお役に立てましたら幸いです。
補足
flask-openapi3のSimple Exampleそのままだとエラーになる
flask-openapi3のPyPIのトップページにあるSimple Exampleをそのままサーバとして用いると、カスタムツールからの登録に失敗します。invalid schema...みたいなメッセージが出ました。少し調べると、server(のurl)の情報がschemaに含まれていないためエラーになるようです。
info = Info(title="Echo API", version="1.0.0")
servers = [
Server(url="https://ngrokaddress.app")
]
app = OpenAPI(__name__, info=info, servers=servers)
本記事のapp.pyのようにServerクラスを使って、urlを与えることで、エラーを出さなくすることができました。