文章目录
- 前言
- 一、项目背景
- 二、系统整体架构
-
- [1. 整体架构图](#1. 整体架构图)
- [2. 面试业务流程图](#2. 面试业务流程图)
- [三、为什么选择 FastAPI](#三、为什么选择 FastAPI)
-
- [1. 原生异步支持](#1. 原生异步支持)
- [2. 自动数据校验](#2. 自动数据校验)
- [3. 自动接口文档](#3. 自动接口文档)
- [四、Dify 与 AI 工作流设计](#四、Dify 与 AI 工作流设计)
- [五、Prompt Engineering 的问题与优化](#五、Prompt Engineering 的问题与优化)
-
- [1. 初版 Prompt 的问题](#1. 初版 Prompt 的问题)
- [2. Prompt 结构化优化](#2. Prompt 结构化优化)
- [3. AI 输出结构化处理](#3. AI 输出结构化处理)
- 六、项目结构设计
- 七、开发过程中遇到的问题
-
- [1. AI 输出不稳定](#1. AI 输出不稳定)
- [2. 前后端联调问题](#2. 前后端联调问题)
- 八、项目带来的收获
- 九、总结
- 结语
一次关于 AI 应用开发、后端架构设计与 Prompt 工程的完整实践。
前言
在学习 FastAPI 与 AI 应用开发的过程中,我尝试构建了一个 AI 面试模拟系统。
项目最初只是一个简单的 FastAPI 练手项目,但随着 Dify、Prompt Engineering 与 AI 工作流逐步加入,它逐渐从传统 CRUD 项目演变成一个真正的 AI 工程实践。
本文主要分享:
- 为什么要做这个项目
- 系统整体架构如何设计
- Dify 如何接入业务流程
- Prompt 为什么需要不断调优
- AI 项目与传统后端项目的差异
- 开发过程中遇到的核心问题
一、项目背景
传统的技术面试准备,往往存在几个问题:
- 缺少真实面试场景
- 难以获得即时反馈
- 回答缺乏表达训练
- 无法持续复盘
因此,我开始思考:
能否通过 AI 模拟真实技术面试流程?
基于这个想法,我尝试构建一个能够:
- 自动生成技术问题
- 分析用户回答
- 提供反馈建议
- 保存面试记录
的 AI 面试系统。
二、系统整体架构
在正式开发之前,我先对整个系统进行了拆分。
因为对于 AI 项目而言,真正复杂的部分往往不是接口本身,而是:
- AI 工作流如何组织
- 数据流如何流转
- 模块之间如何解耦
- AI 输出如何约束
因此,我希望整个系统能够尽量保持:
- 模块职责清晰
- 结构可扩展
- AI 与业务解耦
- 后期方便维护
1. 整体架构图
整个系统采用前后端分离架构。
核心结构如下:
text
┌───────────────────────────────┐
│ Frontend │
│ Vue / React 页面 │
└──────────────┬────────────────┘
│ HTTP Request
▼
┌───────────────────────────────┐
│ FastAPI │
│ Backend API Layer │
└──────────────┬────────────────┘
│
┌────────┴────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ MySQL │ │ Dify │
│ Database │ │ AI Workflow │
└──────────────┘ └──────┬───────┘
│
▼
┌────────────────┐
│ OpenAI API │
│ LLM Service │
└────────────────┘
这里整个系统主要分成四层:
| 层级 | 作用 |
|---|---|
| Frontend | 用户交互与页面展示 |
| FastAPI | 业务逻辑与接口管理 |
| Dify | AI 工作流与 Prompt 管理 |
| MySQL | 用户数据与历史记录存储 |
整个架构的核心思想是:
AI 能力与业务逻辑尽量解耦。
这样即使未来替换模型或者工作流平台,也不会影响整体后端结构。
2. 面试业务流程图
整个 AI 面试流程的数据流如下:
text
用户开始面试
↓
FastAPI 接收请求
↓
创建面试 Session
↓
调用 Dify Workflow
↓
AI 生成技术问题
↓
用户提交回答
↓
AI 分析回答内容
↓
返回结构化分析结果
↓
保存数据库历史记录
↓
前端展示面试反馈
相比传统聊天系统,这里更强调:
- 面试状态管理
- 多轮上下文维护
- AI 输出结构化
- 历史记录持久化
因此整个系统本质上已经不仅是一个简单的 ChatBot。
而是一个完整的 AI 业务系统。
整个项目采用"前后端分离 + AI 工作流"的方式构建。
系统整体结构如下:
text
Frontend
↓
FastAPI Backend
↓
Dify Workflow
↓
OpenAI API
其中:
| 模块 | 职责 |
|---|---|
| Frontend | 用户交互 |
| FastAPI | 接口与业务逻辑 |
| Dify | AI 工作流管理 |
| OpenAI API | 提供模型能力 |
| MySQL | 数据持久化 |
整个请求流程如下:
text
用户开始面试
↓
FastAPI 接收请求
↓
调用 Dify 工作流
↓
AI 生成问题
↓
用户提交回答
↓
AI 分析结果
↓
保存历史记录
相比传统聊天 Demo,这里更强调:
AI 如何真正参与业务流程。
三、为什么选择 FastAPI
项目后端最终选择 FastAPI,主要有以下几个原因。
1. 原生异步支持
AI 接口调用通常耗时较长。
FastAPI 基于 ASGI,天然支持异步请求,更适合 AI 场景。
2. 自动数据校验
AI 输出具有不稳定性。
FastAPI 配合 Pydantic 可以快速完成:
- 参数校验
- JSON 结构约束
- 响应格式统一
这对于 AI 项目非常重要。
3. 自动接口文档
Swagger 文档能够显著提升前后端联调效率。
尤其在个人项目开发中,可以减少大量接口维护成本。
四、Dify 与 AI 工作流设计
相比直接调用 OpenAI API,我最终选择了 Dify 来管理 AI 工作流。
原因主要包括:
- Prompt 管理更加清晰
- 工作流更容易扩展
- AI 输出调试更方便
- 更适合复杂业务场景
在这个项目中,AI 主要负责:
- 生成面试问题
- 分析用户回答
- 输出技术反馈
- 给出能力评价
因此,AI 不再只是简单聊天工具,而是真正参与核心业务逻辑。
五、Prompt Engineering 的问题与优化
整个项目开发过程中,我认为最核心、也最容易被低估的一部分,就是 Prompt Engineering。
很多人会认为:
Prompt 只是给 AI 发一句话。
但真正开始做 AI 项目之后会发现:
Prompt 本质上决定了:
- AI 的行为方式
- 输出结构
- 内容质量
- 稳定性
- 可维护性
因此它实际上已经属于"工程设计"的一部分。
1. 初版 Prompt 的问题
项目最开始时,我使用的是非常简单的 Prompt:
python
prompt = "请模拟一个 Python 面试官"
但很快就发现几个明显问题:
- 问题过于宽泛
- 缺少真实面试语境
- 输出内容不稳定
- 无法直接被后端解析
例如 AI 有时候会:
- 返回 Markdown
- 增加额外解释文本
- 输出字段缺失
- 返回结构不一致
这些问题都会直接影响后端处理。
2. Prompt 结构化优化
后来我开始逐步增加上下文与约束。
例如:
python
prompt = f"""
你现在是一名高级 Python 面试官。
岗位:Python 后端开发
难度:中级
技术栈:FastAPI、MySQL、Redis
请根据以上信息生成一条技术面试问题。
要求:
1. 问题必须贴近真实面试
2. 问题不要过于宽泛
3. 返回 JSON 格式
4. 包含 question 与 analysis 字段
"""
优化之后:
- AI 输出稳定性明显提高
- 问题质量更加真实
- 后端解析更加容易
同时,我也开始意识到:
Prompt 并不是"提示词",而是一种 AI 行为控制机制。
3. AI 输出结构化处理
为了保证后端稳定性,我还增加了 AI 输出校验。
例如:
python
try:
result = json.loads(response)
except Exception:
raise HTTPException(
status_code=500,
detail="AI response format error"
)
对于 AI 系统而言:
永远不能完全信任模型输出。
因此后端必须增加:
- fallback 逻辑
- 数据校验
- 异常处理
- 格式限制
这也是 AI 项目与传统 CRUD 项目最大的区别之一。
整个项目中,最核心的问题之一其实是 Prompt 调优。
项目初期,我使用的是非常简单的 Prompt:
python
prompt = "请模拟一个 Python 面试官"
但实际效果并不理想。
主要问题包括:
- 问题过于宽泛
- 输出格式不稳定
- 缺少真实面试语境
后续我开始逐步增加上下文约束。
例如:
python
prompt = f"""
你现在是一名高级 Python 面试官。
岗位:Python 后端开发
技术栈:FastAPI、MySQL、Redis
要求:
1. 返回 JSON 格式
2. 问题贴近真实面试
3. 包含考察点
"""
优化之后,AI 输出稳定性明显提升。
这个过程让我意识到:
Prompt 本质上也是一种工程设计。
六、项目结构设计
随着项目功能逐渐增加,我开始意识到:
项目结构设计的重要性,甚至高于功能开发本身。
因为一个项目在初期即使功能不多,如果没有合理结构,后期会越来越难维护。
因此,我开始按照真实后端项目的方式进行模块拆分。
1. 后端目录结构
当前后端整体结构如下:
text
backend/
│
├── app/
│ ├── api/
│ │ └── v1/
│ │ ├── auth.py
│ │ ├── users.py
│ │ ├── interview.py
│ │ ├── answer.py
│ │ └── history.py
│ │
│ ├── core/
│ │ ├── config.py
│ │ ├── security.py
│ │ └── dependencies.py
│ │
│ ├── models/
│ │ ├── user.py
│ │ ├── interview.py
│ │ └── history.py
│ │
│ ├── schemas/
│ │ ├── user.py
│ │ ├── interview.py
│ │ └── answer.py
│ │
│ ├── services/
│ │ ├── dify_service.py
│ │ ├── auth_service.py
│ │ └── interview_service.py
│ │
│ ├── db/
│ │ └── database.py
│ │
│ └── main.py
│
├── requirements.txt
└── README.md
2. 模块职责划分
为了避免业务逻辑混乱,我对不同模块进行了职责划分。
api/
负责:
- 路由管理
- 请求接收
- 参数解析
- 响应返回
例如:
python
@router.post("/start")
async def start_interview(
request: InterviewRequest,
db: Session = Depends(get_db)
):
return await interview_service.start_interview(
db=db,
request=request
)
services/
负责:
- 核心业务逻辑
- Dify 调用
- AI 数据处理
- 面试流程管理
例如:
python
class InterviewService:
async def generate_question(self, tech_stack: str):
response = await dify_service.chat(
query=f"生成一个{tech_stack}面试问题"
)
return response
这样做的好处是:
路由层与业务层完全分离。
后期维护会更加清晰。
schemas/
负责:
- 请求数据校验
- AI 返回结构限制
- 响应格式统一
例如:
python
class InterviewRequest(BaseModel):
position: str
level: str
tech_stack: list[str]
对于 AI 项目而言,Schema 层尤其重要。
因为 AI 输出天然具有不稳定性。
因此必须通过 Pydantic 做数据约束。
models/
负责数据库模型。
例如:
python
class InterviewHistory(Base):
__tablename__ = "interview_history"
id = Column(Integer, primary_key=True)
question = Column(Text)
answer = Column(Text)
feedback = Column(Text)
3. API 路由版本化
为了方便后期升级,我还对 API 做了版本管理。
例如:
python
app.include_router(api_router, prefix="/api/v1")
这样后期即使新增:
text
/api/v2
也不会影响旧版本接口。
这一点在真实项目中非常重要。
随着功能增加,我开始对项目进行模块化拆分。
后端整体结构如下:
text
app/
├── api/
├── auth/
├── users/
├── interview/
├── answer/
├── history/
├── services/
├── schemas/
└── models/
不同模块分别负责:
| 模块 | 职责 |
|---|---|
| auth | 登录与鉴权 |
| interview | 面试流程管理 |
| answer | 回答分析 |
| history | 历史记录 |
| services | 核心业务逻辑 |
这样拆分之后:
- 代码职责更加清晰
- 模块耦合度更低
- 后期扩展更容易
这也是我第一次真正开始理解:
后端开发不仅是写接口,更是系统结构设计。
七、开发过程中遇到的问题
1. AI 输出不稳定
即使要求返回 JSON,AI 依然可能出现:
- 字段缺失
- 格式错误
- 返回额外文本
因此后端必须增加:
- 数据校验
- 异常处理
- 输出约束
- fallback 逻辑
2. 前后端联调问题
例如:
- Token 鉴权
- CORS 配置
- JSON 字段统一
- 状态码规范
这些问题虽然基础,但会直接影响开发效率。
八、项目带来的收获
这个项目最大的收获,并不是学会了某个框架。
而是让我开始真正理解:
AI 项目与传统 CRUD 项目的本质区别。
例如:
- AI 输出天然不稳定
- Prompt 需要持续优化
- 后端必须对 AI 做约束
- 项目结构会直接影响后期扩展
同时,我也逐渐意识到:
AI 工程不仅仅是"调用模型",更重要的是如何让 AI 真正融入业务系统。
九、总结
这个项目从一个简单的 FastAPI 练习,逐渐演变成一次完整的 AI 工程实践。
在开发过程中,我不仅学习了:
- FastAPI
- Dify
- Prompt Engineering
- AI 工作流
更重要的是,我开始真正接触:
- 系统设计
- 工程化开发
- AI 输出约束
- 后端架构思维
我认为,只有真正完成一个完整项目,才能真正理解:
AI 应用开发与传统后端开发之间的差异。
结语
从CRUD到AI工程,差距不在技术栈,而在系统设计思维。当你学会用结构化Prompt约束不稳定的模型输出,用分层架构解耦AI与业务,用Pydantic兜底数据安全,你才真正把AI从玩具变成了生产力工具。