新闻详情

新闻详情

首页 / 资讯中心 / 详情

pgai 代码生成机制解析:如何从 PostgreSQL 函数目录自动生成 CreateVectorizer 配置数据类

发布时间:2026/9/17 14:36:32来源:尧图网络
pgai 代码生成机制解析:如何从 PostgreSQL 函数目录自动生成 CreateVectorizer 配置数据类
pgai 代码生成机制解析如何从 PostgreSQL 函数目录自动生成 CreateVectorizer 配置数据类【免费下载链接】pgaiA suite of tools to develop RAG, semantic search, and other AI applications more easily with PostgreSQL项目地址: https://gitcode.com/GitHub_Trending/pg/pgai在 pgai 的 Python SDK 中CreateVectorizer 及其一系列配置数据类如 EmbeddingOpenaiConfig并不是手写维护的而是由 generate 模块 通过查询已安装 pgai 扩展的数据库目录自动生成的。本文基于 generate 模块的 README深入解析这套“以数据库函数签名为唯一事实来源Single Source of Truth”的代码生成机制当你扩展了aischema 下的函数接口后如何在本地启动一个装有 pgai 的 PostgreSQL用一条uv run generate命令同步刷新全部 Python 参数类并理解其底层元数据解析与模板渲染的完整链路。一、模块定位为什么需要“生成”而不是“手写”pgai 的向量化Vectorizer功能在数据库侧由ai.create_vectorizer()函数承载它接受loading、parsing、embedding、chunking、indexing、formatting、scheduling、processing、destination等一系列命名参数每个参数对应aischema 下一个独立的“配置构造函数”例如ai.embedding_openai(model, dimensions, ...)。在 Python 侧开发者希望以类型安全的 dataclass 来描述这些参数from pgai.vectorizer import CreateVectorizer from pgai.vectorizer.configuration import ( ChunkingCharacterTextSplitterConfig, DestinationTableConfig, EmbeddingOpenaiConfig, ) config CreateVectorizer( sourcepublic.documents, embeddingEmbeddingOpenaiConfig( modeltext-embedding-ada-002, dimensions1536, api_key_nameopenai_api_key, ), destinationDestinationTableConfig( target_schemavectorizer, target_tabledocument_embeddings, ), )如果这些 dataclass 全部手写那么每当数据库侧的函数签名新增参数、修改类型、增加默认值发生变化时Python 侧就存在失配风险。generate 模块的 README 明确说明了该模块的动机当扩展的接口发生变化时运行生成脚本即可更新 configuration.py 与 create_vectorizer.pyREADME 中旧称vectorizer_params.py里的数据类无需手工维护。这也体现在两个生成文件的文件头注释中This file is generated by the configuration generator in generate/config_generator.py. Do not modify by hand.也就是说configuration.py 和 create_vectorizer.py 属于“禁止手改”的生成产物手改会在下次生成时被覆盖。二、运行方式前置环境与命令2.1 前置启动装有 pgai 的 PostgreSQL生成脚本本身不内置任何函数签名数据而是实时查询一个已经安装了 pgai 扩展的数据库的pg_catalogpg_proc、pg_type、pg_namespace等系统目录表。因此运行前必须先有一个可用的数据库。README 给出的做法是先在本目录启动一个装有 pgai 的 PostgreSQL监听 5432 端口例如使用 generate 目录下的 docker-compose 文件name: pgai services: db: build: context: ../../../../extension dockerfile: Dockerfile target: pgai-test-db environment: POSTGRES_PASSWORD: postgres ports: - 5432:5432 volumes: - data:/var/lib/postgresql/data该 compose 文件以仓库中的 extension/Dockerfile 为构建上下文、pgai-test-db为目标镜像即“PostgreSQL pgai 扩展”的测试数据库端口映射5432:5432密码为postgres。2.2 执行生成命令数据库就绪后在 projects/pgai 目录下执行uv run generategenerate之所以是一条独立命令是因为 pyproject.toml 的[project.scripts]中注册了该入口点[project.scripts] pgai pgai.cli:cli generate pgai.vectorizer.generate.generate:generate_models它指向 generate.py 的generate_models()函数其核心逻辑为def generate_models(): # Connect to database conn_str postgresql://postgres:postgreslocalhost:5432/postgres output_file Path(../../vectorizer/configuration.py) vectorizer_output_file Path(../../vectorizer/create_vectorizer.py) generate_vectorizer_configs(conn_str, output_file, vectorizer_output_file)这里可以确认几个实操要点连接串是硬编码的postgresql://postgres:postgreslocalhost:5432/postgres即默认用户postgres、密码postgres、主机localhost、端口5432、库名postgres。如果你的本地数据库凭据不同需要自行调整这一行这正是 README 强调“先在 5432 端口启动数据库”的原因。输出路径是相对路径../../vectorizer/configuration.py与../../vectorizer/create_vectorizer.py即覆盖 pgai/vectorizer/ 下的两个核心文件。生成前会先执行pgai.install(conn_str)generate_vectorizer_configs()的第一步是通过 Python 侧的pgai.install()把仓库中的 SQL 脚本安装进该数据库保证查询到的函数签名与当前代码库中的扩展定义一致而不是数据库里残留的旧版本。三、白名单机制VECTORIZER_FUNCTIONS 列表generate.py 中硬编码了VECTORIZER_FUNCTIONS列表第 15–41 行完整枚举了所有“允许暴露为向量化参数”的数据库函数VECTORIZER_FUNCTIONS [ loading_column, loading_uri, parsing_auto, parsing_none, parsing_pymupdf, parsing_docling, embedding_litellm, embedding_openai, embedding_ollama, embedding_voyageai, chunking_character_text_splitter, chunking_recursive_character_text_splitter, chunking_none, formatting_python_template, indexing_diskann, indexing_hnsw, indexing_default, indexing_none, scheduling_default, scheduling_none, scheduling_timescaledb, processing_default, destination_table, destination_column, ]README 对这一设计意图有明确说明脚本通过查询pg_catalog获取函数元数据但在generate.py中硬编码这份函数名清单目的是避免为那些本不该作为向量化参数使用的函数创建 dataclass例如aischema 下还有ai.moderate、ai.summarize等其他能力函数它们不在此列。README 同时给出了重要的维护约束“这也意味着这份清单必须保持最新”——每当数据库侧新增一个可用作向量化参数的函数比如新的embedding_*实现必须同步把它加入该列表否则生成结果中不会出现对应的配置类。list_vectorizer_functions()会将该白名单与系统目录求交只保留数据库中真实存在的函数query SELECT p.proname FROM pg_proc p JOIN pg_namespace n ON p.pronamespace n.oid WHERE n.nspname ai AND p.proname ANY(%s) ORDER BY p.proname 即白名单 ∩aischema 中实际存在的函数。这样既过滤了未安装的可选函数例如依赖额外扩展的函数又保证了顺序稳定、便于生成结果 diff。四、元数据解析从 pg_proc 到 Python 类型函数签名的抽取在 function_parser.py 中完成。4.1 读取函数参数信息get_function_metadata()对pg_proc发起查询取出每个函数的参数名proargnames、默认值数量pronargdefaults、参数类型 OID 列表proargtypes以及返回类型SELECT p.proname, n.nspname, p.proargnames, p.pronargdefaults, string_to_array(array_to_string(p.proargtypes, ), ) as argtypes, p.proallargtypes, p.proargmodes, t.typname as return_type, ... FROM pg_proc p JOIN pg_namespace n ON p.pronamespace n.oid JOIN pg_type t ON p.prorettype t.oid WHERE n.nspname ai AND p.proname ANY(%s) ORDER BY p.proname;随后对每个参数 OID 再查一次pg_type区分基本类型、基类型数组会解引用typelem以及是否为数组typtype a。4.2 必填参数的判定一个参数是否必填依据是它在函数定义中是否有默认值。Postgres 将默认值统一放在参数列表尾部因此源码用“默认值个数”反推count_of_default_params row[3] # pronargdefaults non_default_count param_count - count_of_default_params ... # A parameter is required if it has no default value is_required i non_default_count对应地生成出的 dataclass 字段中必填参数没有默认值可选参数标注 None例如已生成的 EmbeddingOllamaConfigdataclass class EmbeddingOllamaConfig(SQLArgumentMixin): Configuration for ai.embedding_ollama function. arg_type: ClassVar[str] embedding function_name: ClassVar[str] ai.embedding_ollama model: str dimensions: int base_url: str | None None options: dict[str, Any] | None None keep_alive: str | None None4.3 Postgres 类型到 Python 类型的映射PostgresParameter.python_type属性内置了一张类型映射表PostgreSQL 类型Python 类型text/namestrint4/int8intbool/booleanbooljsonbdict[str, Any]float8floatintervaltimedeltatimestamptzdatetime_textlist[str]_int4/_float8list[int]/list[float]regclassstr其他Any非必填字段会自动追加| None。这一映射直接解释了生成代码中 SchedulingTimescaledbConfig 为什么是schedule_interval: timedelta | None、LoadingUriConfig 的column_name是str必填字段——它们都源自数据库侧函数的真实签名。4.4 为 create_vectorizer 推导“配置类联合类型”read_create_vectorizer_metadata()对ai.create_vectorizer本身做了一层增强遍历它的每个参数跳过以_开头的内部参数如_trigger_column_name用前缀模式匹配查找该参数可接受的配置函数SELECT p.proname FROM pg_proc p JOIN pg_namespace n ON p.pronamespace n.oid WHERE n.nspname ai AND p.proname LIKE %s; -- 传入 embedding_%、chunking_% 等若参数embedding匹配到embedding_openai、embedding_ollama等函数就把它们转换为类名embedding_openai→EmbeddingOpenaiConfig并生成 Python 联合类型embedding: ( EmbeddingLitellmConfig | EmbeddingOllamaConfig | EmbeddingOpenaiConfig | EmbeddingVoyageaiConfig | None ) None这正是 create_vectorizer.py 中CreateVectorizer各配置字段的形态source为必填strname、queue_schema、grant_to、enqueue_existing等为普通标量参数而destination、loading、parsing等则为对应配置类的联合类型。新增一个embedding_*数据库函数后重新生成这个联合类型就会自动扩上去Python 侧无需改动。五、模板渲染与生成产物config_generator.py 用 Jinja2 模板把元数据渲染成两个文件。5.1 configuration.py每函数一个 Config 类TEMPLATE为白名单中的每个函数生成一个继承SQLArgumentMixin的 dataclass。类名的生成规则在模板过滤器中去掉ai.前缀、下划线转空格、首字母大写再拼回例如chunking_character_text_splitter→ChunkingCharacterTextSplitterConfig。其中两个 ClassVar 的生成逻辑为arg_type: ClassVar[str] {{ function.name|split(.)|last|split(_)|first }} function_name: ClassVar[str] {{ function.name }}即arg_type取函数名的第一个下划线前缀chunking、embedding……它恰好就是create_vectorizer的对应参数名function_name是完整的ai.xxx函数限定名。SQLArgumentMixin是所有配置类的公共基类提供to_sql_argument()遍历 dataclass 字段跳过arg_type/function_name与None值拼出, {arg_type} {function_name}(...)片段配套的format_sql_params()负责标量值的 SQL 格式化——布尔值转小写true/false、列表转ARRAY[...]、timedelta转为秒数 seconds的 interval 字面量、其余值加单引号。5.2 create_vectorizer.py顶层参数类与 to_sqlVECTORIZER_TEMPLATE则渲染 CreateVectorizer导入全部 Config 类按ai.create_vectorizer的真实参数生成字段必填无默认值、可选置None并生成to_sql()方法先写SELECT ai.create_vectorizer(source::regclass)再遍历字段——凡是SQLArgumentMixin实例调用其to_sql_argument()标量值按 bool / list / 字符串分别格式化。最终效果可以用 tests/vectorizer/test_create_vectorizer_sql.py 中的测试用例来验证例如config CreateVectorizer( sourcepublic.large_documents, loadingLoadingColumnConfig(column_namecontent), embeddingEmbeddingOpenaiConfig( modeltext-embedding-ada-002, dimensions1536 ), chunkingChunkingCharacterTextSplitterConfig( chunk_size1000, chunk_overlap100 ), indexingIndexingHnswConfig(m16, ef_construction100, opclassvector_l2_ops), processingProcessingDefaultConfig(batch_size100, concurrency4), schedulingSchedulingTimescaledbConfig(schedule_intervaltimedelta(hours1)), enqueue_existingTrue, destinationDestinationTableConfig( target_schemavectors, target_tablechunked_embeddings, ), )config.to_sql()应产生去除空白对比后SELECT ai.create_vectorizer( public.large_documents::regclass ,destinationai.destination_table(target_schemavectors,target_tablechunked_embeddings) ,loadingai.loading_column(column_namecontent) ,embeddingai.embedding_openai(modeltext-embedding-ada-002,dimensions1536) ,chunkingai.chunking_character_text_splitter(chunk_size1000,chunk_overlap100) ,indexingai.indexing_hnsw(opclassvector_l2_ops,m16,ef_construction100) ,schedulingai.scheduling_timescaledb(schedule_interval3600seconds) ,processingai.processing_default(batch_size100,concurrency4) ,enqueue_existingtrue )该测试同时覆盖最简配置只给source与完整配置两种场景确保生成代码的 SQL 拼装行为稳定。而生成类代码在框架层的另一个消费点是 alembic/operations.pyCreateVectorizerOp直接以关键字参数构造CreateVectorizer从而支持在 Alembic 迁移中以声明式方式创建向量化器。六、完整调用链与工程注意事项把整条链路串起来一次uv run generate的执行顺序为generate_models()generate.py#L73-L78读取硬编码连接串与两个输出路径generate_vectorizer_configs()先pgai.install(conn_str)将当前仓库的扩展 SQL 装入数据库再用psycopg连接list_vectorizer_functions()白名单与pg_proc求交得到实际存在的函数名get_function_metadata()批量抽取参数名、类型、默认值、返回值逐参数解析pg_type得到 Python 类型与必填标记generate_config_classes()渲染configuration.py含SQLArgumentMixin与全部*Config类read_create_vectorizer_metadata()generate_vectorizer_params()抽取create_vectorizer签名、推导配置联合类型渲染create_vectorizer.py。使用与扩展该机制时需注意的几点白名单必须与数据库函数同步这是 README 明确强调的人工维护点。新增了可用的向量化参数函数但忘记加入VECTORIZER_FUNCTIONS生成结果就不会包含对应 Config 类反之把内部函数加入白名单会污染公共 API。连接串与端口固定脚本假设localhost:5432、postgres/postgres。若使用 generate 目录的 docker-compose 起库该假设天然成立自定义环境时需先修改 generate.py 中的conn_str。不要手改生成文件configuration.py与create_vectorizer.py的文件头均标注 “Do not modify by hand”。要新增参数能力正确路径是先在 extension SQL 或 pgai/db/sql 中扩展数据库函数签名再重跑uv run generate让 Python 侧自动跟进并通过 test_create_vectorizer_sql.py 这类测试回归验证to_sql()输出。生成是覆盖式的两个输出文件整文件重写任何本地对生成文件的临时补丁都会丢失差异应体现在上游 SQL 定义中。七、小结pgai 的 generate 模块展示了一种典型的“数据库即契约”database-as-contract工程实践Python SDK 的参数模型不是静态编写的而是每次从装有 pgai 扩展的 PostgreSQL 系统目录中动态推导——函数名经白名单过滤参数名与类型经pg_proc/pg_type解析默认值决定必填性前缀匹配决定CreateVectorizer上的联合类型最终由 Jinja2 模板渲染成 dataclass 与 SQL 拼装逻辑。对使用者而言日常只需理解uv run generate这一入口及其前置的数据库环境对扩展贡献者而言掌握VECTORIZER_FUNCTIONS白名单的维护与“先改 SQL、后跑生成”的流程即可在扩展接口演进时安全地同步 Python 侧 API。【免费下载链接】pgaiA suite of tools to develop RAG, semantic search, and other AI applications more easily with PostgreSQL项目地址: https://gitcode.com/GitHub_Trending/pg/pgai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

