软件工程第一次作业-102402126黄炜杰
| 这个作业属于哪个课程 | 2026级软件工程与软件工程实践(H202601) |
|---|---|
| 这个作业要求在哪里 | 2026秋软件工程个人作业(第一次) |
| 这个作业的目标 | 熟悉课程以博客园、GitHub 为主的实践体系,通过调用 HuggingFace API 实现 AI 生图交互页面初步体验大模型的实际应用能力,并完成个人技能评估与学习规划 |
| 学号 | 102402126 |
2026秋软件工程个人作业(第一次)
一、HuggingFace API 调用:AI 生图交互页面
1.1 实现思路
整体采用"前端页面 → Flask 后端 → Hugging Face Inference Providers"三层结构:
- 模型选择:
XLabs-AI/flux-RealismLora是挂在 FLUX.1-dev 底模上的照片真实感 LoRA,调用它 = FLUX.1-dev + 真实感权重出图,目标是让结果接近真实摄影而非"AI 插画味"。 - API 调用:使用
huggingface_hub.InferenceClient(provider="auto", api_key=HF_TOKEN)的text_to_image接口。注意旧版api-inference.huggingface.co接口已停用,2024 年前的老教程代码会报 410/404,统一改走 Inference Providers。 - 令牌安全:HF 令牌只放在后端环境变量
HF_TOKEN中,浏览器端不接触令牌——这是 Web 应用调用鉴权 API 的标准做法,避免令牌泄露。 - 交互流程:前端页面可填提示词、负向提示词、种子,点击"生成图像"后
fetch调用后端/api/generate,后端转发到 Hugging Face,把返回的 PNG 以 base64 显示在页面上,同时落盘到outputs/并向calls_log.jsonl追加一条调用记录(时间、模型、提供方、耗时、提示词、输出路径)。 - 运行方式:
python -m pip install -r requirements.txt装依赖 →$env:HF_TOKEN = "hf_你的令牌"→python app.py→ 浏览器打开http://127.0.0.1:5000。另有generate_image.py脚本版可先单测跑通 API。
1.2 代码展示
项目结构:
hf-flux-realism-demo/
├── generate_image.py # 方式 A:脚本直接调用 API
├── app.py # 方式 B:Flask 后端(前端 + 后端一体)
├── static/index.html # 前端交互页面
├── requirements.txt # 依赖:huggingface_hub / flask / pillow
├── outputs/ # 生成的图片
└── calls_log.jsonl # 每次调用的记录(成功日志素材)
① API 核心调用(generate_image.py)
# -*- coding: utf-8 -*-
"""通过 Hugging Face Inference Providers 调用 XLabs-AI/flux-RealismLora 生成照片级真实图像。"""
import os, sys, time, json, datetime
from pathlib import Path
from huggingface_hub import InferenceClient
MODEL_ID = "XLabs-AI/flux-RealismLora" # FLUX.1-dev 的照片真实感 LoRA
PROVIDER = os.environ.get("HF_PROVIDER", "auto") # auto 自动选择模型页可用的提供方
DEFAULT_PROMPT = (
"natural candid photo of a young woman laughing in a rainy city street at night, "
"neon reflections on wet ground, shot on 35mm film, realistic skin texture, "
"cinematic lighting, shallow depth of field"
)
NEGATIVE_PROMPT = "cartoon, anime, illustration, painting, drawing, deformed, ugly, watermark"
def main():
token = os.environ.get("HF_TOKEN")
if not token:
sys.exit("请先设置环境变量 HF_TOKEN(在 huggingface.co/settings/tokens 创建令牌)")
prompt = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_PROMPT
client = InferenceClient(provider=PROVIDER, api_key=token)
t0 = time.time()
image = client.text_to_image(
prompt,
model=MODEL_ID,
negative_prompt=NEGATIVE_PROMPT,
width=1024,
height=1024,
num_inference_steps=28,
guidance_scale=3.5,
)
elapsed = time.time() - t0
out_dir = Path(__file__).parent / "outputs"
out_dir.mkdir(exist_ok=True)
stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
out_file = out_dir / f"flux_realism_{stamp}.png"
image.save(out_file)
# 向 calls_log.jsonl 追加一条调用记录,作为"API 调用成功记录"的素材
record = {"time": stamp, "model": MODEL_ID, "provider": PROVIDER,
"status": "success", "elapsed_seconds": round(elapsed, 1),
"prompt": prompt, "output": str(out_file)}
with open(Path(__file__).parent / "calls_log.jsonl", "a", encoding="utf-8") as f:
f.write(json.dumps(record, ensure_ascii=False) + "\n")
print(f"[成功] 耗时 {elapsed:.1f} 秒,图片已保存:{out_file}")
if __name__ == "__main__":
main()
② Flask 后端(app.py,关键部分)
# -*- coding: utf-8 -*-
"""前端 + 后端一体:Flask 提供交互页面,后端代调 Hugging Face 推理 API。
令牌只放在后端环境变量里,不暴露给浏览器。"""
import base64, io, json, os, time, datetime
from pathlib import Path
from flask import Flask, jsonify, request, send_from_directory
from huggingface_hub import InferenceClient
BASE = Path(__file__).parent
MODEL_ID = "XLabs-AI/flux-RealismLora"
PROVIDER = os.environ.get("HF_PROVIDER", "auto")
app = Flask(__name__)
_client = None
def get_client():
global _client
if _client is None:
token = os.environ.get("HF_TOKEN")
if not token:
raise RuntimeError("缺少环境变量 HF_TOKEN,请先设置后再启动")
_client = InferenceClient(provider=PROVIDER, api_key=token)
return _client
@app.route("/")
def index():
return send_from_directory(BASE / "static", "index.html")
@app.route("/api/generate", methods=["POST"])
def generate():
data = request.get_json(force=True)
prompt = (data.get("prompt") or "").strip()
if not prompt:
return jsonify(error="prompt 不能为空"), 400
kwargs = dict(
model=MODEL_ID,
negative_prompt=data.get("negative_prompt")
or "cartoon, anime, illustration, painting, deformed, watermark",
width=int(data.get("width", 1024)),
height=int(data.get("height", 1024)),
num_inference_steps=int(data.get("steps", 28)),
guidance_scale=float(data.get("guidance", 3.5)),
)
seed = data.get("seed")
if seed not in (None, ""):
kwargs["seed"] = int(seed)
t0 = time.time()
try:
image = get_client().text_to_image(prompt, **kwargs)
except Exception as exc: # 把 API 报错原样返回给前端便于截图记录
return jsonify(error=f"API 调用失败:{exc}"), 500
elapsed = time.time() - t0
out_dir = BASE / "outputs"
out_dir.mkdir(exist_ok=True)
stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
out_file = out_dir / f"flux_realism_{stamp}.png"
image.save(out_file)
buf = io.BytesIO()
image.save(buf, format="PNG")
# …(追加 calls_log.jsonl 记录,同脚本版)…
return jsonify(
image_base64=base64.b64encode(buf.getvalue()).decode(),
file=str(out_file),
elapsed=round(elapsed, 1),
)
if __name__ == "__main__":
app.run(host="127.0.0.1", port=5000, debug=False)
③ 前端交互脚本(static/index.html 的 JS 部分)
const btn = document.getElementById('go');
btn.addEventListener('click', async () => {
const prompt = document.getElementById('prompt').value.trim();
if (!prompt) { statusEl.textContent = '请先输入提示词'; return; }
btn.disabled = true;
statusEl.textContent = '调用中……首次调用提供方冷启动可能需要数十秒,请耐心等待';
try {
const resp = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt,
negative_prompt: document.getElementById('neg').value.trim(),
seed: document.getElementById('seed').value.trim()
})
});
const data = await resp.json();
if (!resp.ok) throw new Error(data.error || ('HTTP ' + resp.status));
const img = document.getElementById('result');
img.src = 'data:image/png;base64,' + data.image_base64;
img.style.display = 'block';
statusEl.textContent = '生成成功,耗时 ' + data.elapsed + ' 秒';
} catch (e) {
statusEl.textContent = '失败:' + e.message;
} finally {
btn.disabled = false;
}
});
页面完整 HTML/CSS(暗色主题、提示词输入框、负向提示词与种子设置、结果展示卡片)见附件项目
static/index.html,博文中可按需粘贴。
1.3 API 调用成功记录

