华为云码道 CodeArts 实战:AI 智能体独立开发一个多平台内容分发管理台(架构设计 + 开发实录)

举报
行者·全栈架构师 发表于 2026/09/20 09:41:55 2026/09/20
【摘要】 我用 CodeArts 代码智能体独立开发了一个全栈 Web 应用「ArticlePilot 多平台内容分发管理台」,解决技术创作者同一篇文章要发多个平台、格式与发布状态全靠人肉维护的问题。文章完整记录选题背景、架构设计(平台适配器模式 + 稿件状态机 + RBAC)、AI 辅助开发的实操流程、功能演示与踩坑记录,源码已在 AtomGit 开源。

摘要:本文是华为云码道 AI 编程挑战赛的参赛实测记录。我用 CodeArts 代码智能体独立开发了一个全栈 Web 应用「ArticlePilot 多平台内容分发管理台」,解决技术创作者同一篇文章要发多个平台、格式与发布状态全靠人肉维护的问题。文章完整记录选题背景、架构设计(平台适配器模式 + 稿件状态机 + RBAC)、AI 辅助开发的实操流程、功能演示与踩坑记录,源码已在 AtomGit 开源。

技术栈版本:码道 CodeArts 代码智能体(2026-09 挑战赛版本)| Spring Boot 3.5.x | Java 21 | Vue 3.5 + TypeScript | MySQL 8 | Docker Compose | 实测时间: 2026-09

001-agent-adapter-codearts.png

一、项目背景:一个真实的多平台发布痛点

先交代我为什么要做这个项目。作为一名技术博主,我的工作流是这样的:一篇文章写完后,要发布到 CSDN、51CTO、腾讯云、阿里云、华为云、掘金、微信公众号等多个平台。每个平台的标签体系不同、封面尺寸不同、摘要字数限制不同、发布状态也各不相同。

在此之前,这套流程全靠 Excel 表格和本地文件夹人肉维护。哪篇稿子发到了哪个平台、哪个平台被拒稿了、哪个平台的标签还没适配,全靠记忆和翻记录。稿子一多,这套管理方式立刻崩坏——漏发、错发、状态对不上是常态。

所以这次参加华为云码道 AI 编程挑战赛,我决定不做一个"演示型"作品,而是直接把这条真实工作流工具化:做一个多平台内容分发管理台,让选题、稿件、平台适配、发布状态在一个地方闭环。这个选题有个额外好处:开发过程中遇到的每一个痛点,都是我真实经历过的,文章里不需要编任何故事。

1.1 作品功能一览

模块 功能
用户与权限 JWT 登录、管理员/作者/访客三角色 RBAC
选题库 选题增删改查、状态流转(IDEA → PLANNED → WRITING → ARCHIVED)
稿件管理 Markdown 编辑预览、乐观锁、版本快照、稿件状态机
平台适配 七大平台适配器、适配字段校验、token 加密存储
发布追踪 发布计划管理、状态看板、统计概览

技术栈:Vue 3 + TypeScript + Element Plus + Pinia(前端),Spring Boot 3 + MyBatis-Plus + Spring Security + MySQL 8(后端),Docker Compose 一键部署。

二、架构设计:三个核心决策

在动手让 AI 生成代码之前,我先把架构决策想清楚了——这一步很重要,AI 智能体擅长执行明确的架构约束,但不擅长替你做架构决策。评审维度里架构设计占 30%,这部分必须在投喂话术之前由人定好。

2.1 决策一:平台适配用适配器模式

多平台分发的核心复杂度在于:每个平台的发布要求都不一样。CSDN 要求 1~10 个标签,掘金必须传封面和摘要,公众号要求作者和 120 字以内的摘要。如果把每个平台的校验逻辑 if-else 地写死在业务代码里,每接入一个新平台就要改一遍核心流程。

所以我在设计上把它抽象成 PlatformAdapter 接口,每个平台一个实现类,通过 Spring 的依赖注入自动收集成注册表。新增平台 = 新增一个实现类,核心流程零改动。

动手前我把三个候选方案摆在一起比过:

方案 新增平台成本 校验逻辑内聚性 结论
if-else / switch 按平台码分支 改核心流程,回归风险大 校验散落各分支 否决,违反开闭原则
配置化(平台规则存表驱动校验) 不改代码,只加配置 复杂校验(如标签数量区间)表达不了,要写大量特判 否决,规则复杂后配置本身变成代码
适配器模式 新增一个实现类 校验、组装逻辑收敛在各自类里 ✅ 采用
// src/main/java/com/articlepilot/adapter/PlatformAdapter.java
/**
 * 平台适配器接口。新增平台只需新增实现类,Spring 自动收集注入 PlatformAdapterRegistry —— 开放扩展原则。
 */
public interface PlatformAdapter {

    String platformCode();

    Set<String> requiredFields();

    ValidationResult validate(PublishDraft draft);

    PublishPlanData buildPlan(PublishDraft draft);
}

以 CSDN 适配器为例,校验规则精确到字段与原因(标签 1~10 个、标题 ≤100 字):

// src/main/java/com/articlepilot/adapter/impl/CsdnAdapter.java(节选)
@Component
@RequiredArgsConstructor
public class CsdnAdapter implements PlatformAdapter {

    @Override
    public String platformCode() {
        return "CSDN";
    }

    @Override
    public Set<String> requiredFields() {
        return Set.of("title", "contentMd", "tags");
    }

    @Override
    public ValidationResult validate(PublishDraft d) {
        if (d.getTitle() == null || d.getTitle().isBlank()) {
            return ValidationResult.fail("title 不能为空");
        }
        if (d.getTitle().length() > 100) {
            return ValidationResult.fail("title 长度不能超过 100");
        }
        int tagCount = d.getTags() == null ? 0 : d.getTags().size();
        if (tagCount < 1) {
            return ValidationResult.fail("tags 至少 1 个");
        }
        if (tagCount > 10) {
            return ValidationResult.fail("tags 最多 10 个");
        }
        return ValidationResult.ok();
    }
    // buildPlan(...) 略:组装发布计划并序列化为 JSON 落库
}

001-articlepilot-codearts-ai-fullstack-development_diagram_1.png

适配器模式的收益在代码上体现为两个"零":核心发布流程对接新平台的改动量为零,平台校验规则的维护彼此干扰为零。这个设计也是本文后面单元测试的落点——每个适配器都能独立测。

2.2 决策二:状态流转用集中式状态机

选题和稿件都有生命周期,如果任由前端"想改成什么状态就改成什么状态",脏数据迟早泛滥(比如把一个还停在 IDEA 的选题直接改成已发布)。所以我把合法流转表集中定义在 Service 层,非法流转直接拒绝并说明当前状态与目标状态。

状态校验的落点也考虑过两个位置:

方案 一致性 测试难度 结论
前端路由守卫拦截 只约束本前端,绕过前端直接调 API 就穿透 无法单测 否决,只能当体验优化
注解/AOP 式声明校验 分散在各切面,流转规则不直观 可测但调试链路长 否决,过度设计
集中式状态机类(纯静态方法) 全局唯一流转表 纯函数,单测最简单 ✅ 采用

001-articlepilot-codearts-ai-fullstack-development_diagram_2.png

稿件状态机保证了一个不变量:只有 READY 状态的稿件才能创建发布计划。这条约束在前端 UI 上也有对应(流转按钮只展示合法目标状态),但真正的防线在后端——前端约束只是体验优化,不能当安全边界。

流转表在 Service 层只有一份,非法流转直接抛业务异常,错误信息带上传入的两个状态:

// src/main/java/com/articlepilot/service/article/ArticleStatusMachine.java(节选)
public final class ArticleStatusMachine {

    public static final int INVALID_TRANSITION_CODE = 1006;

    private static final Map<ArticleStatus, Set<ArticleStatus>> ALLOWED =
            new EnumMap<>(ArticleStatus.class);

