首页
/ OpenViking 0.3.x 到 0.4.0 升级与 User/Peer 数据模型迁移实战指南

OpenViking 0.3.x 到 0.4.0 升级与 User/Peer 数据模型迁移实战指南

2026-09-09 18:08:06作者:殷蕙予

本指南面向已经运行 OpenViking 0.3.x 的开发者与运维人员,系统讲解升级到 0.4.0 前后的完整动作:哪些旧用法保持兼容、何时必须执行数据迁移、迁移的底层规则与向量索引处理方式,以及业务代码如何从 viking://agent/...viking://session/... 逐步迁移到新的 viking://user/<user_id>/peers/<peer_id>/... 模型。读完本文,你将掌握一条可安全执行的升级迁移路径,并理解 0.4.0 中 User / Peer / Session / Skill 新数据模型背后的源码级实现依据。

是否需要升级

如果继续停留在 0.3.x,现有 agent_idviking://agent/...viking://session/... 行为不会变化,但也无法获得 0.4.0 的能力:

  • 没有 User / Peer 数据模型。
  • 没有 legacy agent/session 数据迁移和 cleanup 命令。
  • 没有 actor_peer_id 请求级 peer 视图。
  • 后续围绕新模型的修复和能力不会回补到旧模型。

如果升级到 0.4.0,可以先不迁移数据。0.4.0 提供运行期兼容,旧数据不会因为升级立即不可读:

  • agent_id 仍可临时配置。当前 HTTP SDK client 会把它映射成请求级 actor_peer_id
  • viking://agent/... 仍可读旧 agent 数据,但只读。
  • viking://session/... 仍可读旧 session 数据,并会合并新 session 视图。

推荐顺序:

备份
  -> 升级 server / CLI / SDK
  -> 验证旧数据仍可读
  -> 执行数据迁移
  -> 验证新路径
  -> 逐步迁移业务用法
  -> 可选 cleanup

升级前备份

先用 0.3.x 兼容版本创建备份。建议使用 0.3.24

pip install openviking==0.3.24 --upgrade --force-reinstall
ov backup ./backups/openviking-before-0.4.0.ovpack

确认当前版本:

python -c "import openviking; print(openviking.__version__)"
ov version

重要约束:不要在 0.3.x 上执行 ov --sudo admin migrate。迁移命令只在 0.4.0 或更新版本可用。从源码看,迁移入口 POST /api/v1/admin/migrate(见 admin.py)依赖 0.4.0 的 task tracker 与 LegacyDataMigration 服务,旧版本二进制中并不存在该能力。

升级服务和客户端

安装 0.4.0,重启服务端,并确保 CLI / SDK 也升级到同一版本线:

pip install openviking==0.4.0 --upgrade --force-reinstall
openviking-server --config ov.conf

如果使用仓库内 Rust ov CLI,需要重新构建或安装 CLI;否则本地 ov 可能仍是旧二进制。仓库内 Rust CLI 的迁移命令实现在 crates/ov_cli/src/commands/admin.rs,它通过 client.rs 中的 admin_migratemigratecleanup 两种 action 调用服务端接口。

升级后先验证配置和旧数据读取:

ov config validate
ov ls viking://agent
ov ls viking://session
ov session list

关键点viking://session 的兼容合并发生在服务端。只升级 CLI、不重启 server,不会改变服务端读取行为。0.4.0 的请求边界解析逻辑位于 openviking/core/namespace.pyviking://session/... 会在认证请求边界被解析为当前用户的 viking://user/<user_id>/sessions/...,而 ~ 是当前用户空间的 home alias,因此“只升级客户端”对服务端读取行为没有任何影响。

兼容性速查