dlt 自学课程指南:从零基础到高级数据工程师的两阶段实战路线 2026/9/17 15:18:44

dlt 自学课程指南:从零基础到高级数据工程师的两阶段实战路线

dlt 自学课程指南:从零基础到高级数据工程师的两阶段实战路线 【免费下载链接】dlt data load tool (dlt) is an open source Python library that makes data loading easy 🛠️ 项目地址: https://gitcode.com/GitHub_Trending/dl/dlt dlt&…

阅读更多 →
GEO实操指南:如何让豆包在AI回答中优先引用你的内容 2026/9/17 15:18:44

GEO实操指南:如何让豆包在AI回答中优先引用你的内容

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
数据驱动的初三化学总复习教案:从JSON配置到Word自动生成 2026/9/17 15:18:44

数据驱动的初三化学总复习教案:从JSON配置到Word自动生成

简介:在教学资源数字化背景下,数据驱动的复习备课成为提升效率与精准度的重要方法。将复习内容按知识模块结构化,利用JSON配置文件管理模块权重、考点与薄弱点,再通过Python脚本与python-docx自动生成Word教案,形成“诊…

阅读更多 →
GPU加速数字信道化:实时频谱监测的CUDA工程实践 2026/9/17 15:18:44

GPU加速数字信道化:实时频谱监测的CUDA工程实践

简介:本资源是一份面向通信工程、信号处理领域高校师生及工程师的专业技术文档,聚焦GPU加速的数字信道化设计这一前沿课题,解决传统硬件在多信道并发处理与高吞吐量场景下的性能瓶颈问题。文档系统阐述多相滤波器组原理、50%重叠子信道设计、…

阅读更多 →
K8S核心三件套:Pod、Deployment、Service与Spring AI部署实战 2026/9/17 15:18:44

K8S核心三件套:Pod、Deployment、Service与Spring AI部署实战

1. 先别急着敲命令,搞懂 K8S 到底在解决什么聊 K8S 之前,我想先吐槽一个特别常见的现象:网上铺天盖地的部署教程,一上来就让你kubectl create deployment,结果你照抄跑通了,但 Pod 换个 IP 服务就断&#x…

阅读更多 →
LDO设计原理与关键技术:从线性稳压到系统级电源治理 2026/9/17 15:15:44

LDO设计原理与关键技术:从线性稳压到系统级电源治理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