BISHENG 后端运维脚本实战指南:数据导出、权限迁移回填与租户数据修复全解析
2026/9/16 10:31:35 网站建设 项目流程

BISHENG 后端运维脚本实战指南:数据导出、权限迁移回填与租户数据修复全解析

【免费下载链接】bishengBISHENG is an open LLM devops platform for next generation Enterprise AI applications. Powerful and comprehensive features include: GenAI workflow, RAG, Agent, Unified model management, Evaluation, SFT, Dataset Management, Enterprise-level System Management, Observability and more.项目地址: https://gitcode.com/GitHub_Trending/bi/bisheng

导读

本文以 BISHENG 开源仓库中 scripts 目录说明文档 为骨架,系统梳理后端所有手工维护与迁移脚本的用途、命令、参数与底层实现原理。这些脚本覆盖四大类场景:日常模式对话导出、RBAC→ReBAC 权限体系迁移与对账、Linsight(F035)升级数据迁移、以及多租户/知识空间/部门树的历史数据修复与压测数据灌入。读完本文,你将掌握在src/backend目录下安全运行这些一次性脚本的正确姿势——包括默认 dry-run 的安全约定、--apply的写入开关、幂等设计与脚本间的顺序依赖,并能从源码层面理解main.py启动期自动回填与手工脚本的分工边界。

一、脚本目录定位与通用运行约定

src/backend/scripts/存放的是手工维护与迁移脚本(manual maintenance and migration scripts),与随服务启动自动执行的初始化逻辑互补。运行这些脚本前,请先掌握三条通用约定:

  1. 运行位置:绝大多数 Python 脚本要求从src/backend/目录下执行,并通过PYTHONPATH=./让解释器能导入bisheng包;
  2. 解释器:使用项目虚拟环境.venv/bin/pythonscripts/seed_load_test_org.py的示例中也有直接用python的写法,取决于你的环境);
  3. 配置加载:多数脚本通过config环境变量指定配置文件,缺省时回落为config.yaml,例如config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/xxx.py

目录内还提供了一批.sh包装脚本(如 migrate_workstation_models_to_workbench.sh、backfill_knowledge_space_user_pin.sh 等),它们会自动探测解释器 /PYTHONPATH/ config,把--apply位置参数透传给 Python 脚本,便于手工运维直接调用。

说明:README 中记载的export_daily_chat_messages.pyreconcile_permission_migration_db.py/.sh未出现在当前仓库快照的 scripts 目录列表中,命令与参数契约以 README 为准,实际使用时请以部署版本目录内容为准。

二、导出类脚本:日常模式对话导出

export_daily_chat_messages.py

该脚本导出**日常模式(flow_type = 15)**的对话内容,默认导出最近 30 天的消息,并按会话聚合为 JSON。核心用法:

PYTHONPATH=./ .venv/bin/python scripts/export_daily_chat_messages.py PYTHONPATH=./ .venv/bin/python scripts/export_daily_chat_messages.py --days 7 PYTHONPATH=./ .venv/bin/python scripts/export_daily_chat_messages.py --format csv PYTHONPATH=./ .venv/bin/python scripts/export_daily_chat_messages.py --tenant-id 3 PYTHONPATH=./ .venv/bin/python scripts/export_daily_chat_messages.py --full-session

参数说明:

参数默认值作用
--config环境变量config,否则config.yaml指定配置文件
--days30导出最近多少天的消息
--formatjson输出格式,jsoncsv
--tenant-id仅导出指定租户
--user-id仅导出指定用户
--chat-id仅导出指定会话
--include-deleted包含已删除会话
--full-session只要会话在时间窗口内活跃,就导出该会话的全部消息(而非仅窗口内消息)

日常模式在 BISHENG 中对应工作站对话(flow_type = 15),导出产物适合作为合规留存、数据迁移或分析的输入。

三、权限模型迁移与回填脚本

权限类脚本解决两类问题:模型配置迁移(把旧位置的配置搬到新位置)与权限数据回填(为历史存量数据补齐缺失的授权信息)。这类脚本的共同特点是:默认 dry-run、--apply才写库、幂等可重跑。

1.migrate_workstation_models_to_workbench.py:工作台模型配置迁移

一次性迁移脚本,把旧的全局每日工作台模型列表从config.key = "workstation"行迁移到默认租户的tenant_system_model_config.key = "linsight_llm"行。

