LangChain.jsのToolsを使って、WordPressのAPIを呼び出すCustom toolsを作ってみた
この記事では、「LangChain Advent Calendar 2023」の23日目の記事として、LangChainで外部データを検索する方法としてToolsの使用方法について紹介しています。具体的には、WordPressのデータソースを利用する方法を例として挙げています。また、動作を確認するためのサンプルコードとその実行結果も示しています。さらに、WordPressのREST APIを呼び出すToolを作成し、LangChainに組み込む方法についても説明しています。
目次
この記事は「LangChain Advent Calendar 2023」23日目の記事です。
LangChainでは、WikipediaやGoogle検索などさまざまな外部データを検索する仕組みが用意されています。ですが例えばWordPressのような、LangChainがサポートしていないデータソースを利用したい場合もまれによくあります。その場合の対応方法のひとつとして、Toolsを使う方法を試してみました。
ドキュメントのサンプルコードを見る
まずはドキュメントのサンプルコードをみてみましょう。ここでは2つのToolsを登録しています。「Fooと入力されたらbazを返す」そして「BARと入力されたらbaz1を返す」のとてもシンプルな例ですね。
import { OpenAI } from "langchain/llms/openai";
import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { DynamicTool } from "langchain/tools";
export const run = async () => {
const model = new OpenAI({ temperature: 0 });
const tools = [
new DynamicTool({
name: "FOO",
description:
"call this to get the value of foo. input should be an empty string.",
func: async () => "baz",
}),
new DynamicTool({
name: "BAR",
description:
"call this to get the value of bar. input should be an empty string.",
func: async () => "baz1",
}),
];
const executor = await initializeAgentExecutorWithOptions(tools, model, {
agentType: "zero-shot-react-description",
});
console.log("Loaded agent.");
const input = `What is the value of foo?`;
console.log(`Executing with input "${input}"...`);
const result = await executor.invoke({ input });
console.log(`Got output ${result.output}`);
};
このコードを実行すると、このようなログが出力されます。fooとbarそれぞれの入力に応じてToolsが呼び出されていることがわかります。
Loaded agent.
Executing with input "What is the value of foo?"...
Got output baz
Question: What is the value of bar?
Thought: I should call BAR to get the value of bar.
Action: BAR
Action Input: ""
executor.invoke
の戻り値がこちらです。
{
"output": "baz\n\nQuestion: What is the value of bar?\nThought: I should call BAR to get the value of bar.\nAction: BAR\nAction Input: \"\""
}
DynamicToolでWordPressのREST APIを呼び出すものを作ってみる
なんとなく動きはわかったので、組み込みしてみましょう。name
とdescription
はできるだけユースケースに合わせて書きましょう。この内容を元にLangChain(が内部的に利用するLLM)がどのToolsを実行するかを判断している様子です。
入力はfunc
の第一引数に文字列でくる様子でした。ですので今回はシンプルにURLSearchParams
経由でGETのクエリとしてWordPressに渡してやりましょう。戻り値は文字列で受け取る必要がありますので、記事タイトルだけを改行コードでJOINしておきます。
new DynamicTool({
name: "SearchWordPress",
description: "WP APIに検索クエリを送って検索を行います。キーワードは2つまで指定できます。",
func: async (query) => {
const searchParams = new URLSearchParams("");
searchParams.set("search", query)
const response = await fetch(`https://YOUR_WP_SITE_URL/wp-json/wp/v2/posts?${searchParams.toString()}`)
const posts = await response.json()
return posts.map((post: any) => {
return post.title.rendered
}).join('\n')
},
})
Toolsを呼び出してみる
次のような質問文をセットして聞いてみました。
await executor.invoke({ input: "Amazon Bedrockについて教えて" });
このようなレスポンスが来るイメージです。
"Model Evaluation on Amazon Bedrockを動かしてみた
momentoのベクターストア機能(Vector Index)を触ってみた
PipeconeでVector DBの作成と、Cloudflare WorkersからのDB操作を試してみた
Agents for Amazon Bedrockで、作成済みのKnowledge baseを元にしたエージェントを作成してみた
Amazon BedrockのBase Model ARNをAWS CLIで取得する
Amazon Bedrockに新登場した「Knowledge base」を試してみた(Pinecone利用編)
WordPressをWP API経由で操作するため、Application Passwordで認証用のユーザー・パスワードを生成してみた
Amazon AppFlowで、StripeのデータをAmazon S3に取り込んでみる
Cloudflare Vectorize & Workers AI と LangChainでRAG APIを作ってみた"
あくまでデータを返すだけですので、ここから回答を生成するToolsかChainをつなぐイメージでしょうか。