您的位置:首页 > 新闻 > 资讯 > 小程序制作单位_申请个人营业执照需要什么资料_凡科建站怎么导出网页_推广公司产品

小程序制作单位_申请个人营业执照需要什么资料_凡科建站怎么导出网页_推广公司产品

2024/10/12 10:44:04 来源:https://blog.csdn.net/pingguocu3/article/details/142641736  浏览:    关键词:小程序制作单位_申请个人营业执照需要什么资料_凡科建站怎么导出网页_推广公司产品
小程序制作单位_申请个人营业执照需要什么资料_凡科建站怎么导出网页_推广公司产品

前言

  1. 用自然语言连接系统的认知,面向未来思考系统间的集成
  2. GPTs 是如何连接外部世界的
  3. 用 Function Calling(函数调用) 把大模型和业务连接起来

一、接口介绍

1. 接口 (Interface)

两种常见接口:

  1. 人机交互接口,User Interface, 简称 UI
  2. 应用程序编程接口,Application Programming Interface, 简称 API

接口能「通」的关键,是两边都要遵守约定。
- 人要按照 UI 的设计来操作。UI 的设计要符合人的习惯
- 程序要按照 API 的设计来调用。API 的设计要符合程序惯例

2. 接口的进化

UI进化的趋势是:越来越适应人的习惯,越来越自然

  1. 命令行,Command Line Interface, 简称 CLI (DOS、Unix/Linux shell, Windows Power Shell)
  2. 图形界面,Graphical User Interface, 简称 GUl (Windows、MacOS、iOS、Android)
  3. 语言界面,Conversational User Interface, 简称CUI,或 Natural-Language User Interface,简称LUI ← 我们在这里
  4. 脑机接口,Brain-Computer Interface, 简称 BCI


API

  1. 从本地到远程,从同步到异步,媒介发生很多变化,但本质一直没变:程序员的约定
  2. 现在,开始进化到自然语言接口,Natural-Language Interface, 简称 NLI(自然语言与自然语言直接进行传递/对接/操作)

3. 自然语言接口 (Natural Language Interface,简称 NLI)

NLI是我们在 《以ChatGPT 为代表的「大模型」会是多大的技术革命?》一文中提出的概念。

用户操作习惯的迁移,会逼所有软件,都得提供「自然语言界面 (NaturalLanguage lnterface, 简称 NLI) 」。这是我生造的词,指的是以自然语言为输入的接口。

不仅用户界面要 NLI, API也要NLI化。这是因为用户发出的宏观指令,往往不会是一个独立软件能解决的,它需要很多软件、设备的配合。

一种实现思路是,入口Al(比如 Siri、小爱同学,机器人管家) 非常强大,能充分了解所有软件和设备的能力,且能准确地把用户任务拆解和分发下去。这对入口 Al 的要求非常高。

另一种实现思路是,入口 AI 收到自然语言指令,把指令通过 NLI广播出去(也可以基于某些规则做有选择的广播,保护用户隐私),由各个软件自主决策接不接这个指令,接了要怎么做,该和谁配合。

......

当 NLI 成为事实标准,那么互联网上软件、服务的互通性会大幅提升,不再受各种协议、接口的限制。

最自然的接口,就是自然语言接口:

以前因为计算机处理不对自然语言,所以有了那么多编程语言,那么多接口,那么多协议,那么多界面风格。而且,它们每一次进化,都是为了「更自然」。现在,终极的自然,到来了。我们終于可以把计算机当人看了!

二、大模型连接外部世界

OpenAl 是如何用自然语言连接一切的呢?

ChatGPT 能听懂自然语言,但是怎么和我们的业务系统进行连接呢?
方式1:我们可以通过提示词来控制大模型输出JSON格式数据,然后再与我们系统来产生连接。但是这种方式存在很多不稳定性,可控性不好。
方式2:使用 OpenAI推出的 Function Calling 技术,它可以让大语言模型和一切产生连接。

为什么要大模型连接外部世界?

大模型两大缺陷:

  1. 并非知晓一切
    A. 训练数据不可能什么都有。垂直、非公开数据必有欠缺
    B. 不知道最新信息。大模型的训练周期很长,且更新一次耗资巨大,还有越训越傻的风险。所以 ta 不可能实时训练。GPT-3.5 的知识截至 2022年1月,GPT-4是2023年4月。
  2. 没有「真逻辑」。它表现出的逻辑、推理,是训练文本的统计规律,而不是真正的逻辑。(大模型本质是基于统计规律/概率去猜下一个字或词)

