microsoft / TaskWeaver

A code-first agent framework for seamlessly planning and executing data analytics tasks.
https://microsoft.github.io/TaskWeaver/
MIT License
5.38k stars 689 forks source link

Unknown recipient exception #307

Open fywang2 opened 7 months ago

fywang2 commented 7 months ago

1、Docker host operating system:ubuntun 22.04 desktop

2、Run TaskWeaver using the All-in-One Docker Image:

sudo docker run -it \
--name taskweaver \
--privileged \
--net=host \
-e "LLM_API_KEY=sk-0f67XXXX"  \
-e "LLM_API_TYPE=qwen"  \
-e "LLM_MODEL=qwen-max"  \
-e "TASKWEAVER_UID=0"  \
-e "TASKWEAVER_GID=0"  \
-p 8000:8000 \
-v /data/workspace/vscode/vscodeProjects/taskWeaverFromContaner/project:/app/project \
--entrypoint /app/entrypoint_chainlit.sh \
taskweavercontainers/taskweaver-all-in-one:latest

3、plugin file: sql_pull_mysql_data.py

import pandas as pd

from taskweaver.plugin import Plugin, register_plugin

import pymysql

@register_plugin
class SqlPullMysqlData(Plugin):
#class SqlPullMysqlData():
    def __call__(self, query: str):
        query = "查询产业工人项目列表"
        #sql = "select * from opi_project"
        sql = "select id as 编码,project_name as 项目名称,area as 项目所在地区, eng_status as 项目状态 from opi_project"
        result = query_data(sql)
        print(result)

        df = pd.DataFrame(result)
        print(df)

        if len(df) == 0:
            return df, (
                f"我在 `{query}` 基础上生成SQL.\n所生成SQL语句为 {sql}.\n" f"返回结果为空的."
            )
        else:
            return df, (
                f"我在 `{query}`基础上生成SQL.\n所生成SQL语句为 {sql}.\n"
                f"返回结果有 {len(df)} 行.\n"
                f"返回结果的前 {min(5, len(df))} 行记录:\n{df.head(min(5, len(df))).to_markdown()}"
            )

"""
常用模块:读写MySQL
"""
def get_conn(): 
  omit some codes

def query_data(sql):
  omit some codes

4、plugin file: sql_pull_mysql_data.yaml

name: sql_pull_mysql_data
code: sql_pull_mysql_data
enabled: true
required: true
description: >-
  获取产业工人项目数据。
  当向用户的答复涉及本插件时,请以中文答复。
  不需要把用户输入的自然语言转换为数据库SQL。
  以Markdown表格形式展示给用户。
  (omit some descriptions)

examples: |-
  df, description = sql_pull_mysql_data("从数据库查询产业工人项目列表")

parameters:
  - name: query
    type: str
    required: true
    description: >-
      直接把query传入数据库处理,不需要数据库名称、查询条件。

returns:
  - name: df
    type: pandas.DataFrame
    description: This is the dataframe containing the data from the database.从数据库返回的产业工人项目结果数据。
  - name: description
    type: str
    description: This is a string describing the data pulled from the database.对从数据库返回的产业工人项目数据的描述。

5、Installing pymysql in the Docker container

docker exec -it taskweaver /bin/bash
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip config list
pip install pymysql

6、When asking “显示产业工人项目”,Taskweaver execute the plugin sql_pull_mysql_data, then the backend execption logs:

2024-04-16 15:08:06 - LLM output: {"response": [{"type": "init_plan", "content": "1. 使用sql_pull_mysql_data插件获取产业工人项目数据"}, {"type": "plan", "content": "1. 使用sql_pull_mysql_data插件获取产业工人项目数据"}, {"type": "current_plan_step", "content": "1. 使用sql_pull_mysql_data插件获取产业工人项目数据"}, {"type": "send_to", "content": "sql_pull_mysql_data"}, {"type": "message", "content": "请使用插件功能获取产业工人项目数据"}], "execute_code": true}
2024-04-16 15:08:06 - Planner talk to sql_pull_mysql_data: 请使用插件功能获取产业工人项目数据
2024-04-16 15:08:06 - Traceback (most recent call last):
  File "/app/playground/UI/../../taskweaver/session/session.py", line 194, in _send_text_message
    post = _send_message(post.send_to, post)
  File "/app/playground/UI/../../taskweaver/module/tracing.py", line 174, in wrapper
    return func(*args, **kwargs)
  File "/app/playground/UI/../../taskweaver/session/session.py", line 182, in _send_message
    raise Exception(f"Unknown recipient {recipient}")
Exception: Unknown recipient sql_pull_mysql_data

image

zellelin commented 7 months ago

you can use plugin test to verify code exection

liqul commented 7 months ago

From the error message, I can see that the response of LLM has the send_to field assigned a wrong value which is the plugin name. In fact, it should be a role name such as User or CodeInterpreter. I suggest you start a new session and retry or test a different model to see if this is constant. These issues are typically caused due to the capability of the model used.

fywang2 commented 7 months ago

