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


# 第3回 | LangSmithによるプロセス追跡
LangChainでチェーンを作成した際、内部でどのような処理が行われたのかを確認するのはデバッグの面ですごく重要です。今回はLangSmithという機能でこれを実現します。
最終的にはこんな感じで過去の実行の詳細がウェブ上で確認できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/4f71cdf4-1ca8-13c2-6e54-6fc11e8fb396.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を作ってみる](https://qiita.com/Sego-don/items/1208a001a2d795225ada) |
| 第3回    | LangSmithによるプロセス追跡と出力評価 ← イマココ                                           |

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

## LangSmithとは？
[LangSmith](https://python.langchain.com/docs/langsmith/)はLangChainで作ったチェーンをデバッグしたりするための仕組みです。
チェーン実行時にLangSmithと紐づけておくことでLangSmithのウェブサイト上でそのチェーンの実行の詳細を確認することができます。

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

## セットアップ
ドキュメントを参考にセットアップしていきます。

https://docs.smith.langchain.com/

インストールは超簡単。
```bash
pip install -U langsmith
```

次にAPIキーを取得します。
[こちら](https://smith.langchain.com/)からアカウントを作成し、[セッティングページ](https://smith.langchain.com/settings)からAPIキーを取得します。
APIキーは後から確認できないので、後で環境変数に設定するまでは画面閉じないようにしてください。

![スクリーンショット 2024-05-07 154117.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/67bf75e2-4804-379b-26ed-e8b0b8747804.png)

最後に環境変数を設定します。`export`コマンドなどを使って毎回登録しても問題ありませんが、面倒なので`env`ファイルに記録しておくのがおすすめです。
```.env
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=先ほど作成したAPIキー
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
```
第1回でOPENAI_API_KEYを記録した方はその下にこれらの環境変数を追記してください。
コード内で次のようにすれば`.env`ファイルから環境変数が読み込まれます。
```sample.py
from dotenv import load_dotenv
load_dotenv()
```
:::note warn
コードを外部に公開する際には```.env```ファイルを含まないようご注意ください。
:::
何らかの問題があってうまく環境変数が登録できなかった場合、pythonコードの先頭で
```sample.py
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "先ほど取得したAPIキー"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
```
とするとそのコード内でのみ使える環境変数が登録できますので、とりあえずはこれで次に進めるはずです。ただしコードにAPIキーをべた書きするのはセキュリティ上非常によろしくないので、このように環境変数を設定した場合にはコードのこの部分を他人に共有しないよう細心の注意を払ってください。

## 使ってみる
では早速LangSmithを使ってみましょう！[LnagSmithのチュートリアル的なの](https://python.langchain.com/docs/langsmith/walkthrough/)はあるんですがちょっとややこしいので、これを参考にしつつもっとシンプルな形で導入していきます。

### 実装
[前回のコード](https://qiita.com/Sego-don/items/1208a001a2d795225ada#実装)にちょっとだけ書き加えてみましょう。
```sample.py
from dotenv import load_dotenv
load_dotenv()

# -----------------------------------
# ----- LangSmithの設定はここだけ -----
# -----------------------------------
import os
os.environ["LANGCHAIN_PROJECT"] = "Qiita-LangSmith"

from langsmith import Client
client = Client()

# --------------------------------------
# ----- チェーンを作成（第1回の内容） -----
# --------------------------------------
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()

# ----------------------------------------
# ----- LangServeの設定（第2回の内容） -----
# ----------------------------------------
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)
```
追加したのは最初の数行だけです。最初に、
```sample.py
import os
os.environ["LANGCHAIN_PROJECT"] = "Qiita-LangSmith"
```
の部分で`LANGCHAIN_PROJECT`という環境変数を登録しています。LangSmithではプロジェクトという形で記録を管理しており、その名前の設定を設定しています。何でもいいのでご自身で好きな値を設定してください。

続いて、
```sample.py
from langsmith import Client
client = Client()
```
の部分でlangsmithのクライアントを生成しています。これだけ生成すれば、のちに実行されるチェーンの詳細が自動的にLangSmithのウェブサイトに登録されます。

### 実行
前回同様にLangServeを実行します。コンソールで
```bash
PS C:\path\to\the\code> python .\sample.py   
```
として、起動したらChromeやらEdgeやらで`http://localhost:8000/myChain/playground`にアクセスします。

試しに質問してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/ba0c3416-ba67-24d9-fe9b-6fb51feae493.png)

質問できたら、[LangSmithのウェブサイト](https://smith.langchain.com/projects)へとアクセスします。

![スクリーンショット 2024-05-07 164902.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/265f4787-4a63-58e7-c7c8-7308a14e2847.png)

`LANGCHAIN_PROJECT`として設定した名前のプロジェクトが作成されているのが確認できます。中を見てみましょう。

![スクリーンショット 2024-05-07 165040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/5be25360-c8a9-324d-92ec-e37b17bac3b5.png)

先ほどの質問が記録されていることがわかりますね。こうやって同じプロジェクトに過去の質問や回答が記録されていきます。また、右のカラムにはプロジェクトの詳細情報が記されていますが、過去にどれだけのトークンを利用し、お金がいくらかかったのかも確認できます。
次に先ほどの質問をクリックします。

![スクリーンショット 2024-05-07 165133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/68c665de-29a6-cb1a-ed3b-259ed3aba42e.png)

すると、そのその質問に対してどのようなプロセスで回答が生成されたのか、詳細を確認することができます。この画面だと「ChatOpenAI」しかいないように見えますが、実際にはその前後にプロンプトを生成する「ChatPromptTemplate」と出力を整形する「StrOutputParser」がいるはずです。これは上の画像に赤枠で示した「Most relevant」の部分を「Show All」に変更することで確認することができます。

![スクリーンショット 2024-05-07 165305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/896babc9-6e7d-01bf-6618-f61452e97aa9.png)

それぞれのプロセスで実際に何が行われたか確認できるので、デバッグに有効活用できますね。
また、例えばこのチャットボットを公開する場合、特定のユーザーを特定のプロジェクトと紐づけることでそのユーザーが過去にした質問の履歴とその答えを確認することができます。

## テストに活用する
LangSmithには入力の例をいくつか作成しておき、それぞれに対する回答が問題なかったかをテストする機能があります。
例えば、[公式のチュートリアル](https://python.langchain.com/docs/langsmith/walkthrough/#evaluate-agent)では質問と正答のセットをいくつか用意し、それを比較することでモデルが出力した回答をテストする方法が紹介されています。
正答との比較だけでなく、回答に「don't know」や「not sure」が含まれているかといった多角的なチェックが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480220/6879bbc8-0666-b574-d094-25bfdf2f0061.png)
（画像は[公式のチュートリアル](https://python.langchain.com/docs/langsmith/walkthrough/#evaluate-agent)からの引用）

本シリーズでは詳細にテストする必要はないので詳しい紹介は割愛しますが、実際にチャットボットとして提供される際にはぜひ活用してみてください。

## おわりに
今回はLangSmithでチャットボットの実行プロセスを追跡しました。ステップバイステップで確認することで開発時のデバッグがずいぶん楽になりますね。
次回はRAGと呼ばれるあらかじめ与えた情報に基づいて回答するための仕組みを導入します。「オリジナル度合い」が上がってより楽しくなりますよ！