Coze Loop 架构学习指南

本文涉及的产品
多模态交互后付费免费试用,全链路、全Agent
简介: 本指南系统解析 Coze Loop 架构,涵盖项目结构、DDD 设计、技术栈与学习路径,助你从零掌握 AI Agent 平台开发与贡献。

Coze Loop 架构学习指南 🚀

👋 欢迎来到 Coze Loop 的学习之旅!我是你的技术教练,将带你从零开始,一步步揭开这个 AI Agent 开发与运维平台的神秘面纱。

这份指南不是冰冷的技术文档,而是一位经验丰富的架构师与你面对面的交流。让我们像探险家一样,用好奇心和系统思维,一起探索这个项目的每一个角落!


📋 目录导航


第一部分:项目架构深度解析(像架构师一样俯瞰全景)🔍

本部分目标: 让你站在架构师的高度,理解 Coze Loop 的设计哲学、技术选型背后的考量,以及各个组件是如何协同工作的。

💡 学习心法: 不要一头扎进代码细节!先建立宏观视野,就像先看地图再开始旅行。

1. 项目架构概览 🏗️

🎭 用一个类比理解 Coze Loop

想象 Coze Loop 是一家现代化的"AI 智能体 4S 店":

  • 展厅(Prompt 开发):这里是你设计和调试 AI 智能体的地方,就像汽车设计师在这里打磨每一个细节
  • 试驾场(评测模块):在这里对你的 AI 智能体进行全方位测试,确保它能应对各种场景
  • 监控中心(观测模块):实时追踪 AI 智能体的运行状态,就像汽车的黑匣子一样记录每一次"行程"

这个类比很贴切吧?😊 Coze Loop 就是这样一个为 AI Agent 提供全生命周期服务的平台。

🎯 核心设计特征

1. 前后端分离的现代架构

Coze Loop 采用了经典的前后端分离架构:

  • 前端:基于 React 18 + TypeScript 的单页应用(SPA),使用 Rsbuild 构建
  • 后端:Go 1.24+ 微服务架构,基于字节跳动的 CloudWeGo 技术栈

这种设计让前后端团队可以独立开发、独立部署,就像两个乐队同时演奏,最后完美合奏 🎵

2. 领域驱动设计(DDD)的后端架构

这是 Coze Loop 最闪耀的设计亮点!后端采用了严格的 DDD 三层架构:

backend/modules/
├── data/           # 数据集管理领域
├── evaluation/     # 评测领域
├── foundation/     # 基础服务领域
├── llm/            # LLM 模型管理领域
├── observability/  # 观测领域
└── prompt/         # Prompt 管理领域

每个领域内部都遵循:
├── application/    # 应用层(用例编排)
├── domain/         # 领域层(核心业务逻辑)
│   ├── entity/     # 实体
│   ├── service/    # 领域服务
│   └── repo/       # 仓储接口
├── infra/          # 基础设施层(技术实现)
│   ├── repo/       # 仓储实现
│   ├── rpc/        # RPC 调用
│   └── mq/         # 消息队列
└── pkg/            # 工具包

💡 为什么这样设计? DDD 架构的核心理念是"让业务逻辑独立于技术细节"。想象一下:

  • Domain 层:纯粹的业务规则,就像象棋的规则,不管你用木制棋盘还是电子屏幕,规则都不变
  • Application 层:用例协调器,像一个指挥家,协调各个领域服务完成复杂任务
  • Infra 层:技术实现,像乐器,可以随时更换(比如从 MySQL 换到 PostgreSQL)而不影响业务逻辑

3. 微服务通信:Thrift IDL

Coze Loop 使用 Thrift 作为接口定义语言(IDL),定义了所有服务间的通信契约:

idl/thrift/
├── base.thrift          # 基础类型定义
└── coze/                # Coze Loop 各模块的接口定义
    ├── dataset.thrift
    ├── evaluation.thrift
    ├── prompt.thrift
    └── ...

这就像团队之间签署的"协议书",确保大家说的是同一种语言 📝

4. Monorepo 的前端架构

前端使用 Rush.js 管理 Monorepo,这是一个超级项目管理器:

frontend/
├── apps/
│   └── cozeloop/        # 主应用
├── packages/
│   └── cozeloop/        # 业务组件库
├── infra/               # 基础设施
│   ├── idl/             # 从 Thrift 自动生成的 API Schema
│   └── utils/           # 工具库
└── config/              # 共享配置(ESLint、TypeScript等)

💡 Monorepo 的优势:所有前端代码在一个仓库中,依赖管理、代码复用、原子化提交都变得轻而易举!

🔗 技术栈分析

让我们看看 Coze Loop 的"工具箱"里都有哪些"利器":

后端核心技术栈:

技术组件 作用 为什么选它?
Go 1.24+ 编程语言 高性能、天生并发、编译型语言,适合构建高吞吐量服务
CloudWeGo Kitex RPC 框架 字节跳动开源,高性能、支持多协议(Thrift/Protobuf)
CloudWeGo Hertz HTTP 框架 高性能 HTTP 框架,兼容 net/http 生态
Eino LLM 统一接入层 字节跳动开源,屏蔽不同 LLM 的差异,统一调用接口
MySQL 关系型数据库 存储结构化数据(用户、项目、配置等)
Redis 缓存 + 分布式锁 高速缓存、分布式 ID 生成、限流
ClickHouse 列式数据库 存储海量观测数据(Trace),支持高效分析查询
RocketMQ 消息队列 异步任务处理(评测任务、数据导入等)
MinIO 对象存储 存储文件(数据集、导出文件等)
GORM ORM 框架 数据库访问层,简化 SQL 操作
Wire 依赖注入 Google 开源,编译时依赖注入,零运行时开销

前端核心技术栈:

技术组件 作用 为什么选它?
React 18 UI 框架 主流前端框架,生态丰富
TypeScript 5.8 编程语言 类型安全,大型项目必备
Rsbuild 构建工具 字节跳动开源,基于 Rspack(Rust 版 Webpack)
Rush.js Monorepo 工具 微软开源,企业级 Monorepo 管理
Zustand 状态管理 轻量级状态管理,比 Redux 简单
React Router v6 路由 SPA 路由管理
TailwindCSS CSS 框架 原子化 CSS,快速构建 UI

🌐 外部系统集成

Coze Loop 并非孤岛,它与多个外部系统协同工作:

graph LR
    A[Coze Loop] --> B[LLM 模型服务]
    A --> C[对象存储 S3/MinIO]
    A --> D[消息队列 RocketMQ]
    A --> E[缓存 Redis]
    A --> F[数据库 MySQL]
    A --> G[分析数据库 ClickHouse]

    B --> B1[OpenAI]
    B --> B2[火山方舟]
    B --> B3[千帆]
    B --> B4[通义千问]
    B --> B5[Gemini]
    B --> B6[Claude]

    style A fill:#ff6b6b,stroke:#333,stroke-width:2px
    style B fill:#4ecdc4,stroke:#333,stroke-width:2px

💡 集成方式亮点

  • LLM 统一接入:通过 Eino 框架,无缝支持 6+ 种主流 LLM 提供商
  • 配置外部化:所有敏感信息(API Key、数据库密码)通过环境变量注入
  • 健康检查机制:每个依赖服务都有完善的健康检查,确保系统稳定性

🔄 架构流程描述

让我们跟随一个"用户创建并执行 Prompt"的典型场景,看看数据是如何在系统中流转的:

sequenceDiagram
    participant User as 👤 用户浏览器
    participant Nginx as 🌐 Nginx
    participant Hertz as 🚀 Hertz (HTTP Gateway)
    participant PromptApp as 📝 Prompt Application
    participant PromptDomain as 🧠 Prompt Domain Service
    participant LLMService as 🤖 LLM Service
    participant DB as 💾 MySQL
    participant Redis as ⚡ Redis
    participant Eino as 🔌 Eino Framework
    participant LLM as 🧙 LLM API
    participant Tracer as 📊 Tracer Service

    User->>Nginx: 1. 创建 Prompt
    Nginx->>Hertz: 转发请求
    Hertz->>PromptApp: 调用 CreatePrompt
    PromptApp->>PromptDomain: 校验并保存
    PromptDomain->>DB: 持久化 Prompt
    DB-->>PromptDomain: 返回 ID
    PromptDomain-->>User: 返回创建成功

    User->>Nginx: 2. 执行 Prompt
    Nginx->>Hertz: 转发请求
    Hertz->>PromptApp: 调用 ExecutePrompt
    PromptApp->>Redis: 检查限流
    Redis-->>PromptApp: 通过
    PromptApp->>PromptDomain: 执行业务逻辑
    PromptDomain->>DB: 查询 Prompt 配置
    DB-->>PromptDomain: 返回配置
    PromptDomain->>LLMService: 调用 LLM
    LLMService->>Eino: 统一接口调用
    Eino->>LLM: 调用实际 LLM API
    LLM-->>Eino: 返回结果
    Eino-->>LLMService: 返回结果
    LLMService->>Tracer: 记录 Trace
    Tracer->>DB: 保存 Trace 元数据
    Tracer->>Redis: 缓存热数据
    LLMService-->>PromptDomain: 返回结果
    PromptDomain-->>User: 流式返回结果

    Note over User,LLM: 整个过程约 200-500ms(取决于 LLM 响应)

📝 关键节点说明

  1. Nginx 反向代理:负责静态文件服务和 API 请求转发
  2. Hertz HTTP 网关:统一的 HTTP 入口,处理认证、日志、限流等横切关注点
  3. Application 层:编排多个 Domain Service 完成复杂用例
  4. Domain 层:核心业务逻辑,如 Prompt 参数校验、版本管理等
  5. Eino 框架:屏蔽不同 LLM 的差异,提供统一的调用接口
  6. Tracer 服务:实时记录每次调用的完整链路,便于问题排查和性能分析

2. 目录结构与核心流程 📂

🗂️ 目录组织逻辑

Coze Loop 的目录结构非常清晰,遵循"约定优于配置"的原则。让我带你深入理解每个目录的职责:

后端目录结构:

backend/
├── cmd/                    # 程序入口
│   ├── main.go            # 主程序入口 🚪
│   ├── consumer.go        # 消息消费者启动
│   └── script/            # 启动脚本
│
├── api/                    # HTTP API 层
│   ├── router/            # 路由定义
│   ├── handler/           # HTTP 请求处理器
│   │   └── coze/loop/apis/  # 各领域的 API Handler
│   └── router_gen.go      # 自动生成的路由代码
│
├── modules/                # 业务模块(DDD 核心)
│   ├── data/              # 数据集管理领域 📊
│   ├── evaluation/        # 评测领域 🧪
│   ├── foundation/        # 基础服务(用户、文件、空间)🏛️
│   ├── llm/               # LLM 模型管理 🤖
│   ├── observability/     # 观测(Trace)📈
│   └── prompt/            # Prompt 管理 📝
│
├── infra/                  # 基础设施组件
│   ├── db/                # 数据库连接池
│   ├── redis/             # Redis 客户端
│   ├── mq/                # 消息队列
│   ├── ck/                # ClickHouse 客户端
│   ├── fileserver/        # 文件存储(S3/MinIO)
│   ├── looptracer/        # 分布式追踪
│   ├── metrics/           # 指标监控
│   ├── limiter/           # 限流器
│   └── ...
│
├── pkg/                    # 共享工具包
│   ├── errorx/            # 错误处理
│   ├── logs/              # 日志
│   ├── lang/              # 语言工具(类型转换等)
│   └── ...
│
├── kitex_gen/              # Kitex 自动生成的代码
│   └── coze/loop/         # Thrift 定义对应的 Go 代码
│
├── loop_gen/               # 业务层生成的代码
│   └── coze/loop/         # GORM 生成的 DAO 代码
│
├── conf/                   # 配置文件目录
│   ├── infrastructure.yaml  # 基础设施配置
│   └── locales/            # 国际化文件
│
├── idl -> ../idl/          # 软链接到根目录的 IDL
└── go.mod                  # Go 模块定义

前端目录结构:

frontend/
├── apps/
│   └── cozeloop/          # 主应用 🎯
│       ├── src/
│       │   ├── pages/     # 页面组件
│       │   ├── layouts/   # 布局组件
│       │   ├── routes/    # 路由配置
│       │   └── App.tsx    # 根组件
│       ├── rsbuild.config.ts  # 构建配置
│       └── package.json
│
├── packages/
│   └── cozeloop/          # 业务组件库
│       ├── account/       # 账号相关
│       ├── auth-pages/    # 认证页面
│       ├── prompt-pages/  # Prompt 相关页面
│       ├── evaluate-pages/# 评测相关页面
│       ├── observation-pages/  # 观测相关页面
│       ├── components/    # 通用组件
│       ├── stores/        # 状态管理
│       └── api-schema/    # API 类型定义(自动生成)
│
├── infra/                  # 基础设施
│   ├── idl/               # IDL 自动生成工具
│   ├── utils/             # 工具库
│   └── plugins/           # 构建插件
│
├── config/                 # 共享配置
│   ├── eslint-config/     # ESLint 配置
│   ├── ts-config/         # TypeScript 配置
│   ├── tailwind-config/   # TailwindCSS 配置
│   └── ...
│
└── rush.json               # Rush Monorepo 配置

🔑 关键文件定位

