4

ChatGPT函数调用初体验:让ChatGPT具备抓取网页文本的能力

 1 year ago
source link: https://zxs.io/article/1925
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

ChatGPT函数调用初体验:让ChatGPT具备抓取网页文本的能力 | XINDOO

  OpenAI在6月13号升级了ChatGPT,推出了类似其网页版插件的功能——函数调用(Function calling),13号当天我在很多微信公众号就看到了这个消息,甚至有人将函数调用称为杀手级特性,正好周末有空,就写个Demo试用下,验证下它是平平无奇还是真的能让人眼前一亮。

  官网给出的函数调用示例是接入查询天气的能力,我看到第一反应 就这……。但当我写了一个简单抓取网页文本的函数,并将其接入到ChatGPT中后,我突然意识到这确实是一个非常强大的功能。之前的ChatGPT只能用文本交互,文本有个特点就是其规范性非常非常弱,同样的语义两个不同的人表述出来可能就是完全不同的两句话,导致我们很难用自然语言区控制普通的程序。而这次的函数调用能力,让其具备了输出强规范的内容,可以用来调起其他程序。这也意味着ChatGPT具备了和普通程序交互的能力,可想象的空间非常大。

  接下来我就用我实现的ChatGPT网页分析能力作为示例,演示下如何让ChatGPT接入普通的python函数,最后我再总结下函数调用的能力和局限,顺便也畅想下函数调用到底还可以实现什么样的强大功能。

Step1:实现普通函数

  首先就是要定义好普通的python函数,我这里写了一个简单的网页爬取的功能,给定url就可以抓取到网页上面的文本内容。这里只是一个简单实现,可能部分网页无法正常抓取。

复制
import requests
from bs4 import BeautifulSoup

def is_target_tag(tag):
    target_tags = ['p', 'code', 'h1', 'h2', 'h2', 'h3', 'h4', 'h5']
    return tag.name in target_tags

def get_text_from_url(url):
    response = requests.get(url, headers=headers)
    html = response.text
    soup = BeautifulSoup(html, 'html.parser')
    extracted_tags = soup.find_all(is_target_tag)
    res_text = '' 
    for tag in extracted_tags:
        res_text = res_text + tag.get_text(strip=True) + '\n'
    return res_text

  这里使用的是request包发起请求,使用bs4的BeautifulSoup来解析html标签,代码将html中所有的段落、代码、标题内容都抓取出来。

Step2: 用json-schema格式将函数描述出来

  这一步的作用就是把可以调用的普通函数信息用ChatGPT可以识别的格式描述出来,这里OpenAI直接采用了JSON-Schema。也比较简单,就是描述出来有哪些函数可以用、函数分别实现了什么样的功能、每个函数有哪些参数、哪些是必填参数、哪些是选填参数…… 这里我用来抓取url对应文本的函数描述如下:

复制
functions = [
    {
        "name": "getText",
        "description": "抓取url对应的网页里的文本内容",
        "parameters": {
            "type": "object",
            "properties": {
                "url": {
                    "type": "string",
                    "description": "网址url",
                }
            },
            "required": ["url"],
        },
    }
]

  注意,这里functions可以有不止一个,只要你能准确将函数功能及入参格式用json-schema描述出来,ChatGPT就能给你调起。 另外这里为了方便调起,我们还需要保存一个方法名到实际方法的映射关系,具体如下:

复制
available_functions = {
    "get_text_from_url": get_text_from_url,
} 

Step3: 调用ChatGPT的时候带上函数信息

  接下来我们只需要在原有Api的参数中增加functions,让ChatGPT知晓有哪些函数可以调用,然后让他决定要不要调。完整的代码及注释如下:

复制
import os
import openai
import json
openai.api_key = os.getenv("OPENAI_API_KEY")

def chat(content):
    messages = [
        {"role": "user", "content": content}
    ]
    response1 = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-0613",
        messages=messages,
        functions=functions,
        function_call="auto"
    )
    response_message = response1["choices"][0]["message"]
    rtn_message = response1["choices"][0]["message"]
    # 如果ChatGPT返回结果会告诉你,是否需要调用函数,我们只需要根据它返回的函数名、参数调起对应的函数
    # 然后将函数的返回结果再给到ChatGPT,让他进行下一步的操作  
    if response_message.get("function_call"):
        # 找到需要调用的函数,并将ChatGPT给的参数传进去 
        function_name = response_message["function_call"]["name"]
        fuction_to_call = available_functions[function_name]
        function_args = json.loads(response_message["function_call"]["arguments"])
        # 用这种方式可以调起任意python函数,不用像官网那样还要指定参数名  
        function_response = fuction_to_call(**function_args)
        # 获取到函数调用结果后,需要将结果拼接到对话记录里,并再次调用ChatGPT
        messages.append(response_message) 
        messages.append(
            {
                "role": "function",
                "name": function_name,
                "content": function_response,
            }
        ) 
        # 二次调用的返回结果里就是我们预期的结果了 
        response2 = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=messages,
        )
        rtn_message = response2["choices"][0]["message"]
    return rtn_message['content']

