收官串讲:把 20 天拼成一张全景图
恭喜你走到最后一天!今天不学新代码,而是把 20 天读过的六大模块、六层前端、IDL 契约、本地 Kitex、Adapter 模式全部串起来,形成一张"以后随时能调出来复习"的全景图,再看看 CI 是怎么替我们守住这些设计约定的,最后聊聊接下来往哪个方向深入。
20 天回顾:你走过的路
先花两分钟,看看自己实际走过的路线——这条时间线本身就是最好的学习地图:
api.go 的 Init 函数把它们全部串成一张依赖图。全景图:六大后端模块 + 六层前端结构
后端 backend/modules/ 六大模块及依赖顺序(ARCHITECTURE.md):
foundation
空间/用户/权限/审计
llm
大模型网关、多厂商适配
prompt
Prompt 版本管理与调试
data
Dataset/Item/Version/Job
evaluation
EvaluationSet/Evaluator/Experiment
observability
Trace/Span 观测链路
前端 frontend/packages/ 六层结构(docs/reference/frontend-packages.md):
L1 foundation
arch/toolkit 基础工具
L2 base
api-schema(IDL 生成)
L3 biz-hooks
业务无关的通用 hooks
L4 components
业务相关 UI 组件
L5 pages
prompt-pages/evaluate-pages 等
L6 apps
cozeloop 应用壳
设计哲学一:DDD 分层——为什么每个模块都是四件套
ARCHITECTURE.md 中"Backend DDD 分层"一节定义的标准结构,20 天里你在六个模块里反复见到同一套四层:
modules/<module>/
├── application/ # 编排:鉴权→转换→审核→调用domain,不含业务规则细节
├── domain/ # 核心:entity + repo接口(interface) + service(领域服务)
├── infra/ # 实现:repo接口的具体落地(mysql/redis/mq/rpc)
└── (可选)consumer/ # MQ消费者,异步任务的入口
interface、infra 层实现它,是让"业务逻辑不关心用 MySQL 还是 Redis"的关键技巧。👶 小白问:Coze Studio(我之前学的另一个仓库)也是这样分层吗?
👨🏫 老师:核心思路一致(application/domain/infra 三层 + repo 接口),但 Coze Studio 偏"Agent 平台",模块以 workflow/agent/knowledge 等为核心;Coze Loop 偏"Prompt 工程与评测平台",模块以 prompt/data/evaluation/observability 为核心。如果你学过 Coze Studio 系列,这套分层思维应该会有强烈的既视感——这也说明字节内部的后端架构风格是有统一范式的。
设计哲学二:IDL 契约驱动——一份 Thrift 定义两端代码
Day 18 学过的核心链路,今天再强调一次它的战略意义:
idl/thrift/**/*.thrift (唯一真相源 Single Source of Truth)
│ kitex 生成
▼
backend/kitex_gen/**/*.go (Go 结构体 + RPC client/server 骨架)
│ rush update-api 生成
▼
frontend/packages/loop-base/api-schema/**/*.ts (TS 接口 + axios 调用函数)
.thrift 文件开始,Go 和 TS 两端永远同步,这是大型全栈仓库能长期保持前后端一致性的核心机制。设计哲学三:本地 Kitex 与 Adapter——同一套代码两种"人格"
Day 15 的"本地客户端"(backend/loop_gen/*/local_*.go)与 Day 17 的 Adapter 模式(docs/reference/frontend-packages.md "Adapter 模式"一节)看似讲的是两件事,其实解决的是同一类问题:
ctx, req → resp, err),但实现是直接函数调用——让模块间调用"看起来像跨服务,实际是同进程",未来要拆成微服务时,只需替换实现,调用方代码不用改。Adapter 模式:同一个业务组件,在开源版和商业版下逻辑分支不同——用 Adapter 把"哪个版本用哪套实现"这一决策从业务代码里剥离出来,业务代码永远只 import 抽象接口。
CI 工作流:这些设计约定是怎么被"强制执行"的
光有设计哲学不够,Coze Loop 用 .github/workflows/ 里的多条流水线把这些约定变成"提交代码时自动检查",而不是靠人自觉:
backend-ci.yaml
golangci-lint 静态检查 + go build + go test -race 单测,覆盖率上报 Codecov。
frontend-ci.yaml
Rush 单体仓的 rebuild 全量构建 + 按改动文件做增量 lint/style 检查。
idl.yaml
用 kitex 工具真实跑一遍 .thrift 文件的代码生成,语法错了直接挡在 PR 外——呼应 Day 18 讲的"IDL 是契约"。
mysql-schema-check.yaml
用 schemadiff 比对 docker-compose 和 helm-chart 两套 mysql-init SQL 是否一致——呼应 Day 19 讲的"双路径同步"红线。
license-check.yaml
检查每个源码文件是否带有开源协议头,保证 License 合规。
semantic-pull-request.yaml
检查 PR 标题是否符合 Conventional Commits 规范(feat:/fix: 等),方便自动生成 CHANGELOG。
接下来往哪个方向深入
semantic-pull-request 的要求发起 PR,体会真实贡献开源项目的完整流程。coze-studio-dayNN.html 系列,试着把两个仓库的模块清单摆在一起对比——同样是字节的开源 Agent/AI 基建项目,模块边界怎么划分、哪些基础设施是复用的思路,会加深你对"中大型 AI 平台该怎么切模块"的理解。结营:20 天小结 + 记忆口诀
🎓 20 天你到底学会了什么
- 看到一个陌生的大型 Go/TS 仓库,知道先摸模块清单,再进每个模块找 application/domain/infra 三层。
- 理解为什么复杂业务要靠异步(RocketMQ/消费者)而不是全用同步调用撑住耗时任务。
- 理解模块间跨调用为什么走"本地客户端"而不是直接 import,以及
api.go的Init函数如何拼出整个依赖图。 - 理解前端 Rush 单体仓的分层依赖规则和 Adapter 模式,知道去哪找一个页面真正用到的底层组件。
- 理解IDL 契约驱动开发的价值,知道改一个字段该走哪条生成链路、哪些文件绝对不能手改。
- 具备了"顺着一个字段名读通全链路"的实战读码能力,能对着一个真实需求设计出改动路径。
六模块看清分工,四层套路走天下
IDL 是契约,生成代码不能碰
本地客户端连模块,Adapter 分场景
CI 守约定,读码先顺一根线
✋ 结营动手(推荐)
# 用一句话向别人介绍 Coze Loop 的六大模块,然后打开这两个文件核对答案:
open /Users/bitmart/work/codes/github/AI_WORK/coze-loop/ARCHITECTURE.md
open /Users/bitmart/work/codes/github/AI_WORK/coze-loop/docs/reference/frontend-packages.md
# 挑一个你还没完全读透的模块,用 Day 19 的"搜字段名读全链路"方法,
# 自己找一个真实字段,顺着 IDL → application → infra 走一遍,
# 检验一下 20 天学到的方法论是否已经变成了你自己的能力。