Cell 导入导出
wesgine 支持将 Cell 导出为可移植的 tar.gz 包,并在另一个引擎实例中导入,实现跨环境迁移。
概述
Cell 是 wesgine 的可移植单元——它不仅是运行时实例,还是可打包的快照。导出/导入机制让 Cell 能够:
- 在开发环境和生产环境之间迁移
- 作为备份和灾难恢复方案
- 在不同团队之间共享 Agent 配置
- 支持 Cell 模板化部署
导出流程
SDK 方式
// 导出 Cell 为 tar.gz 流
reader, err := hyp.Cells().Export(ctx, "my-cell")
if err != nil {
log.Fatal(err)
}
defer reader.Close()
// 写入文件
f, _ := os.Create("my-cell-export.tar.gz")
defer f.Close()
io.Copy(f, reader)
HTTP 方式
# 导出 Cell
curl -o my-cell-export.tar.gz \
http://localhost:9091/admin/cells/my-cell/export \
-H "Authorization: Bearer <admin-token>"
导出内容
默认包含:
| 内容 | 路径 | 说明 |
|---|---|---|
| 元数据 | meta.db | Cell 配置、Agent 定义 |
| 会话数据 | sessions.db | 历史对话、消息 |
| 运行时状态 | state.db | Traces、观测数据 |
| 技能 | skills/ | 已安装的 Tier C 技能 |
| 知识库 | knowledge/ | KB 文件和索引 |
| 工作区文件 | workspace/ | Agent 产出文件 |
默认排除:
| 内容 | 说明 |
|---|---|
.scratch/ | 临时计算域(Run 结束后 GC) |
.cell.lock | 进程排他锁 |
导出选项
// 排除 workspace(减小包体积)
reader, err := hyp.Cells().Export(ctx, "my-cell", ExportOpts{
SkipWorkspace: true,
})
tar.gz 格式
导出文件是标准 tar.gz 压缩包,内部结构:
my-cell-export.tar.gz
├── cell-manifest.json # 导出元信息(版本、时间、引擎版本)
├── spec.json # CellSpec 快照(密钥已脱敏)
├── meta.db # Cell 元数据库
├── sessions.db # 会话数据库
├── state.db # 运行时状态库
├── skills/ # 技能包
│ ├── skill-a/
│ └── skill-b/
├── knowledge/ # 知识库文件
│ ├── sources/
│ └── files/
└── workspace/ # 工作区产出(可选)
└── {actor}/
cell-manifest.json
{
"version": "1.0",
"cell_id": "my-cell",
"exported_at": "2026-09-14T12:00:00Z",
"engine_version": "v1.0.0",
"checksum": "sha256:abc123...",
"includes": {
"sessions": true,
"knowledge": true,
"skills": true,
"workspace": true
}
}
密钥处理
导出时 spec.json 中的密钥自动脱敏:
{
"private_providers": [
{
"name": "openai",
"api_key_ref": {
"source": "inline",
"value": "***REDACTED***"
}
}
]
}
导入后需要重新配置 Provider 密钥。
导入流程
SDK 方式
// 从文件导入
f, _ := os.Open("my-cell-export.tar.gz")
defer f.Close()
cellID, err := hyp.Cells().Import(ctx, f, ImportOpts{})
if err != nil {
log.Fatal(err)
}
log.Printf("Cell 已导入: %s", cellID)
HTTP 方式
# 导入 Cell
curl -X POST http://localhost:9091/admin/cells/import \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/octet-stream" \
--data-binary @my-cell-export.tar.gz
# 覆盖已存在的 Cell
curl -X POST "http://localhost:9091/admin/cells/import?overwrite=1" \
-H "Authorization: Bearer <admin-token>" \
--data-binary @my-cell-export.tar.gz
导入选项
type ImportOpts struct {
// 覆盖已存在的同 ID Cell
Overwrite bool
// 重命名 Cell ID(避免冲突)
NewCellID string
}
导入后操作
导入完成后,通常需要:
- 重新配置 Provider 密钥:导出时密钥已脱敏
cell, _ := hyp.Cells().Get("imported-cell")
// 通过 UpdateSpec 重新配置 Provider
hyp.Cells().UpdateSpec(ctx, "imported-cell", SpecPatch{
PrivateProviders: []config.ProviderConfig{
{
Name: "openai",
APIKeyRef: config.SecretRef{Source: "inline", Value: "sk-new-key"},
},
},
})
- 验证 Cell 状态
curl http://localhost:9091/cells/imported-cell/state \
-H "Authorization: Bearer <token>"
- 测试连通性
curl -X POST http://localhost:9091/cells/imported-cell/providers/test \
-H "Authorization: Bearer <token>" \
-d '{"provider": "openai"}'
数据完整性
导出时校验
- 每个 SQLite 数据库导出前执行
PRAGMA quick_check(INV-RESIL-05) - 损坏的数据库不会被打包
导入时校验
- 验证
cell-manifest.json完整性 - 校验
checksum - 验证 tar.gz 结构正确性
- 检查 Cell ID 是否冲突(除非
Overwrite=true)
SQLite 备份机制
导出使用 VACUUM INTO(原子快照)而非文件拷贝:
// 内部实现(INV-RESIL-05)
resilience.SQLiteBackup(sourceDB, targetPath)
为什么不用 cp:直接拷贝 .db 文件会忽略 -wal 和 -shm 文件,导致数据不一致。Cell 有 meta.db、sessions.db、state.db 三个数据库,必须全部使用原子快照。
跨环境迁移
开发 → 生产
# 在开发环境导出
curl -o dev-cell.tar.gz http://dev:9091/admin/cells/dev-cell/export \
-H "Authorization: Bearer <dev-admin-token>"
# 在生产环境导入
curl -X POST http://prod:9091/admin/cells/import \
-H "Authorization: Bearer <prod-admin-token>" \
--data-binary @dev-cell.tar.gz
# 重新配置生产 Provider
curl -X PATCH http://prod:9091/admin/cells/dev-cell \
-H "Authorization: Bearer <prod-admin-token>" \
-d '{"private_providers": [...]}'
Cell 模板化
利用导出/导入实现 Cell 模板:
# 创建模板 Cell(配置好 Agent、Skill、治理策略)
# 导出为模板
curl -o template.tar.gz http://localhost:9091/admin/cells/template/export
# 为新部门导入模板
curl -X POST "http://localhost:9091/admin/cells/import" \
-d @template.tar.gz
# 导入后重命名或修改 ID
灾难恢复
# 定期备份
#!/bin/bash
BACKUP_DIR="/backups/wesgine/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# 导出所有 Cell
for cell_id in $(curl -s http://localhost:9091/admin/cells | jq -r '.[].id'); do
curl -o "$BACKUP_DIR/${cell_id}.tar.gz" \
"http://localhost:9091/admin/cells/${cell_id}/export" \
-H "Authorization: Bearer <admin-token>"
done
# 保留最近 30 天
find /backups/wesgine -mtime +30 -delete
最佳实践
- 定期导出作为备份策略,结合 cron 自动化
- 导出前确认 Cell 无活跃 Run,避免数据不一致
- 大型知识库 Cell 使用
SkipWorkspace减小包体积 - 模板化 Cell 实现快速部署新租户
- 保留导出的 manifest 用于追溯和审计
注意事项
- 导出时密钥自动脱敏,导入后必须重新配置
- 导入不会自动启动 Cell,需要显式
Start或等待首次请求触发 Overwrite会替换目标 Cell 的全部数据,不可撤销.scratch/目录永不包含在导出中(INV-IO-08)- 进程排他锁(
.cell.lock)不包含在导出中(INV-RESIL-04) - 导入的 Cell 会使用目标引擎的
spec.key加密,与源引擎无关