見出し画像

LangChain の HOW-TO EXAMPLES (5) - エージェント

「LangChain」の「エージェント」が提供する機能を紹介する HOW-TO EXAMPLES をまとめました。

前回

1. エージェントの機能

「エージェント」はLLMを使用して、実行するアクションその順序を決定します。アクションは、「ツールを実行してその出力を観察」「ユーザーに戻る」のいずれかになります。「ツール」は、特定の機能のことです。

エージェントは、次の3つの部分で構成されます。

・ツール : エージェントが使用できるツール。
・LLMChain : 実行するアクションを決定するためテキストを生成。
・エージェントクラス : LLMChainの出力を解析して、実行するアクションを決定。

「LangChain」には、カスタムツール、カスタムLLMChain、カスタムエージェントクラス(Comminc soon)を実装する仕組みも提供されています。

2. 中間ステップ

Agentクラスの引数に「return_intermediate_steps=True」を指定することで、エージェントが何をしているかをより詳細に可視化できます。

(1) エージェントの準備と質問応答の実行。

from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.llms import OpenAI

# エージェントの準備
agent = initialize_agent(
    llm=OpenAI(temperature=0), 
    tools=load_tools(["serpapi", "llm-math"], llm=OpenAI(temperature=0)), 
    agent="zero-shot-react-description", 
    verbose=True, 
    return_intermediate_steps=True
)

# 質問応答の実行
response = agent({"input":"サザエさんの年齢に2を掛けると?"})
> Entering new AgentExecutor chain...
 サザエさんの年齢を知る必要がある
Action: Search
Action Input: サザエさんの年齢
Observation: フグ田サザエ(ふぐたさざえ) 年齢は24歳。 明るく朗らか、竹を割ったような性格で、町内の人気者。 料理、洗濯、裁縫と主婦業はたいていこなしますが、おしゃべりとおっちょこちょいなのがたまにキズ。
Thought: サザエさんの年齢を2倍する
Action: Calculator
Action Input: 24 * 2
Observation: Answer: 48
Thought: I now know the final answer
Final Answer: サザエさんの年齢に2を掛けると48歳です。
> Finished AgentExecutor chain.

(2) 中間ステップの確認。
出力は見やすいように整形しています。

# 中間ステップの確認
print(response["intermediate_steps"])
[
    (
        AgentAction(
            tool='Search', 
            tool_input='サザエさんの年齢', 
            log=' サザエさんの年齢を知る必要がある\nAction: Search\nAction Input: サザエさんの年齢'
        ), 
        'フグ田サザエ(ふぐたさざえ) 年齢は24歳。 明るく朗らか、竹を割ったような性格で、町内の人気者。 料理、洗濯、裁縫と主婦業はたいていこなしますが、おしゃべりとおっちょこちょいなのがたまにキズ。'
    ), 
    (
        AgentAction(
            tool='Calculator', 
            tool_input='24 * 2', 
            log=' サザエさんの年齢を2倍する\nAction: Calculator\nAction Input: 24 * 2'
        ), 
        'Answer: 48'
    )
]

3. マルチ入力ツール

エージェントでマルチ入力ツールを利用するには、文字列をマルチ入力にパースする小さなラッパー関数を作成します。

(1) ツールとして呼び出す関数の準備。

from langchain.llms import OpenAI
from langchain.agents import initialize_agent, Tool

# 乗数関数
def multiplier(a, b):
    return a * b

# 文字列をを2つの引数に変換
def parsing_multiplier(string):
    a, b = string.split(",")
    return multiplier(int(a), int(b))

(2) ツールとエージェントの準備

# ツールの準備
llm = OpenAI(temperature=0)
tools = [
    Tool(
        name = "Multiplier",
        func=parsing_multiplier,
        description="useful for when you need to multiply two numbers together. The input to this tool should be a comma separated list of numbers of length two, representing the two numbers you want to multiply together. For example, `1,2` would be the input if you wanted to multiply 1 by 2."
    )
]

# エージェントの準備
mrkl = initialize_agent(
    tools, 
    llm, 
    agent="zero-shot-react-description", 
    verbose=True)

(3) エージェントの実行。

mrkl.run("3に4を掛けると?")
> Entering new AgentExecutor chain...
 I need to multiply 3 and 4 together
Action: Multiplier
Action Input: 3,4
Observation: 12
Thought: I now know the final answer
Final Answer: 3 × 4 = 12
> Finished AgentExecutor chain.
'3 × 4 = 12'

4. カスタムツール

カスタムツールの定義は、次のとおりです。ツールの説明はオプションですが、一部のエージェントで必要になります。

class Tool(NamedTuple):
    name: str  # ツール名
    func: Callable[[str], str]  # ツールの実行関数
    description: Optional[str] = None  # ツールの説明

エージェントにツールを使用させるには、ツールリストを提供する必要があります。

