-
一台 2 核 2G 的 Linux 服务器,部署 Nginx 做反向代理,访问网站偶尔出现 502 Bad Gateway,请问最常见的 3 个可能原因是什么?
-
找出 /var/log 目录下所有7天前修改过且大小超过100M的 .log 文件,并一次性删除它们(请给出安全的命令)。
-
作为一名个人开发者,平时需要经常测试Python脚本、部署轻量API调度工具,一直想找一台稳定的国内免费云服务器,对比多家平台后,最终选择了阿贝云免费云服务器。 阿贝云免费机型标配:1核CPU、1G运行内存、10G固态硬盘、5M公网带宽,配备独立公网IP,支持Ubuntu、CentOS、Windows多系统,开通仅需要简单实名认证,无强制绑定银行卡、无隐性扣费套路。 我主要用这台服务器做开发测试,用来部署OpenSquilla精简版、调试API中转接口、学习Linux运维命令。5M带宽跑纯文字API请求完全无压力,国内BGP线路延迟很低,SSH连接流畅,后台控制面板简洁,新手也能快速重装系统、管理防火墙、查看服务器资源占用。 很多免费VPS要么几天回收、要么境外网络卡顿严重,阿贝云只要每5天发布一篇使用体验文章即可完成续期,实现永久免费使用。非常适合学生党学习建站、练手运维、小型程序挂机、个人项目调试,完全够用。 如果你也需要一台零成本国内测试机,可以前往官网了解:https://www.abeiyun.com
-
自回归生成为什么是“逐个Token”的?为什么不能一次性输出完整回答?
-
你启动了一个长时间运行的前台进程 ./long_task,现在想:把它放到后台继续运行退出终端后让它继续运行如果之后想强制终止它,应该用什么命令?
-
在Shell脚本中,$VAR 和 "$VAR" 有什么区别?
-
软链接(符号链接)和硬链接有什么区别?如果删除原始文件,链接文件还能访问内容吗?
-
服务器中如何设置nginx的开机自启动
-
您好,想要按需购买专属资源池(华东二和西南贵州一),申请开通白名单,信息已私发
-
提问一个小问题,有点不明白
-
基于华为云码道的校园二手书交易平台全栈开发实践1. 案例概述在高校学习生活中,教材和课外书具有明显的阶段性。课程结束、考试完成或学生毕业后,大量书籍进入闲置状态;与此同时,新生和低年级学生仍然需要以较低成本获取教材。传统微信群、朋友圈和线下摆摊存在信息分散、搜索效率低、书籍状态不透明、交易过程无法追踪等问题。本案例围绕“让校园闲置书低成本、安全、可追踪地流转”这一目标,构建一套前后端分离的校园二手书交易平台。项目提供用户注册登录、书籍发布与审核、关键词检索、购物车、站内余额、管理员充值、订单履约、收藏、评价、站内通知和后台统计等功能,最终形成“发布—审核—选购—支付—发货—收货—评价”的完整业务闭环。项目在开发过程中使用华为云码道辅助完成需求梳理、系统设计、任务拆解、功能开发和代码检查,并在仓库中沉淀了 spec.md、design.md 和 tasks.md 等规格文档。当前交付版本采用 Vue 3、Node.js、Express 和 sql.js,能够在本地快速运行,也便于进一步部署到华为云。2. 案例目标本案例不是只完成静态页面,而是以“可正常运行、可完整演示、可自动验证”为交付目标。主要目标如下:实现普通用户、买家、卖家和管理员之间清晰的权限边界。实现真实书籍封面、分类筛选、关键词搜索和书籍详情。实现管理员为用户充值、用户使用站内余额购买书籍的资金闭环。实现购物车、跨卖家拆单、订单支付、卖家发货、买家收货和评价。为充值、支付和订单状态变化保留资金流水与站内通知。使用自动化测试验证权限、状态、余额和异常场景。保留可部署到华为云 ECS、RDS 和 OBS 的演进空间。3. 开发环境与技术选型3.1 前端Vue 3:构建组件化单页应用。Vue Router:管理用户端和管理端路由。Pinia:保存登录用户、余额和公共业务状态。Element Plus:提供表单、表格、弹窗、分页和消息反馈组件。Axios:统一访问后端 REST API。Vite:提供开发服务器和生产构建。3.2 后端Node.js + Express:提供 REST API。JWT:完成身份认证和接口鉴权。bcryptjs:保护用户密码。Multer:处理书籍封面上传。sql.js:使用 SQLite 数据文件完成轻量持久化。Supertest + Node.js Test Runner:实现接口级集成测试。3.3 工程结构项目当前主要由以下部分组成:used-book-web/ Vue 3 前端 used-book-api/ Express 后端与 SQLite 数据 used-book-server/ 早期 Spring Boot 实现(保留版本) .codeartsdoer/ 需求、设计和任务规格文档 README.md 项目启动、账号和功能说明早期系统设计采用 Spring Boot/MySQL。为了降低实习项目演示和单机部署的复杂度,当前默认运行主线演进为 Express/sql.js。案例以实际运行版本为准,同时保留早期版本作为架构演进记录。4. 使用华为云码道完成项目构建4.1 需求分析首先向华为云码道提供校园二手书的业务背景、目标角色和初步功能设想,请其帮助拆分功能域、明确验收条件和识别边界场景。需求阶段重点确认了以下规则:新发布书籍默认进入待审核状态。普通用户不能访问管理接口。用户不能购买自己发布的书籍。订单详情只能由相关买家、卖家或管理员访问。余额不足时必须阻止支付。同一购物车存在多个卖家时,需要按卖家拆分订单。只有卖家可以发货,只有买家可以确认收货和评价。需求分析结果沉淀在 .codeartsdoer/specs/used_book/spec.md 中,为后续设计和测试提供统一依据。4.2 系统设计在需求规格基础上,继续让华为云码道从数据模型、接口、权限、业务状态和异常处理几个方面给出设计建议。系统最终包含 13 张业务表:数据表作用user用户、角色、余额与账户状态category书籍分类book书籍基础信息、卖家、价格与状态book_image书籍图片price_change_log价格变更记录cart购物车order买家、卖家和订单状态order_item订单中的书籍价格快照review交易完成后的评价wallet_transaction充值、购买支出和卖家收入流水notification支付、发货、收货等站内通知favorite用户收藏book_view_log书籍浏览记录系统设计文档和任务拆解分别记录在 design.md 和 tasks.md 中。设计阶段最大的价值是提前发现“余额支付不是单表状态更新”“多卖家订单不能由一个卖家统一履约”等问题。4.3 任务拆解项目按照依赖关系分阶段实施:初始化前后端项目与数据库。完成用户注册、登录和 JWT 鉴权。完成分类、书籍发布、封面上传和审核。完成首页检索、详情、收藏和浏览记录。完成购物车和订单创建。完成管理员充值、余额支付和资金流水。完成发货、收货、评价和通知。完成管理后台和统计。增加集成测试并执行完整代码审查。通过规格驱动的任务拆解,可以减少前后端并行开发时的接口歧义,也方便在每个阶段运行测试。4.4 关键功能迭代在初版完成后,又使用华为云码道对照 README 检查实际代码和需求,重点完成了两轮增强。第一轮增强解决了交易资金来源问题。系统原本具有买卖功能,但缺少适合演示的充值入口。优化后只有管理员可以为指定用户增加站内余额,同时记录充值金额、备注、操作时间和变动后余额。普通用户不能直接修改余额。第二轮增强提升了书籍展示真实性。项目演示数据补充了真实书籍封面,并为图片加载失败保留默认占位图,避免外部图片失效导致页面结构异常。最后对完整仓库进行功能和代码检查,运行后端集成测试和前端生产构建,修复字段命名、参数校验、权限边界、待审核书籍可见性等问题。5. 系统总体方案5.1 逻辑架构浏览器 │ ▼ Vue 3 单页应用 │ Axios / JSON / JWT ▼ Express REST API ├─ 用户与鉴权 ├─ 书籍与审核 ├─ 购物车与订单 ├─ 钱包与资金流水 ├─ 收藏、评价与通知 └─ 管理后台与统计 │ ├─ SQLite 数据文件 └─ 封面上传目录前端通过 Axios 访问 API,后端使用 JWT 判断用户身份和角色。所有关键权限均在服务端再次校验,不能只依赖前端隐藏按钮。业务数据持久化到 SQLite 文件,封面图片由上传目录提供静态访问。5.2 用户与权限普通用户可以浏览和搜索书籍、发布书籍、加入购物车、购买、发货或确认收货,但具体操作受到资源归属限制。管理员拥有用户管理、书籍审核、充值和数据统计权限。管理接口统一检查 admin 角色,普通用户直接调用接口也会被拒绝。5.3 书籍发布与审核用户发布书籍时需要填写书名、作者、分类、价格、成色、出版信息和描述,并可上传封面。前端提供表单提示,后端再次校验日期、价格和分类合法性。新书默认处于待审核状态。只有审核通过并处于在售状态的书籍才进入公共列表,避免违规或错误内容直接公开。首页支持分类、关键词、价格与排序筛选。搜索同时匹配书名和作者,详情页展示封面、价格、成色、卖家和描述。5.4 购物车与跨卖家拆单用户可将不同卖家的书籍加入同一个购物车。创建订单时,后端重新读取每本书的最新状态和价格,并按 sellerId 分组,为每个卖家生成独立订单。这种设计使每个卖家只能处理自己的订单,发货和结算互不影响,也避免某个卖家延迟发货导致其他订单无法推进。5.5 站内余额与管理员充值系统买卖书籍使用平台站内余额。管理员可在用户管理页面选择用户,输入充值金额和备注。服务端校验管理员身份、金额范围和目标用户,并同时更新用户余额和钱包流水。钱包流水包含:管理员充值;购买支出;卖家收入;交易说明;变动后余额;操作时间。这样既能方便训练营项目演示,也能让每次资金变化可追踪。5.6 订单状态订单的主要状态流转如下:待支付 pending_payment │ 买家余额支付 ▼ 已支付 paid │ 卖家发货 ▼ 已发货 shipped │ 买家确认收货 ▼ 已完成 completed │ ▼ 评价 review创建订单后,买家可以支付或取消。支付时后端重新检查订单状态和余额,余额不足则拒绝。卖家只能对已支付订单发货,买家只能对已发货订单确认收货。关键状态变化会生成站内通知。6. 关键技术难点与解决方案6.1 资金与业务状态一致性支付涉及买家余额、钱包流水、订单状态、书籍状态和通知等多项变化。如果只在前端扣减显示余额,刷新页面后数据会失真,也可能产生越权支付。本项目将后端作为唯一可信来源。支付请求到达后,后端依次验证:当前用户是否为订单买家;订单是否处于待支付状态;订单中的书籍是否仍可交易;买家余额是否足够;所有校验通过后再执行扣款、状态更新和流水记录。前端只负责展示后端返回的新余额和订单状态。6.2 多卖家订单拆分购物车是买家维度的数据,但订单履约是卖家维度的数据。如果不同卖家的书籍进入同一订单,一个卖家可能看到或操作另一个卖家的书籍。系统在创建订单时先按卖家分组,再分别创建订单和订单条目。自动化测试专门覆盖跨卖家拆单,验证订单数量、卖家归属和金额计算。6.3 状态机与越权防护订单详情、评价删除、书籍审核和后台统计都存在越权风险。系统在每个接口中校验用户角色、资源归属和前置状态。例如普通用户不能删除他人评价,未参与订单的用户不能查看订单详情,待审核书籍不会出现在公共列表。6.4 真实封面与降级展示真实封面可以显著改善项目效果,但外部图片可能失效、加载缓慢或出现跨域问题。当前演示数据使用可访问封面,同时保留默认封面作为降级展示。部署到生产环境后,建议将确认合规的图片迁移到 OBS 或项目静态资源。6.5 架构演进的一致性项目早期规格采用 Spring Boot/MySQL,当前交付主线采用 Express/sql.js。为了避免评审时出现文档与实现不一致,本案例明确区分“早期设计版本”和“当前可运行版本”,并建议后续以实际云端部署技术栈更新设计文档。7. 测试与验证项目执行统一检查命令:npm run check检查结果如下:后端集成测试:14/14 通过,0 失败;前端生产构建:成功;Vite 版本:8.1.5;前端转换模块:1799 个;本地 Web 服务:http://localhost:5173;本地 API 服务:http://localhost:8088。14 个集成场景覆盖:公共书籍接口字段采用 camelCase;搜索同时匹配书名和作者;非法出版日期和分类被拒绝;不存在的接口返回统一 JSON 404;订单详情权限隔离;普通用户不能删除评价;购物车返回卖家信息;待审核书籍的可见性;管理后台统计;管理员充值、余额购买和卖家入账;跨卖家购物车拆分订单;支付、发货、收货、评价和通知完整闭环;收藏功能;余额不足时拒绝支付,并允许取消订单。除自动化测试外,还进行了真实页面操作。本次演示由管理员为用户充值 100 元,用户以 20 元购买《三体》,支付后余额为 80 元,同时生成购买支出流水和支付成功通知。8. 运行与演示8.1 启动方式在项目根目录执行:npm run dev该命令同时启动前端和 API。执行 npm run check 可以运行后端测试并构建前端生产包。8.2 推荐演示路径在首页搜索并查看《三体》详情。管理员进入后台,为测试用户充值 100 元。买家将书籍加入购物车并创建订单。使用站内余额支付,查看余额由 100 元变为 80 元。查看资金流水和支付成功通知。卖家发货,买家确认收货并评价。回到管理后台查看订单和书籍状态统计。8.3 运行效果截图以下截图展示首页、书籍详情、管理员充值、购物车、订单支付、钱包流水、站内通知和后台统计等核心效果。9. 华为云实际部署项目已部署到华为云 ECS,在线演示地址为 http://124.70.103.252/,健康检查地址为 http://124.70.103.252/health(受论坛外链白名单限制,复制地址时请将中文全角冒号 : 改为英文半角冒号 :)。完整案例 PDF 下载地址:http://124.70.103.252/used-book-case-report.pdf(复制时同样将 : 改为 :)。使用 Nginx 部署 used-book-web/dist,并反向代理 /api、/uploads 和 /health;使用 systemd 运行 Node.js API,支持开机启动和异常重启;SQLite 与 uploads 位于独立持久化目录;API 仅监听 127.0.0.1:8088,8088 不直接对公网开放;部署时生成随机 JWT 密钥,并使种子账号默认密码失效;演示实例计划于 2026 年 7 月 31 日 02:49(GMT+08:00)自动释放。当前部署适合训练营阶段验收。如果后续需要长期运行,可增加域名和 HTTPS,将 SQLite 迁移到华为云 RDS,将上传图片迁移到 OBS,并增加集中日志、监控和备份。10. 案例总结本项目完成了从需求、设计、编码、测试到交付材料整理的完整过程。与简单的增删改查项目相比,校园二手书平台重点解决了多角色权限、订单状态、跨卖家拆单、资金流水和业务一致性问题。华为云码道在项目中的主要价值体现在:将模糊的项目想法转化为可执行的规格和验收条件;从需求中识别状态、权限和异常场景;形成设计文档和任务拆解;辅助实现管理员充值、真实封面和完整交易闭环;对照 README 和代码进行仓库级检查;通过自动化测试验证功能并发现边界问题;将代码、截图、测试结果和指导书要求整理为可交付案例。
-
在线体验地址:http://113.44.103.96(请复制到浏览器访问)项目源码仓库:cid:link_5一、概述1.1 案例介绍在软件研发和云上运维过程中,遗留代码重构依赖人工经验,故障日志分析又常常跨越应用、容器和函数等多个层次,定位慢、重复劳动多。CodeVerse-Ops 将华为云 MaaS 大模型能力接入研发运维流程,提供智能代码重构、云原生日志诊断、代码质量评分、上下文追问、历史任务分析和代码片段管理等能力。本案例将使用华为云 MaaS 的 DeepSeek-V4-Flash 模型作为推理引擎,基于 Next.js、Prisma 和 SQLite 构建全栈应用,并通过 PM2 与 Nginx 部署到弹性云服务器 ECS。完成案例后,您将掌握:使用 OpenAI 兼容接口调用华为云 MaaS 模型;使用华为云码道的 Spec-Driven 模式,将需求依次转化为规格、设计、任务和代码;理解 Server-Sent Events(SSE)任务事件,并在 AI 追问场景中实现流式回复;将模型能力组合为代码重构、日志根因分析和质量评分工作流;使用 Prisma 与 SQLite 管理任务、对话和收藏数据,并理解质量评分的数据模型;在 Ubuntu ECS 上完成 Node.js 应用的一键部署、验证和运维。说明:模型生成内容可能存在偏差。重构代码和运维修复建议应经过人工审查,并在测试环境验证后再应用到生产环境。1.2 适用对象企业开发者及 DevOps、SRE、云原生运维人员;希望学习大模型应用开发的个人开发者;具备 JavaScript/TypeScript、Linux 命令行基础的高校学生。1.3 案例时间直接使用仓库源码完成资源准备、部署和功能验证,预计需要 60~90 分钟。如通过码道分阶段搭建 CodeVerse-Ops,建议预留 2~3 小时,具体时间取决于代码生成、人工评审、依赖下载和构建速度。1.4 案例流程图 1-1 CodeVerse-Ops 案例流程说明:开通 MaaS:登录华为开发者空间,开通 DeepSeek-V4-Flash 预置服务,创建并妥善保存 API Key;创建 ECS:购买 Ubuntu ECS,绑定弹性公网 IP,并在安全组中开放 SSH 和 HTTP 访问;配置并上传:填写 MaaS API Key、基础地址和数据库连接,将项目部署包上传至 ECS;一键部署:运行部署脚本,自动安装依赖,完成数据库迁移、项目构建、PM2 启动和 Nginx 配置;功能体验:依次验证代码重构、批量处理、日志诊断、质量评分、AI 对话、仪表盘和收藏库;验证并释放:检查应用、代理和数据库状态;体验结束后删除 ECS、EIP 及不再使用的模型凭据。流程说明:图 1-1 展示的是“使用现有源码部署体验”的主流程。如需从需求开始复现项目开发过程,请在获取源码和正式部署前完成第三章的码道 Spec-Driven 四阶段实践。1.5 方案架构图 1-2 CodeVerse-Ops 系统运行架构核心调用链如下:浏览器提交代码或日志,Next.js API 创建任务并写入 SQLite;当前版本的提交接口同步调用华为云 MaaS,解析结果并将任务更新为 COMPLETED;浏览器收到 taskId 后连接任务 SSE 接口,通常直接收到 complete 事件并展示结果;用户继续追问时,服务端通过 thinking、result_chunk、complete 或 error 事件逐段推送模型回复;任务结果、对话记录和收藏内容持久化到 SQLite;质量评分接口在收到 taskId 时可持久化评分;仪表盘聚合任务数据,展示近 30 天趋势、任务分布,并预留质量趋势展示。1.6 资源总览本案例使用按需资源。以 1 小时体验、少量公网流量和少量模型调用估算,费用通常由 ECS 实例费用、EIP 流量费用和 MaaS Token 费用组成。云服务价格会因区域、规格和活动变化,最终以购买页面及账单为准。资源名称推荐规格用途计费说明华为开发者空间已完成实名认证的账号进入开发平台和实战案例免费MaaS 模型即服务DeepSeek-V4-Flash代码重构、日志分析、质量评分和对话按实际 Token 用量计费,可优先使用已领取权益弹性云服务器 ECS2 vCPU、4 GiB、Ubuntu 22.04、40 GiB 系统盘运行 CodeVerse-Ops推荐按需计费,价格以控制台为准弹性公网 IP EIP按流量计费、5 Mbit/sSSH 登录和浏览器访问按流量计费,价格以控制台为准费用提示:体验完成后请及时释放 ECS 和 EIP。仅关闭操作系统不会停止 ECS 计费。二、环境和资源准备2.1 前置条件开始前请确认:已注册华为云账号并完成实名认证;账号余额或代金券足以支付本案例资源;本地可使用 SSH 和 SCP。Windows 10/11 可在 PowerShell 中执行 ssh -V 和 scp 检查;已获得完整的 codeverse-ops 项目目录;不要将 API Key 写入公开仓库、聊天记录或截图。2.2 开通 MaaS 模型并创建 API Key登录华为开发者空间。如尚未领取模型权益,可参考《华为云 MaaS 平台大模型 Tokens 领取使用指导》完成领取。然后按以下步骤开通模型:进入 MaaS 控制台 > 模型推理 > 在线推理 > 预置服务;找到 DeepSeek-V4-Flash,单击 开通服务;服务开通后单击 调用说明,确认模型参数为 deepseek-v4-flash;在调用说明页面创建 API Key,并立即复制到安全位置。API Key 通常只在创建时完整显示;记录 OpenAI 兼容接口地址。中国大陆站的 OpenAI 兼容接口当前仅支持 西南-贵阳一,该区域的完整地址为:https://api.modelarts-maas.com/openai/v1/chat/completions本项目会自动在基础地址后追加 /v1/chat/completions,因此项目配置中应填写:https://api.modelarts-maas.com/openai中国香港站应以控制台“调用说明”显示的地址为准,常见基础地址为:https://api-ap-southeast-1.modelarts-maas.com/openai重要:模型服务、API Key 和调用地址必须属于同一区域,并以控制台“调用说明”为准。不要填写完整的 /v1/chat/completions 地址,否则项目会重复拼接路径;不要使用 https://api.deepseek.com,该地址不是华为云 MaaS 服务地址。Linux、macOS 或 ECS 可使用以下命令验证 API Key:export MAAS_API_KEY="<你的MaaS API Key>" curl -sS "https://api.modelarts-maas.com/openai/v1/chat/completions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${MAAS_API_KEY}" \ -d '{ "model": "deepseek-v4-flash", "messages": [{"role": "user", "content": "请回复:连接成功"}], "max_tokens": 64 }' 响应中出现 choices 和模型回复即表示调用成功。若返回 401 或 403,请检查 API Key、模型开通状态和区域是否一致。Windows PowerShell 使用以下命令:$env:MAAS_API_KEY = "<你的MaaS API Key>" $headers = @{ "Content-Type" = "application/json" "Authorization" = "Bearer $env:MAAS_API_KEY" } $body = @{ model = "deepseek-v4-flash" messages = @(@{ role = "user"; content = "请回复:连接成功" }) max_tokens = 64 } | ConvertTo-Json -Depth 4 Invoke-RestMethod ` -Uri "https://api.modelarts-maas.com/openai/v1/chat/completions" ` -Method Post ` -Headers $headers ` -Body $body2.3 创建 ECS登录华为云控制台,进入 服务列表 > 计算 > 弹性云服务器 ECS,单击 购买弹性云服务器。图 2-1 选择 ECS 规格、镜像、磁盘和公网访问配置推荐配置如下:配置项推荐值说明计费模式按需计费便于体验结束后及时释放区域与账号和网络规划一致购买后不可直接更换CPU 架构x86与常用 Node.js 依赖兼容规格2 vCPU、4 GiB低于 4 GiB 可能在 next build 时内存不足镜像Ubuntu 22.04 Server 64bit部署脚本使用 apt-get系统盘40 GiB用于系统、依赖、构建产物和 SQLiteEIP现在购买用于 SSH 和 Web 访问带宽计费按流量计费,5 Mbit/s适合短时体验登录方式密钥对或强密码密钥对安全性更高购买完成后,在 ECS 详情页记录:ECS 公网 IP:后文以 <ECS_IP> 表示;登录用户名:本案例部署脚本固定使用 /root 并以 root 用户配置 PM2,因此应选择支持 root 登录的 Ubuntu 公共镜像;密钥文件路径或登录密码。图 2-2 ECS 创建完成并处于运行中说明:截图中的实例名称、IP、价格和区域仅为操作示例,请以实际控制台页面为准。2.4 配置安全组进入 ECS 详情 > 安全组 > 配置规则 > 入方向规则,添加以下规则:协议端口来源用途TCP22本机公网 IP/32SSH 和 SCPTCP80本机公网 IP/32;公开体验时可临时使用 0.0.0.0/0浏览器访问应用图 2-3 配置 ECS 安全组入方向规则安全建议:不要将 22 端口长期对全网开放。生产环境还应配置 HTTPS、Web 应用防火墙、身份认证和访问审计。本案例应用本身未实现用户登录,不应直接承载敏感代码或生产日志。2.5 准备项目环境变量记录从 MaaS 控制台获取的 API Key 和基础地址。为避免凭据进入压缩包,本案例将在代码上传 ECS 后创建 .env.production,文件内容如下:# 华为云 MaaS API Key HUAWEI_MAAS_API_KEY=<你的MaaS API Key> # 仅填写基础地址,不包含 /v1/chat/completions HUAWEI_MAAS_BASE_URL=https://api.modelarts-maas.com/openai # Prisma 会相对 prisma/schema.prisma 解析该路径 DATABASE_URL=file:../dev.db配置要求:HUAWEI_MAAS_API_KEY 不要添加多余空格或中文引号;HUAWEI_MAAS_BASE_URL 末尾有无 / 均可,客户端会移除末尾斜杠;DATABASE_URL 保持为 file:../dev.db,使 Prisma CLI 和应用运行时使用项目根目录下同一个数据库;.env.production 含敏感信息,不得提交到公开代码仓库或打入部署包;项目已通过 .gitignore 排除 .env.production;提交前仍应使用 git status 确认该文件未被暂存;部署脚本不会输出环境变量内容,终端日志中不应出现 API Key。2.6 获取案例源码通过 Git 下载案例源码:git clone cid:link_5.git codeverse-ops cd codeverse-ops仓库地址:CodeVerse-Ops(GitCode)【本帖子开头有】。下载后确认目录中至少包含:codeverse-ops/ ├── package.json ├── package-lock.json ├── scripts/deploy-ecs.sh ├── prisma/ └── src/检查点:执行 git status 能正常显示仓库状态,且 package.json、scripts/deploy-ecs.sh、prisma/ 和 src/ 均存在。三、通过码道分阶段搭建 CodeVerse-Ops本模块参考华为开发者空间案例中心的码道实践组织方式,结合 CodeVerse-Ops 的实际开发记录,演示如何使用华为云码道(CodeArts)代码智能体,以 Spec-Driven 模式将复杂需求依次转化为需求规格、技术设计、任务清单和可运行代码。说明:码道界面、模型列表和按钮位置可能随版本更新而变化,请以实际产品页面为准。生成代码必须经过人工审查、构建测试和安全检查;不要在对话、截图或提交记录中粘贴 API Key、密码等敏感信息。3.1 开通并进入码道登录华为开发者官网,进入华为云码道(CodeArts)代码智能体体验页面;按页面提示完成体验版开通;下载并安装支持码道的开发工具,登录同一华为云账号;打开码道 Agent Space 或 IDE 右侧智能体面板,确认可以选择 氛围编程(Vibe-Coding) 和 规范开发(Spec-Driven)。图 3-1 开通华为云码道代码智能体体验版图 3-2 进入码道 Agent Space图 3-3 在 IDE 中打开码道代码智能体3.2 创建项目并选择 Spec-Driven 模式新建空工作区,在智能体面板选择 规范开发(Spec-Driven)。首次输入应描述业务目标、技术栈、模型服务、核心功能和交付要求,避免只输入“帮我做一个网站”等宽泛指令。可使用以下需求作为起始提示词:请使用 Next.js 14、TypeScript、Tailwind CSS、Prisma 和 SQLite 构建 CodeVerse-Ops。应用接入华为云 MaaS 的 DeepSeek-V4-Flash, 提供单文件/批量代码重构、CCE/FunctionGraph 日志诊断、代码质量评分、 上下文对话、任务仪表盘和代码片段收藏功能。请采用 Spec-Driven 流程, 先生成需求规格,再生成技术设计和任务清单,经确认后分阶段实现。图 3-4 选择 Spec-Driven 模式并提交项目目标Spec-Driven 流程包含四个阶段:需求规格设计:明确目标、边界、用户故事和验收标准;实现方案创建:确定架构、数据模型、接口和部署方案;编码任务规划:将设计拆分为可追踪、可验证的任务;任务执行:按依赖顺序生成代码,并持续构建验证。3.3 第一阶段:生成并评审 spec.md码道首先将自然语言需求整理为 spec.md。评审时重点检查:是否覆盖代码重构、日志诊断、任务状态、模型调用和数据持久化;是否明确“不负责自动修改生产代码、不直接执行模型生成命令”等安全边界;每个核心能力是否具有可验证的验收标准;模型名称、接口兼容方式和部署目标是否与项目实际一致。图 3-5 第一阶段完成需求规格设计若规格有遗漏,先在对话中提出修改要求,确认 spec.md 后再进入设计阶段。不要让智能体在需求边界未确定时直接批量生成代码。3.4 第二阶段:生成并评审 design.mddesign.md 应把需求落实为可实现的技术方案。本项目重点确认:Next.js App Router 同时承载页面和 API;Prisma/SQLite 数据模型覆盖任务、日志、对话、评分和收藏;MaaS 客户端统一处理鉴权、超时、重试及流式响应;首轮任务与 AI 对话的 SSE 行为描述准确;ECS、PM2、Nginx 和容器化部署路径清晰;API Key 仅通过环境变量注入,不进入源码、镜像和日志。图 3-6 第二阶段完成实现方案设计3.5 第三阶段:生成并评审 tasks.md码道根据规格和设计生成 tasks.md,把工作拆分为初始化、数据模型、MaaS 客户端、任务状态、核心 API、前端页面和部署验证等任务。评审任务清单时应确保:每项任务都能回溯到 spec.md 和 design.md;任务依赖顺序正确,可并行项和串行项明确;每项任务包含完成条件,而不只是文件名;构建、数据库迁移、接口验证和安全检查被列入任务。图 3-7 第三阶段完成编码任务规划3.6 第四阶段:按任务清单执行确认任务清单后进入执行阶段。码道会读取规格和设计,按依赖关系创建文件、安装依赖并实现功能。建议采用“小批次执行—查看变更—运行验证—继续下一批”的节奏:先完成项目初始化、环境变量声明和 Prisma Schema;再实现 MaaS 客户端、任务状态和后端 API;然后实现重构、诊断、仪表盘、收藏等页面;最后补充 Dockerfile、ECS/CCE 部署文件和操作文档;每批变更后查看差异,拒绝与规格无关的修改。图 3-8 码道开始执行初始化与配置任务图 3-9 码道继续实现后端接口和前端页面图 3-10 任务执行阶段完成3.7 本地运行与阶段验收智能体完成首轮实现后,在项目目录执行:npm install npx prisma generate npx prisma migrate deploy npm run dev浏览器访问 http://localhost:3000,先验证页面路由和基本交互,再使用脱敏的测试代码与测试日志验证 MaaS 调用。首个可运行版本可能只具备代码重构和日志诊断,应按 tasks.md 的验收条件逐项检查,而不是仅以“页面能打开”作为完成标准。图 3-11 首个本地可运行版本的代码重构页面图 3-12 本地验证日志诊断功能3.8 模型接入的原型记录与正式配置项目早期曾使用 DeepSeek 官方 API 验证 OpenAI 兼容调用链,以下两张图仅用于说明原型演进,不是本案例的最终配置步骤。图 3-13 早期原型的 API Key 创建记录图 3-14 早期原型的环境变量配置正式案例已经切换到华为云 MaaS。请严格按照 2.2 和 2.5 节配置 HUAWEI_MAAS_API_KEY 与 https://api.modelarts-maas.com/openai,不要照抄历史截图中的 https://api.deepseek.com;截图中的凭据已失效或脱敏。3.9 迭代优化与上下文管理首轮功能完成后,可继续让码道基于实际测试结果迭代,但每次指令应说明问题、预期行为、影响范围和验证方式。本项目的后续迭代包括主题系统、命令面板、仪表盘、收藏库、批量重构、上下文对话以及 ECS 部署加固。图 3-15 基于功能差距分析继续迭代图 3-16 依据新增需求升级功能版本长任务会持续占用上下文。阶段验收后可使用会话压缩保留目标、约束、关键文件和未完成任务,再继续下一轮开发。压缩前应确认摘要未包含 API Key、登录密码等敏感信息。图 3-17 使用会话压缩管理长周期开发上下文完成本模块后,项目应通过 npm run build,数据库迁移可执行,核心页面可访问,且所有环境变量和部署步骤与后续章节一致。四、构建并部署 CodeVerse-Ops 应用4.1 技术栈与项目结构主要技术栈如下:层次技术版本/作用Web 框架Next.js14.2.35,App Router 全栈应用前端React、TypeScript、Tailwind CSSReact 18、TypeScript 5、Tailwind CSS 3.4编辑器CodeMirror 6代码输入、语法高亮和只读结果展示图表Recharts仪表盘与五维质量雷达图数据访问Prisma5.22.0,模型定义、迁移和查询数据库SQLite保存任务、日志、对话、评分和收藏模型服务华为云 MaaSDeepSeek-V4-Flash、OpenAI 兼容接口运行环境Node.js、PM2、NginxNode.js 20、进程守护、反向代理项目关键结构:codeverse-ops/ ├── prisma/ │ ├── schema.prisma # 7 个数据模型 │ └── migrations/ # 数据库迁移 ├── src/ │ ├── app/ │ │ ├── page.tsx # 首页 │ │ ├── refactor/page.tsx # 单文件/批量代码重构 │ │ ├── ops/diagnose/page.tsx # CCE、FunctionGraph 日志诊断 │ │ ├── dashboard/page.tsx # 任务统计与趋势 │ │ ├── snippets/page.tsx # 代码片段收藏库 │ │ └── api/ # 重构、诊断、评分、对话等 API │ ├── components/ # 编辑器、对比、图表、命令面板等组件 │ ├── hooks/ # SSE、主题等 React Hooks │ ├── lib/ │ │ ├── huawei-maas.ts # MaaS 客户端、重试和超时控制 │ │ ├── prisma.ts # Prisma 单例 │ │ ├── sse-client.ts # SSE 消息与响应头 │ │ ├── task-state.ts # 任务状态 │ │ ├── conversation-manager.ts # 30 分钟内存上下文 │ │ └── templates.ts # 代码与日志示例模板 │ └── types/ # API、模板和 SSE 类型 ├── .env.example # 环境变量示例 ├── .env.production # 生产配置,需自行创建 ├── scripts/ │ ├── deploy-ecs.sh # ECS 一键部署脚本 │ └── build-image.sh # SWR 镜像构建脚本 ├── deploy/ │ └── cce-deployment.yaml # CCE 部署清单 ├── Dockerfile # 容器化构建文件 ├── package.json # 项目依赖与命令 └── package-lock.json # 锁定依赖版本Prisma 数据模型职责:模型作用Task保存重构或日志诊断任务及状态CloudLog保存待分析日志及分析状态Snippet保存收藏的原始代码、重构代码和说明BatchGroup管理批量重构的总数和完成进度Conversation关联任务与对话Message持久化用户和助手消息QualityScore在评分接口收到 taskId 时,保存安全性、可维护性、性能、可读性和类型安全评分4.2 关键实现解析4.2.1 MaaS 客户端src/lib/huawei-maas.ts 负责:从环境变量读取 API Key 和基础地址;拼接 /v1/chat/completions;使用 Authorization: Bearer <API_KEY> 鉴权;固定调用 deepseek-v4-flash;同步调用最多尝试 3 次,即首次失败后最多重试 2 次,退避时间依次为 1 秒、2 秒;单次调用超时时间为 120 秒;支持普通 JSON 响应和流式响应。核心请求结构如下:const response = await fetch(`${baseUrl}/v1/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, }, body: JSON.stringify({ model: "deepseek-v4-flash", messages, temperature: 0.7, max_tokens: 4096, stream: true, }), }); 4.2.2 任务接口与 SSE 事件代码重构和日志诊断采用“同步任务提交 + SSE 结果回传”的两阶段请求:图 4-1 CodeVerse-Ops 首轮任务与对话请求流程图中编号说明:提交代码或日志:浏览器将用户输入发送到对应的 Next.js API;创建任务:服务端在 SQLite 中创建状态为 PENDING 的任务;进入处理状态:开始推理前,将任务状态更新为 PROCESSING;调用模型:服务端通过 OpenAI 兼容接口同步调用华为云 MaaS;返回完整结果:MaaS 返回完整的代码重构或日志分析结果;保存结果:服务端解析模型输出,将结果写入 SQLite,并将任务标记为 COMPLETED;响应提交请求:Next.js API 向浏览器返回 taskId 和完整结果;连接任务 SSE:浏览器使用 EventSource 连接任务 SSE 接口;返回完成事件:SSE 接口查询到已完成任务后,发送 complete 事件。用户继续对话时,应用则通过 SSE 逐段返回模型回复。实现边界:页面上的“正在连接 AI 服务”和 SSE 状态组件已经具备流式展示结构,但首轮重构、诊断请求的等待主要发生在同步 POST 阶段,当前版本不会逐 Token 展示首轮模型输出。对话追问采用真实流式响应。4.2.3 提示词与结构化结果应用通过系统提示词限定模型角色,并要求模型返回 JSON:代码重构:返回 refactoredCode 和 explanation;日志诊断:返回 analysis 和 patchSuggestion;质量评分:返回五个 0~100 的维度分数及 details。服务端会从模型输出中提取 JSON。若模型未严格返回 JSON,部分接口会回退为原始文本。因此,生成结果仍需人工复核。4.3 打包项目在本地打开项目父目录执行。部署包明确排除环境变量、依赖、构建产物、数据库和 Git 元数据:tar -czf codeverse-ops-deploy.tar.gz \ --exclude=codeverse-ops/node_modules \ --exclude=codeverse-ops/.next \ --exclude=codeverse-ops/dev.db \ --exclude=codeverse-ops/.env \ --exclude=codeverse-ops/.env.production \ --exclude=codeverse-ops/.git \ codeverse-ops/Windows PowerShell 使用反引号续行:tar -czf codeverse-ops-deploy.tar.gz ` --exclude=codeverse-ops/node_modules ` --exclude=codeverse-ops/.next ` --exclude=codeverse-ops/dev.db ` --exclude=codeverse-ops/.env ` --exclude=codeverse-ops/.env.production ` --exclude=codeverse-ops/.git ` codeverse-ops/ 打包后检查文件和压缩包内容:Get-Item .\codeverse-ops-deploy.tar.gz tar -tzf .\codeverse-ops-deploy.tar.gz检查点:压缩包中必须包含 package-lock.json、scripts/deploy-ecs.sh、prisma/ 和 src/,不得包含 .env、.env.production、node_modules、.next 或旧的 dev.db。4.4 上传项目并执行一键部署步骤 1:上传部署包在本地项目父目录执行:scp codeverse-ops-deploy.tar.gz root@<ECS_IP>:/root/使用密钥对时执行:scp -i <私钥文件路径> codeverse-ops-deploy.tar.gz root@<ECS_IP>:/root/步骤 2:登录 ECSssh root@<ECS_IP> 使用密钥对时执行:ssh -i <私钥文件路径> root@<ECS_IP> 步骤 3:解压并运行部署脚本cd /root tar -xzf codeverse-ops-deploy.tar.gz rm -f codeverse-ops-deploy.tar.gz cd /root/codeverse-ops vi .env.production在编辑器中填写 2.5 节准备的三个环境变量,保存后限制文件权限:chmod 600 .env.production # 确保 Node.js 主版本为 20 node -v 2>/dev/null || true 若已安装的 Node.js 不是 20.x,先升级:curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt-get install -y nodejs首次部署执行:chmod +x scripts/deploy-ecs.sh bash scripts/deploy-ecs.sh重新部署时,scripts/deploy-ecs.sh 会先备份 /opt/codeverse-ops/dev.db,替换应用文件后再恢复数据库并执行增量迁移。重要数据仍建议在部署前单独备份。部署脚本自动完成:阶段操作预期结果1/6安装 Node.js 20、PM2、Nginx、SQLite输出各工具版本2/6备份数据库,替换 /opt/codeverse-ops 中的应用文件并恢复数据项目文件部署完成,历史数据保留3/6将 .env.production 复制为 .env应用可读取配置4/6执行 npm ci、Prisma 生成、迁移和 next build数据表和生产构建生成5/6使用 PM2 启动 npm startcodeverse-ops 状态为 online6/6配置 Nginx,将 80 端口代理到 3000nginx -t 成功并重载部署脚本结束时会输出访问地址。请以实际 ECS 公网 IP 为准:http://<ECS_IP>说明:脚本末尾可能显示脚本内预置的示例 IP,该值不一定是当前 ECS 地址,不应作为访问依据。图 4-2 PM2 启动成功且 Nginx 配置校验通过4.5 部署结果验证依次执行:node -v npm -v pm2 status systemctl is-active nginx curl -I http://127.0.0.1:3000 curl -I http://127.0.0.1预期结果:Node.js 主版本为 v20;PM2 中 codeverse-ops 状态为 online;Nginx 状态为 active;两次 curl 均返回 HTTP 200、301 或 307 等正常响应,而不是连接失败。检查数据库:cd /opt/codeverse-ops sqlite3 dev.db ".tables" 预期至少看到与以下模型对应的数据表:BatchGroup CloudLog Conversation Message QualityScore Snippet Task最后,在浏览器访问 http://<ECS_IP>。首页应显示“代码重构”“日志诊断”“仪表盘”和“收藏库”等入口。图 4-3 通过 ECS 公网地址访问 CodeVerse-Ops图 4-4 首页功能入口、核心特性和任务统计五、功能体验5.1 智能代码重构在首页单击 代码重构;保持 单文件 模式;选择 javascript,单击 快捷模板 > 回调地狱;也可粘贴自己的代码;单击 提交重构;提交后等待 MaaS 返回完整结果。当前版本在此阶段可能仅显示按钮处于处理中;页面连接任务 SSE 接口并显示“重构完成”后,查看 TypeScript 结果和优化点;单击 对比查看,检查原代码与重构代码差异;查看五维质量雷达图,比较原始代码和重构代码;使用复制、导出或收藏功能保存结果。图 5-1 提交代码并获得 TypeScript 重构结果图 5-2 对比重构前后代码并查看质量评分示例输入:function getUserData(userId, callback) { db.query("SELECT * FROM users WHERE id = ?", [userId], function (err, user) { if (err) return callback(err); db.query("SELECT * FROM orders WHERE userId = ?", [userId], function (err, orders) { if (err) return callback(err); callback(null, { user, orders }); }); }); } 验收标准:请求完成后页面显示任务成功状态、完整重构结果和任务 ID;结果包含带明确类型的 TypeScript 代码;优化说明能够指出异步流程、错误处理或类型安全等改进;雷达图至少展示安全性、可维护性、性能、可读性和类型安全五个维度。注意:当前重构提示词统一要求输出 TypeScript。即使输入 Python、Java、Go、PHP、Ruby、C 或 C++,输出目标仍是 TypeScript。5.2 批量代码重构进入 代码重构,切换到 批量;单击 添加文件,填写文件名、语言和代码内容;重复添加多个文件;单击批量提交按钮,查看总体和单文件处理状态;等待各文件状态更新为 COMPLETED 或 FAILED。限制条件:单次最多 20 个文件;接口以 JavaScript 字符串长度统计总量,上限约 500 万字符;该限制不等同于严格的 UTF-8 字节大小;每个文件会创建独立任务,并归属同一个批次;批量处理消耗的模型 Token 通常高于单文件处理,请控制测试代码规模。当前版本说明:批量页面仅展示文件名、语言和任务状态,暂不提供单个文件的重构结果详情入口。5.3 云原生日志故障诊断在首页单击 日志诊断;选择 CCE(云容器引擎);单击 快捷模板 > CCE OOMKilled;单击 提交诊断;等待同步分析完成,查看根因分析和 YAML 修复建议;再选择 FunctionGraph(函数工作流),使用“函数超时”模板重复体验。图 5-3 提交 FunctionGraph 故障日志并查看根因图 5-4 查看结构化修复建议并继续追问示例输入:Warning OOMKilled pod/api-server-7d9f8b6c4-x2k9j Last State: Terminated Reason: OOMKilled Exit Code: 137 Restart Count: 5 Limits: cpu: 1, memory: 512Mi Requests: cpu: 500m, memory: 256Mi验收标准:根因分析能识别容器内存超限和退出码 137;修复建议包含调整 resources.requests、resources.limits 或排查内存泄漏的可执行方向;FunctionGraph 超时案例能给出超时时间、内存、数据读取方式等方面的排查建议。安全提示:提交真实日志前应删除账号、Token、密码、内网地址、用户数据等敏感信息。模型建议不可直接应用于生产集群。5.4 代码质量评分单文件重构完成后,页面会分别调用质量评分接口评估原始代码和重构代码。评分范围为 0~100:维度评估内容常见风险安全性注入、XSS、敏感信息、危险 API拼接 SQL、明文密钥、eval可维护性模块化、重复度、耦合度超长函数、重复逻辑、全局状态性能复杂度、I/O 和资源使用不必要的嵌套循环、重复请求可读性命名、结构、注释单字母变量、深层嵌套类型安全类型覆盖与边界处理any、隐式转换、空值未处理评分由大模型生成,适合辅助比较,不等同于静态代码扫描、单元测试或安全审计结果。当前版本说明:重构页面会展示原始代码和重构代码的即时评分,但页面请求暂未携带 taskId,因此这些评分不会写入 QualityScore 表,仪表盘“质量评分趋势”可能为空。这不影响雷达图展示和其他任务统计。5.5 AI 上下文对话在重构或诊断结果页单击 继续对话;输入针对当前结果的问题,例如“请解释此处的类型设计”或“如何验证该 YAML 修复有效”;查看流式回复;收起对话面板后再次打开,确认历史消息仍可显示。对话消息会写入 SQLite,但服务端用于连续推理的内存上下文有效期为 30 分钟,每 5 分钟清理一次。重新打开“继续对话”面板时,应用会读取持久化消息并重建上下文;如果面板保持打开期间上下文过期,接口会提示重新创建。刷新页面后,当前结果和 taskId 会丢失,现有页面没有从仪表盘重新进入原任务详情的入口。5.6 历史任务仪表盘完成至少一次代码重构和一次日志诊断;进入 仪表盘;查看总任务数、重构次数、诊断次数和成功率;查看近 30 天趋势、任务类型分布、状态分布、质量评分趋势和最近任务;单击 刷新,或保持 30 秒自动刷新。图 5-5 查看任务总量、成功率和近 30 天趋势图 5-6 查看任务分布、质量趋势和最近任务若仪表盘为空,请先确认任务已成功写入数据库,再刷新页面。5.7 代码片段收藏库在代码重构结果页单击 收藏;进入 收藏库;使用关键词或编程语言筛选收藏;复制或导出收藏结果;单击 删除 并确认,可移除不再需要的收藏。图 5-7 搜索、复制、导出或删除收藏内容日志诊断结果也提供收藏入口。收藏前请确认结果中不含敏感日志。5.8 命令面板与主题按 Ctrl+K(macOS 为 Command+K)打开命令面板;输入“重构”“诊断”“仪表盘”“收藏”或“主题”等关键词;使用方向键选择命令,按 Enter 执行,按 Esc 关闭;可通过页面导航切换明暗主题。图 5-8 使用命令面板快速导航图 5-9 切换为浅色主题六、运行维护与故障排查6.1 常用运维命令# 查看进程 pm2 status # 查看最近日志 pm2 logs codeverse-ops --lines 100 # 重启应用 pm2 restart codeverse-ops # 查看 Nginx 状态与配置 systemctl status nginx --no-pager nginx -t # 查看端口监听 ss -lntp | grep -E ':80|:3000' # 查看磁盘和内存 df -h free -h # 查看数据库表和最近任务 cd /opt/codeverse-ops sqlite3 dev.db ".tables" sqlite3 dev.db \ "SELECT id, type, status, language, createdAt FROM Task ORDER BY createdAt DESC LIMIT 10;" 修改 .env 后必须重启应用:cd /opt/codeverse-ops pm2 restart codeverse-ops --update-env6.2 常见问题现象可能原因处理方法浏览器无法访问 http://<ECS_IP>安全组未开放 80、Nginx 未启动、EIP 错误检查安全组、systemctl status nginx 和 ECS 公网 IP502 Bad GatewayNext.js 进程未启动或 3000 端口未监听执行 pm2 status、pm2 logs codeverse-ops,重启 PM2返回 401 或 403API Key 无效、模型未开通、账号区域不匹配重新查看 MaaS 调用说明并创建 API Key返回 404MaaS 基础地址配置错误确保地址不包含 /v1/chat/completions,国内站填写 https://api.modelarts-maas.com/openai页面提示“系统配置异常”环境变量缺失检查 /opt/codeverse-ops/.env 中两个 HUAWEI_MAAS_* 变量AI 请求长时间无响应或连接中断单次 MaaS 调用超时为 120 秒,普通调用最多尝试 3 次缩短输入并检查 MaaS 状态;Nginx 已配置 400 秒读取超时,生产环境仍应结合调用策略统一超时对话流式输出中断Nginx、浏览器网络或模型连接中断检查 PM2/Nginx 日志,重新打开对话面板后重试首轮重构或诊断没有逐 Token 输出当前提交接口同步完成 MaaS 调用后才连接任务 SSE这是当前版本的实现行为;等待请求完成,以最终结果为准next build 被系统终止ECS 内存不足使用 4 GiB 或更高规格,停止无关进程后重试Prisma 报数据库不存在或无表DATABASE_URL 错误或迁移失败恢复 file:../dev.db,执行 npx prisma generate && npx prisma migrate deploy仪表盘有任务但无质量趋势当前重构页面的评分请求未携带 taskId这是当前版本已知限制,不影响即时雷达图和其他任务统计批量任务拒绝提交文件数或字符串总长度超限保持不超过 20 个文件、代码总量约 500 万字符以内6.3 重新构建与升级更新代码后,在 ECS 执行:cd /opt/codeverse-ops npm ci npx prisma generate npx prisma migrate deploy npm run build pm2 restart codeverse-ops --update-env执行数据库迁移前建议备份:cd /opt/codeverse-ops cp dev.db "dev.db.backup.$(date +%Y%m%d%H%M%S)" 6.4 生产化建议本案例以快速体验为目标。用于团队或生产环境前,至少应补充:使用 IAM、统一身份认证或应用登录保护所有页面和 API;使用 ELB/Nginx 配置 HTTPS 证书,禁止明文传输代码和日志;将 API Key 存储到云凭据管理服务,避免落盘和终端输出;使用云数据库替代单机 SQLite,并建立自动备份;将内存对话上下文迁移到 Redis 等共享存储,支持多实例;增加请求限流、输入大小限制、审计日志和敏感信息脱敏;对模型生成代码执行静态扫描、单元测试和人工评审;对模型生成的运维命令和 YAML 建立审批及灰度验证流程;配置 AOM、LTS 或其他可观测服务监控 CPU、内存、错误率和模型调用延迟。七、释放资源7.1 删除 ECS登录华为云控制台,进入 弹性云服务器 ECS > 实例;选择本案例创建的 ECS;单击 更多 > 删除;根据页面提示勾选释放绑定的 EIP、删除系统盘和数据盘;确认资源名称和影响范围后完成删除。删除后再次检查 ECS、云硬盘和 EIP 列表,确认没有遗留按需资源。7.2 处理 MaaS 资源进入 MaaS 控制台 > 模型推理 > 在线推理:预置模型通常按实际调用量计费,停止调用后不会继续产生推理 Token;删除不再使用的 API Key,降低泄露风险;如创建过专属部署实例或其他持续计费资源,请停止并删除;在费用中心检查账单和代金券使用情况。7.3 删除本地敏感文件不再使用项目时,可删除包含 API Key 的部署包和环境变量文件:# Linux/macOS rm -f codeverse-ops-deploy.tar.gz rm -f codeverse-ops/.env.productionWindows PowerShell 执行:Remove-Item .\codeverse-ops-deploy.tar.gz -ErrorAction SilentlyContinue Remove-Item .\codeverse-ops\.env.production -ErrorAction SilentlyContinue若 API Key 曾出现在公开仓库、日志或截图中,应立即在 MaaS 控制台删除并重新创建。八、扩展资料华为云 MaaS OpenAI 兼容接口说明华为云 MaaS 模型列表弹性云服务器 ECS 文档弹性公网 IP 文档云容器引擎 CCE 文档函数工作流 FunctionGraph 文档九、案例验收清单完成以下检查即表示案例体验成功:[ ] 已开通 DeepSeek-V4-Flash,并使用华为云 MaaS API Key 完成接口验证;[ ] 如实践第三章,已通过码道完成 spec.md、design.md、tasks.md 和分阶段任务执行;[ ] ECS、EIP 和安全组配置完成;[ ] codeverse-ops 在 PM2 中为 online,Nginx 为 active;[ ] 浏览器可通过 ECS 公网 IP 打开首页;[ ] 单文件代码重构可通过任务 SSE 接口收到 complete 结果;[ ] 批量重构可显示批次和单文件状态;[ ] CCE 或 FunctionGraph 日志可生成根因分析和修复建议;[ ] 质量雷达图可展示原始代码与重构代码对比;[ ] AI 对话可逐段显示回复,仪表盘和收藏库可正常使用;[ ] 已确认模型输出仅作辅助并经过人工复核;[ ] 体验结束后已释放不再使用的计费资源和 API Key。
-
一、概述1.1 案例介绍在课程学习中,学生常常同时面对 PDF 讲义、Markdown 笔记、教材摘录和练习题等多种资料。传统学习工具通常只能解决“保存资料”或“回答问题”中的某一个环节,难以持续回答下面几个问题:一门课程到底包含哪些知识点,它们之间有什么层级和前置关系?学生目前真正薄弱的是哪些知识点,判断依据是什么?学习计划能否根据实际作答结果自动调整?AI 给出的知识点、题目和回答是否有课程资料依据?当模型或外部服务不可用时,核心学习流程能否继续运行?基于这些问题,我利用华为云码道(CodeArts)智能体开发了 CoursePilot。它不是一个只负责聊天的通用助手,而是一个以课程资料和学习证据为基础的 AI 个性化学习教练 Agent。系统围绕以下闭环工作:注册登录 → 创建课程 → 添加资料 → 构建知识结构 → 设置学习目标 → 初始诊断 → 生成知识画像 → 制定学习计划 → 学习与练习 → 错因分析 → 更新掌握度 → 动态调整计划 项目仓库:cid:link_7项目地址:115.120.251.21(由于成本限制,该IP发布帖子几日后可能会释放!)演示视频:项目仓库根目录 demo视频.mp41.2 核心设计原则课程无关:不把业务逻辑绑定到某一门固定课程。资料驱动:知识点、题目和学习辅导尽量建立在用户资料之上。来源可追溯:知识点和 AI 生成题目保留对应资料与分块来源。证据驱动:掌握度来自真实作答、难度、耗时和提示使用情况。人机协同:AI 负责提取、生成和辅助判断,用户保留确认与修正权。可解释与可审计:重要算法采用确定性规则,Skill 与 MCP 调用保存日志。可降级:大模型不可用时,资料解析、诊断和掌握度更新等核心流程仍可运行。1.3 适用对象希望完成 AI Agent 项目实践的高校学生;学习 Vue 3、FastAPI、MCP、Skill 与 Docker 的开发者;需要搭建课程资料管理、诊断或个性化学习系统的团队;希望了解如何将本地全栈应用部署到华为云 ECS 的开发者。1.4 案例时间本案例总时长预计240分钟。1.5 案例流程本案例采用“需求规格—架构设计—任务拆解—分阶段开发—测试验证—云端部署—迭代优化”的流程完成 CoursePilot 的设计与实现。使用华为云码道(CodeArts)代码智能体辅助完成需求分析,编写产品规格、功能需求和用户流程文档,明确 CoursePilot 的产品定位、功能范围、验收条件以及“资料驱动、证据驱动、来源可追溯”等核心原则,定义系统“做什么”。完成系统架构与技术方案设计,确定 Vue 3、FastAPI、SQLAlchemy、MCP、Skill 和 Docker Compose 技术栈,并编写领域模型、总体架构、MCP 设计、Skill 设计及关键算法 ADR,定义系统“怎么做”。根据需求和架构生成开发路线及阶段任务清单,将项目拆分为课程资料、知识结构、题库诊断、知识画像、学习计划、学习 Agent、MCP/Skill、学习看板和云端部署等可独立验收的开发任务。按照任务清单逐步开发:搭建 FastAPI 后端和 Vue 3 前端,实现用户认证、课程管理、资料解析、知识结构生成、AI 辅助出题、动态诊断、掌握度计算、个性化学习计划及渐进式辅导 Agent。建立 CoursePilot MCP Server,封装课程资料、题库、作答记录、学习状态和计划管理等工具;同时实现资料结构化、学习诊断、计划生成和苏格拉底式辅导等可插拔 Skill。使用码道代码智能体辅助进行跨文件代码审查、缺陷定位和测试补充;后端及 MCP Server 使用 Pytest 和 Ruff 验证,前端使用 TypeScript 类型检查、ESLint 和 Vite 生产构建验证。使用 Docker Compose 完成前端、后端和 MCP Server 的容器化编排,并部署至华为云 ECS;结合华为云 SWR 镜像加速解决基础镜像拉取问题,使用 Alembic 完成数据库迁移,并通过健康检查和容器日志验证服务状态。根据实际使用结果持续迭代,修复文件上传 413、AI 长任务 504、生成题目知识点 ID 越界、诊断中断后无法继续等问题,进一步提升系统的数据一致性、容错能力和用户体验。1.6 资源总览资源名称本案例使用规格主要用途计费说明弹性云服务器 ECS通用计算增强型 ac9s.large.2;2 vCPU;4 GiB;Ubuntu 24.04 Server 64 位;60 GiB 通用型 SSD运行前端、FastAPI 后端和 MCP Server 容器0.3452元/小时 弹性公网 IP EIP全动态 BGP;按流量计费;5 Mbit/s提供网站公网访问及 SSH 运维入口0.8元/GB虚拟私有云 VPC 和安全组1 个 VPC、1 个子网、1 个安全组提供私有网络及端口访问控制免费容器镜像服务 SWR使用个人专属镜像加速地址加速拉取 Python、Node.js 和 Nginx 等 Docker 基础镜像免费华为云码道(CodeArts)代码智能体专业版辅助需求分析、架构设计、任务拆解、代码开发、测试及问题定位专业版,139元/6000万tokens免排队MaaS - Console个人使用deepseek-v4-flash用于知识结构优化、AI 辅助出题及学习辅导输入:1元/百万tokens 输出:2元/百万tokensECS 本地存储SQLite 数据库及课程上传目录,共用 ECS 系统盘保存业务数据、课程资料和调用记录已包含在本案例 ECS 云硬盘配置中二、系统方案设计2.1 技术栈层级技术选型前端Vue 3、TypeScript、Pinia、Vue Router、Vite、AxiosWeb 服务Nginx后端Python 3.11、FastAPI、Pydantic、异步 SQLAlchemy数据迁移AlembicAgent 协议Model Context Protocol(MCP)业务能力4 个可插拔 Skill大模型接入OpenAI 兼容 Provider,用户自行配置模型数据库SQLite(案例演示);可切换 PostgreSQL容器化Docker、Docker Compose云资源华为云弹性云服务器 ECS、弹性公网 IP、安全组代码托管GitCodeAI 辅助开发华为云码道(CodeArts)代码智能体2.2 总体架构用户浏览器 │ ▼ Nginx / Vue 3 前端(80/443) │ /api/* ▼ FastAPI 后端(容器内部 8000) ├── SQLAlchemy / Alembic ── SQLite 或 PostgreSQL ├── 课程资料与上传文件 ├── LLM Provider ───────── 用户配置的大模型服务 └── MCP Client │ Streamable HTTP ▼ MCP Server(容器内部 8001) ├── 13 个业务工具 └── 4 个 CoursePilot 运行时 Skill2.3 项目结构CoursePilot/ ├── backend/ # FastAPI、领域模型、服务、Alembic 与测试 ├── frontend/ # Vue 3 前端 ├── mcp-server/ # MCP Server 与业务工具 ├── skills/ # 4 个 CoursePilot 运行时 Skill ├── docs/ # 需求、架构、ADR、验收与阶段报告 ├── AGENTS.md # 项目技术规范与协作约束 ├── docker-compose.yml └── README.md2.4 MCP 与 Skill 设计CoursePilot 的 MCP Server 提供 13 个业务工具,分为四类:课程与资料:课程列表、课程结构、资料检索、资料来源;学习状态:学生画像、知识点掌握度、错题;题库与作答:题目搜索、题目详情、保存作答;计划与掌握度:读取计划、更新计划、更新掌握度。系统还实现了 4 个运行时 Skill:Skill作用course_material_structuring将课程资料整理为知识结构learning_diagnosis根据作答证据分析学习状态和错因study_plan_generator生成及动态调整学习计划socratic_tutor使用分级提示进行启发式辅导三、使用华为云码道进行规范驱动开发3.1 建立项目上下文CoursePilot 涉及课程资料、题库、诊断、知识画像、计划、Agent、MCP 和 Skill 等多个领域。如果只用一句话要求 AI “生成一个学习平台”,很容易得到功能堆叠但规则不一致的代码。因此,本项目先在仓库中沉淀以下上下文:AGENTS.md:技术栈、目录结构、编码规范和测试命令;docs/product-spec.md:产品定位、范围和冻结决策;docs/requirements.md:功能需求与验收条件;docs/domain-model.md:领域实体、关系与约束;docs/architecture.md:系统边界与调用链;docs/adr/:掌握度算法、学习计划算法、Agent 编排等架构决策。3.2 各阶段Prompt每次使用时,可以先附加这段通用要求:请先阅读 AGENTS.md、本阶段相关设计文档和现有代码。 开始修改前必须: 1. 说明当前实现基线; 2. 给出任务拆解、影响文件和数据迁移方案; 3. 明确本阶段边界; 4. 不修改与本阶段无关的模块; 5. 不覆盖用户已有修改; 6. 实现后运行相关自动化测试和质量检查; 7. 最后报告修改文件、测试结果、未完成项和已知限制。 所有新增API统一放在 /api/v1/ 下。 后端IO操作优先使用 async/await。 数据库结构变更必须使用Alembic,不使用create_all代替迁移。 前端使用Vue 3、TypeScript、Pinia和<script setup lang="ts">。前置阶段:需求与规格设计请作为产品经理和系统架构师,为 CoursePilot 建立完整的需求与设计基线。 项目定位: CoursePilot 是一个课程无关、资料驱动、证据驱动、来源可追溯的AI个性化学习教练。系统需要形成: 创建课程 → 添加资料 → 构建知识结构 → 设置学习目标 → 初始诊断 → 知识画像 → 学习计划 → 学习与练习 → 错因诊断 → 掌握度更新 → 动态调整计划 请检查当前项目骨架,并编写或完善: - docs/product-spec.md - docs/requirements.md - docs/mvp-acceptance.md - docs/user-flows.md - docs/domain-model.md - docs/skill-design.md - docs/mcp-design.md - docs/development-roadmap.md - docs/current-gap-analysis.md 具体任务: 1. 定义目标用户、用户痛点、产品定位和产品边界; 2. 将需求划分为Must、Should、Could和Won't; 3. 为每项Must需求定义正常流程、异常流程和验收条件; 4. 使用Given/When/Then编写可执行验收标准; 5. 设计课程、资料、知识点、题目、诊断、画像、计划和Agent等领域实体; 6. 设计4个业务Skill及13个MCP工具; 7. 冻结掌握度、简答题、诊断题数量、模型Provider、账号体系和课程无关性决策; 8. 将开发工作拆分为阶段0至阶段7; 9. 明确每个阶段的目标、任务、边界、验收标准和交付物。 本阶段只编写需求和设计文档,不修改业务代码。 不得提前将尚未实现的功能标记为完成。阶段0:可运行基础设施基线请执行 CoursePilot 阶段0:可运行基础设施基线。 阶段目标: 让FastAPI后端、Vue前端、异步数据库、Alembic和MCP Server形成可启动、可测试的基础工程。 具体任务: 1. 修复FastAPI启动流程,确保GET /health返回200; 2. 建立统一的SQLAlchemy Base、异步engine和AsyncSession; 3. 配置Alembic target_metadata及异步迁移环境; 4. 验证upgrade head、downgrade base、再次upgrade head; 5. 统一Python模块路径和项目依赖,消除循环引用; 6. 修复Vue 3开发启动、TypeScript检查、ESLint和生产构建; 7. 将MCP Server统一为Streamable HTTP传输,端点为/mcp; 8. 确定FastAPI后端是唯一MCP Client,移除前端直连MCP的设计; 9. 修复后端、前端和MCP Server的Dockerfile及docker-compose.yml; 10. 建立后端健康检查、MCP连通性和前端页面加载冒烟测试; 11. 更新AGENTS.md和docs/deployment.md中的启动命令。 阶段边界: - 不实现课程CRUD; - 不实现资料解析; - 不创建完整业务领域模型; - 不实现正式业务Skill和MCP工具; - 不接入真实大模型; - 不实现完整注册、登录和管理员后台。 验收要求: - 后端、前端和MCP Server均可独立启动; - Alembic往返迁移通过; - MCP Streamable HTTP调用通过; - 前端type-check、lint和build通过; - docker compose config验证通过。阶段1:课程、资料与知识结构闭环请执行 CoursePilot 阶段1:课程、资料和知识结构垂直闭环。 请重点阅读: - docs/product-spec.md - docs/requirements.md中的FR-001至FR-003 - docs/domain-model.md - docs/user-flows.md中的流程1至流程4 - docs/mvp-acceptance.md中的AC-001至AC-003 阶段目标: 完成“创建课程→添加资料→解析资料→形成知识结构”的完整闭环。 具体任务: 1. 创建Course、CourseMaterial、MaterialChunk、KnowledgePoint和KnowledgeRelation模型; 2. 编写对应Alembic迁移、约束、外键和索引; 3. 实现课程创建、列表、详情、编辑和软删除API; 4. 实现PDF、Markdown、TXT文件上传及文本粘贴; 5. 实现资料状态、失败原因、重试和删除; 6. 实现规则型文本提取和资料分块; 7. 保存文件名、页码、章节或字符范围等来源信息; 8. 实现知识点新增、编辑、删除、排序和父子层级; 9. 实现prerequisite、contains和related知识关系; 10. 防止知识点关系自引用和循环依赖; 11. 实现课程列表、课程详情、资料管理和知识结构页面; 12. 使用两门内容不同的课程验证业务代码没有学科硬编码。 阶段边界: - 不实现题库和诊断; - 不实现知识画像、掌握度和学习计划; - 不实现正式业务Skill和MCP工具; - 不调用真实大模型。 验收要求: 用户能够创建课程,上传或粘贴资料,查看解析状态、资料分块和来源,并获得可编辑的树形知识结构。阶段2:题库、诊断与作答记录请执行 CoursePilot 阶段2:题库、初始诊断和作答记录。 请重点阅读: - requirements.md中的FR-004、FR-006和FR-010 - mvp-acceptance.md中的AC-004、AC-006和AC-010 - product-spec.md中的D-002和D-003 - domain-model.md中的题目、诊断和作答实体 阶段目标: 完成“建立题库→开始诊断→逐题作答→完成诊断”的业务流程。 具体任务: 1. 创建Question、QuestionOption和QuestionSource模型; 2. 创建question_knowledge_point多对多关联表; 3. 支持单选题、判断题和简答题; 4. 实现题目新增、编辑、删除、列表、筛选和审核状态; 5. 手动题目默认confirmed,AI或导入题目默认pending; 6. 题目必须关联至少一个当前课程知识点; 7. 保存题目对应的资料分块和来源位置; 8. 创建DiagnosticAttempt和AnswerRecord; 9. 按D-003规则选择诊断题: target_count = min(max(核心知识点数量, 10), 20); 10. 题库不足时阻止诊断并提示用户补充; 11. 诊断开始时保存不可变题目快照; 12. 保存答案、正确性、作答时间、跳过状态、提示次数和最高提示等级; 13. 实现L1至L4渐进式提示,L4完整解析需要二次确认; 14. 实现题库、诊断作答和诊断结果前端页面; 15. 为AI辅助出题预留接口,但本阶段不接入真实模型。 阶段边界: - 不计算知识画像和最终掌握度; - 不实现错因诊断; - 不实现学习目标和学习计划; - 不实现业务Skill、正式MCP工具和Agent。 验收要求: 用户能够管理题库并完成一次10至20题的诊断;系统保存完整作答证据,诊断题响应不得提前泄露正确答案和解析。阶段3:知识画像、错因诊断与掌握度请执行 CoursePilot 阶段3:知识画像、错因诊断和掌握度算法。 请重点阅读: - requirements.md中的FR-007、FR-011和FR-012 - mvp-acceptance.md中的对应验收条件 - product-spec.md中的D-001和D-002 - docs/adr/ADR-003-mastery-algorithm.md 阶段目标: 将用户作答记录转换为确定、可解释、可追溯的知识画像。 具体任务: 1. 创建MasteryRecord和ErrorDiagnosis模型及Alembic迁移; 2. 实现mastery-v1确定性掌握度算法; 3. 掌握度范围为0至100,置信度范围为0至1; 4. 算法考虑正确性、难度、作答时间、提示等级、连续错误、时间间隔和前置知识; 5. 使用Decimal和ROUND_HALF_UP,禁止依赖浮点round; 6. 每次有效证据追加MasteryRecord,不覆盖历史记录; 7. 保存旧值、新值、计算依据、变化原因和关联AnswerRecord; 8. 保证同一作答记录不会重复生成掌握度记录; 9. 实现10类规则型错因判断; 10. 保存错因类型、诊断依据、置信度、建议行动和关联知识点; 11. 支持用户确认或修改错因; 12. 实现知识画像列表和掌握度证据详情API; 13. 实现掌握度、置信度、薄弱点、待复习和证据链前端页面。 阶段边界: - 大模型不能直接计算或写入掌握度; - 本阶段不得调用真实LLM; - 不实现学习目标、学习计划和Agent; - 不实现正式业务Skill和MCP工具。 验收要求: 相同输入必须产生相同掌握度结果,每次变化均可追溯到具体作答记录;未经确认的简答题不得影响掌握度。阶段4:学习目标、计划与动态调整请执行 CoursePilot 阶段4:学习目标、个性化学习计划与动态调整。 请重点阅读: - requirements.md中的FR-005、FR-008和FR-013 - mvp-acceptance.md中的对应验收条件 - docs/adr/ADR-004-study-plan-algorithm.md 阶段目标: 根据学习目标、知识画像、知识点关系和时间约束生成确定、可解释的学习计划。 具体任务: 1. 创建LearningGoal、StudyPlan和StudyTask模型及迁移; 2. 每个用户每门课程只维护一个LearningGoal; 3. 支持目标日期、目标掌握度、每日时长和每周学习日; 4. 实现study-plan-v1确定性计划算法; 5. 根据掌握度差距、重要性、复习状态、连续错误和前置关系计算优先级; 6. 使用Kahn算法对前置关系稳定拓扑排序; 7. 检测知识点关系环; 8. 将任务分配到目标日期范围内的可用学习日; 9. 每日总时长不得超过daily_minutes; 10. 超过60分钟的任务拆分为多个子任务; 11. 容量不足时返回结构化错误和调整建议; 12. 每个任务保存generation_reason和generation_basis; 13. 支持完成、跳过、延期和手动调整; 14. 支持评估是否需要重新规划; 15. 重新规划时将旧计划设为superseded,并通过previous_plan_id保留历史; 16. 实现学习目标、当前计划和历史计划前端页面。 阶段边界: - 不调用真实大模型; - 不实现Agent、业务Skill和正式MCP工具; - 不实现错题本、学习看板、日历同步和消息推送。 验收要求: 计划生成结果可重复、可解释,不违反前置关系和时间容量;用户操作任务后能够评估调整需求并保留计划版本历史。阶段5:Skill、MCP、Agent 与 LLM Provider请执行 CoursePilot 阶段5:业务Skill、MCP工具、Agent和LLM Provider。 请重点阅读: - docs/skill-design.md - docs/mcp-design.md - docs/adr/ADR-005-agent-provider-and-orchestration.md - 阶段1至阶段4已经实现的业务服务 阶段目标: 建立可配置、可审计、可降级的CoursePilot Agent体系。 具体任务: 1. 删除course_recommend、schedule_optimizer和learning_analyzer占位Skill; 2. 实现4个正式Skill: - course_material_structuring - learning_diagnosis - study_plan_generator - socratic_tutor 3. 每个Skill包含skill.py、config.yaml和async execute(params); 4. Skill不直接操作数据库,通过业务服务或MCP工具获取数据; 5. 实现13个正式MCP业务工具; 6. 将MCP工具划分为只读工具和写入工具; 7. MCP Server通过BackendGateway调用FastAPI业务API; 8. 前端不得直接连接MCP Server; 9. 实现可配置的LLM Provider抽象; 10. 支持Mock Provider和OpenAI兼容Provider; 11. 自动测试只能使用Mock/Fake Provider; 12. 创建AgentSession、AgentMessage和ToolCallLog; 13. 实现Agent会话创建、消息发送、历史查询和结束会话; 14. 实现L1至L4苏格拉底式辅导; 15. 标记course_material、ai_supplement、mixed和unverified来源; 16. 所有Skill和MCP调用保存审计记录; 17. 对API Key、Token、Cookie、密码和密钥进行递归脱敏; 18. Agent写操作必须先请求用户确认; 19. 实现Agent对话和来源展示前端页面; 20. 实现Provider和MCP不可用时的规则降级。 阶段边界: - 不实现错题本和学习看板; - 不实现管理员后台; - 不允许把具体模型写成不可替换依赖; - Skill不得复制确定性掌握度和计划算法。 验收要求: 4个Skill和13个MCP工具能够独立调用;Agent可读取课程资料、画像和计划,能够恢复会话、显示来源、记录调用并在模型不可用时降级。阶段6:错题本、看板与日志展示请执行 CoursePilot 阶段6:完整前端交互、错题本、学习看板和调用日志展示。 请先检查阶段1至阶段5的数据模型和业务调用链,特别是: - AnswerRecord - DiagnosticAttemptQuestion不可变快照 - ErrorDiagnosis - MasteryRecord - StudyPlan和StudyTask - AgentSession和ToolCallLog 阶段目标: 补齐学习数据展示、错题复习和完整前端体验。 具体任务: 1. 实现WrongQuestionState模型及Alembic迁移; 2. 按user_id、course_id和question_id聚合错题; 3. 错题内容优先读取不可变题目快照; 4. 仅将有效错误作答计入错误次数; 5. 支持按知识点、错因、状态和关键词筛选; 6. 展示历史错误、资料来源、错因证据和掌握度证据; 7. 支持标记已掌握; 8. 用户后续再次答错时自动重新打开错题状态; 9. 复用DiagnosticAttempt体系创建单题练习; 10. 实现学习看板10类确定性指标; 11. 展示今日任务、总体进度、掌握度分布、薄弱点、待复习项、错因分布、本周有效作答时长和计划完成率; 12. 实现课程级ToolCallLog查询; 13. 支持类型、状态、工具、会话、时间和分页筛选; 14. 保存日志和查询输出时均执行敏感信息脱敏; 15. 实现错题本、看板和调用日志前端页面; 16. 完善加载状态、错误提示、空状态、导航、路由参数和刷新恢复。 阶段边界: - 不修改4个Skill核心逻辑; - 不修改13个MCP工具契约; - 不修改mastery-v1和study-plan-v1; - 不实现管理员后台和阶段7部署功能。 验收要求: 错题复习、学习看板和调用日志形成前后端闭环;跨用户访问统一返回404;页面刷新后数据可以从API恢复。3.3 Skill前端美化AI直接生成的前端通常不符合我们的胃口,存在以下问题:全站仍是系统默认字体、同一字号层级和同一种 8px 圆角,页面缺少品牌辨识度。紫色高饱和主色、纯白卡片加灰边框在所有页面重复,是典型的通用 AI 后台视觉。顶栏只是文本平铺,当前页面反馈弱,宽屏松散、窄屏拥挤。首页、课程列表和登录页过度居中,信息层级单薄;题库等高频页面则过密。按钮、表单、弹窗样式在各页面重复且状态不统一,Hover、Pressed、Focus 反馈不足。加载和空状态大多只是一行文字,视觉完成度不足。因此我们可以为Code添加Skill对前端进行美化我们选用GitHub - Leonxlnx/taste-skill: Taste-Skill - gives your AI good taste. stops the AI from generating boring, generic slop · GitHub 这个67.7k Star的Github开源skill进行优化请你根据skill修改现有前端界面,做的更好看一些效果也是很明显:美化前首页美化后首页四、核心功能实现具体核心功能展示请参考仓库内的demo视频,或者通过打开网站或本地部署实际操作,这里简单展示一下界面和操作功能4.1 从课程资料生成可追溯知识结构用户可以上传 PDF、Markdown、TXT 文件,或者直接粘贴文本。后端解析后将内容切分为资料块,并保存文件、位置与内容之间的对应关系。知识结构生成时,系统不会只保存一个无法解释的标题,而是将知识点关联到原始资料。用户可以查看、调整层级和关系,降低模型幻觉对后续诊断的影响。如果知识结构生成不清晰,你可以使用AI进行结构的优化,也可以手动进行修改,使结构更加清晰4.2 基于资料的 AI 辅助出题在题库管理界面你可以手动添加题目,也可以使用AI辅助出题AI 出题只允许引用当前课程中有效的知识点 ID 和资料块 ID。模型输出后,后端还会再次校验:题型和难度是否符合请求;knowledge_point_ids 是否属于允许范围;source_chunk_id 是否来自本次课程资料;选项、答案和解析结构是否完整。如果模型第一次返回了越界 ID,系统会把错误约束和合法范围反馈给模型并重试;连续失败时停止保存,避免产生半成品题目。4.3 测验与知识画像当题库足够完整,能够覆盖全部知识点时,可以进行测验与诊断:测验过程中可以申请不同等级的提示,或者跳过,但是这和答错一样会不同程度影响你的掌握度判定!系统不会让大模型直接决定最终掌握度,而是使用确定性规则综合以下证据:作答是否正确;题目难度;作答耗时;提示次数与提示等级;最近正确率;是否重复犯错;前置知识掌握情况。每次掌握度变化都会保存旧值、新值、变化原因和关联作答记录,用户能够查看“为什么发生了这次变化”。错题可以在“错题本”中进行复习,或者重新做题:4.4 学习计划与动态调整用户可以设置目标日期、目标掌握度、每日学习时长和每周可学习日期。系统根据知识画像、知识点重要程度、前置关系、历史错题和可用时间生成学习任务。当用户完成任务、连续答错或掌握度明显变化时,系统可以触发重新规划,并保留计划版本和调整原因。同时用户也可以在学习看板上查看一系列学习数据:4.5 渐进式学习辅导 Agent学习辅导 Agent 通过 MCP 工具读取当前课程资料、知识结构、学生画像和学习计划,再由 Skill 控制提示节奏:L1:提醒相关知识点;L2:指出思路方向;L3:给出关键步骤;L4:在用户确认后给出完整解析。回复通过 SSE 流式返回,并标记内容来自课程资料、AI 补充或混合来源。模型不可用时,系统可以降级为规则型提示。五、部署到华为云 ECS5.1 案例环境本案例采用一台华为云 ECS 完成演示部署:配置项案例选择区域华东-上海一ECS通用计算增强型,2 vCPU / 4 GiB操作系统Ubuntu 24.04 Server 64 位系统盘通用型 SSD,60 GiB公网访问弹性公网 IP,按流量计费,5 Mbit/s容器编排Docker Compose安全组:端口用途来源建议22SSH 运维仅允许管理员当前公网 IP /3280HTTP0.0.0.0/0443HTTPS0.0.0.0/05.2 登录服务器这里我采用的是密钥对登录:$key = "D:\EdgeDownload\KeyPair-e9f4.pem" icacls $key /inheritance:r icacls $key /grant:r "$($env:USERDOMAIN)\$($env:USERNAME):(R)" icacls $key先执行这一步是为了防止Window私钥文件权限过宽然后执行登录:ssh -i $key root@115.120.251.215.3 安装 Docker 和 Git登录 ECS 后执行:apt update apt install -y ca-certificates curl git install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo ${UBUNTU_CODENAME:-$VERSION_CODENAME}) stable" \ > /etc/apt/sources.list.d/docker.list apt update apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin systemctl enable --now docker docker --version docker compose version这里可能会出现报错,可能是因为访问 Docker 官方源被重置。直接改用华为云 Docker 镜像源即可。curl -fsSL https://mirrors.huaweicloud.com/docker-ce/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.huaweicloud.com/docker-ce/linux/ubuntu $(. /etc/os-release && echo ${UBUNTU_CODENAME:-$VERSION_CODENAME}) stable" \ > /etc/apt/sources.list.d/docker.list apt update apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin systemctl enable --now docker5.4 克隆 CoursePilot输入:cd /opt git clone cid:link_7.git cd CoursePilot5.5 创建生产环境变量先生成三个密钥,分别复制输出结果:python3 -c "import secrets; print(secrets.token_urlsafe(48))" python3 -c "import secrets; print(secrets.token_urlsafe(48))" python3 -c "import base64,secrets; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode())"创建环境变量文件:nano .env填入:SECRET_KEY=第一个随机值 MCP_INTERNAL_API_KEY=第二个随机值 LLM_CREDENTIAL_ENCRYPTION_KEY=第三个随机值 ALLOWED_ORIGINS=["http://你的EIP"]保存退出即可。5.6 添加持久化配置现有 Compose 没有持久化 SQLite 和上传文件,所以不要直接启动。创建覆盖文件:nano docker-compose.override.yml填入:services: backend: environment: DATABASE_URL: sqlite+aiosqlite:////data/coursepilot.db DEBUG: "False" SECRET_KEY: ${SECRET_KEY} LLM_CREDENTIAL_ENCRYPTION_KEY: ${LLM_CREDENTIAL_ENCRYPTION_KEY} MCP_INTERNAL_API_KEY: ${MCP_INTERNAL_API_KEY} MCP_SERVER_URL: http://mcp-server:8001/mcp UPLOAD_DIR: /data/uploads ALLOWED_ORIGINS: '${ALLOWED_ORIGINS}' volumes: - ./data:/data restart: unless-stopped frontend: restart: unless-stopped mcp-server: environment: BACKEND_API_URL: http://backend:8000/api/v1 MCP_INTERNAL_API_KEY: ${MCP_INTERNAL_API_KEY} restart: unless-stopped保存退出,创建数据目录:mkdir -p data/uploads chmod 700 data5.7. 构建并启动docker compose build --pull如果出现报错可能是因为Docker Hub 在大陆网络访问超时。需要给 Docker 配置华为云 SWR 镜像加速器。在华为云控制台:切换到“华东-上海一”。搜索并进入“容器镜像服务 SWR”。左侧选择“镜像资源 → 镜像中心”。点击“镜像加速器”。复制地址在ECS执行:mkdir -p /etc/docker nano /etc/docker/daemon.json填入复制的真实地址:{ "registry-mirrors": [ "https://xxxxxxxx.mirror.swr.myhuaweicloud.com" ] }保存退出即可!然后拉取基础镜像:docker pull python:3.11-slim docker pull node:20-alpine docker pull nginx:alpine三个都成功后,重新构建:cd /opt/CoursePilot docker compose build5.8 文件上传问题解决课程文件上传和 AI 知识结构优化都可能超过 Nginx 默认限制。可以在 /api/ 代理中补充:server { listen 80; server_name _; client_max_body_size 20m; location /api/ { proxy_pass http://backend:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 60s; proxy_send_timeout 300s; proxy_read_timeout 300s; } }修改后重新构建并启动前端容器:docker compose build frontenddocker compose up -d --no-deps frontend六、问题排查与踩坑复盘AI生成的代码在一些小细节上会出现疏忽和错误,同时部署过程中一些文件的配置不完全也可能会带来一些问题。这里是我列出的一部分可能会出现的问题可解决方案,如果大家部署过程中产生错误可参考以下内容:6.1 Docker Hub 连接超时现象failed to resolve source metadata for docker.io/library/python:3.11-slimdial tcp ...:443: i/o timeout原因ECS 访问 Docker Hub 不稳定,构建阶段无法获取基础镜像元数据。解决配置华为云 SWR 镜像加速器,先单独执行 docker pull 验证,再重新执行 Compose 构建。拉取完成后若 referrers 请求偶发超时,可重试构建。6.2 Alembic 找不到 app 模块现象ModuleNotFoundError: No module named 'app'原因迁移进程启动时,后端源码目录没有进入 Python 模块搜索路径。解决docker compose run --rm \ -e PYTHONPATH=/app/backend \ backend python -m alembic upgrade head6.3 上传课程资料返回 413现象Request failed with status code 413原因请求在进入 FastAPI 前就被 Nginx 的默认请求体大小限制拒绝。解决在 Nginx server 中设置 client_max_body_size,同时保证该值不小于后端允许的上传上限。6.4 AI 优化知识结构返回 504现象Request failed with status code 504原因模型需要读取多份资料并生成分层结构,耗时超过 Nginx 默认代理等待时间。解决提高 proxy_read_timeout 和 proxy_send_timeout。更长期的方案是将长任务改造成异步任务,并通过任务状态接口或 SSE 返回进度。6.5 模型返回越界知识点 ID现象第 4 道题结构不合法:knowledge_point_ids 不在允许范围内原因旧逻辑只重试题型和难度错误,知识点 ID 到保存阶段才校验,模型没有纠正机会。解决将知识点 ID 和资料块 ID 校验前移到模型重试阶段,反馈非法值与允许范围;连续失败则停止整批保存。6.6 诊断退出后无法再次进入现象该课程已有进行中的诊断,attempt_id=...原因后端正确阻止了重复创建,但前端没有恢复已有 attempt 的入口。解决将“开始诊断”设计为幂等操作:发现进行中的 attempt 时直接返回原记录,前端显示“继续诊断”,再从下一道未答题恢复。八、案例总结CoursePilot 的开发让我认识到,AI Agent 应用的难点不只是“接入一个大模型”,而是如何把模型放进一个可信、可解释、可恢复的业务闭环中。在开发阶段,华为云码道(CodeArts)代码智能体的价值主要体现在:通过 Codebase 理解跨前后端、MCP 与 Skill 的项目上下文;将自然语言需求拆解成可执行、可追踪的开发任务;在多文件修改、测试补充和日志排障中提高效率;结合仓库规范与验收条件,减少无边界生成;帮助整理从本地开发到 ECS 部署的完整过程。在运行阶段,CoursePilot 则通过资料来源、确定性算法、用户确认、调用审计和降级策略约束大模型,让 AI 真正服务于学习过程,而不是只生成看似合理的答案。九、参考资料华为云社区 HCSD 板块华为云码道(CodeArts)代码智能体产品介绍华为云码道(CodeArts)代码智能体下载安装CoursePilot GitCode 项目仓库
-
一、概述1.1 案例介绍银发智伴(ElderlyCare AI) 是一款面向子女、老年家庭成员和应用后台管理员三类用户的智能体检报告管理应用。子女可在 PC 端上传父母的 PDF、JPG 或 PNG 体检报告,系统通过 OCR 识别、指标提取和大模型健康解读,将专业检验结果转换为通俗说明、健康建议和饮食计划;随后生成适老化 H5 分享链接与二维码,父母通过手机即可查看大字版报告并使用语音播报。后台管理员负责用户状态、角色、系统概览和审计信息管理,不参与用户报告内容的日常操作。本案例采用 FastAPI、Vue 3、SQLite、Redis、Nginx 和华为云 ECS 构建,集成华为云 OBS 与 OCR,并使用华为云码道(CodeArts)代码智能体完成需求分析、存量代码理解、任务拆解、增量开发和问题调试。应用还提供家庭成员管理、历年指标趋势、异常变化提醒、报告对比、分享密码、访问次数限制和后台治理,形成“报告上传、智能解析、健康解读、长期跟踪、适老分享、后台治理”的完整业务闭环。GitCode 源码与演示视频:https://gitcode.com/SDSXshlbz/elderlycare-ai本案例中的演示账号、家庭成员和体检指标均为合成数据,不对应任何真实个人。健康解读仅供参考,不构成医疗诊断建议。1.2 适用对象企业开发者个人开发者高校学生学习本案例前,建议具备 Python、JavaScript、Linux 常用命令和 HTTP API 的基础知识。1.3 案例时间本案例总时长预计90分钟,其中云资源准备约20分钟,项目配置与部署约40分钟,功能验证与资源清理约30分钟。1.4 案例流程[1. 准备云资源] | v [2. 配置项目与密钥] -> [3. 构建 PC/H5 前端和 FastAPI 后端] | v [5. H5适老分享] <- [4. OCR识别、指标提取与健康解读]说明:在华为云创建 ECS、VPC、安全组、EIP 和 OBS 桶,公网仅长期开放演示所需的 80 端口;准备华为云 AK/SK、OCR、OBS 和大模型配置,通过 .env 注入运行参数,不将密钥写入源码;将源码上传到 Ubuntu 22.04 ECS,执行 deploy_ecs.sh,自动安装依赖、构建两个前端并配置 Nginx、Redis 和 systemd;用户上传报告后,后端依次完成 OCR 降级识别、指标提取、风险判定、健康解读和饮食计划生成;子女在 PC 端查看趋势和对比结果,并生成带二维码、可选访问密码和语音播报的适老化 H5 分享页面。1.5 资源总览本案例使用按需计费资源,建议将完整体验控制在2小时内。不同区域和活动价格可能变化,实际费用以华为云控制台订单页为准。体验完成后请及时释放 ECS、EIP 和不再使用的 OBS 数据,避免产生多余费用。资源名称规格单价(元)弹性云服务器 ECS通用计算增强型 c7.large.2 | 2 vCPUs | 4 GiB | Ubuntu 22.04 Server | 40 GiB GPSSD以控制台实时价格为准弹性公网IP(Elastic IP,简称EIP)按流量计费 | 5Mbit/s按实际公网流量计费虚拟私有云 VPC 和安全组1个VPC、1个子网、1个安全组VPC和安全组本身免费对象存储服务 OBS标准存储,用于报告文件、二维码等对象按存储量与请求次数计费文字识别 OCR通用文字识别、通用表格识别按调用量计费或使用套餐包华为云码道(CodeArts)代码智能体通用体验版以开通页面为准阿里云百炼大模型 APIqwen-turbo、qwen-vl-ocr、qwen-vl-plus按模型调用量计费二、环境和资源准备2.1 购买华为云 ECS 弹性云服务器登录华为云控制台,依次进入 服务列表 > 计算 > 弹性云服务器 ECS,点击 购买弹性云服务器。计费模式选择 按需计费,区域选择 北京四 cn-north-4,规格选择 通用计算增强型 c7.large.2,2 vCPUs,4 GiB。镜像选择 Ubuntu Server 22.04 64bit,系统盘选择 40 GiB GPSSD。创建或选择 VPC 与子网,购买 5Mbit/s、按流量计费 的弹性公网 IP。创建安全组,长期入方向规则只放行 TCP/80。部署期间如需 SSH,可临时放行 TCP/22,并将源地址限制为管理员当前公网 IP,部署完成后立即删除 22 端口规则。点击 立即购买,确认按需资源并等待 ECS 状态变为“运行中”。记录 ECS 公网 IP,后文用 <ECS公网IP> 表示。关键节点说明:安全组只控制云侧入站流量,Nginx 仍需在实例内监听 80 端口。后端 Uvicorn 仅监听 127.0.0.1:8005,不能绕过 Nginx 直接从公网访问。2.2 准备华为云 OBS、OCR 和访问密钥进入 服务列表 > 存储 > 对象存储服务 OBS,创建私有桶,例如 elderlycare,区域需与 ECS 一致。进入 服务列表 > 人工智能 > 文字识别 OCR,开通通用文字识别和通用表格识别。点击控制台右上角用户名,进入 我的凭证 > 访问密钥,创建并妥善保存 AK/SK。在 我的凭证 > API凭证 中记录项目 ID,项目所属区域应为 cn-north-4。AK/SK 具有云资源访问权限,只能写入服务器上的 .env,不得提交到 Git、案例文档、截图或前端代码中。OBS 桶保持私有,文件由后端 SDK 访问。2.3 准备大模型与 OCR 降级服务登录阿里云百炼控制台,地址:https://dashscope.console.aliyun.com/,开通 DashScope 服务。在 API-KEY 管理 中创建 API Key,并确认账号可调用 qwen-turbo、qwen-vl-ocr 和 qwen-vl-plus。将 API Key 仅配置在 .env 中。项目首先调用华为云 OCR;若该调用失败,再依次尝试 qwen-vl-ocr 和 qwen-vl-plus,避免单一识别服务异常导致整条解析链路不可用。2.4 准备本地和云端环境本案例以 Windows 作为开发端、Ubuntu 作为运行端,建议环境如下:环境软件及版本用途Windows 10/11PowerShell 5.1+、OpenSSH Client、tar.exe源码检查、测试、打包和上传本地 PythonPython 3.10+,本案例测试环境为 Python 3.12后端测试本地 Node.jsNode.js 20、npm 10PC/H5 生产构建Ubuntu ECSUbuntu 22.04、Python 3.10、Node.js 20、Nginx、Redis演示环境运行执行以下命令复制配置模板:Copy-Item .env.example .env编辑 .env,将占位内容替换为实际配置。不要删除未使用的键,也不要在等号两侧添加多余引号:HUAWEI_CLOUD_AK=你的华为云AK HUAWEI_CLOUD_SK=你的华为云SK HUAWEI_CLOUD_REGION=cn-north-4 HUAWEI_CLOUD_PROJECT_ID=你的华为云项目ID OBS_BUCKET_NAME=elderlycare OBS_ENDPOINT=obs.cn-north-4.myhuaweicloud.com JWT_SECRET_KEY=至少32字节的随机字符串 REDIS_URL=redis://localhost:6379/0 DATABASE_URL=sqlite+aiosqlite:///./elderlycare.db MCP_SERVER_URL= LLM_API_KEY=你的千问APIKey LLM_API_BASE=https://dashscope.aliyuncs.com/compatible-mode/v1 LLM_MODEL_NAME=qwen-turbo ALIYUN_OCR_API_KEY=你的阿里云OCR_APIKey ALIYUN_OCR_MODEL=qwen-vl-ocr SHARE_BASE_URL=http://<ECS公网IP>/h5在 Windows PowerShell 中生成随机 JWT 密钥:$bytes = New-Object byte[] 48 [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes) [Convert]::ToBase64String($bytes) 三、构建银发智伴应用3.1 使用 CodeArts 代码智能体创建项目登录华为云码道(CodeArts),创建 Python + Vue 3 项目。在 CodeArts IDE 中输入以下需求描述,让代码智能体先理解目标和约束,再结合本案例存量源码进行增量开发:创建“银发智伴”体检报告管理应用。后端使用 Python FastAPI 和 SQLAlchemy Async,PC 端与 H5 端使用 Vue 3。子女在 PC 端上传父母体检报告,后端通过 OCR 提取指标,生成健康解读、饮食计划、趋势分析和报告对比;H5 使用大字号、清晰风险标签和中文语音播报。项目部署到 Ubuntu ECS,由 Nginx 统一提供 PC、H5 和 API 入口。本项目工作区保留了代码智能体生成并持续修订的规格、设计和任务文件,使用过程如下:阶段代码智能体产物或操作人工确认的关键节点需求规格化.codeartsdoer/specs/elderlycare_ai/spec.md明确子女、父母、管理员三类角色,以及“仅提供健康参考、不替代医生诊断”的职责边界存量代码分析.codeartsdoer/specs/elderlycare_ai/design.md对照现有认证、报告和分享模块,判断哪些功能复用、哪些功能增量扩展,避免大幅改变原有结构任务拆解.codeartsdoer/specs/elderlycare_ai/tasks.md将工作拆分为认证、报告、OCR、健康解读、分享、管理员、测试和部署等可验证任务代码开发根据任务逐个生成或补全 FastAPI 服务、Vue 页面和部署配置审查接口权限、异步数据库事务、上传限制、异常映射和前后端字段契约调试验证结合错误日志定位登录、复制、H5 子路径和 Ubuntu 兼容问题每次修复后执行后端测试、两个前端生产构建和 ECS 健康检查本案例使用代码智能体辅助完成的典型调试过程如下:登录错误调试:根据后端日志和认证服务调用链,发现错误凭据触发的业务异常未正确映射。修正空用户判断和异常处理器后,错误账号由 HTTP 500 变为 HTTP 401,并返回“账号或密码错误”;分享链接复制调试:公网演示环境使用 HTTP,浏览器可能禁用安全上下文中的 Clipboard API。智能体协助定位兼容性原因,并在 navigator.clipboard.writeText() 失败时使用 document.execCommand('copy') 回退;Windows 到 Ubuntu 迁移调试:检查 CRLF/LF、文件名大小写、依赖锁文件和路径分隔符;前端使用 npm ci 复现依赖,部署脚本保持 LF,源码导入路径与真实文件名大小写一致;H5 子路径调试:统一 Vite base: '/h5/'、Vue Router 的 import.meta.env.BASE_URL 与 Nginx try_files,解决分享深层路由刷新 404;验证闭环:本地运行 python -m pytest tests -q,分别执行 PC/H5 的 npm run build,部署后访问 /health,并验证登录、趋势、对比、分享和管理员接口。代码智能体用于加速分析、编码和定位问题,不能替代人工评审。代码生成后必须逐项检查权限边界、异常处理、上传限制、密钥加载、医疗免责声明和敏感信息,并通过测试及生产构建后才能部署。3.2 部署项目代码1)解决方案总体设计银发智伴采用“多端访问、统一 API、智能服务可降级、云上统一接入”的解决方案。PC 端承载报告管理、趋势对比和后台治理,H5 端专注适老化查看与语音播报;Nginx 提供统一公网入口,FastAPI 编排认证、报告、分享和智能解析流程;OBS 保存私有报告对象,SQLite 保存结构化业务数据,Redis 保存令牌黑名单和运行期状态。OCR 与大模型均设置超时、错误处理和本地降级,避免第三方服务短暂不可用时整个应用失效。用户上传报告后,请求依次经过文件校验、私有存储、OCR 识别、指标提取、风险判定、大模型健康解读和合规过滤;处理状态通过状态机管理。子女可在 PC 端查看结果、趋势和对比,也可生成带随机状态 ID、有效期、可选密码和访问次数限制的分享链接。父母通过 H5 查看大字版内容;管理员通过角色鉴权后的接口查看系统概览和管理用户。2)系统架构设计用户层:PC 子女端 / H5 父母端 / PC 管理后台 | 接入层:EIP + Nginx(/、/h5/、/api/、/health) | 应用层:FastAPI API / JWT认证 / 报告 / 分享 / 趋势 / 对比 / 管理 | 智能层:华为云OCR -> 百炼OCR -> Qwen VL / MCP大模型 / 合规工具 / 本地规则 | 数据层:SQLite业务数据 / Redis状态与令牌 / OBS私有对象 | 运维层:systemd / 健康检查 / 审计日志 / 华为云安全组架构关键点:公网只暴露 Nginx 的 80 端口,FastAPI 仅监听 127.0.0.1:8005;PC、H5 与 API 共用同一主机,减少跨域配置;智能服务通过统一服务层调用,业务 API 不直接依赖某一家模型厂商;配置和密钥全部由 .env 注入,仓库只提供不含真实值的 .env.example。核心技术难点与解决思路核心难点解决思路验证方式OCR 服务超时、配额不足或结果为空依次调用华为云 OCR、百炼 OCR 和 Qwen VL,仅在获得有效文本时结束;全失败时明确标记报告失败Mock 各级返回值,检查降级顺序和失败状态大模型输出不稳定且健康内容有合规风险传入结构化指标,以系统提示词约束输出;执行合规过滤并固定展示免责声明;调用失败时使用本地规则生成基础解读断开模型服务后仍能生成可查看的基础结果报告解析耗时,用户难以判断进度使用 OCR_PROCESSING、EXTRACTING、INTERPRETING、COMPLETED、FAILED 状态机,并通过 SSE 推送进度检查页面进度变化及异常后最终状态Windows 开发代码迁移到 Ubuntu锁定 Python/Node 依赖,使用 npm ci;Shell 脚本使用 LF;检查源码路径大小写,不使用 Windows 专属路径本地测试、双前端生产构建和 ECS 健康检查均通过H5 部署在 /h5/ 后深层路由刷新 404Vite base、Router base 和 Nginx try_files 使用一致的 /h5/ 前缀直接访问 /h5/share/<state_id> 返回 HTTP 200HTTP 演示站点复制分享链接失败优先使用 Clipboard API,失败时回退到隐藏文本框和 document.execCommand('copy')本地 HTTPS/localhost 与 ECS HTTP 环境分别点击复制医疗报告、账号和后台权限安全bcrypt 保存密码,JWT 鉴权,失败次数锁定,角色依赖保护管理员接口,OBS 私有存储并记录审计日志错误登录返回 401,普通用户访问管理员接口返回 4033)通过 GitCode 下载源码并了解项目结构本案例源码公开托管于 GitCode:https://gitcode.com/SDSXshlbz/elderlycare-ai。在 Windows PowerShell 或 Ubuntu 终端执行:git clone https://gitcode.com/SDSXshlbz/elderlycare-ai.git cd elderlycare-ai仓库不包含 .env、数据库、用户上传文件或真实医疗图片。克隆后需根据 .env.example 创建本地 .env 并填写自己的服务配置。项目结构如下:├── app/ # FastAPI后端 │ ├── api/ # 登录、报告、分享、趋势、对比等API路由 │ ├── core/ # 配置、数据库、安全、OBS、OCR、异常处理 │ ├── mcp/ # 大模型调用和本地工具降级 │ ├── models/ # SQLAlchemy ORM模型 │ ├── schemas/ # 请求和响应数据模型 │ ├── services/ # 认证、报告、解析、解读、分享等业务服务 │ └── main.py # FastAPI入口、路由和健康检查 ├── frontend/ │ ├── pc/ # 子女使用的PC端Vue 3应用 │ │ └── src/views/ # 工作台、详情、趋势、对比、家庭成员等页面 │ └── h5/ # 父母使用的适老化H5应用 │ └── src/views/SharePage.vue # 大字版健康报告和语音播报 ├── mcp_server/ # 可独立运行的模型编排与工具服务 ├── migrations/ # Alembic数据库版本记录 ├── tests/ # 后端单元测试与集成测试 ├── deploy_ecs.sh # Ubuntu ECS一键部署脚本 ├── requirements.txt # 固定版本的Python依赖 └── .env.example # 环境变量模板,不包含真实密钥 项目采用前后端分离和 API、服务、模型分层结构。浏览器请求先到 app/api/ 路由层,Pydantic app/schemas/ 完成输入输出校验,app/services/ 编排业务规则,app/models/ 通过异步 SQLAlchemy 持久化数据;OCR、OBS、安全和异常处理集中在 app/core/,模型调用与合规、营养、参考范围工具位于 app/mcp/。PC 与 H5 分别构建为静态文件,Nginx 将 / 映射到 PC,将 /h5/ 映射到 H5,将 /api/ 和 /health 反向代理到 FastAPI。4)在 Windows 本地执行构建与测试在项目根目录执行后端测试:.\.venv\Scripts\python.exe -m pytest tests -q预期结果:54 passed分别构建 PC 和 H5 生产包:Set-Location frontend\pc npm ci npm run build Set-Location ..\h5 npm ci npm run build Set-Location ..\.. npm ci 会严格按照 package-lock.json 安装依赖,避免 Windows 和 Ubuntu 使用不同依赖版本。两个 npm run build 均应成功生成各自的 dist 目录。PC 端构建时可能提示 ECharts 相关分块超过 Vite 默认的 500 KB 建议阈值,该提示不影响产物生成,后续可通过 manualChunks 进一步拆包。依赖审计警告不会阻断构建,但应单独评估,不建议直接执行可能引入破坏性升级的 npm audit fix --force。5)关键代码讲解OCR 三级降级机制(app/core/ocr_client.py)OCR 是报告解析的入口。代码先调用华为云通用文字和表格识别;如果没有识别到有效文本,再调用百炼 OCR 模型;最后使用千问 VL 多模态模型兜底。每一级仅在返回非空文本时结束链路,所有方法失败时返回空结果并由解析状态机标记失败。async def recognize_medical_report(self, image_data: bytes, file_type: str = "image") -> dict: image_b64 = base64.b64encode(image_data).decode("utf-8") result = await self._try_huawei_ocr(image_b64) if result: return result result = await self._try_aliyun_ocr(image_b64, file_type) if result: return result result = await self._try_qwen_vl(image_b64, file_type) if result: return result logger.error("All OCR methods failed (huawei -> aliyun -> qwen-vl)") return {"text": "", "confidence": 0.0} 关键释义:base64.b64encode() 将图片转为云 OCR API 可接收的 Base64 内容;降级调用相互独立,单个云服务超时或配额不足不会立即终止处理;日志只记录调用结果和错误,不输出图片、AK/SK 或 API Key;最终空文本不是伪造成功结果,业务层会将报告标记为 FAILED,便于用户重新处理。报告解析状态机和指标风险判定(app/services/parse_service.py)报告处理依次进入 OCR_PROCESSING、EXTRACTING、INTERPRETING 和 COMPLETED。前端根据状态显示处理进度;任何未捕获异常都会进入 FAILED,避免报告长期停留在处理中。await self._update_status(report, ParseStatus.OCR_PROCESSING) ocr_text = await self._run_ocr(report) if not ocr_text or not ocr_text.strip(): report.status = ParseStatus.FAILED await self.db.flush() return await self._update_status(report, ParseStatus.EXTRACTING) indicators = self._extract_indicators(ocr_text) abnormal = [i for i in indicators if i.status != IndicatorStatus.NORMAL] if abnormal: names = [i.name for i in abnormal[:5]] report.abnormal_summary = f"发现{len(abnormal)}项异常指标: {', '.join(names)}" await self._update_status(report, ParseStatus.INTERPRETING) report.status = ParseStatus.COMPLETED指标提取阶段会校验名称长度、医学单位、数值与参考范围。高于上限标记为 HIGH,低于下限标记为 LOW;偏离比例达到 1.2 或 1.5 时,风险等级依次提升为中风险或高风险。大模型健康解读与本地降级(app/mcp/mcp_client.py)后端使用 OpenAI 兼容接口调用配置的大模型,系统提示词约束输出范围,用户提示词携带结构化指标。HTTP 状态异常通过 raise_for_status() 进入异常分支;大模型不可用时,generate_interpretation() 会调用本地规则生成基础解读,保证报告仍可查看。async def _call_llm(self, system_prompt: str, user_prompt: str, temperature: float = 0.7) -> str: if not self._can_call_llm(): raise AppException(40004, "LLM API 未配置") async with httpx.AsyncClient(timeout=settings.LLM_TIMEOUT, proxy=None) as client: response = await client.post( f"{self._llm_api_base}/chat/completions", json={ "model": self._llm_model, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], "temperature": temperature, }, headers={"Authorization": f"Bearer {self._llm_api_key}"}, ) response.raise_for_status() data = response.json() return data.get("choices", [{}])[0].get("message", {}).get("content", "") 登录失败返回业务错误而不是服务器内部错误(app/services/auth_service.py、app/core/exceptions.py)登录时先判断用户是否存在,再校验 bcrypt 密码。账号不存在或密码错误均抛出业务码 60003,统一异常处理器将其映射为 HTTP 401。这样错误凭据不会因为空用户访问、密码哈希异常或未处理业务异常而显示“服务器内部错误”。if user is None: raise AppException(60003, "账号或密码错误") if not verify_password(password, user.password_hash): user.login_fail_count += 1 if user.login_fail_count >= settings.LOGIN_MAX_FAILURES: user.status = AccountStatus.LOCKED user.locked_until = datetime.utcnow() + timedelta( minutes=settings.LOGIN_LOCK_MINUTES ) await self.db.flush() raise AppException( 60002, f"密码错误次数过多,账号已锁定{settings.LOGIN_LOCK_MINUTES}分钟", ) await self.db.flush() raise AppException( 60003, f"账号或密码错误,还剩{settings.LOGIN_MAX_FAILURES - user.login_fail_count}次机会", ) if exc.code in (60002, 50005): status_code = 429 elif exc.code in (60003, 60004): status_code = 401 连续失败达到阈值后账号临时锁定,可以降低暴力尝试风险;成功登录后失败次数会被清零,并签发访问令牌和刷新令牌。报告分享、二维码和访问限制(app/services/share_service.py)分享状态使用随机 UUID,默认30天有效。可选4位数字访问密码使用 bcrypt 哈希保存,数据库中不存储明文;同时支持访问次数上限、失败次数锁定和主动撤销。state_id = str(uuid.uuid4()) expire_time = datetime.utcnow() + timedelta( days=settings.SHARE_DEFAULT_EXPIRE_DAYS ) password_hash = None if access_password: if not access_password.isdigit() or len(access_password) != 4: raise AppException(10001, "访问密码需为4位数字") password_hash = _bcrypt.hashpw( access_password.encode("utf-8"), _bcrypt.gensalt() ).decode("utf-8") share_url = f"{settings.SHARE_BASE_URL}/share/{state_id}" qr = qrcode.QRCode(version=1, box_size=10, border=5) qr.add_data(share_url) qr.make(fit=True) H5 适老化语音播报(frontend/h5/src/views/SharePage.vue)H5 使用浏览器原生 Web Speech API,无需额外安装播放器。播报内容由健康解读、建议、注意事项和指标组成,语速设置为 0.8,优先选择中文语音;用户再次点击按钮时立即停止。function toggleSpeech() { if (!speechSupported.value) return const synth = window.speechSynthesis if (isSpeaking.value) { synth.cancel() isSpeaking.value = false return } speechUtterance = new SpeechSynthesisUtterance(getSpeechText()) speechUtterance.lang = 'zh-CN' speechUtterance.rate = 0.8 speechUtterance.pitch = 1.0 speechUtterance.volume = 1.0 synth.speak(speechUtterance) isSpeaking.value = true } H5 子路径适配(frontend/h5/vite.config.ts、frontend/h5/src/router/index.ts)生产环境将 H5 部署在 /h5/,构建资源路径和 Vue Router 必须使用同一个基础路径,否则在 Ubuntu Nginx 下刷新分享深层路由会出现资源 404 或空白页。export default defineConfig({ base: '/h5/', plugins: [vue()], }) const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/share/:stateId', name: 'SharePage', component: () => import('../views/SharePage.vue'), }, ], }) 6)打包并上传源码不要上传 .env 等本地敏感文件,也不要上传真实 elderlycare.db、测试数据库、医疗图片、.venv、node_modules 和 dist。在 Windows PowerShell 的项目根目录执行:tar.exe -czf elderlycare-deploy.tar.gz ` --exclude='.venv' ` --exclude='*/node_modules' ` --exclude='*/dist' ` --exclude='.env' ` --exclude='elderlycare.db' ` --exclude='test.db' ` --exclude='*.jpg' ` . scp .\elderlycare-deploy.tar.gz root@<ECS公网IP>:/tmp/ scp .\.env root@<ECS公网IP>:/tmp/elderlycare.env ssh root@<ECS公网IP> 如果使用 SSH 密钥,则在三个 SSH/SCP 命令中增加 -i <私钥路径>。上传完成后,在 ECS 中执行:sudo mkdir -p /opt/elderlycare sudo tar -xzf /tmp/elderlycare-deploy.tar.gz -C /opt/elderlycare sudo install -m 600 /tmp/elderlycare.env /opt/elderlycare/.env cd /opt/elderlycare sudo chmod +x deploy_ecs.sh sudo ./deploy_ecs.sh也可以先在 Windows PowerShell 中单独上传仅保存在本地的 .env:scp .\.env root@<ECS公网IP>:/tmp/elderlycare.env ssh root@<ECS公网IP> 登录 ECS 后,直接通过 GitCode 拉取公开源码并部署:/opt/elderlycare 是 Ubuntu ECS 上的绝对安装目录,不是 GitCode 仓库中的 opt 文件夹。git clone 命令的第二个参数会把仓库内容直接检出到该目录;后续部署脚本、Nginx 和 systemd 均统一使用此路径。sudo mkdir -p /opt/elderlycare sudo chown -R "$USER:$USER" /opt/elderlycare git clone https://gitcode.com/SDSXshlbz/elderlycare-ai.git /opt/elderlycare sudo install -m 600 /tmp/elderlycare.env /opt/elderlycare/.env cd /opt/elderlycare sudo chmod +x deploy_ecs.sh sudo ./deploy_ecs.sh关键节点说明:GitCode 只传输可公开的源码和合成演示截图,.env 必须沿独立安全通道上传。后续更新可在确认服务器无未提交修改后执行 git pull --ff-only,再重新运行 deploy_ecs.sh;数据库和用户上传文件应提前备份,不能用代码仓库代替业务数据备份。7)理解并执行一键部署脚本deploy_ecs.sh 使用 set -euo pipefail,任一关键命令失败都会终止部署。脚本执行七个阶段:安装系统依赖、准备运行用户、安装 Python 依赖、构建 PC/H5、配置 Nginx、注册 systemd 服务、执行健康检查。Nginx 的关键配置如下:location /h5/ { alias /opt/elderlycare/frontend/h5/dist/; index index.html; try_files $uri $uri/ /h5/index.html; } location /api/ { proxy_pass http://127.0.0.1:8005; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 120s; } location / { root /opt/elderlycare/frontend/pc/dist; index index.html; try_files $uri $uri/ /index.html; } try_files 是 PC 和 H5 深层路由刷新可用的关键。后端服务使用独立用户运行,并等待网络和 Redis:[Unit] After=network-online.target redis-server.service Wants=network-online.target redis-server.service [Service] User=elderlycare Group=elderlycare WorkingDirectory=/opt/elderlycare ExecStart=/opt/elderlycare/.venv/bin/python -m uvicorn app.main:app --host 127.0.0.1 --port 8005 Restart=always RestartSec=5 脚本结束前会轮询后端健康接口。成功时输出:Backend health check passed. ======================================== Deployment completed PC: http://<ECS_PUBLIC_IP>/ H5: http://<ECS_PUBLIC_IP>/h5/ Health: http://<ECS_PUBLIC_IP>/health ========================================8)记录数据库版本并检查服务项目启动时通过 SQLAlchemy create_all() 创建当前模型表。首次部署成功后,执行 alembic stamp head 记录当前迁移基线,不重复执行已由模型创建的历史表结构:cd /opt/elderlycare source .venv/bin/activate alembic stamp head deactivate sudo nginx -t sudo systemctl is-active nginx redis-server elderlycare curl --fail http://127.0.0.1:8005/health预期结果:nginx: configuration file /etc/nginx/nginx.conf test is successful active active active {"status":"ok","version":"1.0.0"}如健康检查失败,使用以下命令定位问题:sudo journalctl -u elderlycare -n 100 --no-pager sudo tail -n 100 /var/log/nginx/error.log常见问题与处理方法:现象原因处理方法deploy_ecs.sh: /bin/bash^MWindows CRLF 换行将脚本保存为 LF 后重新上传H5 分享链接刷新后 404Vite 基础路径或 Nginx 回退错误检查 base: '/h5/' 和 /h5/index.html登录显示服务器内部错误业务异常未映射或数据库字段不完整查看 journalctl,确认 60003 返回 401,数据库版本已记录上传后一直处理中OCR、OBS 或大模型配置错误检查 .env、OBS 区域、OCR权限及后端日志CSS/模块在 Ubuntu 找不到Windows 文件名大小写不敏感统一源码导入路径与真实文件名大小写9)安全收尾部署完成后删除包含密钥的临时文件和部署压缩包,并在安全组中删除临时 22 端口规则:rm -f /tmp/elderlycare.env /tmp/elderlycare-deploy.tar.gz服务器上的 /opt/elderlycare/.env 权限应为 600,所有者应为 elderlycare:sudo stat -c '%U:%G %a %n' /opt/elderlycare/.env预期输出:elderlycare:elderlycare 600 /opt/elderlycare/.env3.3 运行效果展示本案例已部署到华为云北京四 ECS。演示环境仅使用合成数据,环境信息如下:项目演示环境信息区域北京四 cn-north-4ECS实例elderlycare-demo,实例ID 5d96458e-5a74-47e7-8859-b78c14be13a8规格与系统c7.large.2,2 vCPU / 4 GiB,Ubuntu 22.04公网IP1.92.111.234PC端URLhttp://1.92.111.234/H5端URLhttp://1.92.111.234/h5/健康检查http://1.92.111.234/health,HTTP 200GitCode源码https://gitcode.com/SDSXshlbz/elderlycare-ai普通功能测试账号邮箱:demo@elderlycare.cn密码:Demo2026!应用后台管理员测试账号邮箱:admin20260726@elderlycare.cn密码:Sc9!Vt4#Lq7@Hm2普通账号用于演示报告上传、解读、趋势、对比和分享;管理员账号登录后进入后台管理页面,用于演示系统概览、用户列表、账号状态和角色权限。演示 ECS 当前为运行状态,公网安全组不保留 SSH 入站规则,只开放作品 Web 演示所需端口。当前地址使用 HTTP,仅用于作品演示,不要录入真实个人信息、医疗报告或其他敏感数据。正式上线应配置域名、HTTPS、数据库备份、日志脱敏和监控告警。核心功能1:报告上传与年度报告管理登录后进入工作台,选择家庭成员后拖拽或点击上传 PDF、JPG、PNG 文件。页面同步展示解析状态和历史报告。演示账号已准备 2024、2025、2026 三份年度报告,用于展示长期健康变化。关键节点说明:上传请求先校验文件数量、扩展名和大小,再将报告与家庭成员关联。后端完成 OCR、指标提取和解读后,状态变为“已完成”,点击报告名称进入详情。核心功能2:智能健康解读与饮食计划报告详情将异常指标转换为通俗说明,展示风险提示、健康建议、推荐食物、忌口食物、每日食谱和指标参考范围。每份解读固定展示医疗免责声明。执行后效果:2026年度合成报告识别出空腹血糖、总胆固醇、尿酸、收缩压和 BMI 偏高,并给出饮食控制、运动、定期监测等建议;血红蛋白显示为正常。核心功能3:历次指标趋势和异常变化提醒进入 趋势分析,可以按家庭成员和指标筛选。ECharts 折线图按报告时间排序,并使用参考范围背景区间辅助判断。执行后效果:演示数据包含6个指标,每个指标有3个年度数据点。系统可识别“正常转异常”“异常恢复”“状态变化”和“数值变化”,当前演示数据生成12条异常变化记录。核心功能4:两份报告逐项对比进入 报告对比,选择较早报告 A 与较近报告 B,点击 开始对比。后端按指标名称求交集,计算 报告B数值 - 报告A数值,并按变化绝对值排序。执行后效果:2024与2026两份报告共有6项指标。尿酸由 330 umol/L 变为 455 umol/L,收缩压由 128 mmHg 变为 148 mmHg,状态从正常变为偏高;页面同时展示 BMI、空腹血糖、总胆固醇和血红蛋白的变化。核心功能5:适老化 H5 分享与语音播报在报告详情中生成分享链接或二维码,父母通过手机打开 H5。页面采用大字号、高行距、明显风险标签和大尺寸圆形播报按钮;点击播放按钮后,图标切换为暂停,再次点击立即停止。执行后效果:在 390 × 844 移动视口下页面无横向溢出,分享接口返回6项指标;语音播报可以正常开始与暂停,H5 深层路由及生产资源均返回 HTTP 200。核心功能6:家庭成员管理进入 家庭成员,可维护父母等家庭成员的关系、性别、出生日期、身高、体重、慢性病、过敏史、用药和备注。报告关联成员后,趋势与对比功能可以按成员筛选,避免多人报告混合统计。核心功能7:应用后台管理与角色权限管理员登录后可查看系统用户、报告和分享数量,按角色或账号状态筛选用户,并执行受保护的管理操作。注册页面不提供管理员角色选择,普通用户不能通过修改前端参数自行获得管理员权限;管理员接口由后端角色依赖统一保护,并具有禁止管理员自降级和最后一名管理员保护逻辑。执行后效果:管理员账号可进入 /admin 页面,普通演示账号访问同一路由时会被前端守卫拦截,直接请求管理员 API 时后端返回 HTTP 403。角色变更记录写入审计日志,便于追溯操作者、目标用户和变更时间。功能验收结果验证项实际结果正确账号登录HTTP 200,进入工作台错误账号登录HTTP 401,返回“账号或密码错误”,无服务器内部错误报告列表3份合成年度报告趋势分析6项指标,每项3个年度数据点异常变化12条变化记录报告对比6项共有指标及数值、状态变化H5分享返回健康解读、饮食计划和6项指标二维码返回 image/png管理员权限管理员可访问后台,普通用户访问管理员接口返回 HTTP 403PC/H5控制台无错误或警告Ubuntu服务Nginx、Redis、FastAPI均为 active自动化测试54 passed演示视频已上传至gitcode四、释放资源4.1 删除ECS弹性云服务器登录华为云控制台,进入 服务列表 > 计算 > 弹性云服务器 ECS。在 ECS 列表勾选本案例创建的服务器,点击 更多 > 删除。在确认对话框中勾选 释放云服务器绑定的弹性公网IP地址;如创建了额外数据盘,同时勾选删除对应数据盘。核对实例名称和公网 IP,确认无需要保留的数据后点击 是。进入 网络 > 弹性公网IP和带宽,确认 EIP 已释放;进入 对象存储服务 OBS,删除不再需要的报告、二维码和桶;进入安全组确认不存在遗留的公网 22 端口规则。删除 ECS、EIP、系统盘或 OBS 数据属于不可逆操作。释放前请先备份需要保留的源码、数据库和日志。仅关机通常仍会产生系统盘、EIP等费用,应以控制台资源状态和账单为准。五、扩展资料说明华为云 ECS:cid:link_2华为云 OBS:cid:link_4华为云 OCR:cid:link_1华为云开发者空间:cid:link_6华为云码道 CodeArts:cid:link_7银发智伴 GitCode 源码:https://gitcode.com/SDSXshlbz/elderlycare-aiFastAPI:https://fastapi.tiangolo.com/Vue 3:https://vuejs.org/Nginx:https://nginx.org/en/docs/阿里云百炼 Model Studio:https://help.aliyun.com/zh/model-studio/
-
借助华为云 CodeArts 实现微信公众号表情包机器人一、案例背景在日常使用微信的过程中,表情包经常分散在聊天记录和收藏列表中,手动保存和整理效率较低。为提升表情包保存效率,本项目实现了一个微信公众号表情包机器人:用户向公众号发送图片或表情后,服务端自动保存图片文件,并返回可访问的下载链接。本项目采用 Python Flask 开发微信公众号回调服务,使用 Docker Compose 部署到华为云 ECS。开发过程中,主要借助华为云 CodeArts 进行技术问题咨询、实现流程拆解、部署步骤梳理和问题排查。项目仓库:https://github.com/T0ngJ1PC/wechat-bot二、项目目标本项目需要实现以下能力:接收微信公众号服务器校验请求。接收用户发送的图片或表情消息。下载图片并保存到服务器目录。返回公网可访问的图片链接。对无法直接解析的收藏表情,记录待处理任务并交由后台服务补偿处理。使用 Docker Compose 在华为云 ECS 上部署 Web 服务和后台服务。开源前排除环境变量、登录态、二维码截图、用户素材等隐私文件。三、整体架构项目整体流程如下:微信用户 -> 向公众号发送图片或表情 -> 微信服务器回调 /wechat -> Flask 服务完成签名校验和消息解析 -> 下载图片并保存到 stickers/ -> 返回图片访问链接 无法直接解析的收藏表情 -> 写入 pending_unsupported.jsonl -> scraper 后台服务读取待处理任务 -> 尝试从公众号后台私信页面补偿抓取 -> 保存图片并更新状态文件主要模块如下:模块文件作用微信公众号回调服务app.py处理服务器校验、消息接收、图片保存和管理接口后台补偿服务mp_private_scraper.py处理无法直接解析的收藏表情容器编排docker-compose.yml启动 Web 服务和 scraper 服务镜像构建Dockerfile构建项目运行环境环境变量模板.env.example提供公开配置示例部署说明README-deploy.md记录基础部署命令本项目使用的华为云资源如下:华为云资源用途CodeArts辅助梳理技术细节、实现步骤和排障方法ECS部署并持续运行微信公众号回调服务弹性公网 IP提供公网访问入口安全组控制 HTTP、HTTPS 等端口访问域名与 SSL 证书提供稳定的 HTTPS 微信公众号回调地址四、CodeArts 辅助开发过程本项目中,CodeArts 主要用于辅助完成开发过程中的具体问题分析,而不是直接替代开发过程。实际使用方式是将问题拆分为明确的技术点,再根据 CodeArts 给出的建议进行代码实现和环境验证。开发阶段向 CodeArts 咨询的问题CodeArts 给出的简要结果实际落地结果需求拆解微信公众号表情包机器人需要拆分哪些模块建议拆分为回调接入、图片保存、后台补偿、状态管理和部署运维确定 Web 回调、图片保存、后台补偿、状态管理和部署模块回调接入微信公众号服务器校验如何实现说明 signature、timestamp、nonce、echostr 的校验关系实现 /wechat GET 校验和 check_sig() 签名校验函数消息处理图片、表情和不支持消息类型如何区分处理建议按消息类型分支处理,普通图片同步保存,异常类型进入待处理流程普通图片直接保存,收藏表情进入待处理队列安全模式EncodingAESKey 配置后如何处理加密消息建议将明文模式和安全模式分支处理,先解密再解析,回复时再加密使用 WeChatCrypto 解密消息并加密回复文件保存如何判断图片格式并生成访问链接建议根据响应头判断扩展名,并使用公网基础地址拼接下载链接根据响应头识别图片类型,保存到 stickers/ 目录后台补偿收藏表情无法直接解析时如何处理建议主回调快速响应,复杂抓取逻辑交给后台任务异步执行使用 pending_unsupported.jsonl 记录任务,由 scraper 后台处理容器部署Flask 服务和后台任务如何部署建议 Web 回调和 scraper 拆成两个 Compose 服务,并共享持久化目录使用 Docker Compose 拆分 web 和 scraper 两个服务ECS 部署云服务器部署需要准备哪些步骤建议按 ECS、端口、安全组、环境变量、日志验证拆分部署清单整理 ECS、端口、安全组、环境变量和日志检查流程公网域名域名解析、备案和 SSL 证书应如何准备建议先确认域名解析和备案状态,再配置 HTTPS 证书和反向代理形成域名解析、HTTPS 入口、证书绑定和回调地址检查项开源检查哪些文件不能提交到公开仓库建议排除环境变量、登录态、二维码、token 缓存、用户素材和本地工具状态完善 .gitignore 和 .dockerignore,排除隐私文件通过这种方式,CodeArts 在项目中承担了技术助手角色,主要用于明确实现路径、减少遗漏项,并辅助形成可复用的开发和部署清单。五、核心实现1. 微信公众号服务器校验微信公众号服务器配置时,需要对 signature、timestamp、nonce 和本地配置的 WX_TOKEN 进行校验。项目中通过 check_sig() 完成签名计算:def check_sig(signature, timestamp, nonce): if not signature or not timestamp or not nonce: return False sort_list = sorted([TOKEN, timestamp, nonce]) sha1 = hashlib.sha1(''.join(sort_list).encode()).hexdigest() return hmac.compare_digest(sha1, signature) 服务器校验通过后,接口返回微信传入的 echostr:@app.route('/wechat', methods=['GET']) def verify(): signature = request.args.get('signature', '') timestamp = request.args.get('timestamp', '') nonce = request.args.get('nonce', '') echostr = request.args.get('echostr', '') if check_sig(signature, timestamp, nonce): return text_response(echostr) return text_response('', 403) 2. 消息接收与图片保存用户向公众号发送图片或表情后,Flask 服务接收微信 POST 请求,解析 XML 消息内容。当消息类型为 image 或 emoji 时,读取图片地址并保存到服务器:if parsed.type in ('image', 'emoji'): pic_url = getattr(parsed, 'image', None) or getattr(parsed, 'picurl', None) if pic_url: link = download_and_save(pic_url) 图片下载后保存到 stickers/ 目录,并根据 BASE_URL 返回公网访问链接。这样用户发送图片后,即可收到下载地址。3. 收藏表情补偿处理部分收藏表情无法在微信公众号回调中直接获得原图。项目采用异步处理方式:主回调先记录待处理消息,后台 scraper 服务再尝试补偿抓取。收到无法直接解析的消息 -> 写入 pending_unsupported.jsonl -> scraper 后台读取任务 -> 登录公众号后台私信页面 -> 尝试识别并下载图片这种设计可以避免主回调阻塞,保证微信公众号服务器能够及时收到响应。4. 状态文件持久化项目运行过程中需要保存图片、待处理任务和后台登录态。Docker Compose 中将这些文件和目录挂载到宿主机,避免容器重建后数据丢失:volumes: - ./stickers:/opt/wechat-bot/stickers - ./mp_state.json:/opt/wechat-bot/mp_state.json - ./mp_scraper_state.json:/opt/wechat-bot/mp_scraper_state.json - ./mp_scraper_status.json:/opt/wechat-bot/mp_scraper_status.json - ./pending_unsupported.jsonl:/opt/wechat-bot/pending_unsupported.jsonl - ./access_token_cache.json:/opt/wechat-bot/access_token_cache.json六、华为云 ECS 部署1. 准备服务器在华为云 ECS 上准备 Linux 运行环境,并完成以下配置:绑定弹性公网 IP。配置安全组,放通 80、443 端口。安装 Docker 和 Docker Compose。如使用域名,将域名解析到 ECS 公网 IP。生产环境建议通过 Nginx 或 Caddy 提供 HTTPS 入口。2. 准备公网域名、备案和 SSL 证书微信公众号服务器地址需要公网可访问。部署阶段,CodeArts 辅助梳理了公网入口相关检查项,主要包括域名解析、备案状态、SSL 证书和反向代理配置。配置项CodeArts 给出的简要结果项目中的处理方式域名解析将业务域名解析到 ECS 绑定的公网 IP使用域名作为微信公众号回调地址备案状态如域名使用场景需要备案,应先完成备案状态确认在正式配置公众号回调前确认域名可用于公网访问SSL 证书微信公众号回调建议使用 HTTPS 地址为域名配置 SSL 证书,提供 https://你的域名/wechat反向代理HTTPS 入口转发到本地 Flask 服务端口使用 Nginx 或 Caddy 将请求转发到 127.0.0.1:5000访问验证回调地址配置前应先验证域名和证书可访问使用浏览器或 curl 检查 HTTPS 访问结果公网入口准备完成后,再将 .env 中的 BASE_URL 配置为正式域名下的图片访问地址:BASE_URL=https://你的域名/stickers3. 初始化目录和配置mkdir -p /opt/wechat-bot/stickers /opt/wechat-bot/verify cd /opt/wechat-bot cp .env.example .env touch pending_unsupported.jsonl touch mp_state.json mp_scraper_state.json mp_scraper_status.json access_token_cache.json.env 中配置公众号和服务运行所需参数:WX_TOKEN=替换为公众号后台Token WX_APPID=替换为公众号AppID WX_AES_KEY=替换为EncodingAESKey BASE_URL=https://example.com/stickers ADMIN_TOKEN=替换为管理接口Token STICKER_DIR=/opt/wechat-bot/stickers PENDING_FILE=/opt/wechat-bot/pending_unsupported.jsonl MP_QR_FILE=/opt/wechat-bot/mp_login_qr.png MP_STATUS_FILE=/opt/wechat-bot/mp_scraper_status.json4. 启动服务docker-compose build docker-compose up -d docker-compose ps 查看日志:docker-compose logs -f web docker-compose logs -f scraper健康检查:curl http://127.0.0.1:5000/返回以下内容表示服务正常:wechat-bot ok5. 配置微信公众号回调在微信公众号后台配置服务器地址:https://你的域名/wechat保存配置时,观察 web 服务日志。如果出现以下日志,说明服务器校验成功:VERIFY OK七、问题排查问题排查方向公众号服务器校验失败检查 WX_TOKEN 是否一致,反向代理是否保留 query string,回调路径是否为 /wechat加密消息解密失败检查 WX_APPID 和 WX_AES_KEY 是否正确图片保存成功但链接打不开检查 BASE_URL、安全组、HTTPS 入口和静态文件访问路径域名或 HTTPS 不可访问检查域名解析、备案状态、SSL 证书、证书绑定和反向代理配置容器重启后状态丢失检查 docker-compose.yml 中 volumes 是否正确挂载收藏表情未被处理检查 pending_unsupported.jsonl、scraper 日志和 mp_scraper_status.json管理接口无法访问检查 ADMIN_TOKEN 是否配置正确常用排查命令:docker-compose ps docker-compose logs -f web docker-compose logs -f scraper ls -lh stickers tail -n 20 pending_unsupported.jsonl八、安全与开源处理项目公开前,需要排除隐私信息和运行态文件。本项目已通过 .gitignore 和 .dockerignore 排除以下内容:类型示例环境变量.env、private.env公众号密钥WX_TOKEN、WX_APPSECRET、WX_AES_KEY管理密钥ADMIN_TOKEN登录态文件mp_state.jsontoken 缓存access_token_cache.json运行状态mp_scraper_state.json、mp_scraper_status.json二维码和截图mp_login_qr.png、mp_private_last.png用户素材stickers/*本地工具状态.arts/、.codeartsdoer/提交前可执行以下命令检查仓库跟踪文件:git ls-files也可进行敏感关键字扫描:rg -n "(token=|APPSECRET|ADMIN_TOKEN|WX_TOKEN|access_token|private.env|mp_state)" . 公开案例或向 CodeArts 提问时,也应避免粘贴真实密钥、登录二维码、OpenID、公网 IP、聊天记录和用户素材。九、实践效果通过本项目,完成了一个可部署、可运行、可开源的微信公众号表情包机器人。项目实现了公众号回调接入、图片保存、收藏表情补偿处理、Docker Compose 部署和隐私文件排除。CodeArts 在实践中的主要价值体现在:帮助拆解项目模块和实现流程。辅助确认微信公众号接入和消息处理细节。辅助整理 ECS 部署步骤和容器持久化配置。辅助梳理公网域名、备案状态、SSL 证书和 HTTPS 回调地址配置。辅助形成常见问题排查清单。辅助梳理开源前的隐私信息排除范围。十、后续优化方向当前方案可优化方向ECS 本地 stickers/ 存储迁移到 OBS 对象存储JSON 文件保存状态使用 SQLite、Redis 或云数据库Docker Compose 查看日志接入云日志服务单台 ECS 部署镜像化部署、多实例和负载均衡ADMIN_TOKEN 简单保护增加 IP 白名单、WAF 或访问审计手动向 CodeArts 提问沉淀固定提问模板和项目知识库对于个人项目,当前方案可以先满足基本使用需求。后续可根据访问量、稳定性要求和维护成本逐步接入更多云服务能力。十一、总结本案例基于华为云 CodeArts 和 ECS,完成了微信公众号表情包机器人的开发与部署。CodeArts 主要用于辅助技术咨询、流程拆解、部署梳理、公网域名与 SSL 配置检查、以及排障复盘;ECS 提供稳定的云上运行环境;Docker Compose 负责服务编排和运行维护。项目最终形成了从需求分析、代码实现、云上部署、问题排查到安全开源处理的完整实践流程,适合作为个人开发者使用 CodeArts 辅助完成云上应用开发的参考案例。项目仓库:https://github.com/T0ngJ1PC/wechat-bot参考资料华为云论坛:cid:link_4华为云 ECS 最佳实践:cid:link_2CodeArts 代码智能体产品介绍:cid:link_3CodeArts IDE 智能问答:cid:link_0CodeArts IDE 智能体对话:cid:link_1
上滑加载中
推荐直播
-
用码道,让你的AI作品三步上朋友圈2026/08/04 周二 19:00-20:00
林华鼎-华为云AI开发者运营负责人
从入门 · 到做AI应用 · 到企业级开发。不教编程,只教用AI · 零代码、有产出、能带走、可炫耀 · 每课人人动手实操
回顾中 -
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
基于华为云码道,构建你的定制化AI搭子2026/08/14 周五 09:00-11:30
明亮-华为云开发者发展与支持部部长
本期直播将向您全面介绍华为云码道产品,并基于码道手把手教你部署自己的定制化AI陪伴搭子。
回顾中
热门标签