    static {
        ALLOWED.put(ArticleStatus.DRAFT, Set.of(ArticleStatus.IN_REVIEW, ArticleStatus.ARCHIVED));
        ALLOWED.put(ArticleStatus.IN_REVIEW, Set.of(ArticleStatus.READY, ArticleStatus.ARCHIVED));
        ALLOWED.put(ArticleStatus.READY, Set.of(ArticleStatus.PUBLISHED, ArticleStatus.ARCHIVED));
        ALLOWED.put(ArticleStatus.PUBLISHED, Set.of(ArticleStatus.ARCHIVED));
        ALLOWED.put(ArticleStatus.ARCHIVED, Set.of());
    }

    public static void validateTransition(ArticleStatus from, ArticleStatus to) {
        Set<ArticleStatus> targets = ALLOWED.getOrDefault(from, Set.of());
        if (!targets.contains(to)) {
            throw new BusinessException(
                    INVALID_TRANSITION_CODE,
                    "稿件状态非法流转: " + from + " → " + to);
        }
    }
}

2.3 决策三:安全边界前置到设计

AI 生成的代码在业务逻辑上表现不错,但安全细节需要人主动提出约束,否则它会给你"能跑但不安全"的默认实现。本项目在设计阶段就定下四条安全红线,贯穿全部开发过程。其中密钥管理在"环境变量注入"和"配置文件加密(Jasypt)"之间权衡过:后者对单机部署更省事,但密文的主密钥还是得落 somewhere,等于把问题往后挪了一层;环境变量 + .env.example 模板在 Docker Compose 场景下零额外依赖,最终选了前者。四条红线如下:

红线 实现
密钥不入库 JWT_SECRET、数据库密码、加密密钥全部环境变量注入
token 不泄露 平台 token AES/GCM 加密落库,接口只返回掩码(sk-****ab12)
越权有防线 @PreAuthorize 接口级鉴权 + Service 层数据归属校验,双层防线
注入有防护 持久层全部走 MyBatis-Plus Wrapper 预编译,排序字段白名单

三、用 CodeArts 开发:我的实操流程

3.1 开发前的准备

在打开 CodeArts 之前,我做了三件"人肉"准备工作:在 AtomGit 创建公开仓库并放好 LICENSE、README 骨架和 .gitignore。

同时把架构决策(2.1~2.3)整理成带验收标准的投喂话术,并规划好七天的开发里程碑(D1 骨架 → D2 认证 → D3 稿件 → D4 适配器 → D5 收口 → D6 文章 → D7 投稿)。

这里分享一个最重要的使用心得:一次只投一个话术块,验收通过再投下一个。AI 在明确的小范围约束下表现非常稳定,但让它一次性"把整个系统写出来"时,质量会明显失控。

我给每个话术块都写死了目录结构、接口签名和验收标准(如 curl 实测场景、mvn test 全绿),AI 的任务是在约束内高质量实现,而不是自由发挥。

001-agent-generate-backend-skeleton.png
开发现场:AtomCode Agent 工作台,articlepilot 仓库已建立代码库索引,Agent 基于索引读写工程文件

001-agent-jwt-filter-output.png

Agent 会话列表:2 个会话贯穿 D1-D5 的全部话术投喂与验收往返,本身就是一份开发日志

3.2 一个典型话术块长什么样

以 D4 的平台适配器话术为例(节选),可以看到我把"硬性要求"和"验收动作"都写在了投喂内容里:

实现多平台适配器体系,要求:

1. 定义接口 PlatformAdapter:platformCode() / requiredFields() /
   validate(PublishDraft) / buildPlan(PublishDraft);
2. 所有实现通过 Spring 注入收集为 Map<platformCode, adapter>,
   新增平台只需新增实现类,不改核心流程;
3. 本期实现 CsdnAdapter、JuejinAdapter、WechatMpAdapter 三个适配器,
   校验规则各不相同,失败信息要具体到字段与原因;
4. 完成后 mvn test 报告结果,单元测试覆盖每个适配器的合法/非法用例。

AI 对这类结构化约束的执行质量很高——三个适配器一次生成即通过编译,校验逻辑与话术要求完全一致。真正需要我介入修正的,反而是话术没写到的细节,下一章的踩坑记录会具体展开。

