「Difyソースコードリーディング #4 - モデルやツールのYAMLファイルの扱いを読み解く」を開催しました #もくもくDify

ジェネラティブエージェンツの大嶋です。

もくもくDifyで「Difyソースコードリーディング #4 - モデルやツールのYAMLファイルの扱いを読み解く」というイベントを開催しました。

dify-mokumoku.connpass.com

アーカイブ動画はこちらです。

youtube.com

Difyのソースコードは以下です。

github.com

今回も 戸塚さん と一緒に話しながらコードを読んでいきました!

今回のポイント

Difyに組み込みのツールを追加する方法

今回まずは、Difyに組み込みのツールを追加する処理がどのように実装されているのかを探していきました。

Difyに組み込みのツールを追加する方法は、api/core/tools/README.mdapi/core/tools/docs ディレクトリのドキュメントに書かれていました。

現状は英語と中国語のドキュメントのみですが、戸塚さんが日本語版のプルリクエストを出してくれているそうです。

プルリクエスト:https://github.com/langgenius/dify/pull/8469

組み込みツールの追加の例

組み込みツールの追加の例として、Discordのツールを追加するプルリクエストも参考に見ていきました。

プルリクエスト:https://github.com/langgenius/dify/pull/7852

そのツール特有の処理を行うクラスを実装し、ツールの名前やパラメータをYAMLファイルに記述するだけで、組み込みのツールが追加されるようです。

YAMlファイルの構造の定義

ツールの名前やパラメータを記述するYAMLファイルの構造は、tool_entities.py というファイルに定義されていました。

たとえばToolParameterというクラスが以下のように定義されています。

class ToolParameter(BaseModel):
        :
    name: str = Field(..., description="The name of the parameter")
    label: I18nObject = Field(..., description="The label presented to the user")
    human_description: Optional[I18nObject] = Field(None, description="The description presented to the user")

ツールの読み込みの実装

ツールを追加する際、そのツール用のPythonファイルとYAMLファイルだけ記述すればいいということは、どこかでツールの実装を動的にimportしているはずです。

builtin_tool_provider.py を見ると、以下のようにツールのモジュール名からサブクラスをロードしている箇所がありました。

            assistant_tool_class = load_single_subclass_from_source(
                module_name=f"core.tools.provider.builtin.{provider}.tools.{tool_name}",
                script_path=path.join(
                    path.dirname(path.realpath(__file__)), "builtin", provider, "tools", f"{tool_name}.py"
                ),
                parent_type=BuiltinTool,
            )

load_single_subclass_from_sourceの実装は module_import_helper.py にあり、

以下のように動的にモジュールを読み込んでいることがわかりました。

        module = importlib.util.module_from_spec(spec)

importlib.util.module_from_specはPythonの標準ライブラリの関数で、モジュールの動的なimportなどに使えるようです。 この関数は知らなかったので勉強になりました。

参考:https://docs.python.org/ja/3/library/importlib.html#importlib.util.module_from_spec

組み込みのモデルについて

その後、組み込みのモデルについても見ていきました。

基本的に同じような構造になっていて、モデルを追加する際に記述するYAMLファイルの構造は model_entities.py で定義されており、組み込みモデルの動的なimportは model_provider.py で実装されているようでした。

モデルやツールを追加しやすいよう動的に読み込んでいるしくみは、なかなか面白かったです!

次回のご案内

次回は「ナレッジベース・RAGの実装を読み解く」というテーマです。 ご興味ある方はぜひ気軽にご参加ください!

dify-mokumoku.connpass.com

また、水曜日にもDifyの活用についてのもくもく会があります。 こちらもご興味ある方はぜひ気軽にご参加ください!

dify-mokumoku.connpass.com

「AIエージェントキャッチアップ #1 - AutoGen / AutoGen Studio」を開催しました

ジェネラティブエージェンツの大嶋です。

「AIエージェントキャッチアップ #1 - AutoGen / AutoGen Studio」という勉強会を開催しました。

generative-agents.connpass.com

アーカイブ動画はこちらです。

youtube.com

AutoGen / AutoGen Studio