所以:大模型需要连接真实世界,并对接真逻辑系统,才能补全缺陷产生真正的价值!

比如算加法:
1.把 100 以内所有加法算式都训练给大模型,ta 就能回答 100以内的加法算式
2.如果问 ta 更大数字的加法,就不一定对了
3.因为 ta 并不懂「加法」,只是记佳了100 以内的加法算式的统计规律
4.Ta 没有真逻辑,相当于是用字面意义做数学

三、Plugins / Actions 的发展

Plugins 是大模型连接真实世界第一次尝试,但产品很不成功

1. Plugins 开发

  • Actions 是 Plugins 的升级,是 GPTs 产品的一部分。
  • 可能是史上最容易开发的 plugin。只需要定义两个文件:
    yourdomain.com/.well-known/ai-plugin.json:描述插件的基本信息
    openai.yaml:描述插件的 API(Swagger 生成的文档)
  • 配置文件中,description 的内容非常重要,决定了 ChatGPT 会不会调用你的插件,调用得是否正确。
  • 而 OpenAI 那边,更简单,没有任何人和你对接。是 AI 和你对接!AI 阅读上面两个文件,就知道该怎么调用你了。(自然语言对接接口 NLI)

2. Plugins 缺陷

  • 缺少「强 Agent」调度,只能手工选三个 plugin,使用成本太高。(解决此问题,相当于 App Store + Siri,可挑战手机操作系统地位)
  • 不在「场景」中,不能提供端到端一揽子服务。(解决此问题,就是全能私人助理了,人类唯一需要的软件)
  • 开销大。(至少两次 GPT-4 生成,和一次 Web API 调用)

第二次尝试:升级为 Actions,内置到 GPTs 中,解决了落地场景问题。

3. 升级为 Actions

“Add actions” 功能是 GPTs 中的一个高级功能,允许用户将自定义聊天GPT与第三方API集成,以便执行特定动作或检索数据。

什么是 GPTs?GPTs 是 OpenAI 推出的自定义 GPT,即用户可以自定义聊天机器人,并发布到 OpenAI 的应用商店。

如:我们自定义的聊天机器人「小瓜 GPT」 ,通过在 GPTs 中添加 actions 接入了高德地图API,具备回答位置相关的问题:https://chat.openai.com/g/g-DxRsTzzep-xiao-gua
注意:需要升级开通 GPT-4 后,才能使用 GPTs(即自定义聊天机器人的功能)

GPTs 这样解决问题:

  • 每个 GPT 有一个场景,比如「写代码」「教小孩数学」「某某人的化身」
  • 被 GPT 绑定的 Actions 被自动调用,缩小了 agent 调度的难度
  • GPT-4 提速又降价

作为开发者,我们:

  • 可以开发 Actions,搭建自己的 GPTs
  • 还可以使用 Assistants API,脱离 ChatGPT 做独立智能应用

4. Actions 的工作流程:

  1. 人向OpenAI发起一个对话,这个对话是会触发 action 的 prompt

如:
prompt1:中关村附近的联通营业厅有哪些?
prompt1 会触发某个action

prompt2:附近的联通营业厅有哪些?
prompt2 不会触发某个action

  1. OpenAI会理解我们发起的对话内容prompt,从里面提取关键信息生成对 action 的调用参数。
  2. 然后去调用外部的API,并返回调用结果给 OpenAI
  3. 最后 OpenAI 会根据 外部API调用结果内容 再结合 我们提问的内容生成回答。

思考:GPT 怎么把 prompt 和 API 功能做匹配的?

5. Actions 开发对接

Actions 官方文档:https://platform.openai.com/docs/actions
把 API 对接到 GPTs 里,只需要配置一段 API 描述信息:

openapi: 3.1.0
info:title: 高德地图description: 获取 POI 的相关信息version: 'v1.0.0'
servers:- url: https://restapi.amap.com/v5/place
paths:/text:get:description: 根据POI名称,获得POI的经纬度坐标operationId: get_location_coordinateparameters:- name: keywords in: querydescription: POI名称,必须是中文required: true schema:type: string- name: region in: querydescription: POI所在的区域名,必领是中文required: false schema:type: stringdeprecated: false/around:get:description: 搜索给定坐标附近的POIoperationId: search_nearby_poisparameters:- name: keywords in: querydescription: 目标POI的关键字required: true schema:type: string- name: location in: querydescription: 中心点的经度和纬度,用逗号分隔required: false schema:type: stringdeprecated: false
components:schemas: {}

