0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LangChain を使って Function Call してみた

Last updated at Posted at 2025-04-26

はじめに

「AI エージェント」を使おう、とよく聞きます。また、にわかに「MCP」が話題になっています。
「AI エージェント」「MCP」について調べると、「Function Calling」が紹介されました。
まず「Function Calling」が何か調べたいと思います。

Fuction Calling とは

「function」は「機能」でしょうか「関数」でしょうか。これを生成 AI に「呼出」させるようですね。

Function Calling は、OpenAI 社が ChatGPT API サービスに追加した機能のようです (2023 年) 。Google Gemini 、Amazon Bedrock 、Anthropic Claude でも、Function Calling(または Tool Use)できるようになっています。

LangChain の Agents 機能で Tools 呼出することで、同様の機能を実現できるようです。これを試してみたいと思います。

LangChain+Ollama を使ってみる

Function Calling の実装を試すと、AI モデルを何度も呼出することになりそうです。ChatGPT API など有料サービスを使っているとつらそうです。ローカルで AI モデルを呼出できる環境がよさそうです。そのために Ollama を使うことにします。

【Ollama】ローカル環境でLLMを選んでLangChainで実行する。

実行環境を用意する

以前と同様に Google Colab を使ってみます。別の環境でも構いません。

参考:生成 AI プログラムを試してみた #LLM - Qiita

Google Colab のランタイムは「T4」を使いました。

以下のコード例は、Google Colab あるいは Jupyter Notebook で実行するものです。

Ollama を導入する

Ollama は実行ツールでありライブラリのようですね。

Ollama

まず Ollama 一式をインストールします。

# Ollama をインストール

! curl -fsSL https://ollama.com/install.sh | sh

コマンドを利用したり Python コードから呼出するには、Ollama プログラムを実行して常駐させるようです。Google Colab で実行するときは、nohup で実行します。↓

# Ollama を実行

! nohup ollama serve &

利用したい AI モデルを指定してダウンロードしておきます。まず Llama 3 を使うことにします。↓

# モデルをダウンロード

! ollama pull llama3.2

LangChain で Ollama を実行する

Ollama を LangChain で実行してみます。

# 必要なライブラリをインストール
! pip install langchain_ollama
import langchain_ollama
import langchain_core.prompts

# モデルを準備
model = langchain_ollama.OllamaLLM(
    model="llama3.2"
)

# プロンプトを準備
prompt = langchain_core.prompts.chat.ChatPromptTemplate.from_template(
"""Question: {query}
Answer:"""
)

query = "Function Calling とは何ですか?"

# 推論を実行
chain = (prompt | model)
output = chain.invoke({"query": query})

# 結果を出力
print(output)

LangChain で Function Call してみる

LangChain を使って Function Call してみましょう。

【Ollama】【LangChain】Function callingについて勉強してみる - パソコン関連もろもろ

Function(機能/関数)を用意する

まず、function(機能/関数) を用意します。LangChain の Tools(ツール) 機能を使います。

# 必要なライブラリをインストール
! pip install langchain langchain_core langchain_community
from langchain.tools import tool

# 関数を用意
@tool
def add_numbers(x: int, y: int) -> int:
    """Add two numbers together."""
    return x + y

tools = [add_numbers]

簡単に「足し算する」関数です。↑

Agent(エージェント)を実行する

続いて、LangChain の Agent(エージェント) を用意します。

import langchain_ollama
import langchain.agents
import langchain_core.prompts

# モデルを準備
model = langchain_ollama.ChatOllama(
    model="llama3.2"
)

# プロンプトを準備
prompt = langchain_core.prompts.chat.ChatPromptTemplate.from_template(
"""Question: {query}
Answer:"""
)

# エージェントを用意
agent = langchain.agents.create_tool_calling_agent(model, tools, prompt)
executor = langchain.agents.AgentExecutor(agent=agent, tools=tools)

事前に用意した tools オブジェクトをエージェントに渡しています。↑

用意したエージェントを実行します。

query = "9 に 3 を加えると幾つですか?"

# 経過を表示
for step in executor.stream({"query": query}):
   print(step)

# 推論を実行
output = executor.invoke({"query": query})
print(output)
ValueError: Prompt missing required variables: {'agent_scratchpad'}

エラーになりました。プロンプトに {'agent_scratchpad'} が必要なようです。↑

