LobeChat v2 无导出按钮?从 PostgreSQL 直接捞回你的对话数据
前言:发现 LobeChat v2 导不出数据
事情是这样的。我用 LobeChat v2 半年多了,攒了 500 多个对话主题、五千多条消息 —— 技术部署、亚马逊运营、踩坑记录,什么都有。某天想把这些对话导出来当自己知识库,结果打开设置一看:
数据存储 → 只有「导入数据」,没有「导出」。
翻 GitHub,Issue #10793已经被官方关闭为 「不计划修复」——LobeHub 云版就是不给导出按钮。评论区里有人骂:「118 刀买了年付版发现导不出来,客服邮件也不回。」
坦率讲,这体验确实让人不爽。但数据在你自己的数据库里,又不是加密锁死的。只要你用的是服务端数据库模式(Vercel + PostgreSQL),直接连库捞出来就是了。
这篇文章就记录全过程 —— 从找到数据库连接,到把 5,565 条消息按主题输出为 Markdown,再到喂进 Open NotebookLM 做 AI 检索。
LobeChat v2 数据存在哪
先搞清楚模式。LobeChat v2 有两种存储方式:
| 模式 | 数据位置 | 适用场景 |
|---|---|---|
| 客户端模式 | 浏览器 IndexedDB | 纯前端部署,无后端数据库 |
| 服务端数据库模式 | PostgreSQL | Docker Compose / Vercel + 外部 PG |
本文针对的是服务端数据库模式—— 你的数据在 PostgreSQL 里。以 Vercel 部署为例,LobeChat 默认用 Neon的免费 PostgreSQL。
如果你的部署方式不同(Docker Compose、直接连自建 PG),思路一样,只是连接参数有差异。
找到数据库连接
进 Vercel Dashboard → 你的项目 → Settings → Environment Variables,找到 DATABASE_URL:
postgresql://neondb_owner:***@ep-xxx-pooler.us-east-1.aws.neon.tech/neondb?sslmode=requireNeon 还给了直连地址(不走连接池),导出大库时用直连更稳:
DATABASE_URL_UNPOOLED=postgresql://neondb_owner:***@ep-xxx.us-east-1.aws.neon.tech/neondb?sslmode=require先看看有哪些表
连上后先跑个 \dt(或者用 Python 查 information_schema.tables),发现好家伙 ——97 张表。这是完整 LobeHub v2,不光是聊天,还有 RBAC 权限、OIDC 认证、Agent 任务调度、RAG 评估等等。
但对你来说,真正需要的就是这几张:
SELECT relname, n_live_tup FROM pg_stat_user_tablesWHERE relname IN ('messages','topics','agents','threads','files','users')ORDER BY n_live_tup DESC;| 表 | 行数 | 说明 |
|---|---|---|
| messages | 5,565 | 对话消息(最核心) |
| topics | 507 | 对话主题 / 标题 |
| files | 315 | 上传的文件记录 |
| agents | 22 | AI 助手配置 |
| threads | 10 | 对话线程 |
| users | 2 | 用户 |
导出数据
这一步最简单也最容易踩坑。说真的,Neon 的密码认证是最让人头疼的环节。
方式一:psql + pg_dump(需要装客户端)
brew install libpq # 装 psql 和 pg_dump,约 50MB
pg_dump "postgresql://..." --table=messages --table=topics --table=agents > export.sql方式二:Python + psycopg2(本文方案)
macOS 自带 Python,不需要额外装系统包。只装一个 Python 库:
python3 -m venv /tmp/pg_venv/tmp/pg_venv/bin/pip install psycopg2-binary然后:
import psycopg2, json
conn = psycopg2.connect( host="ep-xxx.us-east-1.aws.neon.tech", user="neondb_owner", dbname="neondb", password="你的密码", sslmode="require")
cur = conn.cursor()tables = ["topics", "messages", "agents", "threads", "users", "files"]
for t in tables: cur.execute(f'SELECT * FROM "{t}"')5 collapsed lines
rows = cur.fetchall() cols = [d[0] for d in cur.description] with open(f"{t}.json", "w") as f: json.dump([dict(zip(cols, r)) for r in rows], f, default=str) print(f"{t}.json: {len(rows)} rows")导出结果:6 个 JSON 文件,总共约 47MB(messages.json 占了 46MB)。
转换成可读 Markdown
JSON 格式的对话很难直接看 —— 每条消息是一个对象,散乱无章。需要按主题分组、按时间排序、把 agent_id 和 user_id 翻译成人类可读的名称,然后输出 Markdown。
转换脚本的核心逻辑:
# 1. 建立索引topics = {t["id"]: t for t in topics_raw}agents = {a["id"]: a for a in agents_raw}
# 2. 按 topic_id 分组by_topic = {}for m in messages: by_topic.setdefault(m["topic_id"], []).append(m)
# 3. 每组内按时间排序,输出 Markdownfor tid, msgs in by_topic.items(): msgs.sort(key=lambda m: m["created_at"]) title = topics.get(tid, {}).get("title", "无标题") agent = agent_name(msgs[0].get("agent_id"))
6 collapsed lines
with open(f"{date}_{title}_{tid[:8]}.md", "w") as f: f.write(f"# {title}\n\n") for m in msgs: role_icon = "👤" if m["role"] == "user" else "🤖" f.write(f"### {role_icon} {agent_name(m['agent_id'])}\n\n") f.write(f"{m['content']}\n\n---\n\n")最终输出:
markdown/├── _INDEX.md ← 按时间全索引├── 2025-04-01_Dify_部署架构详解_....md├── 2025-04-19_UFW_配置防火墙_....md├── 2025-05-02_亚马逊_Feedback_申诉_....md└── ...(共 507 个 .md 文件)_INDEX.md 里面按时间排列了全部 507 个主题,每个带日期、消息数、使用的助手名,可以直接当目录翻。
下一步:喂进 Open NotebookLM
507 个 Markdown 文件,每个是一个独立的对话主题。把它们丢进 Open NotebookLM(部署教程看这里):
- 创建一个 Notebook,比如「我的 LobeChat 对话存档」
- 批量上传 markdown 目录下的 .md 文件
- 等它做 embedding(507 个文件可能要几分钟)
然后你就可以跟自己的对话历史对话了:
- 「我之前怎么解决 FRP 客户端失败问题的?」
- 「Dify 部署架构的关键配置是什么?」
- 「总结所有亚马逊 Feedback 申诉的模板」
Open NotebookLM 会用 RAG 检索相关对话,直接给出带引用的回答。这比自己翻半年聊天记录高效太多了。
避坑指南
Neon 连不上
密码认证失败但密码明明是对的?试三件事:
- 用直连地址(不含
-pooler),不走连接池 - 用
PGPASSWORD环境变量传密码,别写在 URL 里(Neon 对 URL 中的特殊字符处理有问题) - 检查 Neon Console → Settings → IP Allow,确保你的 IP 在白名单里
macOS 没装 psql
brew install libpq 只装客户端(约 50MB),比完整 PostgreSQL(几百 MB)轻量得多。
如果不想碰 Homebrew,Python 也能搞定:pip install psycopg2-binary 之后纯 Python 操作,不依赖系统包。
大库导出慢
5,565 条消息导出 JSON 很快(几秒),但转 Markdown 如果逐行写 I / O 可能上百秒。建议用批处理 + 后台任务,别在前台干等。
密码安全
导出过程中密码会在命令行和脚本里出现。导出完记得:
history -c # 清当前 shell 历史rm /tmp/export*.py # 删除包含密码的脚本更好的做法是把密码存进 ~/.pgpass(chmod 600),然后用 PGPASSFILE 指向它。
FAQ
Q: 客户端模式(浏览器 IndexedDB)的数据怎么导出?
A: Chrome DevTools → Application → IndexedDB → 展开 LobeChat 的数据库 → 选中 Object Store → 导出 JSON。但数据量大会比较慢,建议分批操作。
Q: 这个方法适用于 LobeChat v1 吗?
A: v1 的数据库 schema 不同,表名和字段可能不一样。但思路一样 —— 找到存储层,连上去捞。
Q: 500 多个 Markdown 文件 Open NotebookLM 吃得下吗?
A: 吃得下。实测单个 Notebook 可以几十个源文件,507 个可能需要分两个 Notebook(比如按年份拆分),但处理效率没问题。
Q: 导出的数据能不能重新导入回 LobeChat?
A: 理论上可以走「导入数据」,但正如文章开头说的,LobeHub 云版的导入功能本身也是坏的(Issue #10793 有记录,导出数据再导回同一个云实例也报错)。如果你用的是自部署服务端数据库版本,直接把 JSON 还原成 PostgreSQL INSERT 更靠谱。