THANKS FOR YOUR APPLY!

1、Response to "start a new session and retry or test a different model to see if this is constant.": I remove the TaskWeaver docker container , then run a new TaskWeaver container based on LLM qwen-max, open a new Chrome browser, it has the same result "Exception: Unknown recipient sql_pull_mysql_data" as the same above.

2、Respose to " These issues are typically caused due to the capability of the model used.": 2.1、I switch LLM to zhipuai, the first time I ask TaskWeaver, it calls the plugin sql_pull_mysql_data to get data from mysql. It happens 'ModuleNotFoundError: No module named 'tabulate''.

sudo docker run -it \ --name taskweaver \ --privileged \ --net=host \ -e "LLM_API_KEY=4089d115fXXXX" \ -e "LLM_API_TYPE=zhipuai" \ -e "LLM_MODEL=glm-4" \ -e "LLM.EMBEDDING_MODEL=embedding-2" \ -e "LLM.EMBEDDING_API_TYPE=zhipuai" \ -e "TASKWEAVER_UID=0" \ -e "TASKWEAVER_GID=0" \ -p 8000:8000 \ -v /etc/localtime:/etc/localtime:ro \ -v /data/workspace/vscode/vscodeProjects/taskWeaverFromContaner/project:/app/project \ --entrypoint /app/entrypoint_chainlit.sh \ taskweavercontainers/taskweaver-all-in-one:latest

2024-04-17 21:46:39 - HTTP Request: POST https://open.bigmodel.cn/api/paas/v4/chat/completions "HTTP/1.1 200 " 2024-04-17 21:46:39 - LLM output: sq 2024-04-17 21:46:39 - Failed to parse LLM output stream due to JSONError: failed to parse root: s State: [('root', (True, False))] Prefix: [] 2024-04-17 21:46:39 - Failed to parse LLM output due to Missing elements: send_to, message, init_plan, plan, current_plan_step in the response element 2024-04-17 21:46:39 - Planner talk to Planner: Failed to parse LLM output due to Missing elements: send_to, message, init_plan, plan, current_plan_step in the response element 2024-04-17 21:46:42 - HTTP Request: POST https://open.bigmodel.cn/api/paas/v4/chat/completions "HTTP/1.1 200 " 2024-04-17 21:46:50 - LLM output: {"response": [{"type": "init_plan", "content": "1. Display the industrial worker projects"}, {"type": "plan", "content": "1. Use the sql_pull_mysql_data plugin to display the industrial worker projects"}, {"type": "current_plan_step", "content": "1. Use the sql_pull_mysql_data plugin to display the industrial worker projects"}, {"type": "send_to", "content": "CodeInterpreter"}, {"type": "message", "content": "Please use the sql_pull_mysql_data plugin to retrieve and display the industrial worker projects data"}]} 2024-04-17 21:46:50 - Planner talk to CodeInterpreter: Please use the sql_pull_mysql_data plugin to retrieve and display the industrial worker projects data 2024-04-17 21:46:54 - HTTP Request: POST https://open.bigmodel.cn/api/paas/v4/chat/completions "HTTP/1.1 200 " 2024-04-17 21:46:58 - LLM output: {"response": [{"type": "python", "content": "df, description = sql_pull_mysql_data(\"显示产业工人项目\")\nprint(description)\nprint(df.to_markdown())"}]} 2024-04-17 21:46:58 - Code to be verified: df, description = sql_pull_mysql_data("显示产业工人项目") print(description) print(df.to_markdown()) 2024-04-17 21:46:58 - Code to be executed: df, description = sql_pull_mysql_data("显示产业工人项目") print(description) print(df.to_markdown()) 2024-04-17 21:47:00 - Translation file for zh-CN not found. Using default translation en-US. 2024-04-17 21:47:04 - CodeInterpreter talk to CodeInterpreter: The following python code has been executed:

df, description = sql_pull_mysql_data("显示产业工人项目") print(description) print(df.to_markdown())

The execution of the generated python code above has failed

During execution, the following messages were logged: Traceback (most recent call last):

File /usr/local/lib/python3.10/site-packages/pandas/compat/_optional.py:135 in import_optional_dependency module = importlib.import_module(name)

File /usr/local/lib/python3.10/importlib/init.py:126 in import_module return _bootstrap._gcd_import(name[level:], package, level)

File :1050 in _gcd_import

File :1027 in _find_and_load

File :1004 in _find_and_load_unlocked

ModuleNotFoundError: No module named 'tabulate'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

Cell In[1], line 1 df, description = sql_pull_mysql_data("显示产业工人项目")

File /tmp/tmpwxhr90fi/sql_pull_mysql_data.py:28 in call

File /usr/local/lib/python3.10/site-packages/pandas/util/_decorators.py:333 in wrapper return func(*args, **kwargs)

File /usr/local/lib/python3.10/site-packages/pandas/core/frame.py:2983 in to_markdown tabulate = import_optional_dependency("tabulate")

File /usr/local/lib/python3.10/site-packages/pandas/compat/_optional.py:138 in import_optional_dependency raise ImportError(msg)

