装了两个包、各自都带一个叫 review 的东西,直接叫 review 会叫到谁? 实测四个调用:只有带命名空间的那两个落在你想要的包上,另外两个都落到了项目本地。
上一节讲装,这一节讲装多了之后的问题:同名。 这一节有真跑:四个调用逐个解析,看优先级怎么起作用。
一、命名空间长什么样
格式是「包名 加 冒号 加 组件名」。比如 corp-review:review。 包名来自清单里的 name 字段——所以那个字段不能随便改,改了所有调用都会失效。 这和编程语言里的模块前缀是一个道理:不是为了好看,是为了不撞。
设计包的时候就要想好前缀:组织名、领域名,都行,但要有意义。
二、真跑:四个调用逐个解析
演示里四个调用:review、corp-review:review、team-web:review、deploy-check。 带命名空间的两个,精确落到对应的包上。 不带的两个,都落到了项目本地的同名项上,而不是插件里的。
四个都解析成功了,但只有两个是你以为的那个——这就是命名冲突最麻烦的地方:它不报错。
三、优先级从哪儿来
显式命名空间最高:写了包名就直接去那个包找。 项目本地次高:当前项目里定义的。 用户级再次:你自己配的。
插件最低:装进来的包。 插件排最后这个设计是对的:装进来的东西不该悄悄盖掉你项目里的定义。 但它也意味着「装了却没生效」——因为项目里有个同名的。这个现象很难查。
四、命名冲突的三种表现
悄悄用错:不报错,用的是项目本地那份,你以为在用插件。 部分生效:命令能调,但里面引用的子智能体是另一个包的。 装不上:两个包声明了同一个包名,后装的那个可能覆盖前一个。
第三种最少见但最严重:它会让一个包「消失」,而你以为装好了。
五、一条实用规矩
给别人用的包,名字里带上组织或领域前缀:corp-、web-、data-。 这样撞名的概率低,而且看调用就能猜到是哪个包提供的。 自己临时试的包,用 tmp- 开头,用完就删——它不该留在别人的机器上。
调用别人的东西时,能写全名就写全名。省下的那几个字符,不值得一次排查。
六、动手 Demo:两个包都有 review,叫它的时候到底叫到谁
装了两个包、各自都带一个叫 review 的东西,直接叫 review 会发生什么? 这里把四个调用逐个解析,看优先级怎么起作用。
reg = {
u"corp-review:review": u"插件 corp-review",
u"review": u"项目本地(优先级最高)",
}
实跑输出:
--------------------------------------------------------------------
两个包都有 review,叫它的时候到底叫到谁
--------------------------------------------------------------------
装了两个包、各自都带一个叫 review 的东西,直接叫 review 会发生什么?
这就是命名空间要解决的问题:让「同名的东西」能共存,而且能被精确指到。
① 命名空间长什么样
--------------------------------------------------------------------
格式是「包名 加 冒号 加 组件名」。比如 corp-review:review。
包名来自清单里的 name 字段——所以那个字段不能随便改,改了所有调用都会失效。
这和编程语言里的模块前缀是一个道理:不是为了好看,是为了不撞。
② 真跑:四个调用逐个解析
--------------------------------------------------------------------
| 你写的 | 怎么写的 | 实际叫到 |
|---|---|---|
| review | 只说名字 | 项目本地(优先级最高) |
| corp-review:review | 带命名空间 | 插件 corp-review |
| team-web:review | 带命名空间 | 插件 team-web |
| deploy-check | 项目里也有一份同名的 | 项目本地(同名时项目优先) |
四个都解析成功了,但只有两个是你以为的那个——带命名空间的那两个。
不带命名空间的两次,都落到了项目本地的同名项上,而不是插件里的。
③ 优先级从哪儿来
--------------------------------------------------------------------
| 来源 | 优先级 | 说明 |
|---|:---:|---|
| 显式命名空间 | 最高 | 写了包名就直接去那个包找 |
| 项目本地 | 次高 | 当前项目里定义的 |
| 用户级 | 再次 | 你自己配的 |
| 插件 | 最低 | 装进来的包 |
插件排在最后,这个设计是对的:装进来的东西不该悄悄盖掉你项目里的定义。
但它也意味着「装了却没生效」——因为项目里有个同名的。这个现象很难查。
④ 命名冲突的三种表现
--------------------------------------------------------------------
- 悄悄用错:不报错,用的是项目本地那份,你以为在用插件。
- 部分生效:命令能调,但里面引用的子智能体是另一个包的。
- 装不上:两个包声明了同一个包名,后装的那个可能覆盖前一个。
⑤ 一条实用规矩
--------------------------------------------------------------------
给别人用的包,名字里带上组织或领域前缀:corp-、web-、data-。
这样撞名的概率低,而且看调用就能猜到是哪个包提供的。
自己临时试的包,用 tmp- 开头,用完就删——它不该留在别人的机器上。
! 优先级的层数与顺序以真实实现为准;这里演示的是「同名时谁赢」这件事。
①命名空间格式是「包名 加 冒号 加 组件名」,包名来自清单里那个 name 字段——所以它不能随便改。 ②四个调用都解析成功,但只有带命名空间的两个落在你想要的包上。另外两个落到了项目本地的同名项上。 ③优先级:显式命名空间最高,然后是项目本地、用户级,插件最低。 插件排最后是对的,但它意味着「装了却没生效」。 ④命名冲突的三种表现:悄悄用错、部分生效(命令在但引用的东西是别人的)、装不上(同包名互相覆盖)。
30 秒实验
- 把项目本地那份 review 删掉,重跑一遍。不带命名空间的调用会落到哪儿? 这说明「插件最低」这个规则的后果是什么?
- 让两个包都叫 corp-review,重跑一遍。会发生什么?这种事在实际里怎么发现?
- 把所有调用都改成带命名空间,重跑一遍。有什么代价?值得吗?
常见误区
- 包名不带前缀。撞名概率高,而且看调用猜不到来源。
- 以为装了就能用。项目本地有同名的,插件那份永远轮不到。
- 改已发布包的 name 字段。所有带命名空间的调用都会失效。
- 调试时只写简称。出问题时会怀疑到错的地方。
- 临时包用正式名字。它会留在别人机器上,和真包混淆。
自测三问(点开对答案)
1. 命名空间的格式是什么? —— 包名加冒号加组件名,比如 corp-review:review。包名来自清单的 name 字段。 2. 同名时谁赢? —— 显式命名空间最高,其次项目本地、用户级,插件最低。 3. 为什么「插件最低」会带来麻烦? —— 因为它意味着「装了却没生效」——项目里有同名的,插件那份永远用不上,而且不报错。单个包讲完了,下一节把六个文件拼成一个能发给同事的团队包。
- ☐ (本篇完,下一篇 9.5 实战:构建团队能力包)
相关笔记
- Plugin 的物理结构:清单里的 name 字段
- 实战:团队能力包怎么搭
- Claude Code 橙皮书 · 索引
- 🐎 Claude Code 实战 · 索引