这里的所有name、description 都是prompt,决定了 GPT 会不会调用你的 APl,调用得是否正确。

还需要配置 APl Key 来满足权限要求。


思考:为什么不干脆整个描述文件都用自然语言写?非要用结构化的 JSON 或
YAML?
是为了提高准确度,为了防止幻觉,为了避免歧义,保证稳定性,所以使用明确的结构化方式来表示。

四、GPTs 与它的平替们

1. OpenAI GPTs,GPTs的好处:

  1. 无需编程,就能定制个性对话机器人的平台
  2. 可以放入自己的知识库,实现 RAG (后面会讲)
  3. 可以通过 actions 对接专有数据和功能
  4. 内置 DALLE3 文生图和 Code Interpreter 能力
  5. 只有 ChatGPT Plus 会员可以使用

没有 ChatGPT Plus 会员,推荐两款平替:

2. 字节跳动 Coze

  1. 可以免科学上网,免费使用 GPT-4 等 OpenAl的服务!大羊毛!
  2. 只有英文界面,但其实对中文更友好
  3. Prompt 优化功能更简单直接
  • 「iOS编程助手」的提示词:下面是系统帮我们优化后的提示词,是MarkDown格式,OpenAI对MarkDown格式支持比较友好。
# 角色
你是一位资深的iOS程序员,擅长Objective-C语言开发。你有着丰富的iOS开发经验,可以针对用户在iOS开发中遇到的问题提供专业解答和代码示例。## 技能
### 技能1: 问题解答
- 根据用户的问题,给出具体的解决方案。
- 如有需要,提供Objective-C语言的代码示例助其理解。### 技能2: 代码优化
- 针对用户提供的Objective-C代码片段,给出优化建议。
- 提供优化后的代码示例。### 技能3: iOS开发知识分享
- 根据用户的疑问,分享相关的iOS开发知识。
- 帮助用户理解iOS开发的核心概念和最佳实践。## 约束条件
- 只回答和解决与iOS开发相关的问题。
- 提供的代码示例只使用Objective-C语言。
- 应答始于对问题的清晰解答,如果涉及代码,应该提供代码示例。

3. Dify

  1. 开源,中国公司开发
  2. 功能最丰富
  3. 可以本地部署,支持非常多的大模型
  4. 有GUI,也有API

有这类无需开发的工具,为什么还要学大模型开发技术呢?

  1. 它们都无法针对业务需求做极致调优
  2. 它们和其它业务系统的集成不是特别方便

五、Function calling

Function calling(函数调用)技术:是一种大模型连接到外部的工具。

官方介绍

在 API 调用中,您可以描述函数,并让模型智能地选择输出包含调用一个或多个函数的参数的 JSON 对象。聊天完成 API 不会调用该函数;相反,模型会生成 JSON,您可以使用它来调用代码中的函数。

最新的模型 (gpt-3.5-turbo-0125gpt-4-turbo-preview) 经过训练,可以检测何时应该调用函数(取决于输入),并使用比以前的模型更紧密地遵循函数签名的 JSON 进行响应。

Function calling 的工作流程

  1. 用户向我们的应用程序发起提问;
  2. 我们的应用程序会把 用户的问题(prompt) 和 我们自己提供的函数(function)定义 一并给大模型,大模型会分析判断这个 prompt,是否需要调用某个函数,以及调用函数所需要的哪些参数,这个过程大模型会返回函数调用参数;(NLU过程 )

这一步是利用大模型把 prompt + function定义 解析成函数的调用,告诉我们要调用哪个函数,以及调用函数的参数是什么

  1. 我们的应用程序拿到大模型返回的参数,就去调用我们的函数;
  2. 我们的应用程序将函数调用的结果 再给 大模型;(NLG过程)
  3. 大模型会把 函数调用结果 再结合 prompt,生成自然语言的回答,并返回给我们的应用程序。

Function Calling 完整的官方接口文档:https://platform.openai.com/docs/guides/function-calling
值得一提:接口里叫 tools,是从 functions 改的。这是一个很有趣的指向

示例1:调用本地函数

