Closed8

ChainlitでLLMアプリを試してみた

kun432kun432

https://github.com/Chainlit/chainlit

Chainlit lets you create ChatGPT-like UIs on top of any Python code in minutes! Some of the key features include intermediary steps visualisation, element management & display (images, text, carousel, etc.) as well as cloud deployment.

Chainlitは、あらゆるPythonコードの上にChatGPTのようなUIを数分で作成することができます!主な機能として、中間ステップの可視化、要素の管理・表示(画像、テキスト、カルーセルなど)、クラウドデプロイメントなどが挙げられます。

kun432kun432

インストール

Get Startedやっていく。

https://docs.chainlit.io/overview

LAN内のサーバ上にあるpyenv-virtualenv環境で試す。Python-3.10.11。

$ pip install chainlit

起動。8000番ポートで上がってくる。

$ chainlit hello
OSError: [Errno 98] Address already in use: ('0.0.0.0', 8000)

うちの場合はポートが埋まっていた。GitHubのissueを見てみると以下を使えば良さそう。

  • 環境変数
    • CHAINLIT_HOST (デフォルト: 0.0.0.0)
    • CHAINLIT_PORT (デフォルト: 8000)
  • コマンドラインオプション
    • ただしこちらはchainlit runの場合のみっぽい。
    • --host IPアドレス
    • --port ポート番号

https://github.com/Chainlit/chainlit/issues/14

ということで、今回は環境変数で8888ポートを使う。

$ CHAINLIT_PORT=8888 chainlit hello
2023-06-06 19:17:15 - Your app is available at http://localhost:8888

ブラウザにアクセスしてみるも真っ白。設定変えたり、8000ポートを開けてデフォルトで起動してみるも同じ状況。issue見るとどうも同じ状況の人がいる様子。

https://github.com/Chainlit/chainlit/issues/38

環境依存なのかもしれないが、ちょっと原因がわからない。

気を取り直して、ローカルマシンのdevcontainerでやってみるとうまくいった。

サンプルは単に名前を入れて応答するだけのものなので、これ以上の会話は続かない。

ということでコードを書いていく。

kun432kun432

ChainlitでPythonアプリを書く

https://docs.chainlit.io/pure-python

app.pyを以下の内容で作成する

app.py
import chainlit as cl

@cl.on_message
def main(message: str):
    # Your custom logic goes here...

    # Send a response back to the user
    cl.Message(
        content=f"Received: {message}",
    ).send()

スクリプトをchainlitで実行する場合はrun。このへんはstereamlitと同じ。名前や見た目もそれっぽいしね。

$ chainlit run app.py 

ブラウザでアクセスしてみる。実行したスクリプトと同じパスにchainlit.mdがあるとその内容が表示される様子(上にある"Readme"も同じ)。

フォームに入力するとこんな感じで先ほどのコードが動く

コードをざっと見た感じ

  • @cl.on_messageでユーザからの入力があれば実行される処理を書く。
  • cl.Message().sendでメッセージを返す。

run に -w をつけると、スクリプトに変更があれば自動リロードされる。

$ chainlit run app.py -w

らしいのだが、修正して実行するとこうなる。

ValueError: Module should at least expose one of @langchain_factory, @on_message or @on_chat_start function

なぜこのエラーに鳴るのか意味がわからないが、例えば以下のようなコードだと問題なく自動リロードが効くので、バグなのかな?

import chainlit as cl


@cl.on_chat_start
def main():
    res = cl.AskUserMessage(content="What is your name?", timeout=10).send()
    if res:
        cl.Message(
            content=f"Your name is: {res['content']}",
        ).send()

@cl.on_message
def main(message: str):

    cl.Message(
        content=f"R: {message}",
    ).send()
kun432kun432

LangChainと組み合わせてみる

https://docs.chainlit.io/langchain

LangChainをインストール

$ pip install langchain

.envを作成。chainlitは.envを自動的に読んでくれる。

.env
OPENAI_API_KEY=XXXXXXXXXX

コード

app.py
import os
from langchain import PromptTemplate, OpenAI, LLMChain
import chainlit as cl

template = """質問: {question}

回答: ステップバイステップで考えてみましょう。"""

@cl.langchain_factory
def factory():
    prompt = PromptTemplate(template=template, input_variables=["question"])
    llm_chain = LLMChain(prompt=prompt, llm=OpenAI(temperature=0), verbose=True)

    return llm_chain

起動

$ chainlit run app.py -w

こんな感じで。ChatGPTのプラグインっぽい雰囲気がある。

こういう感じで回答が来る。Took 1 stepというところをクリックすると、

処理内容がここに表示されるっぽい。今回はシンプルなLLMChainなので大した内容ではないけど。

chainlitを起動したターミナルを見ると、プロンプトが表示されている。LangChainでverbose=Trueしているため。

ちなみにLangChainを使った場合、プロンプトやcompletionの結果は.chainlitディレクトリにキャッシュされるらしい。

