智普清言开放平台函数调用

记得去年2023GPT刚发布我就到处找较便宜的API,但当时大多是国外的虽然有代理的但是稍微贵了点(相对与我).终于现在模型市场卷起来了,国产的==GLM4也还是不错。记录下自己使用过程:
有了API就可以将大语言模型集成到很多地方。

先来个图,这个是我下面举的例子,图是AI画的

Created with Raphaël 2.3.0 用户提出需求: "创建一个文件夹" 判断是否调用函数 提取关键信息: "创建文件夹" 调用get_func_run_result函数 生成Python代码: mkdir("new_folder") 在本地环境运行代码 检查代码运行结果 记录成功结果: 文件夹已创建 大语言模型总结结果 记录失败结果: 创建文件夹失败 重试最多5次 yes yes no

函数作用—个人理解

大语言模型怎么使用应该都知道------给模型输入信息------模型返回结果。
但是有个问题,如果你做应用,想利用大模型理解别人说的话,提取到必要信息怎么做?
有个人要通过大模型查询北京到上海的航班信息。
他这样问的:查询2024年7月23日从北京到上海的ABX21次飞机的航班信息。
这样问虽然提供的信息很具体,但是模型还没意识还没有联想信息的功能,所以他只会机械方式得在海量已有数据里检索出:胡编乱造的信息回答你。
如下:下面回答还好,如果没有网页搜索,他真的是胡编乱造。
在这里插入图片描述

揭秘大语言模型的“超能力”与我们的“小秘密”

哎呀呀,虽然我们这位大语言模型兄台在网络上翻云覆雨,但它有时候也会遇到一点小尴尬——比如说,找不到我们想要的航班信息。不过,别小看了这位大兄弟,它可是有着精准提取关键信息的能力。瞧瞧,客户一提到“日期、出发地、目的地、航班号”,它就像个侦探一样,把这些线索一一记录下来。

关键信息提取大展示:

日期:2024-07-23
出发地:北京
目的地:上海
航班号:ABX21

转折来了!

虽然大语言模型在网络上找不到信息,但是别忘了,我们手里还有一张王牌——自家数据库!这就好比大模型是个聪明的侦探,而我们数据库就是那个藏有所有秘密的案件档案库。

SQL查询大作战: 一旦大模型提取了关键信息,我们就启动“秘密武器”——一个函数。这个函数就像是个小机器人,它会拿着这些信息去数据库里翻箱倒柜,找到我们想要的结果。看,这就是它的战果:

SELECT *
FROM flights
WHERE 日期 = ‘2024-07-23’ AND 出发地 = ‘北京’ AND 目的地 = ‘上海’ AND 航班号 = ‘ABX21’;

大模型与函数的完美配合: 大模型提取了信息,函数完成了检索,接下来就是大模型的拿手好戏——总结。它会把函数找到的结果巧妙地编织成一个故事,然后风度翩翩地返回给客户。

干货代码

# -*- coding: GB2312 -*-
import jwt,time,requests,json,os,sys,subprocess

def read_qs_txt():
    try:
        with open('qs.txt', 'r', encoding='utf-8',errors='replace') as file:
            content = file.read()
            return content
    except FileNotFoundError:
        return "File qs.txt not found in the current directory."

