本页目录
DeepSeek Harness 有 12,578 个文件、898,685 行代码。直接把整个仓库丢给模型没有用,因为它根本放不进上下文窗口。我的做法是先给模型一份这个仓库的“地图”:入口在哪、分几层、哪些文件改得最多、哪里有循环依赖,再让它按地图去读具体文件。这篇文章用 DeepSeek 驱动 Claude Code,通过 MCP 把这份地图交给模型,然后用同样的方法看一眼火山引擎的 OpenViking 作对照。
文中所有数字都来自 repowise 对这两个仓库的公开索引,每个数字都能在对应页面上核对:deepseek-ai/deepseek-harness(索引于 2026-09-28)和 volcengine/openviking(索引于 2026-06-14)。
为什么不让模型直接读代码
模型读代码的方式和人在终端里差不多:grep 一下,打开几个文件,再 grep。这在几十个文件的项目里很好用。到了一万多个文件的仓库,问题就变成了“先读哪几个”。读错了,上下文窗口很快就被无关的文件占满,后面的回答越来越偏。
所以我把问题拆成两步:
- 先读预先算好的结构信息:模块、分层、入口、热点、依赖关系。这部分很小,几千 token 就够。
- 再按需读源码:模型知道该打开哪个文件,才去打开它。
MCP(Model Context Protocol)就是把第一步变成“模型可以调用的工具”的标准做法。模型不用猜,直接调用 get_overview 拿到全局,用 get_context 看某个文件或模块,用 get_risk 看改动某个文件的风险。
配置:DeepSeek、Kimi、Qwen 三种接法
下面的配置都来自各家官方文档。repowise 的托管 MCP 地址格式是 https://api.repowise.dev/mcp/<owner>/<repo>,用 Streamable HTTP 传输,请求头带 Authorization: Bearer <你的 key>。key 在登录后的 Settings → Editor 里生成,公开仓库免费。
DeepSeek + Claude Code
DeepSeek 的 API 提供了 Anthropic 兼容接口,Claude Code 改几个环境变量就能换成 DeepSeek 的模型(见 DeepSeek 官方文档):
export ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
export ANTHROPIC_AUTH_TOKEN=<你的 DeepSeek API Key>
export ANTHROPIC_MODEL=deepseek-v4-pro
export ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-flash
claude mcp add --transport http repowise \
https://api.repowise.dev/mcp/deepseek-ai/deepseek-harness \
--header "Authorization: Bearer <你的 repowise key>"
有一点容易误会:DeepSeek 的文档写明它会忽略 Anthropic 接口里服务端的 mcp_servers 字段。这不影响上面的用法。MCP 客户端跑在你本机的 Claude Code 里,Claude Code 把 MCP 工具当成普通的工具定义发给模型,而 DeepSeek 支持工具调用(tools 和 tool_choice)。模型决定调哪个工具,Claude Code 负责去调。
Kimi + Claude Code
Moonshot 同样提供 Anthropic 兼容接口,做法一样:把 ANTHROPIC_BASE_URL 指向 Moonshot 的 /anthropic 地址,填上 Moonshot 的 key,再执行同一条 claude mcp add。常见的坑是环境里还残留着一个 ANTHROPIC_API_KEY,它会覆盖你填的 token。切换后用 /status 确认当前用的是哪个模型。
Qwen Code
Qwen Code 自带 MCP 支持,一条命令就够(见 Qwen Code 文档):
qwen mcp add --transport http repowise \
https://api.repowise.dev/mcp/deepseek-ai/deepseek-harness \
--header "Authorization: Bearer <你的 repowise key>"
或者直接写进 ~/.qwen/settings.json:
{
"mcpServers": {
"repowise": {
"httpUrl": "https://api.repowise.dev/mcp/deepseek-ai/deepseek-harness",
"headers": { "Authorization": "Bearer <你的 repowise key>" }
}
}
}
Cherry Studio 这类桌面客户端也支持 Streamable HTTP 的 MCP 服务,填同样的地址和请求头即可。
说明一下:上面的配置是按官方文档整理的,我没有逐个实际跑过。三家的接口都在快速迭代,请以各自的最新文档为准。
第一个问题:这个仓库是做什么的
连上以后,我问的第一个问题总是“给我讲讲这个仓库”。模型会调用 get_overview,拿到的就是仓库首页上的那些信息。对 DeepSeek Harness 来说,最有用的是这几条:
- 它是什么:一个仍处于开发者预览阶段的 agent 运行框架(仓库自己的说法是“Everything is a Plugin”)。它读入运行配置和会话状态,通过 CLI、SDK 和沙箱执行层跑 agent 工作流,产出可以持久化的会话结果(包括检查点),再由 Web、桌面端和 SDK 读取展示。项目明确说明会有不兼容的变更。
- 规模:12,578 个文件,898,685 行代码,39,595 个符号,11 个顶层模块。TypeScript 文件 5,108 个,JavaScript 109 个,Python 30 个,还有少量 C/C++。
- 入口:
apps/desktop/src/main.ts(桌面端)、apps/web/src/main.ts(Web 端)、packages/sdk/server/src/server.ts(SDK 服务端),工作流引擎从packages/workflow/workflow-ptc/src/index.ts里的PtcWorkflowEngine.start开始。
文件数最多的几个顶层目录是 packages(6,157 个文件)、.agents(3,686)、apps(884)、snapshots(764)、docs(556)。真正的业务代码几乎都在 packages 里,apps 是几个外壳。
分层:代码到底堆在哪一层
repowise 把每个文件归到一个层里。DeepSeek Harness 的分布是这样的(单位是知识图谱里的节点数):
| 层 | 节点数 |
|---|---|
| Application(应用逻辑) | 4,828 |
| Config(配置) | 3,748 |
| Test(测试) | 2,568 |
| Docs & Tooling(文档与工具) | 938 |
| Utility(工具函数) | 187 |
| API | 161 |
| Service | 81 |
| CLI | 28 |
| Data | 25 |
| UI | 14 |
Scroll the table sideways to see every column.
Config 层有 3,748 个节点,接近应用逻辑的八成,这是“一切皆插件”的设计带来的代价:要写大量的预设和组合配置。.agents 目录有 3,686 个文件,我猜大部分就是这类预设和配置,但没有逐个核对。另一个反常的数字是 UI 层只有 14 个节点,可这个项目明明有 Web 端和桌面端,界面代码多半被归进了 Application 层。分层是按代码的角色推断的,不看目录名,所以这组数字只能作参考。
它怎么跑起来:从一个 C 入口开始
生成的“How it works”文档从原生入口 native/system/packages/entry/src/main.c 讲起。这个程序启动时会用 Linux 的 Landlock(landlock_create_ruleset 系统调用)先把自己关进沙箱,再去执行后面的命令。
我觉得最值得一读的是它的失败策略。如果内核不支持 Landlock,restrict_self 会直接报错退出,不会在没有限制的情况下继续运行。代码注释写得很直白:“fail CLOSED, never exec unconfined”。每个允许访问的目录由 add_rule 单独加规则,如果某个路径打不开,同样直接失败。TypeScript 这一侧,packages/shell/bash-sandbox/src/index.ts 负责把 bash 包在沙箱里执行,并根据实际的隔离级别标注结果。
一个让模型执行命令的框架,沙箱加不上就拒绝运行,我认为这个默认值选得对。如果我只让模型 grep,它很可能根本找不到这段 C 代码,因为它在一个 TypeScript 仓库的 native/ 目录深处。
风险在哪:改得最多、修得最多的文件
get_risk 和热点数据回答的是另一个问题:如果我要改这个仓库,哪里最需要小心。repowise 把既改得频繁、代码又复杂的文件叫作热点文件。DeepSeek Harness 一共有 1,306 个热点文件,排在前面的几个是:
| 文件 | 修复类提交 | bus factor |
|---|---|---|
packages/extensions/tool-cordis/src/api-catalog.ts | 139 | 8 |
packages/core/agent-loop/src/agent.ts | 78 | 5 |
packages/core/agent/src/types.ts | 54 | 4 |
packages/core/session/src/index.ts | 51 | 6 |
packages/core/tools/src/index.ts | 49 | 4 |
Scroll the table sideways to see every column.
bus factor 指的是有多少人对这个文件足够熟悉,数字越大,知识越分散。这几个文件都在 4 到 8 之间,也就是说每个文件都有好几个人熟悉。
packages/core/agent-loop/src/agent.ts 是 agent 主循环所在的文件,页面上的“当前优先事项”也指向它。改这个文件之前,先让模型调用一次 get_risk,看看哪些文件依赖它、最近谁改过、历史上修过哪些问题,比直接改稳妥得多。
核心文件的修复类提交多,通常是因为这些文件改动最频繁,所以它们也最值得先读懂。
47 组循环依赖,其中一组在 MCP 客户端里
repowise 为每一组循环依赖生成了单独的文档页,DeepSeek Harness 一共有 47 页。名字里能看到 Sandbox、Tools、Session Persistence、Subagent、Llm、Schedule、Jobs 这些核心模块。
最小也最好懂的一组在它自己的 MCP 客户端包里:packages/mcp/mcp-client。
connection.ts → transport.ts → index.ts → connection.ts
connection.ts → index.ts
三个文件互相引用,谁也没法单独加载、单独测试。页面按“在环里承担了几条边”给出了拆环建议:connection.ts 引入环内文件 2 次、被引用 1 次,是最纠缠的那个,从它入手抽一个接口或挪一个 import,收益最大。
这种小环在大仓库里很常见,通常是 index.ts 统一导出、内部文件又反过来从 index.ts 引东西造成的。程序照样能跑,但重构和单元测试会变难。让模型改这类代码之前,先让它知道环在哪,它就不会在一个文件里修好、在另一个文件里又绕回来。
死代码:工具自己说“拿不准”
get_dead_code 对 DeepSeek Harness 给出了 270 条线索:169 个“没人引用的文件”,101 个“没人使用的导出”。这 270 条的置信度全部是 0.4,没有一条被标成可以安全删除,可删行数是 0。
比如 tsdown.config.ts 被标成“没有文件引用它”,但证据里同时写着“这个包使用动态导入或运行时解析”和“配置文件,运行时加载风险”。这个判断是对的:配置文件由构建工具读取,本来就不会被 import。一个以插件和预设为核心的框架,大量代码都是在运行时按名字加载的,静态的引用图看不全。
我认为死代码工具就该这样,看不准的时候直接标出来。这份清单适合让模型逐条去查“这个文件是谁加载的”;如果拿它直接删代码,会出问题。
对照:OpenViking,只有图没有文档
火山引擎的 OpenViking 是一个给 agent 用的上下文数据库,2,522 个文件,528,563 行代码。语言比 DeepSeek Harness 杂得多:Python 1,335 个文件,C++ 386 个,TypeScript 178 个,Rust 88 个。
它在我们这里的索引没有生成文档页,只有依赖图、健康度和死代码分析。即便如此,地图依然有用:
- 分层:Application 1,316、Test 697、Utility 125、API 118、Data 80、Config 63、Service 41、UI 39、CLI 26、Middleware 15。和 DeepSeek Harness 正好相反,配置很轻,逻辑集中在应用层。
- 热点:
openviking/storage/viking_fs.py(35 次修复类提交,bus factor 14)、openviking/storage/queuefs/semantic_processor.py(16 次,bus factor 11)、openviking/session/session.py(14 次,bus factor 13)。存储和会话是最常被改的地方,而且熟悉它们的人不少。 - 死代码:434 条线索,其中 272 条被标为可以安全删除。但我抽查源码时发现,
api_fastapi.py里的create_collection、search_by_vector被我们的检测器以 1.0 的置信度判成了“没人使用”。它们其实是 FastAPI 的路由函数,靠@search_router.post("/vector")这样的装饰器注册,框架会调用它们,只是没有代码 import 它们。这是我们自己的检测器判错了,我们会修。
两个仓库对照来看,有文档的时候,模型可以先读“它是怎么工作的”;只有图的时候,模型至少知道入口、分层和热点在哪,不至于从第一个文件读到最后一个文件。
这些数字说明不了什么
- 健康度不是质量评分。repowise 的健康度(1 到 10 分)衡量一个文件引发 bug 的可能性和修改它的难度,依据是静态检查加上 git 历史;仓库得分是各文件得分按代码行数加权的平均值。DeepSeek Harness 页面显示 6.6 分(满分 10),OpenViking 5.8 分。我们统计了 3,126 个有评分的公开仓库,健康度和代码规模关系很大:1,000 行以下的仓库中位数接近满分(9.91),10 万到 100 万行的中位数是 6.79。近 90 万行、快速迭代中的项目拿到 6 到 7 分很正常。
- 索引有时间点。DeepSeek Harness 索引于 2026-09-28,OpenViking 索引于 2026-06-14。这两个项目改得都很快,文中的文件路径和数字以后会变。
- 分层是推断的。一个文件属于哪一层,是根据它的角色和依赖关系推断的,边界上的文件会分错。
- 修复类提交是按提交信息分类的,写着 fix 的提交不一定都是 bug 修复。
repowise 在这里做了什么
上面用到的“地图”,就是 repowise 对仓库建的索引:依赖图、分层、热点、循环依赖、死代码和生成的文档,通过 MCP 交给 DeepSeek、Kimi 或 Qwen 这类模型。公开仓库可以直接在网页上看,不用注册;想让自己的编辑器或 agent 调用,需要登录后生成一个 key。它也是开源的,pip install repowise && repowise init 可以在本地对自己的仓库跑一遍。
想试试的话,从 把 repowise 连到你的编辑器 开始,或者把任意 GitHub 地址粘到 repowise.dev。
写作说明
- 仓库数据来自 repowise 的公开索引:DeepSeek Harness 为 2026-09-28 的快照(提交 4878cda),OpenViking 为 2026-06-14 的快照(提交 66622aa)。数字于 2026-10-06 重新核对。
- 文件数、代码行数、模块数、分层和热点来自仓库概览;循环依赖来自生成的循环依赖文档页;死代码来自死代码接口。
- OpenViking 的误报是我对照提交 66622aa 的源码确认的。
- DeepSeek、Kimi、Qwen Code 的配置来自各自的官方文档(2026-10-06 查阅),文中没有展示我没有实际看到的输出。