需求:实现一个回答问题的 Al。题目中如果有加法,必须能精确计算。

  • 封装的通用代码
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
from math import *
import json# 加载 .env 到环境变量
_ = load_dotenv(find_dotenv())client = OpenAI()# 打印优美的JSON
def print_json(data):"""打印参数。如果参数是有结构的(如字典或列表),则以格式化的 JSON 形式打印;否则,直接打印该值。"""if hasattr(data, 'model_dump_json'):data = json.loads(data.model_dump_json())if (isinstance(data, (list, dict))):print(json.dumps(data, indent=4, ensure_ascii=False))else:print(data)   # 调用大模型方法
def get_completion(messages, tools, model="gpt-3.5-turbo-0125"):# tools 里定义了函数,大模型会解析 prompt,智能判断调用哪个函数,也可能不调用,也可能调错response = client.chat.completions.create(model=model,messages=messages,temperature=0.7,    # 模型输出的随机性,0表示随机性最小tools=tools,        # 用 JSON 描述函数。可以定义多个。由大模型决定调用谁。也可能都不调用)message = response.choices[0].messageprint("=====大模型回复=====")print_json(message)return message
  • 调用大模型代码
# 提示词
prompt = "Tell me the sum of 1, 2, 3, 4, 5, 6, 7, 8, 9, 10."  # 求和结果:55
prompt1 = "桌上有2个苹果, 四个桃子和3本书, 一共有几个水果?"  # 求和结果: 2 + 4 = 6
prompt2 = "1+2+3...+99+100" # 求和结果:5050
prompt3 = "1024 乘以 1024 是多少?"   # tools 里没有定义乘法,会怎样? 求和结果:可能会出现幻觉,结果不一定正确
prompt4 = "太阳从哪边升起?"           # 不需要算加法,会怎样? 求和结果:不会调用函数,返回的结果 tool_calls 是空的# 对话历史list
messages = [{"role": "system", "content": "你是一个数学家,你能帮我算一下吗?"},{"role": "user", "content": prompt}
]# 定义函数
tools = [{         "type": "function","function": {"name": "sum","description": "加法器,计算一组数的和","parameters": {"type": "object","properties": {"numbers": {"type": "array","items": {"type": "number"}}}}}}]# 1.调用大模型(将 prompt + function定义 传给大模型),返回函数调用参数
res_message = get_completion(messages, tools)# 记录对话历史,以便后续进行多轮对话
messages.append(res_message)# 2.获取函数调用参数
if (res_message.tool_calls is not None):tool_call = res_message.tool_calls[0]if tool_call.function.name == "sum":# 解析参数,获取 numbers 的值args = json.loads(tool_call.function.arguments) # 将 JSON字符串 转成 字典(Python对象)print("====解析出函数参数====")print_json(args)# 3.调用函数求和result = sum(args["numbers"])print(f'调用了加法器,计算结果是:{result}')# 4.将函数调用结果 和 历史会话 传给大模型messages.append({"tool_call_id": tool_call.id,   # 用于标识函数调用的 ID"role": "tool",                 # 用于标识是函数调用的结果"name": "sum",                  # 用于标识是哪个函数调用的结果"content": str(result)          # 数值 result 必须转成字符串})# 重新调用大模型   res_message = get_completion(messages, tools)
  • 输出结果:
=====大模型回复=====
{"content": null,"role": "assistant","function_call": null,"tool_calls": [{"id": "call_UhHsmflCKbYn8inSXHtSCtRQ","function": {"arguments": "{\"numbers\":[1,2,3,4,5,6,7,8,9,10]}","name": "sum"},"type": "function"}]
}
====解析出函数参数====
{"numbers": [1,2,3,4,5,6,7,8,9,10]
}
调用了加法器,计算结果是:55
=====大模型回复=====
{"content": "The sum of 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10 is 55.","role": "assistant","function_call": null,"tool_calls": null
}

注意:
1.Function Calling 中的函数与参数的描述也是一种Prompt
2.这种 Prompt 也需要调优,否则会影响函数的调用、参数的准确性,甚至让 GPT 产生幻觉

示例2:多Function 调用

