0


GLM-4 (5) - API & Function Calling

系列文章目录

GLM-4 (1) - 推理+概览
GLM-4 (2) - RoPE
GLM-4 (3) - GLMBlock
GLM-4 (4) - SelfAttention
GLM-4 (5) - API & Function Calling
GLM-4 (6) - KV Cache / Prefill & Decode


文章目录


前言

我们之前解析了

GLM-4

模型相关的部分,这有助于我们对理解和使用开源大模型。然后,有一些场景对于大模型的性能(比如某个任务的推理准确率)有较高的要求,

10B

以下参数的模型很可能无法胜任。那么就有两条路可以选择:1)收集与任务相关的数据,微调该模型;2)直接使用商业化的

API

服务。由于第一条路收集数据工作量较大,所以调用

API

是个不错的选择,也是本篇要讲述的内容。
大模型并不是万能的,推理的时候也会出错,比如近期的热搜就是大模型比较

9.11

9.8

大小的时候变成弱智。但是,大模型有

Function Calling

的加持,调用外部函数,就能有效缓解这些问题。
本文将展示

glm-4

gpt-4o

以及

deepseek coder v2

大模型的

API

的调用,以及

Function Calling

的集成。参考链接如下:
zhipuai:https://open.bigmodel.cn/dev/howuse/functioncall
openai:https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/function-calling?tabs=python
deepseek:https://platform.deepseek.com/usage
微调大模型function calling:https://blog.csdn.net/weixin_40959890/article/details/140137952

在这里插入图片描述


一、获取API KEY

想要使用大模型

API

服务,需要去各厂商官网上获取

API KEY

。这比较容易,不再赘述。值得一提的是,

智谱

deepseek

只要注册就会有免费的资源包。对于

gpt-4o

,我使用的是

Azure

提供的服务。使用的

API KEY

和模型如下:

ZHIPU_API_KEY ="xxxxx.xxxxx"
DEEPSEEK_API_KEY ="sk-xxxxx"# Azure的服务
OPENAI_API_KEY ="xxxxx"
OPENAI_ENDPOINT ="https://xxxxx"# 系列模型,在前面的效果好一些
ZHIPU_MODELS =["glm-4-0520","glm-4"]
DEEPSEEK_MODELS =["deepseek-coder","deepseek-chat"]
OPENAI_MODELS =["gpt-4o"]

二、API调用 & Function Calling使用

1.引入库

我在类

LLMRequestWithFunctionCalling

中集成了上述几种大模型的

API

调用,且包含了

Function Calling

(这里

deepseek

不支持)。

API

调用可以是SDK调用,也可以是

HTTP

调用。这边在使用

智谱

deepseek

模型时,选择了SDK调用,对于

Azure gpt-4o

则采用了

HTTP

调用。