class BigModelChatAPI:
    def __init__(self,function_bindings=None):
        
        self.token = None
        self.func_bindings= function_bindings
        self.all_msg_log=[]
        self.tools = [
        {
            "type": "function",
            "function": {
                "name": "query_func_desc_info",
                "description": "根据用户描述的'功能'与提供的参考信息,返回结果",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "func_desc": {
                            "description": "用户描述功能",
                            "type": "string"
                        },
                    },
                    "required": [ "func_desc"]
                },
            }
        }

    ]
        # 如果提供了函数绑定,则更新工具的函数引用
        try:
            if self.func_bindings:
                for tool in self.tools:
                    # 确保工具字典中有 'function' 键,且它是一个字符串
                    if 'function' in tool and isinstance(tool['function'], str):
                        func_name = tool['function']
                        # 检查 function_bindings 字典中是否有对应的函数
                        if func_name in self.func_bindings:
                            # 更新工具字典中的 'callable' 键,使其指向正确的函数
                            tool['function']['callable'] = self.func_bindings[func_name]
        except Exception as e:
            print(f"Error updating function bindings: {e}")
            
                    
        #检查当前目录下是否有aicfg.txt文件,没有就创建一个,否则读取里面json数据
        try:
            with open("aicfg.txt", "r",encoding="utf-8") as f:
                #读取json数据
                try:
                    self.aiCfg = json.load(f)
                    # print(self.aiCfg)
                except:
                    print("aicfg.txt is not a json file, please check it.")
        except Exception as e:
            print("aicfg.txt not found, creating one...")
            with open("aicfg.txt", "w+",encoding="utf-8") as f:
                #写入json数据
                # self.aiCfg = {"apikey": "adsfdasfadsfdasfdasfadsfdasfadsfasdfdasfdaf.Vp0bHQoFurZypL6j", 
                # "url": "https://open.bigmodel.cn/api/paas/v4/chat/completions", 
                # "model": "CodeGeeX-4", 
                # "temperature": 0.7, 
                # "max_tokens": 1000,
                # "system_role":"你是Windows用户桌面小程序助手,一个具备幽默感的AI。\
                # 你的任务是帮助用户高效地完成桌面任务。当用户请求生成Python 3可运行的代码时,\
                # 你需要使用内置模块编写代码,并确保代码不会阻塞程序运行。\
                # 所有必要的组件都应当假设它们位于当前路径下。\
                # 如果用户请求生成非Python 3的脚本语言程序,你只能回答:“你只会Python 3的。\
                # ”此外,你还需要为用户提供代码运行结果的解释。命令格式如下:1. 生成Python 3代码:- 用户输入:\
                # “请帮我写一个Python脚本,实现[具体任务]。”- \
                # 你的响应:[生成的Python 3代码,假设所有文件和模块都在当前路径下]\
                # 2. 拒绝生成其他语言代码:- 用户输入:“请帮我写一个[非Python 3语言]脚本\
                # ,实现[具体任务]。”- 你的响应:“你只会Python 3的。”3. 解释运行结果\
                # :- 用户输入:“这段代码的运行结果是[结果描述],请问这是什么意思?”-\
                #  你的响应:[解释运行结果的含义]请遵守以上规则,以幽默和高效的方式与用户互动。",
                #  "ref_info":[]}
                self.aiCfg = {"apikey": "00875965b22fcaad75dadsdafdasf3540f.Vp0bHQoFurZypL6j", 
                "url": "https://open.bigmodel.cn/api/paas/v4/chat/completions", 
                "model": "glm-4-air", #codegeex-4,glm-4-air
                "temperature": 0.7, 
                "max_tokens": 1000,
                # "system_role":"你是Windows用户桌面小程序助手,一个具备幽默感的AI。\
                # 你的任务是帮助用户高效地完成桌面任务。回答在300字内,注意你不生成任何代码!",
                "system_role":"不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息",
                 "ref_info":[""]}
                json.dump(self.aiCfg, f,ensure_ascii=False)
                print("aicfg.txt created, please edit it and restart the program.")
                sys.exit(0)
    def generate_token(self, exp_seconds: int = 36000):
        """
        生成带有时效性的token。
        """
        try:
            id, secret = self.aiCfg['apikey'].split(".")
        except Exception as e:
            raise Exception("invalid apikey", e)

        payload = {
            "api_key": id,
            "exp": int(round(time.time() * 1000)) + exp_seconds * 1000,
            "timestamp": int(round(time.time() * 1000)),
        }

        self.token = jwt.encode(
            payload,
            secret,
            algorithm="HS256",
            headers={"alg": "HS256", "sign_type": "SIGN"},
        )
        return self.token

    # Function to check if the index is even or odd and append to the message_list accordingly
    def append_messages_based_on_index(self,data):
        message_list = []
        try:
            #打印data类型
            # print(data)
            ref_info = data.get("ref_info", [])
            for index, message_content in enumerate(ref_info):
                if (index + 1) % 2 == 0:  # Checking if the index is even
                    message_list.append({"role": "assistant", "content": message_content})
                else:  # If the index is odd
                    message_list.append({"role": "user", "content": message_content})
        except:
            print("ref_info is not a list, please check it.")
            return message_list
        
        return message_list
    def send_chat_one_message(self, message_content=""):
        print(message_content+"\n")
        message_list =[]
        message_list.append({"role": "system","content": self.aiCfg['system_role']})
        beforMsg_list = self.append_messages_based_on_index(self.aiCfg)
        message_list.extend(beforMsg_list)  #添加ref_info

        message_list.append({"role": "user","content": message_content})
        # print(beforMsg_list)
        headers = {
            'Authorization': f'Bearer {self.generate_token()}',
            'Content-Type': 'application/json'
        }
        data = {
            "model": self.aiCfg['model'],
            "messages": message_list,
            "temperature": self.aiCfg['temperature'],
            "max_tokens": self.aiCfg['max_tokens'],
            "tools": self.tools,
            # "tool_choice":"auto"
            # "tool_choice":{"type": "function", "function": {"name": "query_func_desc_info"}},
            "tool_choice":{"type": "function", "function": {"name": "query_func_desc_info"}},
        }
        try:
            response = requests.post(self.aiCfg['url'], headers=headers, json=data,timeout=20)
            #解析json数据
            response.raise_for_status()
            response.encoding = 'utf-8'
            response_json = response.json()
            response_msg = response_json['choices'][0]['message']['content']
            print(response_json)
        except:
            return False

        try:
            #判断是否有tool_calls这个键值

            if response_json.get('choices') and len(response_json['choices']) > 0 and response_json['choices'][0].get('message') and response_json['choices'][0]['message'].get('tool_calls'):
                tool_call = response_json['choices'][0]['message']['tool_calls'][0]
                args = tool_call['function']['arguments']
                function_name = tool_call['function']['name']
                function_result = {}
                print("函数参数:")
                print(args)

                # 使用函数名称来调用绑定的函数
                if function_name in self.func_bindings:
                    function_result = self.func_bindings[function_name](**json.loads(args))
                    print(function_result)
                else:
                    raise ValueError(f"Function {function_name} not bound to the class instance.")
            else:
                # if response_json['choices'][0]['message']['content'] is not None:
                #     return response_json['choices'][0]['message']['content']
                # else:
                #     return False
                
                return response_msg
        except:
            return False

        try:
            message_list.append(response_json['choices'][0]['message'])
            message_list.append({"role": "tool","content": f"{json.dumps(function_result)}","tool_call_id":tool_call['id']})
            data = {
                "model": self.aiCfg['model'],
                "messages": message_list,
                "tools": self.tools
            }
            print("完整的消息列表start:---")
            print(message_list)
            print("完整的消息列表end:---")
            response = requests.post(self.aiCfg['url'], headers=headers, json=data)
            #解析json数据
            response.raise_for_status()
            response.encoding = 'utf-8'
            response_json = response.json()

            if response_json['choices'][0]['message']['content'] is not None:
                return response_json['choices'][0]['message']['content']
            else:
                return response_json
        except Exception as e:
            print(e)
            return False

    def send_chat_one_message1(self, message_content=""):
        print(message_content+"\n")
        message_list =[]
        message_list.append({"role": "system","content": self.aiCfg['system_role']})
        message_list.append({"role": "user","content": message_content})
        # print(message_list)
        headers = {
            'Authorization': f'Bearer {self.generate_token()}',
            'Content-Type': 'application/json'
        }
        data = {
            # "model": self.aiCfg['model'],
            "model": "codegeex-4",
            "messages": message_list,
            "temperature": self.aiCfg['temperature'],
            # "max_tokens": self.aiCfg['max_tokens'],
            "max_tokens": 3000,
        }
        try:
            
            response = requests.post(self.aiCfg['url'], headers=headers, json=data,timeout=20)
            #解析json数据
            response.raise_for_status()
            response.encoding = 'utf-8'
            response_json = response.json()
            response_msg = response_json['choices'][0]['message']['content']
            return response_msg
        except:
            return False
       