需求:查询某个地点附近的酒店、餐厅、景点等信息。即,查询某个 POI附近的 POl。

  • 封装的通用代码
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
import requests
import json# 加载 .env 到环境变量
_ = load_dotenv(find_dotenv())client = OpenAI()# 打印优美的JSON
def print_json(data):"""打印参数。如果参数是有结构的(如字典或列表),则以格式化的 JSON 形式打印;否则,直接打印该值。"""if hasattr(data, 'model_dump_json'):data = json.loads(data.model_dump_json())if (isinstance(data, (list, dict))):print(json.dumps(data, indent=4, ensure_ascii=False))else:print(data)   # 调用大模型方法
def get_completion(messages, tools, model="gpt-3.5-turbo-0125"):# tools 里定义了函数,大模型会解析 prompt,智能判断调用哪个函数,也可能不调用,也可能调错response = client.chat.completions.create(model=model,messages=messages,temperature=0,       # 模型输出的随机性,0表示随机性最小seed=1024,           # 随机种子保持不变,temperature 和 prompt 不变的情况下,输出就会不变tool_choice="auto",  # 选择函数调用的策略。auto为默认值,表示由大模型自动决定是否调用函数tools=tools,         # 用 JSON 描述函数。可以定义多个。由大模型决定调用谁。也可能都不调用)message = response.choices[0].messageprint("=====大模型回复=====")print_json(message)return message# 高德地图开发者密钥
amap_key = "005deb4aeb1f8cfdd28fb5fdd6badf25"# 根据POI名称, 获得POI的经纬度坐标
def get_location_coordinate(location, city):url = "https://restapi.amap.com/v5/place/text"params = {"key": amap_key,"keywords": location,"city": city,"output": "json"}response = requests.get(url, params=params)data = response.json()if "pois" in data and data["pois"]:return data["pois"][0]else:return None# 搜索给定坐标附近的poi
def search_nearly_pois(longitude, latitude, keyword):url = "https://restapi.amap.com/v5/place/around"params = {"key": amap_key,"location": f"{longitude},{latitude}","keywords": keyword,"output": "json"}response = requests.get(url, params=params)data = response.json()ans = "" # 用于存储结果if "pois" in data and data["pois"]:pois = data["pois"]for i in range(min(3, len(pois))):name = pois[i]["name"]address = pois[i]["address"]distance = pois[i]["distance"]ans += f"{name}\n{address}\n距离: {distance}米\n\n"return ans
  • 调用大模型代码
# 提示词
prompt = "我想在北京五道口附近喝咖啡,给我推荐几个"
prompt1 = "我到北京出差,给我推荐三里屯的酒店,和五道口附近的咖啡"# 对话历史list
messages = [{"role": "system", "content": "你是一个地图通,你可以找到任何地址。"},{"role": "user", "content": prompt1}
]# 定义函数
tools = [{         "type": "function","function": {"name": "get_location_coordinate","description": "根据POI名称, 获得POI的经纬度坐标","parameters": {"type": "object","properties": {"location": {"type": "string","description": "POI名称, 必须是中文"},"city": {"type": "string","description": "POI所在的城市名, 必须是中文"}},"required": ["location", "city"]}}},{         "type": "function","function": {"name": "search_nearly_pois","description": "搜索给定坐标附近的poi","parameters": {"type": "object","properties": {"longitude": {"type": "string","description": "中心点的经度"},"latitude": {"type": "string","description": "中心点的纬度"},"keyword": {"type": "string","description": "目标poi的关键词"}},"required": ["longitude", "latitude", "keyword"]}}}]# 1.调用大模型(将 prompt + function定义 传给大模型),返回函数调用参数
res_message = get_completion(messages, tools)# 记录对话历史,以便后续进行多轮对话
messages.append(res_message)# 2.获取函数调用参数
while (res_message.tool_calls is not None):for tool_call in res_message.tool_calls:# 解析参数args = json.loads(tool_call.function.arguments) # 将 JSON字符串 转成 字典(Python对象)# 3.调用外部函数if tool_call.function.name == "get_location_coordinate":result = get_location_coordinate(**args)print ("Call: get_location_coordinate")print_json(result)elif tool_call.function.name == "search_nearly_pois":result = search_nearly_pois(**args)print ("Call: search_nearly_pois")print_json(result)messages.append({"tool_call_id": tool_call.id,       # 用于标识函数调用的 ID"role": "tool",                     # 用于标识是函数调用的结果"name": tool_call.function.name,    # 用于标识是哪个函数调用的结果"content": str(result)              # 数值 result 必须转成字符串})# 重新调用大模型res_message = get_completion(messages, tools)   if res_message.content is None: # 如果大模型返回的是 None,就将其置为空字符串(解决OpenAI的一个 400 bug)res_message.content = ""messages.append(res_message) # 把大模型的回复加入到対活中
  • 问1:我想在北京五道口附近喝咖啡,给我推荐几个
