AI时代如何临摹项目:Vault跨项目持久化存储系统
开发中,经常需要学习和参考各种开源项目。为了让AI助手更好地理解这些学习资源,我们设计了Vault跨项目持久化存储系统。
这套方案已经在HagiCode中经过了实际验证,如果你也面临类似的知识管理难题,希望这些经验能给你一些启发。毕竟,有些坑踩过了,总得留下点什么给后来的人。
Vault系统设计理念
Vault系统的核心思想很简单:创建一个统一的、可被AI理解的知识存储抽象层。从实现角度来看,系统具有几个关键特征。
多类型支持
系统支持四种vault类型,分别对应不同的使用场景:
// folder:通用文件夹类型 |
|
export const DEFAULT_VAULT_TYPE = 'folder'; |
|
// coderef:专门用于临摹代码项目的类型 |
|
export const CODEREF_VAULT_TYPE = 'coderef'; |
|
// obsidian:与Obsidian笔记软件集成 |
|
export const OBSIDIAN_VAULT_TYPE = 'obsidian'; |
|
// system-managed:系统自动管理的vault |
|
export const SYSTEM_MANAGED_VAULT_TYPE = 'system-managed'; |
其中 coderef 类型是HagiCode中最常用的。它专门为临摹代码项目设计,提供了标准化的目录结构和AI可读的元数据描述。
持久化存储机制
Vault的注册表以JSON格式持久化存储,确保配置在应用重启后仍然可用:
public class VaultRegistryStore : IVaultRegistryStore |
|
{ |
|
private readonly string _registryFilePath; |
|
public VaultRegistryStore(IConfiguration configuration, ILogger<VaultRegistryStore> logger) |
|
{ |
|
var dataDir = configuration["DataDir"] ?? "./data"; |
|
var absoluteDataDir = Path.IsPathRooted(dataDir) |
|
? dataDir |
|
: Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), dataDir)); |
|
_registryFilePath = Path.Combine(absoluteDataDir, "personal-data", "vaults", "registry.json"); |
|
} |
|
} |
这种设计的好处是简单可靠。JSON格式人类可读,便于调试和手动修改;文件系统存储避免了数据库的复杂性,降低了系统的依赖。毕竟,有时候简单的反而是最好的。
AI上下文集成
最关键的是,系统能够自动将vault信息注入到AI提案的上下文中:
export function buildTargetVaultsText( |
|
vaults: VaultForText[], |
|
template: VaultPromptTemplate = DEFAULT_VAULT_PROMPT_TEMPLATE, |
|
): string { |
|
const readOnlyVaults = vaults.filter((vault) => vault.accessType === 'read'); |
|
const editableVaults = vaults.filter((vault) => vault.accessType === 'write'); |
|
if (readOnlyVaults.length === 0 && editableVaults.length === 0) { |
|
return ''; |
|
} |
|
const sections = [ |
|
buildVaultSection(readOnlyVaults, template.reference), |
|
buildVaultSection(editableVaults, template.editable), |
|
].filter(Boolean); |
|
return `\n\n### ${template.heading}\n\n${sections.join('\n')}`; |
|
} |
这样就实现了一个重要的功能:AI助手能够自动理解可用的学习资源,无需用户手动提供上下文。这倒也算是一种默契了。
CodeRef Vault的标准化结构
对于coderef类型的vault,HagiCode提供了一套标准化的目录结构:
my-coderef-vault/ |
|
├── index.yaml # vault元数据描述 |
|
├── AGENTS.md # AI助手的操作指南 |
|
├── docs/ # 存放学习笔记和文档 |
|
└── repos/ # 通过Git子模块管理临摹的代码仓库 |
创建vault时,系统会自动初始化这个结构:
private async Task EnsureCodeRefStructureAsync( |
|
string vaultName, |
|
string physicalPath, |
|
ICollection<VaultBootstrapDiagnosticDto> diagnostics, |
|
CancellationToken cancellationToken) |
|
{ |
|
Directory.CreateDirectory(physicalPath); |
|
var indexPath = Path.Combine(physicalPath, CodeRefIndexFileName); |
|
var docsPath = Path.Combine(physicalPath, CodeRefDocsDirectoryName); |
|
var reposPath = Path.Combine(physicalPath, CodeRefReposDirectoryName); |
|
// 创建标准目录结构 |
|
if (!Directory.Exists(docsPath)) |
|
{ |
|
Directory.CreateDirectory(docsPath); |
|
} |
|
if (!Directory.Exists(reposPath)) |
|
{ |
|
Directory.CreateDirectory(reposPath); |
|
} |
|
// 创建AGENTS.md指南 |
|
await EnsureCodeRefAgentsDocumentAsync(physicalPath, cancellationToken); |
|
// 创建index.yaml元数据 |
|
await WriteCodeRefIndexDocumentAsync(indexPath, mergedDocument, cancellationToken); |
|
} |
这套结构的设计也是有讲究的:
- docs/ 目录存放你的学习笔记,可以用Markdown格式记录对代码的理解、架构分析、踩坑经验等
- repos/ 目录通过Git子模块管理临摹的仓库,而不是直接复制代码。这样既能保持代码同步,又能节省空间
- index.yaml 包含vault的元数据,让AI助手快速理解这个vault的用途和内容
- AGENTS.md 是专门写给AI助手看的指南,说明如何处理这个vault中的内容
或许这样组织起来,AI也能更容易理解你的想法吧。
系统管理的自动初始化
除了手动创建vault,HagiCode还支持系统自动管理的vault:
public async Task<IReadOnlyList<VaultRegistryEntry>> EnsureAllSystemManagedVaultsAsync( |
|
CancellationToken cancellationToken = default) |
|
{ |
|
var definitions = GetAllResolvedDefinitions(); |
|
var entries = new List<VaultRegistryEntry>(definitions.Count); |
|
foreach (var definition in definitions) |
|
{ |
|
entries.Add(await EnsureResolvedSystemManagedVaultAsync(definition, cancellationToken)); |
|
} |
|
return entries; |
|
} |
系统会自动创建和管理以下vault:
- hagiprojectdata:项目数据存储,用于保存项目的配置和状态
- personaldata:个人数据存储,用于保存用户的偏好设置
- hbsprompt:提示词模板库,用于管理常用的AI提示词
这些vault在系统启动时自动初始化,无需用户手动配置。毕竟,有些事情交给系统去做就好了,人类何必操心呢。
访问控制机制
一个重要的设计是访问控制。系统将vault分为两种访问类型:
export interface VaultForText { |
|
id: string; |
|
name: string; |
|
type: string; |
|
physicalPath: string; |
|
accessType: 'read' | 'write'; // 关键:区分只读和可编辑 |
|
} |
- reference(只读):AI仅用于分析和理解,不能修改内容。适用于参考的开源项目、文档等
- editable(可编辑):AI可以根据任务需要修改内容。适用于你的笔记、草稿等
这种区分很重要。它让AI知道哪些内容是"只读参考",哪些是"可以动手改的",避免了误操作风险。毕竟,谁也不想自己的心血被无意中改没了。
实战:创建和使用Vault
看完了原理,咱们来看看实际怎么用。
创建CodeRef Vault
以下是一个完整的前端调用示例:
const createCodeRefVault = async () => { |
|
const response = await VaultService.postApiVaults({ |
|
requestBody: { |
|
name: "React Learning Vault", |
|
type: "coderef", |
|
physicalPath: "/Users/developer/vaults/react-learning", |
|
gitUrl: "https://github.com/facebook/react.git" |
|
} |
|
}); |
|
// 系统会自动: |
|
// 1. 克隆React仓库到vault/repos/react |
|
// 2. 创建docs/目录用于笔记 |
|
// 3. 生成index.yaml元数据 |
|
// 4. 创建AGENTS.md指南文件 |
|
return response; |
|
}; |
这个API调用会完成一系列操作:创建目录结构、初始化Git子模块、生成元数据文件等。你只需要提供基本信息,剩下的交给系统处理。其实这样也挺省心的。
在AI提案中使用Vault
创建好vault后,就可以在AI提案中引用它了:
const proposal = composeProposalChiefComplaint({ |
|
chiefComplaint: "帮我分析React的并发渲染机制", |
|
repositories: [ |
|
{ id: "react", gitUrl: "https://github.com/facebook/react.git" } |
|
], |
|
vaults: [ |
|
{ |
|
id: "react-learning", |
|
name: "React Learning Vault", |
|
type: "coderef", |
|
physicalPath: "/vaults/react-learning", |
|
accessType: "read" // AI只能读取,不能修改 |
|
} |
|
], |
|
quickRequestText: "重点关注fiber架构和scheduler实现" |
|
}); |
系统会自动将vault信息注入到AI的上下文中,让AI知道你有哪些学习资源可用。AI能理解你的想法,这倒也算是一种难得的默契了。
最佳实践和注意事项
在使用Vault系统的过程中,我们总结了一些经验教训。
路径安全
系统会严格校验路径,防止路径穿越攻击:
private static string ResolveFilePath(string vaultRoot, string relativePath) |
|
{ |
|
var rootPath = EnsureTrailingSeparator(Path.GetFullPath(vaultRoot)); |
|
var combinedPath = Path.GetFullPath(Path.Combine(rootPath, relativePath)); |
|
if (!combinedPath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
throw new BusinessException(VaultRelativePathTraversalCode, |
|
"Vault file paths must stay inside the registered vault root."); |
|
} |
|
return combinedPath; |
|
} |
这点很重要。如果你在自定义vault路径,一定要确保路径在允许的范围内,否则系统会拒绝操作。安全这东西,怎么强调都不过分。
Git子模块管理
CodeRef vault推荐使用Git子模块而非直接复制代码:
private static string BuildCodeRefAgentsContent() |
|
{ |
|
return """ |
|
# CodeRef Vault Guide |
|
Repositories under `repos/` should be maintained through Git submodules |
|
rather than copied directly into the vault root. |
|
Keep this structure stable so assistants and tools can understand the vault quickly. |
|
""" + Environment.NewLine; |
|
} |
这样做有几个好处:保持代码与上游同步、节省磁盘空间、便于管理多个版本的代码。毕竟,谁愿意一遍遍地重复下载同样的东西呢。
文件预览限制
为了防止性能问题,系统限制了文件大小和类型:
private const int FileEnumerationLimit = 500; |
|
private const int PreviewByteLimit = 256 * 1024; // 256KB |
如果你的vault包含大量文件或超大文件,可能会影响预览功能的性能。这种情况下可以考虑分批处理或使用专门的搜索工具。毕竟,有些东西太大了,反而不好处理。
诊断信息
创建vault时会返回诊断信息,帮助调试:
List<VaultBootstrapDiagnosticDto> bootstrapDiagnostics = []; |
|
if (IsCodeRefVaultType(normalizedType)) |
|
{ |
|
bootstrapDiagnostics = await EnsureCodeRefBootstrapAsync( |
|
normalizedName, |
|
normalizedPhysicalPath, |
|
normalizedGitUrl, |
|
cancellationToken); |
|
} |
如果创建失败,可以查看诊断信息了解具体原因。出错了就看看诊断信息,这倒也是一种解决问题的方法。
总结
Vault系统通过统一的存储抽象层,解决了AI时代临摹项目的核心痛点:
- 知识集中管理:所有学习资源集中在一个地方,不再散落各处
- AI上下文自动注入:AI助手能够自动理解可用的学习资源,无需手动提供上下文
- 跨项目知识复用:多个学习项目之间可以共享和复用知识
- 标准化目录结构:提供一致的目录结构,降低学习成本
这套方案在HagiCode项目中已经经过了实际验证。如果你也在做AI辅助开发相关的工具,或者面临类似的知识管理问题,希望这些经验能给你一些参考。
其实技术方案的价值不在于有多复杂,而在于能不能解决实际问题。Vault系统的核心思想很简单——就是建立一个统一的、AI可理解的知识存储层。但正是这个简单的抽象,让我们的开发效率提升了不少。
有时候,简单的反而是最好的。毕竟,复杂的东西往往藏着更多的坑......
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)