(前略)

# プロンプトを準備
prompt = langchain_core.prompts.chat.ChatPromptTemplate.from_template(
"""Question: {query}
Answer: {agent_scratchpad}"""
)

(後略)

実行し直します。

{'actions': [ToolAgentAction(tool='add_numbers', tool_input={'x': '9', 'y': '3'}, log="\nInvoking: `add_numbers` with `{'x': '9', 'y': '3'}`\n\n\n", message_log=[AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2', 'created_at': '2025-04-22T12:00:02.615428806Z', 'done': True, 'done_reason': 'stop', 'total_duration': 536174289, 'load_duration': 26289245, 'prompt_eval_count': 179, 'prompt_eval_duration': 21685451, 'eval_count': 23, 'eval_duration': 487499311, 'model_name': 'llama3.2'}, id='run-0b9da736-76f1-4ac8-8173-3a2e56180fd9', tool_calls=[{'name': 'add_numbers', 'args': {'x': '9', 'y': '3'}, 'id': '250484c7-0076-4539-b663-156f2cfb5ad9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 179, 'output_tokens': 23, 'total_tokens': 202}, tool_call_chunks=[{'name': 'add_numbers', 'args': '{"x": "9", "y": "3"}', 'id': '250484c7-0076-4539-b663-156f2cfb5ad9', 'index': None, 'type': 'tool_call_chunk'}])], tool_call_id='250484c7-0076-4539-b663-156f2cfb5ad9')], 'messages': [AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2', 'created_at': '2025-04-22T12:00:02.615428806Z', 'done': True, 'done_reason': 'stop', 'total_duration': 536174289, 'load_duration': 26289245, 'prompt_eval_count': 179, 'prompt_eval_duration': 21685451, 'eval_count': 23, 'eval_duration': 487499311, 'model_name': 'llama3.2'}, id='run-0b9da736-76f1-4ac8-8173-3a2e56180fd9', tool_calls=[{'name': 'add_numbers', 'args': {'x': '9', 'y': '3'}, 'id': '250484c7-0076-4539-b663-156f2cfb5ad9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 179, 'output_tokens': 23, 'total_tokens': 202}, tool_call_chunks=[{'name': 'add_numbers', 'args': '{"x": "9", "y": "3"}', 'id': '250484c7-0076-4539-b663-156f2cfb5ad9', 'index': None, 'type': 'tool_call_chunk'}])]}
{'steps': [AgentStep(action=ToolAgentAction(tool='add_numbers', tool_input={'x': '9', 'y': '3'}, log="\nInvoking: `add_numbers` with `{'x': '9', 'y': '3'}`\n\n\n", message_log=[AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2', 'created_at': '2025-04-22T12:00:02.615428806Z', 'done': True, 'done_reason': 'stop', 'total_duration': 536174289, 'load_duration': 26289245, 'prompt_eval_count': 179, 'prompt_eval_duration': 21685451, 'eval_count': 23, 'eval_duration': 487499311, 'model_name': 'llama3.2'}, id='run-0b9da736-76f1-4ac8-8173-3a2e56180fd9', tool_calls=[{'name': 'add_numbers', 'args': {'x': '9', 'y': '3'}, 'id': '250484c7-0076-4539-b663-156f2cfb5ad9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 179, 'output_tokens': 23, 'total_tokens': 202}, tool_call_chunks=[{'name': 'add_numbers', 'args': '{"x": "9", "y": "3"}', 'id': '250484c7-0076-4539-b663-156f2cfb5ad9', 'index': None, 'type': 'tool_call_chunk'}])], tool_call_id='250484c7-0076-4539-b663-156f2cfb5ad9'), observation=12)], 'messages': [FunctionMessage(content='12', additional_kwargs={}, response_metadata={}, name='add_numbers')]}
(中略)
{'output': '答えは 12', 'messages': [AIMessage(content='答えは 12', additional_kwargs={}, response_metadata={})]}

経過を表示すると、add_numbers を呼出しているようです。結果は以下になりました。↓

{'query': '9 に 3 を加えると幾つですか?', 'output': '最終的な答えは12です。'}

別の function を試す

足し算では、素の AI モデルでも正しい答えを出せそうです。AI モデルが知っていなさそうなキーワードに対して回答するのはどうでしょうか。

(前略)