001-agent-adapter-mvn-test-green.png

D4 适配器话术投喂后的会话现场:Agent 按约束生成三个适配器并回报 mvn test 结果

四、功能演示:从选题到发布追踪的完整闭环

项目完成后,我用 docker compose up -d --build 一条命令拉起整站(MySQL + 后端 + nginx 托管的前端),浏览器访问 8081 端口完成以下全链路验证。

4.1 登录与三角色权限

本地起服务只需两步:IDEA 里 Debug 启动 ArticlePilotApplication(后端 8081),前端目录执行 yarn dev 起 Vite 调试服务(5173)。之后使用预置的三个测试账号(管理员/作者/访客)分别登录,验证 RBAC 生效:作者看不到用户管理入口,访客对看板以外的写操作被后端 403 拦截,越权请求返回统一的错误格式而非堆栈。

001-login-page.png
后端启动:IDEA 以 Debug 方式运行 ArticlePilotApplication,可直接断点排查请求链路
001-publish-front-yarn-dev.png

前端启动:yarn dev 后 Vite 不到 1 秒即就绪(ready in 482 ms),本地调试地址

001-main-interface.png

登录页:admin / author / guest 三个测试账号直接列在页面下方,点「填入」免输入即可体验三种角色

4.2 选题库与稿件管理

新建选题后按状态机流转(IDEA → PLANNED → WRITING),再关联创建稿件。稿件侧支持编辑与版本快照,两个账号并发编辑同一稿件时,后者会收到"已被他人修改"的 409 提示,乐观锁生效。
001-topic-library-list.png

选题库列表:按状态筛选,每条选题带摘要与来源(用户征稿/热点事件/自发),标题即后续稿件的雏形

001-manuscript-list.png

稿件管理:DRAFT / IN_REVIEW / PUBLISHED / ARCHIVED 各状态稿件同屏可见,状态机流转的结果一目了然

4.3 平台适配与发布追踪

稿件流转到 READY 后,为它逐平台填写适配字段(表单项按适配器 requiredFields 动态渲染),提交发布计划。缺封面、摘要超长这类校验错误会精确提示到字段。发布计划状态更新为已发布并填入链接后,追踪看板的统计卡片实时同步。

发布计划自身的生命周期也是一台状态机,与稿件状态机的区别在于它多出 FAILED 和 CANCELLED 两个"异常出口"——发布动作可能因平台校验失败而失败,也可能被作者主动取消:
001-articlepilot-codearts-ai-fullstack-development_diagram_3.png

稿件状态机(§2.2)管"这篇稿子能不能发",发布计划状态机管"发到这个平台的动作结果如何"——两台状态机通过"只有 READY 稿件才能创建 PENDING 计划"这条不变量衔接。
001-tracking-board.png

发布追踪:每篇稿件一张卡片,卡片上按平台展示状态徽标(CSDN/JUEJIN/WECHAT_MP/TENCENT_CLOUD…),哪个平台发过、哪个平台还没发一眼可辨
001-workbench-dashboard.png

工作台首页:素材库累计稿件、选题总数、近 7 天新增趋势与选题/文章状态分布图,创作管道的健康度尽收一屏

001-platform-config-page.png

平台配置页:各平台 Token 以掩码形式回显(对应 §2.3 安全红线),待配置的平台显示「去配置」入口

平台 token 的安全展示在配置页完成:保存时 AES/GCM 加密落库,页面只回显末 4 位掩码(对应 §2.3 的安全红线与 §5.3 的踩坑修复)。

4.4 接口文档

后端集成 springdoc-openapi,全部接口可在 Swagger 页面浏览与调试,统一返回体结构一目了然。
001-swagger-api-docs.png

Swagger 首页(OAS 3.0):Admin-User / Article / Topic 等按 Controller 分组,接口支持在页面直接调试,稿件更新接口标注了乐观锁 409 语义
001-swagger-api-docs-2.png

接口分组一览:Auth / Dashboard / Health / Manuscript / PlatformConfig(标注 token 加密存储、掩码返回)/ PublishPlan / Topic,统一返回体结构在每个接口的 Schema 中可见

