第一次接手一个陌生仓库,很多人会从 README 开始。
但真正让人停下来的,通常不是"这个项目是做什么的",而是更具体的几个问题:入口在哪里?这个模块被谁调用?改动一个文件会影响哪些路径?如果我只想修一条回调链,应该先读哪几个目录?
这些问题看起来像是阅读问题,实际上更接近一张地图缺失的问题。
文件树只能告诉你代码放在哪里,README 只能告诉你作者希望如何介绍项目,真正决定阅读顺序的,往往是符号之间的调用关系。
现在,CodexQA 新增的 codexqa-code-wiki skill,尝试把这张地图从代码里直接画出来:先用 CodexQA 建立符号索引,再把调用图切成模块,最后生成一份可以离线打开的架构 Wiki。
它不要求模型替你猜测整个仓库,也不让 Agent 直接手写一张容易过期的架构图。
它更想回答的是另一个问题:当一个人刚克隆仓库,他能不能在一页页面里知道,应该从哪里开始读?
代码很多,但真正难的是找到第一步
大型仓库的复杂,通常不是文件数量本身,而是文件之间的关系被分散在不同地方。
一个命令行入口可能调用应用层的编排逻辑,应用层再调用领域服务,领域服务又依赖一组解析器、存储适配器和报告渲染器。任何一层单独打开,都能看到不少代码;但如果不知道调用方向,阅读就会变成目录之间的来回跳转。
传统的代码 Wiki 往往有两种做法:
- 由人手工维护目录、模块和架构图;
- 让模型根据仓库内容生成一份解释。
前一种容易过期,后一种容易把"看起来合理"误写成"代码确实如此"。尤其是调用次数、模块边界和阅读路径,一旦没有确定的工程数据支撑,页面很快就会和代码分叉。
codexqa-code-wiki 选择把问题拆成两半:
- 事实由符号图和确定性脚本负责;
- 名称、职责说明和阅读建议由 Agent 写入一个受校验的
notes.json。
换句话说,页面上的连线、数量、文件和符号,不由文案决定;文案也不能反过来创造一条代码里不存在的调用关系。
三步生成一份架构 Wiki
整个流程只有三个核心动作:brief、notes 和 build。
第一步是 brief。它会对本地仓库做增量索引,导出 CodexQA 的 wiki inputs,并生成一份简报。简报里包含模块、分组、调用方向、调用次数、被调用关系、公开符号、关键方法流以及推荐阅读路径。
这一步不会调用模型。它做的是把仓库变成一份可供后续处理的事实数据。
第二步是填写 notes.json。Agent 只需要补充几类人能读懂的内容:仓库叫什么、每个模块负责什么、模块之间为什么会连在一起,以及面对不同任务应该怎么读。
JSON
json
{
"lang": "zh",
"title": "CodexQA 技能仓库",
"tagline": "把仓库变成一页可搜索、可追溯的架构 Wiki。",
"overview": "先看入口和主链路,再按真实调用关系深入模块。"
}
第三步是 build。脚本会校验这些文字是否引用了真实存在的模块,检查阅读路径中的相邻步骤是否确实互相调用,再把导出事实、说明文字、架构图、搜索和主题切换合并成一个自包含 HTML 文件。
Bash
javascript
node <skill>/scripts/wiki.mjs build <repo>
如果 notes.json 里写了一条不存在的模块,或者把两个没有调用关系的模块强行串成阅读路径,构建会直接报错,而不是安静地生成一张漂亮但错误的图。
一张图里,哪些信息来自代码?
打开生成的页面,可以看到几类信息。
首先是模块地图。模块不是简单按照文件夹切出来的,而是从符号调用图中识别出的社区,再结合目录先验和页面上限整理出来。一个模块可能包含多个目录,也可能把一批共同依赖工具的脚本聚在一起。
其次是调用关系。模块卡片会列出它调用了谁、被谁调用,以及静态符号图中统计到的调用次数。架构图会根据调用强度调整连线,并标出组内连接较多的枢纽模块。
再次是公开接口和关键流程。页面会展示模块中较重要的公开符号,以及方法流里出现的调用步骤。读者可以从模块职责继续下钻到符号,再跳到源码文件。
最后是阅读路径。比如"要改扫描流程",页面可以给出一条从入口到编排层、再到报告渲染的路径。路径不是模型凭经验编出来的,每两个相邻模块之间都要存在真实调用关系。
这让架构 Wiki 不再只是"项目介绍",而更像一份带导航的代码地图。
从文件树到符号图
文件树回答的是"代码放在哪里"。
符号图回答的是"代码如何一起工作"。
这两种视角并不互相替代。文件仍然是最终需要打开和修改的对象,但调用图可以帮助读者决定打开顺序。
对于一个陌生仓库,最常见的阅读路径可能不是从最大的目录开始,而是从一个能把多个模块串起来的枢纽开始:先理解入口如何组织任务,再看它依赖的核心模块,最后进入被多个路径复用的基础能力。
codexqa-code-wiki 会根据模块之间的调用关系给出建议路径。对于没有跨模块调用的独立模块,它不会强行把它放进某一层架构,也不会编造一条不存在的链路,而是单独标识出来。
这一点很重要。
架构图最容易犯的错误,不是少画一条线,而是为了让图看起来完整,画出代码里没有的线。
一个模型,两种责任
这套设计背后有一个简单的分工:模型负责表达,人负责确认,脚本负责守住边界。
脚本负责的内容包括:
- 模块规模和文件数量;
- 模块之间的调用关系与方向;
- 静态调用次数;
- 公开符号和方法流;
- 架构图的布局与连线;
- 源码文件链接、搜索、主题和打印样式。
Agent 负责的内容包括:
- 用人话给模块命名;
- 解释模块承担的职责;
- 提炼新人真正需要知道的阅读提示;
- 为具体任务组织阅读顺序。
两者之间通过 notes.json 连接。它不是一个随意的配置文件,而是整个页面中唯一允许模型写入文字的地方。
因此,页面可以有不同的表达方式,但不会因为换了一次文案,就改变模块数量、调用次数或架构连线。
同一份导出,在不同语言、不同标题和不同阅读任务下,也能重新生成页面;事实保持不变,解释可以继续迭代。
生成的不是一张静态截图,而是一份可读的页面
最终产物是单个 HTML 文件,不依赖 CDN,也不需要启动服务。
页面里包含:
- 架构图与模块高亮;
- 模块、符号和文件搜索;
- 模块卡片与调用详情;
- 推荐阅读路径;
- 白天 / 黑夜主题;
- 手机阅读和打印样式;
- 提交号、分支、生成时间和工作区状态。
这意味着它可以直接作为代码评审前的背景材料,也可以作为新人 onboarding 的附件,或者在没有网络的环境里打开。
当代码发生变化时,不需要手动修改 HTML。重新运行 brief,更新必要的 notes.json,再 build 一次即可。
页面事实来自新一轮导出,说明文字则会在构建阶段被重新校验。
这不是"让模型理解整个仓库"
codexqa-code-wiki 有意把目标限定在架构和上手问题上。
它可以帮助你回答:
- 这个仓库由哪些模块组成?
- 哪些模块互相调用?
- 一个模块对外暴露了哪些符号?
- 我应该从哪里开始读?
- 修改某条主链路时,下一步应该看哪里?
但它不负责回答:
- 这次变更会影响哪些测试?
- 某个 PR 是否存在缺陷?
- 哪个问题应该打 P0、P1 或 P2?
- 某段代码是否存在安全风险?
这些问题分别属于变更影响分析、代码评审和缺陷扫描。把不同问题交给不同技能,反而比让一份"万能 Wiki"承担所有判断更可靠。
能力从哪里来?
这份架构 Wiki 的核心能力,来自三层配合。
数据:符号调用图
CodexQA 先对仓库建立本地索引,再导出架构、模块页面、公开符号和方法流等数据。索引与导出都在本地完成,生成 Wiki 的主流程不需要 LLM。
调用次数代表符号图中的静态引用,不代表线上流量;箭头表示代码关系,不代表运行时一定会走到这条路径。这些边界会在页面和已知限制中明确标出。
模型:确定性的模块整理
脚本把导出的模块和页面数据转成统一的数据模型,再计算连接关系、组、枢纽、调用方向和建议路径。
同一份输入会得到同一组模块和连线。架构图不是每次由模型重新"想象"出来的,因此更适合做增量更新和版本对比。
表达:少量、受约束的文字
最后才是人话说明。Agent 不需要重写整个页面,只需要给模块补上名字、职责和阅读提示。
如果模块发生了变化,构建会检查 source、模块成员和路径是否仍然匹配;如果代码里的分组已经移动,页面不会默默保留旧解释。
仍然有边界
任何从静态图生成的架构视图,都不应该被理解为运行时真相。
目前这份 Wiki 的调用次数来自符号图中的静态引用;模块是调用图上的社区,不等同于文件夹或业务分层;导出会受社区数量和页面上限影响;没有统计到次数的关系可能只能显示为无计数连线。
对于 stub 节点较多、同名符号碰撞明显或导出覆盖率较低的仓库,模块边界的置信度也会下降。
这些信息不是要藏起来的缺点,而是架构文档的一部分。页面会展示分支、提交号、工作区是否有未提交修改、导出覆盖率和截断提示,让读者知道这张地图是在什么条件下生成的。
好的代码 Wiki 不应该假装自己无所不知。
它应该让人知道哪些是事实,哪些是解释,哪些地方还需要回到代码里确认。
结语
对一个陌生仓库来说,最宝贵的并不是又一份更长的说明文档,而是一个可靠的第一步。
codexqa-code-wiki 没有试图替工程师读完整个仓库,也没有试图用一张图替代所有文档。它做的是把符号调用关系整理成模块,把模块关系整理成阅读路径,再把这些事实和少量解释放进一份可搜索、可离线打开的页面里。
从"仓库里有什么",到"谁调用谁",再到"我应该先读哪里",这条路径被压缩成了三个命令和一个 HTML 文件。
当代码持续变化、人员持续交接、架构文档很难同步时,也许最值得保留下来的,不是某个人记忆里的系统结构,而是一张能够从当前代码重新生成的地图。
这张地图未必解释所有事情。
但它至少能让下一位读者,不必从目录树里盲目开始。 github.com/openqa-cn/c...