文档目录与内容框架

一、 前言

1.1 本文目标
  • 本指南旨在为需要进行万悟平台(WanwuLite)二次开发的开发者提供一份从本地代码修改、Docker镜像构建、本地功能验证到最终部署发版的完整、一站式的操作手册。

1.2 适用人群
  • 对万悟平台进行定制化开发的软件工程师、运维工程师。

  • 需要了解完整CI/CD流程的开发者。

  • 对Docker、容器化部署感兴趣的初学者。

1.3 环境与前提准备
  • 开发环境: Linux/Mac/Windows WSL2

  • 内存建议:本地开发建议至少32G内存,尤其是Windows系统用户,避免因IDE、Docker等占用导致运行卡顿或异常。

  • 必备工具

    • Git: 用于代码版本管理。

    • Docker & Docker Compose: 用于镜像构建和容器化部署。

    • Go(万悟平台实际技术栈): 本地开发调试环境。

  • 已有资源

    • 万悟平台源代码仓库访问权限。

    • 基础的万悟平台使用知识。


二、代码结构

万悟的后端是采用Golang语言开发的,该项目代码结构采用了标准的Golang项目布局(Standard Go Project Layout),并结合了前后端开发所需的配置,万悟代码结构:

1. 核心目录结构

① /cmd:应用程序入口点,通常包含多个子目录,每个子目录对应一个可执行程序(如 main.go)。

② /internal:私有代码,仅限项目内部使用,不对外暴露。

③ /api :Protocol Buffers 生成的代码文件。

④ /pkg:公共库代码,可被其他项目导入(如数据库、日志、工具函数等)。

⑤ /proto:Protocol Buffers 定义文件。

⑥ /vendor:Go 依赖的本地副本(通过 go mod vendor 生成),用于离线依赖管理。

⑦ /web :前端相关代码(如静态文件、前端框架代码等)。

2. 配置与部署

① /configs:配置文件模板或默认配置(如 YAML、JSON 文件)。

② /bin:编译生成的可执行文件(通常会被 .gitignore 忽略)。

③ Docker 相关文件:docker-compose.yaml 和 docker-compose-develop.yaml :定义多容器服务的开发和生产配置。

④ 环境变量文件:.env、.env.image.amd64、.env.image.arm64:不同环境或架构的配置变量。

3. 依赖与文档

① go.mod 和 go.sum:Go 模块管理文件,明确项目依赖及其版本。

② /docs:项目文档(Swagger/OpenAPI 规范的文档 和 Go 代码生成的 API 文档)。

③ README.md 和 license:项目说明和许可证文件。

4. 其他文件
  • Dockerfile.backend 和 Dockerfile.frontend :分别用于构建后端和前端镜像。

  • Makefile:一个 Go 项目的构建、测试、文档生成和部署流程的工具。

  • Makefile.deploy:一个在开发中对于各服务的控制,便于测试的工具。

5. 核心目录详解

① /cmd

  • 每个微服务对应一个子目录,如 app-service、assistant-service等

  • 每个目录下包含main.go作为服务入口点

  • main.go负责初始化配置、日志、数据库连接,并启动服务

② /internal

  • 按微服务划分目录,如 internal/app-service/

  • 每个服务内部包含 client、config、server 等子包

  • server/grpc/目录包含gRPC服务实现

③ /api与 /proto

  • 包含服务间通信的Protocol Buffers定义

  • 按服务划分目录,如 api/proto/app-service

  • 定义了服务接口和消息格式

④ /pkg

  • 包含公共功能模块,如数据库客户端、日志工具、MinIO客户端等

  • 这些包可被多个微服务引用

  • 遵循Go的包管理最佳实践,只包含可被外部安全使用的代码

6. 核心业务微服务说明

① bff-service:api服务接入服务,业务串联

② iam-service:身份认证服务,多租户管理及访问权限管理

③ model-service:模型管理服务,处理模型的接入和管理

④ rag-service:文本问答服务

⑤ app-service:api key管理、安全护栏敏感词服务

⑥ assistant-service:智能体应用服务

⑦ mcp-service:MCP服务

⑧ operate-service:系统设置管理服务

⑨ knowledge-service:知识库服务

该项目是一个 基于 Go 的微服务系统,具备清晰的目录结构、自动化构建部署流程,便于新功能的扩展。符合Go语言的最佳实践,为后续的开发和维护奠定了良好基础。


三、 获取代码与本地开发

3.1 克隆代码仓库
  • 示例命令:

    git clone <repository_url>
  • 切换至正确的开发分支或Tag:

    git checkout -b dev
