首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >在数据库里直接调大模型:OpenTenBase opentenbase_ai 扩展从 0 到 1

在数据库里直接调大模型:OpenTenBase opentenbase_ai 扩展从 0 到 1

原创
作者头像
baixi
发布2026-09-19 17:44:21
发布2026-09-19 17:44:21
1040
举报

导读:给评论表做情感分析、给工单做摘要,传统做法是"导出数据 → 写 Python 脚本 → 回写结果",链路长、一致性差。OpenTenBase 的 opentenbase_ai 扩展把大模型调用变成了一条 SQL。本文讲清三件事:① 模型注册背后的三个设计决策(复制表 / json_path 模板 / GUC 默认模型);② 跑通摘要生成 + 文本分类的最小闭环;③ 叠加 pgvector 实现"embedding 入库 + 相似度检索"的库内 RAG。文中 SQL 语义已与 master 源码及回归测试逐句核对;涉及真实端点的运行效果均标注"待验证",以实测为准。演示环境基于本组 PR #302 交付的 PostgreSQL 18.6 + pgvector v0.8.6 增强版。

一、背景:为什么要把 AI 调用搬进数据库?

假设你有一张用户反馈表 feedback,想给每条评论生成摘要、判断正负面。常规路径是:导出数据 → 写脚本调 LLM API → 把结果写回数据库。这条路有三个老问题:

  • 链路长:ETL 管道、脚本调度、失败重试,每一环都要维护;
  • 一致性差:数据出库再回写,期间源表可能已变更;
  • 权限分散:数据出了库,管控边界就被打破了。

opentenbase_ai 的思路很直接:LLM 调用 = SQL 函数。数据不出库,UPDATE / SELECT 可以直接加工整列文本,权限、事务、一致性全部复用数据库本身的能力。

先交代一下上游现状:社区由 Issue #304 牵头为 opentenbase_ai 补文档,PR #305(611 行完整版)与 PR #306(228 行精简版)都在提交 README。本文不重复通用函数参考,聚焦最小闭环 + RAG 案例,与二者互补。

环境说明:本文演示环境为本组 PR #302 交付的 PostgreSQL 18.6 + pgvector v0.8.6 增强版 + OpenTenBase master 源码树。扩展依赖 http(pgsql-http)、libcurl 与可达的模型端点,安装前置清单不在本文展开,详见文末参考链接中的 README 与交付文档。

二、3 分钟看懂设计:模型注册背后的三个决策

opentenbase_ai 的全部配置都存在一张表里,全部调用都收敛到两个函数。读一遍 opentenbase_ai--1.0.sql,有三个决策值得拿出来讲。

决策 1:配置表为什么是复制表。 ai_model_list 的建表语句收尾是 DISTRIBUTE BY REPLICATION——在 OpenTenBase 的 CN/DN 分布式架构下,模型配置需要在所有节点上保持一致:在 CN 上注册一次,全局生效,任何节点执行 SQL 函数都能本地读到配置,避免跨节点查询配置表。

决策 2:json_path 不是 JSONPath,是 SQL format 模板。 这是最容易望文生义的地方。invoke_model 拿到 HTTP 响应体后,执行的是 EXECUTE format(json_path, 响应体)。三个内置注册函数分别写死了 OpenAI 兼容协议的提取模板,例如 completion 模型的是:

代码语言:sql
复制
'SELECT %L::jsonb->''choices''->0->''message''->>''content'''

即把响应体作为字面量代入模板,用 jsonb 运算符取出 choices[0].message.content。想接任何非 OpenAI 兼容的协议,不需要改代码——用 8 参数的 ai.add_model 传一个自定义模板即可。这个"模板即适配层"的设计,把协议差异收敛成了一行配置。

决策 3:默认值与合并。 GUC ai.completion_model 决定默认模型(embedding / image 各有对应的 ai.embedding_model / ai.image_model);每次调用时 default_args || user_args 做 jsonb 浅合并,顶层键覆盖——注册时写好 temperature: 0.3,某条 SQL 想临时调高,传个 config 参数就行。

整体调用链路如下(后续会替换为正式配图):

代码语言:txt
复制
[图 1] 调用链路示意图(占位,发布前替换为配图)
  SQL (ai.summarize ...)
    └─> ai.invoke_model(model_name, user_args)
          ├─> 读 ai_model_list(复制表,全节点一致)
          ├─> default_args || user_args 合并参数
          ├─> pgsql-http 发起 POST(Bearer token)
          └─> EXECUTE format(json_path, 响应体) 提取结果

