mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-28 00:14:21 +00:00
Merge pull request #533 from RockChinQ/perf-function-call-process
[Perf] 优化函数调用的底层逻辑
This commit is contained in:
@@ -239,6 +239,11 @@ image_api_params = {
|
|||||||
"size": "256x256", # 图片尺寸,支持256x256, 512x512, 1024x1024
|
"size": "256x256", # 图片尺寸,支持256x256, 512x512, 1024x1024
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 跟踪函数调用
|
||||||
|
# 为True时,在每次GPT进行Function Calling时都会输出发送一条回复给用户
|
||||||
|
# 同时,一次提问内所有的Function Calling和普通回复消息都会单独发送给用户
|
||||||
|
trace_function_calls = False
|
||||||
|
|
||||||
# 群内回复消息时是否引用原消息
|
# 群内回复消息时是否引用原消息
|
||||||
quote_origin = True
|
quote_origin = True
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@
|
|||||||
"image_api_params": {
|
"image_api_params": {
|
||||||
"size": "256x256"
|
"size": "256x256"
|
||||||
},
|
},
|
||||||
|
"trace_function_calls": false,
|
||||||
"quote_origin": true,
|
"quote_origin": true,
|
||||||
"at_sender": false,
|
"at_sender": false,
|
||||||
"include_image_description": true,
|
"include_image_description": true,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class ChatCompletionRequest(RequestBase):
|
|||||||
)
|
)
|
||||||
self.pending_msg = ""
|
self.pending_msg = ""
|
||||||
|
|
||||||
def append_message(self, role: str, content: str, name: str=None):
|
def append_message(self, role: str, content: str, name: str=None, function_call: dict=None):
|
||||||
msg = {
|
msg = {
|
||||||
"role": role,
|
"role": role,
|
||||||
"content": content
|
"content": content
|
||||||
@@ -39,6 +39,9 @@ class ChatCompletionRequest(RequestBase):
|
|||||||
if name is not None:
|
if name is not None:
|
||||||
msg['name'] = name
|
msg['name'] = name
|
||||||
|
|
||||||
|
if function_call is not None:
|
||||||
|
msg['function_call'] = function_call
|
||||||
|
|
||||||
self.messages.append(msg)
|
self.messages.append(msg)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -87,16 +90,17 @@ class ChatCompletionRequest(RequestBase):
|
|||||||
choice0 = resp["choices"][0]
|
choice0 = resp["choices"][0]
|
||||||
|
|
||||||
# 如果不是函数调用,且finish_reason为stop,则停止迭代
|
# 如果不是函数调用,且finish_reason为stop,则停止迭代
|
||||||
if 'function_call' not in choice0['message']: # and choice0["finish_reason"] == "stop"
|
if choice0['finish_reason'] == 'stop': # and choice0["finish_reason"] == "stop"
|
||||||
self.stopped = True
|
self.stopped = True
|
||||||
|
|
||||||
if 'function_call' in choice0['message']:
|
if 'function_call' in choice0['message']:
|
||||||
self.pending_func_call = choice0['message']['function_call']
|
self.pending_func_call = choice0['message']['function_call']
|
||||||
|
|
||||||
# self.append_message(
|
self.append_message(
|
||||||
# role="assistant",
|
role="assistant",
|
||||||
# content="function call: "+json.dumps(self.pending_func_call, ensure_ascii=False)
|
content=choice0['message']['content'],
|
||||||
# )
|
function_call=choice0['message']['function_call']
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"id": resp["id"],
|
"id": resp["id"],
|
||||||
@@ -106,7 +110,7 @@ class ChatCompletionRequest(RequestBase):
|
|||||||
"message": {
|
"message": {
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"type": "function_call",
|
"type": "function_call",
|
||||||
"content": None,
|
"content": choice0['message']['content'],
|
||||||
"function_call": choice0['message']['function_call']
|
"function_call": choice0['message']['function_call']
|
||||||
},
|
},
|
||||||
"finish_reason": "function_call"
|
"finish_reason": "function_call"
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ def count_completion_tokens(messages: list, model: str) -> int:
|
|||||||
|
|
||||||
|
|
||||||
def count_tokens(messages: list, model: str):
|
def count_tokens(messages: list, model: str):
|
||||||
|
|
||||||
if model in CHAT_COMPLETION_MODELS:
|
if model in CHAT_COMPLETION_MODELS:
|
||||||
return count_chat_completion_tokens(messages, model)
|
return count_chat_completion_tokens(messages, model)
|
||||||
elif model in COMPLETION_MODELS:
|
elif model in COMPLETION_MODELS:
|
||||||
|
|||||||
+40
-10
@@ -194,7 +194,7 @@ class Session:
|
|||||||
|
|
||||||
# 请求回复
|
# 请求回复
|
||||||
# 这个函数是阻塞的
|
# 这个函数是阻塞的
|
||||||
def append(self, text: str=None) -> tuple[str, str, list[str]]:
|
def query(self, text: str=None) -> tuple[str, str, list[str]]:
|
||||||
"""向session中添加一条消息,返回接口回复
|
"""向session中添加一条消息,返回接口回复
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -255,29 +255,59 @@ class Session:
|
|||||||
|
|
||||||
funcs = []
|
funcs = []
|
||||||
|
|
||||||
|
trace_func_calls = config.trace_function_calls
|
||||||
|
botmgr = pkg.utils.context.get_qqbot_manager()
|
||||||
|
|
||||||
|
session_name_spt: list[str] = self.name.split("_")
|
||||||
|
|
||||||
|
pending_res_text = ""
|
||||||
|
|
||||||
|
# TODO 对不起,我知道这样非常非常屎山,但我之后会重构的
|
||||||
for resp in pkg.utils.context.get_openai_manager().request_completion(prompts):
|
for resp in pkg.utils.context.get_openai_manager().request_completion(prompts):
|
||||||
|
|
||||||
|
if pending_res_text != "":
|
||||||
|
botmgr.adapter.send_message(
|
||||||
|
session_name_spt[0],
|
||||||
|
session_name_spt[1],
|
||||||
|
pending_res_text
|
||||||
|
)
|
||||||
|
pending_res_text = ""
|
||||||
|
|
||||||
finish_reason = resp['choices'][0]['finish_reason']
|
finish_reason = resp['choices'][0]['finish_reason']
|
||||||
|
|
||||||
if resp['choices'][0]['message']['type'] == 'text': # 普通回复
|
if resp['choices'][0]['message']['role'] == "assistant" and resp['choices'][0]['message']['content'] != None: # 包含纯文本响应
|
||||||
res_text += resp['choices'][0]['message']['content']
|
|
||||||
|
if not trace_func_calls:
|
||||||
|
res_text += resp['choices'][0]['message']['content'] + "\n"
|
||||||
|
else:
|
||||||
|
res_text = resp['choices'][0]['message']['content']
|
||||||
|
pending_res_text = resp['choices'][0]['message']['content']
|
||||||
|
|
||||||
total_tokens += resp['usage']['total_tokens']
|
total_tokens += resp['usage']['total_tokens']
|
||||||
|
|
||||||
pending_msgs.append(
|
msg = {
|
||||||
{
|
"role": "assistant",
|
||||||
"role": "assistant",
|
"content": resp['choices'][0]['message']['content']
|
||||||
"content": resp['choices'][0]['message']['content']
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
elif resp['choices'][0]['message']['type'] == 'function_call':
|
if 'function_call' in resp['choices'][0]['message']:
|
||||||
|
msg['function_call'] = json.dumps(resp['choices'][0]['message']['function_call'])
|
||||||
|
|
||||||
|
pending_msgs.append(msg)
|
||||||
|
|
||||||
|
if resp['choices'][0]['message']['type'] == 'function_call':
|
||||||
# self.prompt.append(
|
# self.prompt.append(
|
||||||
# {
|
# {
|
||||||
# "role": "assistant",
|
# "role": "assistant",
|
||||||
# "content": "function call: "+json.dumps(resp['choices'][0]['message']['function_call'])
|
# "content": "function call: "+json.dumps(resp['choices'][0]['message']['function_call'])
|
||||||
# }
|
# }
|
||||||
# )
|
# )
|
||||||
|
if trace_func_calls:
|
||||||
|
botmgr.adapter.send_message(
|
||||||
|
session_name_spt[0],
|
||||||
|
session_name_spt[1],
|
||||||
|
"调用函数 "+resp['choices'][0]['message']['function_call']['name'] + "..."
|
||||||
|
)
|
||||||
|
|
||||||
total_tokens += resp['usage']['total_tokens']
|
total_tokens += resp['usage']['total_tokens']
|
||||||
elif resp['choices'][0]['message']['type'] == 'function_return':
|
elif resp['choices'][0]['message']['type'] == 'function_return':
|
||||||
|
|||||||
@@ -327,6 +327,10 @@ def apply_privileges():
|
|||||||
for path, priv in data.items():
|
for path, priv in data.items():
|
||||||
if path == 'comment':
|
if path == 'comment':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if path not in __command_list__:
|
||||||
|
continue
|
||||||
|
|
||||||
if __command_list__[path]['privilege'] != priv:
|
if __command_list__[path]['privilege'] != priv:
|
||||||
logging.debug('应用权限: {} -> {}(default: {})'.format(path, priv, __command_list__[path]['privilege']))
|
logging.debug('应用权限: {} -> {}(default: {})'.format(path, priv, __command_list__[path]['privilege']))
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
from ..aamgr import AbstractCommandNode, Context
|
|
||||||
|
|
||||||
|
|
||||||
@AbstractCommandNode.register(
|
|
||||||
parent=None,
|
|
||||||
name="continue",
|
|
||||||
description="继续未完成的响应",
|
|
||||||
usage="!continue",
|
|
||||||
aliases=[],
|
|
||||||
privilege=1
|
|
||||||
)
|
|
||||||
class ContinueCommand(AbstractCommandNode):
|
|
||||||
@classmethod
|
|
||||||
def process(cls, ctx: Context) -> tuple[bool, list]:
|
|
||||||
import pkg.openai.session
|
|
||||||
import config
|
|
||||||
session_name = ctx.session_name
|
|
||||||
|
|
||||||
reply = []
|
|
||||||
|
|
||||||
session = pkg.openai.session.get_session(session_name)
|
|
||||||
|
|
||||||
text, _, _ = session.append()
|
|
||||||
|
|
||||||
reply = [text]
|
|
||||||
|
|
||||||
return True, reply
|
|
||||||
@@ -40,7 +40,7 @@ def process_normal_message(text_message: str, mgr, config, launcher_type: str,
|
|||||||
try:
|
try:
|
||||||
prefix = "[GPT]" if config.show_prefix else ""
|
prefix = "[GPT]" if config.show_prefix else ""
|
||||||
|
|
||||||
text, finish_reason, funcs = session.append(text_message)
|
text, finish_reason, funcs = session.query(text_message)
|
||||||
|
|
||||||
# 触发插件事件
|
# 触发插件事件
|
||||||
args = {
|
args = {
|
||||||
@@ -68,7 +68,7 @@ def process_normal_message(text_message: str, mgr, config, launcher_type: str,
|
|||||||
except openai.error.APIConnectionError as e:
|
except openai.error.APIConnectionError as e:
|
||||||
err_msg = str(e)
|
err_msg = str(e)
|
||||||
if err_msg.__contains__('Error communicating with OpenAI'):
|
if err_msg.__contains__('Error communicating with OpenAI'):
|
||||||
reply = handle_exception("{}会话调用API失败:{}\n请尝试关闭网络代理来解决此问题。".format(session_name, e),
|
reply = handle_exception("{}会话调用API失败:{}\n您的网络无法访问OpenAI接口或网络代理不正常".format(session_name, e),
|
||||||
"[bot]err:调用API失败,请重试或联系管理员,或等待修复")
|
"[bot]err:调用API失败,请重试或联系管理员,或等待修复")
|
||||||
else:
|
else:
|
||||||
reply = handle_exception("{}会话调用API失败:{}".format(session_name, e), "[bot]err:调用API失败,请重试或联系管理员,或等待修复")
|
reply = handle_exception("{}会话调用API失败:{}".format(session_name, e), "[bot]err:调用API失败,请重试或联系管理员,或等待修复")
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"plugin.del": 2,
|
"plugin.del": 2,
|
||||||
"plugin.off": 2,
|
"plugin.off": 2,
|
||||||
"plugin.on": 2,
|
"plugin.on": 2,
|
||||||
"continue": 1,
|
|
||||||
"default": 1,
|
"default": 1,
|
||||||
"default.set": 2,
|
"default.set": 2,
|
||||||
"del": 1,
|
"del": 1,
|
||||||
|
|||||||
@@ -180,7 +180,6 @@
|
|||||||
!draw <提示语> 进行绘图
|
!draw <提示语> 进行绘图
|
||||||
!version 查看当前版本并检查更新
|
!version 查看当前版本并检查更新
|
||||||
!resend 重新回复上一个问题
|
!resend 重新回复上一个问题
|
||||||
!continue 继续响应未完成的回合(通常用于内容函数继续调用)
|
|
||||||
!plugin 用法请查看插件使用页的`管理`章节
|
!plugin 用法请查看插件使用页的`管理`章节
|
||||||
!default 查看可用的情景预设值
|
!default 查看可用的情景预设值
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user