浅聊一下--Function Calling(Tool Calling)
由来
最开始是OpenAI提出的function calling,那个时候还没有agent的概念,就是在调用LLM的时候,告诉他有function XXX,在可以用到的时候返回function和参数调用。
后来有了agent的概念,就变成了tool calling,加上langchain对tool的封装就越来越好用了。
流程
代码实现
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
基于LangChain的工具调用示例
功能:实现多轮工具调用循环,展示工具调用的完整流程
"""
import datetime
import json
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
# 第一步:定义工具类
@tool
def get_current_time() -> int:
"""获取当前的毫秒时间戳。
Returns:
int: 当前时间,毫秒时间戳
"""
current_time = int(datetime.datetime.now().timestamp() * 1000)
print(f"\n[工具调用] get_current_time() -> {current_time}")
return current_time
@tool
def get_weather(input_str):
"""查询指定地点和时间的天气情况。
Args:
input_str: 输入参数,可以是字典或JSON字符串
Returns:
str: 天气信息
"""
# 处理整个输入是JSON字符串的情况
if isinstance(input_str, str):
try:
input_data = json.loads(input_str)
if isinstance(input_data, dict):
# 从解析后的字典中提取参数
location = input_data.get("location")
time = input_data.get("time")
else:
# 如果解析后不是字典,使用默认处理
location = input_str
time = int(datetime.datetime.now().timestamp() * 1000)
except json.JSONDecodeError:
# JSON解析失败,使用默认值
location = input_str
time = int(datetime.datetime.now().timestamp() * 1000)
elif isinstance(input_str, dict):
# 直接从字典中提取参数
location = input_str.get("location")
time = input_str.get("time")
else:
# 其他类型,使用默认值
location = str(input_str)
time = int(datetime.datetime.now().timestamp() * 1000)
# 确保time是整数
if isinstance(time, str):
try:
time = int(time)
except ValueError:
time = int(datetime.datetime.now().timestamp() * 1000)
# 将毫秒时间戳转换为用户可读格式
readable_time = datetime.datetime.fromtimestamp(time / 1000).strftime(
"%Y-%m-%d %H:%M:%S"
)
# 模拟天气数据,返回mock结果
weather_data = {
"location": location,
"time": readable_time,
"temperature": "22°C",
"condition": "晴",
"humidity": "55%",
"wind": "东北风 3级",
}
result = json.dumps(weather_data, ensure_ascii=False, indent=2)
print(f"\n[工具调用] get_weather(location='{location}', time={time}) -> {result}")
return result
# 第二步:创建LLM实例
# 配置硅基流动的OpenAI兼容API
llm = ChatOpenAI(
model="",
api_key="sk-rx", # 请替换为你的硅基流动API密钥
base_url="https://api.siliconflow.cn/v1", # 硅基流动API地址
temperature=0.0,
)
# 第三步:创建工具列表
tools = [get_current_time, get_weather]
# 第四步:创建提示模板 - REACT风格专用
from langchain_core.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_template(
"""Answer the following questions as best you can. You have access to the following tools:
{tools}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action, must be a JSON object with the correct parameter names
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {input}
Thought:{agent_scratchpad}"""
)
# 第五步:创建REACT风格的Agent
agent = create_react_agent(llm, tools, prompt)
# 第六步:创建Agent执行器
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 第七步:测试工具调用
if __name__ == "__main__":
# 测试场景:查询南京现在的天气
response = agent_executor.invoke({"input": "现在南京的天气"})
print(f"\n[最终回复] {response['output']}")结果
> Entering new AgentExecutor chain...
我需要先获取当前时间,然后根据当前时间查询南京的天气情况。
Action: get_current_time
Action Input: {}
[工具调用] get_current_time() -> 1754103192901
1754103192901
现在我有了当前时间,可以使用这个时间来查询南京的天气情况。
Action: get_weather
Action Input: {"location": "南京", "time": 1754103192901}
[工具调用] get_weather(location='南京', time=1754103192901) -> {
"location": "南京",
"time": "2025-08-02 10:53:12",
"temperature": "22°C",
"condition": "晴",
"humidity": "55%",
"wind": "东北风 3级"
}
{
"location": "南京",
"time": "2025-08-02 10:53:12",
"temperature": "22°C",
"condition": "晴",
"humidity": "55%",
"wind": "东北风 3级"
}
我获得了南京的天气信息,现在可以给出最终答案。
Final Answer: 南京现在天气晴朗,温度为22°C,湿度55%,风向为东北风,风力3级。
> Finished chain.
[最终回复] 南京现在天气晴朗,温度为22°C,湿度55%,风向为东北风,风力3级。最佳实践
编写清晰详细的功能名称,参数描述和说明
尽量少的参数,已知的就直接内置
提示词给出清晰且统一的schema,以防参数传递解析出错
tool的数量不要太多,消耗token
Tool Calling的工程意义
工程化进阶方向
注册中心:统一管理tool,动态加载
参数校验:防止注入和错误传参
重试机制:调用失败或超时重试
缓存机制:减轻服务器压力
权限控制:不同角色有不同的调用权限
日志追踪:内部思维链过程记录
可视化面板:内部思维连可视化
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 故宫而过
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果