三、上手第一步:注册你的第一个模型

以 DeepSeek 为例(任何 OpenAI 兼容端点都可以):

代码语言:sql
复制
CREATE EXTENSION opentenbase_ai;   -- 依赖 http 扩展,需先装好 pgsql-http

SELECT ai.add_completion_model(
  'my-chat',
  'https://api.deepseek.com/v1/chat/completions',
  '{"model":"deepseek-chat","temperature":0.3}'::jsonb,
  'sk-***',          -- token,自动构造 Authorization: Bearer 头
  'deepseek'
);

SET ai.completion_model = 'my-chat';
SELECT * FROM ai.models;           -- 视图查验:model_name / provider / uri / default_args

注册与管理函数速查(函数签名已与 master 源码逐行核对):

函数

作用

ai.add_completion_model(name, uri, default_args, token, provider)

注册对话模型(内置 chat 提取模板)

ai.add_embedding_model(name, uri, default_args, token, provider)

注册向量模型(内置 embedding 提取模板)

ai.add_image_model(name, uri, default_args, token, provider)

注册多模态模型

ai.add_model(name, header, uri, default_args, provider, request_type, content_type, json_path)

通用 8 参注册,适配任意协议

ai.update_model(name, config, value)

修改单个配置项

ai.delete_model(name)

删除模型

⚠️ 生产安全提示:源码中 GRANT USAGE ON SCHEMA ai TO PUBLIC,且 ai_model_list 表对 PUBLIC 授予了 SELECT——而 request_header 里存着 API token,等于全库用户可读。同时 PL/pgSQL 函数创建后默认 PUBLIC 有 EXECUTE 权限。生产环境请务必 REVOKE,只授权给管理员角色,这一点请当作上线前检查项。

四、核心演示:一条 SQL 跑通摘要 + 文本分类

注册好模型之后,高层函数就是一句话的事:

代码语言:sql
复制
-- 摘要
SELECT ai.summarize('这款数据库安装简单,文档清晰,就是初始化集群时端口配置踩了点坑……');

-- 文本分类(布尔判断)
SELECT ai.generate_bool('好评返回 true,差评返回 false:物流很快,包装也不错');

-- 情感分析
SELECT ai.sentiment('客服响应很及时,但问题没彻底解决');

全文最想给你看的是这一句——整列文本库内加工

代码语言:sql
复制
UPDATE feedback
SET summary     = ai.summarize(content),
    is_positive = ai.generate_bool('好评返回 true:' || content);

一条 UPDATE 扫完整张表,摘要和情感标签直接落列,没有导出、没有脚本、没有回写。想限流就加 WHERE 分批跑,想重跑就事务回滚,全部是老 DBA 熟悉的武器。

  • 图 2 ai.summarize / ai.generate_bool / ai.sentiment 三条调用的真实返回(待验证,实测后回填)
  • 图 3 UPDATE 前后 feedback 表对比(待验证,实测后回填)

状态标注:以上 SQL 的语义已与扩展回归测试逐句核对;真实端点的运行结果与截图待环境实测后回填,本文发布前补齐。

五、mock 能证明什么:httpbin 验证的边界

没有真实 API Key 时,可以把 URI 指向 httpbin.org 这类回显服务做 mock 测试。但请清醒——mock 的验证边界非常明确:

✅ 能验证

❌ 不能验证

请求构造(method / headers / body 被正确发出)

真实推理质量

default_args \|\| user_args 的合并行为

json_path 与真实响应结构是否匹配

json_path 模板的提取逻辑

token 鉴权能否通过真实服务

错误路径(模型不存在 / http_code ≠ 200)

超时、限流等真实网络行为

一句话结论:mock 通过 ≠ 真实调用通过。接真实模型前,请用真实端点把第四章完整重跑一遍。这也是本文所有演示结果坚持标注"待验证"的原因——没跑过真实端点,就不写"已实测"。

六、进阶实战:AI + pgvector 搭一个库内 RAG

有了对话模型,再加上 pgvector,检索增强生成(RAG)的检索半边也能搬进库里:

代码语言:sql
复制
-- 1. 注册 embedding 模型(OpenAI 兼容端点均可)
SELECT ai.add_embedding_model(
  'my-emb',
  'https://api.openai.com/v1/embeddings',
  '{"model":"text-embedding-3-small"}'::jsonb,
  'sk-***'
);
SET ai.embedding_model = 'my-emb';

-- 2. embedding 直接入库(::vector 由 pgvector 提供)
CREATE TABLE docs (
  id        serial PRIMARY KEY,
  content   text,
  embedding vector(1536)
);

