GLM-4-9B-Chat-1M函数调用功能详解:自定义工具集成实战

想象一下,你正在开发一个智能客服系统,用户问:“帮我查一下北京明天飞上海的航班,然后看看天气怎么样,再推荐几个附近的酒店。”

传统的大模型可能只能回答“我无法查询实时信息”,或者给你一段编造的航班信息。但如果你能让大模型真正“动手”去调用查询接口、获取真实数据、再综合分析给出建议,那体验就完全不一样了。

这就是函数调用(Function Call)的魅力所在。它让大模型从一个“只会说”的聊天机器人,变成了一个“能动手”的智能助手。今天,我们就来深入聊聊GLM-4-9B-Chat-1M这个支持百万上下文的开源模型,看看它的函数调用功能到底有多强大,以及如何用它来构建真正实用的自动化工作流。

1. 函数调用:让大模型从“说”到“做”

简单来说,函数调用就是让大模型学会“使用工具”。你告诉模型:“我这里有几个工具(函数),分别是查天气、查航班、订酒店……”,然后当用户提出需求时,模型会自己判断:“哦,这个需求需要调用查天气和查航班这两个工具”,接着它会把调用这些工具所需的参数整理好,交给你去执行。

GLM-4-9B-Chat-1M在这方面做得相当不错。它不仅能理解复杂的工具描述,还能在长达100万token的上下文里记住你定义的所有工具,然后精准地选择该用哪个、该怎么用。

1.1 一个简单的例子:查天气

我们先来看个最简单的例子,感受一下函数调用是怎么工作的。

假设我们有一个查询天气的函数:

def get_weather(city: str, date: str) -> str:
    """查询指定城市在指定日期的天气情况
    
    Args:
        city: 城市名称,如“北京”、“上海”
        date: 日期,格式为“YYYY-MM-DD”
    
    Returns:
        天气情况的描述字符串
    """
    # 这里应该是调用真实天气API的代码
    # 为了演示,我们返回一个模拟结果
    return f"{city}在{date}的天气:晴,温度20-28°C"

现在,我们把这个函数“教”给GLM-4-9B-Chat-1M。当用户问“北京明天天气怎么样?”时,模型不会直接编造一个答案,而是会输出类似这样的内容:

{
  "function": "get_weather",
  "arguments": {
    "city": "北京",
    "date": "2024-12-25"
  }
}

看到没?模型识别出了需要调用get_weather函数,并且准确地提取出了“北京”作为城市参数。至于日期,模型根据“明天”这个描述,自动推算出了具体的日期值。

你拿到这个调用请求后,去执行真正的get_weather函数(调用真实天气API),拿到结果后再交给模型,模型会把这个结果组织成自然语言回复给用户:“北京明天(12月25日)天气晴朗,温度在20到28度之间,适合外出。”

这个过程听起来简单,但背后有几个关键点:

  1. 模型要能理解工具的功能:从函数描述中知道这个工具是干什么的
  2. 模型要能提取正确的参数:从用户问题中提取出城市、日期等信息
  3. 模型要能处理工具返回的结果:把API返回的原始数据转换成用户能看懂的话

GLM-4-9B-Chat-1M在这几个方面都表现得很扎实,特别是它的长上下文能力,意味着你可以一次性定义几十个甚至上百个工具,模型都能记住并在需要时准确调用。

2. 实战:构建一个智能旅行助手

光说不练假把式,我们用一个实际的例子来展示函数调用的威力。我们来构建一个智能旅行助手,它能帮用户处理旅行中的各种需求:查航班、看天气、找酒店、算汇率等等。

2.1 定义我们的工具集

首先,我们需要定义助手能用到的所有工具。为了简化,我们先实现四个核心功能:

# 工具函数定义
import json
from datetime import datetime, timedelta
import random

def search_flights(departure: str, arrival: str, date: str) -> dict:
    """搜索航班信息
    
    Args:
        departure: 出发城市
        arrival: 到达城市
        date: 出发日期,格式为“YYYY-MM-DD”
    
    Returns:
        航班信息的字典
    """
    # 模拟航班数据
    flights = [
        {
            "flight_no": "CA1501",
            "departure_time": "08:00",
            "arrival_time": "10:30",
            "airline": "中国国际航空",
            "price": 1200
        },
        {
            "flight_no": "MU5101",
            "departure_time": "10:30",
            "arrival_time": "13:00",
            "airline": "中国东方航空",
            "price": 1100
        },
        {
            "flight_no": "CZ3101",
            "departure_time": "14:00",
            "arrival_time": "16:30",
            "airline": "中国南方航空",
            "price": 1050
        }
    ]
    
    return {
        "departure": departure,
        "arrival": arrival,
        "date": date,
        "flights": flights[:2]  # 返回前两个航班
    }