=====大模型回复=====
{"content": null,"role": "assistant","function_call": null,"tool_calls": [{"id": "call_DgUaQN9Tc9MHMSeyuEwWZT9f","function": {"arguments": "{\"location\":\"五道口\",\"city\":\"北京\"}","name": "get_location_coordinate"},"type": "function"}]
}
Call: get_location_coordinate
{"parent": "","address": "(在建)13A号线;13号线","distance": "","pcode": "110000","adcode": "110108","pname": "北京市","cityname": "北京市","type": "交通设施服务;地铁站;地铁站","typecode": "150500","adname": "海淀区","citycode": "010","name": "五道口(地铁站)","location": "116.337742,39.992894","id": "BV10006886"
}
=====大模型回复=====
{"content": null,"role": "assistant","function_call": null,"tool_calls": [{"id": "call_XzzqdcbJKAlswCFh4et1DsLQ","function": {"arguments": "{\"longitude\":\"116.337742\",\"latitude\":\"39.992894\",\"keyword\":\"咖啡\"}","name": "search_nearly_pois"},"type": "function"}]
}
Call: search_nearly_pois
瑞幸咖啡(五道口地铁站店)
荷清路与成府路交叉口华清嘉园1号楼二层1-2号
距离: 97米八号桥咖啡(华清嘉园东区店)
五道口华清嘉园12号(五道口地铁站B南口步行150米)
距离: 120米星巴克(北京五道口购物中心店)
成府路28号1层101-10B及2层201-09号
距离: 122米=====大模型回复=====
{"content": "以下是在北京五道口附近的几家咖啡店推荐:\n\n1. 瑞幸咖啡(五道口地铁站店)\n地址:荷清路与成府路交叉口华清嘉园1号楼二层1-2号\n距离地铁站:97米\n\n2. 八号桥咖啡(华清嘉园东区店)\n地址:五道口华清嘉园12号(五道口地铁站B南口步行150米)\n距离地铁站:120米\n\n3. 星巴克(北京五道口购物中心店)\n地址:成府路28号1层101-10B及2层201-09号\n距离地铁站:122米\n\n您可以选择其中一家前往享受咖啡时光。祝您喝咖啡愉快!","role": "assistant","function_call": null,"tool_calls": null
}
  • 问2:我到北京出差,给我推荐三里屯的酒店,和五道口附近的咖啡
