部署蓝图 · single-vps RAG stack

在一台 VPS 上搭建
金融机构知识库 RAG 服务

500 家中国大陆金融机构 · 公开信息检索问答系统。小数据量、单机、可落地的轻量方案。

规模 ~500 docs 向量库 ChromaDB 嵌入 bge-large-zh 框架 LlamaIndex 服务 FastAPI
01

为什么不用 OceanBase

// 选型先做减法

500 家机构、即使每家几页资料,全部文本也就 几 MB 到几十 MB。这个量级用分布式数据库属于杀鸡用牛刀——部署、运维、资源占用都不划算。单台 VPS 配一个本地向量库就完全够用,且零运维成本。

组件选择理由
向量库ChromaDB纯本地、零运维,小规模绰绰有余;若已有 Postgres 可换 pgvector
Embeddingbge-large-zh中文金融文本效果好;嫌本地慢可改用通义 / OpenAI 嵌入 API
LLMAPI 调用DeepSeek / 通义 / OpenAI;VPS 不本地跑大模型
框架LlamaIndex把爬取 → 切分 → 嵌入 → 检索 → 生成串成一条流水线
接口FastAPI对外暴露一个查询端点
02

整体数据流

// pipeline overview

爬取 ──▶ 清洗 ──▶ 切分 chunk ──▶ 向量化 embedding ──▶ 存入向量库 查询 ──▶ 检索 Top-K ──▶ 拼接 prompt ──▶ LLM 生成答案 + 来源引用
03

爬取前的合规边界

// 先读这一段,再写爬虫

⚠ 合规提醒

只爬取官网与公开监管披露(金融监管总局、证监会、央行等公示信息);遵守目标站点的 robots.txt;控制请求频率;不爬登录后 / 付费 / 明确禁止抓取的内容;不采集个人隐私数据。优先使用官方公开数据源或开放接口,比公开爬取更稳妥。

04

环境准备

// dependencies

bash
pip install chromadb sentence-transformers llama-index \
    llama-index-vector-stores-chroma \
    llama-index-embeddings-huggingface \
    llama-index-llms-openai-like \
    fastapi uvicorn requests beautifulsoup4
05

第一步 · 爬取与整理

// crawler.py — 示意,按实际数据源调整

python
import requests, time, json
from bs4 import BeautifulSoup

def fetch_institution(name, url):
    # 务必先看 robots.txt,加 headers、限速
    headers = {"User-Agent": "Mozilla/5.0 (research; contact: you@example.com)"}
    r = requests.get(url, headers=headers, timeout=15)
    r.encoding = r.apparent_encoding
    soup = BeautifulSoup(r.text, "html.parser")
    text = soup.get_text(separator="\n", strip=True)
    time.sleep(2)  # 限速,做个有礼貌的爬虫
    return {"name": name, "url": url, "content": text}

# institutions 来自你的清单 [{name, url}, ...]
docs = [fetch_institution(i["name"], i["url"]) for i in institutions]
json.dump(docs, open("data.json", "w"), ensure_ascii=False, indent=2)
06

第二步 · 切分 · 嵌入 · 入库

// build_index.py — 一次性建库

python
import chromadb
from llama_index.core import Document, VectorStoreIndex, StorageContext
from llama_index.core.node_parser import SentenceSplitter
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
import json

embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-large-zh-v1.5")

docs = json.load(open("data.json"))
documents = [
    Document(text=d["content"], metadata={"name": d["name"], "url": d["url"]})
    for d in docs
]

client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_or_create_collection("fin_institutions")
vector_store = ChromaVectorStore(chroma_collection=collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)

index = VectorStoreIndex.from_documents(
    documents,
    storage_context=storage_context,
    embed_model=embed_model,
    transformations=[SentenceSplitter(chunk_size=512, chunk_overlap=64)],
)
07

第三步 · 查询服务

// main.py — FastAPI + LLM

python
from fastapi import FastAPI
from llama_index.core import Settings
from llama_index.llms.openai_like import OpenAILike

# 接 DeepSeek / 通义 等兼容 OpenAI 协议的 API
Settings.llm = OpenAILike(
    model="deepseek-chat",
    api_base="https://api.deepseek.com/v1",
    api_key="YOUR_KEY",
    is_chat_model=True,
)
Settings.embed_model = embed_model   # 与建库时同一个模型

app = FastAPI()
query_engine = index.as_query_engine(similarity_top_k=5)

@app.get("/ask")
def ask(q: str):
    resp = query_engine.query(q)
    return {
        "answer": str(resp),
        "sources": [n.metadata for n in resp.source_nodes],
    }
bash · 启动
uvicorn main:app --host 0.0.0.0 --port 8000

# 访问
http://你的VPS:8000/ask?q=某某银行的注册资本是多少
08

VPS 配置建议

// sizing & hardening

✦ 后续优化

数据量大了再考虑:重排序(bge-reranker)、混合检索(向量 + BM25 关键词)、给 chunk 加结构化 metadata 以便按机构类型 / 地区过滤。现在这个量级不用管。