def get_weather_forecast(city: str, days: int = 3) -> dict:
    """获取城市多日天气预报
    
    Args:
        city: 城市名称
        days: 预报天数,默认3天
    
    Returns:
        天气预报信息
    """
    # 模拟天气数据
    weather_types = ["晴", "多云", "阴", "小雨", "中雨", "雷阵雨"]
    
    forecast = []
    today = datetime.now()
    
    for i in range(days):
        date = (today + timedelta(days=i)).strftime("%Y-%m-%d")
        forecast.append({
            "date": date,
            "weather": random.choice(weather_types),
            "temp_low": random.randint(15, 20),
            "temp_high": random.randint(25, 32),
            "humidity": random.randint(50, 90)
        })
    
    return {
        "city": city,
        "forecast": forecast
    }

def find_hotels(city: str, check_in: str, check_out: str, guests: int = 2) -> dict:
    """查找酒店信息
    
    Args:
        city: 城市名称
        check_in: 入住日期
        check_out: 离店日期
        guests: 入住人数,默认2人
    
    Returns:
        酒店信息列表
    """
    hotels = [
        {
            "name": f"{city}国际大酒店",
            "star": 5,
            "price": 800,
            "address": f"{city}市中心人民广场1号",
            "rating": 4.8
        },
        {
            "name": f"{city}商务快捷酒店",
            "star": 3,
            "price": 300,
            "address": f"{city}火车站附近",
            "rating": 4.2
        },
        {
            "name": f"{city}特色民宿",
            "star": 4,
            "price": 500,
            "address": f"{city}老城区文化街",
            "rating": 4.6
        }
    ]
    
    return {
        "city": city,
        "check_in": check_in,
        "check_out": check_out,
        "guests": guests,
        "hotels": hotels
    }

def currency_conversion(amount: float, from_currency: str, to_currency: str) -> dict:
    """货币兑换计算
    
    Args:
        amount: 金额
        from_currency: 源货币,如“USD”、“CNY”
        to_currency: 目标货币
    
    Returns:
        兑换结果
    """
    # 模拟汇率(非实时)
    exchange_rates = {
        "USD": {"CNY": 7.2, "EUR": 0.92, "JPY": 150},
        "CNY": {"USD": 0.14, "EUR": 0.13, "JPY": 21},
        "EUR": {"USD": 1.09, "CNY": 7.8, "JPY": 163},
        "JPY": {"USD": 0.0067, "CNY": 0.048, "EUR": 0.0061}
    }
    
    if from_currency in exchange_rates and to_currency in exchange_rates[from_currency]:
        rate = exchange_rates[from_currency][to_currency]
        converted = amount * rate
        return {
            "amount": amount,
            "from_currency": from_currency,
            "to_currency": to_currency,
            "exchange_rate": rate,
            "converted_amount": round(converted, 2)
        }
    else:
        return {
            "error": f"不支持{from_currency}到{to_currency}的兑换"
        }

2.2 准备工具描述给模型

接下来,我们需要把这些工具的描述准备好,让GLM-4-9B-Chat-1M知道每个工具是干什么的、需要什么参数。这是函数调用的关键一步:

# 工具描述(模型需要知道的信息)
tools = [
    {
        "type": "function",
        "function": {
            "name": "search_flights",
            "description": "搜索指定日期、出发地和目的地的航班信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "departure": {
                        "type": "string",
                        "description": "出发城市,如'北京'、'上海'"
                    },
                    "arrival": {
                        "type": "string", 
                        "description": "到达城市,如'广州'、'深圳'"
                    },
                    "date": {
                        "type": "string",
                        "description": "出发日期,格式为YYYY-MM-DD"
                    }
                },
                "required": ["departure", "arrival", "date"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "get_weather_forecast",
            "description": "获取城市的多日天气预报",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称"
                    },
                    "days": {
                        "type": "integer",
                        "description": "预报天数,默认3天",
                        "default": 3
                    }
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "find_hotels",
            "description": "查找指定城市的酒店信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称"
                    },
                    "check_in": {
                        "type": "string",
                        "description": "入住日期,格式为YYYY-MM-DD"
                    },
                    "check_out": {
                        "type": "string",
                        "description": "离店日期,格式为YYYY-MM-DD"
                    },
                    "guests": {
                        "type": "integer",
                        "description": "入住人数,默认2人",
                        "default": 2
                    }
                },
                "required": ["city", "check_in", "check_out"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "currency_conversion",
            "description": "货币兑换计算",
            "parameters": {
                "type": "object",
                "properties": {
                    "amount": {
                        "type": "number",
                        "description": "要兑换的金额"
                    },
                    "from_currency": {
                        "type": "string",
                        "description": "源货币代码,如USD、CNY、EUR"
                    },
                    "to_currency": {
                        "type": "string",
                        "description": "目标货币代码"
                    }
                },
                "required": ["amount", "from_currency", "to_currency"]
            }
        }
    }
]