行为要点:

  • 读取workstation.models(来自config表);
  • 只写默认租户tenant_id = 1
  • 若 Root 已有linsight_llm行,仅合并更新models字段;
  • 若 Root 没有linsight_llm行,则新建一行;
  • 保留旧的workstation.models不动,后续 UI 保存流程可自行清理/覆盖。
PYTHONPATH=./ .venv/bin/python scripts/migrate_workstation_models_to_workbench.py PYTHONPATH=./ .venv/bin/python scripts/migrate_workstation_models_to_workbench.py --apply bash scripts/migrate_workstation_models_to_workbench.sh bash scripts/migrate_workstation_models_to_workbench.sh apply

2.migrate_channel_permissions_for_relation_models.py:自定义资源权限模板回填

把 channel 模块的默认权限回填进 channel 模块出现之前创建的旧自定义关系模型(资源权限模板)。注意它的适用对象是is_system = false的自定义模型:

  • 读取全局config.key = "permission_relation_models_v1"JSON 列表;
  • 对每个没有任何 channel 权限 id 的自定义模型,按其继承档位(owner/manager/editor/viewer)追加 channel 默认权限,来源为channel_permission_template.default_permission_ids_for_relation
  • 跳过系统模型(它们在运行时从模板动态计算 channel 默认值);
  • 跳过已含任一 channel 权限 id 的自定义模型(绝不覆盖管理员显式做过的 channel 定制);
  • 保留所有非 channel 权限。
PYTHONPATH=./ .venv/bin/python scripts/migrate_channel_permissions_for_relation_models.py PYTHONPATH=./ .venv/bin/python scripts/migrate_channel_permissions_for_relation_models.py --apply bash scripts/migrate_channel_permissions_for_relation_models.sh bash scripts/migrate_channel_permissions_for_relation_models.sh apply

3.backfill_relation_model_move_permissions.py:冻结系统档位的 F034 移动权限回填

这是"大部分情况下无需手动执行"的脚本:相同的幂等回填已在每次后端启动时自动运行(接线在 main.py 的 lifespan 中,第 61-64 行调用了backfill_relation_model_move_permissions),正常升级 + 重启即可自愈。独立脚本的存在价值仅在于:不重启修复环境,或先预览改动

要理解它,需要先理解permission_relation_models_v1配置行中每个系统档位的permissions_explicit开关(见 backfill_relation_model_move_permissions.py 的 docstring):

  • permissions_explicit=False(默认 seed 值):勾选状态读取时按代码模板动态计算,调用default_permission_ids_for_relation(relation)现算,新增权限(如本次的move_file/move_folder)会自动出现,无需回填;
  • permissions_explicit=True:勾选状态是保存那一刻冻结的快照update_relation_model保存 permissions 时会把开关翻成 True)。模板后来新增的权限不会自动补进快照——这正是"所有者/可管理档位缺移动权限"的根因。

脚本行为:

  • 对每个系统is_system = true)且已冻结permissions_explicit = true)的档位,计算目标权限集:{move_file, move_folder} ∩ default_permission_ids_for_relation(relation)
    • 所有者 / 可管理 / 可编辑(can_edit 及以上)→ 两个都补;
    • 可查看(viewer)→ 交集为空,不补
  • 只把缺失的这两个 id并入permissions[],不动其它任何已勾选项;
  • 跳过动态档位(permissions_explicit = false)和自定义(is_system = false)档位;
  • 幂等:补齐后重跑无变化。

在 relation_model_backfill.py 中可以看到核心逻辑apply_move_permission_backfill的实现:NEW_PERMISSION_IDS & default_permission_ids_for_relation(relation or "")计算交集,且仅当m.get("is_system") and m.get("permissions_explicit") is True时才处理。脚本主流程(L76-L110)直连 DB 读取Config行、JSON 解析、dry-run 打印、--apply时写回整行配置并提交。

安全保证(源码 docstring 明确声明):

  • 只新增move_file/move_folder,绝不删除或重置已有勾选;
  • 只动 system + explicit=True 的档位;
  • 单次写整行配置,失败回滚;
  • 该 config key 不走 Redis 缓存(aget_config_by_key直连 DB),运行中的进程下次读取即生效,无需重启
# 从 src/backend/ 运行: config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_relation_model_move_permissions.py config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_relation_model_move_permissions.py --apply

