大型语言模型能够快速编写代码,但它们仍然会记错API的用法,忽略与特定版本相关的细节,并且会在会话结束后忘记自己所学的内容。

这就是Context Hub试图解决的问题。

Context Hub(简称chub)为编程辅助工具提供了经过整理、按版本分类的文档和技能资源,这些资源可以通过命令行界面进行搜索和获取。此外,它还为这些辅助工具提供了两种学习机制:用于辅助工具记忆的本地注释功能,以及供维护人员使用的反馈系统。

在本教程中,你将了解官方chub工作流程的具体运作方式,了解Context Hub是如何组织文档和技能资源的,了解注释和反馈机制是如何帮助形成记忆循环的,以及如何构建一个辅助相关性引擎,以便在不破坏上游内容模型的前提下提升信息检索效果。

本教程同时使用了两个公共仓库来进行演示:

我还将自己的分支代码提交到了上游项目的主仓库中,如果你想跟踪这篇教程中提到的相关开发工作,可以查看按作者筛选后的上游拉取请求列表:提交的pull requests

我们将要构建什么

完成本教程后,你将掌握以下内容:

  • 对Context Hub的工作原理有清晰的理解

  • 能够成功在本地安装并使用官方的chub命令行工具

  • 掌握一套可重复使用的搜索、获取数据、添加注释以及提供反馈的工作流程

  • 了解如何构建一个能够在Context-Hub风格的内容结构基础上进一步优化信息检索效果的辅助代码库

  • 熟悉一种可用于进行端到端测试的小型基准测试工具及相应的本地对比界面

  • 明白如何将辅助代码库与上游的拉取请求有效地结合起来使用

先决条件

在开始学习之前,请确保你已经具备以下条件:

  • Node.js 18或更高版本

  • npm工具

  • 熟悉终端操作环境

  • 对Markdown格式有一定的了解

目录

  1. 如何理解Context Hub

  2. 如何了解官方仓库、辅助代码库以及上游拉取请求

  3. 如何安装并使用官方命令行工具

  4. 如何理解文档、技能资源以及内容布局结构

  5. 如何使用增量式数据获取机制与分层资源结构

  6. 如何利用注释和反馈功能构建记忆循环

  7. 如何找出信息检索仍然存在问题的地方

  8. 辅助相关性引擎是如何提升检索效果的

  9. 如何端到端地运行辅助代码库

  10. 如何正确解读测试结果

  11. 如何将辅助代码库与上游拉取请求连接起来

  12. 总结

  13. 参考资料

如何理解Context Hub

将Context Hub理解为一种工作流程会更容易理解——这种流程能够将变化迅速的文档转化为编程工具可使用的可靠输入数据。

与其让编程工具依赖它从训练数据中记住的信息,不如为它制定一份可预测的操作规范:

  1. 搜索正确的条目

  2. 获取相应的文档或技能信息

  3. 根据这些整理好的内容编写代码

  4. 将学习过程中的关键点保存为注释

  5. 向维护者反馈有关文档质量的建议

示意图展示了从开发者的指令到工具的搜索与数据获取,再到生成注释及接收维护者反馈的整个流程。

这种系统边界划分非常重要。

这样的设计使得编程工具更易于被审计、更便于改进,也更容易进行扩展。同时,它还能确保接口的复杂性保持在可控范围内,从而帮助人们判断问题究竟发生在哪个环节。如果编程工具仍然无法找到正确答案,你就可以进一步分析问题是出现在搜索阶段、数据获取阶段、上下文选择阶段,还是内容生成阶段。

如何理解官方仓库、辅助仓库以及上游拉取请求

本教程有意将代码库和开发路径分为三部分进行讲解。

官方的上游项目andrewyng/context-hub是真正实现CLI功能、内容模型以及相关工作流程的代码基础。如果你想了解当前版本的chub是如何工作的,就应该使用这个仓库。

辅助仓库natarajsundar/context-hub-relevance-engine则是将本文中提到的各种理念具体化为可实际操作的代码的地方。它是一个辅助性实现工具,并非替代产品,它的作用是让各种检索相关的优化方案变得可见、可测量,并且能够方便地在本地进行测试。

