0


AI系列:大语言模型的function calling(上)

目录

大语言模型(LLM) 的function calling

大语言模型(LLM)可以使用自然语言与人类对话。但在使用它完成某项复杂工作时,很多时候必须依赖其他外部工具,这包括但不限于:

  • 训练的知识库和提示词以外的知识。包括某些垂直细分领域以及非公开的数据。
  • 计算任务。相信我,即使它给出的结果看起来很像样,你也不能相信它在计算方面的能力;它无法保证100%的准确性。
  • 实时数据。需要外部工具提供。

能识别需要使用的外部工具,能根据其结果数据完成对话的功能叫做function calling。

实验:OpenAI之function calling

OpenAI的GPT作为LLM的代表作,我们将给它提出如下问题:

问题:一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?
注: 这个简单的逻辑和算数题只作为实验用途;实际应用中可以扩展到复杂的计算。

我们将给GPT提供两个function/tool。一个是乘法,一个是加法。
注: 其中加法用来迷惑GPT。

我们期待的结果:GPT能判断使用乘法及其参数,并使用乘法function calling给出的结果数据,最终返回正确答案:
三个人一共有45个苹果。

序列图:function calling如何工作

我们的代码和GPT将怎样完成这个过程呢?这里将整个过程描绘在下面的时序图中:

#mermaid-svg-v1VpWwjHY7Hg9fuV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-v1VpWwjHY7Hg9fuV .error-icon{fill:#552222;}#mermaid-svg-v1VpWwjHY7Hg9fuV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-v1VpWwjHY7Hg9fuV .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-v1VpWwjHY7Hg9fuV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-v1VpWwjHY7Hg9fuV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-v1VpWwjHY7Hg9fuV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-v1VpWwjHY7Hg9fuV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-v1VpWwjHY7Hg9fuV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-v1VpWwjHY7Hg9fuV .marker.cross{stroke:#333333;}#mermaid-svg-v1VpWwjHY7Hg9fuV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-v1VpWwjHY7Hg9fuV .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-v1VpWwjHY7Hg9fuV text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-v1VpWwjHY7Hg9fuV .actor-line{stroke:grey;}#mermaid-svg-v1VpWwjHY7Hg9fuV .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-v1VpWwjHY7Hg9fuV .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-v1VpWwjHY7Hg9fuV #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-v1VpWwjHY7Hg9fuV .sequenceNumber{fill:white;}#mermaid-svg-v1VpWwjHY7Hg9fuV #sequencenumber{fill:#333;}#mermaid-svg-v1VpWwjHY7Hg9fuV #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-v1VpWwjHY7Hg9fuV .messageText{fill:#333;stroke:#333;}#mermaid-svg-v1VpWwjHY7Hg9fuV .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-v1VpWwjHY7Hg9fuV .labelText,#mermaid-svg-v1VpWwjHY7Hg9fuV .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-v1VpWwjHY7Hg9fuV .loopText,#mermaid-svg-v1VpWwjHY7Hg9fuV .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-v1VpWwjHY7Hg9fuV .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-v1VpWwjHY7Hg9fuV .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-v1VpWwjHY7Hg9fuV .noteText,#mermaid-svg-v1VpWwjHY7Hg9fuV .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-v1VpWwjHY7Hg9fuV .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-v1VpWwjHY7Hg9fuV .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-v1VpWwjHY7Hg9fuV .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-v1VpWwjHY7Hg9fuV .actorPopupMenu{position:absolute;}#mermaid-svg-v1VpWwjHY7Hg9fuV .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-v1VpWwjHY7Hg9fuV .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-v1VpWwjHY7Hg9fuV .actor-man circle,#mermaid-svg-v1VpWwjHY7Hg9fuV line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-v1VpWwjHY7Hg9fuV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
代码

  1. 大模型LLM
  2. 1. 调用对话接口,告诉LLM提示词+可使用的functions/tools定义
  3. 2. 需要调用的functions/tools及调用参数
  4. 3. 将步骤2LLM的回复加入对话
  5. 4. 循环执行function calling,并将结果加入对话
  6. 5. 调用对话接口,需要以上所有对话信息
  7. 6. 最终回答
  8. alt
  9. [分支:需要function calling]
  10. [分支:不需要function calling]
  11. 代码
  12. 大模型LLM

详情: 对话内容

以下内容是真实的对话历史,程序和GPT配合按照我们的预想完成了整个过程,并最终给出了正确答案。
注:以下用到的UserMessage, AIMessage, FunctionMessage都是LangChain中的概念;它比较贴切的抽象了不同role的对话项。

步骤1中的对话项:HumanMessage | 向GPT输入对话提示词。

  1. #提示词
  2. {
  3. "role": "user",
  4. "content": "一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?"
  5. }

