Open-Assistant REST Backend 开发实战:从本地数据库搭建到数据导出的完整指南
【免费下载链接】Open-AssistantOpenAssistant is a chat-based assistant that understands tasks, can interact with third-party systems, and retrieve information dynamically to do so.项目地址: https://gitcode.com/gh_mirrors/op/Open-Assistant
导读
本文以 Open-Assistant 仓库的 backend/README.md 为骨架,系统讲解其 REST 后端的完整开发流程:如何用 Docker Compose 拉起本地 PostgreSQL、安装 Python 依赖并以热重载模式启动 FastAPI 服务、通过.env配置数据库与 Redis、借助 Alembic 管理数据库迁移、启动 Celery Worker 处理毒性检测与特征提取等异步任务,以及用export.py把对话消息树导出为可用于模型训练的数据集。读完本文,你将能独立搭建一套可运行的 Open-Assistant 后端开发环境,并掌握其配置体系与数据导出管线的底层原理。
一、后端开发环境搭建
Open-Assistant 的 REST 后端(位于 backend/ 目录)是一个基于 FastAPI 的 Python 服务,负责任务分发、消息树管理、用户统计与数据导出。下面从零开始搭建本地开发环境。
1.1 启动本地数据库(Docker Compose)
在仓库根目录执行以下命令即可启动一套带backend-devprofile 的依赖服务:
docker compose --profile backend-dev up --build --attach-dependencies该命令的核心逻辑定义在根目录 docker-compose.yaml 中。与后端开发相关的服务包括:
- db:PostgreSQL 数据库,使用
ghcr.io/laion-ai/open-assistant/oasst-postgres镜像,环境变量为POSTGRES_USER=postgres、POSTGRES_PASSWORD=postgres、POSTGRES_DB=postgres,映射宿主端口5432:5432,并通过pg_isready做健康检查(docker-compose.yaml)。 - redis:用于缓存与限流,映射端口
6379:6379,加载仓库根目录的 redis.conf(docker-compose.yaml)。 - redis-insights:Redis 可视化监控面板,映射端口
8001。 - adminer:轻量级数据库管理工具,映射端口
8089:8080,可手动检查 web 与 backend 两套数据库。
注意(Apple Silicon / M1 芯片):若在 MacOS M1 上运行,需要显式指定平台架构:
DB_PLATFORM=linux/x86_64 docker compose ...
后端的默认配置已经按localhost:5432连接数据库(见 config.py 中POSTGRES_HOST=localhost、POSTGRES_PORT=5432等默认值),因此数据库启动后无需额外改动即可连通。
1.2 Python 版本与虚拟环境
后端要求Python 3.10,仓库根目录的.python-version文件声明了版本,推荐使用pyenv管理,进入仓库目录后 pyenv 会自动识别并切换到对应版本。
1.3 安装 Python 依赖
按顺序执行以下三步安装全部依赖:
pip install -r backend/requirements.txt pip install -e ./oasst-shared/. pip install -e ./oasst-data/.backend/requirements.txt是后端主依赖(FastAPI、SQLModel、Celery、Redis 等);oasst-shared以可编辑模式安装,提供跨模块共享的协议 schema 与异常定义(oasst-shared/);oasst-data以可编辑模式安装,提供导出数据格式(ExportMessageTree、LabelAvgValue等)与读写工具(oasst-data/)。
安装完成后,运行:
./scripts/backend-development/run-local.sh后端服务即会在http://localhost:8080启动。该脚本实际执行的是(run-local.sh):
uvicorn main:app --reload --port 8080 --host 0.0.0.0--reload开启热重载,任何代码改动都会自动重启服务,非常适合开发调试。
1.4 本地开发脚本族
scripts/backend-development/ 目录提供了一整套开发辅助脚本:
| 脚本 | 作用 |
|---|---|
run-local.sh | 以热重载模式启动后端(默认跳过毒性/嵌入计算,传hf参数则启用真实 HuggingFace 调用) |
run-local-no-limit.sh | 关闭限流后启动本地后端 |
start-docker.sh | 等价于docker compose --profile backend-dev up --build --attach-dependencies |
start-worker.sh | 在 backend 目录下启动 Celery worker(含 Beat 调度器) |
stop-worker.sh | 停止 Celery worker |
start-mock-server.sh/stop-mock-server.sh | 启动/停止 mock 服务 |
二、REST 服务器配置:.env与核心环境变量
2.1 生成.env配置文件
复制 backend/.env.example 为.env并按要求修改:
# backend/.env.example 的内容 HUGGING_FACE_API_KEY=HF API KEY DATABASE_URI="postgresql://<username>:<password>@<host>/<database_name>" BACKEND_CORS_ORIGINS=["http://localhost", "http://localhost:4200", "http://localhost:3000", "http://localhost:8080", ...] REDIS_HOST=localhost REDIS_PORT=6379其中DATABASE_URI必须设置为本地数据库地址,例如postgresql://postgres:postgres@localhost:5432/postgres。
2.2 环境变量的底层解析逻辑
所有环境变量最终由 backend/oasst_backend/config.py 中的Settings(BaseSettings)统一解析(基于 pydantic 的BaseSettings,读取当前目录下的.env文件,大小写不敏感)。几个关键点:
- 数据库连接:若未显式设置
DATABASE_URI,pydantic validator 会根据POSTGRES_HOST、POSTGRES_PORT、POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_DB自动拼接出postgresql://连接串(config.py)。 - CORS:既支持
BACKEND_CORS_ORIGINS列表,也支持用BACKEND_CORS_ORIGINS_CSV以逗号分隔字符串传入(config.py)。 - Redis 与限流:
RATE_LIMIT(默认True)、REDIS_HOST、REDIS_PORT控制 FastAPI 限流器。服务启动时会连接 Redis 并初始化FastAPILimiter(main.py)。 - DEBUG 系列开关:
DEBUG_SKIP_EMBEDDING_COMPUTATION与DEBUG_SKIP_TOXICITY_CALCULATION控制是否跳过 HuggingFace 的嵌入向量与毒性计算(本地无 API Key 时置True可加速);DEBUG_USE_SEED_DATA会在启动时把backend/test_data/realistic/realistic_seed_data.json的种子数据灌入数据库,方便本地联调(main.py)。 - 认证相关:
AUTH_*系列字段用于解密前端 NextAuth.js 生成的 JWT,必须与website的认证配置保持一致;OFFICIAL_WEB_API_KEY用于启动时自动创建官方 Web API 客户端(main.py)。 - Prometheus 指标:
ENABLE_PROM_METRICS(默认True)会在/metrics暴露监控指标(main.py)。
2.3 主服务启动入口
后端入口为 backend/main.py。除了uvicorn启动,它还提供了几个实用 CLI 参数(main.py):
python main.py --host 0.0.0.0 --port 8080 # 常规启动 python main.py --print-openapi-schema # 将 OpenAPI schema 打印到 stdout python main.py --retry-scoring # 重试打分失败的消息树后退出服务启动时会执行一系列 startup 事件:自动升级 Alembic 到最新版本(UPDATE_ALEMBIC开启时)、创建官方 Web API 客户端、初始化 Prometheus 与限流器、检查/恢复消息树状态(TreeManager.ensure_tree_states())、按周期更新日/周/月/总排行榜缓存统计、每小时清理过期任务等(main.py)。
三、Alembic:数据库迁移管理
修改 SQL 模型(位于 backend/oasst_backend/models/)后,需要在backend目录下生成迁移脚本:
cd backend alembic revision --autogenerate -m "描述你做的改动"生成后务必人工检查并编辑新创建的迁移文件,再执行alembic upgrade head应用到数据库。仓库中已有的迁移脚本全部位于 backend/alembic/versions/,例如add_message_revisions.py、add_text_search.py等,可作为编写迁移的参考范本。后端启动时若UPDATE_ALEMBIC=True(默认开启),会自动把数据库升级到head,避免手工执行(main.py)。
四、API 文档:本地 docs 与 OpenAPI 导出
后端启动后,默认 API 文档地址为:
http://localhost:8080/docs(Swagger UI,由 FastAPI 自动生成,openapi_url为/api/v1/openapi.json,见 main.py)。
如果需要把 OpenAPI 规范同步到仓库docs/目录,以便其他人无需搭建环境即可查看 API 定义,可以执行:
wget localhost:8080/api/v1/openapi.json -O docs/docs/api/backend-openapi.json导出的文件即 docs/docs/api/backend-openapi.json。该文件预期由test-api-contract.yamlCI 工作流自动更新(README 中标注为 TODO)。
五、Celery Worker:异步任务与周期调度
5.1 职责划分
Celery 在后端体系中承担两类工作:
- 异步 HuggingFace 调用:如消息毒性检测(toxicity)与嵌入特征提取(feature extraction / embedding computation);
- 周期任务(Celery Beat):如用户连续签到天数(user streak)重置。
Celery 应用定义在 backend/oasst_backend/celery_worker.py,broker 与 result backend 默认均为redis://localhost:6379/0,可用CELERY_BROKER_URL/CELERY_RESULT_BACKEND覆盖。内置的 beat 调度表(celery_worker.py):
| 任务名 | 调度周期 | 说明 |
|---|---|---|
periodic_user_streak_reset | 每 4 小时 | 重置用户连续签到 |
update_search_vectors | 每 20 分钟 | 批量更新全文搜索向量,batch_size=1000 |
周期任务的具体实现位于 backend/oasst_backend/scheduled_tasks.py(通过include=["oasst_backend.scheduled_tasks"]引入)。
5.2 本地运行 Worker
按 README 的指引:
- 在 backend/oasst_backend/config.py 中把
HUGGING_FACE_API_KEY设置为正确的 API Key; - 在 scripts/backend-development/run-local.sh 中确认:
export DEBUG_SKIP_TOXICITY_CALCULATION=False export DEBUG_SKIP_EMBEDDING_COMPUTATION=False- 在
backend目录运行 worker 启动脚本(start-worker.sh):
./scripts/backend-development/start-worker.sh # 等价于: celery -A oasst_backend.celery_worker worker -l INFO -B其中-B表示把 Beat 调度器内嵌进 worker 进程。
- 查看日志:
tail -f celery.log tail -f celery.beat.log5.3 CI / Docker 环境运行 Worker
在 CI(或 docker-compose 环境)中:
- 在根目录 docker-compose.yaml 里设置
DEBUG_SKIP_TOXICITY_CALCULATION=False与DEBUG_SKIP_EMBEDDING_COMPUTATION=False(backend 服务已默认如此配置,见 docker-compose.yaml); - 会创建两个 Docker 实例:backend-worker(
celery -A oasst_backend.celery_worker worker -l info -E)与backend-worker-beat(celery -A oasst_backend.celery_worker beat -l INFO),两者均依赖 db 与 redis 健康检查(docker-compose.yaml); - 日志与普通 Docker 容器一样通过
docker logs查看。
六、数据导出:export.py详解
6.1 基本用法
数据在数据库中积累后,可用 backend/export.py 导出。它直接连接数据库(复用后端的.env配置),因此需要与后端相同的 Python 环境。
导出所有通过评审的英文消息树:
python export.py --lang en --export-file output.jsonl完整选项列表可用python export.py --help查看。
6.2 参数语义与源码级说明
结合 export.py 的 argparse 定义,各参数含义如下:
| 参数 | 默认行为 | 说明 |
|---|---|---|
--export-file | 输出到 STDOUT | 导出文件名;文件名含.gz时自动启用 gzip 压缩 |
--include-deleted | 排除 | 包含已删除消息 |
--deleted-only | — | 仅导出已删除消息(隐含--include-deleted) |
--include-spam | 排除 | 包含未评审或评审为负的消息(review_result不限定为 True) |
--spam-only | — | 仅导出评审为负的消息(隐含--include-spam) |
--include-synthetic | 排除 | 包含合成消息 |
--synthetic-only | — | 仅导出合成消息 |
--user <UUID> | — | 仅导出指定用户参与的消息(与--state互斥) |
--state <state> | ready_for_export | 消息树状态过滤:all、prompt_lottery_waiting、growing、ready_for_export、aborted_low_grade、halted_by_moderator、backlog_ranking |
--lang <code> | 全部 | 按 BCP 47 语言码过滤(如en) |
--prompts-only | — | 仅导出初始 prompt 消息列表 |
--export-labels | — | 附带消息的平均文本标签值(含各标签的 count) |
--export-events | — | 附带用户的 emoji、评分(rating)、排序(ranking)事件 |
--limit <N> | 全部 | 最多导出的消息树数量 |
--anonymizer-seed <int> | 不匿名 | 匿名化随机种子;不指定则不做匿名化 |
几个值得注意的实现细节:
- 默认过滤链:若不传
--state,默认只导出READY_FOR_EXPORT状态的树;review_result默认限定为True(即必须通过评审),--include-spam会放宽该限制(export.py)。 - 匿名化:传入
--anonymizer-seed时使用oasst_shared.utils.Anonymizer对用户 ID 等敏感信息做确定性匿名化;不传则打印警告并原样导出(export.py)。 - 导出格式:正常树导出时使用
tree_export.build_export_tree组装成ExportMessageTree结构(消息树 + 标签均值 + 事件),并使用oasst_data的 writer 写入文件(export.py);按用户过滤或过滤不完整树时则扁平化为消息列表导出。 - 数据来源:导出时对
Message、MessageTreeState、MessageEmoji、MessageReaction、TextLabels等表进行聚合查询,按TextLabel枚举逐一计算avg(labels[l])与count(labels[l])(export.py)。
6.3 常见问题:"Why isn't my export working?"
README 指出最常见的原因是消息尚未通过评审流程,导致消息树未达到可导出状态。此时可加上--include-spam参数,将review_result限制放宽为不限,从而导出尚未通过评审的树(export.py)。
七、总结
Open-Assistant 的 REST 后端是一个典型的"FastAPI + SQLModel + PostgreSQL + Redis + Celery"技术栈:
- 环境就绪:
docker compose --profile backend-dev up --build --attach-dependencies一条命令拉起数据库与 Redis; - 服务启动:
pip install三个依赖后运行 run-local.sh,uvicorn热重载模式监听8080; - 配置驱动:所有行为(数据库、Redis、限流、DEBUG 开关、种子数据、Prometheus)均由
.env环境变量经 config.py 统一驱动; - 迁移与文档:Alembic 管理 schema 演进(启动时自动升级),
/docs提供交互式 API 文档,wget可同步 OpenAPI 规范到 docs/docs/api/backend-openapi.json; - 异步任务:Celery Worker + Beat 处理毒性检测、嵌入计算与周期任务,本地与 CI/Docker 两种运行模式均有配套脚本;
- 数据出口:export.py 提供高度可配置的消息树导出能力(语言、状态、评审结果、匿名化、压缩等),是 Open-Assistant 数据飞轮的关键一环。
按照上述步骤,你即可获得一套完整的本地开发环境,并深入理解该后端从数据采集到数据集导出的全链路设计。
【免费下载链接】Open-AssistantOpenAssistant is a chat-based assistant that understands tasks, can interact with third-party systems, and retrieve information dynamically to do so.项目地址: https://gitcode.com/gh_mirrors/op/Open-Assistant
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考