ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

foundational RAG Agent 实战:用 Pydantic AI + Supabase pgvector 构建零外部库的文档问答系统

foundational RAG Agent 实战:用 Pydantic AI + Supabase pgvector 构建零外部库的文档问答系统 foundational RAG Agent 实战用 Pydantic AI Supabase pgvector 构建零外部库的文档问答系统【免费下载链接】ottomator-agentsAll the open source AI Agents hosted on the oTTomator Live Agent Studio platform!项目地址: https://gitcode.com/GitHub_Trending/ot/ottomator-agents本文围绕 foundational-rag-agent 项目的规划文档与真实实现系统讲解如何用 Pydantic AI 搭建一个检索增强生成RAG智能体从本地 TXT/PDF 文档摄入、OpenAI 向量化、Supabase pgvector 语义检索到带知识库搜索工具的 Agent 与 Streamlit 对话界面完整覆盖架构设计、建表 SQL、核心源码链路与测试验证读者可据此在 oTTomator Live Agent Studio 生态中复现一个可运行、可扩展的 RAG 应用。一、项目定位一个简单但完整的 RAG 基线PLANNING.md 将本项目定位为最简单的端到端 RAG 实现不引入 LangChain 等重型编排框架而是直接用 Pydantic AI 定义 Agent用 Supabase pgvector 做向量存储与语义检索用纯 Python 手写分块逻辑。其核心目标是让开发者能看懂、能修改、能复现一条完整的 RAG 链路并作为后续复杂 Agent 项目多步检索、图谱 RAG、自反思 RAG 等的基线。规划文档明确给出系统的四大核心组件文档摄入管道Document Ingestion Pipeline接收本地 TXT/PDF 文件不依赖外部分块库用简单文本处理与滑动窗口分块调用 OpenAI embeddings API 生成向量写入 Supabase。Supabase 数据库基于 pgvector 存储文档分块与向量支持语义搜索表结构通过 Supabase MCP server 创建与管理。Pydantic AI Agent定义知识库查询工具使用 OpenAI 模型生成回复并把检索结果整合进回答。Streamlit UI提供文档上传与 AI 对话界面展示回复内容。对应技术栈同样来自规划文档层次选型语言Python 3.11Agent 框架Pydantic AI数据库Supabase pgvector 扩展向量模型OpenAI embeddings API默认 text-embedding-3-small1536 维LLMOpenAI默认 gpt-4.1-mini可通过OPENAI_MODEL切换UIStreamlit文档解析PyPDF2 提取 PDF 文本依赖清单与上述选型一一对应见 requirements.txtpydantic-ai、supabase、openai、PyPDF2、streamlit、python-dotenv、numpy、pytest、pytest-asyncio。二、数据库层pgvector 表结构与 match_rag_pages 检索函数规划文档要求通过 Supabase MCP server 创建和管理表。项目把完整建表 SQL 固化在 rag-example.sqldatabase/setup_db.py 中还有一份同源的SQL_SETUP常量可直接通过mcp2_apply_migration(namerag_setup, querySQL_SETUP)之类的 MCP 调用执行。2.1 核心表 rag_pagescreate extension if not exists vector; create table rag_pages ( id bigserial primary key, url varchar not null, chunk_number integer not null, content text not null, metadata jsonb not null default {}::jsonb, embedding vector(1536), created_at timestamp with time zone default timezone(utc::text, now()) not null, unique(url, chunk_number) );字段设计要点urlchunk_number标识文档来源 分块序号联合唯一约束防止同一文档重复摄入配合unique(url, chunk_number)。content分块原文是最终返回给 Agent 的检索内容。metadataJSONB 类型的扩展字段摄入管道会自动写入文件名、文件大小、处理时间、source、source_type等见 ingestion.py也支持自定义业务元数据。embedding vector(1536)维度与 OpenAItext-embedding-3-small输出一致由 embeddings.py 中的embedding_dim 1536确认。2.2 检索性能索引create index on rag_pages using ivfflat (embedding vector_cosine_ops); create index idx_rag_pages_metadata on rag_pages using gin (metadata); CREATE INDEX idx_rag_pages_source ON rag_pages ((metadata-source));三层索引分工明确ivfflat近似最近邻索引支撑大规模向量检索余弦距离GIN 索引加速 metadata 的 JSONB 过滤(metadata-source)表达式索引让按来源筛选source_filter走索引而非全表过滤。2.3 match_rag_pages 相似度检索函数create or replace function match_rag_pages ( query_embedding vector(1536), match_count int default 10, filter jsonb DEFAULT {}::jsonb ) returns table ( id bigint, url varchar, chunk_number integer, content text, metadata jsonb, similarity float ) language plpgsql as $$ #variable_conflict use_column begin return query select id, url, chunk_number, content, metadata, 1 - (rag_pages.embedding query_embedding) as similarity from rag_pages where metadata filter order by rag_pages.embedding query_embedding limit match_count; end; $$;该函数是语义检索的核心是 pgvector 的余弦距离运算符1 - distance将其换算为 similarity越接近 1 越相关metadata filter利用 JSONB 包含语义实现可选过滤例如{source: xxx.pdf}时仅检索该来源limit match_count控制返回条数默认 10。调用方可通过 RPC 传入这三个参数。2.4 行级安全策略SQL 末尾为rag_pages启用了 RLS并创建了公共只读策略setup_db.py中的版本还额外包含允许插入的策略。这意味着在生产 Supabase 项目中前端/服务端密钥可直接读取该表为 Streamlit 等客户端直接写入提供了权限基础——同时提醒读者如果要在公网暴露写入能力应根据实际场景收紧 RLS 策略。三、文档摄入管道从文件到向量的完整链路规划文档强调构建不依赖复杂库的简单文档摄入管道。该管道由四个模块组成实际调用关系为processors提取文本→chunker切分→embeddings向量化→ingestion编排并入库。3.1 文本提取TXT 与 PDF 双处理器processors.py 定义DocumentProcessor抽象基类与两个实现TxtProcessor按[utf-8, latin-1, cp1252, ascii]依次尝试解码解决中文等非 UTF-8 文本的乱码/报错问题元数据中包含line_count、word_count。PdfProcessor用 PyPDF2 逐页提取并为每页注入[Page X of Y]页标记processors.py让检索结果天然携带页码信息便于溯源同时解析 PDF 内置的 title/author/subject 等元数据。入口函数get_document_processor(file_path)按扩展名分发当前支持.txt、.pdf未知类型返回None扩展点清晰——增加新格式只需在processors字典中注册。3.2 分块零依赖的滑动窗口实现chunker.py 的TextChunker默认chunk_size1000、chunk_overlap200这是摄入管道在 ingestion.py 中实际使用的取值。实现要点文本长度不超过chunk_size时整体作为一个块返回超过时按step_size chunk_size - chunk_overlap滑动切分相邻块共享 200 字符重叠区避免语义在边界被截断自动兜底chunk_overlap被限制不超过chunk_size // 2chunker.py且step_size最小 100 字符防止死循环另外提供chunk_by_separator(text, \n\n)按段落优先切分先按空行分段段落超限再降级用滑动窗口拆分兼顾语义完整性与长度约束。上述边界行为overlap 钳制、短文本单块、段落切分在 test_chunker.py 中都有对应单测覆盖。3.3 向量化带重试与批处理的 EmbeddingGeneratorembeddings.py 的EmbeddingGenerator模型默认text-embedding-3-small可用环境变量EMBEDDING_MODEL覆盖embed_text内置 3 次重试与 2 的指数退避超长文本8000 字符先截断再调用空文本返回 1536 维零向量作为降级方案embeddings.pyembed_batch按batch_size5小批处理批间 sleep 0.5s 缓解限流单条失败不影响整批embeddings.py。3.4 编排DocumentIngestionPipelineingestion.py 的DocumentIngestionPipeline串联上述步骤并做了工程化防护文件校验默认max_file_size_mb 10超限或不存在直接拒绝流程顺序校验 → 选处理器 → 提取文本 → 分块 → 批量向量化 → 组装 metadata → 逐块写入 Supabase元数据注入自动补充filename、file_path、file_size_bytes、processed_at、chunk_count并写入source、source_type等检索侧字段来源标识文件以file://{filename}作为url纯文本输入以text://{source_id}标识与数据库unique(url, chunk_number)约束配合防重支持process_text直接处理字符串供 UI 之外的场景复用与process_batch批量文件逐文件隔离异常。四、Agent 层Pydantic AI 工具式知识库检索规划文档要求定义一个工具查询知识库、用 OpenAI 模型生成回复。Agent 层拆成三个文件职责清晰。4.1 工具定义KnowledgeBaseSearchtools.py 用 Pydantic 模型定义了工具的入参与出参这是 Pydantic AI 工具模式的核心——Agent 通过 schema 自动理解工具如何被调用KnowledgeBaseSearchParamsquery检索语句必填、max_results默认 5、source_filter可选限定检索单一来源KnowledgeBaseSearchResultcontent、source、source_type、similarity、metadata保证返回结构稳定便于后续渲染与溯源。KnowledgeBaseSearch.search的内部调用链tools.pyembed_text(query) → 生成查询向量 → supabase.search_documents(query_embedding, match_count, filter_metadata) → client.rpc(match_rag_pages, params) # 见 database/setup.py#L108 → 组装 KnowledgeBaseSearchResult 列表其中source_filter会转换为{source: ...}的 metadata 过滤传给 SQL 函数metadata filter。这条工具 → RPC → pgvector 函数的调用链是整篇架构里最关键的连通点在 test_agent_tools.py 中通过 mock 验证了参数传递的正确性包括无过滤与带source_filter两种路径。4.2 Agent 组装RAGAgentagent.py 中的RAGAgent完成三件事self.search_tool Tool(self.kb_search.search) self.agent Agent( fopenai:{self.model}, system_promptRAG_SYSTEM_PROMPT, tools[self.search_tool] )模型字符串采用 Pydantic AI 的openai:{model}约定model默认取自OPENAI_MODEL缺省gpt-4.1-mini搜索工具通过Tool(...)注册进 AgentLLM 会在需要时自主调用它query(question, max_results5, source_filterNone)方法负责执行对话并解析结果运行agent.run(question, depsdeps)后从result.tool_calls中提取名为search的工具调用结果与模型输出一起打包返回{response, kb_results}模块底部还创建了单例agent RAGAgent()供 UI 直接导入。依赖通过AgentDepsTypedDict 注入kb_search保持工具与 Agent 松耦合。4.3 系统提示词检索结果的使用纪律prompts.py 的RAG_SYSTEM_PROMPT为 LLM 定义了 6 条行为准则直接决定回答质量检索结果与问题相关时必须优先使用引用知识库信息时需提及文档名可追溯知识库无相关内容时回退到通用知识不知道就诚实承认不编造回答简洁、切题用 Markdown 格式化提升可读性。这套提示词在知识库优先 兜底回答 明确溯源之间取得平衡是 RAG 应用防幻觉的关键一层。五、Streamlit UI上传与对话一体ui/app.py 是规划文档中上传文档、查询 Agent、展示回复三个界面目标的落地实现侧边栏文档上传st.file_uploader限定[txt, pdf]且支持多文件通过文件名 内容 hash生成file_id并记录在processed_files会话集合中实现重复上传自动跳过非阻塞处理把 CPU 密集的摄入逻辑放进loop.run_in_executor线程池ui/app.py避免卡死 Streamlit 主线程上传文件先写入临时文件再交给管道处理完立即os.unlink清理文档统计侧边栏用st.metric展示知识库中文档数来自count_documents()并列出get_available_sources()返回的可用来源流式对话通过rag_agent.agent.iter(...)结合PartStartEvent/PartDeltaEvent逐 token 渲染ui/app.py聊天历史保存在st.session_state.messages并持久化为 Pydantic AI 的ModelRequest/ModelResponse消息支持多轮上下文页面级入口streamlit run ui/app.py直接启动README.md。六、环境配置四个关键变量规划文档要求提供.env.example作为模板变量如下变量用途默认值/说明OPENAI_API_KEY向量生成与 LLM 调用必填缺失时相关模块直接抛错见 agent.pyOPENAI_MODELAgent 使用的 LLMgpt-4.1-mini可按需替换SUPABASE_URLSupabase 实例地址必填SUPABASE_KEYSupabase API Key必填与SUPABASE_URL一起在 setup.py 校验补充说明来自源码事实EMBEDDING_MODEL也是有效变量默认text-embedding-3-small见 embeddings.py。各模块统一从项目根目录.env加载且load_dotenv(dotenv_path, overrideTrue)会强制覆盖已有环境变量agent.py保证本地配置优先。建议按 README 的步骤创建虚拟环境 →pip install -r requirements.txt→ 复制.env.example为.env并填写 → 执行rag-example.sql建表 →streamlit run ui/app.py。七、开发流程、设计原则与测试验证7.1 任务式开发路径规划文档给出 7 步顺序化开发流程与仓库实际落地一一对应搭建项目结构agent/、database/、document_processing/、ui/、tests/五个包用 Supabase MCP server 建表SQL 固化在rag-example.sql/setup_db.py实现文档摄入管道processors → chunker → embeddings → ingestion创建带知识库搜索工具的 Pydantic AI Agenttools.py → agent.py开发 Streamlit UIui/app.py连通各组件工具 RPC 调用match_rag_pages是连通关键测试完整系统。任务进度在 TASK.md 中跟踪这也是规划文档 Notes 中每完成一个任务就标记约定的体现。7.2 四条设计原则的源码印证原则源码体现模块化Modularity摄入、数据库、Agent、UI 分属四个包通过构造器注入依赖如KnowledgeBaseSearch(supabase_client, embedding_generator)可单独替换实现简洁Simplicity分块不引第三方库纯 Python 滑动窗口配置集中于.env性能Performanceivfflat 向量索引、GIN metadata 索引、批量嵌入、批间限流用户体验UX上传进度条、重复文件跳过、流式输出、来源列表展示7.3 测试覆盖tests/ 下四个测试文件test_chunker.py、test_processors.py、test_agent_tools.py、test_agent.py采用 pytest pytest-asyncio分块器默认/自定义参数、overlap 超限钳制、短文单块、长文多块覆盖全文、段落切分与超长段落降级test_chunker.py搜索工具以MagicMock隔离 Supabase 与 Embedding验证query_embedding、match_count、filter_metadata三类参数正确传递以及无结果空返回、来源过滤test_agent_tools.py处理器与 Agent验证 TXT/PDF 文本提取与 Agent 查询封装逻辑。这种mock 外部依赖、聚焦参数契约的测试风格恰好印证了模块化设计带来的可测试性。八、预期产出与扩展方向按规划文档的Expected Output系统最终交付的能力是用户上传本地 TXT/PDF 构建知识库 → 向 Agent 提问 → 获得融合知识库信息的带来源回答。该基线仓库README 以 MIT 协议开源在 oTTomator-agents 仓库中的定位是foundational——后续若要演进可参考仓库中其他项目的思路在其上叠加多路检索与重排、知识图谱增强、自反思式 RAG 等而本文所述的建表、摄入、工具、UI 四层骨架可以原样复用。提示本文所有行为均基于仓库当前源码与 SQL 事实含rag-example.sql、database/setup_db.py的双份同源建表脚本如你所在 Supabase 项目的 RLS 策略与密钥权限与公共只读策略不同请先核对rag_pages表的访问策略再上线使用。【免费下载链接】ottomator-agentsAll the open source AI Agents hosted on the oTTomator Live Agent Studio platform!项目地址: https://gitcode.com/GitHub_Trending/ot/ottomator-agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表