(1) パッケージのインポート。

# パッケージのインポート
from langchain.agents import initialize_agent, Tool
from langchain.llms import OpenAI
from langchain import LLMMathChain, SerpAPIWrapper

(2) LLMの準備。

# LLMの準備
llm = OpenAI(temperature=0)

(3) ツールリストの準備。

# ツールリストの準備
search = SerpAPIWrapper()  # 検索
llm_math_chain = LLMMathChain(llm=llm, verbose=True)  # 計算
tools = [
    Tool(
        name = "Search",
        func=search.run,
        description="useful for when you need to answer questions about current events"
    ),
    Tool(
        name="Calculator",
        func=llm_math_chain.run,
        description="useful for when you need to answer questions about math"
    )
]

(4) エージェントの準備と実行。

# エージェントの準備
agent = initialize_agent(
    tools, 
    llm, 
    agent="zero-shot-react-description", 
    verbose=True
)

# エージェントの実行
agent.run("ぼっち・ざ・ろっくの作者の名前を教えて")
> Entering new AgentExecutor chain...
 I need to find out who wrote the book
Action: Search
Action Input: "ぼっち・ざ・ろっくの作者"
Observation: 『ぼっち・ざ・ろっく!』( BOCCHI THE ROCK!) は、はまじあきによる日本の4コマ漫画。『 まんがタイムきららMAX』(芳文社)にて、20182月号から4月号までゲスト連載後、同年5月号から連載中。
Thought: I now know the final answer
Final Answer: はまじあき
> Finished AgentExecutor chain.
'はまじあき'

5. カスタムLLMChain

カスタムLLMChainの作成作業の多くは、プロンプトに帰着します。出力解析するために既存のエージェントクラスを使用しているため、プロンプトがその形式でテキスト生成するように指示することが非常に重要です。さらに現在、以前のアクションと観察に関するメモを入れるため、プロンプトの最後にagent_scratchpadが必要です。それに加えて、必要に応じてプロンプトをカスタマイズできます。

プロンプトに適切な指示が含まれるようにするために、ZeroShotAgentクラスでヘルパーメソッドを使用します。

・tools : エージェントがアクセスできるツールのリスト。
・prefix : ツール一覧の前に付ける文字列。
・suffix : ツール一覧の後に付ける文字列。
・input_variables : 最終プロンプトが期待する入力変数のリスト。

今回は、エージェントにGoogle検索へのアクセスを許可し、それをカスタマイズして、一人称は"ぼく"、語尾は"なのだ"を使用するようにします。

(1) パッケージのインポート。

# パッケージのインポート
from langchain.agents import ZeroShotAgent, Tool, AgentExecutor
from langchain import OpenAI, SerpAPIWrapper, LLMChain

(2) ツールリストの準備

# ツールリストの準備
search = SerpAPIWrapper()
tools = [
    Tool(
        name = "Search",
        func=search.run,
        description="useful for when you need to answer questions about current events"
    )
]

(3) ZeroShotAgentの準備。
プレフィックス、サフィックスをカスタマイズします。

prefix = """次の質問にできる限り答えてください。次のツールにアクセスできます:"""
suffix = """始めましょう! 最終的な答えを出すときは、一人称は"ぼく"、語尾には"なのだ"を使用してください

Question: {input}
{agent_scratchpad}"""

prompt = ZeroShotAgent.create_prompt(
    tools,
    prefix=prefix,
    suffix=suffix,
    input_variables=["input", "agent_scratchpad"]
)

(4) プロンプトの確認。

print(prompt.template)
次の質問にできる限り答えてください。次のツールにアクセスできます:

Search: useful for when you need to answer questions about current events

Use the following format:

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [Search]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

始めましょう! 最終的な答えを出すときは、一人称は"ぼく"、語尾には"なのだ"を使用してください

Question: {input}
{agent_scratchpad}

(5) AgentExecuterで実行。

# LLMChainの準備
llm_chain = LLMChain(llm=OpenAI(temperature=0), prompt=prompt)

# エージェントの準備
agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools)

# AgentExecuterで実行
agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True)
agent_executor.run("2022年の日本の人口は?")
> Entering new AgentExecutor chain...
Thought: この質問に答えるために何をすべきか考えるなのだ
Action: Search
Action Input: 2022年の日本の人口
Observation: 202211日時点の日本の人口は125927902人で、前年から726342人(0.57%)の減少。
Thought: これが最終的な答えなのだ
Final Answer: 202211日時点の日本の人口は125927902人で、前年から726342人(0.57%)の減少なのだ。
> Finished AgentExecutor chain.
'2022年1月1日時点の日本の人口は1億2592万7902人で、前年から72万6342人(0.57%)の減少なのだ。'

6. カスタムエージェントクラス

以下のドキュメントで Comminc soon になってます。

次回


この記事が気に入ったらサポートをしてみませんか?