"第一个应阅读"的文件清单:

  1. 后端启动入口backend/cmd/main.go

    • 这是一切的开始!了解系统如何初始化组件、启动服务
  2. 后端配置示例backend/conf/infrastructure.yaml

    • 看看系统需要哪些配置项,每个配置的作用
  3. API 路由定义backend/api/router/register.go

    • 了解系统提供了哪些 HTTP 接口
  4. 前端入口frontend/apps/cozeloop/src/App.tsx

    • 前端的根组件,了解路由和全局状态管理
  5. 前端路由配置frontend/apps/cozeloop/src/routes/

    • 看看前端有哪些页面,URL 路径规划
  6. 部署配置release/deployment/docker-compose/docker-compose.yml

    • 了解系统的部署架构和依赖的基础服务

🧩 模块依赖关系

Coze Loop 的各模块之间有清晰的依赖关系,遵循单向依赖原则:

依赖层次(从上到下):

┌─────────────────────────────────────┐
│     api (HTTP API 层)               │  ← 最外层,依赖所有
├─────────────────────────────────────┤
│     modules (业务领域模块)          │  ← 业务核心
│  - data                             │
│  - evaluation                       │
│  - foundation                       │
│  - llm                              │
│  - observability                    │
│  - prompt                           │
├─────────────────────────────────────┤
│     infra (基础设施层)               │  ← 被所有业务模块依赖
│  - db, redis, mq, ck               │
│  - fileserver, tracer, metrics     │
│  - limiter, idgen, etc.            │
├─────────────────────────────────────┤
│     pkg (通用工具包)                 │  ← 最底层,零依赖
│  - errorx, logs, lang, etc.       │
└─────────────────────────────────────┘

💡 依赖规则

  • ✅ 上层可以依赖下层
  • ✅ 同层模块之间通过接口(interface)解耦
  • ❌ 下层不能依赖上层(否则会循环依赖)
  • ❌ 业务模块之间不能直接依赖(通过 RPC 或事件通信)

模块间通信方式:

通信场景 通信方式 示例
API 调用业务模块 直接调用 api/handlermodules/prompt/application
业务模块访问基础设施 依赖注入接口 prompt/domain/serviceinfra/db.Provider (接口)
业务模块间通信 RPC 或消息队列 evaluation/domain → RPC → prompt/domain
异步任务 消息队列 evaluation/application → MQ → evaluation/infra/mq/consumer

🎬 典型业务流程深度剖析

让我们选择"创建并执行一个 Prompt 评测实验"这个核心场景,深入理解数据流和控制流:

场景:用户在前端创建一个评测实验,测试 Prompt 在多个测试用例下的表现

步骤 1:前端发起请求

// frontend/packages/cozeloop/evaluate-pages/src/components/ExperimentForm.tsx
import {
    createExperiment } from '@cozeloop/api-schema';

const handleSubmit = async (values) => {
   
  const result = await createExperiment({
   
    name: values.name,
    promptId: values.promptId,
    evaluationSetId: values.evaluationSetId,
    evaluators: values.evaluators,
  });
  // 跳转到实验详情页
  navigate(`/evaluation/experiments/${
     result.id}`);
};

步骤 2:HTTP API 层接收请求

// backend/api/handler/coze/loop/apis/experiment_service.go
func (h *APIHandler) CreateExperiment(ctx context.Context, req *loop.CreateExperimentReq) (*loop.CreateExperimentResp, error) {
   
    // 1. 参数校验
    if err := validator.Validate(req); err != nil {
   
        return nil, errorx.Wrap(err, errorx.CodeInvalidParam)
    }

    // 2. 调用 Application 层
    expt, err := h.ExperimentApp.Create(ctx, &application.CreateExperimentParam{
   
        Name: req.Name,
        PromptID: req.PromptId,
        EvaluationSetID: req.EvaluationSetId,
        Evaluators: req.Evaluators,
    })
    if err != nil {
   
        return nil, err
    }

    // 3. 返回响应
    return &loop.CreateExperimentResp{
   
        Experiment: convertor.ToExperimentVO(expt),
    }, nil
}

📝 实现文件backend/api/handler/coze/loop/apis/experiment_service.go

步骤 3:Application 层编排业务逻辑

// backend/modules/evaluation/application/experiment_app.go
func (app *ExperimentApplication) Create(ctx context.Context, param *CreateExperimentParam) (*entity.Experiment, error) {
   
    // 1. 校验 Prompt 是否存在(跨领域调用)
    prompt, err := app.promptRPC.GetPrompt(ctx, param.PromptID)
    if err != nil {
   
        return nil, errorx.Wrap(err, errno.PromptNotFound)
    }

    // 2. 校验评测集是否存在
    evalSet, err := app.evalSetService.GetByID(ctx, param.EvaluationSetID)
    if err != nil {
   
        return nil, errorx.Wrap(err, errno.EvaluationSetNotFound)
    }

    // 3. 创建实验实体
    expt := entity.NewExperiment(param.Name, prompt, evalSet)

    // 4. 保存到数据库
    if err := app.exptService.Create(ctx, expt); err != nil {
   
        return nil, err
    }

    // 5. 发送异步评测任务到消息队列
    if err := app.mqProducer.SendExperimentRunTask(ctx, &mq.ExperimentRunTask{
   
        ExperimentID: expt.ID,
    }); err != nil {
   
        log.Error(ctx, "failed to send experiment run task", "err", err)
        // 任务发送失败不影响创建
    }

    return expt, nil
}

📝 实现文件backend/modules/evaluation/application/experiment_app.go

步骤 4:Domain Service 执行核心业务逻辑

// backend/modules/evaluation/domain/service/experiment_service.go
func (s *ExperimentService) Create(ctx context.Context, expt *entity.Experiment) error {
   
    // 1. 业务规则校验
    if err := expt.Validate(); err != nil {
   
        return errorx.Wrap(err, errno.InvalidExperiment)
    }

    // 2. 生成唯一 ID
    id, err := s.idgen.GenerateID(ctx)
    if err != nil {
   
        return err
    }
    expt.ID = id

    // 3. 设置默认值
    expt.Status = entity.ExperimentStatusPending
    expt.CreatedAt = time.Now()

    // 4. 调用仓储层保存
    return s.repo.Create(ctx, expt)
}

📝 实现文件backend/modules/evaluation/domain/service/experiment_service.go

步骤 5:Infra 层持久化数据

// backend/modules/evaluation/infra/repo/experiment_repo.go
func (r *ExperimentRepo) Create(ctx context.Context, expt *entity.Experiment) error {
   
    // 转换为 PO(Persistent Object)
    po := &po.Experiment{
   
        ID: expt.ID,
        Name: expt.Name,
        PromptID: expt.PromptID,
        EvaluationSetID: expt.EvaluationSetID,
        Status: int(expt.Status),
        CreatedAt: expt.CreatedAt,
    }

    // 使用 GORM 保存
    return r.db.WithContext(ctx).Create(po).Error
}

📝 实现文件backend/modules/evaluation/infra/repo/experiment_repo.go

步骤 6:消息队列异步处理评测任务

// backend/modules/evaluation/infra/mq/rocket/experiment_consumer.go
func (c *ExperimentConsumer) ConsumeMessage(ctx context.Context, msgs ...*primitive.MessageExt) (consumer.ConsumeResult, error) {
   
    for _, msg := range msgs {
   
        task := &mq.ExperimentRunTask{
   }
        if err := json.Unmarshal(msg.Body, task); err != nil {
   
            log.Error(ctx, "failed to unmarshal task", "err", err)
            continue
        }

        // 执行评测
        if err := c.experimentApp.Run(ctx, task.ExperimentID); err != nil {
   
            log.Error(ctx, "failed to run experiment", "experimentID", task.ExperimentID, "err", err)
            return consumer.ConsumeRetryLater, err
        }
    }
    return consumer.ConsumeSuccess, nil
}

📝 实现文件backend/modules/evaluation/infra/mq/rocket/experiment_consumer.go

步骤 7:评测执行(核心业务逻辑)

// backend/modules/evaluation/application/experiment_app.go
func (app *ExperimentApplication) Run(ctx context.Context, experimentID string) error {
   
    // 1. 获取实验配置
    expt, err := app.exptService.GetByID(ctx, experimentID)
    if err != nil {
   
        return err
    }

    // 2. 获取评测集的所有测试用例
    items, err := app.evalSetService.GetItems(ctx, expt.EvaluationSetID)
    if err != nil {
   
        return err
    }

    // 3. 并发执行所有测试用例
    var wg sync.WaitGroup
    results := make([]*entity.ExperimentResult, len(items))

    for i, item := range items {
   
        wg.Add(1)
        go func(idx int, testItem *entity.EvaluationSetItem) {
   
            defer wg.Done()

            // 3.1 调用 Prompt 执行
            output, err := app.promptRPC.Execute(ctx, &rpc.ExecutePromptReq{
   
                PromptID: expt.PromptID,
                Input: testItem.Input,
            })
            if err != nil {
   
                log.Error(ctx, "failed to execute prompt", "err", err)
                return
            }

            // 3.2 调用评估器
            scores, err := app.evaluatorService.Evaluate(ctx, &EvaluateParam{
   
                Input: testItem.Input,
                Output: output.Content,
                Expected: testItem.Expected,
                Evaluators: expt.Evaluators,
            })
            if err != nil {
   
                log.Error(ctx, "failed to evaluate", "err", err)
                return
            }

            // 3.3 保存结果
            results[idx] = &entity.ExperimentResult{
   
                ExperimentID: experimentID,
                ItemID: testItem.ID,
                Output: output.Content,
                Scores: scores,
            }
        }(i, item)
    }

    wg.Wait()

    // 4. 保存所有结果
    if err := app.resultService.BatchCreate(ctx, results); err != nil {
   
        return err
    }

    // 5. 更新实验状态为完成
    return app.exptService.UpdateStatus(ctx, experimentID, entity.ExperimentStatusCompleted)
}

📝 实现文件backend/modules/evaluation/application/experiment_app.go

📊 流程图总览

flowchart TD
    A[前端用户操作] -->|HTTP POST| B[Nginx 反向代理]
    B --> C[Hertz HTTP 网关]
    C --> D[API Handler]
    D --> E[Application 层]
    E --> F{校验 Prompt}
    F -->|RPC| G[Prompt Service]
    G --> F
    F --> H{校验评测集}
    H --> I[EvaluationSet Service]
    I --> H
    H --> J[Domain Service]
    J --> K[生成 ID]
    J --> L[业务规则校验]
    L --> M[Infra Repo]
    M --> N[(MySQL)]
    J --> O[发送 MQ 消息]
    O --> P{
  {RocketMQ}}
    P --> Q[Consumer 消费任务]
    Q --> R[执行评测]
    R --> S[并发调用 Prompt]
    R --> T[并发调用 Evaluator]
    S --> U[LLM Service]
    U --> V[Eino 框架]
    V --> W[实际 LLM API]
    W --> V
    V --> U
    U --> S
    T --> Y[保存评测结果]
    Y --> N
    R --> Z[更新实验状态]
    Z --> N

    style A fill:#ff6b6b
    style N fill:#4ecdc4
    style P fill:#ffe66d
    style W fill:#a8dadc

3. 代码结构观察 🔍

💎 代码组织模式

Coze Loop 的代码组织体现了多种优秀的设计模式和编码实践:

1. 依赖注入(Dependency Injection)

Coze Loop 使用 Google Wire 进行编译时依赖注入。Wire 的优势是零运行时开销,所有依赖关系在编译期就确定了。

// backend/modules/evaluation/application/wire.go
//go:build wireinject
// +build wireinject

package application

import (
    "github.com/google/wire"
    "github.com/coze-dev/coze-loop/backend/modules/evaluation/domain/service"
    "github.com/coze-dev/coze-loop/backend/modules/evaluation/infra/repo"
)

// ProviderSet 定义依赖集合
var ProviderSet = wire.NewSet(
    // Domain Services
    service.NewExperimentService,
    service.NewEvaluatorService,

    // Repositories
    repo.NewExperimentRepo,
    repo.NewEvaluatorRepo,

    // Application Services
    NewExperimentApplication,
    NewEvaluatorApplication,
)

// InitExperimentApplication 自动生成的构造函数
func InitExperimentApplication(
    db db.Provider,
    redis redis.Cmdable,
    idgen idgen.IIDGenerator,
    mqFactory mq.IFactory,
) (*ExperimentApplication, error) {
   
    wire.Build(ProviderSet)
    return nil, nil
}

运行 wire gen 后,会自动生成 wire_gen.go,包含完整的依赖注入代码:

// backend/modules/evaluation/application/wire_gen.go
// Code generated by Wire. DO NOT EDIT.

func InitExperimentApplication(
    db db.Provider,
    redis redis.Cmdable,
    idgen idgen.IIDGenerator,
    mqFactory mq.IFactory,
) (*ExperimentApplication, error) {
   
    experimentRepo := repo.NewExperimentRepo(db)
    experimentService := service.NewExperimentService(experimentRepo, idgen)
    evaluatorRepo := repo.NewEvaluatorRepo(db)
    evaluatorService := service.NewEvaluatorService(evaluatorRepo)
    mqProducer := mqFactory.NewProducer()
    experimentApplication := NewExperimentApplication(
        experimentService,
        evaluatorService,
        mqProducer,
    )
    return experimentApplication, nil
}

💡 为什么使用 Wire?

  • ✅ 编译期检查,避免运行时依赖错误
  • ✅ 零反射,性能无损耗
  • ✅ 代码可读性强,依赖关系一目了然

2. 仓储模式(Repository Pattern)