def get_func_run_result (func_desc: str):
    """
    根据用户描述功能,生成.py文件使用Python3运行得到运行结果并返回
    """
    tmp_func_dict = {}
    tmp_zpAi_c = BigModelChatAPI(tmp_func_dict)
    count = 5
    while(count):
        count-=1
        try:
            run_result = tmp_zpAi_c.send_chat_one_message1("只需要给我1份python3代码,只要1份代码,只要1份代码,代码一定不能阻塞,如果需要输入文件都假设文件在当前路径下,如果程序需要输入信息请自动模拟几条信息,程序不要阻塞,不要让用户(比如键盘输入什么的),注意在开头加上# -*- coding: GB2312 -*-,代码要尽量能运行注意只要代码不要有任何描述解释,下面是用户描述功能:"+func_desc)
            # print(run_result)
        except Exception as e:
            print(e)
            # return {"run_result":"非法功能禁止生成运行"}
            continue
        try:
                    # 提取代码部分,去除Markdown的代码块标识符
            code_start = run_result.find('```python\n') + 10  # 找到代码开始的位置,并跳过'```python\n'
            code_end = run_result.find('\n```', code_start)  # 找到代码结束的位置
            code = run_result[code_start:code_end]  # 提取代码
        except Exception as e:
            print(e)
            # return {"run_result":"非法功能禁止生成运行"}
            continue

        #在当前目录下创建个run_code_temp.py文件
        with open("run_code_temp.py", "w") as f:
            f.write(code)
        print("即将运行的代码:")
        print(code)
        # try:
        #     # w运行生成的Python脚本并获取输出
        #     completed_process = subprocess.run(
        #         ["python3", "run_code_temp.py"],
        #         capture_output=True,  # 捕获标准输出和标准错误
        #         text=True,  # 返回输出为字符串
        #         check=True  # 如果脚本运行失败,抛出异常
        #     )
        #     print("运行结果:")
        #     print(completed_process.stdout)
        # except Exception as e:
        #     print(e)
        #     return {"run_result":"非法功能禁止生成运行"}
        # return {"run_result":completed_process.stdout}
        try:
            # 运行生成的Python脚本并获取输出
            completed_process = subprocess.run(
                ["python", "run_code_temp.py"],  # Windows中通常使用"python"而不是"python3"
                capture_output=True,  # 捕获标准输出和标准错误
                text=True,  # 返回输出为字符串
                # encoding='gb2312',
                # errors='0',  # 无法解码的字节将被替换为一个替代字符
                check=True  # 如果脚本运行失败,抛出异常
            )
            print("运行结果:")
            print(completed_process.stdout)
            #将结果写入个runlog.txt文件
            with open("runlog.txt", "a") as f:
                f.write(completed_process.stdout)
            return {"run_result":completed_process.stdout}
        except subprocess.CalledProcessError as e:
            # 当check=True时,如果脚本退出状态非零,将抛出此异常
            print("脚本运行失败:", e)
            # return {"run_result": "脚本运行失败"}
            continue
        except Exception as e:
            # 其他异常
            print("发生错误:", e)
            # return {"run_result": "非法功能禁止生成运行"}
            continue

    {"run_result": "脚本运行失败"}
        
