SQL UDF 包装 AI Function 最佳实践

通过

CREATE FUNCTION
将 AI Function 封装为 SQL UDF,可以固化模型选择、prompt 逻辑和参数配置,让业务用户以最简方式调用 AI 能力。


基础模式

模式一:包装 AI_CLASSIFY(分类任务)

CREATE OR REPLACE FUNCTION public.classify_ticket(text STRING) RETURNS STRING AS AI_CLASSIFY( text, ARRAY('系统缺陷:API超时', '账号权限:SSO登录', '计费问题:升级扣费', '功能建议', '通用咨询'), JSON '{"output.behavior": "raw_string"}' ); -- 使用 SELECT public.classify_ticket('API一直报超时') AS category;

优点:

  • 标签列表固化在 UDF 中,业务用户无需关心分类体系
  • output.behavior
    output.behavior
    参数封装在内,输出格式统一
  • 更换分类体系时只需改 UDF 定义,调用方不受影响

模式二:包装 AI_COMPLETE 自定义 prompt(情感打分)

CREATE OR REPLACE FUNCTION public.sentiment_score(text STRING) RETURNS STRING AS AI_COMPLETE( CONCAT('请对以下文本进行情感打分,返回 -1.0 到 +1.0 之间的数值,只返回数字:', text), JSON '{"output.behavior": "raw_string"}' ); -- 使用 SELECT public.sentiment_score('产品非常好用') AS score;

优点:

  • prompt 模板封装在 UDF 中,调用方无需编写 prompt
  • raw_string
    raw_string
    模式确保输出可直接
    TRY_CAST
    TRY_CAST
    为数值
  • 可统一控制是否开启 thinking 模式等参数

模式三:多参数 UDF(运营建议生成)

CREATE OR REPLACE FUNCTION public.gen_recommendation( category STRING, volume INT, avg_sentiment DOUBLE ) RETURNS STRING AS AI_COMPLETE( CONCAT('你是一名客服运营主管。类别:', category, ',工单量:', volume, ',平均情感分:', avg_sentiment, '。请给出具体改进建议。'), JSON '{"output.behavior": "raw_string"}' ); -- 使用 SELECT public.gen_recommendation('API超时', 1240, -0.85) AS advice;

模式四:包装 AI_MASK(PII 脱敏)

CREATE OR REPLACE FUNCTION public.mask_pii(text STRING) RETURNS STRING AS AI_MASK( text, ARRAY('姓名', '电话', '邮箱', '地址'), JSON '{"output.behavior": "raw_string"}' ); -- 使用 SELECT public.mask_pii('张三的电话是13800138000') AS masked;


进阶用法

与动态表组合

将 UDF 直接嵌入动态表定义,实现声明式 AI 管道:

-- 先创建 UDF CREATE OR REPLACE FUNCTION public.classify_ticket(text STRING) RETURNS STRING AS ... ; CREATE OR REPLACE FUNCTION public.sentiment_score(text STRING) RETURNS STRING AS ... ; -- 动态表中直接使用 UDF CREATE DYNAMIC TABLE enriched_tickets REFRESH INTERVAL 30 MINUTE AS SELECT ticket_id, channel, raw_text, created_at, public.classify_ticket(raw_text) AS category, public.sentiment_score(raw_text) AS sentiment_score FROM raw_tickets;

参数化分类(动态传标签)

CREATE OR REPLACE FUNCTION public.flexible_classify( text STRING, labels ARRAY(STRING) ) RETURNS STRING AS AI_CLASSIFY(text, labels, JSON '{"output.behavior": "raw_string"}'); -- 对不同场景传不同标签 SELECT public.flexible_classify('API超时', ARRAY('技术', '业务', '其他')) AS tag;

批量处理优化

在 UDF 内部启用并发参数,提升大表处理吞吐量:

CREATE OR REPLACE FUNCTION public.batch_classify(text STRING) RETURNS STRING AS AI_CLASSIFY( text, ARRAY('系统缺陷:API超时', '账号权限:SSO登录', '计费问题:升级扣费', '功能建议', '通用咨询'), JSON '{"output.behavior": "raw_string", "task.concurrency": "4"}' );


最佳实践总结

1. 模型配置策略

场景建议
分类、抽取、翻译等确定性任务UDF 中省略 model 参数,使用工作区默认模型
需要特定模型的自定义 prompt可在 UDF 内显式指定
'conn_bailian:qwen3.6-flash'
'conn_bailian:qwen3.6-flash'
测试阶段先用 session SET 切换模型验证效果,再固化为 UDF

2. output.behavior 选择

模式适用场景UDF 返回值
raw_string
raw_string
下游需要纯文本直接返回模型输出,配合
TRY_CAST
TRY_CAST
转数值
formatted_json
formatted_json
下游需解析结构化结果返回 JSON 字符串
fail_on_error
fail_on_error
不容忍静默失败的场景异常时抛错而非返回 NULL

3. 权限管理

  • UDF 是原生 Schema 对象,通过标准 RBAC 控制访问权限
  • 业务用户只需
    SELECT
    SELECT
    权限即可使用 UDF,无需直接访问 AI Function
  • 底层模型切换对调用方透明

4. 注意事项

注意点说明
Schema 前缀调用 UDF 时必须使用 Schema 前缀,如
public.classify_ticket()
public.classify_ticket()
参数顺序带默认值的参数必须排在无默认值的参数之后
模型锁定UDF 中指定的 model、prompt、options 一旦固化为 UDF,调用方无法修改
版本管理通过
CREATE OR REPLACE FUNCTION
CREATE OR REPLACE FUNCTION
更新 UDF 定义,对调用方透明
性能测试建议在 UDF 中设置
task.concurrency
task.concurrency
,对比不同并发度下的吞吐量

完整示例:智能客服管道

-- 1. 定义 AI UDF CREATE OR REPLACE FUNCTION public.classify_ticket(text STRING) RETURNS STRING AS AI_CLASSIFY(text, ARRAY('系统缺陷:API超时', '账号权限:SSO登录', '计费问题:升级扣费', '功能建议', '通用咨询'), JSON '{"output.behavior": "raw_string", "task.concurrency": "4"}'); CREATE OR REPLACE FUNCTION public.sentiment_score(text STRING) RETURNS STRING AS AI_COMPLETE(CONCAT('请对以下工单情感打分,范围 -1.0 到 +1.0,只返回数字:', text), JSON '{"output.behavior": "raw_string"}'); CREATE OR REPLACE FUNCTION public.mask_pii(text STRING) RETURNS STRING AS AI_MASK(text, ARRAY('姓名', '电话', '邮箱', '地址'), JSON '{"output.behavior": "raw_string"}'); -- 2. 原始数据表 CREATE TABLE raw_tickets ( ticket_id BIGINT, channel STRING, raw_text STRING, created_at TIMESTAMP ); -- 3. 动态表:使用 UDF 自动处理 CREATE DYNAMIC TABLE enriched_tickets REFRESH INTERVAL 30 MINUTE AS SELECT ticket_id, channel, raw_text, created_at, public.classify_ticket(raw_text) AS category, public.sentiment_score(raw_text) AS sentiment_score, public.mask_pii(raw_text) AS masked_text FROM raw_tickets; -- 4. 业务查询(无需了解 AI Function 细节) SELECT category, COUNT(*) AS volume, ROUND(AVG(TRY_CAST(sentiment_score AS DOUBLE)), 2) AS avg_sentiment FROM enriched_tickets GROUP BY category ORDER BY volume DESC;

联系我们
预约咨询
微信咨询
电话咨询
邮件咨询