1. 简介
本文章旨在详细介绍我们AI Agent项目中采用的基于 Flask、Flask-RESTful 和 Flask-SQLAlchemy 的三层 Web 应用架构。该架构将应用清晰地划分为控制层 (Controller) 、服务层 (Service) 和模型层 (Model),旨在实现关注点分离 (Separation of Concerns),从而提高代码的可维护性、可扩展性和可测试性。
2. 技术栈
- Web 框架: Flask
- RESTful API 框架: Flask-RESTful
- ORM (对象关系映射): Flask-SQLAlchemy
3. 架构详解
我们的应用遵循经典的三层架构模式,每一层都有明确的职责。
3.1. 控制层 (Controller Layer)
控制层是应用的入口,负责处理 HTTP 请求和响应。它不包含任何业务逻辑,仅作为客户端和业务逻辑之间的协调者。
- 职责 :
- 定义 API 路由 (Endpoints)。
- 接收和验证客户端请求参数。
- 调用服务层相应的方法来处理业务。
- 将服务层的返回结果格式化为标准的 HTTP 响应 (通常是 JSON)。
- 实现 : 使用
Flask-RESTful的Resource来构建。
示例: controllers/admin/intent_group.py
python
from flask_restful import reqparse, Resource
from controllers.admin import api
from services.assistant.intent_group_service import IntentGroupService
from libs import helper
# 定义一个处理意图分组创建的 API 资源
class IntentGroupSaveApi(Resource):
def post(self):
# 1. 使用 reqparse 验证和解析请求参数
parser = reqparse.RequestParser()
parser.add_argument('name', type=str, required=True, help='名称不能为空', location='json')
parser.add_argument('parent_id', type=int, required=False, location='json')
args = parser.parse_args()
# 2. 调用服务层处理业务逻辑
response = IntentGroupService.create_intent_group(
name=args.get("name"),
parent_id=args.get("parent_id"),
)
# 3. 将结果包装成标准响应返回
return helper.compact_response(response)
# 将资源注册到指定的 URL 路由
api.add_resource(IntentGroupSaveApi, '/intent/group/create')
在这个例子中,IntentGroupSaveApi 只关心三件事:接收什么参数 (reqparse)、调用哪个服务 (IntentGroupService.create_intent_group)、如何返回结果 (helper.compact_response)。
3.2. 服务层 (Service Layer)
服务层是应用的核心,负责实现所有的业务逻辑。它封装了对数据模型的复杂操作,并确保业务规则的一致性。
- 职责 :
- 实现具体的业务功能。
- 组合和调用一个或多个模型层的操作来完成一个业务流程。
- 处理业务级别的验证和异常(例如,检查资源是否存在、权限是否满足等)。
- 实现 : 独立的 Python 类 (
class IntentGroupService),其方法通常是静态的,以便于调用。
示例: services/assistant/intent_group_service.py
python
from libs.exception import BusinessException
from libs.status import Status
from models import db
from models.assistant import IntentGroup
class IntentGroupService:
@staticmethod
def create_intent_group(name: str, parent_id: int) -> bool:
# 1. 业务规则校验:检查是否存在同名分组
existing_group = db.session.query(IntentGroup).filter_by(name=name, parent_id=parent_id, is_deleted=0).first()
if existing_group:
raise BusinessException(Status.PARAMS_ILLEGAL, msg="不允许出现同名一级分组")
# 2. 数据模型操作:创建并填充模型对象
intent_group = IntentGroup()
intent_group.name = name
intent_group.parent_id = parent_id
# ... 此处省略了设置 level, parent_ids, alias_name 等业务逻辑
# 3. 数据持久化
db.session.add(intent_group)
db.session.commit()
return True
服务层封装了"创建意图分组"的完整流程,包括验证、数据处理和持久化。如果出现业务错误,它会抛出 BusinessException,由上层统一捕获处理。
3.3. 模型层 (Model Layer)
模型层负责与数据库进行交互,定义了应用的数据结构。
- 职责 :
- 定义数据表的结构(即 Schema)。
- 将数据库表映射为 Python 对象 (ORM)。
- 定义数据对象之间的关系(如一对多、多对多)。
- 实现 : 使用
Flask-SQLAlchemy的db.Model(在本项目中为自定义的Base) 来定义模型类。
示例: models/assistant.py
python
from .engine import Base, db, IntListEncodeStrType, MutableObject
class IntentGroup(Base):
__tablename__ = "ise_ast_intent_group"
id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment="主键ID")
name = db.Column(db.String(255), nullable=False, comment="分组名称")
parent_id = db.Column(db.Integer, default=0, nullable=True, comment="父分组ID,顶级为0")
alias_name = db.Column(db.String(255), nullable=False, comment="分组全称")
level = db.Column(db.Integer, default=1, nullable=True, comment="层级(1:一级,2:二级)")
@property
def children(self):
if not hasattr(self, "_children"):
self._children = list()
return self._children
IntentGroup 类精确地定义了 ise_ast_intent_group 表的结构。SQLAlchemy 会自动将对这些 Python 对象的操作转换为相应的 SQL 语句。
4. 请求处理流程示例
让我们以创建意图分组 (POST /intent/group/create) 为例,追踪一个完整的请求流程:
- 进入控制层 : 客户端发送 POST 请求。
Flask-RESTful根据路由/intent/group/create将请求分发给IntentGroupSaveApi的post方法。 - 参数解析 :
post方法使用reqparse从请求的 JSON body 中提取name和parent_id,并进行基本验证(如required=True)。 - 调用服务层 : 控制层调用
IntentGroupService.create_intent_group()方法,并将解析后的参数传递过去。 - 执行业务逻辑 :
IntentGroupService查询数据库,检查是否存在同名的分组。- 如果存在,则抛出
BusinessException异常。 - 如果不存在,则创建一个
IntentGroup模型实例,填充其属性。 - 调用
db.session.add()和db.session.commit()将新数据保存到数据库。
- 返回结果 :
- 服务层执行成功,返回
True。 - 控制层接收到
True,通过helper.compact_response()将其包装成一个成功的 JSON 响应(例如{"code": 0, "data": True, "msg": "success"})。 - 如果服务层抛出异常,全局异常处理器会捕获它,并返回一个包含错误信息的 JSON 响应。
- 服务层执行成功,返回
- 响应客户端: 最终的 JSON 响应被发送回客户端。
5. 总结
该三层架构为我们的项目带来了诸多好处:
- 高内聚,低耦合: 每一层都专注于自己的职责,层与层之间的依赖关系清晰明了。
- 易于维护和扩展: 当业务逻辑需要变更时,我们只需要修改服务层,而无需触及控制层和模型层。同样,更换数据库或 API 风格也变得更加容易。
- 提升可测试性: 我们可以独立地对服务层和模型层编写单元测试,而无需启动一个完整的 Web 服务器。
- 代码复用: 业务逻辑集中在服务层,可以被不同的控制器(例如,一个给管理员用,一个给普通用户用)复用。
通过遵循这一架构模式,我们能够构建一个健壮、可维护且易于团队协作的 Web 应用程序。