旧用法 0.4.0 行为
client 配置 agent_id 支持。当前 HTTP SDK client 会映射成请求级 actor_peer_id;它本身不再触发 legacy agent 模式。
ov ls viking://agent 支持读;如果设置了 agent_id / actor_peer_id,只显示当前 actor peer 对应的 legacy agent。
viking://agent/<agent_id>/... 支持读旧数据。
viking://agent/... 不支持。新写入应进入 viking://user/<user_id>/peers/<peer_id>/...
ov ls viking://session 支持读,会合并新 session 和旧 session。
viking://session/<session_id>/... 支持读,按新路径优先、旧路径兜底。
viking://session/... 不支持。新 session 写入 viking://user/<user_id>/sessions/...
HTTP SDK find / searchagent_id 支持,只查选中的 actor peer 视图,不会自动查未迁移的旧 agent 数据。
find / search body 传旧 peer_id 不支持。新 peer 视图使用 actor_peer_idX-OpenViking-Actor-Peer
同时配置 actor_peer_idagent_id 不支持,会报错。
HTTP SDK agent_id client 下显式传 message peer_id 支持。该 message 使用显式 peer_id;未提供时不会从 agent_id 推导。
role_id 记忆隔离 不再支持,升级后忽略。

actor_peer_id 视图的源码依据

“只读当前 actor peer”这一行为不是文档约定,而是有真实实现支撑的:

  • openviking/core/namespace.py 中,is_hidden_by_actor_peer_viewmay_include_hidden_actor_peers 会依据 ctx.actor_peer_id 过滤当前 user root 下 peers 集合中属于其他 peer 的内容——它只过滤 peers 集合,不会隐藏非 peer 的用户内容,也不会改变租户/用户身份。
  • openviking/core/namespace.pyis_accessible 中,访问 agent scope 时若配置了 actor_peer_id,只有 agent id 与 actor_peer_id 一致的目录才可访问,这正是“ov ls viking://agent 只显示当前 actor peer 对应 legacy agent”的实现原因。
  • 请求上下文中的 actor_peer_id 会随 RequestContext 传递(见 namespace.py 中构造 RequestContext 时保留 actor_peer_id 字段),说明 peer 视图是请求级的,而非全局状态。

执行数据迁移

确认升级后旧数据可读,再执行迁移:

ov --sudo admin migrate --output json

响应会返回 task id:

{
  "task_id": "..."
}

查询任务:

ov --sudo task status <task_id>
ov --sudo task list --task-type legacy_migration

HTTP API:

POST /api/v1/admin/migrate
X-API-Key: <root-key>

请求体可以为空,等价于:

{
  "action": "migrate"
}

查询任务:

GET /api/v1/tasks/{task_id}
X-API-Key: <root-key>

ROOT 查询迁移任务时不会按普通 account/user 过滤。迁移会为整个存储创建一个 root 级别 task,不会按 account 分别创建 task。从 admin.py 的实现可以看到:migrate_legacy_data 端点先构造 LegacyDataMigration,若 action 为 migrate 则先执行 preflight(),preflight 存在 errors 时直接抛出 FailedPreconditionError(task 根本不会被创建);通过后以 SYSTEM_TASK_ACCOUNT_ID / SYSTEM_TASK_USER_ID 创建 task 并用 asyncio.create_task 异步执行,因此接口立即返回 task_id,实际迁移在后台完成。对应的测试用例 tests/server/test_admin_api.py 专门验证了“preflight 失败不创建 task”的行为。

迁移规则

0.4.0 的新模型是 User / Peer:

User = 自然人或业务使用者
Peer = User 下的交互对象
Session = User 下的会话状态
Skill = User 下的可执行技能

迁移目标:

旧数据 新位置
viking://agent/<agent_id>/memories/... viking://user/<user_id>/peers/<agent_id>/memories/...
viking://agent/<agent_id>/resources/... viking://user/<user_id>/peers/<agent_id>/resources/...
viking://agent/<agent_id>/skills/<skill>/... viking://user/<user_id>/skills/<skill>/...
viking://session/<session_id>/... viking://user/<user_id>/sessions/<session_id>/...

共享 legacy agent 数据会复制到每个目标 user 的 peer 目录。如果旧路径已经表达了 user owner,只迁移到该 user。

迁移规划器的源码视角

