Open2
LangChainメモ
トークン数と課金額の確認
from langchain.callbacks import get_openai_callback
with get_openai_callback() as cb:
# ここでOpen AIを使用した処理
print(cb)
Prompt Tokens: 393449
Completion Tokens: 132951
Successful Requests: 900
Total Cost (USD): $1.712150999999997
LangGraphをさわる
概要
LangChain v0.1.0, LCELでエージェントを作ってみようと思ってLangGraphをさわってみた。
本当は、中間ステップを書き出してほしいだけなのだが。
主に以下のgithubの内容をなぞる。
各要素の定義
エージェントを構成する要素を順番に作成する。
- ツールの定義
- プロンプトの定義
ツールの定義
githubではTavilyを使用していますがAPI取得が面倒なので、お手軽なWikipedia検索のツールを使用。
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
api_wrapper = WikipediaAPIWrapper(top_k_results=1, doc_content_chars_max=100)
tool = WikipediaQueryRun(api_wrapper=api_wrapper)
tools = [tool]
プロンプトの定義
-
hub.pull("hwchase17/openai-functions-agent")
でいいのだが、中身をある程度理解したいため書き出す。 - 要は
input(質問文)
とagent_scratchpad
を入力として、4つの会話を準備してくれるっぽい。
"""
以下2行と同じ
from langchain import hub
prompt = hub.pull("hwchase17/openai-functions-agent")
"""
from langchain.prompts import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
MessagesPlaceholder,
HumanMessagePromptTemplate
)
from typing import List, Union
import langchain_core
prompt = ChatPromptTemplate(
input_variables=['agent_scratchpad', 'input'],
input_types={
'chat_history': List[
Union[
langchain_core.messages.ai.AIMessage,
langchain_core.messages.human.HumanMessage,
langchain_core.messages.chat.ChatMessage,
langchain_core.messages.system.SystemMessage,
langchain_core.messages.function.FunctionMessage,
langchain_core.messages.tool.ToolMessage
]
],
'agent_scratchpad': List[
Union[
langchain_core.messages.ai.AIMessage,
langchain_core.messages.human.HumanMessage,
langchain_core.messages.chat.ChatMessage,
langchain_core.messages.system.SystemMessage,
langchain_core.messages.function.FunctionMessage,
langchain_core.messages.tool.ToolMessage
]
]
},
messages=[
SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], template='You are a helpful assistant')),
MessagesPlaceholder(variable_name='chat_history', optional=True),
HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'], template='{input}')),
MessagesPlaceholder(variable_name='agent_scratchpad')
]
)
モデルの定義
v0.1.0よりlangchain_openai
からインポートするのが良いらしい。
from langchain_openai.chat_models import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo-1106")
Azure OpenAI Serviceを使用する場合は以下の通り。
function-calling使うんだろうか?
from langchain_openai.chat_models import AzureChatOpenAI
llm = AzureChatOpenAI(
openai_api_version="2023-07-01-preview",
azure_deployment="<デプロイ名称>",
)
OpenAI Functions エージェントの定義
普通のエージェントとは、なにか違うのだろうか?とりあえずRunnableクラスになってるらしい。
agent_runnable = create_openai_functions_agent(llm, tools, prompt)
agent_runnable.get_graph().print_ascii()
でチェインの構造を見ると、LCELでよく見るグラフ構造が見える。Lambdaの所は、data = RunnableLambda(lambda x: format_to_openai_function_messages(x['intermediate_steps'])))
。
+---------------------------------+
| Parallel<agent_scratchpad>Input |
+---------------------------------+
*** ***
**** ****
** **
+---------------------------------------+ +-------------+
| Lambda(lambda x: format_to_openai_... | | Passthrough |
+---------------------------------------+ *+-------------+
*** ***
**** ****
** **
+----------------------------------+
| Parallel<agent_scratchpad>Output |
+----------------------------------+
*
*
*
+--------------------+
| ChatPromptTemplate |
+--------------------+
*
*
*
+-----------------+
| AzureChatOpenAI |
+-----------------+
*
*
*
+----------------------------------+
| OpenAIFunctionsAgentOutputParser |
+----------------------------------+
*
*
*
+----------------------------------------+
| OpenAIFunctionsAgentOutputParserOutput |
+----------------------------------------+
エージェントの定義
通常のエージェントを定義する。
from langchain_core.runnables import RunnablePassthrough
agent = RunnablePassthrough.assign(
agent_outcome = agent_runnable
)
ツール実行関数の定義
# ツールを実行する関数を定義する
def execute_tools(data):
# Get the most recent agent_outcome - this is the key added in the `agent` above
agent_action = data.pop('agent_outcome')
# Get the tool to use
tool_to_use = {t.name: t for t in tools}[agent_action.tool]
# Call that tool on the input
observation = tool_to_use.invoke(agent_action.tool_input)
# We now add in the action and the observation to the `intermediate_steps` list
# This is the list of all previous actions taken and their output
data['intermediate_steps'].append((agent_action, observation))
return data
# Define logic that will be used to determine which conditional edge to go down
def should_continue(data):
# If the agent outcome is an AgentFinish, then we return `exit` string
# This will be used when setting up the graph to define the flow
if isinstance(data['agent_outcome'], AgentFinish):
return "exit"
# Otherwise, an AgentAction is returned
# Here we return `continue` string
# This will be used when setting up the graph to define the flow
else:
return "continue"