# function_calling.pyclassLLMRequestWithFunctionCalling:"""
    在使用llm的时候,使用function calling以满足你的需求
    有两种方式实现function calling:
    1) function call: https://techcommunity.microsoft.com/t5/ai-azure-ai-services-blog/function-calling-is-now-available-in-azure-openai-service/ba-p/3879241
    2)tool call: https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/function-calling?tabs=python
    我们这里使用tool call
    """def__init__(self, system_prompt:str, prompt:str, tools: List[Dict]=None, model:str="glm-4"):# 系统提示
        self.system_prompt = system_prompt
        # 用户提示
        self.prompt = prompt
        # tools
        self.tools = tools
        # # 函数functions# self.functions = [tool.get("function") for tool in tools if tool.get("type") == "function"]# 使用的模型
        self.model = model

        # 消息
        self.messages: List[Dict]=[]# 客户端
        self.client: Union[OpenAI, ZhipuAI,None]=None# http请求 -> 这是Azure的gpt-4o的请求方式
        self.http_args: Union[Dict[str, Dict],None]=None# 函数名称
        self.function_names: List =[]# 初始化
        self._init()def_init(self):"""
        初始化
        """# client & http_argsassert self.model in ZHIPU_MODELS + DEEPSEEK_MODELS + OPENAI_MODELS
        if self.model in ZHIPU_MODELS + DEEPSEEK_MODELS:if self.model in ZHIPU_MODELS:# 使用智谱api
                self.client = ZhipuAI(api_key=ZHIPU_API_KEY)# 填写您自己的APIKeyelse:# 使用deepseek api
                self.client = OpenAI(api_key=DEEPSEEK_API_KEY, base_url="https://api.deepseek.com")else:# 使用Azure的gpt-4o api
            self.http_args ={"headers":{"Content-Type":"application/json","api-key": OPENAI_API_KEY,},"generate_args":{"temperature":0.7,"top_p":0.95,"max_tokens":800}# 这边设置了一些生成参数,当然上面client也是可以设置的}# messages# 这是必备消息
        self.messages.append({"role":"system","content": self.system_prompt})
        self.messages.append({"role":"user","content": self.prompt})# function name抽取一下for tool in self.tools:
            self.function_names.append(tool["function"]["name"])def_llm_request(self,
                     messages: List[Dict],
                     tools: Optional[List[Dict]]=None)-> Union[ChatCompletion, Completion, Dict,None]:"""
        使用llm api请求
        """if self.client isnotNone:try:
                response = self.client.chat.completions.create(
                    model=self.model,# 模型名称
                    messages=messages,
                    stream=False,
                    tools=tools,# tool_choice="auto")except Exception as e:print("response error")
                response =Noneelse:# Azure提供的api服务print()
            headers = self.http_args["headers"]
            payload ={"messages": messages,}if tools isnotNone:# function call# functions = [tool.get("function") for tool in tools if tool.get("type") == "function"]# payload.update({#     "function_call": "auto",#     "functions": functions# })# tool call
                payload.update({"tools": tools,"tool_choice":"auto"})
            payload.update(**self.http_args["generate_args"])# Send requesttry:
                response = requests.post(OPENAI_ENDPOINT, headers=headers, json=payload)
                response.raise_for_status()# Will raise an HTTPError if the HTTP request returned an unsuccessful status codeexcept requests.RequestException as e:# raise SystemExit(f"Failed to make the request. Error: {e}")print(f"Failed to make the request. Error: {e}")
                response =Noneif response isnotNone:# 转成dict, eg:{'choices': [{'content_filter_results': {'hate': {'filtered': False, 'severity': 'safe'}, 'self_harm': {'filtered': False, 'severity': 'safe'}, 'sexual': {'filtered': False, 'severity': 'safe'}, 'violence': {'filtered': False, 'severity': 'safe'}}, 'finish_reason': 'stop', 'index': 0, 'logprobs': None, 'message': {'content': '中国最发达的城市之一是上海。上海是中国的经济、金融、贸易和航运中心。它拥有世界上最繁忙的港口之一,同时也是许多跨国公司在中国的总部所在地。除了上海,北京、深圳和广州也被认为是中国最发达的城市之一。北京是中国的政治和文化中心,深圳是科技和创新的前沿城市,而广州则是重要的贸易和制造业中心。这些城市在经济、教育、医疗、基础设施等多个方面都非常发达。', 'role': 'assistant'}}], 'created': 1721784656, 'id': 'chatcmpl-9oL8Cm6q3LNTJcpP4EePv1MK2tEzj', 'model': 'gpt-4o-2024-05-13', 'object': 'chat.completion', 'prompt_filter_results': [{'prompt_index': 0, 'content_filter_results': {'hate': {'filtered': False, 'severity': 'safe'}, 'self_harm': {'filtered': False, 'severity': 'safe'}, 'sexual': {'filtered': False, 'severity': 'safe'}, 'violence': {'filtered': False, 'severity': 'safe'}}}], 'system_fingerprint': 'fp_abc28019ad', 'usage': {'completion_tokens': 116, 'prompt_tokens': 31, 'total_tokens': 147}}
                response = response.json()return response

    defexecute(self, use_functions:bool)-> Union[ChatCompletion, Completion, Dict,None]:"""
        执行请求,
        当use_functions=True时才会进行函数调用
        """ifnot use_functions ornot self.tools:return self._llm_request(self.messages)if self.model in ZHIPU_MODELS:return self._execute_zhipuai()elif self.model in OPENAI_MODELS:return self._execute_openai()else:raise NotImplementedError(f"{self.model} 在此处暂时不支持function calling!")def_parse_function_call_zhipuai(self, response_to_tools):"""
        解析智谱的function_call
        """ifnot response_to_tools.choices[0].message.tool_calls:return
        tool_call = response_to_tools.choices[0].message.tool_calls[0]
        args = tool_call.function.arguments
        function_result ={}
        name = tool_call.function.name
        if name in self.function_names:
            function_result =eval(name)(**json.loads(args))# 添加消息
        self.messages.append({"role":"tool","content":f"{json.dumps(function_result)}","tool_call_id": tool_call.id})def_parse_function_call_openai(self, response_to_tools):"""
        解析openai function_call (http请求)
        """ifnot response_to_tools:# todo: 观察字段return
        function_obj = response_to_tools["choices"][0]["message"]["tool_calls"][0]
        tool_call_id = function_obj["id"]
        function = function_obj["function"]
        name = function["name"]
        args = function["arguments"]

        function_result ={}if name in self.function_names:
            function_result =eval(name)(**json.loads(args))# 添加消息
        self.messages.append({"role":"tool","content":f"{json.dumps(function_result)}","tool_call_id": tool_call_id
        })def_execute_zhipuai(self)-> Union[Completion, Dict,None]:"""
        glm系列实现function calling
        """# 调用tools并响应
        response_to_tools = self._llm_request(self.messages, tools=self.tools)if response_to_tools isNone:raise Exception("智谱函数调用失败")# {'content': '', 'role': 'assistant', 'tool_calls': [{'id': 'call_202407301506203c337e808ac84619', 'function': {'arguments': '{"date":"2022-01-23","departure":"北京","destination":"广州"}', 'name': 'get_flight_number'}, 'type': 'function', 'index': 0}]}
        self.messages.append(response_to_tools.choices[0].message.model_dump())
        self._parse_function_call_zhipuai(response_to_tools)# 以上添加了assistant和tool的响应,接下来根据所有message请求
        response = self._llm_request(self.messages, tools=self.tools)if response isnotNone:
            self.messages.append(response.choices[0].message.model_dump())return response

    def_execute_openai(self)-> Union[ChatCompletion, Dict,None]:"""
        gpt系列(http请求)实现function calling
        """
        response_to_tools = self._llm_request(self.messages, tools=self.tools)if response_to_tools isNone:raise Exception("openai函数调用失败")
        self.messages.append(response_to_tools["choices"][0]["message"])
        self._parse_function_call_openai(response_to_tools)

        response = self._llm_request(self.messages, tools=self.tools)if response isnotNone:
            self.messages.append(response["choices"][0]["message"])return response

三、示例

假设这边有两个函数

get_flight_number

get_ticket_price

,我们构建了函数如下方的

tools

所示,该结构化数据主要包含函数的名称

name

,函数的描述

description

,函数入参

parameters

tools =[{"type":"function","function":{"name":"get_flight_number","description":"根据始发地、目的地和日期,查询对应日期的航班号","parameters":{"type":"object","properties":{"departure":{"description":"出发地","type":"string"},"destination":{"description":"目的地","type":"string"},"date":{"description":"日期","type":"string",}},"required":["departure","destination","date"]},}},{"type":"function","function":{"name":"get_ticket_price","description":"查询某航班在某日的票价","parameters":{"type":"object","properties":{"flight_number":{"description":"航班号","type":"string"},"date":{"description":"日期","type":"string",}},"required":["flight_number","date"]},}},]defget_flight_number(date:str, departure:str, destination:str):
    flight_number ={"北京":{"上海":"1234","广州":"8321",},"上海":{"北京":"1233","广州":"8123",}}return{"flight_number": flight_number[departure][destination]}defget_ticket_price(date:str, flight_number:str):return{"ticket_price":"1000"}

我们来让大模型借助

Function Calling

来查一下航班:

system_prompt ="不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息"
prompt ="帮我查询1月23日,北京到广州的航班"

llmr = LLMRequestWithFunctionCalling(system_prompt, prompt, tools,"gpt-4o")# or glm-4
res = llmr.execute(use_functions=True)print(res)

我测试了

glm-4

以及

gpt-4o

这两个模型,得到

llmr.messages

结果如下:

# ------------------- glm-4 ---------------------[{'role':'system','content':'不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息'},{'role':'user','content':'帮我查询1月23日,北京到广州的航班'},{'content':'','role':'assistant','tool_calls':[{'id':'call_202407301506203c337e808ac84619','function':{'arguments':'{"date":"2022-01-23","departure":"北京","destination":"广州"}','name':'get_flight_number'},'type':'function','index':0}]},{'role':'tool','content':'{"flight_number": "8321"}','tool_call_id':'call_202407301506203c337e808ac84619'},{'content':'根据您的查询,经过API调用,我找到了1月23日从北京到广州的航班号,它是8321。','role':'assistant','tool_calls':None}]# ------------------- gpt-4o ---------------------[{'role':'system','content':'不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息'},{'role':'user','content':'帮我查询1月23日,北京到广州的航班'},{'content':'请稍等,我将为您查询1月23日从北京到广州的航班信息。','role':'assistant','tool_calls':[{'function':{'arguments':'{"departure":"北京","destination":"广州","date":"2024-01-23"}','name':'get_flight_number'},'id':'call_znSa2Quwbwze9xtjRebUgSsI','type':'function'}]},{'role':'tool','content':'{"flight_number": "8321"}','tool_call_id':'call_znSa2Quwbwze9xtjRebUgSsI'},{'content':'查询到1月23日从北京到广州的航班号是8321。您是否需要查询该航班的票价信息?','role':'assistant'}]

成功!

四、其他

  • Function Calling功能现在都是使用toolstool_choice参数来实现的,实际上也可以使用functionsfunction_call实现,比如Azure的example和OpenAI的example(这种方式可能比较老旧);
  • 上面有两个函数,我们在进行Function Calling的时候,tool_choice参数要么是使用默认值,要么就是"auto",这意味着让模型自主选择其中的一个函数;如果将其设置为 {"name": "your_function_name"}时,可以强制API返回特定函数的调用;根据智谱文档所说,目前它只支持默认的"auto"
  • 该博客中提到了NexusRavenV2-13B模型感觉也不错。

总结

本文介绍了大模型

API

调用,以及

Function Calling

的使用,适用于推理准确性要求较高的场景。


本文转载自: https://blog.csdn.net/daihaoguang/article/details/140806559
版权归原作者 戴昊光 所有, 如有侵权,请联系我们删除。

“GLM-4 (5) - API & Function Calling”的评论:

还没有评论