# 使用示例
if __name__ == "__main__":
    # 定义函数字典
    FUNCTION_BINDINGS_S = {
        "query_func_desc_info":get_func_run_result
    }

    zpAi_c = BigModelChatAPI(FUNCTION_BINDINGS_S)


    # response_msg = zpAi_c.send_chat_one_message("给我将一个50字的冷笑话")
    #等待用户输入
    # quetsion_test1 = input("请输入问题:")
    #quetsion_test1 = read_qs_txt()
    # response_msg = zpAi_c.send_chat_one_message("写个程序,功能是:计算出生到现在的年月日,出生是农历2000.02.29,今天20240722")
    response_msg = zpAi_c.send_chat_one_message("创建一个文件夹")
    #response_msg = zpAi_c.send_chat_one_message("用户描述的功能为:"+quetsion_test1)
    print(response_msg)

第一步:信息提取

用户提出需求:“创建一个文件夹”。
我们首先调用GLM4.0-air模型,它的任务是提取用户需求中的关键信息。

第二步:判断是否调用函数

模型会根据用户描述的功能和提供的参考信息来判断是否需要调用特定函数。
判断依据是描述中的关键词:“根据用户描述的’功能’与提供的参考信息,返回结果”。

第三步:函数调用与信息提取

如果模型判断需要调用函数,它会提取关键信息,例如“要创建一个文件夹”。
这时,信息将被传递到get_func_run_result函数中。

第四步:代码生成