注意看这些描述,它们都是用自然语言写的,清楚地说明了每个函数是干什么的、需要哪些参数、参数是什么类型。GLM-4-9B-Chat-1M就是靠这些描述来理解工具的用途。

2.3 与模型交互:完整的对话流程

现在,让我们看看如何与模型进行完整的函数调用对话。这里我用一个简化的示例来展示整个流程:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

# 初始化模型和分词器
device = "cuda" if torch.cuda.is_available() else "cpu"
model_name = "THUDM/glm-4-9b-chat-1m"

tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    low_cpu_mem_usage=True,
    trust_remote_code=True
).to(device).eval()

def chat_with_tools(user_input, conversation_history=None):
    """与模型进行带工具调用的对话"""
    if conversation_history is None:
        conversation_history = []
    
    # 添加用户输入到历史
    conversation_history.append({"role": "user", "content": user_input})
    
    # 准备消息格式,包含工具描述
    messages = [
        {
            "role": "system",
            "content": "你是一个智能旅行助手,可以帮用户查询航班、天气、酒店和货币兑换。"
        }
    ]
    
    # 添加工具描述
    messages.append({
        "role": "system",
        "content": f"你可以使用以下工具:\n{json.dumps(tools, ensure_ascii=False, indent=2)}"
    })
    
    # 添加对话历史
    messages.extend(conversation_history)
    
    # 编码输入
    inputs = tokenizer.apply_chat_template(
        messages,
        add_generation_prompt=True,
        tokenize=True,
        return_tensors="pt",
        return_dict=True
    )
    inputs = inputs.to(device)
    
    # 生成回复
    with torch.no_grad():
        outputs = model.generate(
            **inputs,
            max_new_tokens=500,
            do_sample=True,
            temperature=0.7,
            top_p=0.9
        )
    
    # 解码输出
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    
    # 提取模型回复(去掉输入部分)
    prompt_length = len(tokenizer.decode(inputs['input_ids'][0], skip_special_tokens=True))
    model_reply = response[prompt_length:].strip()
    
    return model_reply

# 示例对话
if __name__ == "__main__":
    # 用户:我想去上海旅行,帮我查一下明天的航班和天气
    user_query = "我想去上海旅行,帮我查一下明天的航班和天气"
    
    print(f"用户: {user_query}")
    print("-" * 50)
    
    # 第一次交互:模型可能会请求更多信息或直接调用工具
    reply = chat_with_tools(user_query)
    print(f"助手: {reply}")
    
    # 在实际应用中,你需要解析模型的回复
    # 如果回复中包含工具调用请求,就执行对应的函数
    # 然后把函数结果再交给模型,让模型生成最终回复

在实际运行中,当用户提出“我想去上海旅行,帮我查一下明天的航班和天气”这样的复合请求时,GLM-4-9B-Chat-1M很可能会输出一个结构化的工具调用请求,比如同时请求search_flightsget_weather_forecast两个函数。

2.4 处理复杂多轮对话

真正的旅行规划往往需要多轮对话。比如用户先说“查北京到上海的航班”,然后又说“那天的天气怎么样?”,接着问“附近有什么酒店?”。GLM-4-9B-Chat-1M的百万上下文在这里就派上大用场了,它能记住整个对话历史,包括之前调用过的工具和返回的结果。