Domain 层定义接口,Infra 层实现,实现了"依赖倒置":

// backend/modules/evaluation/domain/repo/experiment_repo.go
package repo

import (
    "context"
    "github.com/coze-dev/coze-loop/backend/modules/evaluation/domain/entity"
)

// IExperimentRepo 实验仓储接口(由 Domain 层定义)
type IExperimentRepo interface {
   
    Create(ctx context.Context, expt *entity.Experiment) error
    GetByID(ctx context.Context, id string) (*entity.Experiment, error)
    Update(ctx context.Context, expt *entity.Experiment) error
    Delete(ctx context.Context, id string) error
    List(ctx context.Context, query *ExperimentQuery) ([]*entity.Experiment, int64, error)
}
// backend/modules/evaluation/infra/repo/experiment_repo.go
package repo

import (
    "context"
    "github.com/coze-dev/coze-loop/backend/infra/db"
    domainRepo "github.com/coze-dev/coze-loop/backend/modules/evaluation/domain/repo"
    "github.com/coze-dev/coze-loop/backend/modules/evaluation/domain/entity"
)

// ExperimentRepo 实验仓储实现(由 Infra 层实现)
type ExperimentRepo struct {
   
    db db.Provider
}

func NewExperimentRepo(db db.Provider) domainRepo.IExperimentRepo {
   
    return &ExperimentRepo{
   db: db}
}

func (r *ExperimentRepo) Create(ctx context.Context, expt *entity.Experiment) error {
   
    // 实现细节...
}

💡 仓储模式的好处

  • Domain 层不依赖具体的数据库实现
  • 可以轻松切换数据库(如从 MySQL 换到 PostgreSQL)
  • 便于单元测试(Mock Repo 接口即可)

3. 工厂模式(Factory Pattern)

LLM 服务的创建使用了工厂模式:

// backend/modules/llm/domain/service/llm_factory.go
package service

import (
    "github.com/cloudwego/eino"
    "github.com/coze-dev/coze-loop/backend/modules/llm/domain/entity"
)

type LLMFactory interface {
   
    CreateChatModel(config *entity.LLMConfig) (eino.ChatModel, error)
}

type llmFactory struct {
   
    // 注册的模型提供商
    providers map[string]ModelProvider
}

func (f *llmFactory) CreateChatModel(config *entity.LLMConfig) (eino.ChatModel, error) {
   
    provider, ok := f.providers[config.Provider]
    if !ok {
   
        return nil, fmt.Errorf("unsupported provider: %s", config.Provider)
    }
    return provider.CreateChatModel(config)
}

4. 策略模式(Strategy Pattern)

评估器(Evaluator)使用策略模式,支持多种评估策略:

// backend/modules/evaluation/domain/service/evaluator_strategy.go
package service

type EvaluatorStrategy interface {
   
    Evaluate(ctx context.Context, input, output, expected string) (float64, error)
}

// 精确匹配策略
type ExactMatchStrategy struct{
   }

func (s *ExactMatchStrategy) Evaluate(ctx context.Context, input, output, expected string) (float64, error) {
   
    if output == expected {
   
        return 1.0, nil
    }
    return 0.0, nil
}

// LLM 评分策略
type LLMJudgeStrategy struct {
   
    llmService *LLMService
}

func (s *LLMJudgeStrategy) Evaluate(ctx context.Context, input, output, expected string) (float64, error) {
   
    // 调用 LLM 进行评分...
}

🎨 设计模式识别

让我们汇总一下 Coze Loop 中使用的主要设计模式:

设计模式 应用场景 位置 作用
依赖注入(DI) 整个项目 所有模块的 wire.go 解耦依赖,便于测试
仓储模式 数据访问层 domain/repo + infra/repo 隔离数据访问逻辑
工厂模式 LLM 模型创建 llm/domain/service/llm_factory.go 统一创建接口
策略模式 评估器 evaluation/domain/service/evaluator_strategy.go 灵活切换评估算法
观察者模式 事件发布订阅 evaluation/domain/events 解耦模块间通信
单例模式 全局组件 pkg/logs/default.go 确保唯一实例
适配器模式 LLM 接口适配 Eino 框架 统一不同 LLM 的接口
建造者模式 复杂对象构建 entity.NewExperiment() 分步构建复杂对象

📏 代码质量观察