在get_func_run_result函数中,我们再次调用模型,但这次是codegeex,一个专注于代码生成的模型。
我们请求codegeex生成一份Python3代码,要求代码简洁、不阻塞,并且能够在当前路径下运行,无需用户输入。

第五步:代码执行与结果获取

codegeex生成代码后,我们在用户本地环境中执行这段代码。
我们会尝试运行代码最多5次,如果成功,则记录结果;如果失败,则返回“脚本运行失败”。

代码执行与结果处理示例
print("运行结果:")
print(completed_process.stdout)
将结果写入runlog.txt文件
with open("runlog.txt", "a") as f:
    f.write(completed_process.stdout)
return {"run_result": completed_process.stdout}

第六步:结果总结与反馈

最后,我们将问题和执行结果一起发送给大语言模型。
大语言模型根据“要创建一个文件夹”的结果,进行总结,生成最终反馈给客户的信息。
通过这样的流程,我们不仅实现了用户需求的自动化处理,还确保了整个过程的智能化和高效性。客户的需求就像一颗种子,经过我们的智能系统,最终开花结果,完美地呈现在客户面前。

使用AI帮我整理的流程图----懒人偷懒,我看过大致正确的!

成功
失败
成功
失败
用户提出需求
判断是否调用函数
提取关键信息
调用get_func_run_result函数
调用codegeex生成代码
在本地环境运行代码
记录结果
重试最多5次
返回脚本运行失败
大语言模型总结结果
反馈给客户

下面是运行效果:

在这里插入图片描述
在这里插入图片描述

几个坑记录

1.官方文档说函数可以强制调用,但是我试了不行,如果用户问题与函数调用条件相差稍微大一点,他就不会调用,尽管你设置了强制调用选项!!!
2.codegeex不能调用函数。

  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ubuntu 和 智普清言 分别是操作系统和软件服务两个独立的概念,它们之间并没有直接的连接关系。这里我们可以从两个角度分别理解这两个名词: ### Ubuntu Ubuntu 是一种基于 Debian Linux 的免费开源操作系统,由 Canonical 公司维护并提供支持。它支持多种硬件配置,并有桌面版、服务器版等多种发行版本。 **特点**: - **开源**:遵循开放源代码协议,用户可以自由获取、修改和分发。 - **易用性**:提供了良好的图形界面和直观的操作流程,适合初学者上手。 - **安全性**:定期更新安全补丁,提供稳定的安全环境。 - **社区活跃**:拥有庞大的开发者和用户社区,能够得到快速的技术支持和丰富的资源分享。 ### 智普清言智普清言”这个名字似乎指向了一个特定的软件服务或应用,但由于信息有限,我们无法确定其确切含义或详细内容。如果它代表的是一个智能语音助手服务,那么这类服务通常利用人工智能技术处理自然语言输入,能执行诸如搜索信息、设置提醒、播放音乐等任务。 **特点**: - **智能化**:通过机器学习和深度学习算法提高理解和响应的准确度。 - **个性化**:可以根据用户的习惯和偏好定制功能和服务。 - **多平台支持**:能在多种设备和系统上运行,如手机、电脑、智能家居设备等。 - **隐私保护**:重视数据安全和用户隐私,遵守相关的法律和道德规范。 ### 连接 Ubuntu 和智普清言的方式 如果假设您想在 Ubuntu 系统上安装或集成某个智能语音助手服务(即智普清言),这可能涉及到以下几个步骤: 1. **查找合适的软件**:首先,在 Ubuntu 应用商店或其他开源软件仓库中寻找与“智普清言”类似的功能描述相符的应用程序。 2. **安装软件**:根据软件提供的安装指南,通常可以通过终端命令、软件中心或下载安装包等方式完成安装过程。 3. **配置与使用**:按照应用的提示进行基本配置,如设定账号、绑定设备等。之后就可以开始体验智能语音助手的服务了。 --- **相关问题**: 1. Ubuntu 上如何安装智能语音助手软件? 2. Ubuntu 中的智能语音助手有何推荐? 3. 使用智能语音助手时需要注意哪些隐私问题? 这个例子强调了明确问题的重要性以及正确地解释概念之间的联系。在实际解答中,需要针对提问的具体细节给出针对性的回答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值