🦜

LangChainとOpenAI API, Morphを使って、ユーザー認証付きのカスタムAIチャットを構築し、デプロイするチュートリアル

2025/02/13に公開

LangchainとMorphを用いて認証付きのAIアプリを作る方法を解説します。MorphによるRBAC(Role-based Access Control)の仕組みを活用して、Langchainで作成したAIアプリを社内に安全に展開する方法を理解することができます。

Morphは、PythonとマークダウンでAIアプリを構築できるフレームワークです。チュートリアルでは、Morphのデプロイ環境(無料で使えます)を使うので、事前にmorph-data.ioにログインして下さい。

Langchainは、LLMを活用したアプリケーションを開発するためのコンポーネント、サードパーティの統合を備えた非常に優れたフレームワークです。

この記事では、Langchainを用いてAIワークフローを構築し、Morphを用いて認証付きのAIアプリとしてチームに展開するための手順を解説します。

本チュートリアルの成果物は以下のリポジトリのRBAC Langchain Appで公開しています。

https://github.com/morph-data/morph-sample-apps

https://youtu.be/WzV3agEy9Y4

環境のセットアップ

morph new コマンドで新しいプロジェクトを立ち上げます。この時パッケージマネージャーはpoetryを選択することを推奨しています。

morph new rbac-langchain-app

pyproject.tomlには、以下のようにdependenciesを設定します。

[tool.poetry.dependencies]
python = "<3.13,>=3.9"
morph-data = "0.1.3"
langchain = "0.3.16"
langchain-core = "0.3.32"
langchain-openai = "0.3.2"

このチュートリアルではOpenAI APIを使うので、 .env にAPI KEYをセットしてください。

OPENAI_API_KEY=[Put your API KEY]

フロントエンドの構築

Morphでは、 src/pages 以下にmdxファイルを配置してフロントエンドを構築ができます。

今回は<Chat />コンポーネントを使用して、Langchainで構築したAIとチャットができる画面を構築します。<Grid />やTailwind CSSのユーティリティクラスを使用して、レイアウトも調整しています。

# Role-based access control with LangChain

This example shows how to use LangChain with role-based access control (RBAC).

<Grid cols={1} className="py-4">
    <div className="p-4 bg-gray-50 rounded-lg shadow-sm border border-gray-200 hover:shadow-md transition-shadow">
        <LLM postData="rbac_langchain" />
    </div>
</Grid>

これで、ターミナルで morph serve を実行して、 http://localhost:8080 にアクセスをすると画面が確認できます。

Langchainを使用したAIアプリの構築とRBACによる権限の制御

Langchainを使用して”admin”のロールを持ったユーザーのみが使えるAIワークフローを構築します。

MDXの<Chat />から prompt, thread_id が自動的に送信されてきます。

  • prompt: ユーザーが入力したメッセージ
  • thread_id: Chat UIで表示されているスレッドを一意に特定するID

historyという直近に使用したスレッドの情報をグローバル変数で定義したものを使って、連続した質問にも回答できるようにします。

history = {}

@morph.func
def rbac_langchain(context: MorphGlobalContext):
    model = ChatOpenAI(model="gpt-4o-mini")
    
    # initialize history when new thread comes. 
    if history.get("thread_id") != context.vars["thread_id"]:
        history["thread_id"] = context.vars["thread_id"]
        history["messages"] = [
            SystemMessage(content="Please translate the following text from English to French."),
        ]

		# set user's prompt
    history["messages"].append(HumanMessage(content=context.vars["prompt"]))

    result = ""
    for token in model.stream(history["messages"]):
        result += token.content
        yield create_chunk(token.content)
    history["messages"].append(AIMessage(content=result))

次に、ユーザーが”admin”というロールを持っている場合以外にはエラーメッセージをチャットで返却します。

# context.user_info comes from user's authentication info.
if "admin" not in context.user_info["roles"]:
	yield stream_chat("You are not authorized to use this feature.")
  return

Pythonコード全体

import morph
from morph import MorphGlobalContext
from morph_lib.stream import create_chunk
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
from morph_lib.stream import stream_chat

history = {}

@morph.func
def rbac_langchain(context: MorphGlobalContext):
    # context.user_info comes from user's authentication info.
    if "admin" not in context.user_info["roles"]:
        yield stream_chat("You are not authorized to use this feature. \n\n Please login as admin.")
        return

    model = ChatOpenAI(model="gpt-4o-mini")
    if history.get("thread_id") != context.vars["thread_id"]:
        history["thread_id"] = context.vars["thread_id"]
        history["messages"] = [
            SystemMessage(content="Please translate the following text from English to French."),
        ]
    history["messages"].append(HumanMessage(content=context.vars["prompt"]))

    result = ""
    for token in model.stream(history["messages"]):
        result += token.content
        yield create_chunk(token.content)
    history["messages"].append(AIMessage(content=result))

デプロイしてアプリを共有する

ダッシュボードで新しいプロジェクトを作成し、API Keyを発行します。

morph_project.yml にプロジェクト詳細画面で取得した project_id をセットしてください。

default_connection: DUCKDB
package_manager: pip
profile: default
project_id: [プロジェクトIDを埋める]
result_cache_ttl: 0
source_paths:
- src

次に morph config を用いてCLIにAPI Keyを紐付けます。

morph config

ここまでで準備は完了なので、ダッシュボードにデプロイをしましょう!

morph deploy

参考

https://docs.morph-data.io/docs/ja/deploy/deploy

デプロイが完了したら、ダッシュボードの”Open”からアプリにアクセスしてみましょう。ダッシュボードのMember Accessから設定したProject Roleに設定されている値に応じて、アクセスコントロールができていることが確認できます!

Morphテックブログ

Discussion