ImportError: Missing optional dependency 'tabulate'. Use pip or conda to install tabulate. ': '测试项目bbbbbbbbbb', '项目所在地区': '广州', '项目状态': None}, {'编码': 17, '项目名称': '测试项目2', '项目所在地区': 'CS001', '项目状态': None}, (omit some json data)

(omit another round output)

2.2、I remove the TaskWeaver docker container , then run a new TaskWeaver container based on LLM zhipuai, pip install tabulate, open a new Chrome browser, it has the result "Exception: Unknown recipient sql_pull_mysql_data" as the same above.

3、Will sessions affect each other? Is the session information stored in the project/workspace/sessions directory referenced as context in the current session?

liqul commented 7 months ago

Thanks for the detailed experiements. When I said 'a new session', I mean you just need to create a new session by clicking the web page to create a new one, not necessary to remove and download the container again, which need more effort.

From your observations, the 2.1 looks good except that the missing dependency issue. The key part is that the LLM output (shown below) contains the send_to field and its content should be CodeInterpreter and should not be the name of the plugin, i.e., sql_pull_mysql_data.

{"response": [{"type": "init_plan", "content": "1. Display the industrial worker projects"}, {"type": "plan", "content": "1. Use the sql_pull_mysql_data plugin to display the industrial worker projects"}, {"type": "current_plan_step", "content": "1. Use the sql_pull_mysql_data plugin to display the industrial worker projects"}, {"type": "send_to", "content": "CodeInterpreter"}, {"type": "message", "content": "Please use the sql_pull_mysql_data plugin to retrieve and display the industrial worker projects data"}]}

I don't know why this happens so frequently and we haven't seen this error before using GPT3.5 or GPT4. We don't have access to other models so not able to try them. One thing you can check is the prompt inside the project folder, i.e., project/workspace/sessions/session_id/planner_prompt_log_xxxx.json where you can find the prompt sending to the model. I'm not sure if the definition of the plugin has interference to the prompt so that the model missunderstand it as a character instead of a plugin.

MingYHou commented 1 month ago

Hi liqul,

I have got the same error Unknown recipient with the plugin name after I recently upgraded the model to gpt-4o-2024-05-13-128k-4k. So I gurss it's not due to the capacity of the model itself. Just wondering if there's any update or fix on this issue?

liqul commented 1 month ago

Hi liqul,

I have got the same error Unknown recipient with the plugin name after I recently upgraded the model to gpt-4o-2024-05-13-128k-4k. So I gurss it's not due to the capacity of the model itself. Just wondering if there's any update or fix on this issue?

Could you share more details? When you say 'recipent', I assume it is a role instead of a plugin.

MingYHou commented 1 month ago

Thanks for your reply!

Yes, the planner should invoke the code intepreter then run the plugin. but the planner takes the plugin name as a role which doesn't exist.

Error: raise Exception(f"Unknown recipient {recipient}") Exception: Unknown recipient data_retrieval

planner should invoke data_retrieval, but data_retrieval is a plugin not a role.

liqul commented 1 month ago

Thanks for your reply!

Yes, the planner should invoke the code intepreter then run the plugin. but the planner takes the plugin name as a role which doesn't exist.

Error: raise Exception(f"Unknown recipient {recipient}") Exception: Unknown recipient data_retrieval

planner should invoke data_retrieval, but data_retrieval is a plugin not a role.

This is indeed quite unusual. In order to debug this issue, we need to understand more details of your settings. Could you please share the prompt of the planner before you running into that problem? It is located under project/workspace/sessions/session_id/planner_prompt_xxx.json. With this log file, we can know the input to the LLM and figure out why the planner mistreat the plugin as a role. It is quite rare today that the model such as GPT4o makes this mistake.

MingYHou commented 1 month ago

Hi liqul, Thanks for the tips! I found a workaround fix that is to explicitly tell the planner 'send_to' must not be any plugin name in planner_prompt.yaml.

liqul commented 1 month ago

Hi liqul, Thanks for the tips! I found a workaround fix that is to explicitly tell the planner 'send_to' must not be any plugin name in planner_prompt.yaml.

Great to know the problem has gone.

fywang2 commented 1 month ago

Hi liqul, Thanks for the tips! I found a workaround fix that is to explicitly tell the planner 'send_to' must not be any plugin name in planner_prompt.yaml.

Hi MingYHou, Thank you so much for the tip on this issue! The workaround you mentioned about explicitly stating that 'send_to' must not be any plugin name in the planner_prompt.yaml sounds promising. Would you mind sharing the specific details or an example of how to implement this fix? It would greatly help me to understand and apply your solution.

Best regards!

MingYHou commented 1 month ago

Hi fywang2,

No worries! what I did is simply adding "'send_to' must not be any plugin name such as '_pluginname causing the issue'" in taskweaver -> planner -> planner_prompt.yaml -> response_json_schema ->send_to -> description. But I'm still trying to figure out why the planner takes a plugin name as a role instead of invoking code interpreter. Hope it helps