1.4 前端页面生成图像效果


1.5 提示词设计思路与修改过程
总体思路:这个 LoRA 的目标是"照片感",所以提示词要用摄影语言写,而不是用插画语言写。对 FLUX + 真实感 LoRA 来说,"怎么拍"(胶片型号、镜头、光线、颗粒)比"拍什么"(主体描述)更能决定最终图像像不像真实照片——因为 LoRA 训练集的 caption 里大量包含这类摄影术语。修改过程遵循"基线 → 加摄影要素 → 加细节与瑕疵 → 负向提示词收口"四步:
| 版本 | 提示词(要点) | 生成效果与问题 |
|---|---|---|
| V1 基线 | an elderly fisherman mending nets on a wooden dock |
主体正确但构图随机、皮肤质感发"塑料",仍有明显的 AI 插画味 |
| V2 加摄影要素 | 追加 shot on Kodak Portra 400 35mm film、natural overcast light、Leica Summilux 35mm f/1.4, shallow depth of field |
真实感明显提升,出现胶片色调和背景虚化;但人物过于"干净完美",像摆拍 |
| V3 加细节与瑕疵 | 追加 wrinkled sun-damaged skin with visible pores and stubble、faded flannel shirt with frayed threads、mist over gray water、subtle film grain、minor lens imperfections, no retouching、documentary photography |
皮肤纹理、衣物磨损、环境雾气都到位,"抓拍纪实感"成立 |
| 最终版 | V3 基础上再加负向提示词收口(见下) | 压掉了偶尔滑向磨皮/影楼风的随机输出 |
负向提示词:airbrushed, beauty filter, smooth plastic skin, makeup, glam, ...——思路不是排除"画错的东西",而是专门排除破坏照片真实感的美化倾向(磨皮、美颜滤镜、影楼妆感),把模型向"精修人像"滑动的情况压回"纪实摄影"。
对照实验方法:固定 seed=42,只替换 V3 中的单个短语(如删掉 subtle film grain),对比两次输出的差异截图——这样"修改过程"就有可复现的证据,而不是凭感觉说"改好了"。
1.6 操作经验总结
- 鉴权前置是基本安全习惯:HF 令牌必须放后端环境变量
HF_TOKEN,浏览器端不接触。如果前端直连 Hugging Face,任何访问者都能从页面源码里拿走令牌——这次把"前端 → Flask 后端 → API"的代理层搭起来后,才真正理解"密钥不出后端"不是一句空话。 - 接口在演进,教程会过期:旧版
api-inference.huggingface.co接口已停用,网上 2024 年前的老教程代码直接报 410/404。现在统一走 Inference Providers(InferenceClient(provider="auto")),同一个模型可以在多个算力提供方之间切换,排错时要先看模型页确认当前可用的提供方(注意官方名称是fal-ai而不是fal)。 - 冷启动与耗时:首次调用提供方冷启动明显偏慢(数十秒级),之后同一模型再调就快很多。我在后端给每次调用记了耗时并写入
calls_log.jsonl,最终一次生成 12.7 秒——没有度量就没有体感,日志同时还能直接当作业截图素材。 - 提示词工程的重心:照片感 LoRA 对摄影术语(胶片型号、镜头、光线、颗粒、"未修图")极其敏感,对主体本身的形容词反而没那么敏感。写提示词更像在给摄影师下拍摄需求单,而不是在描述一幅画。
- 随机性管理:不固定种子时,同一提示词两次输出差异很大,容易误判"改动有没有效"。固定 seed 做单变量对比后,评估才变得可靠——这大概就是软件工程里"可复现实验"的直觉版本。
- 许可证意识:flux-RealismLora 沿用 FLUX.1-dev 的非商业许可,作业使用没问题但不能商用。模型选型时许可证和效果同等重要,这是之前完全没考虑过的维度。
二、GitHub 个人主页搭建
采用方案:创建个人资料自述文件(Profile README)。新建一个与 GitHub ID 完全同名的公开仓库,在其根目录 README.md 中撰写个人介绍,GitHub 会自动将其作为个人主页展示。
搭建步骤:
- 登录 GitHub,点击右下角
+→New repository - Repository name 填入与自己的 GitHub 用户名一模一样的字符串(如用户名为
zhangsan,仓库名也必须写zhangsan),可见性选 Public - 勾选
Add a README file,点击Create repository - 进入仓库,点击
README.md→ 右上角铅笔图标编辑,将撰写好的主页内容粘贴进去,Commit changes保存 - 打开
https://github.com/X-runner354验证主页效果,确认渲染正常
- 主页地址:【 https://github.com/X-runner354 】
2.1 主页截图
【贴图:https://github.com/X-runner354 页面完整截图,建议包含头像、简介、技能树与规划部分,滚动截长图更佳】