4.backfill_channel_member_rebac_grants.py:修复缺失的频道成员 ReBAC 授权

修复在 commitc530bf375之前就已激活、因此从未写入 ReBAC grant的频道订阅者。由于成员管理/授权列表是从 OpenFGA tuple 渲染的,这类成员在space_channel_member中处于激活态,却在授权列表中不可见。

行为:

  • 扫描频道(全部,或--channel-id指定单个),筛选status = ACTIVE、非CREATOR直接grant_subject_typeNULL/self)成员;
  • 对每个在 FGA 上没有既有 grant 的成员,通过ChannelService.sync_direct_channel_user_permissions写入 viewer/manager grant 与关系模型绑定(幂等);
  • 跳过:创建者(owner 由OwnerService管理)、PENDING/REJECTED成员、组织授权成员、以及 FGA 中已存在的成员。
PYTHONPATH=./ .venv/bin/python scripts/backfill_channel_member_rebac_grants.py PYTHONPATH=./ .venv/bin/python scripts/backfill_channel_member_rebac_grants.py --apply PYTHONPATH=./ .venv/bin/python scripts/backfill_channel_member_rebac_grants.py --channel-id <id> --apply bash scripts/backfill_channel_member_rebac_grants.sh bash scripts/backfill_channel_member_rebac_grants.sh apply bash scripts/backfill_channel_member_rebac_grants.sh --channel-id <id> apply

5.clean_department_space_user_group_grants.py:清理部门空间的用户组授权

F033 的一次性清理。部门知识空间不再允许用户组授权维度(API 拒绝新增 user_group grant,客户端也隐藏了对应 Tab),本脚本移除部门空间上历史遗留的 user_group grant——撤销 OpenFGA tuple 并删除关系模型绑定,运行时代码不再为这些 grant 保留兼容路径。

行为:

  • 扫描每个部门知识空间(DepartmentKnowledgeSpaceDao.aget_all);
  • 将每个user_groupgrant 报告为(space_id, group_id, relation, affected_users)
  • --apply时通过PermissionService.authorize撤销 grant 并移除绑定;
  • 只处理部门空间的user_groupgrant——绝不触碰普通空间、也绝不处理 user/department grant。

⚠️--apply不可逆(会撤销组成员访问权限),务必先 review dry-run 输出。

export config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/clean_department_space_user_group_grants.py # dry-run PYTHONPATH=./ .venv/bin/python scripts/clean_department_space_user_group_grants.py --apply # execute

四、F006 RBAC → ReBAC 权限迁移与对账

1.permission_migration.sh:历史权限迁移手工执行器

F006 历史权限迁移(RBAC → ReBAC)的手工运行入口。用法与模式(详见 permission_migration.sh 源码实现):

bash bisheng/script/permission_migration.sh bash bisheng/script/permission_migration.sh dry_run bash bisheng/script/permission_migration.sh verify bash bisheng/script/permission_migration.sh replay bash bisheng/script/permission_migration.sh replay 3

模式映射(脚本会把模式翻译成permission_rbac_to_rebac_migration.py的不同参数):

模式行为底层参数
execute(默认)正常执行迁移--step <N>
dry_run仅预览迁移统计--dry-run --step <N>
only_step只执行指定步骤--only-step <N>
dry_run_only_step只预览指定步骤--dry-run --only-step <N>
verify对比旧 RBAC 与新 ReBAC 权限结果--verify --step <N>
replay从指定步骤强制重放,忽略已完成状态并清空 checkpoint--force --step <N>
forcereplay行为一致,为兼容保留--force --step <N>

步骤映射(8 步,脚本第 2 个参数传入步骤号):

  • 1:Super Admin
  • 2:User Group Membership
  • 3:Role Access Expansion
  • 4:Space/Channel Members
  • 5:Resource Owners
  • 6:Folder Hierarchy
  • 7:Department Membership
  • 8:Group Resources

2.reconcile_permission_migration_db.py:业务级数据库对账

该脚本不重放迁移实现,而是直接从业务表重建期望的 tuple 并与 OpenFGA datastore 的tuple表对比。涉及的业务表包括userroleroleaccessspace_channel_memberknowledgefileuser_departmentgroupresource等。

PYTHONPATH=./ .venv/bin/python scripts/reconcile_permission_migration_db.py \ --tuple-db-url "mysql+pymysql://user:pass@host:3306/openfga" \ --step 1 PYTHONPATH=./ .venv/bin/python scripts/reconcile_permission_migration_db.py \ --tuple-db-url "mysql+pymysql://user:pass@host:3306/openfga" \ --step 3 --apply

