AI智能体筑基:Python项目文件读写和配置的“黄金原则“
Day02 AI智能体筑基打卡
当 Python 首次登顶 TIOBE 榜首、取代霸榜多年的 Java,AI 时代的编程版图已然改写。语法易学只是入场券,真正的分水岭在于智能体应用开发中的落地能力。无论你是在校园里学着与现实脱节的旧知识,还是身处传统前后端领域面临被替代的焦虑——这个系列不绕弯子、不讲废话,只聚焦那些真正会卡住你的痛点,记录一步步踩坑与补全认知的过程。
AI 浪潮下,我们都是摸着石头过河的同行者。与其被焦虑裹挟,不如把学习日常摊开来,一起查缺补漏、扎实成长。希望这些记录能陪你在这场技术变革中,走得更稳、更远。
今日目标:实现项目文件读写能力,完成配置与代码分离。
一、今日学习内容
单一职责函数封装原则(SRP)
是编程中最重要的设计原则之一,核心思想只有一个:一个函数只做一件事,且只做好一件事。
把一个复杂需求拆成很多单个需求,每个需求都用一个独立的函数执行,每个函数只处理一个逻辑层面的任务。
好处:可读性提升,便于测试和维护,代码复用,降低耦合,减少BUG。
标准:
- 名称清晰: 函数名准确描述功能(如
send_email而不是handle_mail) - 参数精简: 不超过3-4个参数
- 代码行数: 控制在20-30行以内(不是硬性指标,但可参考)
- 单一抽象层级: 函数内所有操作应在同一个抽象层级(高层函数调用中层函数,中层函数调用底层函数)
就像前面说的,单一职责不是"函数越短越好",而是"函数越聚焦越好"。
如果不知道如何判断函数是否职责单一,问自己这个问题:**是否可以在其他场景复用其中部分逻辑?**如果发现某个步骤在别处也要用,但被写在当前函数里,就应该独立出来。
跨平台路径处理(pathlib)
pathlib是Python标准库中内置的文件系统路径模块。
在AI项目中,经常需要读数据文件/写日志/存向量库。pathlib可以把路径当作对象来处理,优于传统 os.path
核心原则: 绝对路径用 Path(__file__).resolve().parent,相对路径用 / 运算符拼接。
from pathlib import Path
# 1. 获取项目根目录(假设这个文件在 project_root/src/ 下)
BASE_DIR = Path(__file__).resolve().parent.parent
# 2. 拼接路径(用 / 运算符,自动适配 Windows/Linux)
data_dir = BASE_DIR / "data" / "raw"
config_file = BASE_DIR / "config" / "settings.json"
知识点拆解:
-
__file__是 Python 在编译时自动执行的变量,表示当前.py文件的路径字符串。 -
Path.resolve():路径规范化,将路径解析为绝对路径,并消除路径中的.(当前目录)和..(上级目录),同时处理符号链接。 -
符号链接:一个指向其他文件的快捷指针,存储路径字符串,由于指向一个文件后链接不可改变,如果
-
属性
.parent与.parents(目录树攀爬):.parent:返回当前路径的上一级目录。.parents:返回一个迭代器,可以索引任意上级目录。
p = Path("/home/user/project/src/main.py") print(p.parents[0]) # /home/user/project/src print(p.parents[1]) # /home/user/project -
运算符
/重载:无论操作系统是 Windows(用\)还是 Linux/macOS(用/),/运算符都会自动转换为当前系统对应的分隔符。
注意事项:
__file__有时可能是相对路径,所以用resolve()可以提前规范化成绝对路径,避免后续拼接时出问题。- 如果确定
__file__已经是绝对路径,也可以直接用Path(__file__).parent.parent,但保留resolve()更稳健。
pathlib 的设计哲学是 “路径即对象”。它让路径拥有自己的属性和方法(读写、权限、统计、遍历),而不再是裸字符串。这大幅提升了代码的可读性,也杜绝了字符串拼接引发的路径注入或转义问题。
with 上下文管理器
with 上下文管理器,是 Python 中用于资源管理的语法糖,它能够自动处理资源的获取和释放,确保即使在发生异常的情况下,资源也能被正确清理。
with 表达式 [as 变量]:
代码块
# 可以同时管理多个资源
with 表达式1 as 变量1, 表达式2 as 变量2:
代码块
JSON 序列化
JSON是软件开发中最常用的数据交换格式
- 序列化: 将字典
dict对象转为json格式字符串,存入文件 - 反序列化: 将文件中的
json格式字符串,转为字典dict对象
import json
# 将user对象写入json数据文件
with open("resources/user.json", "w", encoding="utf-8") as f:
#
#
json.dump(user, f, ensure_ascii=False, indent=2)
ensure_ascii: 默认为True, 确保所有的数据输出的数据都是ascii编码(非ASCII码会进行转义); False, 非ASCII码保留原样输出indent: 会在输出的json数据中添加缩进(格式化)
import json
# 读取json数据文件
with open("resources/user.json", "r", encoding="utf-8") as f:
user = json.load(f)
配置文件设计原则(参数抽离)(工程化思想)
”参数抽离“有三条黄金原则,也是工程化思维的重要组成部分。
原则一:分层配置(Overlay配置)
核心逻辑:环境不同(本地、测试服务器、线上生产),配置必然不同。但不可能每次上线都去改代码里的IP和端口。
具体落地方案(标准三层结构):
default.yaml(提交 Git):存放所有环境都一样的默认值,是“保底方案”。local.yaml(加入.gitignore,绝不提交):存放本地调试的专属配置,比如电脑上的数据路径或者自己的测试Key。production.yaml(通常部署时通过环境变量生成):放在服务器上。
程序启动的加载逻辑(重点):
程序启动时,先读 default.yaml,然后用 local.yaml 去覆盖。如果有相同的键,local 的内容会把 default 的顶掉;如果 local 没有的,就保留 default 的。
**原则二:按模块归组(分层级嵌套)
核心逻辑:把所有参数平铺写成 max_token=1024, db_host=localhost是大忌。
正确做法(命名空间隔离):
把配置按照功能边界拆分成独立的字典块。
# 坏的(平铺直叙)
max_tokens: 2048
api_base: "https://api.deepseek.com"
db_host: "127.0.0.1"
db_port: 3306
redis_host: "127.0.0.1"
chunk_size: 512
# 好的(模块归组)
model: # 模型相关
provider: "deepseek"
name: "deepseek-chat"
max_tokens: 2048
temperature: 0.7
top_p: 0.9
database: # 数据库相关
host: "127.0.0.1"
port: 3306
name: "agent_db"
pool_size: 10
rag: # 检索增强相关
chunk_size: 512
overlap: 128
embedding_model: "text-embedding-3-small"
cache: # 缓存相关
redis_host: "127.0.0.1"
redis_port: 6379
ttl: 3600
原则三:硬编码零容忍(ZERO Hardcode)
核心逻辑:代码里除了逻辑结构,不允许出现任何与业务环境相关的具体数值或字符串。
绝对硬编码零容忍的落地标准:
- 数值:最大长度、超时时间、重试次数、连接池大小,必须写在配置文件的
settings里。 - 路径:绝对禁止
./或../。必须用前文提到的pathlib动态计算项目根目录,或者写在配置文件里。 - 秘钥与账号:绝对禁止写配置文件,必须放在
.env环境变量里,通过os.getenv("API_KEY")拿。
快捷键补充
shift + F6 同时修改同一文件下所有同名数据
ctrl + Tab 快速切屏(摸鱼专…诶不对我在说什么)
二、今日核心代码
今天有一个很爆炸的想法,所以一直在改代码,一直到晚上才有机会学一些知识点,也没时间实操了。代码明天补,至于那个很爆炸的想法,我先试试看……
三、每日三件事
- 今日代码实操完成情况: ###
- 今日踩坑Bug+原因+解决方案: ###
- GitHub当日代码仓库地址: ###
四、今日优质代码习惯
写注释!!!!一定要写注释!!!!
补充:vibe coding小技巧
指令模板:帮我把代码里所有硬编码绝对路径替换成pathlib相对路径,抽离所有固定参数生成config.json,再写一个配置读取工具类
一键完成配置抽离,培养工业级配置管理思维。
依旧一句话,”无人负我青云志,我自踏雪至山巅“!干了兄弟们!
更多推荐
所有评论(0)