今回は、AutoGen / AutoGen Studioについて、ドキュメントを読んだり、実際に動かしてみたりしてキャッチアップしていきました。

AutoGenはこちらです。

github.com

AutoGen Studioはこちらです。

github.com

どちらも公式ドキュメントに記載されている手順ですぐに動きました!

フレームワークによってはなかなか動作しないこともあるので、まず動いてよかったです。

今回のポイント

AutoGen

AutoGenのGitHubリポジトリには、以下のように書かれています。

Multi-Agent Conversation Framework

この言葉の通り、AutoGenはマルチエージェントの「会話」に特化したフレームワークでした。

実装としては、Python版と.NET版があるようです。

ConversableAgentやその子クラスであるAssistantAgent・UserProxyAgentといったクラスでエージェントが実装されており、これらにシステムプロンプトなどの設定をほどこした上で会話させるということでした。

各エージェントは、コードの実行環境やHuman-in-the-Loopといった設定をON/OFFすることもできれば、Function callingの関数を設定したり、自作したコードで機能拡張することもできるようでした。

上にも書いたように、AutoGenは、マルチエージェントの汎用フレームワークというよりは、「会話」に特化したフレームワークです。 そのため、「マルチエージェントに議論させたい」といったAutoGenのユースケースにハマる状況であれば、かなり素早くに実装できそうでした。

AutoGen Studio

AutoGenのGUIである、AutoGen Studioにもふれました。

AutoGenのコードを書くときのように、AssistantAgentやUserProxyAgentクラスに対応する設定をGUIで入力したりしていく、というものでした。

「グループチャット」という種類のエージェントを作成することで、3種類のエージェントに会話させるところまで試すことができました。

AutoGen Studioは、認証機能などもまだなさそうで、少なくとも現時点では個人の手元で動かすぐらいの使い方になりそうです。

ちなみに、画面上のログアウトボタンを押すと、「Please implement your own logout logic」と表示されます。

次回のご案内

AutoGenはかなり有名で前々からさわらなくてはと思っていたので、この機会にキャッチアップできてよかったです。

次回は「AIエージェントキャッチアップ #2 - crewAI」ということで、crewAIにふれてみます。

generative-agents.connpass.com

ご興味・お時間ある方はぜひご参加ください!

また、その次の回以降のテーマも募集しているので、気になるエージェントのOSSなどあれば教えてください!

AKSクラスター上にHelmでDifyコミュニティ版を構築する

こんにちは。tubone24です。

Difyにはセルフホステッド版が存在しております。

github.com

こちらをAzure Kubernetes Service (AKS)上に構築する手順についてまとめていきます。

手順の概略

本手順はdouban/charts difyを用いてDifyの動作に必要なサービス郡をAKS上に作ります。

基本的にHelmを用いて一式が立ち上がりますが、パブリックアクセスでDifyにアクセスしたいため、 パブリックアクセス用にイングレスをLoadBarancerタイプに紐づける形で新規作成する手順が追加されております。

事前準備

開発環境整備

Macなどのローカル環境から構築手順を実施する場合はこちらの手順を実施し、環境を作成してください。

Azure Cloud Shellを使って構築も可能ですが、その場合はAzure CLI, Helm, kubectlがすでにインストール済みのため、こちらの手順は不要となります。

Homebrewがインストール済みのMacの場合、次のコマンドでインストール可能です。

# 開発ツール一式をインストール
brew install helm
brew install azure-cli
brew install kubectl

# Azureにコマンドラインでログイン
az login
az account set --subscription ${サブスクリプションID}

Azureの設定更新

下記コマンドはサブスクリプションの操作権限以上がないと実行できないので、リソースグループの共同所有者では実施できません。

Azureのアカウント管理者にて実施をお願いします。

  • Aレコードが登録可能なドメインを取得しておく
    • このあとの手順で作成するAKSのLoadbarancerのExternal-IPをAレコードに設定する手順を実施するため

AKSクラスターの作成

douban/charts difyのHelmをそのまま実行しただけでは、デプロイしたサービス一式が外部(パブリック)からできるイングレスを持たない形で立ち上がってきてしまうのでパブリックアクセス可能な http_application_routing を組み込んだAKSクラスターを事前に作ることでパブリックアクセスが可能となります。