五、踩坑记录:AI 写对了九成,剩下一成靠人

如实记录开发过程中真实遇到的问题。AI 智能体大幅提效是事实,但"生成的代码能编译通过"和"能正确运行"之间的缝隙,仍然需要人填。

5.1 JWT 过滤器链顺序不对,登录后所有请求 401

现象:登录接口正常返回 token,但带着 token 访问任何业务接口都是 401。

根因:AI 生成的 SecurityConfig 中,自定义 JwtAuthenticationFilter 注册的位置不对——被加在了默认过滤器链之后,请求到达它之前就已经被认证逻辑拒掉了。

修复:显式指定过滤器插入位置,把 JwtAuthenticationFilter 挂到 UsernamePasswordAuthenticationFilter 之前,重新验证三角色场景后恢复正常。这个问题 AI 两次修改才修对,第二次我按"先定位根因再动手"的纪律要求它先解释过滤器链的执行顺序,确认理解一致后一次修复。修复后的关键配置如下:

// src/main/java/com/articlepilot/config/SecurityConfig.java(节选)
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                    .requestMatchers(PUBLIC_PATHS).permitAll()
                    .anyRequest().authenticated()
            )
            .exceptionHandling(eh -> eh
                    .authenticationEntryPoint((request, response, authException) ->
                            writeJson(response, 401, "未认证或令牌已失效"))
                    .accessDeniedHandler((request, response, accessDeniedException) ->
                            writeJson(response, 403, "无权访问该接口"))
            )
            // 坑一的修复点:自定义过滤器必须挂在用户名密码过滤器之前,
            // 否则请求先被默认认证逻辑拒掉,永远到不了 JWT 解析
            .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
                    UsernamePasswordAuthenticationFilter.class)
            .formLogin(form -> form.disable())
            .httpBasic(basic -> basic.disable());
    return http.build();
}

001-bug1-401-security-config.png

坑一现场:401 问题在 Agent 会话中往返定位,Agent 先解释过滤器链执行顺序再动手修复

5.2 数据库增量 SQL 没生效,新接口集体报表不存在

现象:D3 之后新增的选题、稿件接口全部报"Table doesn’t exist",但 SQL 文明明明提交了。

根因:MySQL 容器挂载的初始化脚本只在 volume 首次创建时执行,后续追加的 migration 文件对已经在运行的库不会自动生效。

修复:两个动作——对运行中的库手动应用增量 SQL;同时把所有建表语句加固为幂等写法(CREATE TABLE IF NOT EXISTS),并验证 docker compose down -v 全新重建后所有表自动创建。这个坑的教训是:容器化项目里,“文件在仓库里"不等于"在数据库里”。

001-bug2-table-not-exist.png

坑二现场:“Table doesn’t exist” 的根因分析与幂等加固方案都在会话中留痕

5.3 AI 默认实现的 token 返回,把加密后的密文原样吐给了前端

现象:安全自查时发现,平台配置接口返回的 token 字段虽然是密文,但密文本身完整返回了——加密等于白做。

根因:话术里写了"AES 加密落库",但没写死"接口返回掩码",AI 按它自己的默认理解实现了。

修复:补充掩码规则(仅展示末 4 位),并在 DTO 层切断 entity 直出。这次踩坑让我把投喂话术的纪律升级了一条:安全要求必须写成可验收的明确规则,不能只给方向。
001-bug3-token-mask-compare.png

坑三现场:安全自查发现密文直出后在会话中补充掩码规则并切断 entity 直出

5.4 小结

三个坑的共同点是:AI 的失误都发生在"话术没约束到的地方",没有一个坑是因为 AI 写不好"话术约束到的代码"。这印证了我的使用策略——架构决策、安全规则、验收标准由人写死,AI 在约束内高效执行,这个分工下的协作质量最高。

