Code Is All You Need
# Code Is All You Need
最近我在想一个很土、但可能很有用的问题:
如果一个 Coding Agent 进到一个完全陌生的 K8s 环境里,它到底靠什么认识这个世界?
靠 README 吗?靠群聊截图吗?靠某位同事三年前画的架构图吗?这些东西当然有用,但它们都有一个共同问题:它们通常是在替系统发言。
而生产环境这个东西吧,它经常不太配合发言人。
README 说服务 A 调用服务 B,线上可能已经改成服务 A 调用服务 C,中间还绕了一下网关。架构图里画着一条优雅的箭头,实际流量可能像下班高峰的立交桥。最刺激的是,大家都很诚恳,没有人撒谎,只是时间撒了谎。

# 陌生系统怎么认识
人操作一个从来没见过的东西,通常不是先等一本完整说明书。我们会先用已有经验去试探它:摸摸边界,看看反馈,猜一个模型,再用新的反馈把模型改掉。
小孩第一次见门把手不会先找 RFC。工程师第一次接手系统,也不会真的相信 Confluence 的最后更新时间。
我不是说文档没用。文档当然有用,尤其是解释背景、约束、取舍和历史债务。问题是,文档描述的是某个时刻的投影,而系统本身一直在动。一个投影如果离现场太久,就会从“说明”慢慢变成“传说”。
所以我更关心的是:能不能让 Agent 直接读到现场?
现场包括两部分。一个是代码,一个是运行时。
# 静态事实和动态事实
我会把它们分成两类事实。
代码是静态事实。repo、commit、配置、测试、接口定义,说明这个系统被构造成什么样。
运行时是动态事实。Pod、Service、HTTPRoute、Ingress、日志、指标、网络探测、磁盘占用,说明这个系统此刻正在怎么活着。
只有代码,会出现一种很礼貌的尴尬:代码看起来很合理,线上就是炸。只有运行时,也会变成另一种尴尬:日志很多,CPU 很忙,大家都很紧张,但没人知道这个镜像到底从哪次提交来的。
两边放在一起,才像是在看同一个状态机。

这也是我说 Code Is All You Need 的原因。这里的 code 不是狭义的几行业务逻辑,而是能被追溯、能被验证、能被修改的事实源。它要和 runtime 放在一起看。
文档像照片,代码和运行时更像两台摄像机。照片能帮你回忆,但摄像机能告诉你现在谁还在动。
# 一个 K8s 排障例子
假设我们给每个 Pod 加上最基本的 Git 信息:
这两个 annotation 很小,但很值钱。它们相当于给每个 Pod 带了一张出生证明:我不是凭空长出来的,我来自这个 repo,这个 commit。
现在你知道一个域名和一个 HTTP path,比如:
帮我看下
https://api.example.com/v1/order/create,最近 500 变多了。
Agent 不需要先听半小时祖传服务介绍。它可以先查现场:
如果还不够,它可以写个小 Python 脚本进容器跑,检查配置文件,请求内部 endpoint,或者看看某个目录是不是偷偷吃胖了。README 一般不会写“凌晨三点请用 ncdu 看缓存目录”,但现场会告诉你。
拿到 Pod annotation 之后,它再把代码拉到 /tmp:
到这一步,事情就开始变得踏实了。
运行时告诉它:请求经过哪个 route,落到哪个 svc,最后进了哪个 pod,日志和网络状态是什么。
代码告诉它:这个 pod 来自哪份实现,依赖怎么连,异常可能从哪里冒出来。
接下来再读代码、复现路径、改实现、更新配置或镜像,最后回到 K8s 里验证。这个循环不神秘,但很有效。它的关键不是“Agent 多聪明”,而是 Agent 手里终于有了可验证的事实链。
# 协作开发也可以这样做
这个想法继续往前走,就不只是排障了。它也能改善协作开发。
多个项目一起开发时,最慢的地方经常不是写代码,而是问路。前端说“我打了这个 URL”。后端说“这个应该不是我”。平台说“你们先确认流量有没有进网关”。然后会议室里每个人都很认真,只有系统本人沉默不语,像一位掌握全部真相但懒得开口的老员工。
那就让系统多说一点。
除了 git.repo 和 git.commit,我觉得最低成本的一条信息是 project:
project: ml-platform 看起来很朴素,像工牌夹里的白底照片。但它给了一个协作边界。
有了这个边界,人和工具都能快速把相关对象收拢起来:
如果从前端项目开始,Agent 可以看 dist、环境变量、构建产物、API 封装,找出页面实际会请求哪些 URL。然后顺着域名、path、HTTPRoute 或 Ingress 找到 Service,再通过 selector 找到 Pod,最后从 Pod annotation 拿到 repo 和 commit。
一条请求路径就可以从“大家凭印象聊聊”变成:
这时候多个 Coding Agent 就比较好分工了。一个看前端请求,一个看 API 服务,一个看 Redis、模型仓库、消息队列这些依赖,一个盯 rollout 和日志。
人也一样。新人接项目,第一天能少问几个“入口在哪”。SRE 半夜排障,能少翻几个群。负责人开会前,也能先拿到一张大致靠谱的调用图。

这里千万别走歪。annotation 不是新一代 README。不要把 Pod 写成小作文选手。
我倾向于这样分层:
- labels 用来筛选,比如
project、app、component、env。 - annotations 放最小追溯事实,比如 repo、commit、owner、provides、depends-on、openapi。
- repo 里放更完整的契约,比如 OpenAPI、ADR、架构说明和测试。
- runtime 用
kubectl、logs、metrics、network probe 去验证。
这样 K8s 就不只是部署平台了,它会顺手变成一张协作地图。不是那种需要专人维护、半年后没人敢点开的“知识图谱”,而是随着部署自然更新的事实索引。
每个 Pod 出生时带着项目、来源、身份、依赖和负责人的线索。Agent 扫一眼,至少不会第一句话就问:您哪位?

# 这不是银弹
当然,这套东西也不是银弹。
annotation 会过期,label 会乱写,owner 可能离职,repo 可能迁移。更麻烦的是,工具能看到事实,不代表它一定理解业务意图。它知道这个请求进了 feature-store-api,不代表它知道为什么这个特征对模型重要。
所以我不想把它说成“有了 annotation,协作开发从此天下太平”。这听起来太像卖平台。
我更愿意把它看成一个起点。让一个新人、一个 SRE、一个 Coding Agent 进到系统里时,不至于像刚下飞机一样到处问路。至少它先知道:我属于哪个 project,我来自哪个 repo,我现在跑的是哪个 commit,我大概依赖谁。
剩下的,还得靠人判断。
# 让事实先开口
我并不反对文档。好的文档像路牌,能省很多时间。但路牌不能代替道路。尤其不能代替一条正在施工、正在改道、旁边还放着临时锥桶的道路。
我现在更相信这种工程原则:
- 意图写进文档,事实留在系统里。
- 每个运行单元都能追溯到代码来源。
- 每个项目边界都能被 label 快速收拢。
- 每条调用链都能从入口追到代码。
- 每次排障都能从动态事实回到静态事实。
- 每次修改都能重新进入运行时验证。
这样做以后,Coding Agent 的工作方式会更像真实工程师:先看现场,再看代码,然后再动手。它不是靠背诵一份文档理解系统,而是不断用工具读取现场,用代码解释现场,用修改改变现场,再用新的现场校验自己。
所以,Code Is All You Need 不是说世界上只剩代码,咖啡、监控大屏和会议室都可以下岗。
它更像一句提醒:在一个持续变化的生产环境里,别让过期投影替真实系统发言。先把代码和运行时连起来,让事实自己开口。