参数:

  • --tuple-db-url:OpenFGA datastore 的 SQLAlchemy URL(必填);
  • --store-id:可选的 OpenFGA store id,省略时自动解析;
  • --step:只检查第 N 步(1~8);
  • --apply:diff 后通过 OpenFGA API 应用写入/删除;
  • --sample-limit:打印多少条样例 tuple diff。

3.reconcile_permission_migration_db.sh:按步骤对账的 shell 包装

bash scripts/reconcile_permission_migration_db.sh check 1 "mysql+pymysql://user:pass@host:3306/openfga" bash scripts/reconcile_permission_migration_db.sh apply 3 "mysql+pymysql://user:pass@host:3306/openfga"

参数:arg1 为checkapply,arg2 为步骤号(1~8),arg3 为 OpenFGA tuple DB URL。第 3 个参数可省略,若以下环境变量之一已设置:

  • OPENFGA_TUPLE_DB_URL
  • OPENFGA_DATASTORE_URL
  • OPENFGA_DATASTORE_URI

五、Linsight(F035)升级脚本

F035 是"灵思任务模式(deepagents)"功能上线的大版本,其升级清单共 4 步:步骤 2/3 在服务启动时自动回填,步骤 4(SOP→Skill 数据迁移)由于要写对象存储、较重,必须手工执行。完整升级清单见 docs/architecture/08-deployment.md 的升级 checklist。

1.migrate_sop_to_skill.py/.sh:SOP → 技能迁移(F035 第 4 步,手工必跑)

升级必做(v2.6 之前 → v2.6,F035 4 步中的第 4 步)——手工执行。必须在alembic upgrade head之后运行。与 F035 菜单/模型回填(第 2/3 步启动自动执行)不同,本次 SOP→Skill 数据迁移不会自动运行——它要写对象存储、较重,保持为手工运维脚本。

一次性迁移:把遗留的linsight_sop行转换为租户自定义技能(linsight_skill元数据行 +SKILLS_ROOT/data/skills/{tenant_id}/<name>/SKILL.md技能包)。细节(见 migrate_sop_to_skill.py 的 docstring 与实现):

  • display_name保留原始(中文)SOP 名,截断到 255 字符,同租户重名追加"(2)/(3)"后缀;
  • name(技能 ID)是 SOP 名的 pypinyin slug(如"标书撰写流程"→biao-shu-zhuan-xie-liu-cheng),空/纯符号名回退为sop-{id},同租户重名追加-2/-3后缀(保证 64 字符上限,见_dedupe_name实现);
  • description使用 SOP 自带描述,截断到 1024 字符;SOP 无描述时用 SOP 名兜底(不调用 LLM)——技能描述是必填的(linsight_skill.description非空且SkillService拒绝空描述),绝不能留空;内容行连名称都没有时,使用_FALLBACK_DESCRIPTION = "历史 SOP(#{sop_id})迁移生成的技能。"
  • frontmatter 携带metadata.display-namemetadata.sop-id——sop-id使重跑幂等:已迁移的 SOP 重跑会覆盖自己的技能包,而不是再分配一个带后缀的新名字;
  • 输出:stdout + JSON 文件的迁移摘要(运维产物,产品内没有迁移报告);失败/跳过项需人工处理:在管理页修复重建,或拆分超限 SOP 后重新上传;
  • 遗留linsight_sop保持不动(归档,设计 §8.6)。
# 从 src/backend/ 运行,默认 dry-run: bash scripts/migrate_sop_to_skill.sh # dry-run, all tenants bash scripts/migrate_sop_to_skill.sh apply # persist bash scripts/migrate_sop_to_skill.sh --tenant-id 2 apply # single tenant

参数:--apply(持久化)、--tenant-id <id>--report-file <path>(默认./migrate_sop_to_skill_report.json)。

2.backfill_linsight_task_mode_web_menu.py:任务模式菜单权限回填(F035 第 3 步,启动自动)

F035 第 3 步——启动自动。服务启动时自动运行(main.lifespan,幂等,失败不阻塞启动);共享逻辑在bisheng/permission/domain/linsight_task_mode_menu_backfill.py。CLI 仅用于手工重跑或 dry-run 预览。

