使用 Stars 训练 GitHub 仓库嵌入

发布: (2026年1月3日 GMT+8 05:55)
15 min read
原文: Dev.to

Source: Dev.to

(请提供需要翻译的正文内容,我才能为您完成简体中文翻译。)

TL;DR

The Idea – 人们使用 GitHub Stars 作为书签。这是理解哪些仓库在语义上相似的极佳信号。

The Data – 处理了约 1 TB 的 GitHub Archive(BigQuery)原始数据,构建了 4 M 开发者的兴趣矩阵。

The ML – 使用度量学习(EmbeddingBag + MultiSimilarityLoss)为 300 k+ 仓库训练了嵌入向量。

The Frontend – 构建了一个仅客户端的演示,直接在浏览器中通过 WASM 运行向量搜索(KNN),无需后端。

The Result – 系统能够发现不明显的库替代方案,并实现对开发者个人资料的语义比较。

个人动机

完成想法通常比看起来更困难。构建原型很容易,但真正的挑战在于之后:打磨粗糙的边缘、撰写文本以及设置演示。这个项目是我尝试全程完成并解决那些“悬而未决”问题的努力。

我也开始思考我们 GitHub Stars 的本质。我们把它们仅仅当作“以后再看”的书签,但实际上它们是一种有价值的数字资产——我们职业兴趣和技能的快照。我在想:

  • 我们能否让这个被动资产发挥作用?
  • 我们能否利用数百万开发者积累的知识,构建一个仓库推荐系统,让人们比较自己的技术兴趣?

概念

集群假设

阅读本文的读者在兴趣上比街上随意挑选的陌生人更相似。在我们的宇宙中,相似的事物常常出现在相似的上下文中。

我们直观地感受到这些“隐藏”的偏好。如果你看到一位新同事使用 Vim 编写代码并在没有帮助的情况下退出,你可能已经在脑中构建了他们兴趣的向量:你大概可以和他们讨论在 FreeBSD 上为 KDE2 打补丁,但询问关于 RGB 游戏鼠标的建议可能就不太合适。

仓库表示

我们希望构建一个空间,使语义相似的仓库彼此靠近。
为了说明,想象一个二维空间,其坐标轴为:

  • Axis X: 数据(准备 & 分析) ↔ 模型(训练 & 推理)
  • Axis Y: 本地 / 单节点 ↔ 大数据 / 集群

语义象限

实际上,神经网络会自行学习这些(往往难以解释的)特征。数学本质保持不变:相似的仓库会根据学习到的特征被拉拢到同一簇中。

有了这些向量,我们可以:

  • 使用 余弦相似度(向量之间的夹角)搜索相似的仓库。
  • 通过对用户 已加星 仓库的向量取平均,得到用户兴趣向量。
  • 将用户画像相互比较。

信号来源

为了获得高质量的向量,我采用了混合方法。

  1. 文本(README.md) – 初始化
    许多仓库都有 README,这是一个很好的“冷启动”来源。我使用了 Qwen3‑Embedding‑0.6B 模型(支持 Matryoshka Representation Learning),并仅保留前 128 维(最重要的成分)。这些向量作为可训练模型的 初始权重

    注意: 这一步约提升最终质量的 10 %。为了保持公共仓库的轻量,我省略了它;模型从随机初始化也能学习,只是稍慢一些。

  2. 星标矩阵 – 主训练
    单靠文本无法体现工具之间的协同使用。协同过滤可以捕捉到这一点。

    User → Starred repositories
    A    → Pandas, Dask, scikit‑learn, NumPy
    B    → Vue, React, TypeScript, Vite

    可选方法包括图算法(LightGCN)或矩阵分解。我选择 度量学习,因为它需要的 GPU 资源更少(≈1 块 GPU,约 8 GB),且在管理向量空间时更灵活。

数据准备

Data were sourced from the public GitHub Archive dataset in BigQuery.

Two queries were required:

QueryPurpose
Stars (WatchEvent)收集拥有 10 – 800 星标的用户(过滤机器人和不活跃用户),并保留星标顺序。
Meta (PushEvent)收集仓库名称、提交日期和描述。