迁移的核心实现在 openviking/service/legacy_migration.py

  • 三类 legacy 布局都会在 preflight 中识别:/local/<account>/user/<user_id>/agent/<agent_id>(user 作用域,_plan_user_agent_data)、/local/<account>/agent/<agent_id>/user/<user_id>(agent 作用域,_plan_agent_user_data)、以及共享的 /local/<account>/agent/<agent_id>_plan_shared_agent_data)。
  • 保留目录保护viking://agent/ 下的 skillsendpointstoolspayments 属于新公共 scope 布局,定义在 _AGENT_RESERVED_SUBDIRSlegacy_migration.py),迁移和 cleanup 规划器都会跳过它们,不会当作 legacy agent_id 处理。
  • 操作粒度:迁移按 TreeCopy 描述每条复制操作,带 category(如 agent_memoriesagent_skillssessions),最终汇总到 MigrationResult.operations 字典,这就是任务结果中 migrated.operations 各项计数的来源。
  • 幂等性_copy_path 在目标文件已存在时记录 skipped(reason 为 target already exists; kept existing target)而不是覆盖;skill 复制同样以 skip_tree_if_target_exists=True 跳过已有同名 skill。

向量索引:不重新向量化,只重写 URI

迁移会一并处理已有向量索引:对实际复制成功的 memory / resource / skill 文件或目录,直接读取旧记录中的 vector / sparse_vector 和标量字段,重写 URI 后写入新记录。迁移不会重新向量化,也不会自动调用 reindex。共享 legacy agent 数据复制到多个 user 时,会按每个目标 user URI 写入多份向量记录。

实现位于 openviking/storage/vector_migration.py

  • copy_vector_recordsL200-L262)通过 _records_in_scope 按 URI scope 过滤旧向量记录,调用 rewrite_vector_record 保留 vector / sparse_vector payload,仅重写 uriidaccount_idowner_user_idowner_spacecontext_type 等字段后 upsert 到新 URI。
  • level 为 0/1 的摘要型记录(abstract / content),会进一步用 rewrite_viking_uri_referencesrewrite_abstract_overview_for_transfer 重写正文中嵌套的 viking:// 引用,避免迁移后正文链接指向旧路径。
  • 每个 scope 的向量记录上限为 _MAX_VECTOR_RECORDS_PER_SCOPE = 100_000vector_migration.py),超过时会产生 warning 提示需手动 reindex。
  • 没有向量 payload 的旧标量记录会跳过并计入 migrated.skipped_vector_records_has_vector_payload 只检查 vector / sparse_vector 字段)。Session 迁移只复制文件状态,不处理向量索引——这一点在 _copy_vectors 中显式判断 if operation.category == "sessions" ... returnlegacy_migration.py)。

Session owner 解析顺序

Session owner 按以下顺序解析:

  1. .meta.json.created_by_user_id
  2. .meta.json.user_id.meta.json.owner_user_id.meta.json.created_by
  3. 旧路径里的 user hint,例如 /session/alice/sess-001
  4. 单用户 account 下的唯一注册用户

多用户 account 下,如果某个 legacy session 无法识别 owner,preflight 会失败。升级后的运行期兼容可以临时读取旧 session,但正式迁移前仍应补齐 owner。源码中 _session_ownerlegacy_migration.py)正是按 created_by_user_iduser_id / owner_user_id / created_by 的顺序读取 .meta.json_looks_like_session_dir 则通过 .meta.jsonmessages.jsonlhistorytool-resultstools 等文件判断目录是否为 session。

Legacy agent instructions 不迁移:

viking://agent/<agent_id>/instructions

迁移会记录 warning,不创建替代目录(见 _plan_agent_tree 中对 instructions 路径的处理)。

迁移前检查

以下问题会在 task 创建前直接失败:

  • 物理存储中存在 legacy 数据,但对应 account 不在 API key user registry 中。
  • 多用户 account 下存在无法识别 owner 的 legacy session。
  • session owner 存在,但不是合法的 OpenViking user id。

以下问题会记录为 warning 或 skipped,并继续迁移:

  • 目标 user 已经存在同名 skill。旧 skill 会被跳过,不覆盖现有 skill。
  • 发现 legacy agent instructions。Instructions 不迁移。
  • 存在共享 legacy agent,但 account 下没有可迁移的目标 user。