2.2 主页内容说明
- 自我介绍:主页以"一个想把'能跑就行'变成'能稳定地跑'的初学者"开场,介绍专业班级、目前沉迷的方向(用大模型解决实际问题),爱好【填写 2~3 项,如跑步、摄影、看悬疑小说】,并附博客园主页与联系方式,方便同学交流。
- 成果与技能:技能部分按编程语言星级表 + 工具环境两个维度列出(Python / C / 前端基础 / Git / Flask),并配了两个实际项目:一是"蒲公英计划"感恩主题网站(1 主页 + 3 人物故事详情页的纯前端项目,含签名墙、知识挑战等交互功能),二是本次作业的 HF Flux 生图应用(Flask 前后端一体、令牌保护、调用日志),每个项目都写明了技术要点与踩过的坑。
- 自我评估:分"已掌握 / 感兴趣方向 / 最希望学习"三层,并单独成段写了"我清楚自己还不会什么"——大型项目架构设计、多人协作规范、测试与 CI/CD、算法竞赛能力,直接回应了作业要求中"了解你会什么以及你不会什么"这一关注点。
- 三年规划:主线考研,方向倾向人工智能 / 软件工程。理由是想在 AI 方向走得更深,补上本科阶段零散工具学习之外的系统理论。规划按大三(打基础 + 数学英语推进 + 争取竞赛或科研经历)、大四上(全力备考)、大四下(做一个真正上线有人用的毕业设计)三段列出可验证目标,并给出备选路径:若升学不理想,先从工程侧进入 AI 应用团队工作,之后再判断是否返校深造。
三、技能树自我评估与学习规划
3.1 技能树与技术偏好
【按要点清晰列出,逻辑明确。形式不限,可用表格】
| 能力 | 掌握程度 | 说明 |
|---|---|---|
| 【Python】 | 【熟练】 | 【感恩小程序】 |
| 【前端】 | 【了解】 | 【静态网页】 |
| 【Git】 | 【基本了解】 | 【课程活动】 |
- 感兴趣的技术方向:【软件工程】
- 还欠缺的能力:【系统架构设计能力】
3.2 代码量
- 截至目前代码量:约 6500 行(包含课程作业和练习)。
- 本学期课程结束后希望达到:15000行,
3.3 对课程的期待
- 最期待学习的知识:【软件生命周期与工程化开发方法(如需求分析、系统架构设计、敏捷开发与项目管理等),以及现代软件开发工具链与质量保证技术(如自动化测试、DevOps等)】
- 希望获得的收获:【建立系统化的软件工程思维,能够独立或协作完成从需求获取、系统设计、编码实现到测试维护的完整软件项目,并具备解决复杂工程问题、跨团队协作及持续学习的能力,为未来的职业发展打下坚实的工程实践基础。】
3.4 AI 生成的软件工程课程学习指南
【使用DeepSeek生成,将指南原文粘贴如下】
AI 时代的软件工程课程学习指南:从传统开发到智能工程
在人工智能技术飞速发展的当下,软件工程的底层逻辑正在经历深刻变革。从“以人力为核心”的工业化生产模式,转向“知识密集型”的智能化生产模式。开发者不再仅仅是代码的编写者,更是AI工具的驾驭者和系统架构的设计师。本指南旨在为你提供一套系统化、面向未来的软件工程学习路径,帮助你在AI时代建立核心竞争优势。
一、 核心认知:AI 时代软件工程的新范式
在学习具体技术之前,首先需要完成认知上的升级。AI 软件工程并非简单的“产品+AI”叠加,而是软件生产逻辑的重构。
角色转变:开发模式正从“面向代码”转向“面向规约(Spec Coding)”。开发者的核心能力转变为精准定义需求、规则与约束,由AI生成可落地的代码。
人机协同:未来的开发团队将是“三元混合劳动力体系”,包括全人劳动力(负责高复杂度战略任务与价值判断)、人携智能体劳动力(人机协同完成需求/代码/测试)以及智能体自闭环劳动力(负责标准化低风险任务)。
基础依然重要:尽管 Coding Agent 的代码编写能力日益强大,但开发者仍需深刻理解系统工作原理。AI 负责“正确地做事”,而人负责判断“什么是正确的事”。
二、 核心技能图谱:AI 时代的软件工程基础
结合行业最新需求与专家共识,AI时代的软件工程基础可划分为以下五大核心模块:
全栈应用开发:借助 AI 辅助,开发者可以跨越不熟悉的技术领域。重点在于理解 UI 组件、API 设计、状态管理、数据持久化等组件如何解决实际问题并相互连接,从而判断 AI 生成的实现是否符合整体设计。
数据管理:数据是软件系统的核心资产。学习如何根据访问方式决定数据模型与存储方式(关系型、文档、键值等),并掌握事务并发控制、数据一致性保障,以及隐私合规等数据生命周期管理。对于 AI 应用,数据架构直接决定了模型能获取的上下文质量。
系统架构设计:架构取决于业务需求。学习如何根据用户规模、延迟敏感度、成本要求等条件,进行前后端边界划分、系统拆分及单体/微服务架构选择。理解架构需随项目阶段和业务复杂度动态演进。
安全与可靠性:建立完善的测试策略(单元测试、集成测试),并设计应对 API 限流、服务降级等故障场景的容错机制。同时,需掌握安全左移实践,理解供应链风险、代码漏洞扫描及云配置安全,确保 AI 生成代码的可靠性。
生产环境扩展与运行:掌握完整的软件生命周期,包括 CI/CD 自动化部署、可观测性(监控与告警)建设、负载均衡及数据基础设施调整。此外,版本控制、代码评审和技术债管理决定了项目的长期可维护性。
三、 进阶学习路径:从基础到智能工程化
建议遵循“基础 → 应用 → 工程化 → 进阶”的分阶段路径,坚持“70%实践 + 20%交流 + 10%理论”的原则。
基础准备阶段:掌握 Python 核心语法、异步编程、API 调用及 Git 版本控制。补充必要的数学基础(线性代数、概率统计),重点理解概念与适用场景,无需深究公式推导。
应用开发阶段:深入学习提示词工程(Prompt Engineering)、检索增强生成(RAG)技术以及 Agent(智能体)基础。通过构建公司内部文档问答系统、个人知识库助手等完整应用,验证学习成果。
工程化阶段:建立自动化评估体系,使用数据而非感觉指导迭代。掌握容器化部署(Docker)、API 服务封装、模型量化及并发处理。学习 LLMOps,包括 CI/CD 流水线、灰度发布及监控运维。
进阶与专精阶段:探索模型微调(LoRA/PEFT)、复杂多 Agent 协作及长周期任务规划。关注 AI 系统架构设计、多模态应用及边缘 AI 技术,并根据场景权衡 RAG 与微调、API 与自部署的成本与效果。
四、 实践与验证:打造你的核心竞争力
纸上得来终觉浅,绝知此事要躬行。在学习过程中,务必注重工程化思维的培养与实战能力的验证。
项目驱动学习:参与或主导完整的 AI 应用开发项目,从需求分析、架构设计到测试上线,体验全流程。尝试将传统业务进行智能化升级,例如构建基于大模型的违禁品识别系统或智能客服,积累可迁移的行业解决方案。
建立评估驱动思维:在开发中引入“AI 生成、AI 验证”的质量保障闭环。构建测试集,利用 LLM 作为评判进行离线与线上评估(关注正确率、幻觉率、延迟、成本等指标)。
能力验证与输出:在 GitHub 上维护 2-3 个包含完整 README 与在线演示的项目。通过撰写技术博客、参与开源社区贡献或对照面试题库自测,持续检验和提升自己的工程化水平。
五、 推荐学习资源
经典课程:吴恩达(Andrew Ng)的 Coursera 系列课程及 DeepLearning.ai 短课程、3Blue1Brown 的数学可视化教程。
核心工具:LangChain、LlamaIndex、Hugging Face Transformers、Vercel AI SDK。
必读书籍:《深度学习》(花书)、《AI Engineering》(Chip Huyen)、《AI Agents Guidebook》。
实战平台:Kaggle 竞赛、AgentInterview 开源项目。
我的分析:
✅哪些建议对你有帮助?
全栈应用开发基础:无论AI多强大,理解前后端交互、API设计、数据库模型依然是《软件工程》课程的核心。你可以借助AI来加速这部分的学习。
安全与可靠性(测试策略):指南中提到的“建立自动化评估体系”和“单元测试/集成测试”是软工课程的必考点和必做项。你可以尝试用AI帮你生成测试用例,这非常实用。
项目驱动与版本控制:强调在GitHub上维护项目、使用Git进行版本控制,这完美契合了软工课程的团队作业要求。
生产环境扩展(CI/CD):了解持续集成和持续部署的概念,对你完成软工课程的最终答辩和交付有极大的加分作用。
❌ 哪些建议不切实际?
数学基础与模型微调(LoRA/PEFT):这是“算法工程师”或“AI研究员”的技能。对于软工课程而言,你不需要去推导公式或微调大模型,你的任务是调用API构建应用和设计系统架构。
复杂多Agent协作与边缘AI:这些属于进阶研究方向,对于刚接触软工课程的学生来说门槛过高,且很难在短短一学期的课程作业中落地。
完全转向“面向规约(Spec Coding)”:虽然这是趋势,但在学校课程中,老师依然会考察你的底层编码能力和对系统原理的理解。你不能完全依赖AI生成代码而放弃自己思考架构。
💡 能否真正指导你的学习?(如何调整)
这份指南不能直接作为《软件工程》课程的学习大纲,但可以作为你的“课外拓展与进阶路线图”。
为了真正指导你的课程学习,建议你这样调整:
主线(占70%精力):严格按照学校软工课程的教学大纲走。扎实掌握需求分析(UML图)、系统设计、传统软件测试、项目管理(敏捷/瀑布)等传统软工核心知识。
副线(占30%精力):把这份指南作为“加分项”。在课程的大作业或毕业设计中,尝试引入指南中的AI工程化思维。例如:用AI辅助编写测试脚本、使用RAG技术为项目增加一个“智能问答模块”、或者用AI生成部分代码并自己进行Code Review。
总结来说: 这份指南是一份优秀的“AI应用工程师”转型指南,但对于你的软工课程,你需要“降维使用”——用传统的软工方法论去驾驭AI工具,而不是被AI工具带偏了软工基础。
四、博文编辑页面截图


浙公网安备 33010602011771号