上游拉取请求则起到了连接这两个仓库的作用。在辅助仓库中,你可以更快地针对基准测试、排序算法以及用户界面进行迭代开发;而通过上游拉取请求,你可以将那些较小规模的修改提案提交到主项目中进行审查。你可以通过以下链接追踪这些拉取请求:按作者筛选的上游拉取请求

这种三分结构的安排使得这篇文章的内容更加清晰明了:

  • 使用上游仓库来了解当前系统的运作机制

  • 利用辅助仓库来全面探索各种相关的改进方案

  • 通过上游拉取请求来了解如何将一个复杂的想法分解成多个便于审查的模块

如何安装和使用官方CLI

官方的快速入门指南篇幅较短,这是有意为之。

npm install -g @aisuite/chub

安装完CLI后,你可以搜索可用的功能并获取特定的内容:

chub search openai
chub get openai/chat --lang py

这就是最简单的使用方法,但了解整个请求流程还是很有帮助的。

序列图显示开发者向智能体询问当前文档,智能体调用chub search和chub get命令,CLI从注册表中获取文档。

实际上,最重要的是要明白:CLI是为智能体设计的,而不仅仅是供人类手动使用的。

因此,上游的CLI也提供了get-api-docs这个功能。例如,如果你使用Claude Code,就可以将这个功能复制到你的本地项目中:

mkdir -p .claude/skills
cp $(npm root -g)/@aisuite/chub/skills/get-api-docs/SKILL.md \
  .claude/skills/get-api-docs.md

这样就可以让智能体养成获取文档的习惯:

在使用第三方SDK或API编写代码之前,请先使用chub来查询相关文档,而不要自己猜测。

这种行为规则往往与文档本身一样重要。

如何理解文档、功能以及内容结构

Context Hub将内容分为两大类:

  • 文档,用于回答“智能体应该了解什么?”这个问题。

  • 功能,用于指导“智能体应该如何行动?”。

这种分类方式使得内容结构更易于扩展。文档可以设置版本并进行语言区分,而功能则可以保持简洁实用。

目录结构也是清晰可预测的。内容管理工具会按照作者、文档类型或功能类别,再按条目名称来组织内容。

结构图显示从作者到文档、再到功能的层次关系,DOC.md和SKILL.md文件会被用于生成注册表数据和搜索结果。

下面是一个简单的例子:

author/docs/payments/python/DOC.md
author/docs/payments/python/references/errors.md
author/skills/login-flows/SKILL.md

这就是Context Hub易于使用的其中一个原因。

所有内容都采用简单的Markdown格式编写,主要文件的结构也是固定的,构建后的输出结果也便于查看。因此,你无需逆向分析隐藏的代码逻辑就能了解智能体正在读取什么内容。

如何使用增量式数据获取与分层资源

Context Hub最出色的设计特点之一就是:它不会强制你在每次请求时都将所有文件都注入到模型中。

相反,入口文件会提供整体概览,而参考文件则包含更详细的内容。

示意图说明chub get可以仅获取主入口文件、特定的参考文件,或整个目录内容。

这样,你就可以分阶段、逐步获取内容。

chub get stripe/webhooks --lang py
chub get stripe/webhooks --lang py --file references/raw-body.md
chub get stripe/webhooks --lang py --full

这一功能既是一种文档管理工具,也是一种基于令牌预算的机制。一个优秀的代理程序应先加载整体概览,确定哪些内容是关键部分,然后再获取具体的支持文件。

Context Hub还支持分层资源结构。你可以通过`~/.chub/config.yaml`文件将公共内容与本地构建结果合并起来。

示意图展示社区资源、官方资源以及本地团队资源如何合并为统一的搜索界面,以便用户通过chub search或chub get获取所需信息。

最简单的配置方式如下:

sources:
  - name: community
    url: https://cdn.aichub.org/v1
  - name: my-team
    path: /opt/team-docs/dist

这样,你就可以将公共文档放在一个路径下,将团队特定的运行手册放在另一个路径下,同时让代理程序仍能提供统一的搜索界面。

如何利用注释和反馈构建记忆循环

Context Hub提供了两种不同的改进途径。

注释是本地存储的,它们有助于代理程序记住上一次操作的成功经验;而反馈则是共享的,它能够帮助维护者为所有人完善文档。

这种区分非常重要,因为并非所有的经验教训都适合被纳入共享数据库中。有些内容仅适用于特定环境,而另一些则反映了需要集中解决的内容质量问题。

