Hologres AI Function 文本分类实战:从提示词设计到 KV-Cache 调优,全程 SQL 搞定

不写 Python,不搭服务,不训模型。一条 SQL 调用大模型,文本分类从未如此简单。

传统 ML 做文本分类,到底有多累?

数据清洗、分词、特征工程、模型选型、训练调参、部署上线、推理服务维护......一套流程走下来,少则数天,多则数周。模型效果不好?重新来过。换个场景?再训一个。

有没有一种方式,让文本分类像查数据一样简单?

Hologres AI Function 给出了答案:SQL 即 AI,数据在哪,智能就在哪。

什么是 Hologres AI Function?

Hologres AI Function 将大模型推理能力直接内置于数据库引擎。你无需部署任何推理服务,只需通过 SQL 函数(如 ai_gen_structured),就能在查询过程中直接调用大模型,完成分类、摘要、抽取等 AI 任务。

核心优势一句话概括:数据不出库,推理即查询。

实战:用 SQL 对豆瓣影评做情感分类

下面我们用一个完整的例子,展示如何用 Hologres AI Function 对豆瓣影评进行情感分类(正向 / 负向 / 中性),并一步步调优到 95% 准确率。

Step 1:准备数据

本文使用的数据集来自 豆瓣影评数据集,取其中 200 条记录。

豆瓣影评数据集:www.kaggle.com/datasets/ut...

首先在 Hologres 中创建数据表:

plaintext 复制代码
CREATE TABLE movie_reviews_200(
    cn_name         text,
    review          text,
    stars           bigint,
    sentiment_label text
);

其中 sentiment_label 是人工标注的情感标签,用于后续评估模型效果。

通过 psql 将 CSV 数据导入 Hologres:

plaintext 复制代码
psql -U <db_user_name> -p 80 -h xxx.hologres.aliyuncs.com -d ai_test1 \
  -c "COPY movie_reviews_200 FROM STDIN WITH DELIMITER ',' CSV HEADER;" \
  < ~/Downloads/movie_reviews_200.csv

数据准备就绪,接下来开始调用大模型。

Step 2:创建提示词表

Hologres 支持将提示词作为数据存储在表中,通过 prompt() 函数动态拼装变量,灵活管理和迭代提示词版本。

plaintext 复制代码
CREATE TABLE ai_prompts(
    name        text PRIMARY KEY,
    prompt_text text
);

INSERT INTO ai_prompts VALUES(
    'classify_prompt1',
    $$
    你是一名专业的电影评论情感分析专家。你的任务是根据输入的**电影名称、用户影评和 stars 评分**,
    判断该影评对电影整体的情感倾向,并输出唯一结果。

    ## 输出要求
    仅输出以下 3 个值之一:
    - 正向
    - 负向
    - 中性

    除上述 3 个标签外,**不要输出任何其他内容**,包括解释、分析过程、标点、前缀、空格或重复输入。

    下面是本次判定的输入:
    - 电影名称:{0}
    - 用户影评:{1}
    - stars:{2}
    $$
);

这种"提示词即数据"的管理方式,让你可以随时新增、修改、对比不同版本的提示词,而无需改动任何代码。

Step 3:一条 SQL 完成批量分类

这是整个流程中最核心的一步。通过 ai_gen_structured 函数,在 SQL 查询中直接调用大模型,对 200 条影评逐条进行情感分类,并将结果写入结果表。

plaintext 复制代码
-- 创建分类结果表
CREATE TABLE movie_reviews_predict(
    cn_name         text,
    reivew          text,
    stars           bigint,
    sentiment_label text,
    predict_label   text,
    usage           jsonb
);

