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)