【Python 函数与模块化 + FastAPI 式工程习惯】+【AI 应用预处理与业务编排】:从【清晰接口、拆模块、包导出】到【main 入口编排与踩坑规避】,彻底搞懂可维护、可复用、可组合的 AI 业务代码 写法,避开可变默认参数、import 顶层执行、循环依赖、相对导入与启动方式等高频坑!

📑 文章目录
- [1. 为什么"函数 + 模块化"是 AI 应用开发的地基](#1. 为什么“函数 + 模块化”是 AI 应用开发的地基)
- [2. 函数:把"接口"写清楚,把"可读性"写出来](#2. 函数:把“接口”写清楚,把“可读性”写出来)
- [2.1 函数到底是什么(用前端类比一下)](#2.1 函数到底是什么(用前端类比一下))
- [2.2 推荐的函数写法:清晰命名 + docstring + 类型标注](#2.2 推荐的函数写法:清晰命名 + docstring + 类型标注)
- [2.3 默认参数的"坑":不要写可变默认值](#2.3 默认参数的“坑”:不要写可变默认值)
- [3. 模块化:从"文件管理"到"依赖管理"](#3. 模块化:从“文件管理”到“依赖管理”)
- [3.1 什么是模块/包(按工程理解)](#3.1 什么是模块/包(按工程理解))
- [3.2 模块化的目标:让你"更容易改",而不是"看着整齐"](#3.2 模块化的目标:让你“更容易改”,而不是“看着整齐”)
- [4. 一个完整案例:写"文本清洗 + 统计 + 生成报告"的小工具(可用于 AI 输入预处理)](#4. 一个完整案例:写“文本清洗 + 统计 + 生成报告”的小工具(可用于 AI 输入预处理))
- [5. 模块化踩坑清单(这些是你最可能遇到的)](#5. 模块化踩坑清单(这些是你最可能遇到的))
- [5.1
import会"执行文件顶层代码"](#5.1 import 会“执行文件顶层代码”) - [5.2 循环依赖(A import B,B 又 import A)](#5.2 循环依赖(A import B,B 又 import A))
- [5.3 相对导入/执行方式差异导致的导入失败](#5.3 相对导入/执行方式差异导致的导入失败)
- [5.4 "把所有逻辑堆在一个文件里"](#5.4 “把所有逻辑堆在一个文件里”)
- [5.1
- [6. 实战规范(把"选择理由"写进你的编码习惯)](#6. 实战规范(把“选择理由”写进你的编码习惯))
- [6.1 函数规范](#6.1 函数规范)
- [6.2 模块规范](#6.2 模块规范)
- [6.3 入口编排规范](#6.3 入口编排规范)
- [7. 总结:你已经具备"AI 应用工程师"的工程骨架能力了](#7. 总结:你已经具备“AI 应用工程师”的工程骨架能力了)
- [🔍 系列模块导航](#🔍 系列模块导航)
- [📝 AI应用开发工程师基础篇](#📝 AI应用开发工程师基础篇)
- [📚 系列总览](#📚 系列总览)
同学们好,我是 Eugene(尤金),一名前端出身、正在持续深耕 AI 应用开发的工程师。
(Eugene 发音 /juːˈdʒiːn/,大家怎么顺口怎么叫就好)
如果你也和曾经的我一样:
会前端、会工程化、项目经验不少,
但一提到大模型、RAG、Agent、向量库、AI 架构,感觉概念很多、路径很乱,不知道该从哪一步开始落地。
那这个系列,就是专门为你准备的。
这不是一套"只讲概念"的内容,而是一条前端工程师可执行的 AI 转型路线:
从 Python 与 FastAPI,到大模型 API、Prompt、RAG、Agent、部署与架构,再到项目实战与面试就业。
我会坚持用大白话 + 工程化视角 + 真实场景来讲,
不堆玄学,不绕术语。
我们的目标很明确:
不只是"看懂 AI",而是"真正做出可上线、可维护、可扩展的 AI 应用"。
从前端转 AI 应用开发时,最容易卡住的点通常不是"数学/玄学",而是:在 Python 里该怎么写出可维护、可复用、可组合的代码 。
好消息是:这件事和你在前端做工程化是同一套思路------只是换成了 Python 的语法与组织方式而已。
本文只讲"日常写代码到底该怎么选、为什么这么选、踩坑会踩在哪",对象是完全把 AI 当新领域的老鸟小白:你看完能直接照着写模块、拆函数、搭出清晰的代码结构,并且知道常见坑怎么避。
1. 为什么"函数 + 模块化"是 AI 应用开发的地基
AI 应用工程里,常见流程通常长这样:
- 输入:用户文本/对话/网页内容
- 预处理:清洗、裁剪、去噪、提取关键信息
- 组装:把数据拼成"提示词/请求参数"
- 调用:请求模型(或检索)
- 输出:格式化成可读结果、结构化返回(JSON/Markdown)
你会发现:这类流程天然适合拆成很多"小步骤",而"小步骤"在工程化里就对应:
- 函数:一个明确的输入输出变换(像前端的纯函数/工具函数/可复用 composable)
- 模块 :把一组相关函数放在一起(像前端的
utils/xxx.ts、services/xxx.ts) - 包(package):把一组模块按"业务域/能力域"聚合(像前端的 feature 目录)
所以:AI 应用写得越久,你越离不开函数与模块化的基本功。
[⬆ 返回目录](#⬆ 返回目录)
2. 函数:把"接口"写清楚,把"可读性"写出来
2.1 函数到底是什么(用前端类比一下)
在前端你写过这种东西:
formatDate(date) -> stringparseQuery(url) -> { ... }normalizeText(text) -> text
Python 的函数也是同样的理念:
函数就是一个"可复用的接口",通过输入得到输出。
关键不是语法,而是工程习惯:
- 参数名清楚、类型含义明确
- 返回值明确(尽量返回数据,而不是到处
print) - 函数职责单一(类似组件/服务职责边界)
[⬆ 返回目录](#⬆ 返回目录)
2.2 推荐的函数写法:清晰命名 + docstring + 类型标注
下面是一个"文本清洗"的示例模块,我们后面会拆成多个文件来展示模块化。
text_tools/cleaning.py
python
from __future__ import annotations
import re
def normalize_text(text: str) -> str:
"""
统一文本格式:去首尾空格、把连续空白压缩为一个空格。
参数:
text: 原始文本
返回:
清洗后的文本
"""
text = text.strip()
# 把连续的空白字符(空格/换行/tab)压缩为一个普通空格
text = re.sub(r"\s+", " ", text)
return text
def limit_length(text: str, max_len: int) -> str:
"""
限制文本长度,超出则截断。
注意:
这里是"简单截断",真实场景可能还需要按句子/段落截断。
"""
if max_len <= 0:
raise ValueError("max_len 必须是正数")
if len(text) <= max_len:
return text
return text[:max_len]
这段代码体现了几个工程化点:
normalize_text(text: str) -> str:输入输出非常明确docstring:让你 6 个月后仍能理解这函数干了什么- 校验
max_len:让错误更早暴露,而不是偷偷产出异常结果
[⬆ 返回目录](#⬆ 返回目录)
2.3 默认参数的"坑":不要写可变默认值
这是 Python 老坑之一。下面是错误示例(非常常见):
python
def append_item(item, items=[]):
items.append(item)
return items
问题 :items=[] 只会在函数定义时创建一次,后续调用会"共享同一个列表"。
正确做法是用 None 作为默认值:
python
from typing import Optional, List, TypeVar
T = TypeVar("T")
def append_item(item: T, items: Optional[List[T]] = None) -> List[T]:
if items is None:
items = []
items.append(item)
return items
前端你可能用过类似"不要用可变对象当默认参数"的坑;Python 这条同样适用。
[⬆ 返回目录](#⬆ 返回目录)
3. 模块化:从"文件管理"到"依赖管理"
3.1 什么是模块/包(按工程理解)
- 模块(module) :一个
.py文件 - 包(package) :一个目录 +
__init__.py(现代 Python 虽有隐式规则,但写清楚仍是好习惯)
你可以把它类比成前端:
.py文件 ≈ 一个工具文件/服务文件- 目录包 ≈ 一个 feature/域(比如
text_tools/)
[⬆ 返回目录](#⬆ 返回目录)
3.2 模块化的目标:让你"更容易改",而不是"看着整齐"
模块拆分最常见的目标不是好看,而是:
- 改一个功能,不要牵一堆没关系的地方(低耦合)
- 同一类能力聚在一起(高内聚)
- 组合流程在入口统一编排(像前端路由/页面入口)
[⬆ 返回目录](#⬆ 返回目录)
4. 一个完整案例:写"文本清洗 + 统计 + 生成报告"的小工具(可用于 AI 输入预处理)
我们做一个小工具,它会:
- 清洗文本(
normalize_text+limit_length) - 计算基础统计(字数/句子数/关键词)
- 生成报告(Markdown 字符串)
你可以把它当成 AI 应用里"调用模型前的预处理 + 结果格式化"。
4.1 目录结构(清晰到像前端 feature 目录)
text
project/
main.py
text_tools/
__init__.py
cleaning.py
analysis.py
reporting.py
[⬆ 返回目录](#⬆ 返回目录)
4.2 模块代码
text_tools/analysis.py
python
from __future__ import annotations
from collections import Counter
import re
from typing import List, Tuple
def word_count(text: str) -> int:
"""返回"单词数"(这里用空格切分,简单可改)。"""
text = text.strip()
if not text:
return 0
return len(text.split(" "))
def sentence_count(text: str) -> int:
"""
估算句子数:用 . ! ? 以及中文常见标点做简单拆分。
更准确通常需要 NLP 或规则增强。
"""
if not text.strip():
return 0
# 中文逗号/句号/问号/感叹号,这里做一个基础规则
parts = re.split(r"[.!?!?。]+", text)
parts = [p.strip() for p in parts if p.strip()]
return len(parts)
def top_keywords(text: str, k: int = 5) -> List[Tuple[str, int]]:
"""
返回出现次数最多的 k 个关键词(这里做了极简规则:只保留"字母/数字/汉字")。
"""
if k <= 0:
raise ValueError("k 必须是正数")
# 提取 token:汉字/字母/数字
tokens = re.findall(r"[\u4e00-\u9fffA-Za-z0-9]+", text.lower())
if not tokens:
return []
counter = Counter(tokens)
return counter.most_common(k)
text_tools/reporting.py
python
from __future__ import annotations
from typing import List, Tuple
def build_report(
original: str,
cleaned: str,
stats: dict,
top_kws: List[Tuple[str, int]],
) -> str:
"""
把统计信息组装成 Markdown 报告。
"""
lines = []
lines.append("# 文本分析报告")
lines.append("")
lines.append("## 原始输入")
lines.append(original if original else "(空)")
lines.append("")
lines.append("## 清洗后文本")
lines.append(cleaned if cleaned else "(空)")
lines.append("")
lines.append("## 基本统计")
for key, value in stats.items():
lines.append(f"- {key}: {value}")
lines.append("")
lines.append("## Top Keywords")
if not top_kws:
lines.append("(无关键词)")
else:
for kw, cnt in top_kws:
lines.append(f"- {kw}: {cnt}")
lines.append("")
return "\n".join(lines)
text_tools/__init__.py(导出公共 API,像前端 index.ts)
python
from .cleaning import limit_length, normalize_text
from .analysis import sentence_count, top_keywords, word_count
from .reporting import build_report
__all__ = [
"normalize_text",
"limit_length",
"word_count",
"sentence_count",
"top_keywords",
"build_report",
]
这一步的意义:
当你在 main.py 里用到这些函数时,不用记住每个文件路径,依赖更清楚。
[⬆ 返回目录](#⬆ 返回目录)
4.3 入口文件:main.py
main.py
python
from __future__ import annotations
from text_tools import (
normalize_text,
limit_length,
word_count,
sentence_count,
top_keywords,
build_report,
)
def run(text: str) -> str:
# 1) 清洗
cleaned = normalize_text(text)
cleaned = limit_length(cleaned, max_len=200)
# 2) 统计
stats = {
"word_count": word_count(cleaned),
"sentence_count": sentence_count(cleaned),
"char_count": len(cleaned),
}
# 3) 关键词
kws = top_keywords(cleaned, k=5)
# 4) 组装报告(输出交付给调用方)
return build_report(
original=text,
cleaned=cleaned,
stats=stats,
top_kws=kws,
)
if __name__ == "__main__":
sample = " Hello 世界! 你好?Hello Python Python 。 "
report = run(sample)
print(report)
你会发现:main.py 只做"编排/组装",不会塞满各种细节逻辑。
这很像前端页面/容器组件:把流程串起来,把复杂变换交给更小的模块。
[⬆ 返回目录](#⬆ 返回目录)
5. 模块化踩坑清单(这些是你最可能遇到的)
5.1 import 会"执行文件顶层代码"
Python 的导入机制是:导入时会执行该 .py 文件的顶层代码。
所以规范是:
- 模块里只放函数/类/常量
- 需要运行逻辑的入口 一定放在
if __name__ == "__main__":
否则你会遇到"导入一次结果就跑了一遍"的怪问题。
[⬆ 返回目录](#⬆ 返回目录)
5.2 循环依赖(A import B,B 又 import A)
循环依赖会导致:
- 变量/函数拿到的是"未初始化的状态"
- 运行时错误或行为异常
工程化处理思路:
- 把"公共工具"抽到第三个模块(
common.py或utils/) - 或把依赖方向调整成"上层只依赖下层",避免互相 import
前端里你也见过这种:互相引用导致打包顺序和导出不稳定。
[⬆ 返回目录](#⬆ 返回目录)
5.3 相对导入/执行方式差异导致的导入失败
当你用相对导入(from .xxx import ...)时,用不同方式启动可能导致包上下文不同,进而报错。
建议策略(偏工程稳妥):
- 项目入口用包方式启动(后续文章再展开)
- 或尽量用明确的包名导入(例如上例的
from text_tools import ...)
[⬆ 返回目录](#⬆ 返回目录)
5.4 "把所有逻辑堆在一个文件里"
这也是最常见的"工程坏味道"。
判断标准可以直接借鉴前端:
- 一个文件里超过太多能力边界(比如清洗、统计、渲染全混)
- 函数名虽然有,但每个函数都被上下文"强绑定"
- 改某个统计逻辑会牵动其他逻辑
模块化的目的就是把边界切出来。
[⬆ 返回目录](#⬆ 返回目录)
6. 实战规范(把"选择理由"写进你的编码习惯)
6.1 函数规范
- 函数尽量做到"输入 -> 输出",避免在函数内部到处
print - 参数命名要说明含义(例如
max_len比n好) - 为非平凡参数/返回写
docstring - 明确校验边界:比如
k <= 0、max_len <= 0这种"应该失败的输入"就早失败
[⬆ 返回目录](#⬆ 返回目录)
6.2 模块规范
- 一个
.py文件只承载一类能力(清洗/分析/报告分别对应不同文件) - 在包
__init__.py中导出公共 API(类似前端index.ts汇总) - 顶层只放定义,不要放运行逻辑
[⬆ 返回目录](#⬆ 返回目录)
6.3 入口编排规范
main.py(或框架入口)只做流程编排:调用模块函数并组织输出- 让"核心算法/变换"留在模块里,入口保持轻量
[⬆ 返回目录](#⬆ 返回目录)
7. 总结:你已经具备"AI 应用工程师"的工程骨架能力了
你现在需要补的不是"玄学原理",而是把工程直觉迁移到 Python:
- 函数 = 清晰接口(像前端工具/纯函数)
- 模块/包 = 能力边界(像前端模块目录)
- 入口编排 = 串流程(像页面/路由/容器层)
- 踩坑点集中在:默认参数、import 执行时机、循环依赖、运行方式差异
[⬆ 返回目录](#⬆ 返回目录)
🔍 系列模块导航
📝 AI应用开发工程师基础篇
一、《AI大模型应用开发怎么入门?认知、选型与避坑指南| 基础篇》
二、《AI 开发工程师到底是什么?| 基础篇》
三、《为什么 AI 应用开发首选 Python?|基础篇》
四、《Python + venv + VSCode:前端工程师 AI 转型入门|基础篇》
五、《Python 基础语法:7 天快速上手|基础篇》
六、《Python 数据结构:list 、 dict 、 set 对应 JS 的哪里?| 基础篇》
七、《Python 函数与模块化:前端工程化思维完全通用| 基础篇》
八、《Python 异步 async/await:为什么 AI 框架大量使用?| 基础篇》
👉 跟着系列慢慢学,把技术功底扎扎实实地打牢~
📚 系列总览
- AI 应用开发从 0 到 1:前端转 AI 完整体系(持续更新中)
系列完结后会整理成一篇完整导航文并附上直达链接,方便大家按顺序、体系化学习。
全套内容持续更新中,敬请期待~
[⬆ 返回目录](#⬆ 返回目录)
AI 时代,真正稀缺的不是会调用一个模型接口的人,
而是能把业务、工程、架构、模型能力连接起来,做成完整产品的工程师。
前端转 AI,不是推倒重来,而是把你原有的工程化能力升级到新的技术栈里。
你过去积累的组件化、性能优化、协作规范、系统思维,都会在 AI 项目中继续产生价值。
后续我会持续更新这个系列:
覆盖基础认知、RAG、Agent、函数调用、开源模型部署、企业级架构、项目实战与面试求职,
帮你一步步从「会写页面」走向「能交付 AI 应用」。
如果这篇对你有帮助,欢迎 点赞 + 收藏 + 关注。
把这套系列当作你的 AI 转型路线图,跟着节奏持续推进,你会看到非常明显的成长。
我是 Eugene,你的电子学友,我们下篇干货见~