智普清言开放平台函数
记得去年2023GPT刚发布我就到处找较便宜的API,但当时大多是国外的虽然有代理的但是稍微贵了点(相对与我).终于现在模型市场卷起来了,国产的==GLM4也还是不错。记录下自己使用过程:
有了API就可以将大语言模型集成到很多地方。
先来个图,这个是我下面举的例子,图是AI画的
函数作用—个人理解
大语言模型怎么使用应该都知道------给模型输入信息------模型返回结果。
但是有个问题,如果你做应用,想利用大模型理解别人说的话,提取到必要信息怎么做?
有个人要通过大模型查询北京到上海的航班信息。
他这样问的:查询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帮我整理的流程图----懒人偷懒,我看过大致正确的!
下面是运行效果:
几个坑记录
1.官方文档说函数可以强制调用,但是我试了不行,如果用户问题与函数调用条件相差稍微大一点,他就不会调用,尽管你设置了强制调用选项!!!
2.codegeex不能调用函数。