def handle_complex_conversation():
    """处理多轮复杂对话示例"""
    history = []
    
    # 第一轮:查询航班
    user1 = "帮我查一下北京到上海明天早上的航班"
    reply1 = chat_with_tools(user1, history)
    history.append({"role": "user", "content": user1})
    history.append({"role": "assistant", "content": reply1})
    
    print(f"用户: {user1}")
    print(f"助手: {reply1}")
    print("-" * 50)
    
    # 第二轮:基于上文的查询(模型记得刚才查的是北京到上海)
    user2 = "那天的天气怎么样?"
    reply2 = chat_with_tools(user2, history)
    history.append({"role": "user", "content": user2})
    history.append({"role": "assistant", "content": reply2})
    
    print(f"用户: {user2}")
    print(f"助手: {reply2}")
    print("-" * 50)
    
    # 第三轮:更具体的需求
    user3 = "找到酒店后,帮我算一下1000美元换成人民币是多少"
    reply3 = chat_with_tools(user3, history)
    
    print(f"用户: {user3}")
    print(f"助手: {reply3}")

在这个例子中,当用户问“那天的天气怎么样?”时,模型能根据上下文理解“那天”指的是北京到上海航班的日期,并且知道要查询的是上海的天气(因为目的地是上海)。这种上下文理解能力对于构建流畅的对话体验至关重要。

3. 高级技巧:让函数调用更智能

基本的函数调用已经很有用了,但如果我们想让助手更智能,还需要一些进阶技巧。

3.1 参数自动补全和验证

有时候用户说的话不够具体,比如“查一下航班”,没说出发地、目的地、日期。好的模型应该能主动询问缺失的信息:

def smart_parameter_handling(user_input):
    """智能处理参数缺失的情况"""
    # 分析用户输入,提取已有信息
    # 如果发现缺失关键参数,让模型生成追问
    
    # 例如用户说“查航班”,模型可以回复:
    # “请问您要从哪个城市出发,去哪个城市,什么时间出发呢?”
    
    # 或者更智能一点,如果上下文中有相关信息,可以自动补全
    # 比如用户之前说过“我要去上海”,那么当他说“查一下航班”时
    # 模型可以自动把目的地设为上海,只追问出发地和时间
    pass

GLM-4-9B-Chat-1M在这方面表现不错,它能够根据工具描述中的required字段,判断哪些参数是必须的,然后在用户没提供时主动询问。

3.2 多工具协同工作

真正的智能助手应该能同时协调多个工具。比如用户说“规划一个三天的北京旅行”,助手应该能自动:

  1. 查航班(往返)
  2. 查三天的天气
  3. 找酒店
  4. 推荐景点(如果定义了这样的工具)
  5. 估算总花费
def plan_trip(destination: str, days: int, budget: float):
    """旅行规划工作流"""
    # 这是一个高级函数,内部会调用多个工具
    
    # 1. 查天气
    weather = get_weather_forecast(destination, days)
    
    # 2. 查航班(假设从用户所在城市出发)
    flights = search_flights("用户所在城市", destination, "出发日期")
    
    # 3. 找酒店
    hotels = find_hotels(destination, "入住日期", "离店日期")
    
    # 4. 计算预算
    total_cost = flights['flights'][0]['price'] + hotels['hotels'][0]['price'] * days
    
    # 5. 组织所有信息,生成完整报告
    return {
        "destination": destination,
        "duration": days,
        "weather_summary": weather,
        "flight_options": flights,
        "hotel_options": hotels,
        "estimated_cost": total_cost,
        "within_budget": total_cost <= budget
    }

你可以把这个plan_trip函数也作为一个工具暴露给模型,这样用户一句话就能触发完整的工作流。

3.3 错误处理和降级方案

工具调用可能会失败(API出错、网络问题等),好的系统应该有错误处理机制:

def robust_tool_call(tool_name, arguments):
    """健壮的工具调用"""
    try:
        # 尝试调用工具
        result = call_tool(tool_name, arguments)
        
        # 检查结果是否合理
        if is_result_valid(result):
            return {"success": True, "data": result}
        else:
            return {"success": False, "error": "工具返回了无效结果"}
            
    except Exception as e:
        # 记录错误
        log_error(f"工具{tool_name}调用失败: {str(e)}")
        
        # 提供降级方案
        fallback_result = get_fallback_data(tool_name, arguments)
        return {"success": False, "error": str(e), "fallback": fallback_result}

当工具调用失败时,你可以把错误信息交给模型,让模型生成得体的回复,比如“抱歉,暂时无法查询航班信息,您可以稍后再试或直接访问航空公司官网查询。”

4. 实际应用场景

函数调用功能在实际工作中有很多应用场景,远不止旅行助手这么简单。

