Closed4

LangChainのTracingをためしてみる

kun432kun432

LangChainのデバッグ

LangChainで何が行われているかを見るためにはverbose=Trueをつけるのが一般的だと思うけど、例えばLLMに投げているプロンプトを全部見たい、とかは、使うChainやAgentなどによってはできないものがある。

https://github.com/hwchase17/langchain/issues/912

でこれを使うとできそうな雰囲気があるのでためしてみる。

https://python.langchain.com/en/latest/tracing.html

kun432kun432

環境

  • Mac
  • Docker Desktop
  • python-3.10.11

手順

仮想環境作る

$ pyenv install 3.10.11
$ pyenv virtualenv 3.10.11 langchain-tracing
$ mkdir langchain-tracing && cd langchain-tracing
$ pyenv local langchain-tracing

パッケージインストール

$ pip install openai langchain python-dotenv

langchain-serverを起動

$ langchain-server

langchain-db, langchain-backend, langchain-frontendの3つのコンテナが立ち上がる。

WARNING: Compose V1 is no longer supported and will be removed from Docker Desktop in an upcoming release. See https://docs.docker.com/go/compose-v1-eol/
Pulling langchain-db       ... done
Pulling langchain-backend  ... done
Pulling langchain-frontend ... done
WARNING: Compose V1 is no longer supported and will be removed from Docker Desktop in an upcoming release. See https://docs.docker.com/go/compose-v1-eol/
Creating network "langchain_default" with the default driver
Creating langchain_langchain-db_1 ... done
Creating langchain_langchain-backend_1 ... done
Creating langchain_langchain-frontend_1 ... done
Attaching to langchain_langchain-db_1, langchain_langchain-backend_1, langchain_langchain-frontend_1

以下のように表示されればOK。http://localhost:4173/がTracingのインタフェースらしい。

langchain-frontend_1  | PUBLIC_BASE_URL is set to:  http://localhost:8000
langchain-frontend_1  | DEV_MODE is set to:  true
langchain-frontend_1  |   ➜  Local:   http://localhost:4173/
langchain-frontend_1  |   ➜  Network: http://172.19.0.4:4173/

ブラウザでhttp://localhost:4173/にアクセスするとこんな感じ。

ドキュメントを読むと、この「セッション」をスクリプト側と紐付けておくことで、実行された内容がトレースできる、というものらしい。

とりあえずSession: defaultをクリックしてみる。

当然ながらなにもない。

ではスクリプトを実行してみる。環境変数LANGCHAIN_HANDLERを有効にする。今回はOpenAIのAPIキーもどうせ読み込まないといけないので.envに記述した。

.env
LANGCHAIN_HANDLER=langchain
OPENAI_API_KEY=xxxxxxxxxx

とりあえずLangChainのシンプルなサンプルを使ってみる。なおLANGCHAIN_HANDLERはLangChainの各モジュールをインポートする前に設定しないといけない様子。なのでdotenvで.envを読み出してからLangChainをインポートしている。

sample.py
import os
from dotenv import load_dotenv

load_dotenv()

from langchain import PromptTemplate, OpenAI, LLMChain

prompt_template = "What is a good name for a company that makes {product}?"

llm = OpenAI(temperature=0)
llm_chain = LLMChain(
    llm=llm,
    prompt=PromptTemplate.from_template(prompt_template),
    #verbose=True
)
print(llm_chain("colorful socks"))

実行してみる。

$ python sample.py
{'product': 'colorful socks', 'text': '\n\nSocktastic!'}

verbose=Trueを有効にしてみる。

sample.py
(snip)
llm_chain = LLMChain(
    llm=llm,
    prompt=PromptTemplate.from_template(prompt_template),
    verbose=True
)(snip)

LLMChainだと出力されるんだよねー。よいサンプルではなかったが、とりあえず。

$ python sample.py
> Entering new LLMChain chain...
Prompt after formatting:
What is a good name for a company that makes colorful socks?

> Finished chain.
{'product': 'colorful socks', 'text': '\n\nSocktastic!'}