优点:

  1. 清晰的分层架构

    • 每层职责明确,依赖关系单向
    • 符合 SOLID 原则中的单一职责和依赖倒置
  2. 丰富的单元测试

    • 几乎每个 Service 都有对应的 _test.go 文件
    • 使用 go-mock 进行依赖 Mock
  3. 完善的错误处理

    • 统一的错误码体系(pkg/errorx
    • 错误信息包含上下文,便于排查
  4. 国际化支持

    • 使用 go-i18n 实现多语言
    • 错误信息、UI 文案都支持中英文
  5. 代码生成工具

    • Thrift 自动生成 RPC 代码
    • GORM Gen 自动生成 DAO 代码
    • Wire 自动生成依赖注入代码

可观察的改进机会:

  1. 部分文件较长 ⚠️

    • backend/modules/evaluation/domain/service/experiment_service.go 超过 1000 行
    • 💡 学习机会:思考如何将大文件拆分为多个职责单一的小文件
  2. 部分注释不足 ⚠️

    • 有些复杂的业务逻辑缺少注释说明
    • 💡 学习机会:为关键业务逻辑补充文档注释
  3. 部分重复代码 ⚠️

    • 如多个模块都有类似的分页逻辑
    • 💡 学习机会:提取通用的分页工具函数
  4. TODO 和 FIXME 📝

    • 搜索 // TODO:// FIXME: 可以找到一些潜在的改进点
    • 💡 学习机会:尝试修复这些标记的问题,作为贡献的起点

第二部分:技能需求清单(你的学习弹药库)📚

好了,我们已经对 Coze Loop 的架构有了全景式的理解。现在让我们务实一点,看看要真正掌握这个项目,你需要具备哪些技能 💪

💡 心法提示:不要被技能清单吓倒!没有人一开始就会所有技能。学习是渐进的过程,先掌握基础,再逐步深入。

1. 基础技能要求 🎯

这些是你"入场"必须具备的基础技能。如果你对某项技能还不熟悉,先暂停,去把它学会再回来。

🐹 Go 语言(后端核心)

必须掌握的语法特性:

  • 基础语法

    • 变量声明、数据类型、控制流
    • 函数、方法、接口
    • 结构体(Struct)和嵌入(Embedding)
    • 指针和值类型的区别
  • 并发编程 ⭐⭐⭐(重要!):

    • Goroutine 和 Channel
    • sync.WaitGroupsync.Mutexsync.RWMutex
    • context.Context 的使用(超级重要!)
    • select 语句和超时控制
  • 错误处理

    • error 接口
    • 错误包装(fmt.Errorferrors.Wrap
    • deferpanicrecover
  • 接口和多态

    • 接口定义和实现
    • 空接口 interface{}
    • 类型断言和类型转换

项目特定要求:

  • Go 版本:Go 1.24+ (项目使用了最新的 Go 特性)
  • Go Modules:理解 go.modgo.sum
  • 编码规范:遵循《阿里巴巴 Go 开发手册》

📚 学习资源推荐

  • 官方教程:A Tour of Go
  • 经典书籍:《Go 程序设计语言》(The Go Programming Language)
  • 进阶阅读:《Go 语言高级编程》

📜 TypeScript(前端核心)

必须掌握的语法特性:

  • 类型系统

    • 基本类型、联合类型、交叉类型
    • 接口(Interface)和类型别名(Type Alias)
    • 泛型(Generics)
    • 类型守卫和类型收窄
  • ES6+ 特性

    • 箭头函数、解构、展开运算符
    • Promise、async/await
    • 模块化(import/export)
  • React 相关

    • 函数组件和 Hooks
    • useStateuseEffectuseCallbackuseMemo
    • Context API
    • 自定义 Hooks

项目特定要求:

  • TypeScript 版本:5.8+
  • 编码规范:遵循项目的 ESLint 配置

📚 学习资源推荐

🗄️ 数据库基础

必须掌握的概念:

  • SQL 基础

    • SELECT、INSERT、UPDATE、DELETE
    • JOIN(INNER、LEFT、RIGHT)
    • 索引、主键、外键
    • 事务(ACID)
  • MySQL 特定

    • InnoDB 存储引擎
    • 事务隔离级别
    • 锁机制(行锁、表锁)
  • Redis 基础

    • 基本数据类型(String、Hash、List、Set、Sorted Set)
    • 过期时间和 TTL
    • Pub/Sub 机制
  • ClickHouse 基础

    • 列式存储的概念
    • 适用场景(OLAP)
    • 基本查询语法

📚 学习资源推荐

🐳 基础工具

必须掌握的工具:

  1. Git

    • 基本操作(add、commit、push、pull)
    • 分支管理(branch、checkout、merge)
    • 冲突解决
  2. Docker

    • 基本概念(镜像、容器、网络、卷)
    • docker 命令(run、exec、logs、ps)
    • docker-compose 的使用
  3. 命令行工具

    • Linux 基本命令(ls、cd、grep、ps、kill)
    • 文本处理(cat、head、tail、awk、sed)
    • 进程管理

📚 学习资源推荐

2. 进阶技能要求 🚀

这些技能不是"入场券",但掌握它们会让你对项目理解更深,能做更复杂的开发。

🏛️ 架构模式

领域驱动设计(DDD)

Coze Loop 的核心架构模式,理解它是深入项目的关键!

  • 核心概念

    • 实体(Entity)、值对象(Value Object)、聚合(Aggregate)
    • 领域服务(Domain Service)、应用服务(Application Service)
    • 仓储(Repository)、工厂(Factory)
    • 领域事件(Domain Event)
  • 分层架构

    • User Interface 层
    • Application 层
    • Domain 层
    • Infrastructure 层

💡 学习路径

  1. 先理解"为什么需要 DDD"(解决什么问题)
  2. 再学习核心概念
  3. 最后在 Coze Loop 代码中寻找对应的实现

📚 学习资源推荐

  • 经典书籍:《领域驱动设计》(Eric Evans)
  • 入门书籍:《实现领域驱动设计》(Vaughn Vernon)
  • 博客文章:DDD 实践系列

微服务架构

  • 核心概念

    • 服务拆分原则
    • 服务间通信(RPC、消息队列)
    • 服务发现和负载均衡
    • 分布式事务
  • CloudWeGo 技术栈

    • Kitex(RPC 框架)
    • Hertz(HTTP 框架)
    • Netpoll(网络库)

📚 学习资源推荐

消息驱动架构

  • RocketMQ 的使用
  • 发布-订阅模式
  • 消息幂等性和重试机制

🔧 设计原则

SOLID 原则

Coze Loop 代码中处处体现这些原则,理解它们会让你"看懂"代码的设计意图。

  1. S - 单一职责原则(SRP)

    • 每个类/模块只做一件事
    • 示例:Coze Loop 中每个 Service 只负责一个领域实体
  2. O - 开闭原则(OCP)

    • 对扩展开放,对修改封闭
    • 示例:通过接口定义 Evaluator,新增评估策略无需修改现有代码
  3. L - 里氏替换原则(LSP)

    • 子类可以替换父类
    • 示例:所有 Repo 实现都可以替换接口
  4. I - 接口隔离原则(ISP)

    • 接口应该小而专注
    • 示例:不同的 Repo 接口有不同的方法集
  5. D - 依赖倒置原则(DIP)

    • 高层模块不应依赖低层模块,都应依赖抽象
    • 示例:Domain 层定义接口,Infra 层实现

📚 学习资源推荐

  • 经典书籍:《代码整洁之道》(Clean Code)
  • 进阶阅读:《重构:改善既有代码的设计》

🧪 测试驱动开发(TDD)

Coze Loop 有完善的测试体系,学习如何编写和运行测试是必须的。

  • 单元测试

    • 使用 Go 的 testing
    • Mock 依赖(gomocktestify
    • 表驱动测试(Table-Driven Tests)
  • 集成测试

    • 使用 miniredis(内存 Redis)和 sqlmock(Mock 数据库)
    • 测试多个模块的协作

📚 学习资源推荐

3. 领域特定知识 🌐

🤖 AI 和 LLM 基础

Coze Loop 是 AI Agent 开发平台,理解 AI 和 LLM 的基础知识会让你更好地理解业务需求。

必知概念:

  • LLM(Large Language Model)

    • 什么是 LLM?(GPT、Claude、Gemini 等)
    • Prompt 和 Completion 的概念
    • Token 和计费模型
  • Prompt Engineering

    • 什么是 Prompt?
    • System Prompt、User Prompt、Assistant Prompt
    • Few-Shot Learning、Chain-of-Thought
  • AI Agent

    • 什么是 Agent?
    • Agent 的工作流(Planning、Tool Use、Reflection)
    • 多 Agent 协作

📚 学习资源推荐

📊 观测和监控

Coze Loop 的核心功能之一是"观测",理解这些概念很重要。

核心概念:

  • Tracing(链路追踪)

    • Span、Trace 的概念
    • OpenTelemetry 标准
  • Logging(日志)

    • 结构化日志
    • 日志级别和分类
  • Metrics(指标)

    • Counter、Gauge、Histogram
    • 监控指标的设计

📚 学习资源推荐

4. 技能掌握程度建议 🎯

不同阶段的学习者应该把精力放在不同的技能上。这里给出三个阶段的建议:

🌱 阶段一:初学者(0-3 个月经验)

目标:能跑起来项目,看懂基本代码逻辑

必修技能(按优先级):

  1. ✅ Go 基础语法(70% 掌握)
  2. ✅ TypeScript 基础语法(60% 掌握)
  3. ✅ Git 基本操作(80% 掌握)
  4. ✅ Docker 基本使用(60% 掌握)
  5. ✅ SQL 基础(60% 掌握)
  6. ✅ HTTP 协议基础(70% 掌握)

选修技能:

  • Redis 基础命令
  • Linux 基本命令

学习重点:

  • 先不要纠结架构细节,能跑起来就是胜利!
  • 跟着文档一步步操作,记录遇到的问题和解决方法
  • 尝试修改一些简单的配置,观察效果

🌿 阶段二:有经验的开发者(3-12 个月经验)

目标:理解架构设计,能独立完成功能开发

必修技能(按优先级):

  1. ✅ Go 高级特性(90% 掌握)
    • Context、Goroutine、Channel
    • Interface 和多态
  2. ✅ DDD 核心概念(70% 掌握)
    • 分层架构
    • Entity、Service、Repo
  3. ✅ 微服务基础(60% 掌握)
    • RPC 通信
    • 服务拆分原则
  4. ✅ 数据库进阶(80% 掌握)
    • 事务、锁、索引优化
  5. ✅ 消息队列基础(60% 掌握)
    • RocketMQ 的使用

选修技能:

  • SOLID 设计原则
  • 常见设计模式
  • 单元测试编写

学习重点:

  • 阅读核心模块的代码,理解每层的职责
  • 尝试实现一个简单的新功能(如新增一个评估器类型)
  • 为你编写的代码添加单元测试

🌳 阶段三:意欲贡献代码的进阶者(12 个月+ 经验)

目标:深度理解系统,能优化架构和性能

必修技能(按优先级):

  1. ✅ Go 性能优化(80% 掌握)
    • Profiling(pprof)
    • 内存管理和 GC
    • 并发优化
  2. ✅ DDD 深度实践(90% 掌握)
    • 领域建模
    • 事件驱动架构
  3. ✅ 分布式系统(70% 掌握)
    • CAP 理论
    • 一致性算法
    • 分布式事务
  4. ✅ CloudWeGo 深度使用(80% 掌握)
    • Kitex 高级特性
    • 性能调优
  5. ✅ 可观测性(70% 掌握)
    • OpenTelemetry 集成
    • 性能分析

选修技能:

  • 编译原理(理解 Thrift IDL)
  • 代码生成工具开发
  • CI/CD 流水线设计

学习重点:

  • 分析系统的性能瓶颈,提出优化方案
  • 阅读项目的 TODO 和 FIXME,尝试修复
  • 参与社区讨论,提交 Pull Request

呼~ 第二部分就到这里!技能清单看起来很长,但不要慌 😊 学习是一个渐进的过程,按照阶段一步步来就好。

接下来我们进入最激动人心的部分——学习路径规划!我会手把手教你如何快速上手 Coze Loop 🚀


第三部分:学习路径规划(你的专属教练计划)🎯

本部分目标:提供清晰、可执行的学习路径,让你从"一脸懵逼"到"运筹帷幄"。

💡 心法提示:学习路径不是线性的!遇到困难时可以跳到其他章节,回头再来挑战。

1. 项目运行入口定位(快速上手)⚡

让我们先把项目跑起来!这是建立信心的第一步 💪

🎯 一键启动指南

前置准备(10 分钟)

在开始之前,请确保你的电脑上已安装:

  • Docker Desktop(版本 20.10+)

    • Windows: 从 Docker 官网 下载
    • macOS: 使用 Homebrew brew install --cask docker
    • Linux: 使用包管理器安装(如 apt install docker.io
  • Git(版本 2.30+)

    • 检查是否已安装:git --version
    • 未安装则从 Git 官网 下载
  • 至少 8GB 内存和 20GB 磁盘空间

    • Coze Loop 会启动多个服务容器(MySQL、Redis、ClickHouse 等)

步骤 1:克隆代码(2 分钟)

打开终端,执行以下命令:

# 克隆项目
git clone https://github.com/coze-dev/coze-loop.git

# 进入项目目录
cd coze-loop

# 查看目录结构,确认克隆成功
ls -la

步骤 2:配置 LLM 模型(3 分钟)

Coze Loop 需要连接 LLM 服务才能运行。这里以火山方舟为例(你也可以用 OpenAI、千帆等):

# 编辑模型配置文件
vim release/deployment/docker-compose/conf/model_config.yaml

# 或者用你喜欢的编辑器(VS Code、Sublime Text 等)

修改以下内容:

models:
  - model_id: "default-model"
    provider: "volcengine_ark"  # 或 "openai"、"qianfan" 等
    model: "ep-xxxxx"            # 你的模型 Endpoint ID
    api_key: "your-api-key"      # 你的 API Key

💡 如何获取 API Key?

步骤 3:启动服务(5-10 分钟)

# 方式一:使用默认模式启动(推荐)
make compose-up

# 方式二:使用开发模式启动(支持代码热更新)
make compose-up-dev

等待时间:首次启动需要下载多个 Docker 镜像,大约 5-10 分钟。你可以:

  • 泡杯咖啡 ☕
  • 看看 README 文档 📖
  • 思考一下今天的晚饭 🍱

步骤 4:验证成功(1 分钟)

看到以下日志,说明启动成功了 🎉

[+] Running 13/13
 ✔ Network coze-loop-network              Created
 ✔ Container coze-loop-redis              Healthy
 ✔ Container coze-loop-mysql              Healthy
 ✔ Container coze-loop-clickhouse         Healthy
 ✔ Container coze-loop-minio              Healthy
 ✔ Container coze-loop-rmq-namesrv        Healthy
 ✔ Container coze-loop-rmq-broker         Healthy
 ✔ Container coze-loop-python-faas        Healthy
 ✔ Container coze-loop-js-faas            Healthy
 ✔ Container coze-loop-app                Healthy
 ✔ Container coze-loop-nginx              Started

打开浏览器,访问:http://localhost:8082

看到 Coze Loop 的登录页面,恭喜你,第一关通过了! 🚀

🛠️ 环境配置清单

让我们深入理解一下启动过程中发生了什么:

Docker Compose 启动的服务:

服务名 容器名 端口 作用 启动优先级
redis coze-loop-redis 6379 缓存、分布式锁 1️⃣
mysql coze-loop-mysql 3306 主数据库 1️⃣
clickhouse coze-loop-clickhouse 9000 观测数据存储 1️⃣
minio coze-loop-minio 9000 对象存储(文件) 1️⃣
rocketmq-namesrv coze-loop-rmq-namesrv 9876 消息队列注册中心 2️⃣
rocketmq-broker coze-loop-rmq-broker 10911 消息队列 Broker 2️⃣
python-faas coze-loop-python-faas 8890 Python 代码执行沙箱 2️⃣
js-faas coze-loop-js-faas 8891 JavaScript 代码执行沙箱 2️⃣
app coze-loop-app 8888 Coze Loop 后端服务 3️⃣
nginx coze-loop-nginx 8082 前端静态文件 + API 反代 4️⃣

💡 启动顺序说明

  • Docker Compose 会按照 depends_onhealthcheck 确保服务按正确顺序启动
  • 每个服务都有健康检查,只有健康后才会启动依赖它的服务

⚠️ 常见配置陷阱及解决方案

陷阱 1:端口被占用

现象:启动时报错 bind: address already in use

排查方法

# 查看 8082 端口被谁占用
# Windows
netstat -ano | findstr :8082

# macOS/Linux
lsof -i :8082

解决方案

方案 A:停止占用端口的进程

# 假设 PID 是 12345
kill 12345  # macOS/Linux
taskkill /PID 12345 /F  # Windows

方案 B:修改 Coze Loop 的端口

# 编辑 .env 文件
vim release/deployment/docker-compose/.env

# 修改端口
COZE_LOOP_NGINX_PORT=18082  # 改成其他未被占用的端口
陷阱 2:Docker 内存不足

现象:容器反复重启,日志显示 OOMKilled

排查方法

# 查看 Docker 内存限制
docker info | grep Memory

解决方案

  • Docker Desktop:设置 → Resources → Memory → 增加到至少 8GB
  • Linux:检查系统内存是否充足,关闭其他占用内存的程序
陷阱 3:网络问题导致镜像拉取失败

现象Error response from daemon: Get https://registry-1.docker.io/...

解决方案

配置 Docker 镜像加速器(国内用户):

# 编辑 Docker 配置
# macOS: ~/.docker/daemon.json
# Linux: /etc/docker/daemon.json
# Windows: Docker Desktop 设置 → Docker Engine

{
   
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}

# 重启 Docker
# macOS/Windows: Docker Desktop 重启
# Linux:
sudo systemctl restart docker
陷阱 4:LLM API 配置错误

现象:项目启动成功,但执行 Prompt 时报错 invalid api_key

排查方法

# 查看后端日志
docker logs coze-loop-app -f

# 搜索 "LLM" 关键字
docker logs coze-loop-app 2>&1 | grep LLM

解决方案

检查 model_config.yaml 中的配置:

# 正确的配置示例
models:
  - model_id: "default-model"
    provider: "volcengine_ark"
    model: "ep-20241201234567-xxxxx"  # 确保是正确的 Endpoint ID
    api_key: "xxxxxxxxxxxxxxxxxxxxxx"  # 确保 API Key 没有多余的空格或换行

✅ 验证成功标志

启动成功后,你应该能看到:

1. 访问前端页面

  • 打开 http://localhost:8082
  • 看到登录页面
  • 可以注册新账号(开源版无需真实邮箱验证)

2. 查看容器状态

# 所有容器都应该是 "Up" 状态
docker ps --format "table {
   {.Names}}\t{
   {.Status}}"

3. 测试后端 API

# 健康检查接口
curl http://localhost:8888/ping

# 应该返回:
# {"message":"pong"}

4. 登录并创建第一个 Prompt

  • 注册账号
  • 登录后进入"Prompt 管理"
  • 创建一个简单的 Prompt:你好,请介绍一下自己
  • 点击"执行",看到 LLM 返回结果

看到 LLM 的回复,说明整个链路打通了!🎉


2. 循序渐进学习计划(四阶段法)📈

好了,项目跑起来了,现在让我们制定一个清晰的学习计划。我把学习分为四个阶段,每个阶段都有明确的目标和可验证的成果。

🌱 阶段一:环境搭建和项目启动(1-2 天)

目标:成功运行项目并能打个断点 🎯

学习任务清单:

  • [x] ✅ 完成项目启动(上一节已经完成)
  • [ ] 📖 阅读 README.md 和 README.cn.md
  • [ ] 🔍 理解 Docker Compose 配置文件
  • [ ] 🐛 学会查看容器日志和排查问题
  • [ ] 💻 配置 IDE(VS Code 或 GoLand)
  • [ ] 🔧 尝试修改一个配置并重启服务

详细步骤:

步骤 1:阅读官方文档(30 分钟)

# 在浏览器中打开 README
# 或者用 Markdown 阅读器打开
cat README.cn.md | less

关注这些关键信息:

  • 项目的核心功能
  • 部署方式(Docker Compose 和 Helm)
  • 开发指南链接

步骤 2:理解 Docker Compose 配置(1 小时)

打开 release/deployment/docker-compose/docker-compose.yml,逐行阅读并理解:

# 示例:理解 app 服务的配置
app:
  container_name: "coze-loop-app"
  image: "..."                    # 使用的镜像
  networks:
    - coze-loop-network           # 网络配置
  ports:
    - "8888:8888"                 # 端口映射
  volumes:
    - ./conf:/coze-loop/conf      # 配置文件挂载
  environment:                    # 环境变量
    COZE_LOOP_REDIS_DOMAIN: "coze-loop-redis"
  depends_on:                     # 依赖的服务
    redis:
      condition: service_healthy

💡 小练习:尝试画出服务依赖图,理解启动顺序。

步骤 3:学会查看日志(30 分钟)

# 查看所有容器状态
docker ps -a

# 查看特定容器的日志
docker logs coze-loop-app

# 实时跟踪日志(Ctrl+C 退出)
docker logs coze-loop-app -f

# 查看最近 100 行日志
docker logs coze-loop-app --tail 100

# 查看带时间戳的日志
docker logs coze-loop-app -t

💡 小练习:故意停止 Redis 容器,观察 app 容器的日志输出。

# 停止 Redis
docker stop coze-loop-redis

# 查看 app 日志,应该看到连接失败的错误
docker logs coze-loop-app -f

# 重启 Redis
docker start coze-loop-redis

步骤 4:配置 IDE(1 小时)

VS Code 配置(推荐):

  1. 安装必要的扩展:

    • Go (官方)
    • Docker
    • ESLint
    • Prettier
    • GitLens
  2. 打开项目:

# 用 VS Code 打开项目
code .
  1. 配置 Go 开发环境:
# 在 VS Code 中打开 backend 目录
cd backend

# 安装 Go 工具(VS Code 会自动提示)
# 点击右下角的 "Install All"
  1. 配置断点调试:

创建 .vscode/launch.json

{
   
  "version": "0.2.0",
  "configurations": [
    {
   
      "name": "Debug Coze Loop",
      "type": "go",
      "request": "launch",
      "mode": "debug",
      "program": "${workspaceFolder}/backend/cmd",
      "env": {
   
        "COZE_LOOP_REDIS_DOMAIN": "localhost",
        "COZE_LOOP_REDIS_PORT": "6379",
        "COZE_LOOP_MYSQL_DOMAIN": "localhost",
        "COZE_LOOP_MYSQL_PORT": "3306",
        "COZE_LOOP_MYSQL_USER": "root",
        "COZE_LOOP_MYSQL_PASSWORD": "coze_loop",
        "COZE_LOOP_MYSQL_DATABASE": "coze_loop"
      },
      "args": []
    }
  ]
}
  1. 尝试打断点:
  • 打开 backend/cmd/main.go
  • main() 函数的第一行设置断点(点击行号左侧)
  • 按 F5 启动调试
  • 程序会在断点处暂停

💡 小练习:在断点处使用调试控制台查看变量值。

步骤 5:修改配置并重启(30 分钟)

尝试修改一些配置,观察效果:

练习 A:修改日志级别

# 编辑配置文件
vim backend/conf/infrastructure.yaml

# 修改日志级别
infra:
  log_level: "debug"  # 改为 debug 级别

# 重启 app 容器
docker restart coze-loop-app

# 查看日志,应该看到更详细的调试信息
docker logs coze-loop-app -f

练习 B:修改前端端口

# 编辑 .env 文件
vim release/deployment/docker-compose/.env

# 修改前端端口
COZE_LOOP_NGINX_PORT=18082

# 重启所有服务
make compose-down
make compose-up

# 访问新端口
open http://localhost:18082

阶段一完成标志:

  • ✅ 能独立启动和停止项目
  • ✅ 能查看和理解容器日志
  • ✅ IDE 配置完成,能打断点调试
  • ✅ 能修改配置并观察效果

🌿 阶段二:核心流程理解(3-5 天)

目标:追踪一个完整业务流程,画出自己的流程图 🎯

学习任务清单:

  • [ ] 📖 理解后端的 DDD 分层架构
  • [ ] 🔍 追踪"创建 Prompt"的完整流程
  • [ ] 🎨 绘制流程图和时序图
  • [ ] 💻 阅读核心代码并添加注释
  • [ ] 🧪 运行单元测试

详细步骤:

步骤 1:理解 DDD 分层架构(2 小时)

阅读本文档的"第一部分 → 1. 项目架构概览",重点理解:

  • Application 层的职责
  • Domain 层的职责
  • Infra 层的职责

然后选择一个模块深入研究,推荐从最简单的 foundation 模块开始:

cd backend/modules/foundation

# 查看目录结构
tree -L 2

# 输出:
# ├── application       # 用例层
# │   ├── space.go
# │   └── user.go
# ├── domain            # 领域层
# │   ├── user/
# │   └── file/
# └── infra             # 基础设施层
#     └── repo/

步骤 2:追踪"创建 Prompt"流程(4 小时)

这是一个完整的业务流程,涉及多个层次。让我们一步步追踪:

2.1 找到 HTTP 入口

# 搜索 CreatePrompt 相关代码
cd backend
grep -r "CreatePrompt" --include="*.go"

# 找到 API Handler
vim api/handler/coze/loop/apis/prompt_manage_service.go

阅读 CreatePrompt 方法:

func (h *APIHandler) CreatePrompt(ctx context.Context, req *loop.CreatePromptReq) (*loop.CreatePromptResp, error) {
   
    // 💡 这里是入口!理解参数校验、权限检查等
}

2.2 追踪到 Application 层

vim modules/prompt/application/manage.go

找到 Create 方法:

func (app *ManageApplication) Create(ctx context.Context, param *CreatePromptParam) (*entity.Prompt, error) {
   
    // 💡 这里编排了整个创建流程
    // 1. 参数校验
    // 2. 调用 Domain Service
    // 3. 发布事件(如果需要)
}

2.3 追踪到 Domain 层

vim modules/prompt/domain/service/prompt_service.go

找到核心业务逻辑:

func (s *PromptService) Create(ctx context.Context, prompt *entity.Prompt) error {
   
    // 💡 这里是核心业务规则
    // 1. 生成 ID
    // 2. 校验业务规则
    // 3. 调用 Repo 保存
}

2.4 追踪到 Infra 层

vim modules/prompt/infra/repo/prompt_repo.go

找到数据库操作:

func (r *PromptRepo) Create(ctx context.Context, prompt *entity.Prompt) error {
   
    // 💡 这里是技术实现
    // 使用 GORM 保存到数据库
}

步骤 3:绘制流程图(1 小时)

使用你喜欢的工具绘制流程图:

示例:创建 Prompt 流程图

sequenceDiagram
    participant User as 👤 用户
    participant API as 🌐 API Handler
    participant App as 📦 Application
    participant Domain as 🧠 Domain Service
    participant Repo as 💾 Repository
    participant DB as 🗄️ Database

    User->>API: POST /api/prompt/create
    API->>API: 1. 参数校验
    API->>API: 2. 权限检查
    API->>App: 3. 调用 Application.Create
    App->>Domain: 4. 调用 Domain.Create
    Domain->>Domain: 5. 生成 ID
    Domain->>Domain: 6. 业务规则校验
    Domain->>Repo: 7. 调用 Repo.Create
    Repo->>DB: 8. INSERT INTO prompts
    DB-->>Repo: 9. 返回成功
    Repo-->>Domain: 10. 返回成功
    Domain-->>App: 11. 返回 Prompt 实体
    App-->>API: 12. 返回 Prompt 实体
    API->>API: 13. 转换为 VO
    API-->>User: 14. 返回 JSON 响应

💡 小练习:对比你画的图和本文档的图,看看有什么不同。

步骤 4:阅读核心代码并添加注释(3 小时)

选择一个你感兴趣的功能,深入阅读代码并添加中文注释:

// CreatePrompt 创建一个新的 Prompt
// 流程:
// 1. 参数校验(必填字段、格式校验)
// 2. 权限检查(用户是否有权限创建)
// 3. 调用 Application 层创建
// 4. 返回结果(转换为 VO)
func (h *APIHandler) CreatePrompt(ctx context.Context, req *loop.CreatePromptReq) (*loop.CreatePromptResp, error) {
   
    // 参数校验
    if req.Name == "" {
   
        return nil, errorx.New(errno.InvalidParam, "name is required")
    }

    // 调用 Application 层
    prompt, err := h.PromptApp.Create(ctx, &application.CreatePromptParam{
   
        Name: req.Name,
        Content: req.Content,
    })
    if err != nil {
   
        return nil, err
    }

    // 转换为 VO(View Object)返回给前端
    return &loop.CreatePromptResp{
   
        Prompt: convertor.ToPromptVO(prompt),
    }, nil
}

💡 小练习:为 3-5 个关键方法添加详细注释。

步骤 5:运行单元测试(1 小时)

# 进入后端目录
cd backend

# 运行所有测试
go test ./...

# 运行特定模块的测试
go test ./modules/prompt/...

# 运行单个测试文件
go test ./modules/prompt/application/manage_test.go

# 运行并显示详细输出
go test -v ./modules/prompt/...

# 运行并显示覆盖率
go test -cover ./modules/prompt/...

阅读测试代码,理解如何测试:

vim modules/prompt/application/manage_test.go

示例测试代码:

func TestManageApplication_Create(t *testing.T) {
   
    // 1. 准备 Mock 对象
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    mockRepo := mock_repo.NewMockIPromptRepo(ctrl)
    mockIDGen := mock_idgen.NewMockIIDGenerator(ctrl)

    // 2. 设置 Mock 期望
    mockIDGen.EXPECT().
        GenerateID(gomock.Any()).
        Return(int64(123456), nil)

    mockRepo.EXPECT().
        Create(gomock.Any(), gomock.Any()).
        Return(nil)

    // 3. 创建被测对象
    app := NewManageApplication(mockRepo, mockIDGen)

    // 4. 执行测试
    prompt, err := app.Create(context.Background(), &CreatePromptParam{
   
        Name: "test prompt",
    })

    // 5. 验证结果
    assert.NoError(t, err)
    assert.NotNil(t, prompt)
    assert.Equal(t, int64(123456), prompt.ID)
}

💡 小练习:尝试编写一个简单的测试用例。

阶段二完成标志:

  • ✅ 能说清楚 Application、Domain、Infra 三层的职责
  • ✅ 能追踪一个完整的业务流程(从 HTTP 请求到数据库)
  • ✅ 画出了自己的流程图或时序图
  • ✅ 理解了核心代码的逻辑
  • ✅ 能运行和理解单元测试

🌳 阶段三:模块深入和定制开发(1-2 周)

目标:能修改或扩展一个现有功能 🎯

学习任务清单:

  • [ ] 🎨 选择一个感兴趣的模块深入研究
  • [ ] 💻 实现一个小功能(如新增字段、新增接口)
  • [ ] 🧪 为你的代码编写单元测试
  • [ ] 📝 编写简单的设计文档
  • [ ] 🔍 学习前端代码(可选)

详细步骤:

步骤 1:选择研究方向(1 小时)

根据你的兴趣选择一个模块深入研究:

方向 A:Prompt 管理模块 📝

  • 适合:对 AI、LLM 感兴趣的开发者
  • 核心代码:backend/modules/prompt
  • 学习重点:Prompt 版本管理、LLM 调用、流式输出

方向 B:评测模块 🧪

  • 适合:对测试、质量保障感兴趣的开发者
  • 核心代码:backend/modules/evaluation
  • 学习重点:评估器设计、并发任务执行、结果分析

方向 C:观测模块 📊

  • 适合:对监控、性能分析感兴趣的开发者
  • 核心代码:backend/modules/observability
  • 学习重点:Trace 采集、ClickHouse 查询、数据可视化

方向 D:数据集管理模块 📊

  • 适合:对数据处理、ETL 感兴趣的开发者
  • 核心代码:backend/modules/data
  • 学习重点:文件解析、Schema 管理、数据导入导出

步骤 2:实现一个小功能(5-7 天)

让我们以"为 Prompt 添加标签功能"为例:

2.1 设计阶段(1 天)

编写简单的设计文档:

# Prompt 标签功能设计

## 需求
- 用户可以为 Prompt 添加多个标签
- 可以通过标签筛选 Prompt
- 标签支持增删改查

## 数据模型
- 新增 `prompt_tags` 表:
  - id (bigint)
  - prompt_id (bigint)
  - tag_name (varchar)

## API 设计
- POST /api/prompt/{id}/tags      # 添加标签
- DELETE /api/prompt/{id}/tags/{tag}  # 删除标签
- GET /api/prompt/tags            # 获取所有标签

## 实现步骤
1. 修改数据库 Schema
2. 添加 Domain Entity
3. 实现 Repository
4. 实现 Domain Service
5. 实现 Application Service
6. 添加 API Handler
7. 编写单元测试

2.2 修改数据库 Schema(1 小时)

# 创建迁移文件
vim release/deployment/docker-compose/sql/001_add_prompt_tags.sql
CREATE TABLE IF NOT EXISTS `prompt_tags` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `prompt_id` bigint(20) NOT NULL,
  `tag_name` varchar(64) NOT NULL,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_prompt_id` (`prompt_id`),
  KEY `idx_tag_name` (`tag_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.3 添加 Domain Entity(2 小时)

vim backend/modules/prompt/domain/entity/prompt_tag.go
package entity

import "time"

// PromptTag Prompt 标签实体
type PromptTag struct {
   
    ID        int64
    PromptID  int64
    TagName   string
    CreatedAt time.Time
}

// NewPromptTag 创建新标签
func NewPromptTag(promptID int64, tagName string) *PromptTag {
   
    return &PromptTag{
   
        PromptID:  promptID,
        TagName:   tagName,
        CreatedAt: time.Now(),
    }
}

// Validate 校验标签
func (t *PromptTag) Validate() error {
   
    if t.PromptID <= 0 {
   
        return errors.New("invalid prompt_id")
    }
    if t.TagName == "" {
   
        return errors.New("tag_name is required")
    }
    if len(t.TagName) > 64 {
   
        return errors.New("tag_name too long")
    }
    return nil
}

2.4 实现 Repository(3 小时)

定义接口:

vim backend/modules/prompt/domain/repo/prompt_tag_repo.go
package repo

import (
    "context"
    "github.com/coze-dev/coze-loop/backend/modules/prompt/domain/entity"
)

// IPromptTagRepo Prompt 标签仓储接口
type IPromptTagRepo interface {
   
    Create(ctx context.Context, tag *entity.PromptTag) error
    Delete(ctx context.Context, promptID int64, tagName string) error
    GetByPromptID(ctx context.Context, promptID int64) ([]*entity.PromptTag, error)
    GetAll(ctx context.Context) ([]string, error)
}

实现接口:

vim backend/modules/prompt/infra/repo/prompt_tag_repo.go
package repo

import (
    "context"
    "github.com/coze-dev/coze-loop/backend/infra/db"
    domainRepo "github.com/coze-dev/coze-loop/backend/modules/prompt/domain/repo"
    "github.com/coze-dev/coze-loop/backend/modules/prompt/domain/entity"
)

type PromptTagRepo struct {
   
    db db.Provider
}

func NewPromptTagRepo(db db.Provider) domainRepo.IPromptTagRepo {
   
    return &PromptTagRepo{
   db: db}
}

func (r *PromptTagRepo) Create(ctx context.Context, tag *entity.PromptTag) error {
   
    po := &po.PromptTag{
   
        PromptID:  tag.PromptID,
        TagName:   tag.TagName,
        CreatedAt: tag.CreatedAt,
    }
    return r.db.WithContext(ctx).Create(po).Error
}

// ... 其他方法实现

2.5 实现 Domain Service(2 小时)

vim backend/modules/prompt/domain/service/prompt_tag_service.go
package service

import (
    "context"
    "github.com/coze-dev/coze-loop/backend/modules/prompt/domain/entity"
    "github.com/coze-dev/coze-loop/backend/modules/prompt/domain/repo"
)

type PromptTagService struct {
   
    repo repo.IPromptTagRepo
}

func NewPromptTagService(repo repo.IPromptTagRepo) *PromptTagService {
   
    return &PromptTagService{
   repo: repo}
}

func (s *PromptTagService) AddTag(ctx context.Context, promptID int64, tagName string) error {
   
    // 1. 创建标签实体
    tag := entity.NewPromptTag(promptID, tagName)

    // 2. 校验
    if err := tag.Validate(); err != nil {
   
        return err
    }

    // 3. 保存
    return s.repo.Create(ctx, tag)
}

// ... 其他方法

2.6 实现 Application Service(2 小时)

vim backend/modules/prompt/application/tag_app.go
package application

import (
    "context"
    "github.com/coze-dev/coze-loop/backend/modules/prompt/domain/service"
)

type TagApplication struct {
   
    tagService *service.PromptTagService
}

func NewTagApplication(tagService *service.PromptTagService) *TagApplication {
   
    return &TagApplication{
   tagService: tagService}
}

func (app *TagApplication) AddTag(ctx context.Context, promptID int64, tagName string) error {
   
    return app.tagService.AddTag(ctx, promptID, tagName)
}

// ... 其他方法

2.7 添加 API Handler(2 小时)

vim backend/api/handler/coze/loop/apis/prompt_tag_service.go
package apis

import (
    "context"
    "github.com/coze-dev/coze-loop/backend/kitex_gen/coze/loop"
)

func (h *APIHandler) AddPromptTag(ctx context.Context, req *loop.AddPromptTagReq) (*loop.AddPromptTagResp, error) {
   
    // 1. 参数校验
    if req.PromptId <= 0 {
   
        return nil, errorx.New(errno.InvalidParam, "invalid prompt_id")
    }
    if req.TagName == "" {
   
        return nil, errorx.New(errno.InvalidParam, "tag_name is required")
    }

    // 2. 调用 Application 层
    err := h.PromptTagApp.AddTag(ctx, req.PromptId, req.TagName)
    if err != nil {
   
        return nil, err
    }

    // 3. 返回结果
    return &loop.AddPromptTagResp{
   }, nil
}

2.8 编写单元测试(1 天)

vim backend/modules/prompt/application/tag_app_test.go
package application_test

import (
    "context"
    "testing"

    "github.com/golang/mock/gomock"
    "github.com/stretchr/testify/assert"

    "github.com/coze-dev/coze-loop/backend/modules/prompt/application"
    mock_repo "github.com/coze-dev/coze-loop/backend/modules/prompt/domain/repo/mocks"
)

func TestTagApplication_AddTag(t *testing.T) {
   
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()

    mockRepo := mock_repo.NewMockIPromptTagRepo(ctrl)
    mockRepo.EXPECT().
        Create(gomock.Any(), gomock.Any()).
        Return(nil)

    tagService := service.NewPromptTagService(mockRepo)
    app := application.NewTagApplication(tagService)

    err := app.AddTag(context.Background(), 123, "test-tag")
    assert.NoError(t, err)
}

运行测试:

go test ./modules/prompt/application -v -run TestTagApplication_AddTag

步骤 3:前端代码学习(可选,2-3 天)

如果你对前端感兴趣,可以学习如何调用新增的 API:

cd frontend/packages/cozeloop/prompt-pages/src/components

# 创建新组件
vim PromptTagManager.tsx
import React, {
    useState } from 'react';
import {
    addPromptTag, deletePromptTag } from '@cozeloop/api-schema';

export const PromptTagManager: React.FC<{
    promptId: number }> = ({
    promptId }) => {
   
  const [tagName, setTagName] = useState('');
  const [tags, setTags] = useState<string[]>([]);

  const handleAddTag = async () => {
   
    try {
   
      await addPromptTag({
    promptId, tagName });
      setTags([...tags, tagName]);
      setTagName('');
    } catch (error) {
   
      console.error('Failed to add tag:', error);
    }
  };

  return (
    <div>
      <input
        value={
   tagName}
        onChange={
   (e) => setTagName(e.target.value)}
        placeholder="输入标签名"
      />
      <button onClick={
   handleAddTag}>添加标签</button>

      <div>
        {
   tags.map(tag => (
          <span key={
   tag}>{
   tag}</span>
        ))}
      </div>
    </div>
  );
};

阶段三完成标志:

  • ✅ 实现了一个完整的新功能
  • ✅ 代码遵循项目的架构规范
  • ✅ 编写了单元测试,覆盖率 > 80%
  • ✅ 功能在本地环境运行正常
  • ✅ 编写了简单的设计文档

🚀 阶段四:架构理解和贡献指南(2 周+)

目标:能理解技术选型原因,并尝试修复一个简单 issue 🎯

学习任务清单:

  • [ ] 📖 深入理解 CloudWeGo 技术栈
  • [ ] 🔍 研究 Eino 框架的设计
  • [ ] 💻 理解 DDD 在项目中的实践
  • [ ] 🐛 修复一个 Good First Issue
  • [ ] 📝 提交 Pull Request

详细步骤:

步骤 1:深入理解技术选型(3-5 天)

1.1 为什么选择 Go?

阅读资料:

思考问题:

  • Go 的并发模型如何帮助 Coze Loop 处理大量请求?
  • 为什么不选择 Java 或 Node.js?

1.2 为什么选择 CloudWeGo?

阅读官方文档:

对比研究:

  • Kitex vs gRPC
  • Hertz vs Gin/Echo

1.3 为什么选择 DDD?

阅读资料:

思考问题:

  • 如果不用 DDD,代码会变成什么样?
  • DDD 的优势和劣势是什么?

步骤 2:研究 Eino 框架(2-3 天)

Eino 是字节跳动开源的 LLM 统一接入框架,理解它的设计对深入 Coze Loop 很重要。

# 克隆 Eino 仓库
git clone https://github.com/cloudwego/eino.git
cd eino

# 阅读文档
cat README.md

关键概念:

  • ChatModel 接口:统一的 LLM 调用接口
  • Provider 模式:支持多个 LLM 提供商
  • Middleware:拦截器,用于日志、限流等

在 Coze Loop 中找到 Eino 的使用:

cd backend
grep -r "eino" --include="*.go" | head -20

阅读 LLM Service 的实现:

vim modules/llm/domain/service/llm_service.go

步骤 3:寻找贡献机会(1-2 天)

3.1 阅读贡献指南

cat CONTRIBUTING.md
cat CODE_OF_CONDUCT.md

3.2 寻找 Good First Issue

访问 GitHub Issues:https://github.com/coze-dev/coze-loop/issues

筛选条件:

  • Label: good first issue
  • Status: open
  • 最好是你感兴趣的模块

3.3 理解 Issue

选择一个 Issue 后:

  1. 仔细阅读 Issue 描述
  2. 复现问题(如果是 Bug)
  3. 查看相关代码
  4. 思考解决方案

步骤 4:提交 Pull Request(3-5 天)

4.1 Fork 项目

在 GitHub 上点击 Fork 按钮

4.2 创建分支

# 添加上游仓库
git remote add upstream https://github.com/coze-dev/coze-loop.git

# 同步最新代码
git fetch upstream
git checkout main
git merge upstream/main

# 创建特性分支
git checkout -b fix/issue-123

4.3 实现修复

按照项目的编码规范实现修复:

  • 遵循 DDD 架构
  • 编写单元测试
  • 确保所有测试通过
# 运行测试
go test ./...

# 运行 linter
golangci-lint run

4.4 提交代码

# 添加修改
git add .

# 提交(遵循 Conventional Commits 规范)
git commit -m "fix: resolve issue #123 - xxx"

# 推送到你的 Fork
git push origin fix/issue-123

4.5 创建 Pull Request

在 GitHub 上创建 PR,描述清楚:

  • 解决了什么问题
  • 如何解决的
  • 测试情况

4.6 代码审查

  • 回复 Reviewer 的评论
  • 及时修改代码
  • 保持耐心和礼貌

阶段四完成标志:

  • ✅ 能说清楚 Coze Loop 的技术选型原因
  • ✅ 理解 Eino 框架的设计
  • ✅ 成功提交了一个 Pull Request
  • ✅ PR 被 Merge 或得到了有价值的反馈
  • ✅ 成为 Coze Loop 社区的贡献者 🎉

3. 学习路径流程图 🗺️

为了让学习路径更清晰,我画了一个完整的流程图:

flowchart TD
    Start([开始学习 Coze Loop]) --> Stage1{阶段一<br/>环境搭建}

    Stage1 -->|1-2 天| Task1_1[克隆代码]
    Task1_1 --> Task1_2[配置 LLM]
    Task1_2 --> Task1_3[启动服务]
    Task1_3 --> Task1_4[配置 IDE]
    Task1_4 --> Check1{能否成功<br/>运行项目?}

    Check1 -->|否| Debug1[查看日志<br/>排查问题]
    Debug1 --> Task1_3
    Check1 -->|是| Stage2{阶段二<br/>核心流程理解}

    Stage2 -->|3-5 天| Task2_1[学习 DDD 架构]
    Task2_1 --> Task2_2[追踪创建 Prompt 流程]
    Task2_2 --> Task2_3[绘制流程图]
    Task2_3 --> Task2_4[阅读核心代码]
    Task2_4 --> Task2_5[运行单元测试]
    Task2_5 --> Check2{能否画出<br/>完整流程图?}

    Check2 -->|否| Task2_2
    Check2 -->|是| Stage3{阶段三<br/>模块深入}

    Stage3 -->|1-2 周| Task3_1[选择研究方向]
    Task3_1 --> Task3_2[设计新功能]
    Task3_2 --> Task3_3[实现功能]
    Task3_3 --> Task3_4[编写测试]
    Task3_4 --> Task3_5[本地验证]
    Task3_5 --> Check3{功能是否<br/>正常运行?}

    Check3 -->|否| Task3_3
    Check3 -->|是| Stage4{阶段四<br/>贡献代码}

    Stage4 -->|2 周+| Task4_1[深入技术栈]
    Task4_1 --> Task4_2[寻找 Issue]
    Task4_2 --> Task4_3[实现修复]
    Task4_3 --> Task4_4[提交 PR]
    Task4_4 --> Task4_5[代码审查]
    Task4_5 --> Check4{PR 是否<br/>被接受?}

    Check4 -->|需要修改| Task4_3
    Check4 -->|是| Success([成为 Contributor 🎉])

    style Start fill:#ff6b6b,stroke:#333,stroke-width:2px
    style Success fill:#51cf66,stroke:#333,stroke-width:2px
    style Stage1 fill:#339af0,color:#fff
    style Stage2 fill:#339af0,color:#fff
    style Stage3 fill:#339af0,color:#fff
    style Stage4 fill:#339af0,color:#fff

好了,第三部分就到这里!你现在有了一个清晰的学习路径,按照这个路径一步步来,你会发现学习 Coze Loop 并没有那么难 😊

接下来让我们进入第四部分——实践建议和进阶指导,我会分享一些实用的技巧和常见陷阱 💡


第四部分:实践建议和进阶指导(从会用到精通)💡

本部分目标:分享实用的调试技巧、扩展练习建议和参与贡献的途径,帮助你从"会用"走向"精通"。

💡 心法提示:实践是最好的老师!不要害怕犯错,每个 Bug 都是一次学习机会。

1. 调试技巧和常见陷阱 🐛

🔧 调试技巧速查表

后端调试:

技巧 1:使用 Go Delve 调试器

# 安装 Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# 调试运行
dlv debug ./backend/cmd -- [args]

# 远程调试(连接到 Docker 容器)
dlv attach <pid> --headless --listen=:2345 --api-version=2

在 VS Code 中配置远程调试:

{
   
  "version": "0.2.0",
  "configurations": [
    {
   
      "name": "Remote Debug",
      "type": "go",
      "request": "attach",
      "mode": "remote",
      "remotePath": "/coze-loop",
      "port": 2345,
      "host": "localhost"
    }
  ]
}

技巧 2:结构化日志查询

Coze Loop 使用结构化日志,可以使用 jq 工具进行高效查询:

# 查看所有错误日志
docker logs coze-loop-app 2>&1 | grep '"level":"error"'

# 使用 jq 格式化输出
docker logs coze-loop-app 2>&1 | grep '^{' | jq '.

# 查询特定用户的请求
docker logs coze-loop-app 2>&1 | grep '^{
   ' | jq 'select(.user_id == "123")'

# 统计错误类型
docker logs coze-loop-app 2>&1 | grep '^{
   ' | jq -r '.error_code' | sort | uniq -c

技巧 3:性能分析(pprof)

# 开启 pprof(在代码中添加)
import _ "net/http/pprof"

# 访问 pprof 端点
# CPU 分析
curl http://localhost:8888/debug/pprof/profile?seconds=30 > cpu.prof

# 内存分析
curl http://localhost:8888/debug/pprof/heap > heap.prof

# 分析结果
go tool pprof -http=:8080 cpu.prof

技巧 4:数据库查询监控

# 进入 MySQL 容器
docker exec -it coze-loop-mysql mysql -u root -p

# 查看慢查询
SHOW VARIABLES LIKE 'slow_query%';
SHOW FULL PROCESSLIST;

# 分析表结构
EXPLAIN SELECT * FROM prompts WHERE user_id = 123;

前端调试:

技巧 1:React DevTools

安装 React DevTools 浏览器扩展,可以:

  • 查看组件树
  • 查看组件 Props 和 State
  • 分析组件渲染性能

技巧 2:Redux DevTools(如果使用 Zustand)

虽然 Coze Loop 使用 Zustand,但可以通过中间件连接到 Redux DevTools:

import {
    devtools } from 'zustand/middleware';

export const useStore = create(
  devtools(
    (set) => ({
   
      // your state
    }),
    {
    name: 'CozeLoopStore' }
  )
);

技巧 3:网络请求监控

使用浏览器开发者工具的 Network 面板:

  • Filter by XHR 查看 API 请求
  • 查看请求头、响应体
  • 分析请求耗时

⚠️ 常见陷阱和解决方案

陷阱 1:Goroutine 泄露

现象:系统运行一段时间后内存持续增长

原因:启动的 Goroutine 没有正确退出

示例代码(有问题):

func (s *Service) Start(ctx context.Context) {
   
    go func() {
   
        // 这个 goroutine 没有监听 ctx.Done()
        for {
   
            s.doWork()
            time.Sleep(time.Second)
        }
    }()
}

修复方案:

func (s *Service) Start(ctx context.Context) {
   
    go func() {
   
        ticker := time.NewTicker(time.Second)
        defer ticker.Stop()

        for {
   
            select {
   
            case <-ctx.Done():
                // 正确处理 context 取消
                return
            case <-ticker.C:
                s.doWork()
            }
        }
    }()
}

陷阱 2:数据库连接泄露

现象:一段时间后报错 too many connections

原因:没有正确释放数据库连接

示例代码(有问题):

func (r *Repo) GetByID(ctx context.Context, id int64) (*entity.Prompt, error) {
   
    rows, err := r.db.Query("SELECT * FROM prompts WHERE id = ?", id)
    // 忘记 defer rows.Close()
    // ...
}

修复方案:

func (r *Repo) GetByID(ctx context.Context, id int64) (*entity.Prompt, error) {
   
    rows, err := r.db.Query("SELECT * FROM prompts WHERE id = ?", id)
    if err != nil {
   
        return nil, err
    }
    defer rows.Close()  // 确保释放连接
    // ...
}

更好的方案:使用 GORM

func (r *Repo) GetByID(ctx context.Context, id int64) (*entity.Prompt, error) {
   
    var po po.Prompt
    err := r.db.WithContext(ctx).First(&po, id).Error
    // GORM 会自动管理连接
    return toDomain(&po), err
}

陷阱 3:Context 传递中断

现象:请求超时没有正确传播到下游

原因:创建了新的 context.Background() 而不是传递原有 context

示例代码(有问题):

func (s *Service) ProcessRequest(ctx context.Context) error {
   
    // 错误:创建了新的 context,丢失了超时信息
    go s.asyncTask(context.Background())
}

修复方案:

func (s *Service) ProcessRequest(ctx context.Context) error {
   
    // 正确:传递原有 context 或派生 context
    go s.asyncTask(ctx)
    // 或者
    go s.asyncTask(context.WithoutCancel(ctx))  // Go 1.21+
}

陷阱 4:并发读写 Map

现象:程序偶尔崩溃,报错 concurrent map read and map write

原因:多个 Goroutine 同时读写普通 map

示例代码(有问题):

type Cache struct {
   
    data map[string]string
}

func (c *Cache) Get(key string) string {
   
    return c.data[key]  // 并发读写会 panic
}

修复方案:

import "sync"

type Cache struct {
   
    mu   sync.RWMutex
    data map[string]string
}

func (c *Cache) Get(key string) string {
   
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.data[key]
}

// 或者使用 sync.Map
type Cache struct {
   
    data sync.Map
}

func (c *Cache) Get(key string) (string, bool) {
   
    val, ok := c.data.Load(key)
    if !ok {
   
        return "", false
    }
    return val.(string), true
}

陷阱 5:React 组件无限渲染

现象:页面卡死,控制台报错 Maximum update depth exceeded

原因:在 useEffect 中修改了依赖项,导致无限循环

示例代码(有问题):

function MyComponent({
    data }) {
   
  const [list, setList] = useState([]);

  useEffect(() => {
   
    // 错误:每次渲染都会创建新的对象
    setList(data.map(item => ({
    ...item })));
  }, [data, list]);  // list 作为依赖会导致无限循环
}

修复方案:

function MyComponent({
    data }) {
   
  const [list, setList] = useState([]);

  useEffect(() => {
   
    setList(data.map(item => ({
    ...item })));
  }, [data]);  // 只依赖 data

  // 或者使用 useMemo
  const list = useMemo(() => {
   
    return data.map(item => ({
    ...item }));
  }, [data]);
}

2. 扩展练习建议 📝

以下是一些从易到难的练习题,帮助你巩固所学知识:

🌱 入门级练习(难度:⭐)

练习 1:修改欢迎消息

  • 目标:修改登录后的欢迎消息
  • 涉及文件:前端组件
  • 预计时间:30 分钟
  • 学习要点:熟悉前端代码结构

练习 2:添加日志

  • 目标:在 Prompt 创建时添加详细日志
  • 涉及文件backend/modules/prompt/domain/service/prompt_service.go
  • 预计时间:1 小时
  • 学习要点:理解日志记录规范

练习 3:修改配置项

  • 目标:添加一个新的配置项,控制日志级别
  • 涉及文件backend/conf/infrastructure.yaml
  • 预计时间:1 小时
  • 学习要点:配置管理和环境变量

🌿 进阶级练习(难度:⭐⭐)

练习 4:新增 API 接口

  • 目标:为 Prompt 添加"归档"功能
  • 涉及文件
    • backend/modules/prompt/domain/entity/prompt.go(添加 Archived 字段)
    • backend/modules/prompt/domain/service/prompt_service.go(添加 Archive 方法)
    • backend/api/handler/coze/loop/apis/prompt_manage_service.go(添加 API)
  • 预计时间:半天
  • 学习要点:完整的功能开发流程

练习 5:添加缓存

  • 目标:为 Prompt 查询添加 Redis 缓存
  • 涉及文件backend/modules/prompt/infra/repo/prompt_repo.go
  • 预计时间:1 天
  • 学习要点:缓存策略、缓存失效

练习 6:导出功能

  • 目标:支持将 Prompt 列表导出为 CSV
  • 涉及文件
    • 后端:添加导出接口
    • 前端:添加导出按钮
  • 预计时间:1-2 天
  • 学习要点:文件生成、前后端协作

🌳 高级练习(难度:⭐⭐⭐)

练习 7:实现定时任务

  • 目标:实现一个定时任务,每天清理过期的 Trace 数据
  • 涉及技术
    • 使用 cron
    • 批量删除 ClickHouse 数据
    • 添加监控指标
  • 预计时间:2-3 天
  • 学习要点:定时任务、大数据清理

练习 8:优化查询性能

  • 目标:优化 Prompt 列表查询,支持 10w+ 数据
  • 涉及技术
    • 添加索引
    • 分页优化(游标分页)
    • 查询缓存
  • 预计时间:3-5 天
  • 学习要点:数据库优化、性能调优

练习 9:实现权限控制

  • 目标:实现基于角色的权限控制(RBAC)
  • 涉及技术
    • 设计权限模型
    • 实现权限中间件
    • 前端权限判断
  • 预计时间:1-2 周
  • 学习要点:权限系统设计、中间件模式

3. 参与贡献的途径 🤝

📍 社区位置

官方渠道:

  1. GitHub 仓库https://github.com/coze-dev/coze-loop

    • 主要用于:代码贡献、Bug 报告、功能建议
  2. Discord 社区Coze Community

    • 主要用于:技术讨论、问题求助、社区交流
  3. Telegram 群组Coze

    • 主要用于:即时沟通、快速问答
  4. 飞书群聊(国内用户):扫描 README 中的二维码加入

    • 主要用于:中文技术交流

🐛 如何寻找 Good First Issue

步骤 1:访问 Issues 页面

https://github.com/coze-dev/coze-loop/issues

步骤 2:使用标签筛选

点击 Labels,选择:

  • good first issue:适合新手的问题
  • help wanted:需要社区帮助的问题
  • documentation:文档类问题(最容易上手)

步骤 3:评估 Issue

选择 Issue 时考虑:

  • ✅ 问题描述清晰
  • ✅ 有复现步骤(如果是 Bug)
  • ✅ 涉及的模块你比较熟悉
  • ✅ 预计工作量在 1-3 天

步骤 4:认领 Issue

在 Issue 下评论:

Hi, I'd like to work on this issue. Could you assign it to me?

I plan to:
1. [你的解决方案简述]
2. [预计时间]

Thanks!

📝 代码规范要求

Coze Loop 的代码规范主要参考《阿里巴巴 Go 开发手册》,以下是关键要点:

命名规范:

// ✅ 正确
type UserService struct {
   }
func (s *UserService) GetUser(ctx context.Context, id int64) (*User, error) {
   }

// ❌ 错误
type userservice struct {
   }  // 类型名应该大写
func (s *UserService) get_user(ctx context.Context, id int64) (*User, error) {
   }  // 不应使用下划线

注释规范:

// ✅ 正确:导出的函数/类型必须有注释
// UserService 提供用户相关服务
type UserService struct {
   }

// GetUser 根据 ID 获取用户
func (s *UserService) GetUser(ctx context.Context, id int64) (*User, error) {
   }

// ❌ 错误:缺少注释
type UserService struct {
   }
func (s *UserService) GetUser(ctx context.Context, id int64) (*User, error) {
   }

错误处理:

// ✅ 正确:包装错误并添加上下文
func (s *Service) DoSomething(ctx context.Context) error {
   
    if err := s.repo.Save(ctx); err != nil {
   
        return errorx.Wrap(err, "failed to save data")
    }
    return nil
}

// ❌ 错误:直接返回错误,丢失上下文
func (s *Service) DoSomething(ctx context.Context) error {
   
    return s.repo.Save(ctx)
}

测试规范:

// ✅ 正确:使用表驱动测试
func TestUserService_GetUser(t *testing.T) {
   
    tests := []struct {
   
        name    string
        userID  int64
        want    *User
        wantErr bool
    }{
   
        {
   
            name:    "existing user",
            userID:  123,
            want:    &User{
   ID: 123, Name: "Alice"},
            wantErr: false,
        },
        {
   
            name:    "non-existing user",
            userID:  999,
            want:    nil,
            wantErr: true,
        },
    }

    for _, tt := range tests {
   
        t.Run(tt.name, func(t *testing.T) {
   
            // test logic
        })
    }
}

🚀 提交流程

1. 提交前检查清单

  • [ ] 代码通过所有测试:go test ./...
  • [ ] 代码符合规范:golangci-lint run
  • [ ] 添加了必要的单元测试
  • [ ] 更新了相关文档(如果需要)
  • [ ] Commit 消息符合 Conventional Commits 规范

2. Commit 消息规范

格式:<type>(<scope>): <subject>

类型(type):

  • feat:新功能
  • fix:Bug 修复
  • docs:文档更新
  • style:代码格式(不影响代码运行)
  • refactor:重构
  • test:测试相关
  • chore:构建/工具相关

示例:

# 新功能
git commit -m "feat(prompt): add archive functionality"

# Bug 修复
git commit -m "fix(evaluation): resolve memory leak in concurrent execution"

# 文档更新
git commit -m "docs(readme): update quick start guide"

3. PR 描述模板

## Description
[简要描述这个 PR 的目的]

## Motivation and Context
[为什么需要这个改动?解决了什么问题?]

## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update

## How Has This Been Tested?
[描述测试方法]
- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual tests

## Checklist
- [ ] My code follows the code style of this project
- [ ] I have added tests to cover my changes
- [ ] All new and existing tests passed
- [ ] I have updated the documentation accordingly

第五部分:技术栈学习指引(你的知识地图)🌐

本部分目标:为你提供系统化的技术栈学习路径,构建完整的知识体系。

💡 心法提示:学习技术栈不要贪多求全,先掌握核心,再逐步拓展。

1. 官方文档定位(学习的基石)📖

🎯 后端技术栈文档

Go 语言核心:

技术 官方文档 重点章节 学习优先级
Go 语言 golang.org Tour of Go、Effective Go ⭐⭐⭐⭐⭐
Go Modules Go Modules 依赖管理、版本控制 ⭐⭐⭐⭐
Go Testing Testing Package 单元测试、基准测试 ⭐⭐⭐⭐

CloudWeGo 技术栈:

技术 官方文档 重点章节 学习优先级
Kitex Kitex Docs Getting Started、Thrift IDL ⭐⭐⭐⭐⭐
Hertz Hertz Docs 路由、中间件、请求处理 ⭐⭐⭐⭐
Netpoll Netpoll Docs 网络模型(可选) ⭐⭐

Eino 框架:

技术 官方文档 重点章节 学习优先级
Eino Eino GitHub README、Examples ⭐⭐⭐⭐⭐

数据库相关:

技术 官方文档 重点章节 学习优先级
MySQL MySQL Docs 事务、索引、查询优化 ⭐⭐⭐⭐⭐
GORM GORM Docs CRUD、关联、Hooks ⭐⭐⭐⭐
Redis Redis Docs 数据类型、持久化、集群 ⭐⭐⭐⭐
ClickHouse ClickHouse Docs 表引擎、查询语法 ⭐⭐⭐

消息队列:

技术 官方文档 重点章节 学习优先级
RocketMQ RocketMQ Docs 快速开始、Go Client ⭐⭐⭐

🎨 前端技术栈文档

技术 官方文档 重点章节 学习优先级
React React Docs Hooks、Context、Performance ⭐⭐⭐⭐⭐
TypeScript TypeScript Handbook 类型系统、泛型、工具类型 ⭐⭐⭐⭐⭐
Rsbuild Rsbuild Docs 配置、插件 ⭐⭐⭐
Rush Rush Docs Monorepo 管理 ⭐⭐⭐
Zustand Zustand GitHub 状态管理 ⭐⭐⭐⭐
React Router React Router Docs 路由配置、导航 ⭐⭐⭐⭐
TailwindCSS Tailwind Docs 工具类、配置 ⭐⭐⭐

📚 Coze Loop 自身文档

文档 链接 内容 学习优先级
快速开始 Wiki 部署安装 ⭐⭐⭐⭐⭐
系统架构 Wiki 架构设计 ⭐⭐⭐⭐⭐
代码开发与测试 Wiki 开发指南 ⭐⭐⭐⭐
模型配置 Wiki LLM 配置 ⭐⭐⭐⭐

📖 权威技术书籍

Go 语言:

  1. 《Go 程序设计语言》(The Go Programming Language)

    • 作者:Alan A. A. Donovan, Brian W. Kernighan
    • 适合:Go 初学者
    • 重点:语言基础、并发编程
  2. 《Go 语言实战》(Go in Action)

    • 作者:William Kennedy, Brian Ketelsen, Erik St. Martin
    • 适合:有一定基础的开发者
    • 重点:实战经验、最佳实践
  3. 《Go 语言高级编程》

    • 作者:柴树杉、曹春晖
    • 适合:进阶开发者
    • 重点:CGO、汇编、RPC

架构设计:

  1. 《领域驱动设计》(Domain-Driven Design)

    • 作者:Eric Evans
    • 适合:架构师、技术Lead
    • 重点:DDD 核心概念、战略设计、战术设计
  2. 《实现领域驱动设计》(Implementing Domain-Driven Design)

    • 作者:Vaughn Vernon
    • 适合:想实践 DDD 的开发者
    • 重点:DDD 实践、代码示例
  3. 《微服务架构设计模式》(Microservices Patterns)

    • 作者:Chris Richardson
    • 适合:微服务架构师
    • 重点:微服务拆分、通信模式、数据一致性

代码质量:

  1. 《代码整洁之道》(Clean Code)

    • 作者:Robert C. Martin
    • 适合:所有开发者
    • 重点:命名、函数、注释、测试
  2. 《重构:改善既有代码的设计》(Refactoring)

    • 作者:Martin Fowler
    • 适合:有经验的开发者
    • 重点:重构手法、代码坏味道

2. 学习路径建议(社区智慧)🛤️

📚 技能学习顺序

阶段一:基础扫盲(2-4 周)

第 1 周:Go 语言基础
  ├── Day 1-2:基本语法、数据类型
  ├── Day 3-4:函数、方法、接口
  ├── Day 5-6:Goroutine、Channel
  └── Day 7:Context、错误处理

第 2 周:Web 开发基础
  ├── Day 1-2:HTTP 协议、RESTful API
  ├── Day 3-4:Hertz 框架入门
  ├── Day 5-6:数据库操作(GORM)
  └── Day 7:Redis 基础

第 3 周:前端基础
  ├── Day 1-2:TypeScript 基础
  ├── Day 3-4:React Hooks
  ├── Day 5-6:状态管理(Zustand)
  └── Day 7:路由和导航

第 4 周:综合实战
  ├── Day 1-3:跑通 Coze Loop 项目
  ├── Day 4-5:阅读核心代码
  └── Day 6-7:实现一个小功能

阶段二:深入理解(1-2 个月)

DDD 架构(2 周)
  ├── Week 1:理论学习(阅读《领域驱动设计》前 3 章)
  └── Week 2:实践分析(分析 Coze Loop 的 DDD 实现)

微服务架构(2 周)
  ├── Week 1:CloudWeGo 技术栈(Kitex + Hertz)
  └── Week 2:Thrift IDL、RPC 通信

性能优化(2 周)
  ├── Week 1:Go 性能分析(pprof)
  └── Week 2:数据库优化(索引、查询优化)

阶段三:工程化实践(持续)

测试(2 周)
  ├── Week 1:单元测试(gomock、testify)
  └── Week 2:集成测试、表驱动测试

可观测性(2 周)
  ├── Week 1:日志、指标
  └── Week 2:分布式追踪(OpenTelemetry)

DevOps(2 周)
  ├── Week 1:Docker、Docker Compose
  └── Week 2:Kubernetes、Helm

🎯 核心概念优先级

必须掌握(⭐⭐⭐⭐⭐):

  1. Go 并发编程

    • Goroutine 和 Channel 的使用
    • Context 的传递和取消
    • 常见并发模式(Worker Pool、Pipeline)
  2. DDD 分层架构

    • Application、Domain、Infra 三层职责
    • 依赖倒置原则
    • 仓储模式
  3. HTTP API 设计

    • RESTful 规范
    • 参数校验
    • 错误处理
  4. 数据库事务

    • ACID 特性
    • 事务隔离级别
    • 锁机制

重要掌握(⭐⭐⭐⭐):

  1. Thrift IDL

    • 类型定义
    • 服务定义
    • 代码生成
  2. Redis 应用

    • 缓存策略
    • 分布式锁
    • Pub/Sub
  3. 消息队列

    • 发布-订阅模式
    • 消息幂等性
    • 重试机制
  4. 前端状态管理

    • Zustand 的使用
    • 异步状态处理
    • 状态持久化

选修拓展(⭐⭐⭐):

  1. ClickHouse

    • 列式存储原理
    • 查询优化
    • 数据导入
  2. 性能优化

    • Go 性能分析(pprof)
    • 内存优化
    • 并发控制
  3. 监控告警

    • Prometheus + Grafana
    • 指标设计
    • 告警规则

🏗️ 实践项目推荐

初级项目(熟悉技术栈):

  1. Todo API

  2. 博客系统

    • 技术栈:Go + React + MySQL
    • 学习要点:前后端分离、用户认证
    • 预计时间:1-2 周
    • 参考:Go Blog Example

中级项目(理解架构):

  1. URL 短链服务

    • 技术栈:Go + Redis + MySQL
    • 学习要点:分布式 ID、缓存策略
    • 预计时间:1-2 周
    • 参考:URL Shortener Go
  2. 任务调度系统

    • 技术栈:Go + RocketMQ + MySQL
    • 学习要点:消息队列、异步处理
    • 预计时间:2-3 周
    • 参考:Temporal Workflow

高级项目(深入实践):

  1. Mini Coze Loop
    • 技术栈:完整技术栈
    • 学习要点:DDD 架构、微服务
    • 预计时间:1-2 个月
    • 参考:Coze Loop 本身 😊

3. 工具与环境配置指南 🛠️

💻 开发环境搭建

后端开发环境:

# 1. 安装 Go
# macOS
brew install go@1.24

# Linux
wget https://go.dev/dl/go1.24.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.24.0.linux-amd64.tar.gz

# Windows:从官网下载安装包

# 2. 配置环境变量
export GOPATH=$HOME/go
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

# 3. 配置 Go Proxy(国内用户)
go env -w GOPROXY=https://goproxy.cn,direct

# 4. 安装开发工具
go install golang.org/x/tools/gopls@latest           # LSP
go install github.com/go-delve/delve/cmd/dlv@latest  # 调试器
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest  # Linter

前端开发环境:

# 1. 安装 Node.js
# macOS
brew install node@18

# Linux (使用 nvm)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install 18
nvm use 18

# Windows:从官网下载安装包

# 2. 安装 pnpm 和 Rush
npm install -g pnpm@8.15.8
npm install -g @microsoft/rush@5.147.1

# 3. 进入项目安装依赖
cd frontend
rush update

🔧 IDE 配置

VS Code(推荐):

必装扩展:

  • Go(官方)
  • Docker
  • ESLint
  • Prettier - Code formatter
  • GitLens
  • Error Lens
  • Thunder Client(API 测试)

配置示例(.vscode/settings.json):

{
   
  "go.useLanguageServer": true,
  "go.lintTool": "golangci-lint",
  "go.lintOnSave": "workspace",
  "go.formatTool": "goimports",
  "[go]": {
   
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
   
      "source.organizeImports": true
    }
  },
  "[typescript]": {
   
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  },
  "[typescriptreact]": {
   
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  }
}

GoLand(专业用户):

优势:

  • 更强大的代码补全
  • 内置调试器
  • 更好的重构支持

配置要点:

  1. 启用 Go Modules:Settings → Go → Go Modules
  2. 配置 Linter:Settings → Tools → File Watchers → golangci-lint
  3. 配置测试:Run → Edit Configurations → Go Test

🐳 Docker 和数据库工具

Docker 管理工具:

  • Docker Desktop(Windows/macOS):官方 GUI 工具
  • Lazydocker:终端 UI 工具

    # macOS
    brew install lazydocker
    
    # 使用
    lazydocker
    

数据库客户端:

API 测试工具:

4. 进阶拓展方向 🚀

📝 技术博客与专家观点

CloudWeGo 技术团队:

Go 语言社区:

DDD 和架构设计:

🎤 相关技术大会

国内大会:

  1. GopherChina

  2. QCon

  3. 字节跳动技术沙龙

    • 时间:不定期
    • 内容:CloudWeGo、Eino 等技术分享

国际大会:

  1. GopherCon

    • 时间:每年 11 月
    • 内容:Go 语言前沿技术
  2. KubeCon

    • 时间:每年 3 月、11 月
    • 内容:云原生、Kubernetes

💬 社区与论坛

Coze Loop 官方社区:

Go 语言社区:

架构设计社区:


🎉 结语

恭喜你读到这里!这份学习指南凝聚了 Coze Loop 项目的精华和我的经验总结。希望它能成为你学习路上的好伙伴 🤝

记住这几点:

  1. 学习是一个循序渐进的过程,不要急于求成
  2. 动手实践永远比纸上谈兵更重要
  3. 遇到问题不要害怕,每个 Bug 都是学习机会
  4. 积极参与社区,分享你的经验和困惑
  5. 保持好奇心和学习热情

下一步行动:

  • [ ] ⭐ Star 这个项目:https://github.com/coze-dev/coze-loop
  • [ ] 🚀 按照第三部分的学习路径开始实践
  • [ ] 💬 加入社区,认识更多志同道合的朋友
  • [ ] 🎯 设定一个小目标(如实现一个新功能)
  • [ ] 🤝 提交你的第一个 Pull Request

保持联系:

如果你在学习过程中有任何问题或建议,欢迎:

  • 在 GitHub 上提 Issue
  • 在社区讨论区发帖
  • 在 Discord/Telegram 群组提问

祝你学习愉快,期待在 Coze Loop 社区见到你的贡献!🎊


附录:常用命令速查表 📋

# Docker 常用命令
docker ps                           # 查看运行中的容器
docker logs -f <container>          # 查看容器日志
docker exec -it <container> bash    # 进入容器
docker restart <container>          # 重启容器

# Go 常用命令
go test ./...                       # 运行所有测试
go test -v -run TestName            # 运行特定测试
go test -cover ./...                # 查看测试覆盖率
go mod tidy                         # 整理依赖
golangci-lint run                   # 运行 Linter

# Git 常用命令
git status                          # 查看状态
git add .                           # 添加所有修改
git commit -m "message"             # 提交
git push origin branch-name         # 推送
git fetch upstream                  # 同步上游
git rebase upstream/main            # 变基到最新

# Make 常用命令(Coze Loop 项目)
make compose-up                     # 启动服务
make compose-down                   # 停止服务
make helm-up                        # Helm 部署
make helm-pod                       # 查看 Pod 状态

祝你在 Coze Loop 的学习之旅一帆风顺!🚀💪✨

目录
相关文章
|
11天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
9天前
|
存储 人工智能 搜索推荐
终身学习型智能体
当前人工智能前沿研究的一个重要方向:构建能够自主学习、调用工具、积累经验的小型智能体(Agent)。 我们可以称这种系统为“终身学习型智能体”或“自适应认知代理”。它的设计理念就是: 不靠庞大的内置知识取胜,而是依靠高效的推理能力 + 动态获取知识的能力 + 经验积累机制。
347 130
|
9天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
436 130
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
3天前
|
存储 安全 前端开发
如何将加密和解密函数应用到实际项目中?
如何将加密和解密函数应用到实际项目中?
201 138
|
10天前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
390 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
|
3天前
|
存储 JSON 安全
加密和解密函数的具体实现代码
加密和解密函数的具体实现代码
202 136
|
22天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1361 8
|
8天前
|
监控 JavaScript Java
基于大模型技术的反欺诈知识问答系统
随着互联网与金融科技发展,网络欺诈频发,构建高效反欺诈平台成为迫切需求。本文基于Java、Vue.js、Spring Boot与MySQL技术,设计实现集欺诈识别、宣传教育、用户互动于一体的反欺诈系统,提升公众防范意识,助力企业合规与用户权益保护。