LangChain 工具调用学习笔记
上一篇手写了最小 Agent 后,我开始用 LangChain 重构。框架的好处是抽象到位,坑点是版本变化太快,文档和实际行为经常对不上。这篇记录我学习工具调用(Tool Calling)的关键点。
工具定义的三种方式
LangChain 里定义工具有三种主流写法:
python
from langchain.tools import tool
@tool
def search(query: str) -> str:
"""在网络上搜索信息"""
return "..."
# 也可以用 StructuredTool.from_function
# 或者继承 BaseTool最推荐用 @tool 装饰器,函数的 docstring 会被当作工具描述喂给 LLM,所以描述写得好不好,直接决定 LLM 会不会调你的工具。
一个常见坑:参数 schema
我第一次写工具时,参数类型用了 Python 的 dict,结果模型死活不调用。后来才明白:工具参数必须是 JSON Schema 友好的类型(str/int/float/bool/List[...]),不能用任意 dict。用 Pydantic 模型定义参数最稳:
python
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(description="搜索关键词")
top_k: int = Field(default=5, description="返回结果数")让模型自己决定调用时机
核心是把工具列表绑定到模型上,然后让模型在回复时输出 tool_calls:
python
llm_with_tools = llm.bind_tools([search, calculator])
response = llm_with_tools.invoke("今天南昌天气怎么样?")
# response.tool_calls 会包含模型想调用的工具模型并不是每次都调工具——它会判断"这个要不要查"。这就是 Agent 与 RAG 的区别:RAG 是每次必检索,Agent 是按需检索。
小结
- 工具描述写清楚(docstring 是给 LLM 看的)
- 参数用 Pydantic,类型严格
bind_tools后让模型自主决策
下一篇准备学 LangGraph 的多智能体协作,到时候再分享。