=====大模型回复=====
{"content": null,"role": "assistant","function_call": null,"tool_calls": [{"id": "call_1B6LSeBa4UuOI3qJBYwcQKcN","function": {"arguments": "{\"location\": \"三里屯\", \"city\": \"北京\"}","name": "get_location_coordinate"},"type": "function"},{"id": "call_R7qgVvUtEzUqMW8cv82kOYfH","function": {"arguments": "{\"location\": \"五道口\", \"city\": \"北京\"}","name": "get_location_coordinate"},"type": "function"}]
}
Call: get_location_coordinate
{"parent": "","address": "朝阳区","distance": "","pcode": "110000","adcode": "110105","pname": "北京市","cityname": "北京市","type": "地名地址信息;热点地名;热点地名","typecode": "190700","adname": "朝阳区","citycode": "010","name": "三里屯","location": "116.455294,39.937492","id": "B0FFF5BER7"
}
Call: get_location_coordinate
{"parent": "","address": "(在建)13A号线;13号线","distance": "","pcode": "110000","adcode": "110108","pname": "北京市","cityname": "北京市","type": "交通设施服务;地铁站;地铁站","typecode": "150500","adname": "海淀区","citycode": "010","name": "五道口(地铁站)","location": "116.337742,39.992894","id": "BV10006886"
}
=====大模型回复=====
{"content": null,"role": "assistant","function_call": null,"tool_calls": [{"id": "call_w9H3DtZas1gpiw2ukK6idQuQ","function": {"arguments": "{\"longitude\": \"116.455294\", \"latitude\": \"39.937492\", \"keyword\": \"酒店\"}","name": "search_nearly_pois"},"type": "function"},{"id": "call_UlYak22SajR1JENOipRYsZWX","function": {"arguments": "{\"longitude\": \"116.337742\", \"latitude\": \"39.992894\", \"keyword\": \"咖啡\"}","name": "search_nearly_pois"},"type": "function"}]
}
Call: search_nearly_pois
北京瑜舍
三里屯路11号三里屯太古里北区
距离: 47米THE OPPOSITE HOUSE(三里屯太古里北区店)
三里屯路11号院三里屯太古里北区L1层
距离: 46米北京三里屯太古里亚朵X酒店
东直门外大街12号
距离: 384米Call: search_nearly_pois
瑞幸咖啡(五道口地铁站店)
荷清路与成府路交叉口华清嘉园1号楼二层1-2号
距离: 97米八号桥咖啡(华清嘉园东区店)
五道口华清嘉园12号(五道口地铁站B南口步行150米)
距离: 120米星巴克(北京五道口购物中心店)
成府路28号1层101-10B及2层201-09号
距离: 122米=====大模型回复=====
{"content": "在北京,我找到了以下地点:\n\n### 三里屯附近的酒店:\n1. 北京丽舍酒店\n   地址:三里屯路11号三里舍太古里北区\n   距离:47米\n\n2. THE OPPOSITE HOUSE(三里舍太古里北区店)\n   地址:三里舍路11号院三里舍太古里北区L1层\n   距离:46米\n\n3. 北京三里舍太古里亚杜X酒店\n   地址:东直门外大街12号\n   距离:384米\n\n### 五道口附近的咖啡店:\n1. 瑞幸咖啡(五道口地铁站店)\n   地址:荷清路与成府路交叉口华清嘉园1号楼2单元1-2号\n   距离:97米\n\n2. 八号桥咖啡(华清嘉园东区店)\n   地址:五道口华清嘉园12号(五道口地铁站B南口步行150米)\n   距离:120米\n\n3. 星巴克(北京五道口购物中心店)\n   地址:成府路28号1号楼101-10B及2号楼201-09号\n   距离:122米\n\n希望这些信息对您有帮助!","role": "assistant","function_call": null,"tool_calls": null
}

示例3:用 Function Calling 获取 JSON 结构

备注:Function calling 生成 JSON 的稳定性比较高。

需求:从一段文字中抽取联系人姓名、地址和电话

  • 调用大模型代码
# 提示词
prompt = "帮我寄给张三, 地址是浙江省杭州市滨江区浦沿街道, 电话151xxxxxxxx。"# 对话历史list
messages = [{"role": "system", "content": "你是一个联系人录入员。"},{"role": "user", "content": prompt}
]# 定义函数
tools=[{"type": "function","function": {"name": "add_contact","description": "添加联系人","parameters": {"type": "object","properties": {"name": {"type": "string","description": "联系人姓名"},"address": {"type": "string","description": "联系人地址"},"tel": {"type": "string","description": "联系人电话"},}}}}]# 1.调用大模型(将 prompt + function定义 传给大模型),返回函数调用参数
res_message = get_completion(messages, tools)# 解析出函数参数
if (res_message.tool_calls is not None):tool_call = res_message.tool_calls[0]if tool_call.function.name == "add_contact":# 解析参数,获取 numbers 的值args = json.loads(tool_call.function.arguments) # 将 JSON字符串 转成 字典(Python对象)print("====解析出函数参数====")print_json(args)
  • 输出结果:
=====大模型回复=====
{"content": null,"role": "assistant","function_call": null,"tool_calls": [{"id": "call_YPXDY8JJHJUCNlwjEJXnq8DP","function": {"arguments": "{\"name\":\"张三\",\"address\":\"浙江省杭州市滨江区浦沿街道\",\"tel\":\"151xxxxxxxx\"}","name": "add_contact"},"type": "function"}]
}
====解析出函数参数====
{"name": "张三","address": "浙江省杭州市滨江区浦沿街道","tel": "151xxxxxxxx"
}

示例 4:通过 Function Calling 查询数据库

需求:从订单表中查询各种信息,比如某个用户的订单数量、某个商品的销量、某个用户的消费总额等等。

示例 5:用 Function Calling 实现多表查询

示例 6:Stream 模式