功能:给所有已拥有home菜单权限的角色授予WEB_MENUlinsight_task_mode权限。F035 把任务模式(/linsight)从共享的home菜单权限中拆出为独立子开关;不做这次回填,升级后的部署会让既有角色丢失任务模式访问权限(路由守卫现在检查linsight_task_mode)。幂等可重跑,默认 dry-run。

# 从 src/backend/ 运行: config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_linsight_task_mode_web_menu.py # dry-run config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_linsight_task_mode_web_menu.py --apply # write

3.migrate_linsight_task_model_to_default.py:任务模型配置改写(F035 第 2 步,启动自动)

F035 第 2 步——启动自动。同上,启动时自动运行(main.lifespan,幂等,失败不阻塞启动);共享逻辑在bisheng/llm/domain/services/linsight_default_model_backfill.py

F035 Track E(deepagents):改写每个租户在tenant_system_model_config中的linsight_llm配置行——删除遗留的task_model/linsight_executor_mode键,设置新的单一linsight_default_model_id(若旧task_model.id仍在该行的models列表中就保留它,否则回退到第一个 model id,models为空则置空)。JSON 用 Python 解析(不用JSON_EXTRACT)以保证 DM8/MySQL 兼容。幂等(无task_model的行跳过)可重跑,默认 dry-run。

# 从 src/backend/ 运行: config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/migrate_linsight_task_model_to_default.py # dry-run config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/migrate_linsight_task_model_to_default.py --apply # write

4.seed_overflow_skill.py:溢出压测技能(Dev/QA 专用,非升级项)

Dev/QA fixture——不属于任何升级清单。种入一个"溢出 QA"技能,其字段被推到极限,用于人工目检技能详情抽屉(SkillDetailSheet.tsx,2026-06-16 溢出加固,Track I)。幂等(重跑替换同一技能);--remove删除。

插入技能(默认目标租户 1):display_name255 字符、name64 字符、description1024 字符(无空格)、SKILL.md 正文携带 400 字符无断点 token、以及一个长名 bundle 资产——覆盖全部四个溢出点(标题 / ID chip / 描述 / 预览)加文件树。人工验收清单见 features/v2.6.0/035-linsight-task-mode/tasks.md 的 TI-1。

config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/seed_overflow_skill.py # dry-run config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/seed_overflow_skill.py --apply # create config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/seed_overflow_skill.py --remove # clean up

六、租户 / 数据修复脚本

1.backfill_message_citation_relations.py:引用关系回填

把历史message_citation.message_id回填到新的message_citation_relation关联表,使同一个全局citation_id可被多条工作流输出消息复用。默认 dry-run、分批执行且幂等;必须在升级后的服务已创建message_citation_relation表之后运行

可选--recover-markers会额外扫描消息正文中的引用标记,恢复旧版本中"消息已提交、随后引用唯一键冲突"留下的关联。恢复时校验chat_id/flow_id,找不到引用实体或作用域不匹配的标记只统计、不写入。

config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_message_citation_relations.py config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_message_citation_relations.py --recover-markers --apply # 或用 shell 包装(自动探测解释器 / PYTHONPATH / config): bash scripts/backfill_message_citation_relations.sh bash scripts/backfill_message_citation_relations.sh --recover-markers apply

2.dedupe_gpts_tools.py:预置工具去重

清理同一租户下(tool_key, tenant_id)重复的预置工具/工具类型行。根因:历史上"复制内置工具到子租户"未显式带tenant_id,在 root 上下文下被server_default=1盖成 root,加上t_gpts_tools.tool_key当时没有唯一约束,导致 root 下同一tool_key堆了多份(如web_search×3)。危害有二:get_tool_by_tool_key().first()可能解析到非预期的那条(工作流读到旧配置);且会阻止后续添加UNIQUE(tool_key, tenant_id)约束。

行为:每组保留最小 id 为 canonical,重定向assistantlink.tool_idt_gpts_tools.type到 canonical,硬删 stray 行。非预置(自定义 API/MCP)重复只报告不删除。工作台配置 JSON / OpenFGA 中对 stray id 的引用也只报告,需人工跟进。

⚠️--apply前先备份数据库。

config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/dedupe_gpts_tools.py # dry-run(默认,不写库) config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/dedupe_gpts_tools.py --apply # 执行清理(硬删 + 重定向引用)

apply 干净后再手动加约束:

ALTER TABLE t_gpts_tools ADD CONSTRAINT uk_gpts_tools_key_tenant UNIQUE (tool_key, tenant_id);

3.backfill_knowledge_space_user_pin.py:知识空间置顶解耦回填

F037:知识空间置顶从space_channel_member.is_pinned解耦到独立的knowledge_space_user_pin表(置顶是纯个人偏好,不再寄生在成员关系上)。本脚本把历史置顶迁移到新表,让升级后用户保留已置顶的空间。

来源行:space_channel_memberbusiness_type='space'is_pinned为真且status='ACTIVE',每条转成knowledge_space_user_pin(user_id, space_id=business_id)。幂等:已存在的(user_id, space_id)跳过,可重复运行。

前置:先alembic upgrade head(建好knowledge_space_user_pin表,迁移f044_knowledge_space_user_pin)。

config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_knowledge_space_user_pin.py # dry-run(默认,不写库) config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_knowledge_space_user_pin.py --apply # 写入 # 或用 shell 包装: bash scripts/backfill_knowledge_space_user_pin.sh # dry-run bash scripts/backfill_knowledge_space_user_pin.sh apply # 写入

4.backfill_departments_under_single_root.py:部门单根收编

把所有"误挂为根"的部门收编到默认组织根部门(BS@root)下,保证全平台只有一个根部门。

背景:历史上 SSO 网关同步的顶层部门(parent_external_id为空)被挂为parent_id=None,变成与"默认组织"平级的兄弟根,导致出现多个根、且其path不以默认组织根 path 为前缀(按path LIKE '{root_path}%'圈定租户成员时被漏算)。同步逻辑已修复(顶层部门改挂默认组织根下),但增量推送未重推的存量部门需本脚本一次性收编。

做什么:默认租户下、除默认组织根外的所有 active 根部门(parent_id IS NULL),设parent_id=默认组织根.id并级联重写整棵子树path。不区分 source,不触碰挂载状态。幂等:收编后parent_id不再为空,重复运行被自然跳过。

config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_departments_under_single_root.py # dry-run(默认,不写库) config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_departments_under_single_root.py --apply # 写入 # 或用 shell 包装: bash scripts/backfill_departments_under_single_root.sh # dry-run bash scripts/backfill_departments_under_single_root.sh apply # 写入

5.backfill_user_tenant_associations.py:用户默认租户归属回填

把缺失/未激活的默认租户归属回填到user_tenant表。这段逻辑原先挂在服务启动流程init_default_data()_init_default_tenant里,每次进程启动都会全表扫描users/user_tenant(一次反连接 + 一次"把全部is_active=1行读进内存"),在大用户量部署下属于把数据维护塞进了热路径。已从启动流剥离——启动只保证默认租户(id=1)存在。

运行期不依赖这张回填表:UserPayload租户解析在用户无user_tenant行时回退到DEFAULT_TENANT_ID,多租户登录还会惰性补挂,故缺行不会阻塞登录/查询,本回填是纯数据一致性维护,按需运行一次即可。

做什么(两步,与原启动逻辑等价、幂等):① 对没有任何user_tenant行的用户插入默认租户行(tenant_id=1, is_default=1, is_active=1, status='active');② 对tenant_id=1 / is_default=1 / status='active' / is_active IS NULL且该用户当前无任何is_active=1行的孤儿默认行,置is_active=1(每用户只激活一条)。只新增/激活,不删除、不 demote。

config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_user_tenant_associations.py # dry-run(默认,不写库) config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_user_tenant_associations.py --apply # 写入 # 或用 shell 包装: bash scripts/backfill_user_tenant_associations.sh # dry-run bash scripts/backfill_user_tenant_associations.sh apply # 写入

6.backfill_department_parent_tuples.py:部门父边 FGA 回填

把 DB 部门树的父子关系回填成 OpenFGA 的department#parent继承边(additive,只加不删,幂等)。

背景:写department:{parent}#parent@department:{child}边的只有 F002 手动建/移部门;SSO 同步及早期 f006 迁移进来的部门在 FGA 里没有这条边,导致部门 admin 的 FGA 继承对其失效。SSO 同步链路已修复为实时维护 parent 边,本脚本按 DB 当前树形一次性补齐存量部门的边。

遍历所有status='active'parent_id非空的部门(全租户、全来源),每个发一条write department:{parent_id}#parent department:{id}batch_write_tuples对重复写幂等,可反复跑。