3.2 项目结构简介

  • 模型管理: 支持导入 LLM、Embedding 和 Rerank 模型,并进行模型推理。

  • 知识库: 支持创建知识库,进行知识管理,并提供向量检索、全文检索和混合检索等功能。

  • 工具广场: 提供精选推荐的 MCP server,并支持导入自定义 MCP 服务。

  • 安全护栏: 支持创建和管理敏感词表,控制模型反馈结果的安全性。

  • 文本问答: 支持创建和管理文本问答应用,并生成 API 接口。

  • 工作流: 支持创建和管理工作流,并进行调试和发布。

  • 智能体: 支持创建和管理智能体,并进行调试和发布。

  • 应用广场: 提供应用体验和历史应用管理功能。

  • 设置: 支持个人信息修改、组织管理、组织切换和平台配置等功能。

3.3 进行代码修改
  • 我们在第三节会以一个简单的示例为例(如何增加一个平台配置权限)。

  • 强调修改代码时要遵循的规范。

3.4 本地运行与调试
  • 如何在本地启动依赖服务(如数据库、Redis)。

  • 如何运行和调试主程序,确保修改在本地环境是有效的


四、后端二次开发流程示例

  • 二进制构建:通过 Makefile 中的命令构建后端微服务(如bff-service、model-service)的二进制文件,输出至 bin/amd64 目录。

  • 容器替换流程:停止原容器,使用开发镜像(如Golang基础镜像)挂载新二进制并重启服务,实现局部更新。

  • 多服务协同更新:当接口变更涉及多个微服务时,需同步更新相关容器以保证前后端一致性。

接下来我们走一遍二次开发的流程:

4.1 配置权限

以权限功能为例,首先需要明确新功能模块的权限需求,以一级权限为例,我们增加了平台配置权限setting

4.2 创建文件

绑定我们在中间件初始化时定义的权限,并根据规范定义好路径、方法、处理函数

internal/bff-service/server/http/handler/router/v1/setting.go

4.3 注册新的方法

internal/bff-service/server/http/handler/router/v1/router.go

4.4 实现处理函数以及swagger API的定义

internal/bff-service/server/http/handler/v1/setting.go

@Tags:将此接口归类到 "setting" 分组

安全要求:需要 JWT 认证

请求/响应格式:JSON

参数说明:

  • 接收一个 request.CustomTabConfig 结构体作为请求体(如果是get请求则是query格式)

  • 成功时返回 response.Response 格式的响应

路由:POST /custom/tab

到定义swagger这一步时需要和前端讨论定义的方法、路由、结构体对需求的可行性

使用 gin_util.Bind() 将请求体 JSON 绑定到 request.CustomTabConfig 结构体,接着从上下文中获取用户id和组织id,调用 service.UploadCustomTab() 服务层方法,最后使用 gin_util.Response() 统一封装返回

4.5 生成proto代码

根据需求定义proto中的消息格式和服务接口 make pb生成代码

proto/operate-service/operate-service.proto

4.6 service层的实现

service层的实现,调用grpc方法:

internal/bff-service/service/setting.go

4.7 定义数据库

在微服务层定义需要存储的数据库表结构 (internal/operate-service/client/orm/client.go中需要同步在db.AutoMigrate方法中添加数据库表的结构体)

internal/operate-service/client/model/system_custom.go

4.8 server层实现

微服务server层实现,也是实现grpc的方法

internal/operate-service/server/grpc/operate/system_custom.go

4.9 client层接口

IClient接口用于隔离业务逻辑层(如 gRPC 方法实现)与基础设施层(如数据库操作)

internal/operate-service/client/client.go

4.10 数据库操作的实现

internal/operate-service/client/orm/system_custom.go

4.11 注意事项
  • proto消息格式必须为每个字段分配唯一的数字标识符,通常递增。

  • swagger注解中如果是get请求需要是query。

  • 数据库表定义时避免使用 SQL 关键字作为列名,必要时使用反引号或自定义列名。

  • 在微服务client层中返回的错误需要用 toErrStatus方法返回,其中参数需要定义key,server层需要定义code,这些是在proto的 err-code中定义的,主要用于后期如果需要做全局翻译,同步要更新 wanwu-i18n.jsonl文件,并执行 

    make i18n-jsonl
  • 如果是添加新的微服务,需要在 configs/middleware/mysql/initdb.d/init.sql中添加初始化数据库语句,并执行 

    make run-mysql-worker