AKSクラスター作成は次のコマンドを実施します。

az aks create --resource-group ${リソースグループID} --name ${クラスター名} --node-count 1 --enable-addons http_application_routing --generate-ssh-keys

AKSクラスターの作成には数分かかります。 また、後の手順でkubectlが打てるようにAKSが作成できたタイミングでget-credentialsを実行します。

az aks get-credentials --resource-group ${リソースグループID} --name ${クラスター名}

ACRの作成・インポート

各サービスが使うDifyのDockerイメージをAzure Container Registryにインポートしておきます。

あらかじめ https://github.com/langgenius/dify/releasesを参照し、最新のイメージのタグを控えておきます。(本手順作成の2024/9/16時点ではv0.8.2でした)

# ACRの作成
az acr create --resource-group ${リソースグループID} --name ${acr名} --sku Basic

# ACRに各イメージをインポート
az acr import --name ${acr名} --source docker.io/langgenius/dify-web --image dify-web:latest
az acr import --name ${acr名} --source docker.io/langgenius/dify-api--image dify-api:latest

Helmでサービスをデプロイ

douban/charts difyを使いDifyのサービスをデプロイしていきます。

基本的にはdouban公式の手順に則って進めていきます。

values.ymlを作成

Helmコマンドに渡すvalues.yamlを作成します。 FixMeの箇所を実際の値に置き換えて使用してください。

global:
  host: "dify.example.com"  # FixMe: 実際に利用可能なドメインを指定
  enableTLS: false
  image:
    tag: "0.8.2"  # FixMe最新バージョンに更新
  extraBackendEnvs:
    - name: SECRET_KEY
      value: "testdify" # FixMe: 必ず推測困難な文字列にしてください
    - name: LOG_LEVEL
      value: "DEBUG"
    - name: VECTOR_STORE
      value: "milvus"
ingress:
  enabled: true
  className: "nginx"
minio:
  embedded: true

Helmレポジトリの取得と更新

Helmコマンドを用いて、doubanのHelmレポジトリを取得します。

helm repo add douban https://douban.github.io/charts/
helm update

Helmでサービスをデプロイ

先ほど作成したvalues.yamlをhelmコマンドで指定して実行します。

helm upgrade dify douban/dify -f values.yaml --install --debug

しばらくすると、AKS上Defaultのnamespaceに次のサービスが立ち上がってきます。

(AzureポータルのKubernetes サービスのサービスとイングレスから確認可能です。)

kubectlでも確認が可能です。 すべてのサービスが登録されていることを確認します。

kubectl get services -n default  
NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
dify-api-svc          ClusterIP   10.0.234.25    <none>        80/TCP              96m
dify-frontend         ClusterIP   10.0.115.89    <none>        80/TCP              96m
dify-minio            ClusterIP   10.0.186.110   <none>        9000/TCP,9001/TCP   96m
dify-postgresql       ClusterIP   10.0.219.74    <none>        5432/TCP            96m
dify-postgresql-hl    ClusterIP   None           <none>        5432/TCP            96m
dify-redis-headless   ClusterIP   None           <none>        6379/TCP            96m
dify-redis-master     ClusterIP   10.0.226.40    <none>        6379/TCP            96m
dify-sandbox          ClusterIP   10.0.35.3      <none>        80/TCP              96m
kubernetes            ClusterIP   10.0.0.1       <none>        443/TCP             102m

また、各podの稼働状況も確認しておきます。

手順が問題なく実行できていれば、すべてのpodがRunningになっているはずです。

もしRunningになっていない場合は、サブスクリプションのリソースプロバイダーの登録状況や、ACRイメージのアクセス周りが問題と思われますのでご確認ください。

kubectl get pods -n default                                                                                                                                          
NAME                             READY   STATUS    RESTARTS   AGE
dify-api-6d6d5bbbb5-zlbdg        1/1     Running   0          61m
dify-frontend-5f5d7fdddd-qcpvc   1/1     Running   0          61m
dify-minio-56b7d4779d-wzd6t      1/1     Running   0          97m
dify-postgresql-0                1/1     Running   0          97m
dify-redis-master-0              1/1     Running   0          97m
dify-sandbox-7bf987566c-f664s    1/1     Running   0          97m
dify-worker-68476c7dcc-7tmzc     1/1     Running   0          61m