4.1 企业内部助手

想象一个公司内部助手,员工可以问:

  • “帮我查一下张三上个月的考勤记录” → 调用HR系统接口
  • “这个季度的销售数据怎么样?” → 调用BI系统接口
  • “给我预约明天下午2点的会议室” → 调用日历系统接口
  • “创建一份关于项目进展的周报” → 调用文档模板+数据填充

4.2 电商客服机器人

顾客可以问:

  • “我订单123456的物流到哪了?” → 调用物流查询接口
  • “这款手机有现货吗?” → 调用库存查询接口
  • “帮我推荐一款适合玩游戏的笔记本电脑” → 调用产品推荐算法
  • “我要退货,怎么操作?” → 调用退货流程指南生成

4.3 数据分析助手

数据分析师可以问:

  • “统计一下上周的用户活跃度” → 调用数据查询+统计函数
  • “画一个销售额随时间变化的趋势图” → 调用图表生成函数
  • “预测下个月的用户增长” → 调用预测模型
  • “对比一下A产品和B产品的用户留存” → 调用对比分析函数

4.4 开发助手

程序员可以问:

  • “帮我写一个用户登录的API” → 调用代码生成函数
  • “检查这段代码有没有安全漏洞” → 调用代码分析工具
  • “把这份JSON转换成TypeScript接口定义” → 调用格式转换函数
  • “部署这个应用到测试环境” → 调用部署脚本

5. 性能考虑和最佳实践

虽然GLM-4-9B-Chat-1M的函数调用功能很强大,但在实际使用时还是需要注意一些性能问题。

5.1 上下文长度管理

百万上下文很强大,但也不是无限的。如果你的工具描述非常详细,或者对话历史很长,还是会占不少token。建议:

  1. 精简工具描述:在保证清晰的前提下,尽量用简洁的语言描述工具功能
  2. 选择性记忆:不是所有对话历史都需要永远记住,可以定期清理
  3. 工具分组:如果工具很多,可以按场景分组,需要时再加载对应的工具集

5.2 响应速度优化

函数调用涉及多次交互(用户→模型→工具→模型→用户),可能会影响响应速度:

  1. 并行调用:如果模型请求多个工具,且工具之间没有依赖关系,可以并行调用
  2. 缓存结果:对于一些不常变的数据(如城市信息、产品目录),可以缓存工具结果
  3. 超时设置:给工具调用设置合理的超时时间,避免长时间等待

5.3 安全性考虑

让模型调用外部工具是有安全风险的,需要注意:

  1. 权限控制:不同用户只能调用其有权限的工具
  2. 输入验证:即使模型提取了参数,在执行前也要再次验证
  3. 输出过滤:工具返回的结果可能包含敏感信息,需要适当过滤
  4. 审计日志:记录所有的工具调用,便于追踪和审计

5.4 错误处理和用户体验

工具调用可能失败,要做好错误处理:

  1. 友好的错误信息:不要直接把技术错误抛给用户
  2. 重试机制:对于临时性错误(如网络超时),可以自动重试
  3. 降级方案:主工具失败时,提供简化的替代方案
  4. 进度反馈:如果工具执行时间较长,要给用户进度反馈

6. 总结

GLM-4-9B-Chat-1M的函数调用功能确实让人眼前一亮。它不只是简单地把用户问题映射到API调用,而是真正理解用户意图、处理复杂上下文、协调多个工具完成复杂任务。

从我们的实践来看,这个模型在工具理解的准确性、参数提取的精确度、以及多轮对话的连贯性上都表现不错。特别是它的长上下文能力,让它可以处理非常复杂的多步骤任务,而不需要开发者做太多额外的上下文管理。

当然,要构建一个真正好用的智能助手,光有强大的模型还不够。你还需要设计合理的工具架构、处理各种边界情况、优化用户体验。但有了GLM-4-9B-Chat-1M这样的模型作为基础,这些工作就变得容易多了。

如果你正在考虑为你的产品或服务添加智能助手功能,或者想自动化一些重复性的工作流程,GLM-4-9B-Chat-1M的函数调用功能绝对值得一试。从简单的查询助手到复杂的业务流程自动化,它都能提供很好的支持。

实际用下来,部署和集成过程比想象中要顺畅。文档比较清晰,社区也比较活跃,遇到问题基本都能找到解决方案。对于有一定开发经验的团队来说,一到两周时间就能搭建起一个可用的原型,然后可以根据实际反馈逐步完善。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