解药不甜SM

本节目标:把跑这条流水线需要的三个组件装好、连通。

读完,你会有一个「一条命令就能验证连通」的环境。

预计耗时 15~20 分钟,大部分时间在等解析模型下载。


一、三个组件

跑通最小问答,本质上要让三个角色凑齐:

组件是什么跑在哪
🟦 主程序我们写的 TS 代码,串起整条流水线你的电脑,Node 运行
🟩 向量库带 pgvector 扩展的 PostgresSupabase 云端(本课主库,免装)
🐍 解析服务MinerU 封装成的 HTTP 服务本地 Python 进程
☁️ 云端模型嵌入模型 + 大模型经 API 调用,不在本地跑

三个角色,三种取舍,各有原因。

模型为什么走云端 API、不本地跑?

本地跑大模型对显卡要求高。

而嵌入 / 生成 API 又便宜又快,对独立开发者最省运维成本。

向量库为什么走 Supabase?

它就是托管版的 Postgres + pgvector——注册即用、免装免运维、跨平台,免费层做演示绰绰有余。

本课就把它定为唯一主库:后面建索引、入库、检索的每一行代码、每一条 SQL,都跑在这套 Supabase 上。

它对接的是标准 Postgres,所以真要私有化、离线部署,本地起个 Docker pgvector 也能平替、只改连接串——但那是边界场景,正文一律以 Supabase 为准,细节见文末附录。

解析服务为什么本地跑?

因为 MinerU 免费、中文表格识别最强,且我们要借它讲「Python 即服务」的架构。


二、前置清单

