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


文章目录


前言

我们之前解析了

  1. GLM-4

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

  1. 10B

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

  1. API

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

  1. API

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

  1. 9.11

  1. 9.8

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

  1. Function Calling

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

  1. glm-4

  1. gpt-4o

以及

  1. deepseek coder v2

大模型的

  1. API

的调用,以及

  1. 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

想要使用大模型

  1. API

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

  1. API KEY

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

  1. 智谱

  1. deepseek

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

  1. gpt-4o

,我使用的是

  1. Azure

提供的服务。使用的

  1. API KEY

和模型如下:

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

二、API调用 & Function Calling使用

1.引入库

我在类

  1. LLMRequestWithFunctionCalling

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

  1. API

调用,且包含了

  1. Function Calling

(这里

  1. deepseek

不支持)。

  1. API

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

  1. HTTP

调用。这边在使用

  1. 智谱

  1. deepseek

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

  1. Azure gpt-4o

则采用了

  1. HTTP

调用。

  1. # function_calling.pyclassLLMRequestWithFunctionCalling:"""
  2. 在使用llm的时候,使用function calling以满足你的需求
  3. 有两种方式实现function calling:
  4. 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
  5. 2tool call: https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/function-calling?tabs=python
  6. 我们这里使用tool call
  7. """def__init__(self, system_prompt:str, prompt:str, tools: List[Dict]=None, model:str="glm-4"):# 系统提示
  8. self.system_prompt = system_prompt
  9. # 用户提示
  10. self.prompt = prompt
  11. # tools
  12. self.tools = tools
  13. # # 函数functions# self.functions = [tool.get("function") for tool in tools if tool.get("type") == "function"]# 使用的模型
  14. self.model = model
  15. # 消息
  16. self.messages: List[Dict]=[]# 客户端
  17. self.client: Union[OpenAI, ZhipuAI,None]=None# http请求 -> 这是Azure的gpt-4o的请求方式
  18. self.http_args: Union[Dict[str, Dict],None]=None# 函数名称
  19. self.function_names: List =[]# 初始化
  20. self._init()def_init(self):"""
  21. 初始化
  22. """# client & http_argsassert self.model in ZHIPU_MODELS + DEEPSEEK_MODELS + OPENAI_MODELS
  23. if self.model in ZHIPU_MODELS + DEEPSEEK_MODELS:if self.model in ZHIPU_MODELS:# 使用智谱api
  24. self.client = ZhipuAI(api_key=ZHIPU_API_KEY)# 填写您自己的APIKeyelse:# 使用deepseek api
  25. self.client = OpenAI(api_key=DEEPSEEK_API_KEY, base_url="https://api.deepseek.com")else:# 使用Azure的gpt-4o api
  26. 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# 这是必备消息
  27. self.messages.append({"role":"system","content": self.system_prompt})
  28. self.messages.append({"role":"user","content": self.prompt})# function name抽取一下for tool in self.tools:
  29. self.function_names.append(tool["function"]["name"])def_llm_request(self,
  30. messages: List[Dict],
  31. tools: Optional[List[Dict]]=None)-> Union[ChatCompletion, Completion, Dict,None]:"""
  32. 使用llm api请求
  33. """if self.client isnotNone:try:
  34. response = self.client.chat.completions.create(
  35. model=self.model,# 模型名称
  36. messages=messages,
  37. stream=False,
  38. tools=tools,# tool_choice="auto")except Exception as e:print("response error")
  39. response =Noneelse:# Azure提供的api服务print()
  40. headers = self.http_args["headers"]
  41. 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
  42. payload.update({"tools": tools,"tool_choice":"auto"})
  43. payload.update(**self.http_args["generate_args"])# Send requesttry:
  44. response = requests.post(OPENAI_ENDPOINT, headers=headers, json=payload)
  45. 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}")
  46. 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}}
  47. response = response.json()return response
  48. defexecute(self, use_functions:bool)-> Union[ChatCompletion, Completion, Dict,None]:"""
  49. 执行请求,
  50. 当use_functions=True时才会进行函数调用
  51. """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):"""
  52. 解析智谱的function_call
  53. """ifnot response_to_tools.choices[0].message.tool_calls:return
  54. tool_call = response_to_tools.choices[0].message.tool_calls[0]
  55. args = tool_call.function.arguments
  56. function_result ={}
  57. name = tool_call.function.name
  58. if name in self.function_names:
  59. function_result =eval(name)(**json.loads(args))# 添加消息
  60. 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):"""
  61. 解析openai function_call (http请求)
  62. """ifnot response_to_tools:# todo: 观察字段return
  63. function_obj = response_to_tools["choices"][0]["message"]["tool_calls"][0]
  64. tool_call_id = function_obj["id"]
  65. function = function_obj["function"]
  66. name = function["name"]
  67. args = function["arguments"]
  68. function_result ={}if name in self.function_names:
  69. function_result =eval(name)(**json.loads(args))# 添加消息
  70. self.messages.append({"role":"tool","content":f"{json.dumps(function_result)}","tool_call_id": tool_call_id
  71. })def_execute_zhipuai(self)-> Union[Completion, Dict,None]:"""
  72. glm系列实现function calling
  73. """# 调用tools并响应
  74. 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}]}
  75. self.messages.append(response_to_tools.choices[0].message.model_dump())
  76. self._parse_function_call_zhipuai(response_to_tools)# 以上添加了assistanttool的响应,接下来根据所有message请求
  77. response = self._llm_request(self.messages, tools=self.tools)if response isnotNone:
  78. self.messages.append(response.choices[0].message.model_dump())return response
  79. def_execute_openai(self)-> Union[ChatCompletion, Dict,None]:"""
  80. gpt系列(http请求)实现function calling
  81. """
  82. response_to_tools = self._llm_request(self.messages, tools=self.tools)if response_to_tools isNone:raise Exception("openai函数调用失败")
  83. self.messages.append(response_to_tools["choices"][0]["message"])
  84. self._parse_function_call_openai(response_to_tools)
  85. response = self._llm_request(self.messages, tools=self.tools)if response isnotNone:
  86. self.messages.append(response["choices"][0]["message"])return response

三、示例

假设这边有两个函数

  1. get_flight_number

  1. get_ticket_price

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

  1. tools

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

  1. name

,函数的描述

  1. description

,函数入参

  1. parameters

  1. 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):
  2. 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"}

我们来让大模型借助

  1. Function Calling

来查一下航班:

  1. system_prompt ="不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息"
  2. prompt ="帮我查询1月23日,北京到广州的航班"
  3. llmr = LLMRequestWithFunctionCalling(system_prompt, prompt, tools,"gpt-4o")# or glm-4
  4. res = llmr.execute(use_functions=True)print(res)

我测试了

  1. glm-4

以及

  1. gpt-4o

这两个模型,得到

  1. llmr.messages

结果如下:

  1. # ------------------- 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模型感觉也不错。

总结

本文介绍了大模型

  1. API

调用,以及

  1. Function Calling

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


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

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

还没有评论