INSERT INTO docs (content, embedding)
SELECT content, ai.embedding(content)::vector
FROM raw_docs;

-- 3. Top-K 相似度检索
SELECT id, content
FROM docs
ORDER BY embedding <=> ai.embedding('如何初始化 OpenTenBase 集群?')::vector
LIMIT 5;

到这里是标准玩法。接下来是本文独有素材——本组 PR #302 为 pgvector v0.8.6 补齐的索引自省与参数推荐能力

代码语言:sql
复制
-- 4. 查看索引构建参数(PR #302 新增)
SELECT * FROM hnsw_index_info('docs_hnsw_idx'::regclass);
--  m | ef_construction | ef_search | dimensions |    opclass
-- ---+-----------------+-----------+------------+---------------
--  16 |              64 |        40 |       1536 | vector_l2_ops

-- 5. 按目标 recall 推荐检索参数(PR #302 新增)
SELECT * FROM hnsw_recommend_ef_search('docs_hnsw_idx'::regclass, 5, 0.95);
SELECT * FROM ivfflat_recommend_probes('docs_ivf_idx'::regclass, 0.99);

推荐函数按目标 recall 给参数倍率:< 0.9 → 0.7x,< 0.95 → 1.0x,≤ 0.99 → 1.5x,> 0.99 → 2.5x。这两个函数的意义在于:线上"向量检索 recall 异常低"的排障,从拼 pg_stat_* 加元数据,变成直接看索引本身的构建参数,RAG 检索质量可解释、可调参。上述诊断与推荐函数已经 make installcheck 14/14 全部通过(PostgreSQL 18.6 + pgvector v0.8.6)。

  • 图 4 embedding 写入与 Top-K 检索结果(待验证,实测后回填)
  • 图 5 hnsw_index_info / 推荐函数的输出(待验证,复用 PR #302 环境回填)

⚠️ 已知限制:PG18 + pgvector 0.8.6 在 2 万行以上构建 HNSW 索引存在段错误(上游 bug,已复现),演示数据量请控制在 ≤ 1 万行;另 PR #302 的诊断函数使用了 PG12+ 的 InitMaterializedSRF API,OpenTenBase 的 PG10 内核暂未适配,改动计划已列入其设计文档 v0.2。

七、踩坑 FAQ

症状

原因与解法

Model not found

模型未注册或名字打错,SELECT * FROM ai.models; 核对

调用报 GUC 未设置

ai.generate 系列依赖默认模型:SET ai.completion_model = '...'(或在函数里显式传 model_name

返回 http_code ≠ 200 报错

ai.raw_invoke_model('模型名', '{}'::jsonb) 拿到完整 http_response,看状态码与响应体定位

Invalid json path for model

该模型的 json_path 为 NULL,用 ai.update_model 修正提取模板

设了 GUC 但不生效

自定义 GUC 需扩展库已加载,确认会话内已 CREATE EXTENSION(必要时 LOAD

模型不是 OpenAI 兼容协议

别硬套便捷函数,用 8 参 ai.add_model 自定义 json_path 模板

八、总结与展望

回顾一下:库内 AI 的价值 = 数据不出库 + 免 ETL + 可组合进任意 SQL;设计上能学两招——用复制表保证分布式配置一致,用 SQL format 模板把协议差异收敛为配置。再叠上 pgvector 与 PR #302 的索引自省能力,检索质量也从玄学变成了可观测的工程问题。

后续计划:真实端点实测并回填本文全部截图;向 Issue #304 提交与 #305 / #306 互补的文档 PR;PR #302 方向继续推进距离计算 SIMD 优化与 PG10 内核适配。欢迎到仓库交流。

参考链接


环境声明:本文演示环境基于 PR #302 交付的 PostgreSQL 18.6 + pgvector v0.8.6 增强版;文中函数签名与 SQL 语义已与 OpenTenBase master 源码及回归测试逐句核对,标注"待验证"的演示结果将于真实端点实测后回填截图,回填前本文不发布。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、背景:为什么要把 AI 调用搬进数据库?
  • 二、3 分钟看懂设计:模型注册背后的三个决策
  • 三、上手第一步:注册你的第一个模型
  • 四、核心演示:一条 SQL 跑通摘要 + 文本分类
  • 五、mock 能证明什么:httpbin 验证的边界
  • 六、进阶实战:AI + pgvector 搭一个库内 RAG
  • 七、踩坑 FAQ
  • 八、总结与展望
  • 参考链接
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档