另外,在调用GPT接口时,定义了2个function type tools:乘法multiply和加法add。内容参见下一部分的代码部分。

步骤2中的对话项:AIMessage | GPT返回需要调用的functions/tools及其调用参数。

  1. #这里GPT没有给出最终答案,它识别出了需要调用乘法multiply,参数一first_int为3个人,参数二second_int为15个苹果/每人。
  2. {
  3. "content": null,
  4. "role": "assistant",
  5. "function_call": null,
  6. "tool_calls": [
  7. {
  8. "id": "call_ZMbo4SiA2iaZUSLJMyX8ZzkP",
  9. "function": {
  10. "arguments": "{\"first_int\":3,\"second_int\":15}",
  11. "name": "multiply"
  12. },
  13. "type": "function"
  14. }
  15. ]
  16. }

步骤4中的对话项:FunctionMessage |function calling的调用结果数据。
tool_call_id对应步骤2中的tool_calls元素中的id。content为程序调用function/tool后的结果数据。

  1. #将function calling的结果为3*15=45,设定role为tool,将其加入对话中。
  2. {
  3. "tool_call_id": "call_ZMbo4SiA2iaZUSLJMyX8ZzkP",
  4. "role": "tool",
  5. "name": "multiply",
  6. "content": "45"
  7. }

步骤6中的对话项:AIMessage | 程序将以上所有对话项发送给GPT,GPT用自然语言返回最终结论。

  1. #最终结果为:三个人一共有45个苹果。
  2. {
  3. "content": "三个人一共有45个苹果。",
  4. "role": "assistant",
  5. "function_call": null,
  6. "tool_calls": null
  7. }

参考代码

function calling的实现代码如下:

  1. __author__ ='liyane'import json
  2. # 初始化环境和OpenAIfrom openai import OpenAI
  3. from dotenv import load_dotenv, find_dotenv
  4. _ = load_dotenv(find_dotenv())
  5. client = OpenAI()#调用GPT大模型defget_completion(messages, tools, model="gpt-3.5-turbo"):
  6. response = client.chat.completions.create(
  7. model=model,
  8. messages=messages,# tool_choice支持设置 "auto"(由模型决定是否调用tool 或者 "none" (不调用tool)作为value tools定义时默认由模型决定。# 也可以强制要求必须调用指定的函数,如下所示# tool_choice= {"type": "function", "function": {"name": "multiply"}} ,
  9. tools=tools
  10. )return response.choices[0].message
  11. #定义function/tool 1: multiplydefmultiply(first_int:int, second_int:int)->int:"""两个整数相乘"""return first_int * second_int
  12. #定义function/tool 2: adddefadd(first_add:int, second_add:int)->int:"""两个整数相加"""return first_add + second_add
  13. #将function calling的schema格式告诉大模型
  14. tools=[{"type":"function","function":{"name":"multiply","description":"两个整数相乘","parameters":{"type":"object","properties":{"first_int":{"type":"integer","description":"第一个乘数",},"second_int":{"type":"integer","description":"第二个乘数",}},"required":["first_int","second_int"],}}},{"type":"function","function":{"name":"add","description":"两个整数相加","parameters":{"type":"object","properties":{"first_add":{"type":"integer","description":"第一个加数",},"second_add":{"type":"integer","description":"第二个加数",}},"required":["first_add","second_add"],}}}]# 调用LLM接口,将LLM回复加入对话上下文
  15. prompt ="一共有3个人,每个人有15个苹果,10个鸭梨,一共有多少苹果?"
  16. messages =[{"role":"user","content": prompt}]
  17. response = get_completion(messages, tools)
  18. messages.append(response)# 如果LLM需要function calling,调用相应的函数,并将函数结果数据加入对话上下文,继续调用LLMwhile(response.tool_calls isnotNone):for tool_call in response.tool_calls:
  19. selected_tool ={"add": add,"multiply": multiply}[tool_call.function.name]
  20. args = json.loads(tool_call.function.arguments)
  21. tool_output = selected_tool(**args)
  22. messages.append({"tool_call_id": tool_call.id,# 用于标识函数调用的 ID"role":"tool","name": tool_call.function.name,"content":str(tool_output)# 数值result 必须转成字符串})
  23. response = get_completion(messages, tools)
  24. messages.append(response)print("=====最终回复=====")print(response.content)

后续: 使用LangChain实现function calling

后续更新AI系列:大语言模型的function calling(下)- 使用LangChain:如何使用LangChain实现function calling,LangChain对比原生调用能提供哪些便利。

参考

OpenAI / function calling
LangChain / Tool/function calling


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

“AI系列:大语言模型的function calling(上)”的评论:

还没有评论