在实际项目里,单纯让大模型生成文本往往不够,你更希望它能够操作外部系统、获取实时信息或者完成精确计算。智谱AI推出的GLM-4 All-Tools API正是为了满足这种需求:它允许模型在对话过程中直接发出工具调用指令,由你的代码去执行真实函数,再把结果反馈给模型继续推理。这篇文章会通过一个完整的Python实战,带你掌握这个API的核心用法。

All-Tools API的核心能力与工具调用机制
GLM-4 All-Tools API基于智谱最新的GLM-4模型,最大的特点就是支持原生工具调用。与传统的Chat Completions接口相比,它不需要你在提示词里手动拼装复杂的工具描述和示例,只需在请求参数中传入tools列表,模型就会在有需要时自动返回一个tool_calls字段。这个字段里包含了要调用的函数名、参数以及一个唯一的调用ID,开发者执行完实际函数后,再把结果以tool角色的消息追加到对话历史中,重新发送请求即可得到最终回答。
整个流程可以抽象为三步:第一步定义工具,每个工具包括名称、描述和参数JSON Schema;第二步发送用户问题并携带工具列表,模型返回tool_calls;第三步执行工具函数,将结果封装成消息发回,模型根据结果继续生成自然语言回复。这种设计让开发者无需关心模型内部如何决策调用哪个工具,只需要专注实现工具本身。下面先展示一个定义工具并发送请求的最小示例。
import json
from openai import OpenAI
client = OpenAI(
api_key="你的智谱AI API Key",
base_url="https://open.bigmodel.cn/api/paas/v4/"
)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的实时天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称,如北京"}
},
"required": ["city"]
}
}
}
]
response = client.chat.completions.create(
model="glm-4-alltools",
messages=[{"role": "user", "content": "北京今天天气怎么样?"}],
tools=tools,
tool_choice="auto"
)
print(json.dumps(response.choices[0].message.model_dump(), ensure_ascii=False, indent=2))
上述代码中,我们使用与OpenAI兼容的Python库,base_url指向智谱的API端点。tools参数是一个列表,每个元素包含type和function,function里必须提供name、description和parameters,其中parameters遵循JSON Schema规范。模型收到“北京今天天气怎么样?”后,不会直接回答,而是返回一个带tool_calls的消息,提示你调用get_weather函数。
这里需要特别注意tool_choice参数的设置:默认值为auto,表示模型自己决定是否调用工具、调用哪个工具。如果希望强制调用某个工具,可以传入{"type": "function", "function": {"name": "get_weather"}};如果想禁止调用工具,则设为none。在Agent开发中,auto最常用,因为它让模型在需要时才调用,避免了不必要的API消耗。
实战:使用GLM-4 All-Tools API构建Agent
理解了基本机制后,我们来实现一个具备搜索和计算两个工具的小型Agent。首先准备两个工具函数:一个模拟搜索,一个进行数学计算。搜索函数可以对接真实的搜索引擎API,这里先用一个返回固定结果的示例代替,方便演示。
Agent的主循环逻辑相对固定:初始化消息列表,添加用户问题;发送请求后检查message.tool_calls是否存在;如果存在,遍历每个tool_call,根据函数名分发到对应的处理函数,将返回结果包装成role: "tool"的消息,并带上tool_call_id;最后把工具结果消息加入历史,再次请求模型获得最终答案。下面给出完整代码。
import json
from openai import OpenAI
client = OpenAI(
api_key="你的智谱AI API Key",
base_url="https://open.bigmodel.cn/api/paas/v4/"
)
def search_web(query: str) -> str:
"""模拟搜索,实际可替换为真实搜索接口"""
return f"搜索结果:关于“{query}”,智谱AI在2024年发布了GLM-4系列模型,支持超长上下文和工具调用。"
def calculate(expression: str) -> str:
"""安全计算数学表达式"""
try:
result = eval(expression)
return f"计算结果:{result}"
except Exception as e:
return f"计算出错:{str(e)}"
tools = [
{
"type": "function",
"function": {
"name": "search_web",
"description": "搜索互联网信息,返回相关摘要",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "搜索关键词"}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "计算数学表达式,支持加减乘除和括号",
"parameters": {
"type": "object",
"properties": {
"expression": {"type": "string", "description": "数学表达式,例如(3+5)*2"}
},
"required": ["expression"]
}
}
}
]
def run_agent(user_query):
messages = [{"role": "user", "content": user_query}]
# 第一轮请求,可能返回工具调用
response = client.chat.completions.create(
model="glm-4-alltools",
messages=messages,
tools=tools,
tool_choice="auto"
)
assistant_message = response.choices[0].message
messages.append(assistant_message)
# 处理工具调用
if assistant_message.tool_calls:
for tool_call in assistant_message.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
if func_name == "search_web":
result = search_web(func_args["query"])
elif func_name == "calculate":
result = calculate(func_args["expression"])
else:
result = f"未知工具:{func_name}"
# 将工具结果追加到消息列表
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
# 二次请求,让模型生成最终答案
final_response = client.chat.completions.create(
model="glm-4-alltools",
messages=messages,
tools=tools,
tool_choice="auto"
)
return final_response.choices[0].message.content
else:
# 如果没有工具调用,直接返回内容
return assistant_message.content
if __name__ == "__main__":
query = "请帮我搜索一下智谱AI GLM-4的最新消息,并计算(15+7)*3的结果"
answer = run_agent(query)
print("Agent回答:", answer)
这段代码展示了多工具调用的完整流程。当用户的问题同时需要搜索和计算时,模型可能会在第一次响应中一次性返回两个tool_calls,我们的循环会依次执行并把结果都追加回去。注意assistant_message是一个消息对象,直接加入messages列表时必须保持其原始结构,包括role、content以及可能存在的tool_calls字段;而工具结果消息则使用role: "tool"并指定tool_call_id,这样模型才能正确关联。
实际运行中,模型可能会在第二轮响应里再次发起工具调用,例如搜索关键词需要修正或者计算结果需要进一步处理。因此更健壮的写法是使用while循环替代仅两轮的硬编码,直到响应中不再包含tool_calls为止。同时要设置最大迭代次数(比如10次),防止模型陷入自我循环导致无限调用。
深入理解工具调用的参数与响应
掌握基础用法后,我们需要更细致地理解工具调用相关的参数和响应结构,这有助于排查问题和优化Agent行为。请求参数中,除了tools和tool_choice,还有一个parallel_tool_calls(布尔值,默认true),它控制模型是否允许在一次响应中并行调用多个工具。当你的工具之间存在依赖关系时,建议将其设为false,以确保模型按顺序逐个调用。
响应中的tool_calls是一个数组,每个元素包含id、type(固定为function)、function对象,function里又有name和arguments。需要注意的是,arguments是一个JSON字符串,必须使用json.loads解析成字典后才能取值。如果模型返回的参数格式不符合你的JSON Schema,解析会失败,这时可以在工具函数内部增加校验逻辑,或者调整工具的description和参数描述让模型生成更准确的参数。
工具调用的另一个重要细节是tool_call_id。该ID在单次对话中唯一标识一个工具调用,回传结果时必须原样使用,否则模型无法关联。此外,当一次响应中包含多个tool_calls时,所有工具结果消息应该一起追加到消息列表,然后再发起下一次请求,这样模型能够同时看到所有结果并综合推理。下面给出一个实际的响应JSON示例,帮助理解结构。
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "calculate",
"arguments": "{\"expression\": \"(15+7)*3\"}"
}
},
{
"id": "call_def456",
"type": "function",
"function": {
"name": "search_web",
"arguments": "{\"query\": \"智谱AI GLM-4\"}"
}
}
]
}
可以看到,当模型决定调用工具时,content字段为null,此时不需要处理文本内容,只需处理tool_calls。反之,如果模型没有调用工具,content就是正常回答,tool_calls为None。这种二元性要求开发者在代码里先判断tool_calls是否存在。
最佳实践与注意事项
使用GLM-4 All-Tools API开发Agent时,有几个实践建议能显著提升稳定性和体验。第一,工具描述要清晰具体:description里明确说明工具的功能、适用场景和限制,参数描述也尽量给出示例值。例如city参数描述为“城市名称,如北京,不要带‘市’字”,可以避免模型生成多余的行政区划词。
第二,严格控制工具数量和调用次数。虽然模型能处理很多工具,但工具过多会增加决策难度和延迟。通常一个Agent配置5到10个工具比较合适。同时要设置循环上限,例如while循环最多执行5轮,超过后强制让模型基于已有信息给出回答,或者直接返回错误提示。第三,注意安全性和成本:工具函数中避免直接执行不可信的命令,比如eval只应用在受控的数学表达式场景;每次工具调用都会消耗额外的token,合理设置tool_choice可以节省不必要的调用。
与普通的Chat Completions接口相比,All-Tools API的优点在于模型对工具调用的理解更加精准,参数生成质量更高,并且支持并行调用。但它也要求开发者严格遵循消息结构,尤其是工具结果的role和tool_call_id必须正确,否则会报错。在真实业务中,你可以将这套机制封装成一个通用的Agent框架,让业务方只关注工具函数的实现,从而快速构建出具备外部能力的智能应用。
总的来说,GLM-4 All-Tools API把复杂的工具调用流程简化成了几个关键步骤,配合良好的错误处理和循环控制,完全可以支撑起一个生产级的Agent系统。希望本文的示例和解析能让你顺利上手,并在自己的项目中发挥作用。