The queries processed ~1 TB of data and almost fit within the BigQuery Free Tier. The output was a Parquet file containing ~4 M users and ~2.5 M unique repositories.

训练向量

模型选择

为了让解决方案在浏览器中保持轻量,我排除了 Transformers。
模型是经典的 torch.nn.EmbeddingBag —— 本质上是一个大型查找表:

repo_id → vector[128]

它可以高效地聚合(平均)向量。

采样与损失函数

我们如何告诉网络 PandasNumPy 是“接近”的?

对于每个用户,我将他们的星标仓库列表拆分成两个随机的、互不重叠的 ,并将它们用作正样本对。负样本则从其他用户的桶中抽取。损失函数使用 MultiSimilarityLoss,其目标是:

  • 拉近 正样本对。
  • 推远 负样本对。

这种简单的方案在不进行昂贵图计算的情况下捕获了协同过滤信号。

推理与前端

训练好的嵌入(128 维向量)被导出为静态二进制文件(约 150 MB)。在浏览器中:

  1. 通过 fetch 加载文件并解码为 Float32Array
  2. 使用 FAISS‑like 产品量化的 WebAssembly(WASM)模块实现快速余弦相似度搜索。
  3. UI(纯 HTML + CSS + Vanilla JS)让用户:
    • 使用 GitHub 进行身份验证 → 获取已加星的仓库 → 计算其兴趣向量。
    • 可视化技能分布雷达图。
    • 搜索相似仓库或比较个人资料。

所有这些都在客户端运行;无需服务器或 API 密钥。

结果

  • 系统会呈现非显而易见的库替代方案(例如,向 Pandas 爱好者推荐 Polars)。
  • 用户画像相似性热图揭示了具有共同兴趣的开发者聚类。

欢迎随意探索演示,给仓库加星,或在有建议时打开 issue!

用于桶级聚合的 EmbeddingBag

我们使用 EmbeddingBag 来计算每个桶的聚合嵌入。

用户桶中的仓库平均值(桶中的嵌入)
AA1NumPy, Dask, SciPy[0.2, -1.1, 0.9, …]
AA2Pandas, SK‑Learn[0.1, -1.3, 0.6, …]
BB1Vue, Vite[-0.4, 0.6, 0.2, …]
BB2React, TypeScript[-0.3, 0.7, 0.1, …]

训练目标

我们训练嵌入,使 以下两个条件 同时成立:

  • 用户内部凝聚 – 同一用户的桶应尽可能接近(例如,A1A2)。
  • 用户间分离 – 不同用户的桶应被推得尽可能远(例如,B1A2)。

梯度下降在这两种相反的力量之间取得平衡,以最小化整体误差。

损失函数

表现最佳的损失是来自 pytorch-metric-learning 库的 MultiSimilarityLoss

注: 我们要感谢 StarSpace,它在八年前提出了这一思路。

高级方法 vs. 简约

我们自然会认为用户给仓库加星的顺序(即“星标序列”)会包含强信号,于是我们尝试了 Word2Vec‑style 滑动窗口模型。

令人惊讶的是,最简单的随机划分优于所有更复杂的方法。
可能的原因:

  • 时间数据噪声过大。
  • 我们未能从中提取有用信息。

我们还尝试了:

  • Hard Negative Miners。
  • 替代损失函数,例如 NTXentLoss(其内存使用约是 MultiSimilarityLoss 的 4 倍)。
  • Cross‑Batch Memory(未见明显收益)。

这些方法都未能超越原始基准。有时 Occam’s razor 确实占上风;而有时,剃刀只是钝的。

质量评估

拥有向量是一回事——它们真的有用吗?

我们没有使用 LLM 生成的合成数据,而是采用了更优雅的真实标签:Awesome Lists(例如 “Awesome Python”、 “Awesome React”)。这些是人工策划的相似库集合。

  1. 下载列表的 README。
  2. 提取共现(哪些仓库一起出现)。
  3. 应用启发式加权。
  4. 使用 NDCG 指标评估排序。

该流水线让我们能够公平地比较损失函数、超参数和采样策略。

前端:展示与 AI‑辅助开发

即使拥有十年的数据科学经验,我也不是前端专家。挑战在于在没有后端不是 JS 开发者的情况下构建复杂的客户端逻辑。