五、 前端二次开发流程示例

  • 前端构建方式:可通过本地 npm run build 构建,或从开发环境拉取打包后的前端包进行部署。

  • 目录结构管理:构建生成的 dist 目录需重命名为 aibase,并放置于 project/nginx/html 下供Nginx容器使用,替换旧版本并更新Nginx内容。

5.1 进入web目录

5.2 安装依赖

根据情况安装依赖:npm install,如果已有可跳过

5.3 二次开发

根据需求更改前端代码,进行二次开发。

5.4 构建项目

修改完成后准备构建项目:npm run build

5.5 打包并部署测试
 在wanwu/web下更改dist文件夹为aibse: mv dist aibase
 压缩成aibase.tar.gz包: tar -zcvf aibase.tar.gz aibase
 将压缩包移动至project/frontend下: mv aibase.tar.gz /wanwulite/project/frontend
 在wanwu路径下执行解压命令: make -f Makefile.develop unzip-frontend-aibase
 在wanwu路径下执行部署命令: make -f Makefile.develop update-frontend-aibase

六、 本地测试与验证

6.1 使用Docker Compose启动全套服务
  • 启动命令:

     amd64系统执行:
     docker compose --env-file .env --env-file .env.image.amd64 up -d
     arm64系统执行:
     docker compose --env-file .env --env-file .env.image.arm64 up -d
  • 查看日志,确认所有容器健康启动:

    docker ps -a

    注意mysql-workerelasticsearchEXIT状态是正常的。

6.2 构建服务镜像
  • 第四部分为例,我们在后端开发中修改了 bff-serviceoperate-service两个服务。现在对修改过的服务进行镜像构建。

  • 执行命令(以amd64架构为例):

     make build-bff-amd64
     make build-operate-amd64

    此时在 /bin/amd64 文件夹下会出现我们构建好的对应镜像文件

  • 构建好后就可以启停服务进行镜像加载了,执行以下命令后即可:

     make -f Makefile.develop stop-operate
     make -f Makefile.develop stop-bff
     make -f Makefile.develop run-operate
     make -f Makefile.develop run-bff
6.3 功能测试
  • 第三步中修改的功能进行测试。

  • 可以根据需求通过Curl命令或Postman操作步骤,验证API返回是否符合预期。

6.4 问题排查
  • 如果测试失败,如何查看容器日志:

    docker logs -f <container_id>
  • 如何进入容器内部排查:

    docker exec -it <container_id> /bin/bash

七、 构建Docker镜像

前后端及workflow文件夹目录结构要求:

wanwu-workflow文件夹与Dockerflie.frontend文件,需要与wanwu文件夹同级放置,如下图所示:

下面是Dockerflie.frontend文件的内容,如果无法获取相关代码,可以复制下面代码构建文件。

# --- 第一阶段:构建阶段aibase ---
FROM node:14 AS builder-aibase
WORKDIR /app
COPY wanwu/web .

ENV npm_config_registry=https://registry.npmmirror.com
ENV npm_config_unsafe_perm=true

RUN set -euo && npm install
RUN set -euo && npm run build

# --- 第二阶段:构建阶段workflow ---
FROM node:22 AS builder-workflow
WORKDIR /app
COPY wanwu-workflow .

ENV npm_config_registry=https://registry.npmmirror.com

RUN cd /app/frontend && npm install -g @microsoft/rush && rush install && rush update
RUN cd /app/frontend/apps/coze-studio && npm run build

# --- 第三阶段:运行阶段 ---
FROM nginx:1.27

COPY wanwu/configs/middleware/nginx/conf.d /etc/nginx/conf.d

COPY --from=builder-aibase /app/dist /usr/share/nginx/html/aibase

COPY --from=builder-workflow /app/frontend/apps/coze-studio/dist /usr/share/nginx/html/workflow

CMD ["nginx", "-g", "daemon off;"]

特别强调: 注意构建镜像的平台.env文件中的版本参数与架构信息),避免在AMD64机器上构建出ARM64的镜像,反之亦然。

  • 其中部分镜像打包先 ->后顺序:workflow -> backend -> frontend

7.1 workflow镜像构建命令

① 进入 /wanwu-workflow文件夹下切换到当前开发分支,git pull 拉取最新代码

② 进入 /wanwu-backend文件夹执行 make init ,生成新的vendor,然后返回上一层

③ 打包镜像:在Makefile中查找相关命令,执行:

 make -f Makefile.wanwu docker-image-backend
7.2 后端镜像构建命令详解

① 切换到当前开发分支,git pull 拉取最新代码,执行 make init ,生成新的vendor。

② 查看.env文件版本并更新,执行:

 vimdiff .env .env.bak