-- 批量分类并写入结果
WITH prompts AS(
    SELECT cn_name, review, stars,
        prompt(prompt_text, cn_name, review, stars)::text AS prompt,
        sentiment_label
    FROM movie_reviews_200
    LEFT JOIN ai_prompts ON ai_prompts.name = 'classify_prompt1'
),
gen_data AS(
    SELECT
        cn_name, review, stars, sentiment_label,
        ai_gen_structured(
            model_name      => 'qwen37-plus',
            message         => prompt,
            response_format => $${
                "type": "json_schema",
                "schema": {
                    "type": "object",
                    "properties": {
                        "label": {"type": "string"}
                    }
                }
            }$$,
            params => '{"show_details": true}'
        ) AS result
    FROM prompts
),
per_row AS (
    SELECT cn_name, review, stars, sentiment_label,
        result->'output'->>'label' AS predict_label,
        result->'usage' AS usage
    FROM gen_data
)
INSERT INTO movie_reviews_predict SELECT * FROM per_row;

没有 Python 脚本,没有推理服务,没有数据搬迁------一条 SQL 搞定全部。

Step 4:效果评估

分类完成后,用一条简单的 SQL 即可计算准确率:

plaintext 复制代码
SELECT
    COUNT(*) AS total_count,
    SUM(CASE WHEN predict_label = sentiment_label THEN 1 ELSE 0 END) AS correct_count,
    ROUND(
        SUM(CASE WHEN predict_label = sentiment_label THEN 1 ELSE 0 END)::numeric
        / COUNT(*) * 100, 2
    ) AS predict_accuracy
FROM movie_reviews_predict;

首轮结果:准确率 83.50%。

效果不错,但还有提升空间。关键在于------我们不需要重新训练模型,只需优化提示词。

Step 5:提示词调优------准确率飙升至 95%

在提示词中加入更精细的分类规则,例如:

  • 明确输入的含义(电影名称、影评文本、评分各自的权重)

  • 设定判定优先级(评论文本 > 结论句 > 整体语气 > 评分)

  • 处理特殊表达(反讽、转折句、欲扬先抑、比较句式)

  • 模糊时兜底为"中性"

