LangChainとGradioを使ったLLMアプリ開発

# はじめに
流行りのChatGPTなどのLLMを使ったデモアプリを簡単に作れる方法としてGradioを用いて検証したので、備忘録的にまとめます。

# 開発環境
- python3.9
- langchain
- gradio
- Google Colab


# 想定読者
- LLMを使った簡単なアプリを作りたい人（langchainの詳細な技術については省略します）
- Gradioを使った機械学習アプリを作成したい人
- Google Colabなどを使って、LLMの機能検証を行い、アプリ化しようとしている人

# やりたいこと
- いい感じのインターフェースでデモアプリを作りたい
- デモのインターフェースとしてnotebook環境は万人受けしない


# 実行コード
https://github.com/t-hashiguchi1995/ChatGPT_APP_Gradio/tree/main

## 必要な手続き
- Google検索のAPIキー作成
1. https://qiita.com/zak_y/items/42ca0f1ea14f7046108c
- OpenAIのAPIキー作成
1. https://openai.com/blog/openai-api にアクセスし、ログイン（アカウント未発行の場合、作成）
1. APIをクリック
1. 画面右上の【Personal】をクリック
1. 【View API keys】から【Create new Secret key】を実行
1. APIキーの名前を入力し、コピーする。【sk-XXX】の文字列がAPIキー
- huggingfaceのアカウント作成
1. Gradioで作成したアプリをデプロイするのに必要
1. https://huggingface.co/ からアカウント作成

## デモ実行

### 作成したAPI情報をコピー、貼り付け
```
from langchain.agents import load_tools, initialize_agent, Tool, AgentType
from langchain.utilities.google_search import GoogleSearchAPIWrapper
from langchain.chat_models import ChatOpenAI

import gradio as gr

import os
os.environ["OPENAI_API_KEY"] = "XXXXX"
os.environ["GOOGLE_API_KEY"] = "YYYYY"
os.environ["GOOGLE_CSE_ID"] = "ZZZZ"
```


### ログを出力
（なくても問題ない）
```
from logging import getLogger
logger = getLogger(__name__)
```

### LLM検証機能

今回はグーグル検索を活用して、生成を行ってもらいたいため、グーグル検索のツールを利用
他にも色んなツールがあるので、LLMの利用用途に応じて利用してください。
- https://python.langchain.com/docs/modules/agents/tools/

```
def search_llm(query: str, model_name: str):
  llm = ChatOpenAI(temperature=0, model=model_name)
  google_search = GoogleSearchAPIWrapper()
  search_tools = [Tool(
      name = "Google Search",
      func=google_search.run,
      description="最新の話題について答える場合に利用することができます。また、今日の日付や今日の気温、天気、為替レートなど現在の状況についても確認することができます。入力は検索内容です。"
      ),]
  search_agent = initialize_agent(search_tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
  search_result = search_agent.run(f"{query}")
  return search_result
```

### Gradioアプリ関数
関数名と入力、出力の内容が**重要**
関数内の処理は適宜変更してよい
```
def app(query: str, model_name: str):
  search_result = search_llm(query, model_name)
  logger.info(search_result)
  return search_result
```

### アプリ実行
デモアプリのインターフェース上にテキストでの説明を付与可能
```
title : str = "デモアプリ"
description : str = "このデモンストレーションは、Gradio（ユーザーインターフェースのライブラリ）を使用しています"
article : str='''このデモンストレーションは、ユーザーインターフェースを作成するためのPythonのライブラリであるGradioを使用しています。
'''
```

先ほどアプリ化した関数を実行するインターフェースを設計
- fnに**アプリ化する関数名**
- inputsに**該当する関数の入力**。今回は自由入力のテキストとOpenAIで利用するChatモデルの種類の2つを入力。
- outputsに**該当する関数の出力**。今回はテキストのみが出力。
- examplesに入力例。chache_examplesと併用することで、1クリックでexamplesの実行結果を確認できる。


```
iface1 = gr.Interface(
    fn=app,
    inputs=[
        gr.Textbox(lines=1, placeholder="query Here"),
        gr.Dropdown(["gpt-3.5-turbo-16k", "gpt-4", "gpt-4-0613"]),
        ],
    outputs=["text"],
    cache_examples=True,
    examples=[
        ["ChatGPTでできること", "gpt-3.5-turbo-16k"],
        ["ChatGPTでできること", "gpt-4-0613"],
        ["日本で一番高い山", "gpt-4-0613"],
    ],
    title=title,
    description=description,
    article=article
    )
```


- queue()を入れることで、実行時間による処理停止がなくなるため、処理時間がかかるものには入れるのがおすすめ。
- launch()でアプリを実行します。
- Google Colabの場合、share=Trueにすることで、URLを使えば、他端末からデモを確認可能。
- authに認証を入れることで、利用者を限定可能。例では**username=user**、**password=password**を入力することでデモにログインできる。
```
iface1.queue()
iface1.launch(share=True, auth=("user", "password"), debug=True)
```


# デモ画面
:::note info
この画面でuserとpasswordを入力
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425860/0bdbbc6a-61fe-6391-fcd9-d105ade3c4f0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425860/654e20fc-2930-53ff-edcb-03d82a60c7b5.png)

:::note info
アプリ実行時にexamplesの内容が実行されます
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425860/da37e963-2ce0-e6e0-0f83-da3b6276f6d5.png)



## デモ実行
examplesを見る限り、日本で一番高い山は周知の事項のようなので、1位から10位までを教えてもらいましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425860/092ac859-3ad1-c7a3-42ce-a2f0911498a1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425860/6f1b7ae2-75aa-828b-03fd-578111b94e66.png)
結果として、1位～7位までしか分からなかったようです...が、不足している情報を補うような検索クエリの試行をしています。
これはlangchainで指定したagentの中にあるプロンプト内に答えが出るまで繰り返し実行するようになっているためです。（場合によっては何回かやって結果が出ないとエラーメッセージが出ます）


# デプロイ
アプリの機能は上手くできていることが確認できたので、デプロイしましょう。
1. https://huggingface.co/spaces から**Create new Space**をクリック
1. 適切な内容を入力後、**Create Space**（一部除いて後からでも変更可能）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425860/0aad1812-c0e0-a7b3-ae94-b29a45b18911.png)
1. spacesの内容をgit cloneし、app.pyとrequirements.txtを該当のリポジトリに格納
1. commitと**huggingfaceのアカウント**でpushの実行




# 参考情報
1. https://python.langchain.com/docs/get_started/introduction.html
1. https://www.gradio.app/
1. https://docs.python.org/ja/3/library/logging.html
1. https://qiita.com/amedama/items/b856b2f30c2f38665701