doubanのHelm chartを実行すると、nginxでイングレスも作成されます。

ただし、こちらのイングレスは利用せず、別途AKSクラスターを作成したときに用意したhttp_application_routing のLoadBalancerと紐づける別のイングレスを利用します。

DBマイグレーション

Difyが利用するPostgreSQLにDBマイグレーションを実施します。

APIサーバーが立っているPodでexecでDBマイグレーションコマンドを実行すればOKです。

あらかじめAPIサーバーのpod名を確認し、execコマンドを実行しましょう。

kubectl get pods -n default
NAME                             READY   STATUS    RESTARTS   AGE
dify-api-6d6d5bbbb5-zlbdg        1/1     Running   0          61m
dify-frontend-5f5d7fdddd-qcpvc   1/1     Running   0          61m
dify-minio-56b7d4779d-wzd6t      1/1     Running   0          97m
dify-postgresql-0                1/1     Running   0          97m
dify-redis-master-0              1/1     Running   0          97m
dify-sandbox-7bf987566c-f664s    1/1     Running   0          97m
dify-worker-68476c7dcc-7tmzc     1/1     Running   0          61m

ここではdify-api-6d6d5bbbb5-zlbdgという名前のPodなのでこちらのpod上でDBのマイグレーションスクリプトを実行します。

実際の手順ではpod名はget podsコマンドの結果を下に変更してください。

kubectl exec -it dify-api-6d6d5bbbb5-zlbdg -- flask db upgrade

Load barancerの更新

先ほどAKSクラスターを作成した際にhttp_application_routingで作成済みのLoadBarancerをdifyのイングレスとして組み込みます。

dify-ingress.yamlを作成し、先ほど作成したhttp_application_routingに各サービスを紐づけて更新します。

(もちろん、Helmコマンドで作成済みのイングレスを更新する形でも構いませんが、その場合kubectl applyが打てるように kubectl.kubernetes.io/last-applied-configuration を追加したYAMLを作成済みのイングレスのYAML定義に追加する形で作成します。)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dify-ingress
  annotations:
    kubernetes.io/ingress.class: addon-http-application-routing
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: dify-frontend
            port:
              number: 80
      - path: /console/api
        pathType: Prefix
        backend:
          service:
            name: dify-api-svc
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: dify-api-svc
            port:
              number: 80
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: dify-api-svc
            port:
              number: 80
      - path: /files
        pathType: Prefix
        backend:
          service:
            name: dify-api-svc
            port:
              number: 80

kubectl applyでイングレスを更新します。

 kubectl apply -f dify-ingress.yaml

暫く待つと、LoadBarancerのExternal-IPアドレス経由でDifyにアクセスできるようになります。

kubectl get ingress -n default

を実行し、dify-ingressのAddressにアクセスすると、Difyのログイン画面が表示されるはずです。

ただし、この時点でサインインやインストールはできません。

なぜならDifyのフロントエンド(Next.js)がAPIサーバーへアクセスするドメインを上記のIPアドレスでなく、values.yamlに指定したglobal.hostの値を利用するためです。

DNSの更新

利用しているDNSサービスでAレコードを作成します。 作成したAレコードの値にはLoadBarancerのExternal-IPを指定します。

再度ドメインでアクセスする

無事全部の設定が問題なく完了していればこの時点で http://ドメイン/install にアクセスすることで管理者アカウントを作成可能になります。

もし、/installにアクセスした際にInternal server errorなどが出るようであれば、 作成したイングレスの設定もしくは、DBマイグレーションが正しくできてない可能性があるので、再度確認してください。

「Difyソースコードリーディング#3 ―APIのリクエストからレスポンスまで」を開催しました #もくもくDify

ジェネラティブエージェンツの大嶋です。

もくもくDifyで「Difyソースコードリーディング#3 ―APIのリクエストからレスポンスまで」というイベントを開催しました。

