[翻訳] LangChainのクイックスタートガイド

[Quickstart Guide — 🦜🔗 LangChain 0\.0\.181](https://python.langchain.com/en/latest/getting_started/getting_started.html)の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

このチュートリアルでは、LangChainを用いたエンドツーエンドの言語モデルの構築のクイックなウォークスルーを提供します。

# インストール

スタートするには、以下のコマンドでLangChainをインストールします：

```
pip install langchain
# or
conda install langchain -c conda-forge
```

# 環境のセットアップ

LangChainを使用する際には通常、一つ以上のモデルプロバイダー、データストア、APIなどとのインテグレーションが必要となります。

この例では、OpenAIのAPIを使用するので、最初にそれらのSDKのインストールが必要となります：

```
pip install openai
```

そして、ターミナルで環境変数を設定する必要があります。

```sh
export OPENAI_API_KEY="..."
```

あるいは、Jupyterノートブック(やPythonスクリプト)内でこれを実行することもできます。

```py
import os
os.environ["OPENAI_API_KEY"] = "..."
```

ユーザーごとのAPIキーを設定するなど、APIキーを動的に設定したいのであれば、OpenAIクラスのインスタンスを作成する際にopenai_api_keyパラメーターを使用することができます。

```py
from langchain.llms import OpenAI
llm = OpenAI(openai_api_key="OPENAI_API_KEY")
```

# 言語モデルアプリケーションの構築：LLM

これでLangChainがインストールされ、環境がセットアップされたので、言語モデルアプリケーションを構築し始めることができます。

LangChainは言語モデルアプリケーションを構築する際に活用できる数多くのモジュールを提供しています。より複雑なアプリケーションを作成するためにモジュールを組み合わせることができ、シンプルなアプリケーションでは個別に使用することができます。

# LLM：言語モデルから予測結果を取得する

LangChainの最も基本的なビルディングブロックは、いくつかの入力に対してLLMを呼び出すというものです。これをどのように行うのかを示すシンプルなサンプルを通じてウォークスルーしましょう。このため、ここでは企業が製造するものに基づいて企業名を生成するサービスを構築しているとしましょう。これを行うには、初めにLLMラッパーをインポートする必要があります。

```py
from langchain.llms import OpenAI
```

そして、任意の引数を用いてこのラッパーを初期化することができます。この例では、出力がより**ランダム**であって欲しいと考えるので、**高い**temperatureを用いて初期化します。

```py
llm = OpenAI(temperature=0.9)
```

これで、入力を指定して呼び出すことができます！

```py
text = "What would be a good company name for a company that makes colorful socks?"
print(llm(text))
```
```
Feetful of Fun
```

LangChainにおけるLLMの使用法の詳細については、[LLM getting started guide](https://python.langchain.com/en/latest/modules/models/llms/getting_started.html)をご覧ください。

# プロンプトテンプレート：LLMのプロンプトの管理

LLMの呼び出しは素晴らしい第一歩でしたが、これは始まりに過ぎません。アプリケーションでLLMを使用する際は通常、LLMに直接ユーザーの入力を送信しません。そうではなく、ユーザーの入力を受け取り、プロンプトを構築してからLLMにそれを送信するでしょう。例えば、上の例では引き渡したテキストは、カラフルな靴下を作成する企業の名前を尋ねるためにハードコードしました。この架空のサービスで行いたいのは、企業が何をしているのかを説明するユーザー入力を受け取り、その情報を用いてプロンプトをフォーマットすることです。

これは、LangChainなら簡単です！

初めに、プロンプトテンプレートを定義しましょう：

```py
from langchain.prompts import PromptTemplate

prompt = PromptTemplate(
    input_variables=["product"],
    template="What is a good name for a company that makes {product}?",
)
```

次にこれがどのように動作するのかを見てみましょう！フォーマットを行うために`.format`メソッドを呼び出します。

```py
print(prompt.format(product="colorful socks"))
```
```
What is a good name for a company that makes colorful socks?
```

詳細は[getting started guide for prompts](https://python.langchain.com/en/latest/modules/prompts/chat_prompt_template.html)をご覧ください。

# チェーン：複数ステップのワークフローにLLMとプロンプトを統合する

ここまでで、プロンプトテンプレートとLLMプリミティブを取り扱ってきました。しかし、もちろんですが、リアルなアプリケーションは単なるプリミティブではなく、これらの組み合わせとなります。

LangChainのチェーンは、LLMのようなプリミティブ、あるいは他のチェーンのリンクを構成します。

チェーンの最もコアなタイプは、PromptTemplateとLLMから構成されるLLMChainです。

上の例を拡張して、ユーザー入力を受け取り、PromptTemplateでフォーマットを行い、フォーマットされたレスポンスをLLMに引き渡すLLMChainを構築します。

```py
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI

llm = OpenAI(temperature=0.9)
prompt = PromptTemplate(
    input_variables=["product"],
    template="What is a good name for a company that makes {product}?",
)
```

これで、ユーザー入力を受け取り、それを用いてプロンプトをフォーマットし、LLMに送信する非常にシンプルなチェーンを作成することができます。

```py
from langchain.chains import LLMChain
chain = LLMChain(llm=llm, prompt=prompt)
```

これで、製品を指定するだけでこのチェーンを実行することができます！

```py
chain.run("colorful socks")
# -> '\n\nSocktastic!'
```

やりました！これが最初のチェーン、LLMChainです。これは、チェーンのシンプルなタイプですが、動作原理を理解することで、より複雑なチェーンを取り扱う準備ができました。

詳細は[getting started guide for chains](https://python.langchain.com/en/latest/modules/chains/getting_started.html)をご覧ください。

# エージェント：ユーザー入力に基づいて動的にチェーンを呼び出す

ここまででみたチェーンは事前に決めた順序で実行されます。

エージェントはそうではありません：これらはどのアクションを適用し、どのような順序で実行するのかを決定するためにLLMを活用します。アクションは、ツールの活用やアウトプットの観測、ユーザーへの返却などです。

適切にエージェントを活用すると非常にパワフルなものとなります。このチュートリアルでは、最もシンプルで高レベルなAPIを通じて、エージェントをどのように簡単に活用できるのかを説明します。

エージェントをロードするには、以下のコンセプトを理解する必要があります：

- ツール：固有の仕事を実行する関数。これは、Google検索、データベース検索、Python REPL、他のチェーンのようなものとなります。ツールの現在のインタフェースは、文字列としての入力、出力としての文字列を受け付ける関数です。
- LLM：エージェントを支援する言語モデル。
- エージェント：使用するエージェント。これは、サポートエージェントクラスを参照する文字列である必要があります。このノートブックでは、最もシンプルで高レベルのAPIにフォーカスしているので、ここでは標準的なサポートエージェントの活用のカバーに留めています。カスタムエージェントを実装いs隊のであれば、カスタムエージェントのドキュメントをご覧ください(まもなく提供されます)。

**エージェント**：サポートされるエージェントと仕様については[こちら](https://python.langchain.com/en/latest/modules/agents/getting_started.html)を参照ください。
**ツール**：定義済みツールのリストと仕様については[こちら](https://python.langchain.com/en/latest/modules/agents/tools/getting_started.html)をご覧ください。

この例では、SearchAPI Pythonパッケージをインストールする必要があります。

```
pip install google-search-results
```

そして、適切な環境変数を設定します。

```py
import os
os.environ["SERPAPI_API_KEY"] = "..."
```

それでは始めましょう！

```py
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.llms import OpenAI

# First, let's load the language model we're going to use to control the agent.
llm = OpenAI(temperature=0)

# Next, let's load some tools to use. Note that the `llm-math` tool uses an LLM, so we need to pass that in.
tools = load_tools(["serpapi", "llm-math"], llm=llm)


# Finally, let's initialize an agent with the tools, the language model, and the type of agent we want to use.
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

# Now let's test it out!
agent.run("What was the high temperature in SF yesterday in Fahrenheit? What is that number raised to the .023 power?")
```

```
> Entering new AgentExecutor chain...
 I need to find the temperature first, then use the calculator to raise it to the .023 power.
Action: Search
Action Input: "High temperature in SF yesterday"
Observation: San Francisco Temperature Yesterday. Maximum temperature yesterday: 57 °F (at 1:56 pm) Minimum temperature yesterday: 49 °F (at 1:56 am) Average temperature ...
Thought: I now have the temperature, so I can use the calculator to raise it to the .023 power.
Action: Calculator
Action Input: 57^.023
Observation: Answer: 1.0974509573251117

Thought: I now know the final answer
Final Answer: The high temperature in SF yesterday in Fahrenheit raised to the .023 power is 1.0974509573251117.

> Finished chain.
```

# メモリー：チェーンとエージェントに状態を追加する

ここまで見てきたチェーンとエージェントはステートレスです。しかし、多くの場合において、以前のインタラクションに関する情報を覚えるように、「メモリー」のコンセプトをチェーンやエージェントに持たせたいことがあるでしょう。これの最もクリアでシンプルな例は、チャットボットを設計するときです。より良い会話を行えるように、コンテキストを利用できるように過去のメッセージを記憶して欲しいと思うことでしょう。これは一種の「短期記憶」です。より複雑になると、ある一定期間においてキーとなる情報をチェーン/エージェントが記憶するようなことを想像することでしょう。これは「長期記憶」の一形態です。後者に関するより具体的な考え方に関しては、こちらの[素晴らしい論文](https://memprompt.com/)を参照ください。

LangChainはこの目的のためだけに特別に作成されたいくつかのチェーンを提供します。このノートブックでは、2つの異なるタイプのメモリーを用いて、これらのチェーンの一つ(`ConversationChain`)をウォークスルーします。

デフォルトでは、`ConversationChain`には過去すべての入力/出力を記憶して指定されるコンテキストに追加するシンプルなタイプのメモリーがあります。このチェーンの使用法を見ていきましょう(プロンプトを見れるように`verbose=True`を設定します)。

```py
from langchain import OpenAI, ConversationChain

llm = OpenAI(temperature=0)
conversation = ConversationChain(llm=llm, verbose=True)

output = conversation.predict(input="Hi there!")
print(output)
```
```
> Entering new chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:

Human: Hi there!
AI:

> Finished chain.
' Hello! How are you today?'
```
```py
output = conversation.predict(input="I'm doing well! Just having a conversation with an AI.")
print(output)
```
```
> Entering new chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:

Human: Hi there!
AI:  Hello! How are you today?
Human: I'm doing well! Just having a conversation with an AI.
AI:

> Finished chain.
" That's great! What would you like to talk about?"
```

# チャットモデルからメッセージコンプリーションを取得する

チャットモデルに1つ以上のメッセージを渡すことでチャットコンプリーションを得ることができます。LangChainで現在されているメッセージタイプは、`AIMessage`, `HumanMessage`, `SystemMessage`, `ChatMessage`です。`ChatMessage`は任意のロールのパラメーターを受け取ります。多くの場合、`HumanMessage`, `AIMessage`, `SystemMessage`を取り扱います。

```py
from langchain.chat_models import ChatOpenAI
from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage
)

chat = ChatOpenAI(temperature=0)
```

単一のメッセージを渡すことでコンプリーションを得ることができます。

```py
chat([HumanMessage(content="Translate this sentence from English to French. I love programming.")])
# -> AIMessage(content="J'aime programmer.", additional_kwargs={})
```

また、OpenAIのgpt-3.5-turboやgpt-4モデルに複数のメッセージを渡すことができます。

```py
messages = [
    SystemMessage(content="You are a helpful assistant that translates English to French."),
    HumanMessage(content="I love programming.")
]
chat(messages)
# -> AIMessage(content="J'aime programmer.", additional_kwargs={})
```

さらに、`generate`を用いて、複数セットのメッセージに対するコンプリーションを生成することができます。これは追加の`message`パラメーターを持つ`LLMResult`を返却します。


```py
batch_messages = [
    [
        SystemMessage(content="You are a helpful assistant that translates English to French."),
        HumanMessage(content="I love programming.")
    ],
    [
        SystemMessage(content="You are a helpful assistant that translates English to French."),
        HumanMessage(content="I love artificial intelligence.")
    ],
]
result = chat.generate(batch_messages)
result
# -> LLMResult(generations=[[ChatGeneration(text="J'aime programmer.", generation_info=None, message=AIMessage(content="J'aime programmer.", additional_kwargs={}))], [ChatGeneration(text="J'aime l'intelligence artificielle.", generation_info=None, message=AIMessage(content="J'aime l'intelligence artificielle.", additional_kwargs={}))]], llm_output={'token_usage': {'prompt_tokens': 57, 'completion_tokens': 20, 'total_tokens': 77}})
```

このLLMResultからのトークンを使用するなど物事を復帰することができます。

```py
result.llm_output['token_usage']
# -> {'prompt_tokens': 57, 'completion_tokens': 20, 'total_tokens': 77}
```

# チャットプロンプトテンプレート

LLMと同じように、`MessagePromptTemplate`を用いてテンプレートを活用することができます。一つ以上の`MessagePromptTemplates`から`ChatPromptTemplate`を構築することができます。`ChatPromptTemplate`の`format_prompt`を活用することができます。これは、LLMやチャットモデルへの入力としてフォーマットされた値を使用したいのかどうかに応じて、文字列や`Message`オブジェクトに変換できる`PromptValue`を返却します。

便利に使えるように、テンプレートに公開される`from_template`メソッドがあります。このテンプレートを使用するのであれば、以下のようなものになります：

```py
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

chat = ChatOpenAI(temperature=0)

template = "You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)

chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])

# get a chat completion from the formatted messages
chat(chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.").to_messages())
# -> AIMessage(content="J'aime programmer.", additional_kwargs={})
```

# チャットモデルを用いたチェーン

上のセクションで議論した`LLMChain`は、チャットモデルでも使用できます：

```py
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain
from langchain.prompts.chat import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

chat = ChatOpenAI(temperature=0)

template = "You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])

chain = LLMChain(llm=chat, prompt=chat_prompt)
chain.run(input_language="English", output_language="French", text="I love programming.")
# -> "J'aime programmer."
```

# チャットモデルを用いたエージェント

チャットモデルでもエージェントを活用することができ、エージェントタイプとして`AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION`を用いて初期化することができます。

```py
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.chat_models import ChatOpenAI
from langchain.llms import OpenAI

# First, let's load the language model we're going to use to control the agent.
chat = ChatOpenAI(temperature=0)

# Next, let's load some tools to use. Note that the `llm-math` tool uses an LLM, so we need to pass that in.
llm = OpenAI(temperature=0)
tools = load_tools(["serpapi", "llm-math"], llm=llm)


# Finally, let's initialize an agent with the tools, the language model, and the type of agent we want to use.
agent = initialize_agent(tools, chat, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

# Now let's test it out!
agent.run("Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?")
```
```

> Entering new AgentExecutor chain...
Thought: I need to use a search engine to find Olivia Wilde's boyfriend and a calculator to raise his age to the 0.23 power.
Action:
{
  "action": "Search",
  "action_input": "Olivia Wilde boyfriend"
}

Observation: Sudeikis and Wilde's relationship ended in November 2020. Wilde was publicly served with court documents regarding child custody while she was presenting Don't Worry Darling at CinemaCon 2022. In January 2021, Wilde began dating singer Harry Styles after meeting during the filming of Don't Worry Darling.
Thought:I need to use a search engine to find Harry Styles' current age.
Action:
{
  "action": "Search",
  "action_input": "Harry Styles age"
}

Observation: 29 years
Thought:Now I need to calculate 29 raised to the 0.23 power.
Action:
{
  "action": "Calculator",
  "action_input": "29^0.23"
}

Observation: Answer: 2.169459462491557

Thought:I now know the final answer.
Final Answer: 2.169459462491557

> Finished chain.
'2.169459462491557'
```

# メモリー：チェーンとエージェントに状態を追加する

チャットモデルで初期化されたチェーンとエージェントでメモリーを活用することができます。LLMのメモリーとの大きな違いは、以前のすべてのメッセージを文字列に混ぜ合わせようとするのではなく、自身固有のメモリーオブジェクトとして保持できるということです。

```py
from langchain.prompts import (
    ChatPromptTemplate, 
    MessagesPlaceholder, 
    SystemMessagePromptTemplate, 
    HumanMessagePromptTemplate
)
from langchain.chains import ConversationChain
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory

prompt = ChatPromptTemplate.from_messages([
    SystemMessagePromptTemplate.from_template("The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know."),
    MessagesPlaceholder(variable_name="history"),
    HumanMessagePromptTemplate.from_template("{input}")
])

llm = ChatOpenAI(temperature=0)
memory = ConversationBufferMemory(return_messages=True)
conversation = ConversationChain(memory=memory, prompt=prompt, llm=llm)

conversation.predict(input="Hi there!")
# -> 'Hello! How can I assist you today?'


conversation.predict(input="I'm doing well! Just having a conversation with an AI.")
# -> "That sounds like fun! I'm happy to chat with you. Is there anything specific you'd like to talk about?"

conversation.predict(input="Tell me about yourself.")
# -> "Sure! I am an AI language model created by OpenAI. I was trained on a large dataset of text from the internet, which allows me to understand and generate human-like language. I can answer questions, provide information, and even have conversations like this one. Is there anything else you'd like to know about me?"
```