所有前端以及“胶水”代码都是在AI 编码代理的帮助下编写的。

架构

  • 数据 – 客户端下载压缩的嵌入(FP16,约 80 MB)和元数据,然后将其缓存到 IndexedDB 中。
  • 搜索(WASM) – 使用 USearch 库的核心,编译为 WebAssembly。

底层魔法

最初我们尝试了预先计算的 HNSW 索引,但它占用的内存比原始嵌入还要多。

AI 代理通过以下方式实现了 精确搜索(仍在 WASM 中):

  1. 暴露底层的 _usearch_exact_search 方法。
  2. 生成一个工作线程 (coreWorker.js),手动管理内存,通过 _malloc 分配缓冲区,并操作指针。
  3. 添加即时的 FP16 → FP32 转换器,因为浏览器对原生 FP16 的支持不佳。

最终实现了在约 300 k 向量上进行快速精确搜索,而无需任何 HNSW 索引。

Source:

用户画像与技能雷达

用户嵌入

  1. 客户端查询 GitHub API,获取用户已加星的仓库。
  2. 检索这些仓库的 embeddings
  3. 对它们求平均,得到 均值向量——用户兴趣的数字指纹。

由于该向量与仓库嵌入位于同一度量空间,我们可以搜索“最近”的库。

技能雷达(向量解释)

  1. 提示 LLM 为每个 10 类别(例如 “GenAI”、 “Web3”、 “系统编程”)生成 20 个参考仓库
  2. 训练简单的 Logistic Regression(线性探针),以区分这些类别的向量。
  3. 在浏览器中,将用户向量输入这些探针,得到雷达图的概率得分。

无服务器共享

  • 相似度度量: 余弦相似度,经过 Quantile Transformation 转换,使得分数以百分位显示(例如,“95 % 匹配” 表示用户比随机配对中 95 % 的情况更相似于该开发者)。
  • 共享机制: 将用户向量压缩后进行 Base64‑编码,并直接嵌入 URL 片段标识符 (#…) 中。无数据库,无后端——纯客户端计算。

结果:期望 vs. 现实

除了量化指标外,我们还进行了“肉眼测试”。

哪些没有奏效

  • 向量算术 类似于 NLP(King – Man + Woman = Queen)。
    假设: Pandas – Python + TypeScript = Danfo.js
    现实: 仓库的向量空间要复杂得多,简单的线性运算并不能得到可解释的结果。

  • 明显的聚类 —— 嵌入向量并未形成清晰分离的可视化簇。

哪些奏效了

  • 主要目标已实现:搜索能够为用户标星的仓库找到相关的替代方案

总体而言,系统展示了 简单、无服务器、仅客户端 架构也能从大规模嵌入空间中提供有用的个性化推荐。

小众工具与新颖解决方案

不同于经常偏向最流行解决方案的 LLM,这种基于 IT 专业人士行为 的方法能够发现:

  • 小众工具: 专业人士使用但在博客中很少提及的库。
  • 新颖解决方案: 最近获得人气且呈现相似“星标模式”的仓库。
  • 本地优先: 所有内容均在客户端设备本地运行。

Future Vision

当前演示展示了在没有后端的情况下可以实现的功能,但还有许多其他用例是可以想象的。

可以训练一个文本编码器,并在其上添加投影层映射到仓库嵌入空间,从而实现通过抽象描述搜索工具或人员。

GitHub Tinder (Networking)

通过用户向量,我们可以匹配人员:

  • Mentor or co‑founder search – 找到拥有互补技术栈的人。
  • Contributor discovery – 识别对相似项目加星但尚未看到你的项目的开发者。
  • HR‑Tech – 根据技术兴趣将候选人与职位匹配。

Trend Analytics

加入时间维度后,可在数月或数年间追踪新兴技术和开发者兴趣的变化。

Back to Blog

相关文章

阅读更多 »

翻页(不重置系统)

引言 新的一年并不是重置按钮。经验上没有 git reset --hard —— 没有可以抹去成功、失败或什么…的干净板块。

微型语言模型

Forem 动态 !Forem 标志 https://media2.dev.to/dynamic/image/width=65,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.co...