LangChainとChainlitによるデータ連携型AIチャットボットの実装からデプロイまで | 第2回


# 第2回 | LangServeでシンプルUIを作ってみる
チャットボットにチャットボットっぽく質問してみるってめっちゃ大事ですよね！開発のモチベ的に！
今回はLangChainが提供するUIであるLangServeを使って、チャットボットとチャットボットっぽくやり取りできるようにします！コードに質問ベタ打ちなんてもう嫌だ！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/195b56d3-f11a-e90c-e529-becded5dd6a2.png)

## はじめに
本シリーズの目標は次の3つです！
1. [LangChain](https://python.langchain.com/docs/get_started/introduction)によるデータ連携型[^1]AIチャットボットの実装
2. [Chainlit](https://docs.chainlit.io/get-started/overview)によるUIの作成
3. デプロイして他端末からアクセスできるようにする

LangChainはLLMに基づくアプリを開発するためのフレームワークで、PythonとJavaScriptの2言語で提供されています。本シリーズではPythonを使います。
ChainlitはAIチャットボット向けの対話型UIが簡単に作れるインターフェースです。

この界隈は技術の新陳代謝がヒジョーーに早いので、ご使用のバージョンをご確認ください！2024年4月現在、私は次のバージョンを使っています。
- LanghChain: 0.1.14
- Chainlit: 1.0.502

### シリーズ一覧
| シリーズ | 内容                                                                     |
| -------- | ------------------------------------------------------------------------ |
| 第1回    | [LangChainの導入](https://qiita.com/Sego-don/items/284075f63266e19873d1) |
| 第2回    | LangServeでシンプルUIを作ってみる ← イマココ                             |
| 第3回    | [LangSmithによるプロセス追跡](https://qiita.com/Sego-don/items/7d95864fd0d33192e3e5) |

[^1]: 「データ連携型」は事前に与えたPDFやウェブページなどのコンテンツに基づいて回答させるという意味で用いています。正確には[RAG](https://python.langchain.com/docs/use_cases/question_answering/)と呼ばれる仕組みを用います。

## LangServeとは？
[LangServe](https://python.langchain.com/docs/langserve/)はLangChainで作ったアプリケーションを外部に提供するためのパッケージです。

https://python.langchain.com/docs/langserve/

基本的にはAPIとして利用するのがメインなようですが、Playgroundという「せっかく作ったんだし試してみようUI」が付随していて、これが開発のモチベキープに一役買ってくれます。

インストールは超簡単。
```bash
pip install "langserve[all]"
```

## 実装
実装も超簡単。
```sample.py
from dotenv import load_dotenv
load_dotenv()

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
  ("system", "あなたはQiitaの専門家です。Qiitaに関すること以外は分からないと回答してください。"),
  ("user", "{input}")
])

chain = prompt | ChatOpenAI() | StrOutputParser()

# ----------------------------
# ----- ここから今回の内容 -----
# ----------------------------
from fastapi import FastAPI
from langserve import add_routes

app = FastAPI(
  title="LangChain Server",
  version="1.0",
  description="A simpele api server using Langchain's Runnable interfaces",
)

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

if __name__ == "__main__":
  import uvicorn
  uvicorn.run(app, host="localhost", port=8000)
```
前半は[前回](https://qiita.com/Sego-don/items/284075f63266e19873d1)の内容そのままにチェーンを作成しています。後半が今回のLangServeに関係するところ。最初に```FastAPI```の```app```を定義して、langserveで提供されている```add_routes()```によってpathを追加します。最後の部分でlocalhostの8000番ポートに公開しているだけ。楽チン！

## 実行
では実行してみましょう。
```bash
PS C:\path\to\the\code> python .\sample.py   
INFO:     Started server process [31320]
INFO:     Waiting for application startup.

 __          ___      .__   __.   _______      _______. _______ .______     ____    ____  _______
|  |        /   \     |  \ |  |  /  _____|    /       ||   ____||   _  \    \   \  /   / |   ____|
|  |       /  ^  \    |   \|  | |  |  __     |   (----`|  |__   |  |_)  |    \   \/   /  |  |__
|  |      /  /_\  \   |  . `  | |  | |_ |     \   \    |   __|  |      /      \      /   |   __|
|  `----./  _____  \  |  |\   | |  |__| | .----)   |   |  |____ |  |\  \----.  \    /    |  |____
|_______/__/     \__\ |__| \__|  \______| |_______/    |_______|| _| `._____|   \__/     |_______|

LANGSERVE: See all available routes at /docs/

LANGSERVE: ⚠️ Using pydantic 2.6.4. OpenAPI docs for invoke, batch, stream, stream_log endpoints will not be generated. API endpoints and playground should work as expected. If you need to see the docs, you can downgrade to pydantic 1. For example, `pip install pydantic==1.10.13`. See https://github.com/tiangolo/fastapi/issues/10360 for details.

INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:8000 (Press CTRL+C to quit)
```
無事```http://localhost:8000```に起動できたようです。自身で追加した"myChain"のplaygroundのアドレスは```http://localhost:8000/myChain/playground```です[^2]。Chromeでアクセスしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/7c1959e5-0e8b-be1b-1e92-53ed7fcb67fb.png)

わーーーい！

## 遊んでみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/195b56d3-f11a-e90c-e529-becded5dd6a2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/37a0c1a0-b367-011b-cd09-fcbf1c04696a.png)

素晴らしいですね！LangServeだと返答が単語ずつずらららーっと表示されるのがいいですよね。本物のChatGPTっぽい。こうやって連続的に回答を生成する仕組みをLangChainではStreamingと呼んでいます。

ちなみに「Intermediate steps」を開くとChatPromptTemplate → ChatOpenAI → StrOutputParser とチェーン内で情報がやり取りされている様子を詳細に確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/69fa4def-f9af-356d-c9f7-816521ffbec6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/4b659371-083d-04b2-047b-2fde53e11b40.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/51324b6e-ef4a-288b-b6e7-121a5ed6869e.png)

[^2]: ちなみに、コンソールへの出力にあるようにアドレスの一覧は```http://localhost:8000```から見ることができます。

## おわりに
今回はLangServeでUIを実装し、返答を得ることができました。ユーザーに提供するには拡張性がイマイチですが、開発で使う分には全然問題なし！
モチベアップ間違いなしでしょう！
次回はLangSmithでチャットボットの実行プロセスを追跡します！

https://qiita.com/Sego-don/items/7d95864fd0d33192e3e5