dify-mokumoku.connpass.com

アーカイブ動画はこちらです。

youtube.com

Difyのソースコードは以下です。

github.com

今回は 戸塚さん にも同席いただいて、一緒に話しながらコードを読んでいきました!

今回のポイント

APIのリクエストからレスポンスまで

今回の目標の1つ目は、APIのリクエストからレスポンスまで、おおよそどのような呼び出しの繋がりになっているのか把握することでした。

ワークフローを実行するAPIである、WorlflowRunApiクラスのpostメソッド を起点として、実際にワークフローのノードが処理されるところまでコードを追ってみました。

CONTRIBUTING_JA.md の記載などから想像していた通りですが、「controllers -> services -> core」という流れで呼び出されていることが分かりました。

ワークフローの実行

ワークフローはDifyの内部でグラフとして表現されており、GraphEngineクラス で各ノードを順に処理していそうなことが読み取れました。

具体的には、コードの以下の箇所のwhileループで、ノードを順に処理しているように見えます。

https://github.com/langgenius/dify/blob/0f1487325531bf4d8b38225218a91f06624dcc35/api/core/workflow/graph_engine/graph_engine.py#L204

ワークフローのノードのクラス

気になったので、ワークフローのノードのクラスもいくつか見てみました。

ワークフローの各ノードは、BaseNodeクラス を継承して実装されていることが分かりました。

例えば LLMNodeクラス でLLMの呼び出しが行われているようです。

おおまかにどんなAPIがあるか

少し話がそれましたが、今回の2つ目の目標だった、おおまかにどんなAPIがあるか把握することにも取り組みました。

DifyのAPIのエンドポイントは api/controllersディレクトリ で定義されています。

この中にさらにディレクトリがあり、それぞれおおよそ以下のAPIのようでした。

  • console ... Difyにログインしてアプリを作成したりする際のAPI
  • files ... ファイル関係(?)
  • inner_api ... Enterprise用(?)
  • service_api ... 不明
  • web ... Difyのアプリを公開した際のAPI

とくに重要なのがconsoleディレクトリとwebディレクトリで、基本的なAPIはこの2つのディレクトリ内でエンドポイントが定義されているようでした。

次回のご案内

Difyでは、モデルやツールの詳細がYAMLファイルで管理されています。 次回は、これらのYAMLファイルがどのように扱われているのか読み解くことを目標にします。 時間があれば、ワークフローを保存するYAMLファイルの出力などのコードも探してみます。 ご興味ある方はぜひ気軽にご参加ください。

dify-mokumoku.connpass.com

また、水曜日にもDifyのもくもく会が開催されます。 こちらではDifyの使い方の解説として、テンプレートをみていく予定となっています。 こちらもご興味ある方はぜひ気軽にご参加ください。

dify-mokumoku.connpass.com

勉強会「【LangChainゆる勉強会#12】LangGraphの最新ドキュメントを全体的にざっと読む」を開催しました #StudyCo

ジェネラティブエージェンツの大嶋です。

運営している勉強会コミュニティStudyCoで「【LangChainゆる勉強会#12】LangGraphの最新ドキュメントを全体的にざっと読む」というイベントを開催しました。

studyco.connpass.com

アーカイブ動画はこちらです。

youtube.com

LangGraphは最近アップデートが活発で、ドキュメントも充実してきています。 LangGraphのドキュメントに一通り目を通す時間を作ろうと、この勉強会を開催しました。

今回LangGraphのドキュメントを読んでみて、「この機能はあまり知られていなそうだな」と感じたものを、3つほどピックアップしてこの記事で紹介します。

Send APIによる動的なエッジの構成

まず、Send APIについてです。

LangGraphでは基本的な使い方として、「add_conditional_edges」を使って、条件に応じてノードを選択するエッジを作成します。 しかし、単純にadd_conditional_edgesを使うだけでは、「実行時にノードの数を動的に変更したい」といったことはできません。

そのように、より動的にエッジを構成するために、LangGraphでは「Send API」が提供されています。 Send APIのコンセプトは以下のページで解説されています。

