LangChain @tool デコレータ——ツール定義

ツール(Tool)は、Agentと外部世界の間でやり取りを行う橋渡し役です。

を通じて@toolデコレータを使用すると、任意のPython関数をAgentが呼び出し可能なツールにすばやく変換できます。


@tool 基本構文

@tool は LangChain が提供するデコレータで、使い方は非常に簡単です。関数に @tool デコレータを付けるだけで、その関数はツールになります。

実例

from langchain.tools import tool

# 最も簡単なツール:普通の関数 + @tool デコレータ
@tool
def hello_tool(name: str) -> str:
    """指定した人に挨拶します。

    Args:
name: 挨拶する相手の名前
    """

    return f"こんにちは、{name}!サンプルへようこそ。"

# ツールも通常のPython関数なので、直接呼び出せます
result = hello_tool.invoke({"name": "太郎"})
print(result)

# ツールには自動生成された説明情報が含まれます
print(f"\nツール名: {hello_tool.name}")
print(fツール説明: {hello_tool.description}")

実行結果:

你好,小明!欢迎来到サンプル。

ツール名: hello_tool
ツールの説明: 向指定的人打招呼。

    Args:
        name: 要打招呼的人的名字

関数のドキュメント文字列(docstring)は自動的にツールの説明になります。Agentはこの説明に基づいて、「このツールは何ができるか」「どのような場合に呼び出すべきか」を判断します。ドキュメント文字列が明確であればあるほど、Agentのツール使用の精度が高まります。説明には、パラメータの意味、関数の機能、使用シナリオを明記しましょう。


異なるパラメータ型を使用

@tool は、int、float、bool、列挙値など、さまざまなパラメータ型をサポートしています。

実例

from langchain.tools import tool
from typing import Literal


@tool
def search_courses(
    keyword: str,
    level: Literal["入門", "中級", "上級"],
    max_results: int = 5,
    free_only: bool = True,
) -> str:
    """サンプルでコースを検索します。

    Args:
keyword: 検索キーワード
level: コースの難易度レベル
max_results: 返す結果の最大件数
free_only: 無料コースのみを表示するかどうか
    """

    # 検索結果のシミュレーション
    courses = {
        ("python", "入門"): "Python3 基礎チュートリアル(無料)",
        ("python", "中級"): "Python データ分析実践(無料)",
        ("python", "上級"): "Python 機械学習上級(会員)",
        ("html", "入門"): "HTML 基礎チュートリアル(無料)",
    }
    key = (keyword.lower(), level)
    course = courses.get(key, f"{level}レベルの{keyword}コースが見つかりません")
    if free_only and "会員" in course:
        return f"検索結果:{course} —— このコースは会員限定のため、フィルタリングしました"
    return f"検索結果:{course}"


# 異なるパラメータでの呼び出しをテスト
print(search_course.invoke({
    "keyword": "python",
    "level": "入門",
}))
# 出力:検索結果:Python3 基礎チュートリアル(無料)

print(search_course.invoke({
    "keyword": "python",
    "level": "上級",
    "free_only": False,
}))
# 出力:検索結果:Python 機械学習上級(会員)

ツールをAgentに登録する

定義したツールを create_agent() の tools パラメータに渡すと、Agentがそれを使用できるようになります。

実例

from dotenv import load_dotenv
load_dotenv()

from langchain.tools import tool
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


@tool
def search_courses(keyword: str) -> str:
    """サンプルでコースを検索します。キーワードを渡すと、関連するコースのリストを返します。

    Args:
keyword: 検索キーワード(例:python、html、java)
    """

    courses = {
        "python": "Python3 基礎チュートリアル、Python データ分析、Python クローラー入門",
        "html": "HTML 基礎チュートリアル、HTML5 新機能、HTML フォーム実践",
        "java": "Java 基礎チュートリアル、Java オブジェクト指向、Java Spring フレームワーク",
    }
    return courses.get(keyword.lower(), f"{keyword} に関連するコースが見つかりません")


@tool
def get_course_detail(course_name: str) -> str:
    """指定したコースの詳細情報(章数と学習時間)を取得します。

    Args:
course_name: コース名(例:"Python3 基礎チュートリアル")
    """

    details = {
        "python3 基礎チュートリアル": "全30章、想定学習時間20時間、初心者向け",
        "html 基礎チュートリアル": "全25章、想定学習時間15時間、初心者向け",
    }
    return details.get(
        course_name.lower(),
        f{course_name} の詳細:初心者向け、内容が豊富で、実践のなケース付き
    )


# Agentを作成
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    tools=[search_courses, get_course_detail],
    system_prompt="あなたはサンプルの学習コンサルタントであり、ユーザーが適切なコースを見つけるのを支援します。",
)