运行顺序:在backfill_departments_under_single_root.py(定型 parent_id)之后运行,会一并补上被收编部门的 root→顶层 边。

config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_department_parent_tuples.py # dry-run(默认) config=config.yaml PYTHONPATH=./ .venv/bin/python scripts/backfill_department_parent_tuples.py --apply # 写入 # 或用 shell 包装: bash scripts/backfill_department_parent_tuples.sh # dry-run bash scripts/backfill_department_parent_tuples.sh apply # 写入

七、压测数据脚本:seed_load_test_org.py

压测数据脚本:批量生成部门树 + 用户灌入数据库,用于大用户量下的体验/性能测试(尤其 ReBAC 读路径)。

在平台默认根部门(Tenant.root_dept_id)下按--fanout广度优先生成--departments个部门(自动维护物化pathdepartment#parentFGA 边),再生成--users个本地用户轮询分配主部门(is_primary=1,可选--secondary-ratio挂附属部门),每人写 user + 默认角色 + user_department + user_tenant 及department#memberFGA 边。

所有数据打source=<--source>(默认loadtest)标签 +external_id=loadtest_dept_*/loadtest_user_*,因此幂等且可用--purge一键清理。统一密码Test@1234ab

干跑是默认行为,--apply才写库/写 FGA/删数据。默认写 OpenFGA;--no-fga只灌库。--with-role-fga才逐用户同步默认角色到 FGA(慢)。

config=config.yaml PYTHONPATH=./ python scripts/seed_load_test_org.py --departments 200 --users 50000 --fanout 8 # dry-run(默认) config=config.yaml PYTHONPATH=./ python scripts/seed_load_test_org.py --departments 200 --users 50000 --fanout 8 --apply # 写入 DB + FGA config=config.yaml PYTHONPATH=./ python scripts/seed_load_test_org.py --departments 200 --users 50000 --apply --no-fga # 只灌库 config=config.yaml PYTHONPATH=./ python scripts/seed_load_test_org.py --purge --apply # 清理压测数据 # 或用 shell 包装(自动探测解释器 / PYTHONPATH / config): bash scripts/seed_load_test_org.sh --departments 200 --users 50000 --apply

八、运维执行安全最佳实践

综合以上全部脚本,提炼出 BISHENG 运维脚本的统一纪律:

  1. 默认 dry-run,--apply才写:所有会改动数据的脚本都以 dry-run 为默认行为(如backfill_relation_model_move_permissions.pydedupe_gpts_tools.pybackfill_knowledge_space_user_pin.pybackfill_departments_under_single_root.pybackfill_user_tenant_associations.pybackfill_department_parent_tuples.pyseed_load_test_org.py),先看输出再确认;
  2. 写前备份:涉及硬删/重定向引用的脚本(如dedupe_gpts_tools.py)要求--apply前先备份数据库;
  3. 幂等设计:脚本普遍通过业务键(如sop-id(user_id, space_id)(tool_key, tenant_id)parent_id是否为空)天然跳过已处理数据,可反复重跑;
  4. 顺序依赖:先定型数据再补派生数据,典型链路为backfill_departments_under_single_root.py(先定型 parent_id)→backfill_department_parent_tuples.py(再补 FGA 边);
  5. 区分自动与手工:部分回填(F035 第 2/3 步、F034 move 权限)已在 main.py 的 lifespan 中自动执行,CLI 仅用于手工重跑或预览;而 SOP→Skill 迁移(写对象存储)与 F006 权限迁移必须按 docs/architecture/08-deployment.md 升级 checklist 手工执行;
  6. 数据一致性 vs 热路径:如backfill_user_tenant_associations.py所示,BISHENG 已把重扫描逻辑从启动热路径剥离为按需脚本,运行期通过回退与惰性补挂保证功能不依赖回填完成。

掌握这些约定后,你可以在升级窗口内安全、有序地完成 BISHENG 的权限迁移、数据修复与压测准备,并随时用 dry-run 输出作为审计依据。

【免费下载链接】bishengBISHENG is an open LLM devops platform for next generation Enterprise AI applications. Powerful and comprehensive features include: GenAI workflow, RAG, Agent, Unified model management, Evaluation, SFT, Dataset Management, Enterprise-level System Management, Observability and more.项目地址: https://gitcode.com/GitHub_Trending/bi/bisheng

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询