plaintext 复制代码
INSERT INTO ai_prompts VALUES(
    'classify_prompt_opt',
    $$
    你是一名专业的电影评论情感分析专家。你的任务是根据输入的**电影名称、用户影评和 stars 评分**,判断该影评对电影整体的情感倾向,并输出唯一结果。

    ## 输入说明

    你将收到以下 3 项内容:

    1. **电影名称**  
       用于辅助理解影片题材、风格和评论语境,但不能脱离影评内容单独判断情感。

    2. **用户影评**  
       这是最主要的判断依据。评论可能很短,也可能包含口语、吐槽、反问、玩梗、引用、夸张、反讽、阴阳怪气等表达。你需要理解其真实语义,而不是只看字面词汇。

    3. **stars 评分**  
       范围为 0~5 的整数。通常分数越高越偏正向,越低越偏负向,但它只能作为辅助信息。**当 stars 与评论内容冲突时,必须以评论文本为准。**

    ---

    ## 判定原则

    ### 1. 以评论文本为核心依据
    判断的是**用户对电影整体的态度**,不是对某个演员、镜头、宣传或观影环境的单独情绪。只要评论文本能体现明确立场,就优先按文本判断。

    ### 2. stars 仅作辅助
    当评论很短、态度模糊时,可以参考 stars;但若评论文字和 stars 冲突,一律以文字真实含义为准。

    ### 3. 关注整体语义,不机械看单个词
    不要因为出现"好"就判正向,也不要因为出现"差"就判负向。要结合上下文、语气、转折、结论和整体情绪来判断。

    ### 4. 无法确定时优先中性
    如果评论信息不足、态度不明、褒贬难分或语义模糊,不要强行判断,优先输出"中性"。

    ---

    ## 标签判定标准

    ### 正向
    当评论整体明确表达喜欢、认可、推荐、满意、惊喜、感动等态度时,判为**正向**。

    常见情况:
    - 明确夸电影好看、精彩、感人、值得看、超出预期
    - 表达"喜欢""推荐""没白看""后劲很大"
    - 虽有小缺点,但总体肯定

    例如:
    - "比预期好很多"
    - "虽然节奏慢一点,但真的很好看"
    - "有瑕疵,不过整体很打动我"

    ### 负向
    当评论整体明确表达失望、不满、否定、不推荐、厌烦等态度时,判为**负向**。

    常见情况:
    - 明确说难看、无聊、尴尬、拖沓、失望、看不下去
    - 认为剧情、演技、节奏、逻辑等问题严重
    - 虽承认局部优点,但总体否定

    例如:
    - "太无聊了,看得想走"
    - "演员不错,但电影真的很难看"
    - "本来很期待,结果特别失望"

    ### 中性
    当评论无法体现明确正负态度时,判为**中性**。

    常见情况:
    - 评论过短,如"还行""一般""就那样"
    - 只复述剧情,没有评价
    - 只提问、引用台词、玩梗,未表达明确好恶
    - 褒贬都有,但无法判断最终倾向
    - 重点不在电影本身

    例如:
    - "所以最后他到底死没死?"
    - "看过"
    - "有优点也有问题"

    ---

    ## 特殊表达处理

    ### 1. 反讽和阴阳怪气
    要按真实语义判断,不按字面判断。  
    例如:"真是神作,看得我快睡着了" → **负向**

    ### 2. 转折句
    重点关注"但是、不过、然而、可惜"等转折后的内容。  
    例如:"前面还行,但是后面崩了" → **负向**

    ### 3. 欲扬先抑 / 欲抑先扬
    看最终落点。  
    例如:"本来没期待,结果意外好看" → **正向**

    ### 4. 比较表达
    通过与前作、同类片比较来表达态度时,提取真实倾向。  
    例如:"比上一部强太多" → 多数为**正向**  
    "还不如网大" → **负向**

    ---

    ## 冲突信息优先级

    当信息不一致时,按以下顺序判断:

    **评论文本真实语义 > 明确结论句 > 整体语气 > stars 评分 > 电影名称**

    ---

    ## 输出要求

    仅输出以下 3 个值之一:

    - 正向
    - 负向
    - 中性

    除上述 3 个标签外,**不要输出任何其他内容**,包括解释、分析过程、标点、前缀、空格或重复输入。


    下面是本次判定的输入:
    - 电影名称:{0}
    - 用户影评:{1}
    - stars:{2}
    $$
);

使用新提示词重新分类:

  • 只需将 SQL 中的提示词 name 改成'classify_prompt_opt'
plaintext 复制代码
-- 清除上次数据
TRUNCATE TABLE movie_reviews_predict;

-- 使用优化后的提示词重新分类
WITH prompts AS(
    SELECT cn_name, review, stars,
        prompt(prompt_text, cn_name, review, stars)::text AS prompt,
        sentiment_label
    FROM movie_reviews_200
    LEFT JOIN ai_prompts ON ai_prompts.name = 'classify_prompt_opt'
),
gen_data AS(
    SELECT
        cn_name, review, stars, sentiment_label,
        ai_gen_structured(
            model_name      => 'qwen37-plus',
            message         => prompt,
            response_format => $${
                "type": "json_schema",
                "schema": {
                    "type": "object",
                    "properties": {
                        "label": {"type": "string"}
                    }
                }
            }$$,
            params => '{"show_details": true}'
        ) AS result
    FROM prompts
),
per_row AS (
    SELECT cn_name, review, stars, sentiment_label,
        result->'output'->>'label' AS predict_label,
        result->'usage' AS usage
    FROM gen_data
)
INSERT INTO movie_reviews_predict SELECT * FROM per_row;

再次评估:

plaintext 复制代码
SELECT
    COUNT(*) AS total_count,
    SUM(CASE WHEN predict_label = sentiment_label THEN 1 ELSE 0 END) AS correct_count,
    ROUND(
        SUM(CASE WHEN predict_label = sentiment_label THEN 1 ELSE 0 END)::numeric
        / COUNT(*) * 100, 2
    ) AS predict_accuracy
FROM movie_reviews_predict;

优化后准确率:95.00%!仅通过调整提示词,准确率提升了 11.5 个百分点。

