-
Notifications
You must be signed in to change notification settings - Fork 703
6. 代码开发与测试
在 CozeLoop 开源版中,前后端代码均需要遵守本文档提供的编码风格与规范。
├── backend/ # 后端代码
│ ├── api/ # API 接口定义和实现
│ │ ├── handler/ # API 处理
│ │ └── router/ # API 路由
│ ├── cmd/ # 应用入口和服务启动
│ │ ├── conf # 各模块配置文件
│ │ └── main.go # 入口函数
│ ├── modules/ # 核心业务模块
│ │ ├── data/ # 数据集模块
│ │ │ ├── application/ # 应用服务层
│ │ │ ├── domain/ # 领域模型层
│ │ │ ├── pkg / # 公共工具层
│ │ │ └── infra/ # 基础设施层
│ │ ├── evaluation/ # 评测模块
│ │ ├── foundation/ # 基建模块
│ │ ├── llm/ # LLM模块
│ │ ├── observability/ # 观测模块
│ │ └── prompt/ # PE模块
│ ├── pkg/ # 通用工具包和库
│ └── script/ # 脚本
│ ├── errorx/ # 错误码定义及生成工具
│ └── kitex/ # Kitex代码生成工具
├── frontend/ # 前端代码
├── conf/ # 基础组件配置文件
├── docs/ # 文档
└── idl/ # IDL接口定义文件
仓库采用 Monorepo 的方式,前后端的代码都在同一个仓库。 后端的代码设计采用 DDD 的方式,遵循分层架构,每个业务模块都遵循以下分层架构:
- application:应用服务层,协调领域对象完成业务流程
- domain:领域模型层,定义核心业务实体和业务逻辑
- infra:基础设施层,提供技术实现和外部服务集成
- pkg:模块特定的公共包
Go 语言的代码规范可参考Google规范。建议使用gofmt等格式化工具进行代码格式化。
| 类别 | 说明 |
|---|---|
| Service 定义 | * 服务命名采用驼峰命名 * 一个Thrift文件只定义一个Service, extends聚合除外 |
| Method 定义 | * 接口命名采用驼峰命名 * 接口只能拥有一个参数和一个返回值,且是自定义Struct类型 * 入参须命名为{Method}Request,返回值命名为{Method}Response * 每个Request类型须包含Base字段,类型base.Base,字段序号为255,optional类型 * 每个Response类型须包含BaseResp字段,类型base.BaseResp,字段序号为255 |
| Struct 定义 | * 结构体命名采用驼峰命名 * 字段命名采用蛇形命名 * 新增字段设置为optional,禁止required * 禁止修改现有字段的ID和类型 |
| 枚举定义 | * 推荐使用typdef来定义枚举值 * 枚举值命名采用驼峰命名,类型和名字之间用下划线连接 |
| API定义 | * 使用Restful风格定义API * 参考现有模块的API定义,风格保持一致 |
| 注解定义 | * 可参考Kitex支持的注解 * 可参考Hertz支持的注解 |
规范示例如下:
# 单个Service
typedef string EnumType(ts.enum="true")
const EnumType EnumType_Text = "Text"
struct ExampleRequest {
1: optional i64 id
255: optional base.Base base
}
struct ExampleResponse {
1: optional string name
2: optional EnumType enum_type
255: base.BaseResp base_resp
}
service ExampleService {
ExampleMethod(1: ExampleRequest) (2: ExampleResponse)
}
# 多个Service
service ExampleAService extends idl_a.AService{}
service ExampleBService extends idl_b.BService{}| 类别 | 规范说明 |
|---|---|
| UT 函数命名 | * 普通函数命名为Test{FunctionName}(t *testing.T) * 对象方法命名为Test{ObjectName}{MethodName}(t *testing.T) * 基准测试函数命名为Benchmark{FunctionName}(b *testing.B) * 基准测试对象命名为Benchmark{ObjectName}{MethodName}(b *testing.B) |
| 文件命名 | 测试文件与被测试文件同名,后缀为_test.go,处于同一目录下 |
| 测试设计 | * 推荐使用 Table-Driven 的方式定义输入/输出,覆盖多种场景 * 使用 github.com/stretchr/testify简化断言逻辑 * 使用 github.com/uber-go/mock生成Mock对象,尽量避免Patch打桩的方式 |
测试示例如下:
func TestRetryWithMaxTimes1(t *testing.T) {
type args struct {
ctx context.Context
max int
fn func() error
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "test1",
args: args{
max: 3,
fn: func() error {
return nil
}
},
wantErr: false,
}
// Add more test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := RetryWithMaxTimes(tt.args.ctx, tt.args.max, tt.args.fn)
assert.Equal(t, tt.wantErr, err != nil)
})
}
}修改 CozeLoop 开源版前端代码之前,请确认开发环境已具备以下要求:
- Node.js 18+ (推荐 lts/iron 版本)
- pnpm 8.15.8
- Rush 5.147.1
你可以参考以下步骤准备前端开发环境。
-
安装 Node.js 18+。
nvm install lts/iron nvm alias default lts/iron # 设置默认 Node 版本 nvm use lts/iron
-
打开
frontend目录。# 切换目录 cd frontend
-
安装全局依赖。
npm i -g [email protected] @microsoft/[email protected]
-
安装或更新项目依赖。
rush update
在 CozeLoop 开源版目录下执行以下命令启动开发任务,运行开发环境。
- 推荐使用
rushx而不是pnpm run或npm run。 - CozeLoop 项目位于
apps/cozeloop目录,是一个 React 应用。
cd apps/cozeloop
rushx dev执行完毕后,在浏览器中打开 http://localhost:8090/ 以查看页面。
CozeLoop 项目由 Rsbuild 构建,配置文件是 apps/cozeloop/rsbuild.config.ts。
执行以下命令以构建项目。
cd apps/cozeloop
rushx build如你所见,apps/cozeloop/package.json 中有许多依赖是 workspace:* 版本,这意味着它们是在此仓库内维护。
CozeLoop 项目依赖这些项目的源代码而非构建产物,通常情况下修改这些 workspace 依赖的源代码,变更会立刻生效。极个别场景下需要重新运行项目。
-
创建功能分支。 建议每个功能对应一个功能分支。
git checkout -b feat/your-feature-name
-
开发新功能。
-
如果需要修改 IDL,按照规范修改,然后使用脚本生成代码,这时候会生成 kitex 以及 hertz 的代码。
cd ./backend/script/cloudwego ./code_gen.sh -
如果需要修改依赖注入,遵循当前使用 wire 依赖注入的方式,修改对应目录下
wire.go后重新生成代码。# 修改总体初始化的依赖注入 cd ./backend/api/handler/coze/loop/apis wire # 修改子模块的依赖注入 cd ./backend/modules/observability/application wire
-
如果需要新增数据库/新增 MQ Topic:
- 新增MySQL表: 在
conf/default/mysql/init-sql下新增建表SQL,注意需要增加IF NOT EXISTS。 - 新增Clickhouse表: 在
conf/default/clickhouse/init-sql下新增建表SQL,注意需要增加IF NOT EXISTS。 - 新增RocketMQ Topic: 在
conf/default/rocketmq/broker/topics.cnf下新增Topic,格式为{topic}={consumer}
- 新增MySQL表: 在
-
按照Go的开发规范进行后端服务开发,如果是在开发模式下运行服务,代码修改后端服务会自动重新进行编译然后启动。其他模式则需要重新进行镜像编译运行,建议使用开发模式进行开发。
# 重新编译镜像运行,编译时间会比较长 docker compose up app --build -
提交代码前,需要先添加单测,增量覆盖率在80%以上,确保存量单测都能通过。
cd backend/ go test -gcflags="all=-N -l" -count=1 -v ./...
-
-
提交代码。
git add . git commit -m "feat: add new feature"
-
合并请求。
- 推送到远程仓库
- 创建 Pull Request
- 确保代码的CI通过
- 等待Code Review
-
运行测试。 执行以下命令进行单元测试。
# 运行所有测试确保通过 cd backend/ go test -gcflags="all=-N -l" -count=1 -v ./...
-
测试覆盖率。 执行以下命令生成测试覆盖率报告。
# 生成测试覆盖率报告 cd backend/ go test -gcflags="all=-N -l" -coverprofile=coverage.out ./... go tool cover -html=coverage.out
本地部署后可以打开平台,测试各模块的功能是否正常:
| 功能模块 | 说明 |
|---|---|
| Prompt开发与调试 | * Playground能够正常进行调试 * Prompt创建与管理符合预期 |
| 评测实验 | * 新建数据集 * 新增评估器 * 新增实验,对刚创建的Prompt进行评测 * 实验完成并查看分析报告 |
| Trace 上报与查询 | 在 Trace 界面选择 Prompt 页签,查看是否有 Trace 展示。 |