$ ls -la .chainlit/
total 24
drwxr-xr-x 2 vscode vscode  4096 Jun  6 12:55 .
drwxr-xr-x 5 vscode vscode  4096 Jun  6 12:34 ..
-rw-r--r-- 1 vscode vscode 12288 Jun  6 12:55 .langchain.db
-rw-r--r-- 1 vscode vscode   954 Jun  6 10:34 config.toml

.langchain.dbはSQLite3で読める。

$ sqlite3 .chainlit/.langchain.db 
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.

sqlite> .tables
full_llm_cache

sqlite> .schema full_llm_cache
CREATE TABLE full_llm_cache (
        prompt VARCHAR NOT NULL, 
        llm VARCHAR NOT NULL, 
        idx INTEGER NOT NULL, 
        response VARCHAR, 
        PRIMARY KEY (prompt, llm, idx)
);

sqlite> .mode list

sqlite> select * from full_llm_cache;
prompt|llm|idx|response
質問: 明日の天気は?

回答: ステップバイステップで考えてみましょう。|[('_type', 'openai'), ('frequency_penalty', 0), ('logit_bias', {}), ('max_tokens', 256), ('model_name', 'text-davinci-003'), ('n', 1), ('presence_penalty', 0), ('request_timeout', None), ('stop', None), ('temperature', 0.0), ('top_p', 1)]|0|まず、地域によって天気は異なります。そのため、明日の天気を知るには、あなたが住んでいる地域の天気予報を確認する必要があります。

ということはキャッシュが効くはず。同じことを聞いてみた。

同じ回答が返ってくるのはもちろん、質問から回答を返すまでの時間が初回とそれ以降で異なることがわかる。

kun432kun432

もう少し複雑な例として、wolframalphaを使ったAgentを作ってみる。

$ pip install wolframalpha

.envに追加

.env
WOLFRAM_ALPHA_APPID=XXXXXXX

コード

app.py
import os
from langchain import OpenAI
from langchain.agents import initialize_agent, load_tools, AgentType
import chainlit as cl

@cl.on_chat_start
def main():
    cl.Message(
        content=f"何でも聞いてね。",
    ).send()

@cl.langchain_factory
def factory():
    agent = initialize_agent(
        tools=load_tools(['wolfram-alpha']),
        llm=OpenAI(temperature=0), 
        agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
        verbose=True,
    )
    return agent

Took...をクリックすると処理が見える。Wolfram Alphaに問い合わせしつつReACTで回答を検討しているのがわかる。

factoryでまるっとChainやAgentを渡すだけでいいのはとても楽ちん。

コンソールの方も。

> Entering new AgentExecutor chain...
 I need to compare the size of two lakes
Action: Wolfram Alpha
Action Input: "What is the size of Lake Biwa compared to twice the size of Lake Biwa"
Observation: Wolfram Alpha wasn't able to answer it
Thought: I need to compare the size of Lake Biwa and Lake Baikal
Action: Wolfram Alpha
Action Input: "What is the size of Lake Biwa compared to Lake Baikal"
Observation: Assumption: Lake Biwa
Lake Baikal | surface area 
Answer: Lake Biwa | 674 km^2 (square kilometers) (national rank: 1st | world rank: 276th)
Lake Baikal | 31500 km^2 (square kilometers) (national rank: 2nd | world rank: 8th)
Thought: I now know the final answer
Final Answer: バイカル湖の方が広いです。バイカル湖は、日本の最大の湖である琵琶湖の2倍以上の広さがあります。

> Finished chain.
kun432kun432

まとめ

まだそこまで深く触ってはないけど所感として。

  • かなりお手軽に書ける。たぶんstreamlitよりもライトに書けるのでは。
  • その名の通り、streamlitと雰囲気が似てる。streamlitを使ったことがあれば、ツールセットとしては同じ感覚になれそう。
  • ドキュメントもまあそこそこある印象。ただ内容が薄かったり、探しにくいところも。
  • ちょいちょいおかしな動きをするところがある。自動リロードでエラーになったり、なかなか起動しなかったり。

まだできたてホヤホヤなのでいろいろ不備もありそうだけど、LangChain触ってるなら、いい感じに使えそう。あとstreamlitと同じく、セッションも扱えるようだし、クラウドもあるみたい。

今後にも期待できそうなので、もうちょっと触ってみるつもり。

kun432kun432

そういえば日本語入力で変換確定のENTERを拾っちゃって送信するみたい。ChatGPTに聞きながらちょっと直してみた。

https://github.com/kun432/chainlit/tree/kun432/cjk-ime-fix

手元で確認した限りは問題なさそうではある。

が、react全然ワカラナイマンなので、pull req出すのちょっと躊躇してる・・・ ビクビクしながらPRだした

https://github.com/Chainlit/chainlit/pull/41

マージされた!

このスクラップは2023/06/06にクローズされました