开工前确认:

  • Node.js 20+node -v 检查)
  • 一个 Supabase 账号(免费,下面讲怎么建库)
  • Python 3.10+(给 MinerU 用,python3 --version
  • 两个 API Key(下面讲怎么拿)

本课主库走 Supabase,不需要装 Docker(私有化 / 离线平替见文末附录,那才需要 Docker Desktop)。

API Key:嵌入与生成分开拿

本课用了两个国内服务,各司其职:

用途服务拿 Key 的地方
嵌入(BGE-large-zh)硅基流动 SiliconFlowsiliconflow.cn 注册 → API 密钥
大模型(对话生成)DeepSeekplatform.deepseek.com → API keys

两者都是 OpenAI 兼容接口。

所以代码里用同一套 @ai-sdk/openai-compatible 就能接,换服务只改 baseURL

🔒 安全红线(贯穿全课)

Key 一律放 .env,绝不写进代码、绝不提交到 Git。

仓库里只留一份不含真实值的 .env.example 作模板。


三、搭建向量库

不用装任何东西,三步拿到一个带 pgvector 的云端 Postgres。

1、建项目

登录 supabase.com → New project,选一个离你近的区域,设置数据库密码(记牢,等下要用)。

等 1~2 分钟项目初始化完成。

2、开 vector 扩展

进项目 → Database → Extensions,搜索 vector,点开启。

这一步让 Postgres 具备向量检索能力——Supabase 后台用的正是 pgvector。

3、复制连接串

Project Settings → Database → Connection string,选 URI 那一栏,复制出来,形如:

postgresql://postgres:[你的密码]@db.xxxxx.supabase.co:5432/postgres

[你的密码] 替换成第 1 步设的密码。

这串就是下一步要填进 .envPOSTGRES_CONNECTION_STRING

建表、写入、查询的 SQL 和代码,对接的都是标准 Postgres。

所以这串连接串就是本课主库的入口;真要搬到自建服务器或本地,也只改这一串(私有化 / 离线见文末附录),其余代码完全不动。


四、环境变量

把模板复制一份成 .env,填进你自己的 Key 和连接串:

cp .env.example .env

.env 的关键字段(值是示意,填你自己的):

# 向量库:粘贴你刚从 Supabase 主库复制的连接串(把 [密码] 换成真实密码)
POSTGRES_CONNECTION_STRING=postgresql://postgres:你的密码@db.xxxxx.supabase.co:5432/postgres
# 私有化 / 离线时改用本地 Docker pgvector(见文末附录):postgresql://finrag:finrag@127.0.0.1:5433/finrag

# 嵌入:硅基流动 BGE-large-zh,1024 维
EMBED_BASE_URL=https://api.siliconflow.cn/v1
EMBED_API_KEY=sk-你的硅基流动key
EMBED_MODEL=BAAI/bge-large-zh-v1.5
EMBED_DIM=1024

# 大模型:DeepSeek
LLM_BASE_URL=https://api.deepseek.com/v1
LLM_API_KEY=sk-你的deepseek-key
LLM_MODEL=deepseek-chat

# 解析服务地址(下一步起)
PARSER_URL=http://127.0.0.1:8000

PARSER_URL127.0.0.1 而不是 localhost,是有原因的。

Node 在某些系统会把 localhost 解析成 IPv6 的 ::1,而服务监听的是 IPv4。

这个坑 1.3 还会再提。

代码侧用 zod 在启动时校验这些变量(src/lib/config.ts)。

缺了或填错会直接报错退出,而不是等跑到一半才崩——这就是「系统边界先校验」。


五、启动解析服务

MinerU 是 Python 包,我们把它封装成一个 FastAPI 服务(services/parser/app.py),对外只暴露一个 POST /parse 接口:

cd services/parser
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt          # 装 mineru + fastapi(首次较慢)

# 起服务(首次会下载 MinerU 模型,一次性)
export MINERU_CMD="$(pwd)/.venv/bin/mineru"
uvicorn app:app --port 8000 --host 127.0.0.1

验证它活着:

curl http://127.0.0.1:8000/health
# {"ok":true}

⚠️ 首次启动会下载模型(几百 MB,可能要几分钟)

这是一次性的,之后秒起。

如果看到 ModuleNotFoundError,十有八九是用了系统全局的 uvicorn 而不是 venv 里的——一定要确认走的是 .venv/bin/uvicorn


六、验证全链路

仓库准备了两个「冒烟测试」脚本,在写业务代码前先确认基础设施 OK:

npx tsx scripts/smoke-db.ts          # 测向量库:建索引 / 写入 / 带过滤查询
npx tsx scripts/smoke-providers.ts   # 测云端:嵌入返回 1024 维 + 大模型能应答

两个都绿了,实验台就算搭好了。


小结

1、三个组件凑齐

主程序 (TS) + 向量库 (Supabase / pgvector) + 解析服务 (MinerU),外加云端嵌入 / 大模型。

2、向量库定为 Supabase 主库

免装、跨平台、免费层够用,本质是托管的 Postgres + pgvector;私有化 / 离线才换本地,只改连接串。

3、Key 走 .env,启动即校验

绝不进代码 / Git;用 zod 在边界校验,缺了就快速失败。

4、先冒烟、再写业务

别在地基未夯实时就盖楼——两个冒烟脚本绿了才动手。


附录:Docker pgvector 平替(私有化 / 离线)

本课主库是 Supabase。

只有私有化、离线、不依赖云这几种边界场景,才用这个本地平替——日常学习直接走主库即可,可跳过本节。

用 Docker 起一个本地 pgvector,代码和 SQL 与 Supabase 完全一致,只换连接串。

前置:Docker Desktop 已安装并启动(docker ps 不报错)。

仓库里已写好 docker-compose.yml,一条命令起库:

docker compose up -d        # 后台起 pgvector,默认映射到本机 5433 端口
docker ps                   # 看到 finrag-db 在 running 即可

然后把 .env 里的连接串换成本地的:

POSTGRES_CONNECTION_STRING=postgresql://finrag:finrag@127.0.0.1:5433/finrag

这里有两个本地细节坑:

坑 1:端口用 5433 而非默认 5432。 避免和你本机可能已有的 Postgres 撞端口。

坑 2:地址用 127.0.0.1 而非 localhost Node 在某些系统会把 localhost 解析成 IPv6 的 ::1,而容器监听的是 IPv4。

换好连接串后,后续步骤(冒烟测试、入库、问答)与主线完全相同。

1.2 实验台

课件下载

本节暂无配套课件