我们简单验证下效果:

复制
chat('总结下这篇文章,将其中的要点提炼出来 https://zxs.io/article/1924')

返回结果如下:

复制
这篇文章总结了使用ChatGPT提升程序员编程能力的方法和场景。作者经过两个月的使用发现,虽然ChatGPT目前还无法完全替代程序员在一些强上下文的编程场景下的能力,但在一些通用化的编程场景下,它的表现仍然可行。作者提炼出以下利用ChatGPT的场景:

1. 代码评审:ChatGPT可以检测代码的语法错误、代码风格问题、潜在的bug和性能问题,但需要注意辅助工具的局限性,建议与其他代码审查工具和人工审查相结合使用。  
2. 代码优化:除了代码评审,ChatGPT还可以帮助优化并重写代码,但同样需要结合其他专业人士的建议进行综合优化。  
3. 代码释义:使用ChatGPT生成代码释义,以减轻维护老代码的负担。  
4. 提供解决方案:描述遇到的问题,让ChatGPT给出建议和解决方案。  
5. 代码生成:ChatGPT可以直接生成相关代码,如分布式锁注解的代码,在实际使用中需要自行甄别和识别生成的代码。  
6. 设计模式和架构建议:ChatGPT可以提供在代码设计和架构设计上的建议。  
7. 学习新知识:在不熟悉的领域使用ChatGPT帮助学习。  

文章提到了一些使用ChatGPT的实例,并强调了在使用过程中需要注意甄别数据的时效性和准确性。最后,作者认为虽然ChatGPT无法替代程序员的大部分技能,但可以作为一个工具来提升工作效率。

  可以看到对于我博客的网址还是非常好用的,我也测试了CSDN、掘金等技术网站,也可以正常使用。但有些网站拿不到结果,不是ChatGPT不行,而是我get_text_from_url方法写的太low了,有些情况下确实没法抓取到内容。

备注:使用函数调用时需要升级最新的openai包,另外目前也只有gpt-3.5-turbo-0613和gpt-4-0613两个模型才支持函数调用,其他模型还不支持。

   不管是从官网查询天气的示例,还是从我这个抓取网页的示例来看,接入函数调用的能力并不复杂。另外需要注意到的一点,虽然这个功能叫函数调用,但ChatGPT并不会帮你去调这些函数,而是帮你判断何时去调用这些函数,给你调用函数所需要的参数,最终肯定得是由你自己去调用函数的。从它的返回数据格式可以看出,当前版本的函数调用还有个局限点,就是当前版本只能在一次对话中调起一个函数,如果遇到那种需要多次调用的操作,就只能通过多轮对话的方式实现了。

   虽然函数调用这个功能看似简单,但我觉得这个功能让ChatGPT拥有了和现有程序打通的能力,以前它只能帮你做决策、给建议,但现在它还可以去帮你执行。举个很实际的例子,现在ChatGPT用的最多的地方就是客服之类的问答场景,现在的系统只能做一些信息交换,比如商品咨询、退换货信息咨询……,但如果接入函数调用功能,用户就可以直接在对话的过程中完成整个流程,这现在是完全可以做到的,不过这个东西刚出来,其决策的可靠性还需要验证,连OpenAI在官网上都提示:

We strongly recommend building in user confirmation flows before taking actions that impact the world on behalf of users (sending an email, posting something online, making a purchase, etc).
我们强烈建议在代表用户采取影响世界的动作(发送电子邮件、在线发布内容、进行购买等)之前,先由用户确认。

  如果你还意识不到函数调用的强大能力,我再举一些简单的例子:如果ChatGPT和你的日历打通,那它是不是就可以帮你管理日程了; 如果和你的笔记打通,那它是不是就可以帮你整理笔记了;甚至是和你的股票账号打通,是不是就可以帮你炒股了;如果和脑机接口打通,那它是不是就可以控制……


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK