yejue / nonebot-plugin-with-ai-agents

AI Agents 插件,仅使用基本原理实现联网能力、页面提取能力、百科搜索能力。(支持ChatGPT、ChatGLM、通义千问、百川、Llama3 等模型)
MIT License
31 stars 1 forks source link

访问api返回”Role must be user or assistant and Content length must be greater than 0“ #11

Open ChenXu233 opened 2 weeks ago

ChenXu233 commented 2 weeks ago

问题

经过一段时间的聊天,Bot 开始回复消息”有错误,自己看日志,可能过期了“。 观察日志发现:

插件版本

0.1.14

Nonebot版本

2.3.0

python 版本

3.12.3

复现过程

只要启动 Bot ,聊一段时间就会出现这样的问题。

日志上下文:

截图

image

文字

06-16 17:52:10 [SUCCESS] nonebot | OneBot V11 278133507 | [message.group.normal]: Message -2147483089 from 1964324406@[ 群:795946478] '[at:qq=278133507] 你好' 06-16 17:52:10 [DEBUG] nonebot | Checking for matchers in priority 1... 06-16 17:52:10 [DEBUG] nonebot | Checking for matchers in priority 11... 06-16 17:52:10 [DEBUG] nonebot | Checking for matchers in priority 12... 06-16 17:52:11 [DEBUG] nonebot | Checking for matchers in priority 13... 06-16 17:52:11 [DEBUG] nonebot | Checking for matchers in priority 999... 06-16 17:52:11 [INFO] nonebot | Event will be handled by Matcher(type='message', module=nonebot_plugin_with_ai_agents.handler, lineno=9) 06-16 17:52:11 [DEBUG] nonebot | Running Matcher(type='message', module=nonebot_plugin_with_ai_agents.handler, lineno=9) 06-16 17:52:11 [DEBUG] nonebot | Running handler Dependent(call=agent_handler) 06-16 17:52:12 [INFO] nonebot_plugin_with_ai_agents | 智脑分类结果:[6] 06-16 17:52:12 [INFO] nonebot_plugin_with_ai_agents | assemble_prompt 06-16 17:52:13 [CRITICAL] nonebot_plugin_with_ai_agents | {"code":"InvalidParameter","message":"Role must be user or assistant and Content length must be greater than 0","request_id":"eb5256d2-08c3-9b7e-8361-09796f4d3f32"}'output' 06-16 17:52:13 [DEBUG] nonebot | OneBot V11 | Calling API send_msg 06-16 17:52:13 [INFO] nonebot | Matcher(type='message', module=nonebot_plugin_with_ai_agents.handler, lineno=9) running complete 06-16 17:52:13 [DEBUG] nonebot | Stop event propagation 06-16 17:52:13 [DEBUG] nonebot | Checking for matchers completed

排查

已确定不是由网络问题引发的

https://github.com/yejue/nonebot-plugin-with-ai-agents/blob/1c1b96d76d115f90b06b40e1697b2c5b8517cdef/llm/llms/dashscope.py#L60-L70 通过观察源码发现这个错误是直接通过错误基类被捕获的,然后以 str 的形式与 r.text 拼接,在这里这个异常的str是'output',然后 bot 回复 ”有错误,自己看日志,可能过期了“。这是不是有点太草率了。

把 body 的内容打印出来以后,发现 role 的内容也是正常的。

ChenXu233 commented 2 weeks ago

深入阅读代码后我还有个疑问:

https://github.com/yejue/nonebot-plugin-with-ai-agents/blob/1c1b96d76d115f90b06b40e1697b2c5b8517cdef/llm/llms/dashscope.py#L60-L70

https://github.com/yejue/nonebot-plugin-with-ai-agents/blob/1c1b96d76d115f90b06b40e1697b2c5b8517cdef/llm/llms/glm.py#L52-L62

这俩段代码相似度很高,可以考虑一下整一个函数出来进行代码复用? 比如可以这样写

async def api_request(url, headers, body, timeout):
    async with httpx.AsyncClient() as client: 
        try: 
            result = await client.post(url, headers=headers, json=body, timeout=timeout) 
        except httpx.ReadTimeout as e: 
            logger.critical(f"访问大模型超时, {e}")
            result = None
        except Exception as e: 
            logger.critical(r.text + str(e)) 
            raise e
    return result

class GLMModel(BaseLLMModel):
    ...
    async def ask_model(
            self,
            question: str,
            system_prompt: str = None,
            message_history: list = (),
            temperature: float = 0.01
    ):
        """向 ChatGLM 提问
         - question:用户问题
         - system_prompt:系统级提示词
         - message_history: 消息历史列表
        """
        url = self.get_api_url()
        headers = self.get_headers()
        body = self.get_body_template(temperature)

        if message_history:
            body["messages"] = message_history

        if system_prompt:
            sys_msg = {"role": "system", "content": system_prompt}
            body["messages"].insert(0, sys_msg)

        user_message = {"role": "user", "content": question}
        body["messages"].append(user_message)

        if result := api_request(url, headers, body, self.timeout):
            #这下面可以依据不同的更改不同的逻辑
            ans = result.json()["choices"][0]["message"]["content"]
        return ans

没有代码复用,这里出现了一个奇怪的try: https://github.com/yejue/nonebot-plugin-with-ai-agents/blob/1c1b96d76d115f90b06b40e1697b2c5b8517cdef/llm/llms/openai.py#L54-L65 把访问大模型放在代码放在 try 外面,可能不是你的本意

ChenXu233 commented 2 weeks ago

想给你发一个 pr 了(跃跃欲试

yejue commented 2 weeks ago
  1. 关于这个问题本身,有可能是历史聊天记录自动拾取的时候和新记录添加的时候出现的一些问题,目前还没细看
  2. 关于代码复用,在此前的版本中,各个平台的代码是直接复制的,因为早期无法预测不同平台间的兼容性,故初始版本不做太多的复用,留存空间
  3. try except httpx.ReadTimeout as e: 原本是要 try 访问大模型的,忘了什么原因又移出去了,try 的内容没有更改;
  4. 至于 "有错误,自己看日志,可能过期了" 也是初始版本中无法预想所有的错误,需要一个全局的 try 来保证全局不会被打断
yejue commented 2 weeks ago
  1. 关于这个问题本身,有可能是历史聊天记录自动拾取的时候和新记录添加的时候出现的一些问题,目前还没细看
  2. 关于代码复用,在此前的版本中,各个平台的代码是直接复制的,因为早期无法预测不同平台间的兼容性,故初始版本不做太多的复用,留存空间
  3. try except httpx.ReadTimeout as e: 原本是要 try 访问大模型的,忘了什么原因又移出去了,try 的内容没有更改;
  4. 至于 "有错误,自己看日志,可能过期了" 也是初始版本中无法预想所有的错误,需要一个全局的 try 来保证全局不会被打断

其实说白了就是有许多问题都是临时解决方案,从这个插件发布第一版的时候就有了,细节的东西比较多需要考虑的,一口气写不过来。所以有些东西会尽量写的简单,为以后的修改留有余地。

ChenXu233 commented 2 weeks ago
  1. 关于这个问题本身,有可能是历史聊天记录自动拾取的时候和新记录添加的时候出现的一些问题,目前还没细看
  2. 关于代码复用,在此前的版本中,各个平台的代码是直接复制的,因为早期无法预测不同平台间的兼容性,故初始版本不做太多的复用,留存空间
  3. try except httpx.ReadTimeout as e: 原本是要 try 访问大模型的,忘了什么原因又移出去了,try 的内容没有更改;
  4. 至于 "有错误,自己看日志,可能过期了" 也是初始版本中无法预想所有的错误,需要一个全局的 try 来保证全局不会被打断

但是还是觉得直接回复“有错误,自己看日志,可能过期了“有些不太妥,用 Bot 的不止 Bot 的主人,非开发者看见了可能一脸懵。其实只要说明出错了可以了,比如说明”出现错误,请稍后在试或者联系 Bot 主人。“,希望后面能改改,自定义一下。

yejue commented 2 weeks ago

这里的问题已经有部分得到解决,详见 0.1.15;标题中的主要的问题待解决