如果迁移发现 legacy 数据 owner 不在 user registry 中,会自动注册该 user。迁移结果只记录自动创建了哪些用户,不返回明文 user key。源码中 _ensure_plan_userlegacy_migration.py)会先校验 user_id 合法性(非法 id 进入 plan.errors),再检查用户是否已存在,不存在则加入 plan.created_usersrun() 阶段对每个自动创建的用户执行 register_user 并调用 initialize_user_directories 初始化用户目录。

如果开启了 api_key_hashing,明文 key 无法从存储中反查。需要重新生成:

ov --sudo admin regenerate-key <account_id> <user_id>

验证迁移结果

查看任务结果:

ov --sudo task status <task_id>

重点看:

  • migrated.files / migrated.directories
  • migrated.vector_records / migrated.skipped_vector_records
  • migrated.operations
  • skipped
  • warnings
  • created_users

这些字段的结构与 MigrationResult.to_dict 一一对应:migrated 下包含 filesdirectoriesvector_recordsskipped_vector_records 和按类别排序的 operations 字典,顶层还有 skippedwarningscreated_users

验证新路径:

ov ls viking://user/<user_id>/peers/<agent_id>/memories
ov ls viking://user/<user_id>/skills
ov ls viking://user/<user_id>/sessions

迁移只复制数据,不删除 legacy 路径或旧向量记录。重复执行是幂等的:已存在的目标文件和 skill 会被跳过,不会覆盖。如果迁移后的检索结果不符合预期,再由用户对新路径手动执行 reindex;迁移流程本身不会触发 reindex。仓库测试 tests/server/test_admin_api.py 覆盖了共享 agent 数据扇出、skill 迁移、session 迁移以及 “Skipped legacy instructions” warning 等场景,可作为验证行为是否符合预期的参照。

业务用法迁移

Client 配置

旧配置可以先继续用:

{
  "agent_id": "legacy-agent"
}

推荐逐步改成:

{
  "actor_peer_id": "legacy-agent"
}

不要同时配置:

{
  "actor_peer_id": "customer-a",
  "agent_id": "legacy-agent"
}

这会报错。actor_peer_id 通过 openviking/core/peer_id.pynormalize_peer_id 校验与归一化,任何空值或非法格式都会被拒绝,因此旧 agent_id 与新的 actor_peer_id 二选一是硬约束而非建议。

文件路径

旧路径:

viking://agent/code-agent/memories/profile.md
viking://session/sess-001/messages.jsonl

新路径:

viking://user/alice/peers/code-agent/memories/profile.md
viking://user/alice/sessions/sess-001/messages.jsonl

viking://session/<session_id> 可以继续作为当前 user session 的读 alias 使用,但新写入和长期引用建议使用 viking://user/<user_id>/sessions/<session_id>。从 openviking/core/namespace.py 可以看到,canonical_session_uri 生成的规范路径始终位于 viking://user/<user_id>/sessions/ 之下;同时 resolve_uri 对顶层 session scope 会抛出 NamespaceShapeError(“Legacy session URI is not canonical”),说明旧 session URI 只在请求边界(resolve_request_uri / resolve_current_user_uri)作为 alias 解析,内部存储与写入一律使用规范化新路径。

find / search

find / search 不再接受 legacy agent 身份字段,也不会自动包含未迁移的旧 agent 数据。旧 viking://agent/... 路径仍可通过内容和文件系统接口只读访问,但应先完成迁移再使用新检索路径。

迁移完成并确认不再需要旧 agent 数据后,所有 client 都改为 client/request 级 actor_peer_id

会话消息

Session 不再从 legacy agent id 推导消息归属;需要表达说话人时必须显式使用 message peer_id

暂不迁移数据

升级后可以暂时不迁移,但要知道这些限制:

  • 旧 agent/session 数据可读,但旧 namespace 不可写。
  • 新 session 和新资源会写入新 namespace,数据会在新旧路径并存一段时间。
  • find / search 不会默认查旧 viking://agent 数据。
  • 多用户 account 下 owner 不明确的旧 session,运行期可能可读,但正式迁移会被 preflight 拦截。
  • cleanup 之前旧目录和旧向量记录仍会保留。