# Agentを実行
def ask(question: str):
    result = agent.invoke({"messages": [HumanMessage(content=question)]})
    print(f"ユーザー: {question}")
    print(f"アドバイザー: {result['messages'][-1].content}")
    print("-" * 60)


ask("Pythonを学びたいのですが、おすすめのコースはありますか?")
ask("Python3 基礎チュートリアルを学び終えるのにどれくらいかかりますか?")

実行結果:

ユーザー: 我想学 Python,有什么课程推荐?
アドバイザー: 在サンプル 中有以下 Python 相关课程:
Python3 基础教程、Python 数据分析、Python 爬虫入门。
这些课程很适合 Python 初学者和进阶学习者,您可以根据兴趣选择!
------------------------------------------------------------
ユーザー: Python3 基础教程学完需要多久?
アドバイザー: Python3 基础教程共 30 章,预计学习时长 20 小时,非常适合零基础入门学习。
------------------------------------------------------------

複数のツールの連携

1つのAgentに複数のツールを登録できます。モデルはいつどのツールを使うかを自動的に判断します。

実例

from langchain.tools import tool
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


@tool
def get_stock_price(symbol: str) -> str:
    """株式の現在価格を取得します。

    Args:
symbol: 株式コード(例:AAPL、GOOGL、TSLA)
    """

    # 株価データのシミュレーション
    prices = {"AAPL": 185.50, "GOOGL": 142.30, "TSLA": 245.80}
    price = prices.get(symbol.upper())
    if price is None:
        return f"株式コード {symbol} が見つかりません"
    return f{symbol.upper()} の現在価格:${price}


@tool
def convert_currency(amount: float, from_currency: str, to_currency: str) -> str:
    """通貨換算。

    Args:
amount: 金額
from_currency: 元の通貨コード(例:USD、CNY)
to_currency: 目標通貨コード(例:CNY、USD)
    """

    # 為替レートのシミュレーション
    rates = {
        ("USD", "CNY"): 7.25,
        ("CNY", "USD"): 0.138,
    }
    rate = rates.get((from_currency.upper(), to_currency.upper()))
    if rate is None:
        return f"{from_currency} → {to_currency} の換算には対応していません"
    result = round(amount * rate, 2)
    return f"{amount} {from_currency} = {result} {to_currency}"


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    tools=[get_stock_price, convert_currency],
    system_prompt="あなたは、ユーザーが株価の照会や通貨換算を行うのを支援する金融アシスタントです。",
)

# Agentはどのツールを呼び出すかを自動的に決定します
result = agent.invoke({
    "messages": [HumanMessage(content="Appleの株価は?人民元に換算すると?")]
})

for msg in result["messages"]:
    if msg.type == "tool":
        print(f"[ツール {msg.name} を呼び出し] {msg.content}")
    elif msg.type == "ai" and msg.content:
        print(f"\n最終回答: {msg.content}")

実行結果:

[调用工具 get_stock_price] AAPL 当前价格:$185.5
[调用工具 convert_currency] 185.5 USD = 1344.88 CNY

最終回答: 苹果(AAPL)当前股价为 $185.50,按当前汇率换算约为 1344.88 人民币。

ツールのオプションパラメータとデフォルト値

ツールのパラメータにデフォルト値を設定すると、ツールをより柔軟に使用できます。