実行した分だけこういう感じでInput/Outputのトレースが表示される。

なるほど、コンポーネントの親子関係みたいな感じでまとまっているっぽい。

Explorerをクリックすると、クリップボードにコピペできたり、子コンポーネントがあれば同じように中身を辿れる。

kun432kun432

RetrivalQAChainでためしてみる。

$ pip install chromadb tiktoken

LangChainのVectorDBサンプルでよく出てくるやつを持ってくる。

$ wget https://raw.githubusercontent.com/hwchase17/langchain/master/docs/modules/state_of_the_union.txt

サンプルコード

sample2.py
import os
from dotenv import load_dotenv

load_dotenv()

from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain.llms import OpenAI
from langchain.chains import RetrievalQA

from langchain.document_loaders import TextLoader
loader = TextLoader("state_of_the_union.txt")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
texts = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
docsearch = Chroma.from_documents(texts, embeddings)

qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type="stuff", retriever=docsearch.as_retriever())

query = "What did the president say about Ketanji Brown Jackson"
print(qa.run(query))

実行してみる

$ python sample2.py
(warning的なものはsnip)
 The president said that Judge Ketanji Brown Jackson is one of our nation's top legal minds, and will continue Justice Breyer's legacy of excellence.

verbose=Trueにして再度実行してみる。

sample2.py
(snip)
qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type="stuff", retriever=docsearch.as_retriever(), verbose=True)
(snip)
$ python sample2.py
(warning的なものはsnip)

> Entering new RetrievalQA chain...

> Finished chain.
 The president said that Ketanji Brown Jackson is one of the nation's top legal minds and will continue Justice Breyer's legacy of excellence.

そう、これなのよね、verbose=Trueが役に立たない。

Tracingでみてみるとこういう感じ。

一番下のllmのところを見てみると、こういう感じでLLMに投げられたプロンプトが見える。

プロンプトはこんな感じ。

Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.

And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.

Last month, I announced our plan to supercharge  
the Cancer Moonshot that President Obama asked me to lead six years ago.

This is personal to me and Jill, to Kamala, and to so many of you.

Vice President Harris and I ran for office with a new economic vision for America.

Question: What did the president say about Ketanji Brown Jackson
Helpful Answer:

chain_typemap_reduceに変えてみる。

sample2.py
(snip)
qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type="map_reduce", retriever=docsearch.as_retriever(), verbose=True)
(snip)
$ python sample2.py
(warning的なものはsnip)

> Entering new RetrievalQA chain...

> Finished chain.
 The president said that he nominated Circuit Court of Appeals Judge Ketanji Brown Jackson to continue Justice Breyer's legacy of excellence.

Tracingでみると、2回LLMに投げられているのがわかる。

1回目は、VectorDBからの検索結果をひとつづつ、質問に対して関連性があるかを確認している。

2回目は、上記で関連性があると判断されたものだけをLLMに渡して最終的な回答を生成している。

kun432kun432

まとめ

複雑なChainやAgentの場合はverbose=Trueだけでは全ての情報を見ることができないが、Tracing環境を用意すれば細かいところ、例えばLLMに投げるプロンプトとかが見えるようになる。

自分の場合は、

  • RetrievalQAChainのプロンプトテンプレートを少しカスタマイズしてみたい
  • でもデフォルトのプロンプトがどうなってるのかわからない
  • LangChainのコードをざっくり追いかけてみたけど、QAChainはchain_typeでプロンプト変わる?
  • 各chain_typeごとのプロンプトのコード、ちょっとわかりにくい

みたいな感じで、Tracingは十分役に立ちそうだと思った。それ以外でもデバッグ目的で使うのは良さそう。

あと、セッションは以下のように定義しておけば、分けることができるので、チームで開発している場合なんかでも使えそうではある(事前にGUIでセッションを作成しておく必要がある)

os.environ["LANGCHAIN_SESSION"] = "my_session"

んー、というかこれはdevcontainerにいれておきたいなー、docker-outside-of-dockerにしないといけなさそうな気がするけど。そしたらセッションとか考えなくて良さそうだし。

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