langchain-ai.github.io

上記のページでは、Send APIを使う一般的な例として、map-reduceが挙げられています。 map-reduceでは、mapの処理として「同じ処理を実行するノードを、データの数だけ用意して実行する」ということになり、これはまさに動的にエッジを構成する例です。

map-reduceの実装例は、次のページに掲載されています。

langchain-ai.github.io

ステートの共有

次に、ステートの共有についてです。

チャットボットなどのアプリケーションを提供するうえで、「スレッド内の会話履歴を記憶させたい」というのに加えて、「スレッドをまたいでユーザー単位で記憶を共有したい」といったケースが考えられます。 そのようなケースのサンプルコードが以下のページに掲載されています。

langchain-ai.github.io

上記のページのコードから、とくに重要な箇所を簡単に説明します。

まず、グラフのステートとして、「SharedValue」という、あるキーをもとにシェアする値を定義します。

from langgraph.managed.shared_value import SharedValue

class AgentState(MessagesState):
    info: Annotated[dict, SharedValue.on("user_id")]

実行時のconfigで、SharedValueで指定したキーに適当な値を設定します。

config = {"configurable": {"thread_id": "1", "user_id": "1"}}

for update in graph.stream({"messages": [{"role": "user", "content": "hi"}]}, config, stream_mode="updates"):
    print(update)

このようにSharedValueを使うことで、「スレッドをまたいでユーザー単位で記憶を共有する」という実装ができるということです。

NodeInterruptによる動的なブレークポイントの設定

最後に、NodeInterruptについてです。

LangGraphでは、「interrupt_before」という設定によって、あるノードに処理がきた際に、処理を中断することができます。

より動的に処理を中断する方法として「NodeInterrupt」が提供されています。 サンプルコードは次のページに掲載されています。

langchain-ai.github.io

こちらも、上記のページのコードから、とくに重要な箇所を簡単に説明します。

from langgraph.errors import NodeInterrupt

def step_2(state: State) -> State:
    if len(state['input']) > 5:
        raise NodeInterrupt(f"Received input that is longer than 5 characters: {state['input']}")
    
    print("---Step 2---")
    return state

簡単に言えば、NodeInterruptをraiseすると、動的にグラフの実行をinterruptできるということです。

ノードの遷移のタイミングで処理を中断したい場合は「interrupt_before」を使えば十分ですが、より動的な制御が必要な場合は「NodeInterrupt」を使えるということになります。

おわりに

以上、LangGraphのあまり知られていなそうな機能を3つ紹介しました。

今回の勉強会は「LangGraphの最新ドキュメントを全体的にざっと読む」というテーマだったため、1つ1つの内容は深堀りできませんでした。 開催後のアンケートでも、「このあたりを深堀りしてほしい」といった意見をいくつかいただいており、もう少し深堀りする会も開催したいと考えています。

LangChain / LangGraph、その他のテーマで引き続き勉強会を開催していきます。 LangGraphの話でもLangGraph以外の話でも、もしも「こんな話が聞きたい」というテーマがあれば、ぜひお声がけください!

LT大会で「LangGraphでのHuman-in-the-Loopの実装」というタイトルで話しました #StudyCo

ジェネラティブエージェンツの大嶋です。

StudyCoのLT大会で「LangGraphでのHuman-in-the-Loopの実装」というタイトルで話しました。

studyco.connpass.com

発表資料はこちらです。

speakerdeck.com

ソースコードはこちらです。

github.com

この記事には、発表内容に含めなかった感想などを書こうと思います。

LangGraphのフレームワークらしさ

LangGraphの機能を活用したHuman-in-the-Loopを実装してみると、LangGraphが処理の全体的な流れを担い、その流れの部品を実装することになります。

そのことから、LangGraphのフレームワークらしさを改めて実感しました。

個人的にはLangChain(とくにLCEL)もフレームワークだと理解することが実は重要で、フレームワークのつもりでキャッチアップすると上手に使いやすい、という感覚がある気がしています。

より本格的なアプリではどうか

今回のLTで紹介したのは、Streamlitのアプリケーションでの簡単なデモ程度の実装でした。

