-
在线体验地址: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/
-
基于华为云 ECS 的微信公众号表情包机器人本文是一份面向华为云论坛/开发者社区的案例分享稿,采用“场景介绍、技术方案、实操步骤、问题排查、经验总结”的写法。案例以 /opt/wechat-bot 项目为基础,演示如何将一个微信公众号表情包保存机器人部署到云服务器,并通过 Docker Compose 管理 Web 回调服务与后台抓取服务。一、案例背景日常使用微信时,很多有趣的表情包会散落在聊天记录或收藏表情里。手动保存、分类和转发这些图片并不方便,尤其是微信公众号接收图片、收藏表情和私信消息时,还会遇到不同消息类型、图片临时地址、登录态失效等问题。本案例希望实现一个轻量级机器人:用户把图片或表情发给公众号后,系统自动保存到服务器目录。如果公众号收到的是“暂不支持的收藏表情”提示,后台任务会记录待处理消息,并尝试从公众号私信页面抓取原图。保存成功后,机器人返回可访问的下载链接。服务部署在云服务器上,使用容器方式运行,便于重启、迁移和排障。从论坛案例分享角度看,这类项目适合作为“云上开发项目分享”或“上云技术实践”:业务场景足够小,但包含云服务器、容器部署、Webhook 回调、文件持久化、后台任务和运行监控等完整工程要素。具体实现请关注公众号:gh_4a17557e4daa为什么适合作为华为云实践案例这类小工具看起来只是一个“保存表情包”的个人需求,但真正跑起来后,会自然牵出一套完整的云上应用流程:需要一台稳定在线的云服务器,保证微信公众号服务器可以随时回调。需要一个公网访问入口,让微信服务器和用户都能访问服务。需要文件持久化,避免容器重建或服务重启后表情包丢失。需要后台任务处理“回调里拿不到原图”的特殊场景。需要日志、状态文件和管理接口,方便定位签名失败、登录过期、下载失败等问题。需要开源前的脱敏处理,避免把公众号密钥、登录态和用户素材上传到仓库。所以它不是一个单纯的 Python 脚本,而是一个很小但比较完整的云上应用雏形。个人开发者可以借这个项目熟悉 ECS、Docker Compose、Webhook、反向代理、持久化目录和基础运维排障;企业内部的小工具也可以按类似方式快速上云。本案例的实现边界为了让案例更容易复现,本项目没有引入复杂的消息队列、数据库和对象存储,主要使用本地文件保存运行状态:pending_unsupported.jsonl 作为待处理消息队列。mp_state.json 保存公众号后台登录态。mp_scraper_state.json 记录后台抓取历史和去重信息。mp_scraper_status.json 保存 scraper 最近一次运行状态。stickers/ 目录保存下载后的图片和表情文件。这种设计适合个人项目、小流量场景和原型验证。如果后续用户量增加,可以再把文件队列替换为 Redis、SQLite、RDS 或云原生消息服务,把本地素材迁移到 OBS 对象存储。二、方案选型1. 云上资源本案例建议使用华为云弹性云服务器 ECS 承载应用。ECS 的定位是提供可按需创建和管理的云服务器,适合部署 Web 应用、后台任务、自动化脚本等轻量服务。建议资源配置如下:模块建议配置说明服务器华为云 ECS,Linux 系统用于运行 Flask 服务和后台抓取任务公网访问弹性公网 IP + 域名微信公众号回调需要公网可访问地址安全组放通 80/443,按需放通 5000生产环境建议由 Nginx/Caddy 反代到 5000存储目录/opt/wechat-bot/stickers保存用户发送的图片或表情包部署方式Docker Compose同时管理 Web 服务与后台 scraper 服务2. 应用架构项目当前由两个核心进程组成:服务入口作用webapp.py提供微信公众号服务器校验、消息接收、表情保存、管理状态接口scrapermp_private_scraper.py watch监听待处理的收藏表情消息,登录公众号后台并尝试抓取原图整体链路如下:微信用户 -> 发送图片/表情到公众号 -> 微信服务器回调 /wechat -> Flask 校验签名并解析 XML -> 图片下载到 /opt/wechat-bot/stickers -> 返回下载链接 收藏表情无法直接解析时: 微信回调 -> 写入 pending_unsupported.jsonl -> scraper 后台轮询公众号私信 -> 抓取图片并保存 -> 更新状态文件3. 项目目录说明部署目录建议固定为 /opt/wechat-bot,这样 Docker、systemd 和运维脚本都可以使用稳定路径。当前项目中比较关键的文件如下:文件/目录是否建议提交仓库作用app.py是Flask Web 服务入口,处理微信公众号校验、回调、图片保存和管理接口mp_private_scraper.py是后台抓取服务,用 Playwright 处理公众号私信页面里的收藏表情docker-compose.yml是同时编排 web 和 scraper 两个服务Dockerfile是基于 Playwright Python 镜像构建运行环境.env.example是环境变量模板,只放占位值,不放真实密钥.gitignore是防止密钥、登录态、图片素材和缓存文件被提交README-deploy.md是简版部署说明huaweicloud-wechat-bot-case-sharing.md是本案例分享文档.env否本地真实环境变量,包含 Token、AppID、密钥等private.env否私有配置文件,不适合进入仓库access_token_cache.json否微信 access token 缓存mp_state.json否公众号后台登录态mp_login_qr.png否后台登录二维码截图mp_private_last.png否后台页面调试截图stickers/*否用户发送或抓取到的实际表情素材开源仓库里只保留代码、模板和说明文档,运行态数据留在服务器本地。这样既方便别人复现,也不会泄露真实公众号配置和用户文件。三、核心实现拆解1. 微信回调校验微信公众号服务器配置需要校验 signature、timestamp、nonce 和 echostr。项目中的 check_sig() 会按微信规则对 token、timestamp、nonce 排序后计算 SHA1,再和微信传入的签名做安全比较。关键点:Token 必须和公众号后台配置一致。回调路径建议使用 /wechat。若启用安全模式,需要同时配置 WX_APPID 和 WX_AES_KEY。示例环境变量: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.json2. 图片和表情保存当消息类型是 image 或 emoji 时,服务会读取图片地址并下载到 STICKER_DIR。保存时根据响应头或内容类型识别扩展名,常见格式包括 JPG、PNG、GIF、WEBP。返回给用户的是一个公开访问链接,链接前缀来自:BASE_URL + "/" + 文件名这里需要注意两点:BASE_URL 必须是外网可访问地址,否则用户收到链接后无法下载。stickers 目录需要做持久化挂载,避免容器重建后文件丢失。3. 收藏表情的异步处理部分收藏表情并不会直接以图片消息形式进入公众号回调,可能只收到“不支持的消息类型”文本。项目的处理方式是:将这类消息写入 pending_unsupported.jsonl。scraper 服务周期性读取待处理消息。通过 Playwright 登录公众号后台私信页面。从私信 DOM 和图片请求中识别候选图片。下载成功后写入状态文件,方便排查。这个设计的优点是不会阻塞公众号回调。即使后台抓取需要等待登录态、页面加载或重试,Web 服务仍然可以快速响应微信服务器。4. 文件持久化和去重思路容器化部署最容易踩的坑之一是“文件写进了容器内部,重建后就没了”。本项目把所有运行状态都挂载到宿主机目录:./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这样容器只是运行环境,真实数据在宿主机。后续如果要做备份,也可以直接备份 /opt/wechat-bot 下的状态文件和 stickers 目录。后台抓取时,图片来源地址会被转换成相对稳定的 source key。这个 key 可以用来判断同一个私信图片是否已经处理过,避免 scraper 每轮轮询都重复下载同一张图片。对于个人项目来说,这种轻量去重比引入数据库更直接。5. 管理接口与运行状态项目提供了两个简单管理接口:接口作用/admin/mp-qr查看公众号后台登录二维码截图/admin/mp-status查看 scraper 最近状态和二维码是否存在这两个接口都依赖 ADMIN_TOKEN,没有正确 token 时直接返回空结果或 404,避免管理信息暴露在公网。状态文件的价值在于排障时能快速回答几个问题:scraper 是否还在运行?最近一次轮询是什么时间?是否需要重新扫码登录公众号后台?待处理消息有没有被消费?图片下载失败是网络问题、页面结构问题,还是消息本身没有可抓取图片?小项目不一定一开始就接入完整监控,但至少要留下“能看见服务状态”的入口。这个项目用状态 JSON 文件和 Docker 日志解决了第一阶段的可观测性问题。四、部署步骤1. 华为云侧准备在华为云控制台准备 ECS 时,可以按下面顺序处理:创建一台 Linux ECS,系统可选择 Ubuntu、Debian、CentOS 或 Huawei Cloud EulerOS。绑定弹性公网 IP,确保微信服务器可以访问到回调地址。配置安全组,至少放通 80、443,测试阶段可临时放通 5000。如果使用域名,把域名解析到 ECS 的公网 IP。安装 Docker 和 Docker Compose。准备 HTTPS 反向代理。微信公众号正式回调建议使用 HTTPS 域名。实际生产环境建议用 Nginx、Caddy 或其他网关把公网请求转发到本机 5000 端口。这样 Flask 服务只负责业务逻辑,TLS 证书、域名转发、访问日志都交给反向代理处理。一个典型的访问链路是:微信服务器 -> https://你的域名/wechat -> ECS 安全组 443 端口 -> Nginx/Caddy -> 127.0.0.1:5000/wechat -> Flask 应用如果只是临时联调,也可以先通过 http://公网IP:5000/wechat 验证逻辑,但长期使用建议切到 HTTPS 域名。2. 准备服务器目录登录 ECS 后创建项目目录:mkdir -p /opt/wechat-bot/stickers /opt/wechat-bot/verify cd /opt/wechat-bot将代码放入该目录后,复制环境变量模板:cp .env.example .env然后编辑 .env,至少配置:WX_TOKENWX_APPIDWX_AES_KEYBASE_URLADMIN_TOKEN生产环境不要把真实 .env、private.env、登录态文件和 access token 缓存提交到代码仓库。为了减少遗漏,可以先创建运行态文件:touch pending_unsupported.jsonl touch mp_state.json mp_scraper_state.json mp_scraper_status.json access_token_cache.json如果这些文件不存在,Docker Compose 在某些环境下可能会把挂载目标当成目录处理,后续读写就会比较别扭。提前创建空文件更稳。3. 启动容器项目已经提供 docker-compose.yml,可以直接构建并启动:docker-compose build docker-compose up -d 启动后查看服务状态:docker-compose ps docker-compose logs -f web docker-compose logs -f scraperWeb 服务默认监听容器内 5000 端口,并映射到宿主机:ports: - "5000:5000" 如果生产环境使用 Nginx 或 Caddy,建议将公网 HTTPS 流量反向代理到 127.0.0.1:5000。启动后可以先做一个最简单的健康检查:curl http://127.0.0.1:5000/如果返回:wechat-bot ok说明 Web 容器已经可以正常响应。4. 配置微信公众号服务器地址在公众号后台配置服务器地址:https://你的域名/wechat同时填入:Token:对应 .env 中的 WX_TOKENEncodingAESKey:对应 .env 中的 WX_AES_KEY消息加解密方式:按实际需求选择明文、兼容或安全模式保存配置时,可以观察 web 服务日志。如果签名校验通过,会看到类似:VERIFY OK5. 登录公众号后台供 scraper 使用后台抓取服务依赖公众号后台登录态。项目提供了管理接口查看二维码和状态:GET /admin/mp-qr?token=你的ADMIN_TOKEN GET /admin/mp-status?token=你的ADMIN_TOKEN如果 scraper 提示需要登录,可以访问二维码接口,用管理员微信扫码。登录成功后,状态会写入:/opt/wechat-bot/mp_state.json /opt/wechat-bot/mp_scraper_status.json这些文件同样需要持久化保存。6. 联调测试完成部署后,建议按下面顺序验证:测试项操作预期结果Web 健康检查访问 /返回 wechat-bot ok微信服务器校验在公众号后台保存服务器配置日志出现 VERIFY OK普通文本消息给公众号发送文字返回使用说明图片消息给公众号发送图片返回 表情包已保存 和下载链接图片访问打开返回的链接能直接看到图片收藏表情发送收藏表情进入待处理流程或返回抓取说明管理二维码访问 /admin/mp-qr?token=...能看到登录截图或未准备提示scraper 状态访问 /admin/mp-status?token=...返回 JSON 状态联调时重点看两个日志:docker-compose logs -f web docker-compose logs -f scraperweb 日志用于确认微信回调是否正常进入、签名是否通过、消息类型是否识别正确;scraper 日志用于确认后台登录态、私信页面访问、候选图片识别和图片下载情况。五、常见问题与处理1. 微信公众号校验失败现象:VERIFY FAIL POST VERIFY FAIL排查方向:检查公众号后台 Token 是否和 .env 的 WX_TOKEN 一致。检查公网 URL 是否真实访问到当前服务。检查反向代理是否转发了 query string。如果启用安全模式,确认 WX_APPID、WX_AES_KEY 是否完整。2. 用户收到链接但打不开排查方向:BASE_URL 是否设置为公网域名,而不是内网地址。/stickers/<filename> 是否能直接访问。安全组、防火墙、反向代理是否放通对应路径。容器内保存路径和宿主机挂载路径是否一致。3. 收藏表情没有抓取成功排查方向:pending_unsupported.jsonl 是否有新增记录。scraper 容器日志是否提示登录过期。/admin/mp-qr 是否能看到最新二维码截图。mp_scraper_status.json 中的 updated_at 是否持续更新。公众号后台页面结构可能变化,DOM 识别逻辑需要随页面调整。4. 容器重启后文件丢失需要确认 docker-compose.yml 中已经挂载持久化目录和状态文件: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六、实践效果完成部署后,用户侧的体验比较直接:给公众号发送图片或表情。机器人自动保存文件。公众号回复下载链接。对于收藏表情,后台服务异步尝试抓取,不影响主回调。工程侧的收益也比较明显:Web 回调和后台任务拆成两个容器,职责清晰。状态文件、待处理队列和图片目录都落在宿主机,便于备份。通过 Docker Compose 管理启动顺序、重启策略和挂载目录,迁移成本较低。日志集中在 docker-compose logs 中,排障路径简单。从开发者实践角度看,项目最大的收获是把“能跑的脚本”改造成了“能长期运行的服务”。这个过程里最重要的并不是代码写了多少,而是把运行条件、配置方式、异常处理、数据持久化和安全边界都补齐。1. 使用体验普通用户不需要理解部署细节,只要把表情或图片发给公众号,就能得到一个下载链接。对于无法直接解析的收藏表情,系统也不会直接失败,而是提示后台正在尝试抓取。这种交互虽然简单,但背后把同步回调和异步补偿拆开了:同步链路负责快速响应微信服务器,避免超时。异步链路负责处理不稳定、耗时长、需要登录态的抓取动作。文件链接统一通过 BASE_URL 暴露,用户拿到的是稳定访问地址。2. 运维体验部署后,日常维护主要关注四类信息:关注点查看方式Web 服务是否在线访问 / 或查看 docker-compose ps微信回调是否正常查看 docker-compose logs -f web后台抓取是否运行查看 docker-compose logs -f scraper登录态是否过期查看 /admin/mp-status?token=... 或二维码截图这套排障路径比较短,适合个人项目。遇到问题时,一般从 Web 日志、scraper 日志、状态 JSON 文件和实际保存目录四个地方就能定位。3. 云上部署收益部署在 ECS 上之后,项目获得了几个本地环境很难稳定提供的能力:公网入口稳定在线,微信公众号服务器可以持续回调。服务可以 7x24 小时运行,不依赖个人电脑开机。容器重启策略能处理部分异常退出。目录挂载让运行态数据和容器生命周期解耦。后续可以继续接入 OBS、云监控、云日志、负载均衡等云服务。这个案例虽然规模小,但应用结构和很多实际业务服务是一致的:入口服务接收外部请求,后台 worker 做异步任务,运行数据持久化,日志用于排障,敏感配置通过环境变量管理。七、安全与开源处理把项目上传到公开仓库前,最容易忽略的是运行态文件。微信公众号项目里常见的敏感信息不只包括 .env,还包括登录二维码、后台登录态、access token 缓存、用户上传素材和调试截图。本项目开源前做了几类处理:类型示例处理方式环境变量.env、private.env不提交,只提交 .env.example公众号密钥WX_TOKEN、WX_APPID、WX_AES_KEY、WX_APPSECRET示例文件中改成占位值管理密钥ADMIN_TOKEN仅通过本地环境变量配置登录态mp_state.json加入 .gitignoretoken 缓存access_token_cache.json加入 .gitignore二维码/截图mp_login_qr.png、mp_private_last.png加入 .gitignore用户素材stickers/*目录保留,实际文件忽略缓存目录venv/、__pycache__/不进入仓库.gitignore 中保留了 stickers/.gitkeep 和 verify/.gitkeep,这样仓库里能看到需要的目录结构,但不会上传真实表情包或验证文件。同时,代码里的默认配置也要避免写真实值。例如:app.py 不内置真实 Token 和 AppID。mp_private_scraper.py 不内置个人域名。snapshot_private.py 不内置公众号后台 token URL。wechat-mp-scraper.service 通过 EnvironmentFile 读取私有配置。这一点很重要。很多项目并不是 .env 泄露,而是开发过程中随手写进脚本、服务文件、调试 URL 的 token 被一起提交了。开源前用 rg 扫一遍关键字,是一个很值得保留的小习惯。示例扫描命令:rg -n "(token=|APPSECRET|ADMIN_TOKEN|WX_TOKEN|access_token|private.env|mp_state)" . 扫描结果不一定都代表泄露,但可以帮助快速发现“不该出现在仓库里的真实运行信息”。八、可优化方向后续可以继续补强以下能力:将 pending_unsupported.jsonl 替换为 SQLite 或 Redis,增强并发和状态管理。为 /admin/* 接口增加 IP 白名单或更严格的鉴权策略。接入 OBS 对象存储,把表情文件从本地磁盘迁移到云上存储。增加 Prometheus 或轻量健康检查,监控回调成功率、下载失败率和 scraper 登录状态。在部署层增加 HTTPS 自动证书续期,降低公众号回调配置维护成本。对重复图片做 hash 去重,避免长期运行后磁盘膨胀。如果从华为云产品组合角度继续扩展,可以按下面路线演进:阶段当前方案可升级方向文件存储ECS 本地 stickers/OBS 对象存储,提供更稳定的静态文件访问状态管理JSON 文件Redis、SQLite、RDS 或云数据库日志查看Docker Compose 日志云日志服务,统一检索和告警可用性单台 ECS镜像化部署、多实例、负载均衡域名证书手动配置自动证书续期和统一入口网关安全防护ADMIN_TOKENIP 白名单、WAF、访问审计对于当前个人项目来说,不需要一开始就把这些都接上。更合理的路径是先保证主流程跑通,再根据使用频率和故障点逐步升级。云上资源的好处就在于弹性比较强:小项目可以轻量起步,后续再平滑补能力。九、论坛发布建议如果把这篇内容发布到华为云论坛,可以再补几张截图,让案例更直观:截图展示重点ECS 控制台实例截图展示项目部署在云服务器上安全组规则截图展示 80/443 或测试端口放通公众号服务器配置截图展示 /wechat 回调地址Docker Compose 运行截图展示 web 和 scraper 两个容器Web 日志截图展示 VERIFY OK 或消息回调日志scraper 状态截图展示后台抓取服务运行状态微信对话截图展示用户发送表情和机器人返回链接Git 仓库截图展示已开源的项目结构和脱敏处理推荐标题:〖案例共创〗基于华为云 ECS 的微信公众号表情包机器人部署实践正文结构可以保持本文这种顺序:先讲为什么做这个项目。再讲整体架构和华为云资源。然后给部署步骤和核心代码思路。接着写遇到的问题和排查方法。最后补实践效果、优化方向和仓库链接。这样读者能先理解需求,再跟着复现,最后也能看到项目还可以怎么继续演进。十、总结这个案例的核心不是复杂算法,而是把一个真实的小需求做成稳定的云上服务:公网回调、消息校验、文件保存、后台补偿、容器部署和日志排障都具备了。对于个人开发者或小团队来说,这类项目很适合用来练习“从脚本到服务”的完整上云流程。项目当前仍然是一个轻量版本,但已经包含了一个云上应用的基本骨架:ECS 提供持续在线的运行环境。Flask 负责微信公众号 Webhook。Docker Compose 负责编排服务。Playwright 负责处理公众号私信页面里的补偿抓取。本地挂载目录保存图片和运行状态。.gitignore 和 .env.example 保证开源时不带隐私数据。后续如果继续完善,可以优先做三件事:第一,把图片文件迁移到 OBS;第二,把运行状态从 JSON 文件升级为更可靠的存储;第三,增加健康检查和告警,让服务出问题时能主动发现。从一个小需求出发,最终沉淀出一个可部署、可维护、可开源的云上小工具,这就是本案例最有价值的地方。十一、参考资料华为云论坛:cid:link_1华为云案例共创活动说明:cid:link_2华为云 ECS 最佳实践汇总:cid:link_0本地项目部署说明:/opt/wechat-bot/README-deploy.md本地项目入口:/opt/wechat-bot/app.py本地后台抓取服务:/opt/wechat-bot/mp_private_scraper.py项目仓库:cid:link_3
-
好像了解一些监控产品 比较喜欢看监控这一类
-
这个问题困扰我好久了
-
一、概述1.1 案例介绍本案例使用华为云码道(CodeArts)代码智能体,从零开始完成一个花店管理系统(花语轩)的全流程开发与云端部署。涵盖需求分析、方案设计、前后端编码、调试验证、ECS部署上线全流程,体验AI辅助编程的高效开发模式。网站url:http://124.71.227.253,仓库地址:https://gitcode.com/2301_80246598/Flower-shop-web.git1.2 适用对象高校学生个人开发者1.3 案例时间本案例总时长预计90分钟。1.4 案例流程说明:在华为云控制台购买ECS弹性云服务器,配置VPC与安全组;使用华为云码道CodeArts代码智能体,通过自然语言对话完成需求规格设计、方案设计和编码任务规划;在CodeArts辅助下完成前后端代码编写、调试和功能验证;将项目构建产物上传至ECS,配置MySQL、Nginx等服务,完成线上部署。1.5 资源总览本案例预计花费164.38元。体验完成后请及时释放资源,避免产生多余的费用。资源名称规格单价(元)华为云码道(CodeArts)代码智能体专业版105.77弹性云服务器 ECS1 vCPU | 1GiB | Huawei Cloud EulerOS 2.030.60云硬盘 EVS高IO | 40GiB28.00虚拟私有云 VPC按需0.01二、环境和资源准备2.1 购买ECS弹性云服务器登录华为云控制台,点击菜单 服务列表 > 计算 > 弹性云服务器,点击"购买弹性云服务器"。选择如下配置:- 计费模式:包年/包月- 区域:可选就近区域- 规格:通用计算型 | 1 vCPU | 1GiB- 镜像:Huawei Cloud EulerOS 2.0 标准版 64位- 系统盘:高IO | 40GiB- 网络:默认VPC和安全组设置登录凭证:root用户,密码自定义。点击"立即购买",等待ECS创建完成。注意:由于1GiB内存较小,后续部署时需为MySQL配置低内存模式并添加2GB Swap交换分区。2.2 开通华为云码道CodeArts登录华为云码道,开通CodeArts服务。在CodeArts中创建项目,进入代码智能体(CodeArts IDE)开发环境。2.3 本地开发环境要求在CodeArts IDE中开发时,需确保本地已安装以下工具:JDK 17+Maven 3.8+Node.js 18+MySQL 8.0+说明:CodeArts代码智能体可在对话中直接执行命令,无需手动切换终端。三、码道研发花店管理系统3.1 需求规格设计在CodeArts代码智能体中,通过自然语言描述项目需求,智能体自动生成需求规格文档(spec.md)。向CodeArts输入需求描述:开发一个花店管理系统(花语轩),课程项目,实现鲜花的分类管理、上架下架管理、会员管理(普通会员/黄金会员/白金会员/普通顾客)、购物车、模拟付款、畅销统计等完整业务闭环。CodeArts自动生成需求规格文档,包含:用户注册即成为普通会员,累计消费金额到达门槛自动升级(≥500元→黄金会员9折,≥2000元→白金会员8折),等级不降级付款做"模拟付款"即可完整业务流程:用户登录→浏览鲜花→加入购物车→修改数量/勾选结算→生成订单→计算折扣→确认付款→扣减库存(乐观锁)→记录销量→清空已购购物车项→更新累计消费→检测会员升级前端需展示鲜花图片技术栈:后端 Spring Boot 3.x + MyBatis-Plus + MySQL 8.0 + JWT,前端 Vue 3 + Element Plus + Pinia3.2 方案设计与任务规划3.2.1 设计文档生成CodeArts根据需求规格自动生成实现方案设计文档(design.md),包括:系统架构:前后端分离,后端Spring Boot提供RESTful API,前端Vue 3 SPA数据库设计:6张核心表(t_member、t_category、t_flower、t_cart_item、t_order、t_order_item)API设计:6组Controller(Member、Category、Flower、Cart、Order、Admin)会员等级与折扣策略3.2.2 编码任务规划CodeArts根据设计文档自动生成编码任务清单(tasks.md),将开发工作分解为可执行的任务项。3.3 后端开发3.3.1 项目结构CodeArts自动生成后端项目结构:flower-shop-server/ ├── pom.xml ├── src/main/java/com/flowershop/ │ ├── FlowerShopApplication.java │ ├── common/ # UnifiedResponse, ErrorCode, BusinessException │ ├── config/ # JwtUtil, CorsConfig, MyBatisPlusConfig, WebMvcConfig │ ├── filter/ # JwtAuthFilter │ ├── entity/ # Member, Category, Flower, CartItem, Order, OrderItem │ ├── entity/enums/ # MemberLevel, MemberRole, FlowerStatus, OrderStatus │ ├── dto/ # 11个请求DTO │ ├── vo/ # 14个响应VO │ ├── mapper/ # 6个Mapper接口 │ ├── service/impl/ # 6个Service实现 │ └── controller/ # 6个Controller └── src/main/resources/ ├── application.yml ├── schema.sql └── data.sql 3.3.2 关键代码说明1) 会员等级自动升级(MemberServiceImpl.java)会员等级根据累计消费自动升级,升级后不降级:public void checkAndUpgradeLevel(Long memberId) { Member member = getById(memberId); BigDecimal totalSpent = member.getTotalSpent(); MemberLevel oldLevel = member.getLevel(); MemberLevel newLevel = oldLevel; if (totalSpent.compareTo(new BigDecimal("2000")) >= 0) { newLevel = MemberLevel.PLATINUM; } else if (totalSpent.compareTo(new BigDecimal("500")) >= 0) { newLevel = MemberLevel.GOLD; } if (newLevel != oldLevel) { member.setLevel(newLevel); updateById(member); } } 2) 乐观锁扣减库存(FlowerMapper.java)使用MyBatis-Plus的乐观锁机制防止超卖:@Update("UPDATE t_flower SET stock = stock - #{quantity}, sales = sales + #{quantity} WHERE id = #{id} AND stock >= #{quantity}") int deductStock(@Param("id") Long id, @Param("quantity") Integer quantity); 3) JWT认证过滤器(JwtAuthFilter.java)公开路径放行,其余请求需携带JWT Token:private static final String[] PUBLIC_PATHS = { "/api/v1/member/login", "/api/v1/member/register", "/api/v1/flowers", "/api/v1/categories", "/images/**", "/error" }; 3.3.3 数据库初始化schema.sql定义6张核心表,data.sql初始化1个管理员、6个分类、16款鲜花:3.3.4 编译与启动在CodeArts终端中执行:.\start-backend.bat3.4 前端开发3.4.1 项目结构CodeArts自动生成前端项目结构:flower-shop-web/ ├── vite.config.js ├── package.json ├── src/ │ ├── main.js │ ├── App.vue │ ├── router/index.js │ ├── stores/ # user.js, cart.js (Pinia) │ ├── utils/request.js # Axios封装 │ ├── api/ # 6个API模块 │ └── views/ # 8个用户页面 + 4个管理页面 └── dist/ # 生产构建产物 3.4.2 关键配置说明1) Vite代理配置(vite.config.js)开发环境下,前端通过Vite代理访问后端API和图片资源:server: { port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true }, '/images': { target: 'http://localhost:8080', changeOrigin: true } } } 2) 路由守卫(router/index.js)根据用户角色控制页面访问权限,管理员可访问管理后台页面。3.4.3 安装依赖与启动.\start-fronted.bat 3.5 功能验证与Bug修复在CodeArts辅助下,通过浏览器自动化测试完整业务流程,发现并修复了以下Bug:3.5.1 图片显示问题问题:外部图片URL存在防盗链,前端无法显示鲜花图片。解决:起初CodeArts创建SVG占位图放在后端static/images/目录下,数据库中image_url改为本地路径如/images/rose1.svg。后续提供了可用的外部图片URL后,替换回外部链接。3.5.2 Vite代理未覆盖images路径问题:vite.config.js只代理了/api,但图片路径/images/**也需要代理到后端8080端口。解决:在vite.config.js中添加/images代理规则。3.5.3 创建订单时total_amount为null问题:OrderServiceImpl.createOrder()先执行insert再计算金额,导致total_amount字段为null(数据库不允许为空)。解决:调整为先计算所有金额,再一次性插入订单。3.5.4 管理员菜单不显示问题:MemberVO缺少role字段,前端无法判断用户是否为管理员。解决:在MemberVO中添加role字段,并在toMemberVO()方法中设置vo.setRole(member.getRole().name())。3.5.5 完整流程验证在CodeArts辅助下验证了完整的用户和管理员流程:用户流程:注册→登录→浏览鲜花→加入购物车→结算→生成订单→确认付款→状态变为"已支付"→购物车清空→销量更新管理员流程:admin登录→商品管理(含编辑/下架)→分类管理(含增删改)→会员管理(显示等级/消费)→畅销统计(排名/时间筛选)四、ECS部署项目4.1 构建生产版本4.1.1 构建前端在CodeArts终端中执行:cd flower-shop-web npm run build 构建产物输出到dist/目录。4.1.2 后端JAR包后端已通过mvn package -DskipTests构建,产物为flower-shop-server/target/flower-shop-server-1.0.0.jar。4.2 上传文件到ECS使用Python paramiko库通过SSH将构建产物上传到ECS服务器的/opt/flower-shop/目录:flower-shop-server.jar — 后端JAR包dist/ — 前端构建产物目录schema.sql — 数据库建表脚本data.sql — 数据库初始数据脚本4.3 安装服务器环境通过SSH连接ECS,安装运行所需软件:4.3.1 安装JDK 17ECS默认yum源无JDK 17,通过华为云镜像下载安装:curl -fsSL 'https://repo.huaweicloud.com/openjdk/17.0.2/openjdk-17.0.2_linux-x64_bin.tar.gz' -o /tmp/jdk17.tar.gz tar -xzf /tmp/jdk17.tar.gz -C /usr/local/ ln -sf /usr/local/jdk-17.0.2 /usr/local/jdk17 /usr/local/jdk17/bin/java -version 4.3.2 安装MySQL 8与Nginxyum install -y mysql-server nginx 4.3.3 配置MySQL低内存模式由于ECS仅1GiB内存,需为MySQL配置低内存模式并添加Swap:dd if=/dev/zero of=/swapfile bs=1M count=2048 chmod 600 /swapfile mkswap /swapfile swapon /swapfile cat > /etc/my.cnf.d/low-memory.cnf << 'EOF' [mysqld] performance_schema=OFF innodb_buffer_pool_size=128M innodb_log_buffer_size=8M max_connections=30 EOF 4.4 配置MySQL数据库4.4.1 重置root密码MySQL 8首次安装后root密码为随机值,需通过skip-grant-tables模式重置:systemctl stop mysqld systemctl set-environment MYSQLD_OPTS="--skip-grant-tables --skip-networking" systemctl start mysqld mysql -uroot -e "FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY '246537Znc'; FLUSH PRIVILEGES;" systemctl stop mysqld systemctl unset-environment MYSQLD_OPTS systemctl start mysqld 4.4.2 创建数据库并导入数据mysql -uroot -p246537Znc -e "CREATE DATABASE IF NOT EXISTS flower_shop DEFAULT CHARACTER SET utf8mb4;" mysql -uroot -p246537Znc flower_shop < /opt/flower-shop/schema.sql mysql -uroot -p246537Znc flower_shop < /opt/flower-shop/data.sql 4.5 启动后端服务4.5.1 直接启动nohup /usr/local/jdk17/bin/java -Xmx256m -jar /opt/flower-shop/flower-shop-server.jar > /opt/flower-shop/backend.log 2>&1 & 4.5.2 配置systemd开机自启创建服务文件/etc/systemd/system/flower-shop.service:[Unit] Description=Flower Shop Backend After=network.target mysqld.service [Service] Type=simple ExecStart=/usr/local/jdk17/bin/java -Xmx256m -jar /opt/flower-shop/flower-shop-server.jar Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target 启用服务:systemctl daemon-reload systemctl enable flower-shop 4.6 配置Nginx反向代理创建Nginx配置文件/etc/nginx/conf.d/flower-shop.conf:server { listen 80; server_name _; root /opt/flower-shop/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } 启动Nginx:rm -f /etc/nginx/conf.d/default.conf nginx -t && systemctl restart nginx && systemctl enable nginx 4.7 防火墙放通80端口firewall-cmd --permanent --add-service=http firewall-cmd --reload iptables -I INPUT -p tcp --dport 80 -j ACCEPT 4.8 验证部署结果在浏览器中访问 [http://<ECS公网IP>](http://124.71.227.253),确认网站正常运行:五、网站功能说明5.1 管理员功能说明管理员账号:admin密码:admin1235.1.1 鲜花的分类管理可进行新增、删除、编辑分类名的操作,如新增洋桔梗类鲜花,删除某类鲜花,修改某类鲜花名称。5.1.2 鲜花上架下架管理下架某类鲜花后首页该花束不可见,可重新上架5.1.3 会员管理5.1.4 统计畅销鲜花5.2 用户功能说明5.2.1 会员等级消费升级用户注册即成为普通会员,累计消费金额到达门槛自动升级(≥500元一黄金会员9折,≥2000元白金会员8折),等级不降级。白金会员后续消费享受8折优惠。5.2.2 基本购物功能至此,码道驱动,打造花店管理系统案例结束!
-
一、概述1.1 案例介绍求职准备通常包含简历整理、岗位理解、技能差距分析、项目经历补充和面试训练等多个环节。传统方式需要用户在招聘网站、开源平台、笔记工具和面试题库之间反复切换,流程分散、反馈慢,也难以形成持续改进闭环。本案例围绕这一痛点,基于华为云码道代码智能体的规范开发模式,构建一个"面试模拟助手"应用。系统支持账号注册登录、简历上传与解析、岗位匹配分析、技能差距识别、GitHub 项目搜索与推荐、项目实践路径生成、模拟面试、面试报告和用户级 API Key 配置等功能。项目采用前后端分离架构:前端:Vue3、TypeScript、Element Plus、Pinia、Vite。后端:FastAPI、Uvicorn、SQLAlchemy、SQLite,支持后续切换 PostgreSQL。AI 能力:DeepSeek API,用于简历分析、项目推荐、技能指导和模拟面试。外部接口:GitHub API,用于开源项目搜索。文件解析:pdfplumber 解析 PDF,python-docx 解析 Word。部署方式:支持 Windows 桌面应用打包和华为云 ECS 云服务部署。整个过程先使用码道完成规范化开发,再通过 AI Shell 完成云资源规划、Terraform 编排、ECS 初始化、应用部署和访问验证,展示从自然语言需求到公网可访问应用的完整交付流程。案例技术选型:华为云码道(CodeArts)代码智能体:集代码大模型、AI IDE、Code Agent 为一体的智能编码产品。本案例使用其中的规范开发模式,从需求分析、技术设计、任务拆解到代码实现、测试验证,形成较完整的开发闭环。开发者空间 AI Shell:华为云提供的智能 AI 命令行工具。本案例通过自然语言对话完成项目结构分析、ECS 资源规划、Terraform 配置生成、云资源创建、远程部署和访问验证。Terraform:用于声明式创建华为云资源,包括 VPC、子网、安全组、ECS、EIP 和 EIP 绑定,降低手动配置云资源的复杂度。通过码道规范开发模式与 AI Shell 对话式部署的结合,本案例完成了"AI 求职辅助应用"的开发、部署和验证,让学生或个人开发者能够以较低门槛体验完整云上交付过程。仓库链接:interview_assistant:基于 FastAPI 与 Vue3 的面试模拟助手桌面应用 - AtomGit本项目部署链接:http://49.4.115.167/1.2 适用对象个人开发者:希望学习 Vue + FastAPI + AI API 的完整应用开发与云部署流程。高校学生:希望完成一个可展示、可部署、可写入课程作品或简历的 AI 项目。求职产品开发者:希望快速搭建简历分析、项目推荐和模拟面试类应用原型。云开发初学者:希望通过 AI Shell 理解 ECS、EIP、VPC、安全组和 Terraform 的基本用法。1.3 案例时间本案例总时长预计 90 到 120 分钟:环境准备与码道项目导入:10 分钟。规范开发模式分析、设计与任务拆解:20 分钟。代码开发与本地验证:30 分钟。AI Shell 分析部署资源并生成 Terraform:15 分钟。执行 Terraform 创建 ECS 并部署应用:20 到 30 分钟。公网访问验证与资源清理:10 分钟。如果已经具备项目源码、华为云账号和开发者空间环境,部署阶段可以压缩到 30 分钟左右。1.4 案例流程说明:用户首先在本地 PC 中打开华为云码道代码智能体,通过规范开发模式完成"面试模拟助手(Interview Assistant)"项目的需求分析、技术设计、任务拆解和代码生成。项目代码开发完成后,将源码提交到 GitCode 仓库中,作为后续云端部署的代码来源。随后,用户进入开发者空间 AI Shell,通过自然语言指令调用 AI Cli 工具,从 GitCode 拉取项目源码,并在云端环境中完成资源规划、Terraform 配置生成、ECS 创建、应用依赖安装、前后端构建、Nginx 反向代理和 systemd 服务配置。部署完成后,用户即可通过公网访问云端运行的 Interview_assistant 应用。1.5 资源总览本案例预计花费约 0 到 20 元,具体取决于 ECS 按需运行时长和带宽计费情况。资源名称规格费用说明华为云码道(CodeArts)代码智能体体验版免费开发者空间 AI Shell标准环境免费ECS 弹性云服务器s6.medium.2,1 vCPU / 2GB按需计费EIP 弹性公网 IP5 Mbps按流量或带宽计费VPC / 子网 / 安全组基础网络资源通常不单独计费EVS 系统盘Ubuntu 22.04,40GB SSD随 ECS 计费二、系统架构设计2.1 整体架构项目采用前后端分离架构,后端使用 FastAPI 提供 RESTful API,前端使用 Vue3 构建单页面应用。支持两种部署方式:桌面应用模式:通过 PyInstaller 和 pywebview 打包为 Windows 桌面应用,适合个人用户本地使用。云服务模式:部署到华为云 ECS,通过 Nginx 反向代理,支持多用户公网访问。数据存储使用 SQLite,用户配置和 API Key 按用户隔离存储。AI 能力通过 DeepSeek API 接入,GitHub 项目搜索通过 GitHub API 接入。2.2 项目结构说明项目核心结构如下:D:\Huawei |-- backend | |-- main.py # FastAPI 应用入口 | |-- config.py # 配置、数据目录、API Key、CORS | |-- database.py # SQLAlchemy 数据库连接和迁移 | |-- interview_assistant.spec # 后端 PyInstaller 打包配置 | |-- requirements.txt # 后端依赖 | |-- adapters | | |-- deepseek.py # DeepSeek API 适配器 | | |-- github_api.py # GitHub API 适配器 | |-- routers | | |-- auth.py # 注册登录 | | |-- resume.py # 简历上传和分析 | | |-- project.py # 项目搜索和推荐 | | |-- interview.py # 模拟面试 | | |-- system.py # API Key 管理 | |-- services | | |-- file_parser.py # PDF / Word 解析 |-- frontend | |-- package.json # 前端依赖 | |-- src | |-- router # Vue Router | |-- stores # Pinia 状态管理 | |-- utils/request.ts # Axios 请求封装 | |-- views # 登录、简历、项目、面试、设置页面 |-- launcher | |-- launcher.py # Windows 桌面启动器 | |-- requirements.txt # launcher 依赖 |-- installer | |-- setup.iss # Inno Setup 安装脚本 |-- deploy | |-- nginx.conf # Nginx 反向代理配置 | |-- interview-assistant.service # systemd 服务配置 | |-- init.sh # ECS 初始化部署脚本 |-- terraform | |-- providers.tf # HuaweiCloud Provider | |-- variables.tf # 变量定义 | |-- main.tf # VPC、子网、安全组、ECS、EIP | |-- outputs.tf # EIP、SSH 命令等输出 |-- tests | |-- test_windows_packaging.py # Windows 打包行为测试 | |-- test_account_api_isolation.py # 多账号 API Key 隔离测试 |-- build.py # 本地一键构建脚本 |-- config.ini.template # 默认配置模板 |-- README.md # 项目说明2.3 后端核心逻辑2.3.1 应用入口后端入口文件为 backend/main.py。它完成以下工作:创建 FastAPI 应用。注册 CORS 中间件。注册 auth、resume、project、interview、user、system 等路由。初始化数据目录、日志目录、上传目录和配置目录。调用 migrate_db() 创建或迁移 SQLite 表结构。在生产部署中监听 0.0.0.0,由 Nginx 反向代理访问。部署前,码道根据 AI Shell 的上云要求完成了关键调整:修改项文件说明后端监听地址backend/main.py从 127.0.0.1 调整为 0.0.0.0,适配 ECS 服务监听动态 API 地址backend/config.py避免硬编码 localhost,支持根据请求动态推断SECRET_KEYbackend/config.py改为环境变量优先,支持生产随机密钥CORS 配置backend/config.py支持环境变量 EXTRA_CORS_ORIGINS生产环境配置backend/.env.production新建生产配置模板Nginx 配置deploy/nginx.conf反向代理 80 到 FastAPI 8000systemd 服务deploy/interview-assistant.service进程守护和开机自启2.3.2 用户级 API Key 隔离API Key 相关逻辑位于 backend/config.py 和 backend/routers/system.py。系统按当前登录用户 ID 生成独立配置路径:def _get_user_api_key_file(user_id: int) -> str: user_dir = os.path.join(USER_CONFIG_DIR, f'user_{user_id}') os.makedirs(user_dir, exist_ok=True) return os.path.join(user_dir, 'api_keys.ini') 读取、写入和状态检查函数都支持 user_id 参数:def read_api_key(key_name: str, user_id: int = 0) -> str | None: ... def write_api_key(key_name: str, key_value: str, user_id: int = 0) -> None: ... def get_all_api_keys_status(user_id: int = 0) -> dict: ... 系统设置接口通过 get_current_user 获取当前用户,并将 user.id 传入 API Key 操作:@router.put("/api-keys") def update_api_key(req: ApiKeyUpdateRequest, user: User = Depends(get_current_user)): ... write_api_key(key_name, key_value, user_id=user.id) DeepSeek 和 GitHub 适配器也接收 user_id,确保 AI 调用使用当前账号自己的密钥:adapter = DeepSeekAdapter(user_id=user.id) adapter = GitHubAdapter(user_id=user.id) 2.4 前端核心逻辑前端位于 frontend 目录,使用 Vue3 + TypeScript + Element Plus。主要页面包括:页面文件功能登录src/views/auth/LoginView.vue用户登录并保存 token注册src/views/auth/RegisterView.vue创建新账号仪表盘src/views/dashboard/DashboardView.vue展示简历、项目和面试概况简历优化src/views/resume/ResumeView.vue上传简历、分析岗位匹配项目推荐src/views/project/ProjectView.vue搜索项目、刷新推荐、生成实践路径模拟面试src/views/interview/InterviewView.vue创建面试会话并答题面试报告src/views/interview/InterviewReportView.vue查看评分与改进建议设置src/views/settings/SettingsView.vue配置 DeepSeek、GitHub 和 TTS请求封装位于 frontend/src/utils/request.ts,会自动读取本地 token,并在接口返回 401 时尝试刷新登录态。三、使用华为云码道(CodeArts)代码智能体辅助完成代码开发及调试3.1 代码智能体在项目开发中的应用华为云码道(CodeArts)代码智能体在本项目中发挥了关键作用,辅助完成了以下开发任务:需求分析与规格定义:根据自然语言需求生成详细的需求规格文档,明确功能边界和技术要求。技术设计与架构规划:基于需求规格生成完整的技术设计方案,包括前后端技术选型、数据库设计、API 设计等。任务拆解与排期:将复杂项目拆解为可执行的开发任务,形成清晰的开发路线图。代码生成与补全:智能体根据需求描述自动生成后端 API 路由、前端组件、数据库模型等代码片段,显著减少手动编码工作量。代码审查与优化:智能体对现有代码进行审查,识别潜在的性能问题、安全漏洞和代码风格不一致,并提供优化建议。调试支持:智能体协助定位运行时错误,分析日志输出,提供修复建议,加速问题排查。测试用例生成:智能体根据功能描述自动生成单元测试和集成测试用例,提高测试覆盖率。文档生成:智能体根据代码注释和结构自动生成 API 文档、部署说明和用户手册。架构设计建议:智能体提供前后端分离架构、数据库设计、API 设计等方面的最佳实践建议。3.2 规范开发模式流程3.2.1 输入需求并启动规范开发在码道代码智能体中切换到规范开发模式后,可以输入类似提示词:我希望开发一个面向求职准备场景的面试模拟助手系统。 系统需要支持以下功能: - 用户注册登录 - 简历上传与解析 - 岗位匹配分析 - 技能差距识别 - 开源项目推荐 - 项目实践路径生成 - 模拟面试 - 面试报告 - 用户个人 API Key 配置。 前端使用 Vue3 + TypeScript + Element Plus,后端使用 FastAPI + SQLAlchemy,AI 能力接入 DeepSeek API。 请按规范开发模式帮我完成需求分析、技术设计、任务拆解、代码实现和测试验证。码道会按照规范开发流程推进,先分析业务目标和功能边界,再生成技术设计与任务列表,最后进入代码实现与测试阶段。3.2.2 项目核心能力模块功能说明用户认证注册、登录、刷新 token、JWT 鉴权简历解析上传 PDF / Word 简历,解析文本并保存岗位分析输入目标岗位 JD,生成匹配分数、差距和建议项目推荐结合简历和岗位目标,通过 DeepSeek 与 GitHub API 推荐项目实践路径为推荐项目生成阶段化实践路线模拟面试根据简历和岗位生成面试题,支持答题、追问和报告用户设置保存 DeepSeek API Key、GitHub Token、TTS 服务地址部署适配支持 Nginx 反向代理、systemd 守护、生产环境变量3.3 具体应用场景3.3.1 后端开发辅助FastAPI 路由生成:智能体根据需求描述自动生成完整的 CRUD 路由,包括请求验证、数据库操作和响应格式化。SQLAlchemy 模型设计:智能体协助设计数据库表结构,生成符合业务需求的 ORM 模型。错误处理与日志:智能体建议统一的错误处理中间件和日志记录策略。API Key 加密存储:智能体提供安全的 API Key 存储方案,包括加密算法选择和密钥管理策略。3.3.2 前端开发辅助Vue3 组件生成:智能体根据设计稿或功能描述生成 Vue 单文件组件,包括模板、脚本和样式。TypeScript 类型定义:智能体根据后端 API 响应自动生成 TypeScript 接口定义,确保类型安全。状态管理设计:智能体建议 Pinia store 结构,优化状态管理和组件通信。路由守卫实现:智能体生成认证和授权路由守卫,保护需要登录的页面。3.3.3 桌面应用打包辅助PyInstaller 配置优化:智能体提供 PyInstaller spec 文件的最佳配置,解决隐藏控制台、资源打包等问题。pywebview 集成:智能体协助实现桌面窗口启动器,管理后端进程和前端页面加载。Inno Setup 脚本编写:智能体生成完整的安装脚本,包含文件复制、快捷创建和卸载清理。3.3.4 测试与调试辅助单元测试生成:智能体根据业务逻辑自动生成 pytest 测试用例,覆盖正常和异常场景。API 测试脚本:智能体生成 Postman 风格的 API 测试脚本,方便接口验证。性能调优建议:智能体分析代码性能瓶颈,提供数据库查询优化、缓存策略等建议。安全审计:智能体检查代码中的安全漏洞,如 SQL 注入、XSS、CSRF 等,并提供修复方案。3.4 开发效率提升通过华为云码道(CodeArts)代码智能体的辅助,本项目开发效率提升显著:开发时间缩短约 40%:智能体自动生成基础代码,减少重复劳动。代码质量提升:智能体的代码审查和建议帮助保持代码风格一致,减少潜在 bug。文档完整性提高:智能体自动生成的文档覆盖全面,减少手动编写工作量。问题解决速度加快:调试支持功能帮助快速定位和修复问题。四、解决方案4.1 整体解决方案本项目提供了一套完整的面试模拟助手解决方案,包括:用户管理:注册、登录、JWT 认证、Token 刷新。简历管理:PDF/Word 简历上传、解析、存储、编辑。岗位匹配分析:基于 AI 的简历与岗位描述匹配度分析、技能差距识别。开源项目推荐:根据技能差距推荐 GitHub 开源项目,生成实践路径。模拟面试:AI 生成面试题、实时评估答案、生成面试报告。多部署模式:支持 Windows 桌面应用打包和华为云 ECS 云服务部署。多用户隔离:每个用户的 API Key、简历数据、面试记录完全隔离。4.2 技术栈选择组件技术选型理由后端框架FastAPI高性能、异步支持、自动 API 文档生成数据库SQLite轻量、无需单独部署、适合桌面应用和简单云部署ORMSQLAlchemyPython 生态成熟、支持异步操作前端框架Vue3 + TypeScript响应式、类型安全、生态丰富UI 组件库Element Plus企业级组件、与 Vue3 完美集成状态管理PiniaVue3 官方推荐、TypeScript 友好构建工具Vite快速构建、热重载、开发体验好桌面启动器pywebview轻量、跨平台、可嵌入浏览器打包工具PyInstaller将 Python 代码打包为独立 exe安装包生成Inno SetupWindows 安装包制作、免费开源云部署华为云 ECS弹性计算、按需付费、稳定可靠基础设施即代码Terraform声明式云资源配置、可重复部署反向代理Nginx高性能、稳定、配置简单进程管理systemdLinux 标准服务管理、开机自启4.3 部署方案开发环境:前后端分离运行,便于调试。桌面应用:打包为 Windows 桌面应用,用户一键安装使用。云服务环境:部署到华为云 ECS,通过 Nginx 反向代理,支持多用户公网访问。数据存储:用户数据存储在本地 %APPDATA% 目录(桌面应用)或 /opt/interview_assistant/data(云部署),确保数据持久化。配置管理:API Key 等敏感配置按用户加密存储,支持多用户隔离。五、核心技术难点与解决思路5.1 多用户 API Key 隔离难点:多个用户使用同一台电脑或同一云服务时,需要确保每个用户的 API Key 相互隔离,避免密钥泄露和混用。解决方案:按用户 ID 创建独立配置目录:%APPDATA%\面试模拟助手\config\user_<用户ID>\(桌面应用)或 /opt/interview_assistant/data/config/user_<用户ID>/(云部署)每个用户的 API Key 加密存储在自己的配置文件中所有 API 调用都传入当前用户 ID,确保使用正确的密钥系统设置接口只操作当前用户的配置实现代码:def _get_user_api_key_file(user_id: int) -> str: user_dir = os.path.join(USER_CONFIG_DIR, f'user_{user_id}') os.makedirs(user_dir, exist_ok=True) return os.path.join(user_dir, 'api_keys.ini') 5.2 桌面应用无控制台窗口难点:打包后的 Python 后端 exe 会显示黑色控制台窗口,影响用户体验。解决方案:在 PyInstaller spec 中设置 console=False桌面启动器使用 subprocess.CREATE_NO_WINDOW 标志启动后端进程后端使用 uvicorn.run(..., log_config=None) 避免日志输出到控制台实现代码:# PyInstaller spec console=False # 启动器代码 startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess.SW_HIDE process = subprocess.Popen( [exe_path, '--port', str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo, creationflags=subprocess.CREATE_NO_WINDOW ) 5.3 前端静态资源嵌入后端难点:桌面应用需要将前端构建产物嵌入后端 exe,避免依赖外部文件;云部署需要将前端资源部署到合适位置。解决方案:前端使用 Vite 构建,输出到 frontend/dist桌面应用:PyInstaller 将 frontend/dist 目录打包到 _internal/web,后端启动时检查是否在打包环境中,如果是则从 _internal/web 加载静态文件云部署:前端构建产物复制到 /opt/interview_assistant/frontend/dist,Nginx 配置静态文件服务使用 StaticFiles 挂载静态资源目录实现代码:if getattr(sys, 'frozen', False): # 打包环境 web_dir = os.path.join(sys._MEIPASS, 'web') else: # 开发环境 web_dir = os.path.join(os.path.dirname(__file__), '..', 'frontend', 'dist') app.mount("/", StaticFiles(directory=web_dir, html=True), name="web") 5.4 简历文件解析难点:支持 PDF 和 Word 格式简历,提取结构化文本信息。解决方案:PDF 使用 pdfplumber 提取文本Word 使用 python-docx 提取文本统一文本清洗流程:去除多余空格、换行符、特殊字符提取关键信息:姓名、联系方式、教育经历、工作经历、技能等实现代码:def parse_pdf(file_path: str) -> str: import pdfplumber text = "" with pdfplumber.open(file_path) as pdf: for page in pdf.pages: text += page.extract_text() + "\n" return clean_text(text) def parse_docx(file_path: str) -> str: from docx import Document doc = Document(file_path) text = "\n".join([paragraph.text for paragraph in doc.paragraphs]) return clean_text(text) 5.5 AI 接口调用与错误处理难点:AI 服务可能超时、限流或返回错误,需要优雅降级和重试机制。解决方案:实现适配器模式,统一 AI 服务接口添加超时设置和重试逻辑记录详细日志便于排查提供友好的用户错误提示实现代码:class DeepSeekAdapter: def __init__(self, user_id: int = 0): self.api_key = read_api_key("deepseek", user_id) self.timeout = 30 self.max_retries = 3 def chat(self, messages: List[Dict], temperature: float = 0.7) -> str: for attempt in range(self.max_retries): try: response = requests.post( "https://api.deepseek.com/v1/chat/completions", headers={"Authorization": f"Bearer {self.api_key}"}, json={"model": "deepseek-chat", "messages": messages}, timeout=self.timeout ) response.raise_for_status() return response.json()["choices"][0]["message"]["content"] except Exception as e: if attempt == self.max_retries - 1: raise time.sleep(2 ** attempt) # 指数退避 5.6 桌面应用单实例锁难点:防止用户多次点击启动多个应用实例,导致端口冲突和资源浪费。解决方案:使用 Windows 命名互斥体(Mutex)实现单实例锁启动时检查是否已有实例运行如果已有实例,激活现有窗口并退出实现代码:import win32event import win32api import winerror mutex_name = "Global\\面试模拟助手_Launcher" mutex = win32event.CreateMutex(None, False, mutex_name) if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS: # 已有实例运行 sys.exit(0) 5.7 云部署适配与配置管理难点:将本地开发的应用适配到云环境,处理环境变量、文件路径、服务监听等问题。解决方案:使用环境变量配置生产环境参数,避免硬编码动态检测运行环境,调整配置路径和监听地址提供 Nginx 配置模板和 systemd 服务文件创建部署脚本自动完成环境初始化实现代码:# 生产环境配置 if os.getenv("ENVIRONMENT") == "production": SERVER_HOST = "0.0.0.0" # 监听所有网络接口 DATA_DIR = "/opt/interview_assistant/data" LOG_DIR = "/var/log/interview_assistant" else: SERVER_HOST = "127.0.0.1" # 本地开发 DATA_DIR = os.path.join(os.path.expanduser("~"), ".interview_assistant", "data") LOG_DIR = os.path.join(os.path.expanduser("~"), ".interview_assistant", "logs") 六、环境和资源准备6.1 准备码道开发环境参考华为云码道(CodeArts)代码智能体安装部署说明,完成 Windows 版码道安装并登录账号。打开项目后,进入代码智能体对话区域,选择"规范开发模式"。本案例使用规范开发模式完成以下工作:根据自然语言需求生成需求规格。根据需求规格生成技术设计。根据技术设计拆解开发任务。自动修改前后端代码。生成并运行测试。输出开发总结和交付说明。6.2 准备 AI 服务配置应用支持以下配置项:配置项是否必需说明DEEPSEEK_API_KEY必需用于 AI 简历分析、岗位匹配、项目推荐、技能指导和模拟面试GITHUB_TOKEN可选提高 GitHub API 搜索额度TTS_SERVICE_URL可选预留语音播报服务地址SECRET_KEY必需用于 JWT 和服务端加密,生产环境应使用强随机值项目在本地开发时支持用户在设置页保存个人 API Key;部署到 ECS 后,还需要在 backend/.env.production 中配置生产环境变量。6.3 准备项目源码本案例项目根目录为:D:\Huawei核心目录如下:D:\Huawei |-- backend # FastAPI 后端服务 |-- frontend # Vue3 前端工程 |-- launcher # Windows 桌面启动器 |-- installer # Windows 安装脚本 |-- deploy # 云部署配置 |-- terraform # Terraform 云资源配置 |-- tests # 测试用例 |-- build.py # 本地一键构建脚本 |-- README.md # 项目说明其中部署到 ECS 时主要使用 backend、frontend 和 deploy 相关文件。七、码道规范开发面试模拟助手7.1 本地验证后端本地启动:cd D:\Huawei\backend python -m pip install -r requirements.txt python -m uvicorn main:app --host 127.0.0.1 --port 8000 --reload 前端本地启动:cd D:\Huawei\frontend npm install npm run dev测试命令:cd D:\Huawei python -m unittest discover -s tests当前项目测试覆盖账号 API Key 隔离、Windows 打包配置等关键逻辑。7.2 使用核心功能7.2.1 注册和登录打开应用。进入注册页,填写邮箱、密码和昵称。注册成功后登录。登录后前端会保存 accessToken 和 refreshToken。7.2.2 配置 API Key进入"设置"页面,配置:DeepSeek API Key:用于 AI 能力。GitHub Token:用于 GitHub 项目搜索,可选。TTS 服务 URL:用于语音播报扩展,可选。保存后,后端会将配置写入当前登录用户目录:%APPDATA%\面试模拟助手\config\user_<用户ID>\api_keys.ini7.2.3 上传简历并分析岗位匹配进入"简历优化"页面。上传 PDF、DOC 或 DOCX 简历。系统解析简历文本并保存到本地数据库。输入目标岗位 JD。点击分析,系统调用 DeepSeek 生成匹配分数、技能差距和优化建议。后端对应接口:接口方法说明/api/v1/resume/uploadPOST上传并解析简历/api/v1/resume/analyzePOST根据简历和 JD 生成匹配分析/api/v1/resume/listGET获取当前用户简历列表/api/v1/resume/market-analysisPOST分析目标岗位市场要求/api/v1/resume/skill-guidancePOST生成技能补充指导7.2.4 生成项目推荐和实践路径系统会结合用户目标岗位、简历内容、岗位匹配差距和市场技能要求生成项目推荐。后端对应接口:接口方法说明/api/v1/project/searchGET使用 GitHub API 搜索开源项目/api/v1/project/refresh-recommendationsPOST使用 DeepSeek 刷新项目推荐/api/v1/project/{project_id}/guideGET生成项目复现指南/api/v1/project/{project_id}/practice-pathGET生成五阶段实践路径/api/v1/project/{project_id}/stage-progress/{stage_index}PUT更新实践阶段完成状态7.2.5 进行模拟面试进入"模拟面试"页面。选择面试类型和难度。系统根据简历和 JD 生成面试题。用户逐题作答。系统评估答案,可生成追问。完成后生成整体面试报告。后端对应接口:接口方法说明/api/v1/interview/sessionsPOST创建面试会话/api/v1/interview/sessions/{session_id}/answersPOST提交答案/api/v1/interview/sessions/{session_id}/completePOST完成面试并生成报告/api/v1/interview/sessions/{session_id}/reportGET查看面试报告/api/v1/interview/sessions/compareGET对比两次面试表现八、开发者空间 AI Shell 部署到华为云 ECS8.1 分析 ECS 部署资源完成代码开发后,打开开发者空间 AI Shell,输入提示词:帮我分析项目,我想将系统部署到ECS上,具体需要哪些资源,请帮我罗列一下AI Shell 会读取项目结构,识别该项目是前后端分离的面试模拟助手系统,并分析部署所需资源。AI Shell 推荐的最小化部署资源如下:ECS 弹性云服务器:s6.medium.2(1 vCPU / 2GB),Ubuntu 22.04,40GB SSDEIP 弹性公网 IP:5 Mbps 带宽,按流量或带宽计费VPC 虚拟私有云:默认配置,包含一个子网安全组:开放 80(HTTP)、443(HTTPS)、22(SSH)端口外部服务依赖:DeepSeek API、GitHub API部署架构:用户通过浏览器访问 EIP 公网 IPNginx 反向代理到 FastAPI 后端(端口 8000)FastAPI 服务处理业务逻辑,连接 SQLite 数据库前端静态资源由 Nginx 直接服务systemd 守护后端进程,确保服务高可用8.2 生成 Terraform 配置并调整代码继续在 AI Shell 中输入:帮我生成最经济的Terraform配置,并且帮我调整一下需要修改的部署要点AI Shell 先给出部署前需要修改的关键点:后端监听地址从 127.0.0.1 改为 0.0.0.0动态 API 地址配置,避免硬编码 localhostSECRET_KEY 改为环境变量优先CORS 配置支持环境变量 EXTRA_CORS_ORIGINS创建生产环境配置文件 backend/.env.production提供 Nginx 配置模板 deploy/nginx.conf提供 systemd 服务配置 deploy/interview-assistant.service随后 AI Shell 查询可用区、生成随机密码,并创建 Terraform 配置文件:terraform/providers.tf:HuaweiCloud Provider 配置terraform/variables.tf:变量定义terraform/main.tf:VPC、子网、安全组、ECS、EIP 资源配置terraform/outputs.tf:EIP、SSH 命令等输出8.3 执行 Terraform 创建云资源确认资源方案后,在 AI Shell 中输入:请使用以上配置,执行terraform applyAI Shell 执行:cd /root/interview_assistant/terraform terraform apply -auto-approveTerraform 创建了 10 个资源,包括 VPC、子网、安全组、安全组规则、ECS、EIP 和 EIP 绑定。部署完成后,ECS 状态为 ACTIVE。8.4 连接 ECS 并部署应用ECS 创建完成后,继续输入:帮我连接到ECS并部署应用AI Shell 通过 SSH / SFTP 将项目上传到 ECS,并执行部署脚本。部署脚本主要完成:安装系统依赖。安装 Node.js 18。创建 Python 虚拟环境。安装后端依赖。构建前端 dist。配置 Nginx。配置 systemd 服务。启动 interview-assistant 服务。验证前端、API 文档和健康检查接口。部署过程中修复的问题:问题处理方式pip install 冲突清理残留的超时进程后重新安装deploy/ 目录缺失配置文件补提交到 git,并通过 SFTP 上传DATA_DIR 权限错误从 /var/www/面试模拟助手 改为 /opt/interview_assistant/data最终部署结果:ECS: 49.4.115.167(s6.medium.2,Ubuntu 22.04)应用路径: /opt/interview_assistantPython 虚拟环境: /opt/interview_assistant/backend/venvNode.js: v18.20.8前端构建: /frontend/dist数据目录: /opt/interview_assistant/data配置文件: backend/.env.production待办事项:在 .env.production 中补充真实 DEEPSEEK_API_KEY,否则 AI 面试和分析功能无法正常调用。可选配置域名、SSL 证书和 GitHub Token。生产环境建议使用 SSH 密钥登录,替代密码登录。九、打包为 Windows 桌面应用9.1 构建前端静态资源cd D:\Huawei\frontend npm run build构建成功后会生成:D:\Huawei\frontend\dist后端 PyInstaller 打包时会把该目录复制到 _internal\web,由 FastAPI 挂载为静态页面。9.2 打包后端服务进入后端目录:cd D:\Huawei\backend python -m pip install -r requirements.txt python -m PyInstaller interview_assistant.spec --noconfirm --clean --distpath D:\Huawei\dist_backend构建产物:D:\Huawei\dist_backend\interview_assistant\interview_assistant.exe D:\Huawei\dist_backend\interview_assistant\_internal\web\index.htmlinterview_assistant.spec 中配置了 console=False,后端 exe 在 launcher 调用时不会弹出黑色命令窗口。9.3 打包桌面 launcherlauncher 位于 launcher/launcher.py,主要职责如下:读取安装目录下的 config.ini。查找可用端口,默认从 8000 到 8010。启动后端 interview_assistant.exe。等待 /health 接口可用。使用 pywebview 打开桌面小窗口,而不是跳转浏览器。在 Windows 下使用单实例锁,避免多次点击创建多个 launcher.exe。关闭窗口时终止后端进程。打包命令:cd D:\Huawei\launcher python -m pip install pyinstaller pystray Pillow pywebview python -m PyInstaller --onefile --windowed --name launcher --noconfirm --clean --distpath D:\Huawei\dist_launcher --workpath D:\Huawei\launcher\build --specpath D:\Huawei\launcher\build launcher.py构建产物:D:\Huawei\dist_launcher\launcher.exe9.4 生成安装包安装脚本位于:D:\Huawei\installer\setup.iss安装包会包含:后端目录 dist_backend\interview_assistant桌面启动器 dist_launcher\launcher.exe配置文件 installer\config.ini桌面快捷方式和开始菜单快捷方式生成安装包:Copy-Item -Path 'D:\Huawei\config.ini.template' -Destination 'D:\Huawei\installer\config.ini' -Force & 'C:\Users\User\AppData\Local\Programs\Inno Setup 7\ISCC.exe' 'D:\Huawei\installer\setup.iss' 输出文件:D:\Huawei\output\面试模拟助手_Setup_v1.0.0.exe9.5 使用一键构建脚本项目根目录提供 build.py,可一键执行前端构建、后端打包、launcher 打包和安装包生成:cd D:\Huawei python build.py可选参数:python build.py --skip-frontend python build.py --skip-backend python build.py --skip-launcher python build.py --skip-installer python build.py --clean 十、访问验证和效果确认10.1 验证前端页面ECS部署完成后,在浏览器访问AI shell给出的链接页面正常显示登录界面,表示前端静态资源已正确部署,Nginx 配置生效。10.2 验证 API 文档访问:http://xx.x.xxx.xxx/docs返回 FastAPI 自动生成的交互式 API 文档,表示 FastAPI 服务正常运行,并且 Nginx 已正确代理 API 文档。10.3 验证健康检查接口访问:http://xx.x.xxx.xxx/health或在服务器中执行:curl http://xxx.x.x.x:xxxx/health服务正常时返回健康状态信息。10.4 验证 systemd 服务在 ECS 上执行:systemctl status interview-assistant如果状态为 active (running),说明后端服务已经由 systemd 守护。后续服务器重启后,也可以自动拉起应用。十一、释放资源11.1 清理云资源ECS、EIP 和 EVS 均可能产生按需费用。体验完成后,如果不再使用,请在 AI Shell 中输入:帮我清理所创建的华为云资源或进入 Terraform 目录执行:cd /root/interview_assistant/terraform terraform destroy执行前请确认已经备份需要保留的数据,例如 SQLite 数据库、上传的简历文件和 .env.production 配置。11.2 清理本地构建产物如果只清理本地 Windows 构建产物,可在项目根目录执行:cd D:\Huawei python build.py --clean 该命令会清理:frontend/distbackend/distbackend/builddist_backenddist_launcheroutput11.3 卸载桌面应用如果通过安装包安装,可在 Windows"应用和功能"中卸载"面试模拟助手",或使用开始菜单中的卸载入口。卸载时安装脚本会尝试清理安装目录下的后端文件:{app}\backend用户数据默认保存在 %APPDATA%,用于保留登录账号、简历、项目、面试记录和 API Key 配置。需要彻底清理时,可手动删除:%APPDATA%\面试模拟助手删除该目录会清空本地数据库、上传文件、日志和所有用户 API Key 配置,请提前确认是否需要备份。十二、扩展资料说明12.1 技术文档华为云码道(CodeArts)代码智能体:https://codearts.huaweicloud.com/华为云 ECS 文档:https://support.huaweicloud.com/ecs/华为云 VPC 文档:https://support.huaweicloud.com/vpc/FastAPI 官方文档:https://fastapi.tiangolo.com/SQLAlchemy 官方文档:https://docs.sqlalchemy.org/
-
基于华为云码道与 ModelArts MaaS 的原创智能论文阅读学习助手PaperLens案例类型:AI 应用开发 / 智能阅读 / 开发者工具实践适用对象:高校学生、科研入门者、需要精读英文论文的个人用户在线体验:http://101.245.81.114代码仓库:falconousZhang/PaperLens_final参考体例:华为云开发者空间实战案例1. 案例介绍1.1 项目背景在阅读英文科研论文时,初学者经常遇到以下问题:PDF 排版复杂,正文、公式、图表与双栏文本之间缺乏清晰的阅读引导;论文中包含大量专业术语和长句,逐句翻译耗时,简单机翻又难以解释原理;阅读过程中产生的高亮、笔记和问题分散在不同工具中,难以形成连续的学习记录;通用大模型不了解当前论文上下文,容易给出脱离原文、缺少依据的回答;传统审稿工具更偏向评价论文质量,并不完全适合个人“读懂论文、掌握方法”的目标。PaperLens 因此被设计为一款 AI 驱动的个人论文阅读学习助手。系统以原始 PDF 为阅读主体,在不破坏论文版式的前提下,将总结、翻译、选中文字解释、论文问答、高亮、笔记、批判性阅读和学习报告导出整合到同一个工作台中。1.2 建设目标项目的核心目标不是替代用户阅读,而是降低进入论文内容的门槛,并让 AI 的每一次回答都尽量与论文原文建立联系。具体目标包括:保留原始 PDF 排版,提供逐页阅读体验;支持页面总结、全文翻译和选中文字解释;建立论文级多轮问答,让模型结合全文和历史对话回答;支持原文高亮与笔记,并按论文、页码进行管理;提供用户注册登录、数据隔离和管理员治理能力;将学习解释、笔记、批判性阅读等内容汇总导出为 Markdown、PDF 或 DOCX;使用低成本华为云资源完成可访问、可演示的部署。1.3 案例成果PaperLens 已形成从论文上传到学习资料沉淀的完整闭环:注册/登录 ↓ 上传 PDF → 文本与版式解析 → 进入逐页阅读工作台 ↓ ↓ 论文库管理 总结 / 翻译 / 选中文字解释 ↓ ↓ 阅读进度 多轮论文问答 ↓ ↓ 高亮与笔记 ← 原文定位与交互 → 批判性阅读 └───────────────┬───────────────┘ ↓ 学习报告导出图 1 PaperLens 论文库:集中展示论文解析状态、阅读进度、高亮与笔记数量,并支持继续阅读和论文管理。项目已部署在华为云 ECS,使用华为云 ModelArts Studio(MaaS)提供真实大模型推理能力,并通过 Docker Compose 运行前端、后端和 PostgreSQL。2. 整体解决方案2.1 方案概述PaperLens 采用前后端分离架构。浏览器负责 PDF 页面展示、文本选择和学习交互;后端负责用户权限、论文解析、任务状态、模型调用、数据持久化和报告生成。大模型能力通过统一的 LLMClient 抽象接入,当前实际部署使用华为云 ModelArts Studio(MaaS)的对话模型服务。系统遵循三个设计原则:原文优先:左侧始终展示原始 PDF 页面,AI 结果作为辅助信息显示在右侧;来源可追溯:解析时记录页码、字符区间和文本块位置,学习内容可以重新定位到原文;任务可恢复:耗时操作以任务状态保存,页面刷新后可以恢复轮询,不依赖一次 HTTP 连接持续到模型返回。2.2 技术选型层次技术或服务作用前端Vue 3、TypeScript、Vite、Pinia、Vue Router、Axios阅读工作台、状态管理、路由保护和 API 调用后端Python、FastAPI、Pydantic、SQLAlchemyREST API、业务服务、参数校验和数据访问数据库PostgreSQL 16、Alembic用户、论文、页面、问答、解释、笔记、任务和审计数据PDF 处理PyMuPDF、pdfplumber页面渲染、正文提取、文本块定位和表格识别大模型华为云 ModelArts Studio(MaaS)、GLM-5.2总结、翻译、选中文字解释、论文问答和批判性阅读报告ReportLab、python-docxMarkdown、PDF、DOCX 学习报告生成部署华为云 ECS、VPC、安全组、弹性公网 IP、Docker Compose、Nginx单机容器化部署与公网访问研发辅助华为云码道(CodeArts)代码智能体需求理解、跨文件编码、测试设计、问题定位和部署调试2.3 开发环境与云资源准备本案例将“开发工具”和“运行资源”明确分开。码道、Rules 与 Skills 只在研发阶段使用,不会随应用一起部署;真正运行 PaperLens 时只需要前端、后端、数据库、文件卷和 MaaS 服务。类别本案例配置说明本地开发Windows、Git、Docker Desktop、Node.js、Python编码、容器联调和定向验收智能研发华为云码道(CodeArts)代码智能体、项目级 Rules、开发 Skills需求设计、编码、测试资产与问题定位大模型服务ModelArts Studio(MaaS)兼容对话接口由统一 LLMClient 调用,密钥仅通过环境变量注入云服务器华为云 ECS,Ubuntu 22.04,2 vCPU、4 GiB、40 GiB小规模实习项目的单机部署网络VPC、子网、安全组、弹性公网 IP,5 Mbit/s公网只开放 Web 入口和受限 SSH容器运行Docker Engine、Docker Compose运行 Nginx、FastAPI 和 PostgreSQL为控制成本,当前实际部署没有单独购买 RDS、OBS、ELB 或 Kubernetes。数据库与文件使用 ECS 上的 Docker 持久卷;项目保留向 RDS 和 OBS 演进的接口与部署资料,但案例不会把“已经设计”描述成“已经购买并运行”。3. 系统架构设计3.1 逻辑架构3.2 分层设计表现层前端采用 Vue 3 + TypeScript。核心页面包括登录注册、论文库、上传页面、论文阅读工作台、批判性阅读结果、报告导出和管理员控制台。论文阅读工作台采用左右分栏布局:左侧按页显示原始 PDF 图像,并叠加可选择的透明文本层;右侧在“学习解释、论文问答、学习记录”之间切换;用户选择原文后,可以直接创建黄色高亮、绿色笔记或发起通俗解释;点击历史解释时,系统自动跳转到对应页并高亮来源文本。接口层FastAPI 对外提供统一的 /api/v1 接口,按领域拆分为认证、论文、任务、学习解释、问答、论文库、学习记录、导出和管理员接口。Pydantic 负责输入输出边界,统一异常处理避免将数据库语句、文件路径或上游响应泄露给前端。业务层业务逻辑集中在 Service 层:pdf_parser:正文、章节、文本块、表格和 Evidence 解析;learning_service:页面总结、翻译与选中文字解释;qa_service、qa_retriever:论文级多轮问答和证据检索;highlight_service、note_service:高亮、笔记与原文锚点;review_service:批判性阅读;export_service、report_converter:学习报告组织与格式转换;admin_service:用户治理、内容元数据查询和审计。数据层PostgreSQL 保存结构化业务数据,Docker Volume 保存 PDF、页面图像和导出报告。数据库迁移由 Alembic 管理,容器启动时先执行迁移,再启动后端服务。3.3 核心数据流论文上传与解析用户上传 PDF,后端校验扩展名、文件头、大小和文件哈希;文件写入受控存储目录,创建论文记录和解析任务;PyMuPDF 提取页面正文、页面尺寸和文本块坐标;pdfplumber 尝试提取表格,表格失败不影响正文解析;系统生成页面、章节、文本分块和 Evidence 数据;论文状态更新为 PARSED,前端进入阅读工作台。学习解释用户选择总结、翻译,或在 PDF 文本层中选择一段原文;后端根据页码、字符区间和论文归属校验来源;系统构造带有明确边界的 Prompt,并调用 MaaS;模型输出经过结构校验和清洗后持久化;前端轮询任务状态,并将结果与对应页和选区关联。论文问答首次提问时,后端读取论文全文,在长度预算内构造论文上下文;后续提问同时附加最近的历史问答。检索模块优先识别问题中的页码、表号、图号等显式引用,再结合文本相关性选择候选证据。问答记录保存在会话中,用户可以切换、滚动查看或删除历史会话。3.4 华为云部署架构本案例定位为小规模实习项目,因此优先选择低成本、易维护的单机方案,而不是引入复杂的微服务集群。部署中只将 Nginx 的 80 端口发布到公网,后端 8000 和数据库 5432 仅在 Docker 私有网络中访问。数据库和文件目录使用持久卷,容器设置健康检查与 restart: unless-stopped。当前演示环境使用 HTTP;正式生产环境应增加域名、HTTPS 证书并启用 Secure Cookie。3.5 工程目录设计项目采用按前端、后端、部署和设计资料分区的单仓库结构。核心目录如下:PaperLens/ ├── backend/ │ ├── paperlens/ │ │ ├── api/ # FastAPI 路由与认证边界 │ │ ├── core/ # 配置、安全、错误和可观测性 │ │ ├── models/ # SQLAlchemy 业务模型 │ │ ├── schemas/ # Pydantic 请求与响应契约 │ │ └── services/ # 解析、解释、问答、记录和导出服务 │ ├── alembic/ # 数据库迁移链 │ └── tests/ # 后端测试资产 ├── frontend/ │ ├── src/api/ # API 客户端 │ ├── src/components/ # 阅读工作台组件 │ ├── src/stores/ # Pinia 状态 │ └── src/views/ # 登录、论文库、阅读、管理等页面 ├── deploy/huawei/ # 单 ECS 与生产化部署配置 ├── ProjectDocs/ # 需求、架构、页面、测试和 SDD 设计资料 ├── docker-compose.yml # 本地开发编排 └── README.md这种结构使码道能够先从设计资料理解约束,再定位到对应领域的路由、Schema、Service、模型和前端页面,减少把业务逻辑堆进单个文件的情况。3.6 核心数据模型PaperLens 的数据模型围绕“用户—论文—页面内容—学习行为”展开:数据域核心实体设计要点认证users、auth_sessions、password_reset_tokens角色、状态、刷新令牌轮换和密码重置论文papers、paper_pages、paper_sections、paper_chunks论文归属、解析状态、逐页正文和章节结构原文定位evidences、paper_tables页码、引用文本、字符区间、边界框和表格结构学习解释learning_explanations、learning_citations模式、范围、任务状态、来源引用和失败恢复论文问答paper_qa_conversations、paper_qa_turns、paper_qa_citations多轮顺序、幂等请求、上下文哈希和证据绑定学习记录paper_library_entries、paper_highlights、paper_notes阅读进度、黄色高亮、绿色笔记和原文锚点扩展分析analysis_tasks、review_results、metric_records、experiment_results批判性阅读、指标与实验理解导出与治理export_reports、admin_audit_logs报告状态、文件信息和管理员不可变审计任务型实体统一使用 PENDING → RUNNING → SUCCEEDED/FAILED 状态机。模型调用前结束数据库事务,模型返回后再用新事务写入结果,避免在外部网络等待期间长期持有连接或行锁。4. 使用华为云码道(CodeArts)代码智能体辅助开发与调试4.1 使用方式PaperLens 的功能跨度较大,涉及前端交互、后端 API、数据库迁移、PDF 处理、大模型调用和云端部署。项目使用华为云码道(CodeArts)代码智能体辅助理解代码库、拆解需求、生成跨文件代码、补充测试以及定位运行故障。项目没有采用“一次性生成整个系统”的方式,而是将开发过程拆成可验证的小阶段:明确用户目标 ↓ 形成单轮任务提示词和边界 ↓ 码道理解代码库并完成跨文件实现 ↓ 集中进行定向测试、构建或实际操作验收 ↓ 根据日志和页面现象定位问题 ↓ 码道完成同轮修正 ↓ 进入下一功能阶段4.2 Rules 与 Skills 工程化约束为了让智能体在长期迭代中保持一致,项目为码道配置了项目级规则和技能工作流,主要覆盖:需求细化与架构设计;页面原型和交互约束;前后端测试设计;功能详细设计与任务拆解;Sprint 进度管理;Bug 修复记录。每次给码道的任务都会说明目标、允许修改的范围、禁止事项、接口契约、数据一致性要求和验收方式。相比只描述“实现某功能”,这种结构化提示词能够降低跨文件修改遗漏、重复造轮子和无关重构的概率。4.3 提示词管理与迭代方法PaperLens 没有把码道提示词当作一次性聊天内容,而是为每个开发阶段保留任务编号、目标、约束、验收标准和后续状态。项目共形成 P1~P8.4 的 32 轮阶段提示词归档,使需求变化、实现边界和技术决策能够回溯。一条可执行的码道提示词通常包含以下结构:# 码道下一阶段提示词:<阶段编号与名称> ## 任务目标 - 本轮只解决什么问题 - 完成后用户能获得什么能力 - 与既有功能的关系 ## 开始前边界与真实基线 - 必读的设计文档和真实代码 - 当前迁移、接口、容器和功能状态 - 必须保护的用户数据与现有修改 - 禁止读取的密钥、令牌和环境信息 ## 设计与实现要求 - 数据模型、状态机和迁移规则 - API 请求/响应与错误语义 - Service、前端交互和安全边界 - 并发、幂等、事务和失败恢复 ## 测试资产与验收 - 只编写少量关键测试资产 - 码道不运行测试、构建、迁移或 Docker 命令 - 集中验收阶段执行定向测试、关键烟测和前端构建 ## 完成定义 - 允许修改的文件 - 必须同步的设计与 Sprint 文档 - 实际完成项、未完成项和风险必须如实报告提示词也随项目实践逐步演进:早期更强调从零搭建和运行验证;中期增加数据模型、API 契约、并发和安全约束;后期为了提高效率,码道只负责编写或更新少量测试资产,不在实现轮次运行耗时测试,测试执行统一放到集中验收阶段。4.4 代表性码道提示词节选以下内容选自项目实际提示词归档。为适合作为案例展示,省略了较长的文件清单、历史统计值和重复性约束,但保留了当轮的目标、关键边界与完成定义。提示词一:建立可运行工程骨架使用场景:项目初期先统一技术选型和数据契约,避免前后端、数据库和设计文档各自演进。你现在负责继续开发 D:\shixi\PaperLens 项目。 本轮目标不是一次性完成整个系统,而是完成“规格修正 + 可运行工程骨架”, 为后续端到端 MVP 开发建立稳定基础。 一、必须采用的 MVP 决策 1. 前端使用 Vue 3 + TypeScript + Vite + Pinia + Vue Router。 2. 后端使用 FastAPI + SQLAlchemy + Alembic。 3. 本地和部署均使用 PostgreSQL,不使用 SQLite。 4. Evidence 必须记录 page_number、quoted_text、bbox、char_start、 char_end、section_id 和 chunk_id,保证前端后续能够定位原文。 5. 上传统一使用 multipart 流式上传,最大 50 MB。 6. 后台任务进度统一使用 HTTP 轮询,暂不引入 WebSocket。 7. MVP 只支持可提取文本的 PDF,OCR 放入后续版本。 8. LLM 必须通过统一 LLMClient 调用,默认提供 MockLLMClient。 二、本轮交付 - 创建 backend、frontend、docker-compose.yml、.env.example 和 README。 - 后端实现健康检查、配置、数据库连接、ORM、首个迁移和统一错误结构。 - 前端实现基础路由、Pinia、首页、健康检查及后端不可用提示。 - Compose 只包含 PostgreSQL、backend 和 frontend。 三、边界 - 不写入真实密钥,不初始化或提交 Git。 - 不引入 Celery、Redis、Nginx、FAISS 或真实云服务。 - 不生成大量空接口或只有 pass 的占位代码。 - 本轮到“工程骨架可以启动、模型和契约自洽”为止, 不继续实现 PDF 解析和真实 LLM 功能。落地结果:码道完成了 FastAPI、Vue、PostgreSQL 与 Docker Compose 的基础工程,并建立了后续一直沿用的 Evidence 定位字段和 LLMClient 抽象。提示词二:接入华为云 ModelArts MaaS使用场景:在 Mock 模型链路已经可用后,增加真实华为云模型适配器,同时保证本地开发不依赖云端密钥。# P3.3 华为云 MaaS 真实生成式模型适配器 ## 任务目标 在不改变现有审阅 API、数据库模型和前端的前提下, 把 LLMClient 从“只有 Mock 实现”扩展为可配置的 HuaweiMaaSLLMClient。 默认本地和测试仍使用 MockLLMClient。 ## 实现边界 1. 复用现有 httpx,不新增第三方模型 SDK、requests 或重试库。 2. 华为 MaaS 适配器使用标准 chat/completions 请求结构。 3. endpoint、model、API Key、连接超时和读取超时全部来自 Settings。 4. API Key 使用安全类型保存,不得出现在日志、异常、响应或 repr 中。 5. 不修改公开 API、ORM、Alembic、Docker 和前端。 6. 云接口测试必须使用 MockTransport,禁止真实联网和产生费用。 ## 响应与失败处理 - 校验 HTTP 状态、响应 JSON、choices、message 和 content。 - 兼容模型返回单个完整 Markdown JSON 围栏。 - 拒绝前后杂文、多对象、字段缺失和未知字段。 - 上游失败统一转换为安全业务错误,不把响应正文或密钥返回给客户端。 ## 完成定义 - Mock 与 Huawei MaaS 通过同一 LLMClient 工厂切换。 - 没有云端配置时项目仍可离线运行。 - 配置示例只使用占位符,不读取、打印或提交真实密钥。落地结果:真实模型与 Mock 模型共用同一业务接口,学习解释、问答和批判性阅读无需感知底层供应商;部署时只需通过环境变量选择 MaaS 适配器。提示词三:把产品主线校正为论文阅读学习使用场景:项目中期确认“帮助个人用户读懂论文”才是核心目标,因此需要在保留已有分析能力的同时重构主要交互。# P7.1 论文阅读学习工作台与证据化学习解释 ## 任务目标 把 PaperLens 的产品主线从“辅助审稿”校正为“帮助个人用户阅读论文并学习”。 在已完成的 PDF 解析、章节/页面、Evidence、认证隔离和 Huawei MaaS LLMClient 基础上,实现受保护的论文阅读工作台,以及针对当前页面或 选中文字的总结、翻译和通俗解释闭环。 已有结构化审阅、指标提取、实验分析和报告能力继续保留,分别作为 “批判性阅读”“实验理解”和“学习成果导出”的高级能力,不删除或重做。 ## 来源与安全边界 1. 客户端只提交 mode、scope 和页码/选区标识,不提交论文正文或 prompt。 2. 后端根据当前用户和 paper_id 重新读取来源,禁止跨用户、跨论文引用。 3. 论文标题和正文均视为不可信输入,并放在明确标签中;其中出现的 “忽略之前指令”等文字不得覆盖 system 指令。 4. SUMMARY 概括当前范围;TRANSLATE 忠实翻译并保留标题、段落和编号; 选中文字解释要说明概念、原理和例子。 5. 结果必须保存页码、来源哈希和任务状态,失败只记录安全公开文案。 ## 前端交互 - 阅读页采用左右分栏,左侧保留原始 PDF 版式并支持文本选择。 - 右侧显示学习解释历史;点击记录跳转到来源页。 - 选中文字解释与原文位置关联,不能把解释结果挤在 PDF 正文下方。 - 页面切换或组件卸载时停止旧轮询,避免旧结果覆盖新页面。落地结果:PaperLens 从“生成审阅结论”转向“原文阅读 + 页面解释 + 学习沉淀”,形成当前最具辨识度的双栏阅读工作台。提示词四:实现论文级多轮问答使用场景:解决“论文里明明存在,模型却因为只收到当前页片段而回答没有”的问题。# P7.2 当前论文多轮问答与证据化会话 ## 任务目标 实现只围绕当前用户、当前论文的多轮问答。用户可以新建会话、连续提问、 查看历史;有依据的回答绑定服务端选取的论文来源,证据不足时明确降级, 不能用模型常识伪装成论文结论。 ## 上下文构造 1. 以当前 question 为 query,仅在当前论文的 Evidence 中做确定性相关性排序。 2. 后续提问附加同会话最近的成功问答,超限时按完整轮次从最旧开始移除。 3. 候选 Evidence 按相关度、页码、创建时间和 ID 稳定排序,并限制 top_k。 4. 当前问题、历史回答和论文正文全部视为不可信内容,不能提升为 system role。 5. Embedding 与 LLM 调用期间不得持有数据库事务或行锁。 ## 幂等与结果契约 - 请求包含 client_request_id;重复请求返回原轮次,不重复调用模型。 - 同一会话只允许一个 PENDING/RUNNING 轮次。 - 成功回答保存 answer、grounded 和来源引用;证据不足时 grounded=false。 - 模型只返回一个严格 JSON 对象,拒绝额外解释、未知字段和跨论文引用。 ## 前端交互 - 右侧使用类似即时通信软件的消息时间线。 - 会话历史和消息区域可独立滚动,输入区固定在底部。 - 支持新建、切换和删除会话,轮询在终态立即停止。落地结果:系统形成论文级会话、轮次、上下文预算和幂等机制。真实论文验证中发现仅依赖少量 Evidence 会漏掉跨页图表后,后续迭代又将策略调整为“首次提问按预算提供全文基础上下文,后续附加历史,并优先识别页码、表号和图号”,体现了设计根据实际效果继续修正的过程。提示词五:准备华为云部署与安全收口使用场景:开发轮次结束后,为 ECS 部署、备份恢复和后续云资源演进准备可复用资产。# P8.4 华为云部署、备份恢复与综合安全验收 ## 任务目标 在既有论文阅读学习、登录注册、管理员、任务恢复和限流能力基础上, 补齐华为云部署配置、备份恢复说明和安全清单,使项目达到 “代码与部署资料完整,等待真实云环境验收”的状态。 ## 真实性要求 1. 不实际购买、创建、修改或删除华为云资源。 2. 不把“部署资产已完成”写成“真实云上已经部署”。 3. 示例只能使用占位符,禁止读取或写入 API Key、AK/SK、JWT Secret、 数据库密码、真实 IP、域名和证书私钥。 4. 码道只编写代码、少量测试资产、部署配置和文档, 不运行测试、构建、迁移、Docker、HTTP 或真实云服务命令。 ## 部署资产 - 提供 deploy/huawei 下的环境示例、Compose、Nginx、部署和回滚说明。 - 后端和数据库不直接暴露公网;只由 Nginx 代理同源 /api/。 - 容器使用非 root、只读文件系统、tmpfs、no-new-privileges、 healthcheck、资源上限和 restart policy。 - Secret 通过受限环境文件或 secret 文件注入,entrypoint 不打印内容。 - 给出 VPC、安全组、ECS、MaaS、健康检查和小额验证的人工配置顺序。 ## 完成定义 区分“代码与部署资产已实现”“离线验收尚未执行” 和“真实华为云资源尚未创建/验证”三种状态,不夸大完成度。落地结果:项目形成单 ECS 演示编排和面向生产化演进的配置资料;真实部署时又根据小规模需求选择 PostgreSQL 与文件卷同机运行,避免为了案例展示购买不必要资源。4.5 码道参与的主要开发阶段阶段码道辅助内容形成的结果工程骨架分析前后端技术栈,生成 FastAPI、Vue、PostgreSQL、Docker 基础结构可运行的前后端与数据库环境PDF 解析实现上传校验、页面解析、章节识别、文本块坐标和 Evidence 生成从 PDF 到可阅读、可定位数据的链路大模型接入抽象 LLMClient,实现 Mock 与 Huawei MaaS 适配器本地离线开发与云端真实模型可切换阅读工作台跨文件实现 PDF 页面、透明文本层、左右分栏和选区工具条保留原版式的交互式阅读体验学习解释设计总结、翻译、选中文字解释的 Prompt、状态机和历史记录面向学习场景的 AI 辅助阅读能力论文问答设计会话、轮次、全文上下文、历史预算和检索策略支持论文内连续提问用户与管理实现 JWT、刷新令牌、用户隔离、管理员角色和审计完整登录注册与管理闭环报告导出组织解释、高亮、笔记和批判性阅读内容Markdown、PDF、DOCX 学习报告云端部署分析 Docker、Nginx、卷权限和 MaaS 日志在小规格华为云 ECS 上稳定运行4.6 码道辅助调试实例实例一:测试数据误写开发库早期测试虽然创建了测试数据库,但应用在模块导入时已经初始化了指向开发库的数据库连接,导致部分测试仍可能写入开发库。码道根据数据库记录变化和初始化顺序分析问题,协助调整为延迟配置数据库 Engine,并增加测试库名称守卫、迁移失败即终止和测试残留检查。解决后,测试环境明确使用 paperlens_test,避免自动化测试污染真实论文数据。实例二:真实 MaaS 输出格式不稳定Mock 模型始终返回标准 JSON,但真实模型可能返回 Markdown 代码围栏、额外解释或字段缺失。码道协助增加严格的响应解析、围栏兼容、字段校验和安全失败状态;学习解释还使用独立的较长读取超时,避免长页翻译被普通问答的超时配置提前终止。实例三:Docker 容器在 ECS 上反复重启部署时 Nginx 采用只读文件系统,但默认尝试在 /var/cache/nginx 创建临时目录,导致容器因权限不足反复重启。码道根据容器日志定位到临时目录问题,将相关目录调整到 /tmp,并通过受限 tmpfs 提供可写空间。后端文件卷也曾因宿主卷所有权不匹配导致上传失败,随后增加一次性的 storage-init 服务,在后端启动前修正目录所有者和权限。实例四:公网 HTTP 下论文问答误报网络失败浏览器在普通 HTTP 环境下不能保证提供 crypto.randomUUID()。前端在创建会话后生成幂等请求 ID 时抛出本地异常,因此服务器只看到会话被创建和删除,没有收到真正的问题请求。码道根据前后端访问日志定位到请求链中断位置,增加基于 getRandomValues 的 UUID v4 回退逻辑,并区分本地运行异常和真实网络异常。这些问题说明,代码智能体的价值不仅是生成代码,还包括结合代码库、日志、运行环境和数据状态完成工程化定位。5. 功能解决方案设计5.1 原版式 PDF 阅读系统不将 PDF 正文简单转换成连续纯文本,而是为每一页生成页面图像,同时输出带坐标的文本层。页面图像保证视觉排版与原论文一致,透明文本层负责文字选择、字符偏移计算和高亮交互。这种设计兼顾了两个目标:用户看到的是原论文版式、图片、公式和表格;系统仍能知道用户选中了哪段文字,并把操作绑定到页码和字符区间。图 2 论文阅读工作台:左侧按页保留原始 PDF 版式,右侧统一承载学习解释、论文问答和学习记录。5.2 页面级学习解释“总结”和“翻译”按页生成并保留历史:总结要求覆盖当前页的各级标题;如果一个段落延续到下一页,可读取有限的下一页上下文补全含义;翻译要求保留标题层级和正文段落,不将公式、编号和专有名词随意改写;选中文字解释只处理用户选择的原文,重点说明概念、原理和例子。所有解释按页排序。点击历史记录可跳转到来源页;选中文字解释打开时,对应原文保持蓝色高亮。图 3 页面完整翻译:在保留标题、作者信息和正文层次的基础上,对当前页内容进行中文翻译。图 4 选中文字解释:左侧原文保持蓝色定位高亮,右侧从概念、原理和示例角度给出通俗说明。5.3 论文级多轮问答论文问答采用类似即时通信软件的对话界面。系统保存完整会话历史,输入区固定在底部,消息区域可独立滚动。为了减少“论文里明明有,模型却回答没有”的情况,后端不只发送当前页摘要,而是在首次提问时组装论文全文上下文;后续轮次再附加历史问答,并对超长内容执行可预测的长度预算。对页码、图号、表号等问题,检索器给予显式引用更高优先级。图 5 论文级多轮问答:用户可以围绕指定页码、表格或方法连续追问,系统保留会话历史并结合论文内容回答。5.4 高亮和笔记用户可以直接在 PDF 上选择文字:高亮以黄色保存;笔记以绿色标记,并保存笔记正文;选中文字解释使用蓝色定位;学习记录只展示当前页的高亮和笔记。记录同时保存原文、页码、字符起止位置和来源哈希。当论文内容或解析结果发生变化时,系统可以识别来源不一致,避免错误定位。图 6 高亮与笔记:黄色标记用于原文高亮,绿色标记关联学习笔记,右侧仅展示当前页的学习记录。5.5 用户、权限与管理员系统系统支持注册、登录、刷新令牌、退出、修改密码、忘记密码和个人资料。密码使用 Argon2 哈希;访问令牌采用 JWT,刷新令牌使用 HttpOnly Cookie,并具有轮换和重放检测机制。所有论文、解释、问答和学习记录均按 user_id 隔离。管理员可以查看系统概况、管理用户状态和角色、只读查看跨用户内容元数据,关键操作写入不可变审计记录。5.6 学习报告导出报告不再限定为“审阅报告”。即使论文没有执行批判性阅读,只要存在学习解释、高亮或笔记,也可以生成学习报告。报告按页组织内容,并可选择是否加入批判性阅读、指标或实验信息,最终导出为 Markdown、PDF 或 DOCX。图 7 学习报告导出:支持 PDF、DOCX 和 Markdown,固定汇总学习解释、高亮摘录和学习笔记,并可按需加入扩展分析。6. 核心技术难点与解决思路6.1 PDF 视觉版式与文本交互难以兼得难点:直接展示 PDF 可以保留版式,但难以稳定获取选中文字的字符位置;只展示解析文本又会破坏双栏、图表和公式布局。解决思路:采用“页面图像 + SVG 透明文本层 + 解析文本索引”的三层结构。图像负责视觉,文本层负责浏览器选择,后端标准化文本负责字符区间与学习记录。6.2 解析结果存在不确定性难点:不同 PDF 的字体、编码、文本顺序和表格结构差异很大,单个表格解析异常可能导致整个事务失败。解决思路:对正文、章节、表格和 Evidence 分阶段处理;表格写入使用嵌套事务或降级策略,使局部失败不影响论文正文;对扫描版 PDF 明确返回不支持 OCR,而不是生成不可用结果。6.3 大模型回答必须与论文上下文绑定难点:如果只传当前页或少量 Evidence,模型可能无法理解跨页图表;如果直接无限制传全文,又会超过上下文或增加费用。解决思路:采用“全文基础上下文 + 当前页优先 + 显式页码/图表引用检索 + 历史轮次预算”的组合策略。系统保存上下文哈希和请求幂等键,避免同一问题被重复提交。6.4 模型输出和网络调用不稳定难点:真实模型可能返回围栏文本、非标准字段或较长推理内容;长页翻译比普通问答耗时更长。解决思路:统一 LLMClient 接口,设置连接与读取超时边界;不同任务可以覆盖单次读取超时;模型结果经过严格 Pydantic 校验,失败时写入安全的任务状态,不将上游响应和密钥返回给用户。6.5 异步任务与页面状态一致性难点:解析、解释、问答和导出都不是瞬时操作。快速切换论文或页面时,旧请求可能晚于新请求返回并覆盖界面。解决思路:后端采用持久化任务状态和原子认领,前端采用受控轮询、代次标识和组件卸载清理。刷新页面后重新查询活动任务,终态立即停止轮询。6.6 小规格 ECS 上的资源与可靠性难点:2 vCPU、4 GiB 内存同时运行镜像构建、数据库、后端和前端时容易出现内存压力;公网拉取 Docker Hub 镜像也可能超时。解决思路:配置交换分区和容器资源上限;使用多阶段构建缩小运行镜像;通过华为云 SWR 镜像加速拉取基础镜像;只运行单后端实例和小连接池,避免为实习项目引入 Redis、Celery、Kubernetes 等额外组件。7. 安全与可靠性设计真实 API Key、数据库密码和 JWT Secret 通过环境文件注入,不进入代码仓库;上传文件校验后缀、PDF magic、大小和存储路径,防止路径穿越;数据查询统一校验资源所有者,管理员接口使用独立权限保护;日志只记录请求 ID、阶段和安全错误分类,不记录论文全文、令牌或 MaaS 响应正文;后端与数据库不直接暴露公网端口;容器启用 no-new-privileges,前端使用只读文件系统;提供 live/ready 健康检查、启动恢复和容器自动重启;自动化测试使用独立测试数据库,并在测试前后检查数据残留。8. 项目实施过程8.1 分阶段建设项目采用逐阶段增量开发,每一阶段都对应独立提示词、设计更新和可验收结果。阶段主要任务阶段出口P1FastAPI、Vue、PostgreSQL、Docker 工程骨架首页与健康检查可运行,迁移链建立P2PDF 上传、解析、章节、页面、文本块、表格和 Evidence论文可从文件转换为结构化、可定位内容P3MockLLM、Embedding、Huawei MaaS、结构化结果前端真实模型与离线模型可以切换P4指标抽取、实验数据统计和模型运行配置模型理解与确定性计算分离P5实验文件导入、校验、比较和可视化论文实验结果可结构化分析P6Markdown、PDF、DOCX 报告分析结果可以形成文件交付P7阅读工作台、学习解释、多轮问答、高亮和笔记产品主线转为个人论文阅读学习P8登录注册、管理员、审计、恢复、限流、部署与安全形成完整用户系统并具备云端运行条件其中 P7 是产品方向最重要的一次调整。项目没有删除已经实现的审阅、指标和实验功能,而是把它们移动为“批判性阅读”和“实验理解”等高级入口,主路径改为上传论文后直接进入逐页阅读工作台。8.2 设计文档与任务追踪码道在编码前先同步以下设计层:需求细化:确认用户目标、功能范围、非目标和冲突决策;架构设计:明确前后端边界、外部 MaaS、任务与存储关系;数据模型:定义实体、外键、状态机、索引和迁移安全;API 设计:固定请求字段、响应结构、权限和错误语义;页面设计:固定路由、页面状态和交互行为;测试设计:只保留正常路径、关键失败和必要恢复场景;SDD 与 Sprint:把需求映射到具体设计、文件和任务状态。这种做法解决了长周期智能体开发中常见的“上一轮约束在下一轮丢失”问题。提示词不再重复粘贴整个项目,而是引用稳定设计资料,再补充本轮真实基线和差异要求。8.3 集中验收策略为了避免码道在每个实现轮次反复执行耗时的全量测试,项目后期采用“实现与验收分离”策略:码道负责更新必要测试资产,但提示词明确禁止运行测试、构建、迁移往返、Docker 重建和 HTTP 烟测;实现轮次完成后,先检查实际改动范围和接口契约;后端默认只运行受影响模块的定向测试;前端变更运行相关 Vitest 和一次生产构建;只保留一条关键业务烟测,例如“上传 PDF → 解析 → 进入阅读页”;认证、迁移链、共享基础设施或最终发布才执行更完整的回归。单个新功能通常只设计 1 个正常用例、1 个重要失败用例,以及在确有并发或恢复风险时增加 1 个对应场景。该策略更符合个人实习项目的成本与风险水平。8.4 华为云 ECS 部署过程部署采用单机 Compose,核心步骤如下:创建 VPC、子网、安全组、弹性公网 IP 和 Ubuntu 22.04 ECS;安全组开放 80,并将 22 端口来源限制为当前管理 IP;安装 Docker Engine 与 Compose,配置华为云 SWR 镜像加速;将代码发布包上传到 /opt/paperlens,检查校验和后解压;创建权限为 600 的部署环境文件,交互式写入数据库密码、JWT Secret 和 MaaS Key;使用 docker-compose.single.yml 构建并启动服务;检查容器状态、前端健康检查和后端 readiness;在浏览器完成注册、上传论文、学习解释和论文问答验证。示例命令中的配置均使用占位符,不包含真实凭据:cd /opt/paperlens chmod 600 deploy/huawei/.env.single docker compose \ --env-file deploy/huawei/.env.single \ -f deploy/huawei/docker-compose.single.yml \ up -d --build docker compose \ --env-file deploy/huawei/.env.single \ -f deploy/huawei/docker-compose.single.yml \ ps -a curl -fsS http://127.0.0.1/healthz curl -fsS http://127.0.0.1/api/v1/health/ready服务以 detached 模式运行,因此关闭本地 PowerShell 或 SSH 会话不会停止容器。ECS 重启后,Docker 服务与 Compose 的重启策略负责恢复应用。8.5 部署期问题闭环现象定位依据修正Docker Hub 拉取超时docker pull 访问官方 Registry 超时配置华为云 SWR 镜像加速并重启 DockerNginx 容器持续重启日志显示只读目录无法创建临时文件临时目录迁移到 /tmp,通过受限 tmpfs 提供写入PDF 上传失败后端日志显示持久卷目录权限不足启动前由一次性初始化服务修正卷所有权管理员升级 SQL 失败psql 变量替换与引号组合错误改用明确参数边界并先只读查询用户 ID论文问答前端报网络失败后端只有会话请求,没有问题请求为非安全 HTTP 环境增加 UUID v4 回退实现长页翻译偶发失败MaaS 请求耗时超过通用读取超时为学习解释配置独立、有限的读取超时部署验收以真实页面操作为准,不仅依赖容器显示 healthy。只有注册登录、论文上传解析、MaaS 学习解释、论文问答和管理员入口均完成小额验证,才认为案例具备可演示性。9. 应用效果与价值PaperLens 将“看 PDF、查术语、做笔记、问模型、整理报告”从多个割裂工具合并为一个连续流程。对个人学习场景而言,它带来的价值主要体现在:降低英文论文和专业概念的理解门槛;保持 AI 结果与当前论文、页码和原文选区的联系;让多轮问答、解释历史、高亮和笔记可以长期保存;通过华为云 MaaS 获得真实模型能力,同时保留 Mock 模型便于离线开发;通过码道代码智能体提升跨前后端开发和故障定位效率;使用单台小规格 ECS 即可完成课程设计、实习成果或个人演示部署。10. 局限与后续规划当前版本面向小规模个人使用,仍有以下边界:暂不支持扫描版论文 OCR;语义检索尚未使用持久化向量数据库;后台任务仍采用进程内执行器,不适合多实例横向扩展;单机 PostgreSQL 和本地文件卷需要定期备份;后续可根据实际用户量逐步引入 OBS、RDS、HTTPS、任务队列、pgvector 和多模态论文理解,但不在小规模案例阶段提前增加系统复杂度。11. 总结PaperLens 展示了如何将华为云码道(CodeArts)代码智能体、ModelArts Studio(MaaS)与常见 Web 技术结合,构建一套可实际部署的智能论文阅读学习应用。在研发侧,码道帮助项目完成需求拆解、跨文件编码、测试设计和部署故障定位;在运行侧,MaaS 提供总结、翻译、解释和问答能力;在基础设施侧,华为云 ECS 提供轻量、可控的容器运行环境。最终方案既满足个人学习项目的成本边界,也保留了向云数据库、对象存储和更可靠任务架构演进的空间。12. 参考资料华为云开发者空间实战案例参考页面华为云码道(CodeArts)代码智能体产品功能华为云码道(CodeArts)内置智能体用户指南ModelArts Studio(MaaS)API 调用规范华为云弹性云服务器 ECS 产品介绍
-
食堂菜品评价管理系统:基于 CodeArts Agent 的构建与华为云部署一、概述1.1 案例介绍校园食堂评价存在三个痛点:缺少上下文、结构与后续处理。本系统以日期、餐次、窗口和菜品确定的菜单项为评价对象,支持多维评分、过敏原筛选、审核与改进任务。开发时使用 CodeArts Agent 按规格拆分任务,并通过 Context7、Playwright MCP 核对资料与定位问题。最终构建成功,26 条关键流程测试通过,系统已部署至华为云 ECS 与 RDS for MySQL,公网验证首页、接口和图片加载正常。1.2 适用对象与案例流程本案例适合高校学生、全栈 Web 初学者,以及希望了解 CodeArts Agent 与 Skill/MCP 协作流程的开发者。整体流程可分为五步:读取项目规格与工程上下文。由 CodeArts Agent 生成并拆分可执行任务。按业务模块完成前后端与数据库实现。使用 Playwright 发现并修复真实数据与接口问题。部署到华为云 ECS/RDS,并验证公网访问。1.3 资源总览资源本案例中的实际用途CodeArts Agent根据规格辅助任务拆分、代码实现和问题定位Skill规范文档、架构图和检索任务的步骤与验收方式Context7 / Playwright MCP资料核对、页面检查和控制台错误定位ECS、EIP、VPC/安全组、RDS for MySQL公网运行、私网数据库连接和部署验证二、环境和资源准备2.1 本地工程与运行条件项目基于 TypeScript pnpm Monorepo 构建,本地复现需要 Node.js 22、pnpm 9 与 Docker(用于启动 MySQL)。README 中已给出最小运行命令:docker compose up -d pnpm install cp .env.example .env pnpm --filter api prisma:migrate pnpm --filter api prisma:seed pnpm dev:api pnpm dev:web.env.example 可作为环境变量模板,真实 .env 包含数据库密码与 JWT 密钥,不应提交或展示。2.2 CodeArts Agent、Skill 与 MCP 配置由于系统包含多角色权限、匿名边界、状态流转和统计规则,直接按页面逐个生成容易前后端字段不一致。开发时采用 CodeArts Agent 的 Spec-Driven 模式:先把业务边界、角色权限和验收标准写入规格,再让 Agent 读取项目目录并拆分为可执行任务。Skill 用于约束文档、架构图和规格检索任务的输入、步骤和验收方式。例如,架构图任务要求保留可编辑的 Draw.io 源文件;文档任务要求保留关键截图和边界说明。这些约束使同类任务得到相对稳定的产出,但不能替代业务判断。项目还启用了 Context7 与 Playwright MCP。Context7 用于查询 React Router、Vite 等依赖的版本资料,核对当前实现是否匹配;Playwright MCP 用于检查页面语义、执行交互、读取控制台错误,并验证真实页面状态。三、对话 CodeArts Agent:构建食堂菜品评价管理系统3.1 读取规格并建立工程骨架进入实现前,先向 CodeArts Agent 提供业务目标、技术基线和产品与开发规格。Agent 读取项目目录与已有文档后,按需求、方案、任务三个阶段推进:需求阶段整理认证、菜品、菜单、评价、审核、改进、分析和审计要求;方案阶段分析模块职责、接口、数据模型与异常处理;任务阶段将方案拆分为前端页面、后端模块、共享契约和数据库模型的具体改动。每个阶段都需要人工检查文件变更和实际运行结果,而不是由 Agent 自动完成全部工作。工程骨架建立后,Monorepo 包含 apps/web(顾客端与管理端)、apps/api(NestJS 后端)、packages/contracts(共享 DTO 与校验规则)和 e2e(关键流程测试)。3.2 按业务模块实现核心功能核心功能按“业务约束 -> 用户操作 -> 后端保障”的顺序实现,避免按前端组件或代码目录流水账展开。每日菜单与评价入口。 顾客端按日期、餐次和窗口查询菜单。无论从菜单页、二维码深层链接还是刷新后的评价页进入,页面都通过 menuItemId 恢复菜品和窗口信息,不依赖前一页面的内存状态。后端校验菜单项是否存在、是否处于可评价状态、是否超过截止时间,以及同一用户是否已提交过评价。过敏原筛选与个人偏好。 菜品库支持关键字、分类、窗口、价格、最低评分和排序条件,筛选状态写入 URL 查询参数。登录用户启用“避开我的过敏原”后,safeForMe 同时进入 Query Key 和接口参数,后端根据个人偏好排除匹配菜品,避免只在前端隐藏数据。const { data: result } = useQuery({ queryKey: ['dishes', q, categoryId, windowId, page, safeForMe], queryFn: () => api.getWithMeta<DishListItem[]>('/dishes', { q: q || undefined, categoryId: categoryId || undefined, windowId: windowId || undefined, safeForMe: safeForMe || undefined, page, pageSize: 12, }), }); 多维评价、审核、通知与改进任务。 评价包含总体评分,以及口味、分量、性价比和卫生观感四项可选评分;用户还可以选择结构化标签、填写正文并决定是否匿名。匿名只影响公开展示,数据库仍保留评价者关联,以便限制重复评价和处理违规记录。低分评价可以创建改进任务,记录负责人、处理措施、目标日期、状态和验证区间;完成任务时要求填写结果说明和验证区间,样本不足时不直接宣称改进有效。const [items, total] = await Promise.all([ this.prisma.improvementTask.findMany({ where, include: { dish: { select: { id: true, name: true } }, owner: { select: { id: true, displayName: true } }, reviews: true, }, orderBy: { createdAt: 'desc' }, }), this.prisma.improvementTask.count({ where }), ]); 改进任务列表明确返回页面需要的菜品和负责人信息,避免前端再按演示数据补字段;同时只选择必要字段,避免将内部用户数据带入响应。数据看板、用户管理与审计。 管理端提供菜品、菜单、评价、改进任务、数据看板、用户管理与审计查询。管理员不能修改自己的角色或禁用自己的账号;前端将按钮置灰只能改善体验,真正的权限判断由后端 API 返回 403,自动化测试直接验证该边界。移动端高频入口。 顾客端在 375 像素宽度下使用底部导航,保留菜单、菜品库、我的评价和偏好等高频入口,避免桌面端导航在移动端占用过多空间。3.3 开发阶段成果小结层次实际成果前端顾客端、管理端、响应式导航与真实数据展示后端认证、菜单、菜品、评价、改进、分析、审计模块数据库Prisma 迁移、菜单项与评价相关约束、演示种子数据契约共享 DTO、枚举和校验规则四、测试、问题修复与华为云部署4.1 从页面可打开到真实数据可用早期页面检查出现过“页面可打开,但菜单数据为空”的情况。最初自动化用例只断言页面标题可见,因此即使列表没有数据,测试仍会通过。Playwright MCP 进一步发现控制台存在认证和资源错误。根因定位分为两层:一是分页接口存在 { data, meta } 与 { items, total } 两种真实契约,需要按端点分别处理;二是测试断言只检查标题,没有验证真实记录是否出现在页面中。修复时,分别处理响应结构,并将断言提升为真实菜单、菜品、改进任务和用户记录可见。另一个隐蔽问题是 Prisma Decimal 在 JSON 中表现为字符串。顾客端 Math.round 会发生隐式数值转换,表面上可以工作;管理端调用 toFixed 时却触发运行时异常。最终在页面适配层显式使用 Number() 转换,并兼容嵌套分类字段。改进任务列表也补齐了菜品和负责人关系,避免前端硬编码演示数据。4.2 自动化测试结果最终执行以下命令:pnpm build pnpm exec playwright test e2e/api.spec.ts e2e/admin.spec.ts e2e/customer.spec.ts --reporter=linepnpm build 成功,关键流程测试结果为 26 passed。覆盖范围包括健康检查、登录、菜品与菜单查询、个人偏好、评价审核、改进任务、数据看板、用户管理、管理员自身保护、顾客端菜单与移动导航等流程。测试运行依赖本地 MySQL、已执行的 Prisma 迁移和种子数据;完整云端 Playwright 回归不在本次范围。4.3 华为云部署与公网验证部署架构如图 7 所示:浏览器请求先到达 EIP 1.94.198.53,进入 ECS 上的 Nginx;Nginx 直接提供 React 静态页面和 /uploads/ 图片目录,并将 /api/ 请求反向代理至本机 127.0.0.1:3000 的 NestJS API;API 由 PM2 管理,并通过 VPC 私网访问 RDS for MySQL。实际部署中处理了两个具体问题。一是原生模块 bcrypt 在 ECS 安装时预编译二进制下载失败,替换为纯 JavaScript 实现的 bcryptjs 后种子脚本可正常执行。二是 RDS 密码中的 $ 需要在 DATABASE_URL 中编码为 %24,否则 Prisma 报 P1013 连接 URL 格式错误。修正后成功应用 2 条迁移,并初始化 20 个菜品、372 条菜单记录和 100 条评价记录。演示图片也同步到 ECS 的运行时上传目录,Nginx 通过 /uploads/ 静态映射提供。已通过公网验证的内容包括:首页 http://1.94.198.53/健康检查 /api/v1/health菜品接口 /api/v1/dishes?pageSize=1指定日期和餐次的 menu-items 查询菜品图片静态资源加载五、案例总结与资源说明本案例展示了如何借助 CodeArts Agent 的 Spec-Driven 模式,将食堂菜品评价管理系统的业务规格拆分为可执行任务,并在实现、调试与部署阶段持续协作。Agent 的价值在于加速任务分解、代码生成和问题定位,而业务边界、代码变更和测试结果仍需人工确认。
-
怎么搭建啊 求助 来个资深老玩家
-
Pod 无法正常启动
-
今天在测试mysql主从复制的时候 导入数据过多
-
昨天我使用还好好的,今天找不到了
-
前言OpenHarmony 轻量系统的固件构建通常会卡在三个地方:构建机架构、预编译工具链、源码和依赖下载。尤其是像 xiaohong (atomgit 开源的软硬件一体项目) 这类面向 WS63 芯片的项目,工具链、Python 依赖、repo 同步、clang 路径等细节只要有一处没对齐,就很容易在编译中途报错。这次我们尝试把 xiaohong 固件构建流程放到华为云上完成:通过 AI Shell 创建云端 ECS、准备构建环境、下载源码、配置工具链并完成固件编译。整体体验下来,AI Shell 比较适合这类“步骤多、依赖多、容易踩坑但流程可沉淀”的云端自动化任务。案例介绍xiaohong 是基于 OpenHarmony 的迷你系统,专为 WS63 芯片设计。本案例介绍如何使用华为云 AI Shell 从零开始编译 xiaohong 固件,包括环境准备、源码下载、工具链配置、编译过程以及常见问题解决方案。最终产物为:ws63-liteos-app_all.fwpkg:完整固件ws63-liteos-app_load_only.fwpkg:仅加载固件为什么适合用 AI Shell这个任务并不是单条命令能解决的问题,而是一个典型的云端构建流水线:需要创建合适规格和架构的 ECS。需要安装大量系统依赖和 Python 依赖。需要同步较大的 OpenHarmony 相关源码和预编译工具。需要处理工具链路径、软链接和环境变量。编译完成后还要下载固件并清理云资源。如果每次都手工操作,容易遗漏步骤。使用 AI Shell 的价值在于:可以用自然语言描述目标,再把重复流程沉淀为 skill 或脚本,后续复用时只需要发起任务即可。核心要点架构选择:必须使用 x86_64 架构的 ECS,预编译工具链不兼容 aarch64。源码下载:使用 repo 工具,并在 repo init 时添加 --git-lfs。工具链配置:需要配置 RISC-V 编译器 PATH,并创建 clang 软链接。Python 依赖:需要安装 kconfiglib、pycparser、markupsafe 等模块。构建命令:使用 ./build.sh --product-name xiaohong --gn-args is_debug=false。资源清理:构建完成后及时保存固件并释放 ECS,避免资源持续计费。适用对象企业个人开发者高校学生案例时间本案例总时长预计60分钟。资源总览创建华为云资源需要收费,请按需充值。本案例中编译环境所创建的云资源预计花费10元。资源名称规格单价(元)AI Shell体验版免费华为云资源按需10整体流程流程可以理解为:用户在开发者空间向 AI Shell 下达编译 xiaohong 固件任务。AI Shell 调用 xiaohong build skill 或自动化脚本。AI Shell 创建 x86_64 ECS 并准备构建环境。ECS 完成源码同步、工具链配置、固件编译。用户下载固件产物,并按需销毁 ECS。案例步骤0. 进入 AIShell参考教程探索智能 Shell 交互新范式 详解 AI Shell 完整用法或者产品文档AI Shell,云上开发运维效率升级 进入到 AI Shell 界面进入到 AIShell 我们应该能看如下界面,和我们常用的 OpenCode、AtomCode 等产品类似,可以输入:1. 使用 xiaohong-build-skill此处,我们不再介绍 AIShell 的详细功能和能力,留给大家自行探索。首先我们输入/确认一下所有功能是否都已经开启(默认是开启了所有的功能),如下图:虽然我们一句话就能实现 xiaohong 编译环境搭建、编译运行,但是为了了解背后的细节,我们先让 AIShell 帮我熟悉熟悉:帮我看看这是什么: https://atomgit.com/huqi/xiaohong-build-skill,如何使用?此处我们理解权限安全规则,这里按需选择 Allow once 或者 Allow always,我选择的是 Allow always,可以左右键切换选择并回车确认:接着我们就让 AIShell 执行这个 skill,如果遇到:帮我实际运行这个 skill 来编译 xiaohong 固件从右侧任务列表我们可以看到类似的:检查前置条件检查华为云凭证创建 ESC 实例构建配置环境下载源码编译固件下载固件到本地清理资源如果我们的华为云账号有幸绑定了短信,在 ECS 创建完我们也能收到短信,当然也能去控制台查看,类似:接下来只需静静等待 Task 被一一执行完。理想情况下,我们会看到 AI Shell 会继续自动执行下去,比如进入到 ECS 中安装依赖:比如下载源码:最终能看到编译完成:2. 下载固件下载固件的方式有很多种,比如让 AIShell 上传到 OBS ,当然我们也可以去 ESC 实例里手动下载:3. 后续后续可以让 AIShell 指导我们烧录固件:题外话:让 AIShell 帮我修改源码,重新编译固件写入我专属的引导语释放资源最后记得让 AIShell 释放资源:帮我释放这次创建的所有资源Q&A⚠️ The maximum number of model requests in a single turn is exceeded原因是触发了 MaaS 的限流,只需回复 “继续” 就行如果我开发的不是 xiaohong 而是其他平台如 小智 等,那怎么办?在我们看来,底层逻辑都是相通的,我们的目的是搭建编译环境–编译–获取产物,理论上只需要把相关的指导文档发给 AIShell 就行,类似的: 我想搭建环境编译 https://github.com/78/xiaozhi-esp32 ,应该怎么做?本文正在参与:【案例共创】【第12期】基于华为云AI Shell完成云资源管理、云服务运维和应用部署
推荐直播
-
华为云码道Skill实战与极速交付,智能开发全链路实战2026/07/22 周三 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;姜浩-华为云HCDG核心组成员
直播深度解读华为云码道6月产品新特性,从Skill市场安装专家技能,带你零距离体验从需求,开发,审查,重构全链路闭环的开发过程。从零构建并交付一个完整项目,让您体验从代码提交到服务上线的“极速”之旅。
回顾中 -
聚开发者之力,创具身新未来2026/07/23 周四 15:00-17:00
张豪杰/程文/王军/刘新春/黄钦开 /张晓天
本次华为云具身智能开发平台CloudRobo培训面向具身智能开发者,带您全流程体验机器人本体R2C小时级接入、环境重建与轨迹生成仿真数据生产、PB级数据管理、数据评测、模型训推、强化学习和Benchmark一键评测等功能,并体验业界主流具身模型应用。
回顾中
热门标签