示意图展示代理程序的数据获取/写入流程,以及在执行下一项任务之前如何参考本地注释或维护者的反馈。

下面是本地记忆机制在实践中的应用示例:

chub annotate stripe/webhooks \
  "注意:在使用Stripe进行签名验证时,request.data必须保持原始格式。"

以下就是反馈处理的流程:

chub feedback stripe/webhooks up

这个循环虽然很简单,但却是该项目中最重要的设计理念之一。它将一次性的调试过程转化为持久化的本地数据记录,或者成为提示共享文档需要改进的信号。

如何判断哪些地方的相关性分析还存在缺陷

上游项目已经采用了较为完善的排序机制。它利用BM25算法以及词汇匹配技术,确保类似包名的标识符、精确的关键词以及模糊搜索结果都能被正确显示出来。

这确实是一个相当不错的基础方案。

然而,开发人员在实际使用中输入的查询语句往往比包名要复杂得多。

人们经常会搜索以下内容:

  • rrf

  • signin

  • pg vector

  • hnsw

  • raw body stripe

这些查询并不算“错误”的,它们只是人们在实际使用中常用的简化表达方式罢了。

而且,这些查询也暴露出了内容模型本身存在的一个问题:许多准确的答案其实都存储在诸如references/rrf.mdreferences/raw-body.mdreferences/hnsw.md这样的参考文件中。

所以,问题并不在于当前的搜索功能是否有效——显然它是有效的。真正需要探讨的是:

如何在不破坏现有内容框架的前提下,进一步提升搜索效果呢?

配套仓库中的解决方案就是保留现有的模型结构,再在其基础上添加一层重新排序的机制。

辅助相关性引擎是如何提升搜索效果的

本文提到的配套仓库地址是context-hub-relevance-engine

这个仓库依然保留了让Context Hub具备吸引力的那些核心设计元素:

  • 纯Markdown格式的内容

  • DOC.mdSKILL.md这两种文档格式

  • 可供查看的构建结果文件

  • 本地注释与反馈功能

  • 渐进式的数据获取机制

此外,这个仓库还新增了一个构建产物:signals.json

在构建过程中,该引擎会提取一些额外的信息,例如:

  • 主文件中的标题信息

  • 参考文件中的标题和关键词

  • 语言类型及版本信息

  • 源代码的元数据及其新鲜度

  • 不同注释之间的重叠情况

  • 之前的反馈记录

初次搜索时的处理过程依然简单且透明。只有在基础排序完成之后,才会进行重新排序操作。

示意图展示了从用户查询开始,到经过BM25算法和词汇匹配处理,再进入同义词扩展、候选结果筛选、重新排序,最终得到搜索结果的整个流程。

采用这种方法有两个重要原因。

首先,它是可叠加的。你无需重新设计内容结构。

其次,它是可测量的。你可以明确界定各种故障模式,逐一进行修复,并且每次修改评分机制后都可以重复运行相同的测试基准。

如何端到端地运行配套代码库

GitHub上打开该代码库,使用常规的克隆流程将其复制到本地,然后从项目根目录执行以下命令。

cd context-hub-relevance-engine
npm install
npm run build
npm test

该代码库不依赖任何第三方运行时环境,因此执行`npm install`主要是为了保持开发流程的连贯性。所有主要的命令实际上都是普通的Node.js脚本。

如何重现“基线失败”情况

首先使用查询指令`rrf`进行测试。

node bin/chub-lab.mjs search rrf --mode baseline --lang python

预期输出结果:

No results.
接下来再使用改进后的模式进行测试。

node bin/chub-lab.mjs search rrf --mode improved --lang python

预期的最佳搜索结果应为:

langchain/retrievers [doc] score=320.24
适用于混合搜索、父文档查询、查询扩展及重新排序的可组合检索方案。

之所以能得到这样的结果,是因为改进后的模式会关注不仅仅是顶层条目的描述信息,还会考虑参考文件的标题`rrf`、通过查询扩展得到的相关术语,以及提取出的数据中存在的词汇重叠部分。

如何重现“工作流程意图相关胜利”情况

现在尝试使用登录相关的查询指令进行测试。

node bin/chub-lab.mjs search signin --mode baseline
node bin/chub-lab.mjs search signin --mode improved