実際のアプリケーションでHuman-in-the-Loopのように処理の流れの根幹に関わる機能を実装するときは、フレームワークの機能を使う/使わないという判断も重要だと思います。

より本格的に、例えばSlackアプリに組み込んだりすると、LangGraphでのHuman-in-the-Loopの実装がどこまで便利で実用的なのかよりよく理解できそうです。近々挑戦したいです。

Notebookのコードをアプリケーションに

今回話題にしたLangGraphでのHuman-in-the-Loopの実装については、公式ドキュメントに解説とNotebookでのサンプルコードが記載されています。

しかし、Notebookのサンプルコードでは、実際にアプリケーションに組み込むにはどうするんだ?と試行錯誤することになりがちです。

LangChain/LangGraphの使い方を広めるうえでも、簡単ではありますがアプリケーション化したコードを紹介できてよかったです。

おわりに

今回のLT大会自体でも、自分の知らない話をたくさん聞くことができ、とても勉強になりました。

また時々LT大会を開催する予定なので、「自分も話したい!」という方は是非お声がけください!

「Difyソースコードリーディング#2 ―Difyの開発環境を起動してみる」を開催しました #もくもくDify

ジェネラティブエージェンツの大嶋です。

もくもくDifyで「Difyソースコードリーディング#2 ―Difyの開発環境を起動してみる」というイベントを開催しました。

dify-mokumoku.connpass.com

アーカイブ動画はこちらです。

youtube.com

Difyのソースコードは以下です。

github.com

今回のポイント

Difyの開発環境の起動方法

Difyの開発環境の起動方法自体は、CONTRIBUTING_JA.md の「インストール」の箇所に書かれている通りの手順でした。

手順自体は少し長めでしたが、まったくエラーに遭遇せず起動できました。

開発環境の起動と、docker/docker-compose.yamlでの起動の違い

補足になりますが、CONTRIBUTING_JA.md に書かれているのは、Dify自体の開発のためのセットアップ手順です。

docker/docker-compose.yaml にもDifyをDocker Composeで起動する手順が書かれていますが、こちらの場合は開発モードではなく、コードを変更しても反映されません。

UIの文言の修正

せっかく開発環境を起動できたので、UIの文言を少し変更してみました。

web/i18n ディレクトリのファイルを編集すると、しっかりUIに反映されました。

設定の変更

昨日のDifyもくもく会で話題になった、チャンクサイズの最大値の変更も挑戦してみました。

チャンクサイズを1000より大きくすると Custom segment length should be between 50 and 1000 と表示されるので Custom segment length should be between で検索してコードの該当箇所を探しました。

最終的にはINDEXING_MAX_SEGMENTATION_TOKENS_LENGTHという環境変数を変更することで、チャンクサイズの最大値を変更できることが確認できました。

コードの該当箇所:https://github.com/langgenius/dify/blob/3e7597f2bd0ff686e7a1ea1972f0421ed0568fbb/api/.env.example#L258

dify-docs

Difyのアプリケーション以外に、dify-docsも少し見てみました。

github.com

こちらはGitBookが使われているようで、マークダウン形式のドキュメントを更新すれば反映されるようです。

translate.py という自動翻訳のスクリプトが置かれていて、このスクリプトの内部ではDifyのアプリケーションを呼び出しているようでした。

dify-sandbox

最後に、dify-sandboxも少しみてみました。

github.com

Go言語で実装されていて、システムコールを制限したりした環境でPythonやNode.jsを実行できるようでした。

詳細までは分からなかったので、またそのうちじっくり読みたいです。

次回のご案内

Difyソースコードリーディングの第3回として、次回はAPIのリクエストからレスポンスまでどんなふうに実装されてるのか読み解いたり、どんなAPIがあるのか見てみる予定です。 ご興味ある方はぜひ気軽にご参加ください。

dify-mokumoku.connpass.com

また、水曜日にもDifyのもくもく会が開催されます。 こちらではDifyの使い方の解説として、テンプレートをみていく予定となっています。 こちらもご興味ある方はぜひ気軽にご参加ください。

dify-mokumoku.connpass.com