実例

from langchain.tools import tool


@tool
def recommend_tutorial(
    language: str,
    level: str = "入門",
    count: int = 3,
) -> str:
    """プログラミング言語と難易度に基づいてサンプルのコースを推薦します。

    Args:
language: プログラミング言語(例:Python、Java、HTML)
level: 難易度レベル("入門"、"中級"、"上級"から選択)。デフォルトは"入門"
count: 推薦するコース数(デフォルトは3)
    """

    tutorials = {
        "python": ["Python3 基礎", "Python オブジェクト指向", "Python クローラー", "Python データ分析"],
        "java": ["Java 基礎", "Java オブジェクト指向", "Java コレクションフレームワーク", "Java マルチスレッド"],
    }
    all_tutorials = tutorials.get(language.lower(), [f"{language} 基礎チュートリアル"])

    selected = all_tutorials[:count]
    return f"おすすめの{language} {level}レベルコース:{'、'.join(selected)}"


# 呼び出し時は必須パラメータのみを渡すだけでよい
print(recommend_tutorial.invoke({"language": "Python"}))
# 出力:おすすめのPython 入門レベルコース:Python3 基礎、Python オブジェクト指向、Python クローラー

# デフォルトパラメータを上書きすることもできます
print(recommend_tutorial.invoke({
    "language": "Java",
    "level": "中級",
    "count": 2,
}))
# 出力:おすすめのJava 中級レベルコース:Java 基礎、Java オブジェクト指向

デフォルト値により、Agentはツール呼び出し時に毎回すべてのパラメータを指定する必要がなくなります。ただし注意:あるパラメータにデフォルト値がなく、Agentが提供しない場合、呼び出しは失敗します。重要なパラメータにはデフォルト値を設定しないでください。


ツールのargs_schema——カスタムパラメータ検証

複雑なパラメータ検証のニーズには、Pydanticモデルをargs_schemaとして使用できます:

実例

from pydantic import BaseModel, Field
from langchain.tools import tool


# パラメータモデルの定義(より細かいパラメータ制御を提供)
class CourseSearchInput(BaseModel):
    """コース検索パラメータ"""
    keyword: str = Field(
        description="検索キーワード、あいまい一致をサポート",
        min_length=1,            # 最小1文字
        max_length=50,           # 最大50文字
    )
    category: str = Field(
        default="all",
        description="コースカテゴリ:all(すべて)、frontend(フロントエンド)、backend(バックエンド)、data(データサイエンス)",
        pattern=r"^(all|frontend|backend|data)$",  # 選択可能な値を制限
    )
    page: int = Field(
        default=1,
        description="ページ番号、1から始まる",
        ge=1,                    # 1以上
        le=100,                  # 100以下
    )


@tool(args_schema=CourseSearchInput)
def search_course(keyword: str, category: str = "all", page: int = 1) -> str:
    """サンプルチュートリアルでコースを検索"""
    return f"「{keyword}」の検索(カテゴリ:{category}、{page}ページ目):合計15件の結果が見つかりました"


# 有効な呼び出し
print(search_course.invoke({"keyword": "Python", "category": "backend", "page": 1}))

# 無効な呼び出し(categoryが許可された値に含まれない)
try:
    search_course.invoke({"keyword": "Python", "category": "invalid"})
except Exception as e:
    print(f"パラメータ検証に失敗しました:{e}")

実行結果:

搜索 'Python' (分类: backend, 第 1 页):共找到 15 条结果
参数校验失败: ...

ツール定義方法の比較

方法コード量適用シーン例
@toolデコレータ最少簡単から中程度の複雑さのツールほとんどのシーン
@tool + args_schema中程度細かいパラメータ検証が必要なツールAPIラッパー、データベース操作
Pydanticクラスをツールとして使用比較的多い複雑なビジネスロジックを持つツール内部に状態を含むツール
辞書形式最少(ただし推奨されない)リモート/組み込みツールの記述MCPツール、サーバーサイドツール
その他の拡張