大语言模型函数调用(Function Call)
主要作用是输入内容以后先通过第一个模型(FCModel)判断你输入的prompt是否存在函数,如果存在,则会触发tool calls,执行相应的函数,然后返回bool类型数据为true,当if检测到function_called为true的时候,重新回到循环,等待你的下一次输入。text就是传进来的“你的问题”,message包括两个部分,一个是系统的system prompt,另一个则是你的输入
Qwen3实现函数调用。
项目链接:GitHub - muggle-stack/Function_calling: LLM Function Calling
部署
首先安装依赖:
pip install ollama webbrowser
我是用的ollama的 API,也可以用openai的或者Anthropic的,即使是相同的模型不同厂家调用tools以后API输出的字段不同,ollama的字段是这样的:

做function call的时候需要根据字段提取tool calls(当然不是ollama的话也不一定叫tool calls,不过大差不差)
克隆代码:
git clone https://github.com/muggle-stack/Function_calling.git
代码讲解
main程序
项目中有两个模型,虽然都是qwen3:0.6b,但是功能不同
llm_model = LLMModel(llm_model_path='qwen3:0.6b', stream=True)
fc_model = FCModel(tools, func_map, fc_model_path='qwen3:0.6b')
类LLMModel初始化的时候默认模型是qwen3:0.6b,可以自行修改。默认是流输出的方式输出文字,也可以自己改为false。
类FCModel(Function call model)初始化的时候默认会传入tools(就是自己定义的工具),func_map是函数名表。这两个参数在functions.py文件里面,在main.py里面这样去导入:
from functions import tools, func_map
主程序中是一个循环:
try:
while True:
text = input("请输入内容:")
t1 = time.time()
function_called = fc_model.generate(text)
print('used time:', time.time() - t1)
if function_called:
continue
llm_output = llm_model.generate(text)
for output_text in llm_output:
print(output_text, end='', flush=True)
print()
except KeyboardInterrupt:
print("process was interrupted by user.")
主要作用是输入内容以后先通过第一个模型(FCModel)判断你输入的prompt是否存在函数,如果存在,则会触发tool calls,执行相应的函数,然后返回bool类型数据为true,当if检测到function_called为true的时候,重新回到循环,等待你的下一次输入。否则,function_called 为 false,则经过第二层,通用模型,通用模型则会正常回答问题。
function_model.py
初始化
def __init__(self, tools, func_map, fc_model_path='qwen3:0.6b'):
self._func_map = func_map
self._model_path = fc_model_path
self._tools = tools
self.messages = [
{
"role": "system",
"content": "你是一个工具助手,严格执行用户定义的tools,严格返回用户在tools设定的函数名和设定的tools参数;",
}
]
工具调用方法
def get_chat_stream(self, text, messages):
messages.append({"role": "user", "content": text})
stream = chat(
model=self._model_path,
messages=messages,
tools=self._tools
)
return stream
text就是传进来的“你的问题”,message包括两个部分,一个是系统的system prompt,另一个则是你的输入content。把系统的的messages append到你的messages后面得到完整的messages通过ollama的chat方法传参messages,tools参数则是你初始化的时候的tools。当然用tools以后就不能流式输出了。
提取大模型回答中的tool_calls对象
def generate(self, text):
response = self.get_chat_stream(text, self.messages)
# print("response:", response)
msg = response.message
if msg.tool_calls and msg.tool_calls is not None:
tc = msg.tool_calls[0] # 取第一个 ToolCall
fn = tc.function # Function 对象
fn_name = fn.name # 函数名
fn_args = fn.arguments or {} # 参数字典
function_to_call = self._func_map.get(fn_name)
if function_to_call:
if has_parameters(function_to_call):
result = function_to_call(**fn_args)
else:
result = function_to_call()
print('Function output:', result)
else:
print('Function not found:', fn_name)
return True
else:
return False
我注释的print加回来可以看到模型的输出或者你看我上面的图,你就知道ollama API的输出是什么格式了。你得提取函数的名字还有参数(如果有的话)has_parameters函数主要是用来判断tool_calls有没有参数,如果有参数就解包拿参数。
llm_model.py
通用模型就比较简单了,和上面用法差不多,就是开启流输出就行了:
def get_chat_stream(self, text, messages):
messages.append({"role": "user", "content": text})
stream = chat(
model=self._model_path,
messages=messages,
stream=self._stream
)
return stream
当然,你流输出你想要在main.py里面去拿到需要一个生成器(yield),每生成一个 token 就迭代一次:
# 处理聊天流中的每一部分
for chunk in stream:
content = chunk['message']['content']
yield content
functions.py
在这里面你可以定义你的函数具体怎么使用:
def open_browser():
url = "https://www.baidu.com"
webbrowser.open(url)
return f"已打开浏览器,访问 {url}"
def turn_off_light():
return "灯已关闭"
def turn_on_light(brightness:int):
return f"灯已调亮{brightness}"
def turn_left(angle:int):
return f"左转{angle}度"
这四个函数是我的示例,实际上都能被执行,但是下面三个只是返回打印,第一个open_browser能够执行打开浏览器的操作。
tools的格式需要注意,qwen官方给出的格式是怎样,你就得怎样:
tools = [
{
"type": "function",
"function": {
"name": "turn_on_light",
"description": "开灯或者turn on light,调高多少亮度",
"arguments": {
"angle": {
"type": "int",
"description": "调高的亮度"
}
}
},
},
{
"type": "function",
"function": {
"name": "turn_off_light",
"description": "关灯或者turn off light",
}
},
{
"type": "function",
"function": {
"name": "turn_left",
"description": "左转一定角度",
"arguments": {
"angle":{
"type": "float",
"description": '旋转的角度值',
}
}
}
},
{
"type": "function",
"function": {
"name": "open_browser",
"description": "打开浏览器",
}
}
]
因为他们是按照这个格式训练的模型,函数调用的细节文档可以看下:函数调用 - Qwen
展望
后续会出模型量化教程,还有CV的分类、跟踪等任务的前后处理。mcp如何手搓客户端(不是用anthropic的desktop)以及mcp server等,还有一些推理框架的技术细节。
点个赞呗,点个赞呗,点个赞呗,谢谢。
更多推荐


所有评论(0)