人生没有彩排
每一天都是现场直播

在PowerBI中使用跨事务任务流接入AI

前言

本篇文章将继续介绍新出的跨事务任务流功能的应用案例,本次介绍的是在PowerBI报表中接入AI模型,实现实时对话,不仅可以读取报表的数据,并且还支持与切片器联动、更改AI模型、清除聊天上下文等。

先来看一下最终效果,如下面所示:

注意,该聊天界面并不是微软官方的Copilot,而是使用PowerBI原生的视觉对象及书签、按钮等组件手搓的界面,并通过跨事务任务流来实现与AI模型的交互等功能。

本案例需要用到Fabric用户数据函数、SQL Server数据库、以及AI模型的API接口与密钥等,实现的简要步骤如下:

1、根据需求,设计存储与AI模型的问答记录的表的表结构,并在SQL Server中创建该表,为方便描述,将其称为问答记录表

2、创建Fabric用户数据函数,将特定的报表数据及用户的问题一起传递给AI模型,最后将用户的问题和AI模型的回答一起写入数据库中的问答记录表

3、在PowerBI中使用按钮来调用Fabric用户数据函数,实现与AI模型的对话和记录

4、在PowerBI中使用DirectQuery模式连接到SQL Server中的问答记录表,实时显示AI模型的最新回答

其中,关于Fabric用户数据函数的详细介绍和使用可以参考我的另一篇文章:Fabric用户数据函数的介绍

表结构设计

首先是问答记录表。问答记录表的表结构设计很简单,这个表需要存储的是用户与AI模型的问答记录,因此只需要记录清楚哪个用户在什么时间用什么模型问了什么问题以及AI模型的回答是什么即可,所以问答记录表的表结构如下:

其中,有一个history字段需要稍微解释一下,这个字段的取值只有0和1,是用来控制用户的历史聊天记录是否也传递给AI模型的,1则是传递,0则是不传递。

然后在SQL Server数据库中按以上表结构创建表即可,使用到的SQL语句如下:

IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[ChatWithAI]') AND type IN ('U'))
    DROP TABLE [dbo].[ChatWithAI]
GO

CREATE TABLE [dbo].[ChatWithAI] (
  [question] ntext COLLATE Chinese_PRC_CI_AS  NULL,
  [answer] ntext COLLATE Chinese_PRC_CI_AS  NULL,
  [user] nvarchar(255) COLLATE Chinese_PRC_CI_AS  NULL,
  [datetime] datetime  NULL,
  [model] nvarchar(255) COLLATE Chinese_PRC_CI_AS  NULL,
  [history] int  NULL
)
GO

另外,由于需要支持切换AI模型,所以还需要创建一张表来存储AI模型的信息,该表命名为:AIModel表,其表结构如下:

AIModel表可以直接在PowerBI中使用“输入数据”功能来创建,但为了保护AI模型的密钥等信息,建议还是在数据库中进行创建和存放,然后使用DirectQuery模式进行连接。

创建Fabric用户数据函数

首先,在PowerBI Server的工作区中创建一个用户数据函数,然后将以下代码粘贴到用户数据函数中即可:

import fabric.functions as fn
import logging
import pymssql
import openai

udf = fn.UserDataFunctions()

@udf.function()
def AIAnswer(AIModel:str,AIAPIVersion:str,AIEndpoint:str,AIkey:str,DBHost:str,DBPort:str,Database:str,DBUser:str,DBPassword:str,Question:str,CSVDate:str,User:str,DateTime:str)->str :
    logging.info('Python UDF trigger function processed a request.')
    logging.info(f"Question: {Question}")
    # Establish a connection to the SQL database
    connection = pymssql.connect(host=DBHost,port=DBPort,database=Database,user=DBUser,password=DBPassword)
    cursor = connection.cursor()
    # Submit prompt to Azure OpenAI and get an AI Answer
    prompt = "You are a data analyst. The user is unable to render, so the style of your answer should be friendly to txt notepad, dont use the markdown style. Please answer the qeustion of user based on the data provided: " + CSVDate 
    # Get the history chat of current user from sql table
    SQL_select_command = "SELECT question, answer FROM [dbo].[ChatWithAI] WHERE [user] = %s and [model]=%s and [history]=1 ORDER BY [datetime] asc;"
    cursor.execute(SQL_select_command,(User,AIModel))
    history = cursor.fetchall()
    # Generate the history chat messages of user and assistant for the AI model
    history_messages = [{"role": "system", "content": prompt}]
    for row in history:
        history_messages.append({"role": "user", "content": row[0]})
        history_messages.append({"role": "assistant", "content": row[1]})
    deployment = AIModel
    openai_client = openai.AzureOpenAI(
        api_key = AIkey,
        api_version = AIAPIVersion,
        azure_endpoint = AIEndpoint
    )
    response = openai_client.chat.completions.create(
        model=deployment,
        messages=history_messages + [{"role": "user", "content": Question}]
    )
    result = response.choices[0].message.content
    SQL_insert_command = "INSERT INTO [dbo].[ChatWithAI]([question],[answer],[user],[datetime],[model],[history]) VALUES(%s,%s,%s,%s,%s,%s);"
    cursor.execute(SQL_insert_command, (Question, result, User, DateTime,AIModel,1))
    # Log the AI answer
    logging.info(f"AI Answer: {result}")
    # Commit the transaction
    connection.commit()
    # Close the connection
    cursor.close()
    connection.close()    
    return "Success"