流式(stream)输出不会一次返回完整 JSON 结构,所以需要拼接后再使用。

  • 完整代码
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
import json# 加载 .env 到环境变量
_ = load_dotenv(find_dotenv())client = OpenAI()# 打印优美的JSON
def print_json(data):"""打印参数。如果参数是有结构的(如字典或列表),则以格式化的 JSON 形式打印;否则,直接打印该值。"""if hasattr(data, 'model_dump_json'):data = json.loads(data.model_dump_json())if (isinstance(data, (list, dict))):print(json.dumps(data, indent=4, ensure_ascii=False))else:print(data)   # 调用大模型方法
def get_completion(messages, tools, model="gpt-3.5-turbo-0125"):# tools 里定义了函数,大模型会解析 prompt,智能判断调用哪个函数,也可能不调用,也可能调错response = client.chat.completions.create(model=model,messages=messages,temperature=0,     # 模型输出的随机性,0表示随机性最小tools=tools,       # 用 JSON 描述函数。可以定义多个。由大模型决定调用谁。也可能都不调用stream=True        # 启动流式输出)# print("====大模型回复====")# print_json(response) # <openai.Stream object at 0x1097cd4f0>return response# 提示词
# prompt = "1+2+3"
prompt = "你是谁"# 对话历史list
messages = [{"role": "system", "content": "你是一个小学数学老师,你要教学生加法"},{"role": "user", "content": prompt}
]# 定义函数
tools = [{         "type": "function","function": {"name": "sum","description": "计算一组数的加和","parameters": {"type": "object","properties": {"numbers": {"type": "array","items": {"type": "number"}}}}}}]# 1.调用大模型(将 prompt + function定义 传给大模型),返回函数调用参数
res_message = get_completion(messages, tools)print("====Streaming 流式输出====")
# 需要把 stream 里的 token 拼起来,才能得到完整的 call
function_name, args, text = "", "", ""
for msg in res_message: # print_json(msg)delta = msg.choices[0].deltaif delta.tool_calls:if not function_name:function_name = delta.tool_calls[0].function.nameargs_delta = delta.tool_calls[0].function.argumentsprint(args_delta)  # 打印每次得到的数据args = args + args_deltaelif delta.content:text_delta = delta.contentprint(text_delta)  # 打印每次得到的数据text = text + text_deltaprint("====完成,最终输出====")
if function_name or args:print(function_name)print_json(args)
if text:print(text)
  • prompt = "1+2+3" 的输出结果:
====Streaming 流式输出===={"
numbers
":[
1
,
2
,
3
]}
====完成,最终输出====
sum
{"numbers":[1,2,3]}
  • prompt = "你是谁" 的输出结果:
====Streaming 流式输出====
我
是
一个
小
学
数
学
老
师
,
我
可以
帮
助
你
学
习
数
学
。
你
有
什
么
问题
需要
帮
忙
吗
?
====完成,最终输出====
我是一个小学数学老师,我可以帮助你学习数学。你有什么问题需要帮忙吗?

六、Function Calling的注释事项

  1. 只有 gpt-3.5-turbo-0125gpt-4-turbo-preview 可用本次课介绍的方法。
  2. OpenAI 针对 Function Calling 做了 fine-tuning,以尽可能保证函数调用参数的正确。
  3. 函数声明是消耗 token 的。要在功能覆盖、省钱、节约上下文窗口之间找到最佳平衡。
  4. Function Calling 不仅可以调用读函数,也能调用写函数。但官方强烈建议,在写之前(对真实世界会产生影响的操作,如:发送电子邮件、在线发布内容、购买等),一定要有人做确认。
  5. 不保证不出错,包括不保证 json 格式正确。但比纯靠 prompt 控制,可靠性是大了很多。

七、支持 Function Calling 的国产大模型

百度文心大模型
MiniMax
  • 这是个公众不大知道,但其实挺强的大模型,尤其角色扮演能力
  • 如果你曾经在一个叫 Glow 的 app 流连忘返,那么你已经用过它了
  • 应该是最早支持 Function Calling 的国产大模型
  • Function Calling 的 API 和 OpenAI 1106 版之前完全一样,但其它 API 有很大的特色
ChatGLM3-6B
  • 最著名的国产开源大模型,生态最好
  • 早就使用 tools 而不是 function 来做参数,其它和 OpenAI 1106 版之前完全一样
讯飞星火 3.0
  • 和 OpenAI 1106 版之前完全一样
最后编辑于:2024-09-24 21:06:27


喜欢的朋友记得点赞、收藏、关注哦!!!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com