DB-GPT AWEL 实践所遇问题
编辑1.取数
根本:LLM的text2sql能力不足
(1)system_prompt无用
具体问题表现:在LLM对user_input上,如果能使用SQL语句进行聚合函数处理他会直接处理,导致取出的数据有问题
使用system_prompt告诉LLM,你不能对生成的SQL语句进行任何聚合、计算等函数操作,但还是继续进行操作了。(针对oai gpt-3.5-turbo)。 但是使用oai gpt-4 他能理解不能用聚合函数,但是SELECT 后面紧跟的就是 对应字段的名字形如 (SELECT domain FROM domain) 这是无效取数,应该使用(SELECT * FROM domain)才对。
尝试解决问题1:system_prompt改写 (未解决)
比如:“你必须使用能查询返回原始数据的SQL语句“等 都是无用
测试了一上午的prompt,以gpt3.5的智商,实在没法完成。
尝试解决问题2:对生成的sql结果拼接 (解决)
直接对生成出来的sql,以FROM进行split x['sql'].split("FROM", 1)[1].strip()
最后再进行拼接 SELECT * FROM
就能构造出获取原始数据的取数行为。
(2)取数是全量数据
具体问题表现:取数取的是全量的数据,因此需要对这些字段进行处理,是否要保留这个字段用于分析等等,再次通过LLM进行判断。
尝试解决问题1: 引入一个新的prompt 结合LLM 用来判断需要哪些字段 (解决)
具体操作如下:
1.创建变量 field_system_prompt = """里面写上形如 根据 user_input 并结合 table_info 获取所需要的字段"""
2.创建变量 FIELD_RESPONSE_FORMAT_SIMPLE = {参考RESPONSE_FORMAT_SIMPLE 变量 还是需要 thoughts key 再加上一个 list 字段}
3.创建任务变量 field_prompt_task = PromptBuilderOperator(task_name="字段提示词算子", prompt=field_prompt)
4.创建DisplayFieldsOperator
类 继承 MapOperator 用来返回字段
4.创建任务变量 display_fields_task = DisplayFieldsOperator(task_name="显示字段算子")
3.通过ChatPromptTemplate 将 field 所需prompt构建成 field_prompt变量
4.根据所需构建新的awel flow
# 这条是用来把table的信息提取出来
input_task # 用户传进来的call
>> MapOperator(task_name="提取用户输入", map_function=lambda x: x["user_input"]) # 提取用户输入
>> retriever_task # 连接向量库 获取 向量库中一开始自己所存的table
>> content_task # 提取retriever_task中只需要table有个的数据
>> merge_task # 先join一部分
# 这条是用来拉通获取所需字段的flow
input_task # 用户传进来的call
>> merge_task # 再join一部分
>> field_prompt_task # field相关prompt
>> req_build_task # 请求的模型参数
>> llm_task # 构造llms请求
>> display_fields_task # 响应最后的数据
(3)选定所需字段数据
具体问题表现:通过(1)已经能够获取到字段的list了 形如:["name", "age"]的返回结果,但是 DatasourceOperator
取出的是全量数据的dataframe,还没有进一步的结合。取出合适的数据字段列,构造一个新的子dataframe 更方便后续分析。
尝试解决问题2:对DatasourceOperator的数据进行一步新一轮取数处理
取运行完display_fields_task后的变量进行再一步处理,形如 data[columns]
2.计算
在开始计算之前,有一点需要主要。 awel中的算子,都是尽可能是无状态的一个形式,也就是如果在DAG_1中的变量(算子),在DAG_2中是没法使用的。因此,当我们在DAG_2想用DAG_1最终的结果,需要将DAG_1的最终结果以DAG_2的call()传入,方能使用这一结果。
(1)llms计算能力差
具体问题表现:用户的问题可能会有不同的问法,如果只靠llm的计算能力,计算出来的结果不行,因此需要进一步处理。llms本身的计算能力并不是非常强,在做数据分析的时候,实际上非常依赖最后计算值的结果,因此,需要单独编写计算算子,以满足需求。
尝试解决问题1: 编写不同的计算类的算子 (解决)
例子:
class DataFrameCountOperator(MapOperator[pd.DataFrame, int]):
def __init__(self, **kwargs):
super().__init__(**kwargs)
async def map(self, df: pd.DataFrame) -> int:
return await self.blocking_func_to_async(self._two_sum, df)
def _two_sum(self, df: pd.DataFrame) -> int:
return len(df)
with DAG("calc_dag") as calc_dag:
input_task = InputOperator(input_source=InputSource.from_callable())
count_task = DataFrameCountOperator()
input_task >> count_task >> # 自己再编写个展示数据的算子 用来做return
(2)计算不智能
具体问题表现:以上的步骤都是建立在我们手动的去设置直接走入哪个计算流程,很明显,显示应用场景会有很大的问题,不够灵活。因此要加入对用户问题进行llm的先一步的决策,决策我要进行哪种方式的计算。
尝试解决问题1: 构建决策字典,将其组合成prompt传递给LLM,以获取字典的键。
通过获取到的key,传递给branch算子
- 2
- 0
-
分享