Hologres AI Function 文本分类实战:从提示词设计到 KV-Cache 调优,全程 SQL 搞定
2026/7/7 4:37:17 网站建设 项目流程

不写 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 条记录。

豆瓣影评数据集: https://www.kaggle.com/datasets/utmhikari/doubanmovieshortcomments

首先在 Hologres 中创建数据表:

CREATE TABLE movie_reviews_200( cn_name text, review text, stars bigint, sentiment_label text );

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

通过 psql 将 CSV 数据导入 Hologres:

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()函数动态拼装变量,灵活管理和迭代提示词版本。

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 条影评逐条进行情感分类,并将结果写入结果表。

-- 创建分类结果表 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 即可计算准确率:

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%

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

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

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

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

  • 模糊时兜底为"中性"

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’
-- 清除上次数据 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;

再次评估:

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 消耗和缓存命中情况:

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 完成全部推理任务。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询