@udf.function()
def ClearHistoryChat(DBHost:str,DBPort:str,Database:str,DBUser:str,DBPassword:str,User:str)->str:
    logging.info('Python UDF trigger function processed a request.')
    logging.info(f"User: {User}")
    # Establish a connection to the SQL database
    connection = pymssql.connect(host=DBHost,port=DBPort,database=Database,user=DBUser,password=DBPassword)
    cursor = connection.cursor()
    SQL_update_command = "UPDATE [dbo].[ChatWithAI] SET [history]=0 WHERE [User]=%s"
    cursor.execute(SQL_update_command, User)
    # Commit the transaction
    connection.commit()
    # Close the connection
    cursor.close()
    connection.close()
    return "Success"

上面总共定义了两个函数,他们的作用如下:

  • AIAnswer函数,首先查询用户的有效历史对话,然后将报表数据以及用户当前的问题一起传递给AI模型,最后把问题和回复一起写入数据库中的问答记录表
  • ClearHistoryChat函数,通过更新问答记录表的history字段来清除聊天上下文

另外,这两个函数中所使用的API密钥、数据库账号密码等凭证都进行了参数化,将在PowerBI报表进行调用时使用度量值进行传参。

在PowerBI中创建交互界面

经过上面的步骤,数据库以及用户数据函数都已经创建完了,然后只需要在PowerBI中创建交互界面,然后将按钮绑定到对应的用户数据函数即可。

具体的交互界面如下图所示:

其中,问题输入框使用的是文本切片器视觉对象,下面展示AI模型的回答的则是表格视觉对象。

然后,模型切换的切片器使用的则是前面创建的AIModel表中的model字段,如下图所示:

然后创建参数度量值,具体如下:

Params_AIAPIVersion = "2025-01-01-preview"
Params_AIEndpoint = MAX('AIModel'[endpoint])
Params_AIKey = MAX('AIModel'[key])
Params_AIModel = MAX('AIModel'[Model])

Params_Database = "请输入数据库信息,或其他获取信息的表达式"
Params_DBHost = "请输入数据库信息,或其他获取信息的表达式"
Params_DBPort = "请输入数据库信息,或其他获取信息的表达式"
Params_DBUser = "请输入数据库信息,或其他获取信息的表达式"
Params_DBPassword = "请输入数据库信息,或其他获取信息的表达式"

Params_ClearHistoryChatUser = 
IF(
    CALCULATE(NOT ISEMPTY('ChatWithAI_Log'),'ChatWithAI_Log'[user]=USERNAME(),'ChatWithAI_Log'[history]=1),
    USERNAME()
)

Params_UpdateTime = CONVERT(UTCNOW()+TIME(8,0,0),STRING)

Params_User = USERNAME()

Params_CSVData = "此处编写需要传递给AI模型的数据的查询,最后以CSV格式返回即可"

然后,使用上面的参数度量值将按钮绑定到对应的用户数据函数,如下图所示:

最后,再使用以下度量值来获取最新的AI回答:

LatestAnswer = 
IF(ISFILTERED('ChatWithAI_Log'[question]),
    COALESCE(
        CALCULATE(
            MAXX(
                TOPN(1,'ChatWithAI_Log','ChatWithAI_Log'[datetime]),
                'ChatWithAI_Log'[answer]
            ),
            'ChatWithAI_Log'[user]=USERNAME(),
            'ChatWithAI_Log'[history]=1,
            'ChatWithAI_Log'[model]=MAX('AIModel'[Model])
        ),
        "Pls enter your questions first."
    ),
    "Pls enter your questions first."
)

将其作为表格视觉对象的值字段即可:

到这里为止,所有关键步骤就都完成了,最后还可以使用书签来做一个聊天界面的展开与隐藏等交互,但这不是重点就不过多赘述了,最终效果请见文章开篇。

总结

虽然PowerBI已经有官方的Copilot,但涉及到数据安全,一般企业都不会开放使用。而通过本篇文章所介绍的方案来接入AI模型,则可以将AI模型的接口更改为本地部署的模型,就可以一定程度上解决数据安全的问题,所以这不仅仅只是一个玩具,也是存在落地的价值的。

未经允许不得转载:夕枫 » 在PowerBI中使用跨事务任务流接入AI
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论