在“基线模式”下会找不到结果,而改进后的模式会返回`playwright-community/login-flows`,因为重新排序机制将`signin`、`sign in`、`login`以及`authentication`这些术语视为相关的搜索意图。

如何测试内存循环机制

首先编写一条本地注释:

node bin/chub-lab.mjs annotate stripe/webhooks \
  "注意:在使用Stripe进行签名验证时,请求数据必须保持原始格式。"

然后获取相关文档内容:

node bin/chub-lab.mjs get stripe/webhooks --lang python

你会看到文档的主要内容、可用的参考文件列表,以及添加的注释信息。
这正是我们期望代理程序的内存循环机制所具备的功能:一次学习,多次重复使用。

如何运行测试基准

从空数据库开始操作:

npm run reset-store
node bin/chub-lab.mjs evaluate

使用空数据库进行测试时,系统会生成如下统计结果:

测试模式 最佳准确率 MRR值
基准状态 0.333 0.333
优化后的状态 1.000 1.000

你也可以先为数据库设置初始数据,然后再重新运行测试:

npm run seed-demo
node bin/chub-lab.mjs evaluate

这种操作可以证明:当用户的查询内容与系统的历史记录有重叠时,注释和反馈信息确实能够帮助系统提高搜索效果。

如何启动本地对比界面

npm run serve

然后在浏览器中访问 http://localhost:8787

该界面允许你同时查看基准状态和优化后的搜索结果,查阅系统中保存的注释和反馈信息,重新生成测试数据,并且能够一次性完成所有测试操作。

如何客观地解读测试结果

这个仓库中的测试案例数量故意设置得较少。

这其实是一种设计意图,而不是缺陷。

这样做的目的是为了让人们能够更容易地重现一些常见的错误情况,例如:

  • 缩写形式的查询词

  • 简化的操作流程相关查询词

  • 针对参考文件的查询词

  • 与内存使用情况相关的排序算法

这样的设计能够确保测试结果的客观性。

如果未来的评分规则发生变化,从而影响了 rrfsigninraw body stripe 等指标,你就能立即发现这一点。而如果你后来添加了更强大的测试数据集,这些原有的测试案例也可以作为防止性能下降的参考。

该仓库中包含的测试文件有:

  • demo/benchmark.json

  • docs/benchmark-empty-store.json

  • docs/benchmark-seeded-store.json

  • docs/relevance-improvement-plan.md

如何将辅助仓库与上游拉取请求关联起来

一个优秀的辅助仓库应该具备足够的包容性,以便人们能够快速探索各种想法;而一个优秀的上游拉取请求则应该具有明确的针对性,便于审查人员进行细致的评估。

因此,这两个仓库的内容不应该完全相同。

辅助仓库用于保存与搜索效果优化相关的所有资料,包括:

  • 本地对比界面

  • 模拟测试用例

  • 用于优化排序算法的各种数据

  • 调试工具和解释功能

  • 详细说明各种设计决策的文档

而上游拉取请求则应该规模较小,且针对的具体问题更为明确。在实际操作中,通常会先提出那些最容易进行审查的部分内容来进行讨论。
  1. 从参考文件中提取相关信息

  2. 提供可解释的评分结果,便于调试

  3. 采用轻量级的基准测试框架格式

  4. 通过一个标志来控制排序逻辑的添加

这样的设计既保证了主代码库的可维护性,同时也让相关文章及辅助代码库能够完整地阐述整个工程方案。与这项工作相关的主流Pull请求链接如下:提交的Context Hub Pull请求

结论

Context Hub的真正价值并不在于它能够存储文档,而在于它为改进编码辅助工具提供了明确的系统边界。你可以查看这些辅助工具具体读取了哪些内容,也可以决定它们应该在何时获取数据;你还可以将公开资源与私有资源结合起来使用,同时保留本地学习成果,并且可以在不破坏整个系统结构的情况下优化排序机制。

配套的相关性引擎展示了如何保留现有功能,使系统的某一部分得到显著改进,そして将这些改进结果打包成其他开发者可以运行、测试和扩展的形式。而那些主流的Pull请求则说明了如何将一个宏观的想法分解成若干在主项目中便于审核的小部分。

图表来源说明

本文中使用的所有图表都是由作者专门为本教程及其辅助代码库制作的。

参考资料

Comments are closed.