langchianlogo

LangChain入門(5) – LangServe – WebAPIからのアクセス

せっかく作成した生成AIやアプリ、何らかの形で公開したくなるでしょう。Streamlitなどのアプリにして公開する方法をご紹介してきましたがWebAPIの形式で公開すれば、いろいろな方法で活用できます。LangChainにはそんなことをサポートするLangServeが用意されています。

本記事はFuture Coders独自教材からの抜粋です。変化の早い分野なので記事の内容が古くなっている可能性もあります。ご注意ください。

langserve

LangServeというモジュールを使用すると、生成AIのモデルをWebサービスとして公開することが簡単に実装できます。

LLMの準備

モジュールを最新版にします。

py -m pip install -qU langchain
py -m pip install -qU langchain-openai

OPENAIのAPIキーは環境変数に設定されているものとします。

Modelの利用

以下のコードでLLMのモデルを作成します。

from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4")

このmodelが生成AIの本体ともいえるオブジェクトです。いったいどのようなオブジェクトなのか興味がある人は以下のコードを実行してください。

import inspect

def print_base_classes(cls):
    bases = inspect.getmro(cls)
    for base in bases:
        print(base)

print_base_classes(type(model))

以下のように出力されました。

<class 'langchain_openai.chat_models.base.ChatOpenAI'>
<class 'langchain_openai.chat_models.base.BaseChatOpenAI'>
<class 'langchain_core.language_models.chat_models.BaseChatModel'>
<class 'langchain_core.language_models.base.BaseLanguageModel'>
<class 'langchain_core.runnables.base.RunnableSerializable'>
<class 'langchain_core.load.serializable.Serializable'>
<class 'pydantic.main.BaseModel'>
<class 'pydantic.utils.Representation'>
<class 'langchain_core.runnables.base.Runnable'>
<class 'typing.Generic'>
<class 'abc.ABC'>
<class 'object'>

これは、modelオブジェクトがどのようなクラスを継承しているか示した内容です。生物→哺乳類→犬、というようにオブジェクトはその性質を継承することができます。modelが様々な機能を有していることがわかります。

この中のRunnableというクラスが重要で、以下のコードを実行すると、その中にinvokeというメソッドが含まれていることが確認できます。

from langchain_core.runnables.base import Runnable
dir(Runnable)

実際にモデルを実行してみましょう。”hi!”をイタリア語に翻訳して、という内容です。

from langchain_core.messages import HumanMessage, SystemMessage

messages = [
    SystemMessage(content="Translate the following from English into Italian"),
    HumanMessage(content="hi!"),
]

model.invoke(messages)

SystemMessageはシステム・背景に関する情報を保持するオブジェクト、HumanMessageはあなたの発言を保持するオブジェクトです。それをリストの形式にしてモデルのinvokeメソッドに渡しています。以下のように出力されました。AIMessageが生成AIモデルの発言です。”ciao!”というのがその内容です。

AIMessage(content='ciao!', response_metadata={'token_usage': {'completion_tokens': 3, 'prompt_tokens': 20, 'total_tokens': 23}, 'model_name': 'gpt-4', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-6efb2081-80a2-43c5-856f-692522f8d739-0')

Output Parser

この出力は読みづらいのでテキスト部分だけを取り出すためにOutputParserを使うことができます。

from langchain_core.output_parsers import StrOutputParser
parser = StrOutputParser()

以下のように同じ処理を実行して、その結果をparserに渡すと、文字の部分だけが取り出されます。

result = model.invoke(messages)
parser.invoke(result)

上記の処理では、生成AIの出力を後段のparserに渡しています。これらは順番につながっているので、chain = model | parserのように表現し、その全体となるchainを実行する(=invokeを呼び出す)というように記述できます。

chain = model | parser
chain.invoke(messages)

Prompt Template

上記の例では、直接メッセージをLLMに渡していました。一般的にメッセージの内容はユーザーの入力と、あらかじめ用意された情報を組み合わせたものとなります。PromptTemplateはこのような作業をサポートする目的で用意されたものです。

from langchain_core.prompts import ChatPromptTemplate

システムのメッセージは言語を切り替えらるようにします。ユーザーのメッセージはそのまま引用するものとします。

system_template = "Translate the following into {language}:"

これらをまとめたテンプレート(チャット:会話)を以下のように作成します。

prompt_template = ChatPromptTemplate.from_messages(
    [("system", system_template), ("user", "{text}")]
)

このテンプレートには{language}と{text}と2つの入力があることに注意してください。 以下のように2つの入力を与えてプロンプトを作成します。

result = prompt_template.invoke({"language": "italian", "text": "hi"})
result

以下のように出力されます。これが生成AIへの入力となります。

ChatPromptValue(messages=[
    SystemMessage(content='Translate the following into italian:'), 
    HumanMessage(content='hi')])

このプロンプトから生成AI、そして出力までつないだChainを以下のように作成して実行します。

chain = prompt_template | model | parser
chain.invoke({"language": "italian", "text": "hi"})

Serving with LangServe

ここまで用意したものをサーバを介して公開してみましょう。LangServeはLangChainで作成したChainをREST APIと呼ばれる形式のWebサービスで提供します。

以下のコマンドを実行して必要なモジュールをインストールします。

py -m pip install "langserve[all]"

サーバーは常時稼働する必要があるため、notebookでなく、コマンドプロンプトから実行するほうが使いやすいでしょう。serve.pyというファイルを作成して、以下のように記述してください。serve.py

#!/usr/bin/env python
from typing import List

from fastapi import FastAPI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
from langserve import add_routes

# 1. Create prompt template
system_template = "Translate the following into {language}:"
prompt_template = ChatPromptTemplate.from_messages([
    ('system', system_template),
    ('user', '{text}')
])

# 2. Create model
model = ChatOpenAI()

# 3. Create parser
parser = StrOutputParser()

# 4. Create chain
chain = prompt_template | model | parser


# 4. App definition
app = FastAPI(
  title="LangChain Server",
  version="1.0",
  description="A simple API server using LangChain's Runnable interfaces",
)

# 5. Adding chain route

add_routes(
    app,
    chain,
    path="/chain",
)

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="localhost", port=8000)

以下のような画面が表示されてサーバが実行開始します。

langserve1
LangChain入門(5) – LangServe - WebAPIからのアクセス 5

ブラウザを起動して http://localhost:8000/chain/playground/ にアクセスしてください。以下のようなWebアプリの画面が表示されます。

langserve2
LangChain入門(5) – LangServe - WebAPIからのアクセス 6

自分のプログラムからWebAPIを呼び出すことも簡単です。Pythonのプログラムをclient.pyとして以下の内容を保存してください。client.py

from langserve import RemoteRunnable

remote_chain = RemoteRunnable("http://localhost:8000/chain/")
r = remote_chain.invoke({"language": "italian", "text": "hi"})
print(r)

以下のように実行すると結果が得られます。 

langserve3
LangChain入門(5) – LangServe - WebAPIからのアクセス 7

Future Coders

Future Codersではほかにも多くの独自教材を用意しています。少人数個別指導・リモート対応でレッスンを行っています。レッスン以外にも出張授業やコンサルタントも行っております。興味のある方はお気軽にお問い合わせください。

Categories: LangChain, OpenAI, Python