因此不迁移适合作为短期过渡,不建议作为长期状态。

可选 cleanup

确认迁移结果无误后,可以删除旧 namespace:

ov --sudo admin migrate --cleanup --output json
ov --sudo task status <cleanup_task_id>

HTTP 请求体:

{
  "action": "cleanup"
}

Cleanup 只删除:

/local/<account>/agent
/local/<account>/session
/local/<account>/user/<user>/agent

Cleanup 会先删除上述 legacy URI scope 下的旧向量记录,再删除对应 AGFS 目录。若向量读取或删除失败,该目录会被跳过,避免旧文件已删除但旧索引仍残留。这一顺序在 legacy_migration.pycleanup() 中体现:先 _delete_vectors(target) 并累加 result.vector_records,若 vector_result.failed 则将目标记入 skipped(reason 为 vector cleanup failed)并跳过目录删除;删除向量成功后才执行 _agfs.rm(target.source_path, recursive=True)

Cleanup 不会删除新 user / peer 路径下的文件或向量记录。不会删除的新模型目录:

/local/<account>/user/<user>/peers
/local/<account>/user/<user>/sessions
/local/<account>/user/<user>/skills

另外注意:cleanup 规划器同样受 _AGENT_RESERVED_SUBDIRS 保护,/local/<account>/agent 下的 skillsendpointstoolspayments 不会被当作 legacy agent 删除(_cleanup_preflight)。

Cleanup 后,viking://agent/... 不再用于读取迁移后的 peer 数据;请使用新路径。viking://session/... 仍可作为当前 user session 的 alias 读取新 session。

常见问题

ov ls viking://agent 只看到一个 agent

如果配置了 agent_idactor_peer_id,这是预期行为。viking://agent 根目录会过滤到当前 actor peer,只显示对应 legacy agent。实现依据见上文对 is_accessibleis_hidden_by_actor_peer_view 的分析(openviking/core/namespace.py)。

ov ls viking://session 仍为空

确认服务端已经重启并加载 0.4.0。viking://session 的合并读发生在服务端;只升级 CLI 不会改变服务端读取行为。旧 session 的兼容读位于请求边界解析层(namespace.py),只有运行 0.4.0 的服务端才会执行该解析。

配置同时有 actor_peer_id 和 agent_id

这是不允许的。保留 agent_id 进入 legacy 模式,或删除 agent_id 后改用 actor_peer_id

Preflight 报告 unknown account

物理存储中存在某个 account 的 legacy 数据,但 API key registry 中没有这个 account。先恢复或重新创建该 account,再重新执行迁移。对应的 preflight 检查位于 legacy_migration.py:遍历物理存储的 account 与 registry 的 account 差集,若该 account 存在 legacy 数据则记录 error。

Preflight 报告 unresolved session owner

给 legacy session 的 .meta.json 补充 owner 字段,或把 session 移到能明确识别 owner 的旧路径下,然后重新执行迁移。可补充的字段包括 created_by_user_iduser_idowner_user_idcreated_by,并按上述解析顺序读取。

某个 skill 没有迁移

查看 task 的 skipped 列表。最常见原因是目标 user 已经存在同名 skill。迁移不会覆盖现有 skill——目标已存在时,规划器直接将该操作标记为 skipped 而不生成 TreeCopy_plan_agent_skills)。

小结

0.3.x 到 0.4.0 的升级本质上是数据所有权模型的升级:从全局 agent / session namespace 收敛为 User → Peer / Session / Skill 的归属结构。本文给出的完整路径——备份、升级、兼容验证、preflight 检查、后台迁移任务、结果核验、业务代码切换、可选 cleanup——每一步都有对应的源码实现(legacy_migration.pyvector_migration.pynamespace.pyadmin.py)与测试用例(tests/server/test_admin_api.py)作为依据。迁移不重新向量化、幂等可重跑、cleanup 先删索引再删目录等设计,保证了整个升级过程在旧数据仍可读的前提下平滑推进。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
docsdocs
暂无描述
Markdown
899
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
525
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395