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纯前端部署,无后端数据库
服务端数据库模式PostgreSQLDocker 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=require

Neon 还给了直连地址(不走连接池),导出大库时用直连更稳:

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_tables
WHERE relname IN ('messages','topics','agents','threads','files','users')
ORDER BY n_live_tup DESC;
行数说明
messages5,565对话消息(最核心)
topics507对话主题 / 标题
files315上传的文件记录
agents22AI 助手配置
threads10对话线程
users2用户

导出数据

这一步最简单也最容易踩坑。说真的,Neon 的密码认证是最让人头疼的环节。

方式一:psql + pg_dump(需要装客户端)

Terminal window
brew install libpq # 装 psql 和 pg_dump,约 50MB
pg_dump "postgresql://..." --table=messages --table=topics --table=agents > export.sql

方式二:Python + psycopg2(本文方案)

macOS 自带 Python,不需要额外装系统包。只装一个 Python 库:

Terminal window
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. 每组内按时间排序,输出 Markdown
for 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(部署教程看这里):

  1. 创建一个 Notebook,比如「我的 LobeChat 对话存档」
  2. 批量上传 markdown 目录下的 .md 文件
  3. 等它做 embedding(507 个文件可能要几分钟)

然后你就可以跟自己的对话历史对话了:

  • 「我之前怎么解决 FRP 客户端失败问题的?」
  • 「Dify 部署架构的关键配置是什么?」
  • 「总结所有亚马逊 Feedback 申诉的模板」

Open NotebookLM 会用 RAG 检索相关对话,直接给出带引用的回答。这比自己翻半年聊天记录高效太多了。

避坑指南

Neon 连不上

密码认证失败但密码明明是对的?试三件事:

  1. 用直连地址(不含 -pooler),不走连接池
  2. PGPASSWORD 环境变量传密码,别写在 URL 里(Neon 对 URL 中的特殊字符处理有问题)
  3. 检查 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 可能上百秒。建议用批处理 + 后台任务,别在前台干等。

密码安全

导出过程中密码会在命令行和脚本里出现。导出完记得:

Terminal window
history -c # 清当前 shell 历史
rm /tmp/export*.py # 删除包含密码的脚本

更好的做法是把密码存进 ~/.pgpasschmod 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 更靠谱。