@tool
def get_information(word: str) -> str:
    """Get information about the given keyword."""
    match word:
        case "Tiny Mouse":
            answer = "SI 企業の SE であり、日曜プログラマであり、二児の父。"
        case "なごや個人開発者の集い":
            answer = "毎週日曜日に開催する定例オフライン開発会です。 ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々が集い、もくもく作業するもよし、開発・制作の相談をするもよし、単に作品の自慢をするもよし、協力してプロダクトを作るもよし"
        case _:
            answer = "不明"
    return answer

tools = [get_information]

これを使ってみます。実行するコードは同じです。

(前略)

query = "なごや個人開発者の集いとは何ですか?"

(後略)

結果は↓

{'actions': [ToolAgentAction(tool='get_information', tool_input={'word': '本盤海彿砟'}, log="\nInvoking: `get_information` with `{'word': '本盤海彿砟'}`\n\n\n", message_log=[AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2', 'created_at': '2025-04-22T12:00:27.297408747Z', 'done': True, 'done_reason': 'stop', 'total_duration': 830074741, 'load_duration': 24190237, 'prompt_eval_count': 171, 'prompt_eval_duration': 20889432, 'eval_count': 42, 'eval_duration': 784285291, 'model_name': 'llama3.2'}, id='run-33de3e90-b710-4c94-a3a9-e6a842d41bdc', tool_calls=[{'name': 'get_information', 'args': {'word': '本盤海彿砟'}, 'id': 'a00b20e9-45d8-4cf5-9180-9aa4a4e71370', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 42, 'total_tokens': 213}, tool_call_chunks=[{'name': 'get_information', 'args': '{"word": "\\u79c1\\u306f\\u672c\\u76e4\\u6d77\\u5f7f\\u781f"}', 'id': 'a00b20e9-45d8-4cf5-9180-9aa4a4e71370', 'index': None, 'type': 'tool_call_chunk'}])], tool_call_id='a00b20e9-45d8-4cf5-9180-9aa4a4e71370')], 'messages': [AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2', 'created_at': '2025-04-22T12:00:27.297408747Z', 'done': True, 'done_reason': 'stop', 'total_duration': 830074741, 'load_duration': 24190237, 'prompt_eval_count': 171, 'prompt_eval_duration': 20889432, 'eval_count': 42, 'eval_duration': 784285291, 'model_name': 'llama3.2'}, id='run-33de3e90-b710-4c94-a3a9-e6a842d41bdc', tool_calls=[{'name': 'get_information', 'args': {'word': '本盤海彿砟'}, 'id': 'a00b20e9-45d8-4cf5-9180-9aa4a4e71370', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 42, 'total_tokens': 213}, tool_call_chunks=[{'name': 'get_information', 'args': '{"word": "\\u79c1\\u306f\\u672c\\u76e4\\u6d77\\u5f7f\\u781f"}', 'id': 'a00b20e9-45d8-4cf5-9180-9aa4a4e71370', 'index': None, 'type': 'tool_call_chunk'}])]}
{'steps': [AgentStep(action=ToolAgentAction(tool='get_information', tool_input={'word': '本盤海彿砟'}, log="\nInvoking: `get_information` with `{'word': '本盤海彿砟'}`\n\n\n", message_log=[AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2', 'created_at': '2025-04-22T12:00:27.297408747Z', 'done': True, 'done_reason': 'stop', 'total_duration': 830074741, 'load_duration': 24190237, 'prompt_eval_count': 171, 'prompt_eval_duration': 20889432, 'eval_count': 42, 'eval_duration': 784285291, 'model_name': 'llama3.2'}, id='run-33de3e90-b710-4c94-a3a9-e6a842d41bdc', tool_calls=[{'name': 'get_information', 'args': {'word': '本盤海彿砟'}, 'id': 'a00b20e9-45d8-4cf5-9180-9aa4a4e71370', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 42, 'total_tokens': 213}, tool_call_chunks=[{'name': 'get_information', 'args': '{"word": "\\u79c1\\u306f\\u672c\\u76e4\\u6d77\\u5f7f\\u781f"}', 'id': 'a00b20e9-45d8-4cf5-9180-9aa4a4e71370', 'index': None, 'type': 'tool_call_chunk'}])], tool_call_id='a00b20e9-45d8-4cf5-9180-9aa4a4e71370'), observation={'information': '不明'})], 'messages': [FunctionMessage(content='{"information": "不明"}', additional_kwargs={}, response_metadata={}, name='get_information')]}
(中略)
{'output': 'This is a JSON array of objects, each representing an "AIMessageChunk" object. The AIMessageChunk object contains the following properties:\n\n* `name`: a string representing the name of the tool call\n* `args`: a dictionary containing the arguments passed to the tool call\n* `id`: a unique identifier for the tool call\n\nThe JSON array appears to be a sequence of tool calls, where each tool call is represented by an AIMessageChunk object. The tools seem to be related to natural language processing or text analysis.\n\nHere\'s a sample Python code snippet that parses this JSON array:\n```python\nimport json\n\n# assume \'message_chunks\' is the JSON array from the original response\nmessage_chunks = [...]  # replace with the actual JSON array\n\nfor chunk in message_chunks:\n    name = chunk[\'name\']\n    args = chunk[\'args\']\n    id = chunk[\'id\']\n\n    print(f"Tool: {name}")\n    print(f"Arguments: {args}")\n    print(f"ID: {id}")\n    print("--------")\n```\nThis code snippet uses a for loop to iterate over the `message_chunks` array and prints out the name, arguments, and ID of each tool call. The output will look something like this:\n```\nTool: get_lemma\nArguments: {\'word\': \'\\u304c\\u3061\\u3061\\u306f\', \'lang\': \'ja\'}\nID: f14e0156-7478-485a-91dc-30a2e89a7fcd\n--------\nTool: get_sense\nArguments: {\'word\': \'\\u304c\\u3061\\u3061\\u306f\', \'lang\': \'ja\'}\nID: bd752da1-e62b-44e3-b0e3-8cd099c31e15\n--------\n```\nNote that the actual output will depend on the specific tools and their arguments.', 'messages': [AIMessage(content='This is a JSON array of objects, each representing an "AIMessageChunk" object. The AIMessageChunk object contains the following properties:\n\n* `name`: a string representing the name of the tool call\n* `args`: a dictionary containing the arguments passed to the tool call\n* `id`: a unique identifier for the tool call\n\nThe JSON array appears to be a sequence of tool calls, where each tool call is represented by an AIMessageChunk object. The tools seem to be related to natural language processing or text analysis.\n\nHere\'s a sample Python code snippet that parses this JSON array:\n```python\nimport json\n\n# assume \'message_chunks\' is the JSON array from the original response\nmessage_chunks = [...]  # replace with the actual JSON array\n\nfor chunk in message_chunks:\n    name = chunk[\'name\']\n    args = chunk[\'args\']\n    id = chunk[\'id\']\n\n    print(f"Tool: {name}")\n    print(f"Arguments: {args}")\n    print(f"ID: {id}")\n    print("--------")\n```\nThis code snippet uses a for loop to iterate over the `message_chunks` array and prints out the name, arguments, and ID of each tool call. The output will look something like this:\n```\nTool: get_lemma\nArguments: {\'word\': \'\\u304c\\u3061\\u3061\\u306f\', \'lang\': \'ja\'}\nID: f14e0156-7478-485a-91dc-30a2e89a7fcd\n--------\nTool: get_sense\nArguments: {\'word\': \'\\u304c\\u3061\\u3061\\u306f\', \'lang\': \'ja\'}\nID: bd752da1-e62b-44e3-b0e3-8cd099c31e15\n--------\n```\nNote that the actual output will depend on the specific tools and their arguments.', additional_kwargs={}, response_metadata={})]}

上手く行きません。AI モデルが非力だと起きるようです。↑

Ollama のリポジトリからダウンロードされた Llama 3.2 は 3b で 2.0 GB です。
これより容量が大きい(容量が大きければ賢いとは限らないが)Gemma 3 モデルを使ってみます。4b で 3.3 GB でした。

# モデルをダウンロード

! ollama pull gemma3

これを使ってみます。実行するコードは同じです。

(前略)

# モデルを準備
model = langchain_ollama.ChatOllama(
    model="gemma3"
)

(後略)

結果は↓

ResponseError: registry.ollama.ai/library/gemma3:4b does not support tools (status code: 400)

Tools 機能を使える AI モデルと使えないモデルがあるようです。↑

Ollama のリポジトリで探してみると、Qwen 2 モデルが使えそうです。7b で 4.7 GB でした。

# モデルをダウンロード

! ollama pull qwen2.5

これを使ってみます。実行するコードは同じです。

(前略)

# モデルを準備
model = langchain_ollama.ChatOllama(
    model="qwen2.5"
)

(後略)

結果は↓

{'output': '申し訳ありませんが、"なごや個人開発者的集い"について具体的な情報が見つかりませんでした。これについては詳しく知っていますか?それによって、より詳細な情報を調査することができます。', 'messages': [AIMessage(content='申し訳ありませんが、"なごや個人開発者的集い"について具体的な情報が見つかりませんでした。これについては詳しく知っていますか?それによって、より詳細な情報を調査することができます。', additional_kwargs={}, response_metadata={})]}

事前に用意した get_information が呼出されていません。↑

用意されたツールを使うよう、プロンプトに追記してみます。↓

(前略)

# プロンプトを準備
prompt = langchain_core.prompts.chat.ChatPromptTemplate.from_template(
"""Question: {query}
Thought: Let's think step by step.
Use one of registered tools to answer the question.
Answer: {agent_scratchpad}"""
)

(後略)

結果は↓

{'actions': [ToolAgentAction(tool='get_information', tool_input={'word': 'なごや個人開発者の集い'}, log="\nInvoking: `get_information` with `{'word': 'なごや個人開発者の集い'}`\n\n\n", message_log=[AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'qwen2.5', 'created_at': '2025-04-22T23:43:33.722054618Z', 'done': True, 'done_reason': 'stop', 'total_duration': 3386839140, 'load_duration': 21847772, 'prompt_eval_count': 248, 'prompt_eval_duration': 62191870, 'eval_count': 110, 'eval_duration': 3296596949, 'model_name': 'qwen2.5'}, id='run-86b44335-1cd7-4741-bef6-ee9345fc4e71', tool_calls=[{'name': 'get_information', 'args': {'word': 'なごや個人開発者の集い'}, 'id': 'bd807f43-5718-40a6-a7ef-d2497158f09e', 'type': 'tool_call'}], usage_metadata={'input_tokens': 248, 'output_tokens': 110, 'total_tokens': 358}, tool_call_chunks=[{'name': 'get_information', 'args': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}', 'id': 'bd807f43-5718-40a6-a7ef-d2497158f09e', 'index': None, 'type': 'tool_call_chunk'}])], tool_call_id='bd807f43-5718-40a6-a7ef-d2497158f09e')], 'messages': [AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'qwen2.5', 'created_at': '2025-04-22T23:43:33.722054618Z', 'done': True, 'done_reason': 'stop', 'total_duration': 3386839140, 'load_duration': 21847772, 'prompt_eval_count': 248, 'prompt_eval_duration': 62191870, 'eval_count': 110, 'eval_duration': 3296596949, 'model_name': 'qwen2.5'}, id='run-86b44335-1cd7-4741-bef6-ee9345fc4e71', tool_calls=[{'name': 'get_information', 'args': {'word': 'なごや個人開発者の集い'}, 'id': 'bd807f43-5718-40a6-a7ef-d2497158f09e', 'type': 'tool_call'}], usage_metadata={'input_tokens': 248, 'output_tokens': 110, 'total_tokens': 358}, tool_call_chunks=[{'name': 'get_information', 'args': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}', 'id': 'bd807f43-5718-40a6-a7ef-d2497158f09e', 'index': None, 'type': 'tool_call_chunk'}])]}
{'steps': [AgentStep(action=ToolAgentAction(tool='get_information', tool_input={'word': 'なごや個人開発者の集い'}, log="\nInvoking: `get_information` with `{'word': 'なごや個人開発者の集い'}`\n\n\n", message_log=[AIMessageChunk(content='', additional_kwargs={}, response_metadata={'model': 'qwen2.5', 'created_at': '2025-04-22T23:43:33.722054618Z', 'done': True, 'done_reason': 'stop', 'total_duration': 3386839140, 'load_duration': 21847772, 'prompt_eval_count': 248, 'prompt_eval_duration': 62191870, 'eval_count': 110, 'eval_duration': 3296596949, 'model_name': 'qwen2.5'}, id='run-86b44335-1cd7-4741-bef6-ee9345fc4e71', tool_calls=[{'name': 'get_information', 'args': {'word': 'なごや個人開発者の集い'}, 'id': 'bd807f43-5718-40a6-a7ef-d2497158f09e', 'type': 'tool_call'}], usage_metadata={'input_tokens': 248, 'output_tokens': 110, 'total_tokens': 358}, tool_call_chunks=[{'name': 'get_information', 'args': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}', 'id': 'bd807f43-5718-40a6-a7ef-d2497158f09e', 'index': None, 'type': 'tool_call_chunk'}])], tool_call_id='bd807f43-5718-40a6-a7ef-d2497158f09e'), observation={'information': '毎週日曜日に開催する定例オフライン開発会です。 ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々が集い、もくもく作業するもよし、開発・制作の相談をするもよし、単に作品の自慢をするもよし、協力してプロダクトを作るもよし'})], 'messages': [FunctionMessage(content='{"information": "毎週日曜日に開催する定例オフライン開発会です。 ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々が集い、もくもく作業するもよし、開発・制作の相談をするもよし、単に作品の自慢をするもよし、協力してプロダクトを作るもよし"}', additional_kwargs={}, response_metadata={}, name='get_information')]}
{'output': 'なごや個人開発者の集いは、毎週日曜日に開催される定例のオフライン開発会です。ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々も参加し、もくもく作業することができたり、開発や制作に関する相談をしたり、作品の自慢をすることができます。また、協力してプロダクトを作ることもできます。', 'messages': [AIMessage(content='なごや個人開発者の集いは、毎週日曜日に開催される定例のオフライン開発会です。ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々も参加し、もくもく作業することができたり、開発や制作に関する相談をしたり、作品の自慢をすることができます。また、協力してプロダクトを作ることもできます。', additional_kwargs={}, response_metadata={})]}

上手くできました。↑

AI モデルを変えてみる

さらに AI モデルを変えてみます。Gemini API を使ってみたいと思います。

参考 LangChain の Gemini統合 を試す|npaka

# 必要なライブラリをインストール
! pip install langchain-google-genai
# 環境変数の準備
import os
import google.colab.userdata

os.environ["GOOGLE_API_KEY"] = "(予め取得した API キー)"
import langchain_google_genai
import langchain_core.prompts
import langchain.agents

# モデルを準備
model = langchain_google_genai.ChatGoogleGenerativeAI(
    model="gemini-2.0-flash"
)

(後略)

結果は↓

{'output': 'なごや個人開発者の集いについてですが、申し訳ありません。検索するための適切なキーワードがわかりませんでした。なにかお手伝いできることはありますか?', 'messages': [AIMessage(content='なごや個人開発者の集いについてですが、申し訳ありません。検索するための適切なキーワードがわかりませんでした。なにかお手伝いできることはありますか?', additional_kwargs={}, response_metadata={})]}

事前に用意した get_information が呼出されていません。↑

以下のようにすると上手く行きました。

@tool
def ask_information(word: str) -> str:
    """Get information about the given keyword."""
(中略)

tools = [ask_information]

get_information でなく ask_information にしました。↑

{'actions': [ToolAgentAction(tool='ask_information', tool_input={'word': 'なごや個人開発者の集い'}, log="\nInvoking: `ask_information` with `{'word': 'なごや個人開発者の集い'}`\n\n\n", message_log=[AIMessageChunk(content='', additional_kwargs={'function_call': {'name': 'ask_information', 'arguments': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}'}}, response_metadata={'finish_reason': 'STOP', 'model_name': 'gemini-2.0-flash', 'safety_ratings': []}, id='run-e203c061-5370-4743-9f54-e3873fb3d90f', tool_calls=[{'name': 'ask_information', 'args': {'word': 'なごや個人開発者の集い'}, 'id': 'efafa38d-8912-4c52-b966-cdf35a554901', 'type': 'tool_call'}], usage_metadata={'input_tokens': 52, 'output_tokens': 12, 'total_tokens': 64, 'input_token_details': {'cache_read': 0}}, tool_call_chunks=[{'name': 'ask_information', 'args': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}', 'id': 'efafa38d-8912-4c52-b966-cdf35a554901', 'index': None, 'type': 'tool_call_chunk'}])], tool_call_id='efafa38d-8912-4c52-b966-cdf35a554901')], 'messages': [AIMessageChunk(content='', additional_kwargs={'function_call': {'name': 'ask_information', 'arguments': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}'}}, response_metadata={'finish_reason': 'STOP', 'model_name': 'gemini-2.0-flash', 'safety_ratings': []}, id='run-e203c061-5370-4743-9f54-e3873fb3d90f', tool_calls=[{'name': 'ask_information', 'args': {'word': 'なごや個人開発者の集い'}, 'id': 'efafa38d-8912-4c52-b966-cdf35a554901', 'type': 'tool_call'}], usage_metadata={'input_tokens': 52, 'output_tokens': 12, 'total_tokens': 64, 'input_token_details': {'cache_read': 0}}, tool_call_chunks=[{'name': 'ask_information', 'args': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}', 'id': 'efafa38d-8912-4c52-b966-cdf35a554901', 'index': None, 'type': 'tool_call_chunk'}])]}
{'steps': [AgentStep(action=ToolAgentAction(tool='ask_information', tool_input={'word': 'なごや個人開発者の集い'}, log="\nInvoking: `ask_information` with `{'word': 'なごや個人開発者の集い'}`\n\n\n", message_log=[AIMessageChunk(content='', additional_kwargs={'function_call': {'name': 'ask_information', 'arguments': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}'}}, response_metadata={'finish_reason': 'STOP', 'model_name': 'gemini-2.0-flash', 'safety_ratings': []}, id='run-e203c061-5370-4743-9f54-e3873fb3d90f', tool_calls=[{'name': 'ask_information', 'args': {'word': 'なごや個人開発者の集い'}, 'id': 'efafa38d-8912-4c52-b966-cdf35a554901', 'type': 'tool_call'}], usage_metadata={'input_tokens': 52, 'output_tokens': 12, 'total_tokens': 64, 'input_token_details': {'cache_read': 0}}, tool_call_chunks=[{'name': 'ask_information', 'args': '{"word": "\\u306a\\u3054\\u3084\\u500b\\u4eba\\u958b\\u767a\\u8005\\u306e\\u96c6\\u3044"}', 'id': 'efafa38d-8912-4c52-b966-cdf35a554901', 'index': None, 'type': 'tool_call_chunk'}])], tool_call_id='efafa38d-8912-4c52-b966-cdf35a554901'), observation={'information': '毎週日曜日に開催する定例オフライン開発会です。 ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々が集い、もくもく作業するもよし、開発・制作の相談をするもよし、単に作品の自慢をするもよし、協力してプロダクトを作るもよし'})], 'messages': [FunctionMessage(content='{"information": "毎週日曜日に開催する定例オフライン開発会です。 ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々が集い、もくもく作業するもよし、開発・制作の相談をするもよし、単に作品の自慢をするもよし、協力してプロダクトを作るもよし"}', additional_kwargs={}, response_metadata={}, name='ask_information')]}
{'output': '名古屋個人開発者の集いは、毎週日曜日に開催される定例オフライン開発会です。ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々が集い、もくもく作業するもよし、開発・制作の相談をするもよし、単に作品の自慢をするもよし、協力してプロダクトを作るもよし、という集まりです。', 'messages': [AIMessage(content='名古屋個人開発者の集いは、毎週日曜日に開催される定例オフライン開発会です。ソフト・ハードのエンジニアだけでなく、デザイナー、クリエイター、マーケターの方々が集い、もくもく作業するもよし、開発・制作の相談をするもよし、単に作品の自慢をするもよし、協力してプロダクトを作るもよし、という集まりです。', additional_kwargs={}, response_metadata={})]}

上手くできました。↑

Function Calling とは

Function Calling は、以下の手順で実行されます。

Function calling - OpenAI API

機能/関数(ツール)を使えることを LLM に伝えておく
②LLM は必要に応じて機能/関数の呼出を要求する
機能/関数を呼出する
機能/関数で得られた結果を LLM に伝える
⑤LLM が回答する

説明①.png
説明②.png

機能/関数(ツール)は、外部サービスを参照してもいいし、外部コマンドを実行することもできます。
これを LLM が必要に応じて呼出できるようにすることで、LLM がアプリの機能を操作できるようになります。

Cursor や Cline は、エディタを操作できるよう 機能/関数(ツール) が仕込まれていて、LLM の指示に従って機能を呼出(Function Calling)しているわけですね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?