补一句质量收口的实测数据(mvn verify 本地实测,JaCoCo 0.8.12):

  • 后端单元测试 9 个测试类、123 个用例,全部通过、0 失败;
  • 核心业务包行覆盖率:状态机(service.article / service.topic)100%,平台适配注册表(adapter)88%;
  • 全项目整体行覆盖率约 14%——这个数字不高,如实说明原因:Controller、DTO、Entity 层未纳入单测范围(Controller 靠 docs/smoke-test.md 的全链路冒烟兜底),单测火力集中在业务逻辑与安全组件上。

001-jacoco-coverage-report.png

mvn verify 生成的 JaCoCo 报告(target/site/jacoco):service.article / service.topic 状态机包 100%,adapter 88%,common 49%,Total 14%——与上文数字一致,未覆盖部分主要是 Controller/DTO/Entity 层

六、提效数据:AI 辅助开发到底快了多少

如实给出本次开发的提效记录(基于开发日志的实际耗时统计,为个人单项目样本,仅供参考,不构成普适结论)。

开发阶段 纯手写预估 AI 辅助实际 提效来源
前后端项目骨架 + Docker 部署 约 2 天 约 2.5 小时 脚手架/配置类工作收益最大
JWT 认证 + RBAC 约 1.5 天 约 3 小时 模板化安全代码,人负责验收
选题/稿件模块 + 状态机 约 2.5 天 约 5 小时 CRUD 由 AI 生成,状态机测试人工把关
平台适配器体系 约 1 天 约 2.5 小时 设计已定,实现即翻译
质量收口(安全自查/补测试/README) 约 1 天 约 4 小时 自查清单执行快,修复靠人

001-dev-log-session-list.png

AtomGit 个人工作台:articlepilot 与其他在维项目并列,Agent 会话记录即开发日志的原始凭证

两点如实说明:一是上表"纯手写预估"基于我以往同类项目的经验估算,存在主观误差;二是提效并非免费的——验收环节(curl 实测、点页面、看测试报告)的耗时包含在内,这部分是 AI 替代不了的人工成本。综合感受:整体工期压缩到传统方式的四分之一左右,且代码质量的下限反而更稳(约束写死的情况下)。

七、开源地址与运行方式

项目已开源,包含可运行源代码、README(作品介绍)与开源协议:

本地运行只需三步(依赖 Docker):
image.png

仓库内附 docs/architecture.md(架构设计文档)、docs/testing.md(测试清单与覆盖率)、docs/smoke-test.md(全链路冒烟记录),按 README 从零环境一次跑通是投稿前的验收门槛。项目采用 Apache-2.0 协议开源,欢迎参考与反馈。

八、总结与平台使用建议

8.1 结论

回到开头的问题:AI 智能体能不能独立完成一个全栈应用?这次实测的答案是——在"人定架构与验收、AI 做实现"的分工下,可以,且提效显著。

三个核心设计(适配器模式、集中状态机、安全红线前置)全部由人预先决策,AI 在这套约束内完成了约九成的代码量。评审关注的架构清晰度、测试覆盖、安全合规,恰恰是靠"投喂前的人肉准备"保住的,而不是靠 AI 自觉。

8.2 给平台的建议

一周深度使用下来,对 CodeArts 代码智能体的几点优化建议(如实反馈,供官方参考):

  1. 多文件改动的事务感:一次话术涉及十几个文件时,中途失败会留下半成品状态,希望提供"本轮改动整体回滚"的操作;
  2. 安全默认值:建议对密钥硬编码、SQL 拼接这类问题在生成时就主动告警,而不是依赖开发者话术约束;
  3. 长会话上下文:跨天开发时,前一天的架构约束需要重新投喂,若能持久化项目级约定会省不少重复工作。

8.3 写在最后

这次参赛对我而言最大的收获不是这个管理台本身,而是验证了一套可复制的 AI 协作工作流:架构决策人做、约束写进话术、每块验收兜底。

这套方法已经整理成完整的执行手册,后续我会在专栏中展开。如果你也在参加本期华为云码道 AI 编程挑战赛,欢迎在评论区交流投喂话术的写法与踩坑经验。

觉得有用就点个赞,有疑问或不同看法欢迎评论区交流。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。