③ 打后端镜像,执行:

 make docker-image-backend
7.3 前端镜像构建命令详解
  • 注意:需要先进行workflow与后端发版,再根据后端打出的镜像号命名前端镜像!

  • 流程示例:以21机器上wanwuwanwu-workflow仓库中arm64版本的frontend为例

① 确认wanwu与wanwu-workflow切到开发分支,均git pull 拉取最新代码,执行 make init 之后。

② 查看.env文件版本并更新,执行:

 vimdiff .env .env.bak
  1. 确认wanwu文件夹与wanwu-workflow文件夹在/a2pp文件夹下处于同一层级

  2. 打前端镜像,切换至/a2pp文件夹下,执行:

    docker build -f Dockerfile.frontend -t wanwulite/frontend:Tag信息 .
7.4 rag镜像构建命令详解

① 在 /wanwu 文件夹下,切换到当前开发分支,git pull 拉取最新代码,执行 make init ,生成新的vendor。

② 查看.env文件版本并更新,执行:

 vimdiff .env .env.bak

③ 打rag镜像,执行:

make docker-image-rag
7.5 agent镜像构建命令详解

① 在 /wanwu 文件夹下,切换到当前开发分支,git pull 拉取最新代码,执行 make init ,生成新的vendor。

② 查看.env文件版本并更新,执行:

 vimdiff .env .env.bak

③ 打agent镜像,执行:

make docker-image-agent
 7.6 callback镜像构建命令详解

① 在 /wanwu 文件夹下,切换到当前开发分支,git pull 拉取最新代码,执行 make init ,生成新的vendor。

② 查看.env文件版本并更新,执行:

 vimdiff .env .env.bak

③ 打callback镜像,执行:

make docker-image-callback
7.7 base镜像构建命令详解

base镜像包含4种:workflow-base、rag-base、callback-base、agent-base(v0.3.0后已舍弃)

① workflow-base:

 # 进入 workflow 目录
 cd wanwu-workflow
 ​
 # 切换到开发分支并更新代码
 git checkout dev
 git pull
 ​
 # 更新环境变量版本(对比并更新.env文件)
 cd wanwu-backend
 vimdiff .env .env.bak
 ​
 # 生成 vendor
 cd wanwu-backend && make init && cd ..
 ​
 # 构建 workflow-base 镜像(在 /a2pp/workflow-wanwu 目录下执行)
 make -f Makefile.wanwu docker-image-backend-base
 ​
 # 同步修改Dockerfile.wanwu-backend里面的基础依赖base镜像名称
 vim Dockerfile.wanwu-backend

② callback-base:

 # 切换到开发分支
 git checkout dev
 git pull
 ​
 # 更新环境变量版本(对比并更新.env文件)
 vimdiff .env .env.bak
 ​
 # 构建callback-base镜像(在 /a2pp/wanwu 目录下执行)
 make docker-image-callback-base
 ​
 # 同步修改Dockerfile.callback里面的基础依赖base镜像名称
 vim Dockerfile.callback
7.8 验证镜像
  • 查看镜像是否构建成功:

    docker images
  • 记得同样更改 .env.image.amd64 和 .env.image.arm64 中前端、后端、workflow、rag、callback以及相关base镜像信息

7.9 注意事项
  • 发版完成后,通过命令重启前端,执行:

make -f Makefile.develop stop-nginx
make -f Makefile.develop run-nginx 
7.10 特殊情况

如果用户只需要更新前端镜像,而不修改后端镜像的话,镜像Tag可以自定义,或者还是与当前后端的对齐,版本号建议修改一下,以便与之前正式版本区别开。


八、打Tag与推送至镜像仓库

8.1 为镜像打上版本Tag
  • 命令示例:

    docker tag wanwulite-backend:custom your-registry.com/your-project/wanwulite-backend:v1.1.0-custom
8.2 登录私有镜像仓库
  • 命令示例:

    docker login your-registry.com
8.3 推送镜像
  • 按照云上的推送镜像命令操作即可,命令示例:

    docker push your-registry.com/your-project/wanwulite-backend:v1.1.0-custom
8.4 推送示例