阶段 准确率 提升
基础提示词 83.50% ---
优化提示词 95.00% +11.5%

Step 6:成本分析------200 条影评仅花 1 毛钱

分类完成后,我们还可以通过 SQL 查看 Token 消耗和缓存命中情况:

plaintext 复制代码
SELECT
    SUM((usage::jsonb ->> 'input_tokens')::int)  AS total_input_tokens,
    SUM((usage::jsonb ->> 'cached_tokens')::int)  AS total_cached_tokens,
    ROUND(
        SUM((usage::jsonb ->> 'cached_tokens')::int)::numeric
        / NULLIF(SUM((usage::jsonb ->> 'input_tokens')::int), 0) * 100, 2
    ) AS cache_hit_rate
FROM movie_reviews_predict;

结果令人惊喜:

指标 数值
总输入 Token ~25.8 万
缓存命中 Token ~23.4 万
缓存命中率 90%

Hologres 针对数据库批量推理的负载特征,对大模型 KV-Cache 命中率进行了深度优化。命中缓存的 Token 仅按 1~2 折 计费,大幅降低推理成本。

最终成本明细:

  • 缓存命中部分:2.4 元/百万 Token × 10% × 0.23 百万 = 0.055 元

  • 未命中部分:2.4 元/百万 Token × 0.024 百万 = 0.057 元

  • 总计:0.11 元

200 条影评,情感分类准确率 95%,成本仅 0.11 元。

TIPS:如何提升 cached token 的命中率?

  • 提示词中尽量将固定不变的部分置于提示词顶端;

  • 变化的部分放到提示词末尾;

  • 推荐使用 prompt()函数做提示词拼装,可参考本文的提示词示例。

三大核心优势总结

1. SQL 即 AI,零门槛上手

不需要 Python,不需要部署推理服务,不需要搭建 ML Pipeline。会写 SQL 的数据分析师,就能直接调用大模型完成文本分类任务。

2. 提示词即数据,迭代快如闪电

提示词存在数据表里,版本管理和 A/B 对比像改一行 SQL 一样简单。效果不好?换个提示词,重新跑一遍------几分钟搞定,无需重训模型。

3. 智能缓存加持,成本降到极致

最高 90% 的 Cache 命中率意味着绝大部分 Token 仅按 1~2 折计费。即便数据量扩大到上万条,成本依然可控。

适用场景

  • 舆情监控: 电商评论、社交媒体的情感分析与趋势洞察

  • 内容审核: UGC 内容的自动分类与合规检测

  • 客服质检: 对话文本的意图识别与满意度评估

  • 数据标注: 海量文本的自动化打标,替代高成本人工标注

  • 行业分析: 金融资讯、医疗文本、法律文书的智能分类

写在最后

Hologres AI Function 让大模型走进了数据库,让文本分类变成了一条 SQL 的事。从数据准备到推理分类,从效果评估到成本优化,全程 SQL 搞定,全程数据不出库。

一条 SQL,从数据到智能。

本文采用通义千问 qwen3.7-plus 模型,搭配 Hologres 4.2 完成全部推理任务。

相关推荐
code_pgf2 小时前
AI-Agent记忆机制分析
大数据·人工智能
阿拉斯攀登3 小时前
安全与可控性:输出校验、权限控制
人工智能·chatgpt·agent·memory·claude·知识库·向量数据库
冬奇Lab3 小时前
每日一个开源项目(第152篇):SAG - 用 SQL JOIN 代替 PageRank 做多跳 RAG 检索
人工智能·开源
冬奇Lab3 小时前
Workflow 系列(09):主流框架对比——Prompt-based、LangGraph、Temporal、n8n 如何选
人工智能·工作流引擎
程序员老猫4 小时前
vide coding 个人产品,那就从博客开始吧
人工智能·程序员·全栈
geo搜搜果数据5 小时前
实测5大AI平台品牌排名:复现GEO监测流程
人工智能·langchain·搜搜果