示例:安全起见,以一个当前版本已经弃用的agentscope镜像从打tag到推送到阿里云镜像仓库为例

  • 通过docker images 获取agentscope的镜像号

  • 控制台登录阿里云,执行命令:

    docker login --username=账户名称 crpi-6pxxxxxxxs8.cn-hangzhou.personal.cr.aliyuncs.com
  • 对镜像添加tag信息,执行命令:

    docker tag [镜像ID] crpi-6pxxxxxxxxs8.cn-hangzhou.personal.cr.aliyuncs.com/wanwulite/[镜像名称]:[Tag信息]-[架构]
     例如: docker tag a127a417d5fa crpi-6pjxxxxxxxxexs8.cn-hangzhou.personal.cr.aliyuncs.com/wanwulite/agentscope:v0.1.0-9f2a8b2f-arm64

    添加好后,此时执行docker images会出现两个Tag不同的agentscope,如下图

    注意它们的IMAGE ID和SIZE必须一模一样

  • 推送带有架构信息TAG的镜像到阿里云,执行:

    docker push crpi-6pxxxxxxxxs8.cn-hangzhou.personal.cr.aliyuncs.com/wanwulite/agentscope:[镜像版本号]
  • 在arm64和amd64均推送对应架构信息的TAG到阿里云之后执行下面命令生成manifest

    docker manifest create crpi-6pxxxxxxxxs8.cn-hangzhou.personal.cr.aliyuncs.com/wanwulite/agentscope:v0.1.0-9f2a8b2f \
      crpi-6pxxxxxxxxs8.cn-hangzhou.personal.cr.aliyuncs.com/wanwulite/agentscope:v0.1.0-9f2a8b2f-arm64 \
      crpi-6pxxxxxxxxs8.cn-hangzhou.personal.cr.aliyuncs.com/wanwulite/agentscope:v0.1.0-9f2a8b2f-amd64
  • 执行成功后把新建的manifest推送到阿里云上

    docker manifest push crpi-6pxxxxxxxxs8.cn-hangzhou.personal.cr.aliyuncs.com/wanwulite/agentscope:v0.1.0-9f2a8b2f

    此时阿里云上会出现一个多架构的agentscope镜像,如下图,它的镜像大小应与两种架构中的一个相同。

8.5 更新镜像信息

确认.env.image.amd64以及.env.image.arm64中的agentscope的Tag信息已更新并且完全相同,且不带架构信息。然后提merge请求

到开发分支


九、部署上线(发版)

9.1 部署环境准备
  • 确保目标服务器已安装Docker。

  • 确保服务器能访问私有镜像仓库。

9.2 更新部署配置
  • 修改生产环境的 .env.image.amd64.env.image.arm64 文件中的镜像标签,将其指向第八步推送的新镜像。

9.3 执行部署操作
  • Docker Compose 方式

    • 关闭旧服务

      # amd64系统执行:
       docker compose --env-file .env --env-file .env.image.amd64 down
      # arm64系统执行:
       docker compose --env-file .env --env-file .env.image.arm64 down
    • 拉取新镜像并重新启动服务

      # amd64系统执行:
       docker compose --env-file .env --env-file .env.image.amd64 up -d
      # arm64系统执行:
       docker compose --env-file .env --env-file .env.image.arm64 up -d
    • 重启nginx,以便后续前端代码部署

      make -f Makefile.deploy stop-nginx
      make -f Makefile.deploy run-nginx

十、 第六阶段:线上验证与监控

10.1 验证部署结果
  • 再次执行第四阶段和第五阶段修改的功能测试,确保线上环境生效。

10.2 监控与观察
  • 查看应用日志,确保无异常错误。

  • 观察监控仪表盘(如CPU、内存、请求量、错误率)。


十一、 常见问题排查(Q&A)

  • Q1: docker build 失败,提示某些依赖下载不了?

  • A1: 切换至科学上网环境,镜像过大可能会下载时间过久

  • Q2: docker: no such file or directory 错误?

  • A2: 镜像平台与运行平台不匹配,非常常见!

  • Q3: 本地测试成功,但部署后无法访问?

  • A3: 检查网络、防火墙、端口映射

  • Q4: 如何回滚到上一个版本?

  • A4: 将.env配置中的镜像Tag改回旧版本,重新部署

  • 更多问题详见README中的Q&A


十二、 总结与最佳实践

12.1 流程总结

我们用一张流程图再次梳理 代码 -> 构建 -> 测试 -> 推送 -> 部署 -> 再测试 的完整闭环。

12.2 最佳实践建议
  • 版本化: 每次构建都使用唯一的Tag(如Git Commit ID)。

  • 安全: 使用.dockerignore文件,避免将敏感信息打入镜像。

  • 不可变基础设施: 始终坚持部署通过验证的镜像Tag,而非在运行中的容器内直接修改代码或配置。任何更改都应通过重新构建和部署新镜像来完成。

  • 文档更新: 若二次开发引入了新的配置项或依赖,建议同步更新项目文档

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