【限时特惠】小白玩转AI大模型应用开发_哔哩哔哩_bilibili
软件开发实战
Section titled “软件开发实战”大语言模型的参数规模
Section titled “大语言模型的参数规模”- 前面提到RX有15亿个参数,而GP3的参数增长到1750亿个
大语言模型的应用
Section titled “大语言模型的应用”- ChatGPT、Cloud、文心一言、同意签问等AI聊天助手
- 均基于大语言模型
- 2022年年底ChatGPT亮相:大模型公众认知显著提升的里程碑
大语言模型发展历史
Section titled “大语言模型发展历史”- 2017年6月:谷歌团队发表论文Attention is All You Need,提出Transformer架构,改变了自然语言处理的发展方向
- 随后出现一系列基于Transformer的模型:
- 2018年:OpenAI发布GPT 1.0,谷歌发布Bird
- 2019年:OpenAI发布GPT 2.0,百度发布A0 1.0等
- 大语言模型发展早已如火如荼,并非很多人以为的2022年才突破
- ChatGPT成功原因:直接向公众开放,支持网页对话交互,体验流畅,从而吸引大众目光
Transformer架构的重要性
Section titled “Transformer架构的重要性”- ChatGPT背后的模型GPT首字母分别表示Generative Pre-trained Transformer
- 生成、预训练、Transformer
- 表明Transformer是大语言模型的关键,无法跳过
语言模型历史:RNN架构
Section titled “语言模型历史:RNN架构”- 主流架构:循环神经网络(RNN)
- 按顺序逐字处理
- 每一步输出依赖先前隐藏状态和当前输入
- 串行计算:上一步完成后才能进行下一步
- 无法并行计算,计算效率低
- 不擅长处理长序列(长文本)
- 由于RNN架构特点,时间距离越远效果越差
Transformer 引入
Section titled “Transformer 引入”- 解决 RNN/LSTM 限制
- 能学习输入序列里所有词的相关性和上下文
Transformer+---------------------------------------------------------------------------------------------+| || Transformer || |+---------------------------------------------------------------------------------------------+Transformer的自注意力机制
Section titled “Transformer的自注意力机制”- 关键能力:处理每个词时,不仅注意词本身及附近词,还注意输入序列里所有其他词
- 不会受短时记忆影响,能捕捉长距离依赖
- 注意力权重:模型通过大量文本训练逐渐习得
- 每个词与其他词有不同权重,反映相关性强弱
- 专注于输入中真正重要部分,即使两个词位置隔得很远
- 论文精髓:Attention is all you need —— 注意力就是一切
Transformer自注意力机制的优势
Section titled “Transformer自注意力机制的优势”- 示例句子:The animal didn’t cross the street because it was too tired
- ‘it’可能指’street’(近)或’animal’(远)
- 自注意力捕获’it’与’animal’的强依赖,更集中关注’animal’
| Word | Attention Weights |
|———|—————––|
| The_ | |
| animal_ | |
| didn_ | |
| t_ | |
| cross_ | |
| the_ | |
| street_ | |
| because_| |
| it_ | |
| was_ | |
| too_ | |
| tire_ | |
| d_ | |
- 自注意力:全局捕获任意位置依赖,不受距离限制
位置编码(Positional Encoding)
Section titled “位置编码(Positional Encoding)”- 语言顺序重要:相同词不同序,含义大变
- “小处不可随便” vs “不可随便小处”
- 位置:小处(0) 不可(1) 随便(2) → 不同含义
- 序列:一系列按特定顺序排列的元素
- Transformer关键创新:位置编码,提供顺序信息
RNN处理瓶颈回顾
Section titled “RNN处理瓶颈回顾”- RNN按顺序串行处理(如人类阅读)
- 无法并行学习所有信息 → 训练速度慢
Transformer 引入 (续)
Section titled “Transformer 引入 (续)”- 词嵌入:将词转换为数字表示(向量)。
- 位置编码:将词在句子中的位置也用数字表示(位置向量)。
- 词向量 + 位置向量:添加到输入序列的表示中。
- 模型既理解词义,又能捕获词在句子中的位置,理解词之间的顺序关系。
- 无需按顺序输入:模型可同时处理输入序列里的所有位置,并行计算。
- 计算效率提高:每个输出可独立计算,无需等待其他位置的计算结果。
- 训练速度提高:训练出巨大模型不再困难。
- Transformer及其变体已被广泛应用于大型数据集上,来训练大语言模型。
Transformer架构深入理解
Section titled “Transformer架构深入理解”- Transformer架构是当前大语言模型不可或缺的部分。
- 核心思想:预测出现概率最高的下一个词,实现文本生成。
- 类似于搜索引擎的自动补全功能。
- 模型具体实现:通过大量数据训练,学习每个词的出现概率。
Transformer架构组成
Section titled “Transformer架构组成”- 包括自注意力机制和位置编码等重要组成部分。
Transformer架构的核心组成部分
Section titled “Transformer架构的核心组成部分”- 自2017年论文 Attention is All You Need 提出 Transformer 后,大模型几乎都基于此。
- Transformer 架构:
- 由编码器(Encoder)和解码器(Decoder)两个核心部分组成。
- 假设任务:做英语翻译法语。
- 给编码器输入一句英语,解码器返回对应的法语。
编码器工作原理
Section titled “编码器工作原理”- Token化:将输入的文本拆分成各个
token。 Token可以理解为文本的一个基本单位。- 短单词可能每个词是一个
token,长单词可能被拆成多个token。 - 每个
token会被用一个整数数字表示。
编码器工作原理
Section titled “编码器工作原理”Token化:将输入文本拆分成token,每个token用一个整数数字表示,称为token ID。- 示例:“She is in a restaurant” ->
token ID序列:[8100, 374, 304, 264, 10960] - 计算机内部无法直接存储文字,任何字符最终都需用数字表示。
嵌入层(Embedding Layer):将token ID转换为向量表示。向量是一串数字,能包含比单个数字更多的语法和语义信息。- 向量的长度实际可以非常长,图示为简化展示。
- 为什么用向量?
- 单个数字难以表达词语的复杂含义和关系。
- 向量能表示词语在多维度上的特征,捕捉词语间的相似性和差异性。
- 例如,“man” 和 “woman” 都指人类,但性别不同。如果只用一个数字表示,很难同时体现这种相似和差异。多维向量可以更好地在不同维度上区分它们。
词嵌入向量 (续)
Section titled “词嵌入向量 (续)”- 向量维度:
- 简化表示:三维向量空间
- 实际:Transformer 论文中,向量长度为512
- GPT-3:12288
- 向量表示的意义:
- 第一个数字:可以表示词性的程度
- 第二个数字:可以表示年龄大小的程度
- 第三个数字:可以表示社会阶层高低的程度
- 词汇关系:
- 词嵌入向量包含词汇之间的语法语义关系
- 相似的词,对应的嵌入向量在向量空间里距离更近
- 无关系的词,距离更远
- 作用:
- 帮助模型利用数学计算向量空间里的距离
- 捕捉不同词在语义和语法等方面的相似性
- 示例:
- “男人”与“国王”的差异,和“女人”与“女王”的差异可以被看作是相似的
- 总结:
- 词向量不仅可以帮模型理解词的语义,也可以捕捉词与词之间的复杂关系
编码器工作原理 (续)
Section titled “编码器工作原理 (续)”- 通过编码器的
嵌入层得到词向量后,下一步进行位置编码。 - 位置编码:表示每个词在文本中顺序的向量。
- 将位置向量与词向量相加,传递给编码器。
- 作用:使模型理解词义,捕捉词在句子中的位置,理解词之间的顺序关系。
- 编码器将输入转换成更抽象的表示形式,也是向量,保留了输入文本的词汇信息和顺序关系,补充了语法语义上的关键特征。
- 捕捉关键特征的核心是编码器的自注意力机制。
编码器工作原理 (续)自注意力机制
Section titled “编码器工作原理 (续)自注意力机制”- 自注意力机制:不仅关注词本身和附近词,还关注输入序列里所有其他词。
- 通过计算每个词之间的相关性来决定注意力权重。
- 两个词相关性越强,注意力权重越高。
- 例句:The animal didn’t cross the street because it was too tired
animal````street````,自注意力机制更集中在 ````animall`` 上。- 编码器输出:融入上下文相关信息,表示各个词的向量会根据上下文信息进行调整。
编码器工作原理(续)多头自注意力机制
Section titled “编码器工作原理(续)多头自注意力机制”- 多头自注意力:编码器不只用一个自注意力模块,而是多个。
- 每个“头”都有自己的注意力权重,关注文本不同特征或方面:
- 动词
- 修饰词
- 情感
- 命名实体
- 并行运算:各“头”计算互不影响。
- 权重学习:模型在大量文本训练中学习和调整。
前馈神经网络
Section titled “前馈神经网络”- 在多头自注意力后,连接一个前馈神经网络。
- 对自注意力模块的输出做进一步处理,增强模型表达能力。
- Transformer 中编码器不只有一个,而是多个堆叠。
- 每个编码器内部结构一样,但不共享权重。
解码器工作原理
Section titled “解码器工作原理”- 解码器:生成一个个词的关键。
- 输入:编码器的抽象表示 + 特殊
<start>值(表示输出序列开头)。 - 解码器不仅会将来自编码器的输入序列的抽象表示作为输入,还会把之前已经生成的文本也作为输入,来保持输出的连贯性和上下文相关性。
- 流程:
- 嵌入层和位置编码(同编码器)。
- 多头自注意力层:与编码器里的自注意力层略有不同。
- 带掩码的多头自注意力:解码器中使用,针对已生成的输出序列。
- 解码器还有个多头自注意力层:利用编码器输出的输入序列抽象表示。
- 注意力:捕捉编码器的输出和解码器即将生成的输出之间的对应关系,融合原始输入序列信息。
- 解码器里的前馈神经网络:作用与编码器类似,增强模型表达能力。
解码器工作原理 (续)多头自注意力机制和前馈神经网络
Section titled “解码器工作原理 (续)多头自注意力机制和前馈神经网络”- 编码器和解码器都是多个堆叠在一起,可以增加模型的性能,有助于处理复杂的输入输出关系。
- 解码器的最后阶段:
- 包含一个线性层和一个 Softmax 层。
- 作用:把解码器输出表示转换为词汇表的概率分布。
- 词汇表的概率分布代表下一个被生成
token的概率。 - 模型会选择概率最高的
token作为下一个输出。 - 模型幻觉:模型一本正经地胡说八道。
- 解码器会重复多次,新的
token会持续生成,直到生成的是一个用来表示输出序列结束的特殊token。
Transformer架构的变体
Section titled “Transformer架构的变体”- 原始架构基础上,出现三种变体:
- 仅编码器
- 例子:
BERT - 用途:掩码语言建模、情感分析等
- 适用场景:理解语言的任务
- 仅解码器
- 例子:
GPT-2、GPT-3 - 用途:文本生成
- 适用场景:预测下一个词来实现文本生成
- 编码器-解码器
Transformer架构的变体 (续)
Section titled “Transformer架构的变体 (续)”- 序列到序列模型:
- 例子:
T5、BART - 用途:翻译、总结等
- 适用场景:一个序列转换为另一个序列的任务
ChatGPT炼成步骤
Section titled “ChatGPT炼成步骤”- 无监督预训练:
- 大量文本进行无监督学习,得到基座模型。
- 监督微调:
- 通过人类撰写的高质量对话数据,对基座模型进行监督微调,得到微调后的模型。
- 微调后的模型具备更好的对话能力。
ChatGPT炼成步骤 (续) 无监督预训练
Section titled “ChatGPT炼成步骤 (续) 无监督预训练”- 需要海量文本作为原料,让模型自动学习。
- 例如:GPT-3 的训练数据。
| Dataset | Quantity (tokens) | Weight in training mix | |
|---|---|---|---|
| Common Crawl | 410 billion | 60% | |
| WebText2 | 19 billion | 22% | |
| Books1 | 12 billion | 8% | |
| Books2 | 55 billion | 8% | |
| Wikipedia | 3 billion | 3% |
- 覆盖书籍、新闻文章、科学论文、维基百科、社交媒体帖子等。
- 训练数据的整体规模:3000亿的
token。
- 大语言模型的一个基本文本单位。
- 像短的英文单词或一个标点符号。
ChatGPT炼成步骤(续)
Section titled “ChatGPT炼成步骤(续)”- 强化学习:
- 利用强化学习技术,让模型学会如何生成更优质的回复。
- 人工标注数据反馈给模型,不断调整优化。
监督学习 vs 无监督学习
Section titled “监督学习 vs 无监督学习”- 监督学习:模型接受带有标签的训练数据,标签是期望的输出值。
- 每个训练数据点包含输入特征和期望输出值。
- 无监督学习:模型在没有标签的数据上进行训练。
- 模型自己找出数据中的结构和模式。
- 例:GPT-3 利用海量文本,自行学习人类语言的语法、语义,了解表达结构和模式。
模型预测Token
Section titled “模型预测Token”- 模型先看到一部分文本,基于上下文尝试预测下一个
token。 - 通过比较正确答案和预测,模型不断学习和调整,变得越来越准确。
ChatGPT炼成步骤 (续) 监督微调
Section titled “ChatGPT炼成步骤 (续) 监督微调”- 对基座模型进行微调。
- 微调后的模型具备更好的对话能力。
- 基座模型有预测下一个
token的能力,但并不擅长对话。 - 模型可以模仿上文生成更多问题,但不回答问题。
监督学习 vs 无监督学习 (续)
Section titled “监督学习 vs 无监督学习 (续)”- 为了解决模型不回答问题,需要进行第二步:监督微调。
ChatGPT炼成步骤 (续)
Section titled “ChatGPT炼成步骤 (续)”- 监督微调:在已有模型上进一步训练,调整模型内部参数,使其更适应特定任务。
- 给基座模型更多对话数据。
- 微调成本低于预训练,因为所需数据规模更小,训练时长更短。
- 模型从人类撰写的高质量对话中学习,获得人类中意的回答,属于监督学习。
- 这一过程称为监督微调(Supervised Fine-Tuning),简称SFT。
- 完成后得到SFT模型,更擅长对问题做出回答。
- 强化学习:让
SFT模型进行强化学习,学会如何生成更优质的回复。
ChatGPT炼成步骤 (续) 强化学习
Section titled “ChatGPT炼成步骤 (续) 强化学习”- 强化学习让模型在环境里采取行动。
- 从反馈里学习,从而能在给定情况下采取最佳行动,来最大化奖励或最小化损失。
- 训练小狗类似:
- 小狗通过观察动作和奖励之间的联系,逐渐接近训练师的期望。
- 让ChatGPT模型扮演一个乐于助人的AI助手也是一样的道理。
- 可以让ChatGPT对问题做出回答,然后让人类评估员去给回答打分。
- 打分主要基于3H原则:
- Helpful(有用性):判断模型遵循用户指令以及推理指令的能力。
- Honest(真实性):判断模型产生幻觉(编造事实)的倾向。
- Harmless(无害性):判断模型的输出是否适当,是否诋毁或包含贬义内容。
- 如果打分高,模型能学到要再接再厉;如果打分低,模型能学到要予以改正。
- 但靠人类给回答打分,成本极高,效率极低。
ChatGPT炼成步骤 (续) 强化学习
Section titled “ChatGPT炼成步骤 (续) 强化学习”- 训练奖励模型:
- 让
SFT模型对每个问题生成多个回答。 - 人工标注员对回答质量排序。
- 利用排序数据训练奖励模型,使其学习预测回答的评分。
- 强化学习:
- ChatGPT模型的初始参数来自之前的
SFT模型,但会随着训练被更新。 - 奖励模型的参数则不再会被更新。
- 奖励模型的任务是对模型生成的内容打分。
- 模型会不断优化策略,回答的质量会进一步提升。
编写Python代码前的准备
Section titled “编写Python代码前的准备”- 2022年11月:ChatGPT对外发布,生成式AI元年。
- 编写Python代码前需准备:
- 安装 Python解释器
- 机器无法直接读取Python代码,需要解释器。
- Python运行过程:翻译一行,执行一行。
- 安装 代码编辑器
- 类似于Word写文档,写代码也需要软件。
- 推荐使用 Pycharm。
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- PyCharm:
- 专门为Python设计的集成开发环境(IDE)。
- 提供代码补全、自动格式化、拼写检查等。
- 内含调试器和版本控制工具。
- 作为新手,无需一次性学会所有功能,随经验增加逐步掌握。
- 安装步骤:
- 从Python官网下载Python解释器和PyCharm。
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- Python解释器安装:
- 访问 www.python.org 下载。
- 点击 Downloads。
- 网站会自动识别系统。
- 点击大黄按钮开始下载。
- 安装时,务必勾选 “Add Python to PATH”,将Python路径添加到环境变量中,让电脑识别Python安装位置。
- 点击 “Install Now” 开始安装。
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- 如果出现路径长度提示,点击并忽略。
- 验证Python是否安装成功:
- 在菜单搜索
cmd进入命令提示符。 - 输入
python(全小写),点击回车。 - 如显示Python版本信息,表示安装成功。
- PyCharm安装:
- 搜索PyCharm官网 www.jetbrains.com/pycharm/。
- 点击 Download。
- PyCharm有两个版本:专业版(收费)和社区版(免费)。
- 纯Python开发者社区版够用。
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- PyCharm 安装:
- 下载:点击黑色 Download 按钮下载免费 Community 版本。
- 安装步骤:
- 打开下载完成的安装包。
- 点击下一步,选择安装位置。
- 勾选创建桌面快捷方式(可选)。
- 勾选所有
.py文件用 PyCharm 打开(可选)。 - 点击下一步,等待安装完成。
- 点击完成,关闭安装窗口。
- 打开 PyCharm:选择语言和地区(默认中文)。
- 同意用户协议。
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- PyCharm初始化后,可以开始创建项目和编写代码。
- Mac电脑安装Python和PyCharm:
- 访问 www.python.org 下载Python解释器。
- 网站自动识别系统。
- 点击大黄按钮下载。
- 确保下载的版本正确匹配电脑的系统。
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- Python解释器安装 (Mac):
- 下载安装包后打开,一路点击下一步
- 需要管理员权限,输入Mac用户名和密码
- 稍等片刻,等待安装完毕
- 关闭安装窗口
- 验证Python是否安装成功:
- 打开电脑终端
- 点击顶部菜单栏放大镜图标,输入“终端”
- 或者,点击“访达”,顶部选择“前往”-“实用工具”,找到“终端”打开
- 输入
python3(全小写),回车 - 显示Python版本信息,说明安装成功
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- PyCharm安装 (Mac):
- 下载:点击黑色 Download 按钮下载免费 Community 版本。
- 安装步骤:把PyCharm拖进应用程序文件夹。
- 打开PyCharm即可开始使用。
- PyCharm 安装 (Mac):
- 下载完成后,将 PyCharm 拖入应用程序文件夹。
- 打开 PyCharm 即可开始使用。
- 首次打开 PyCharm 会弹出窗口让你选择语言和地区,可以选择中文。
- 接下来需要同意用户协议。
- 然后会询问是否分享匿名数据,可选择不分享。
- 可能会弹出提示,询问文件访问权限,点击好即可。
- 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过。
- 完成初始化后,可以开始创建项目和编写代码了。
PyCharm 设置中文界面
Section titled “PyCharm 设置中文界面”- 如果 PyCharm 界面是英文,可通过以下步骤设置为中文:
- 点击左下角设置图标(或 Windows 系统下的 Settings)。
- 选择
Plugins(插件)。 - 在插件页面的搜索框输入
chinese。 - 找到
Chinese (Simplified) Language Pack中文语言包。
- 如果在
Marketplace找不到,可能是已默认安装,转到Installed查看。
- 如果中文语言包是灰色禁用状态,点击启用。
PyCharm 设置中文界面 (续)
Section titled “PyCharm 设置中文界面 (续)”- 如果中文语言包是灰色禁用状态,点击启用。
- 点击右下角的
Apply,然后点击OK。 - 再次点击左下角设置图标(或 Windows 系统下的 Settings)。
- 搜索
language,找到Language and Region。 - 在这里选择中文,点击
OK。 - 然后点击
Restart重启。 - 现在界面上的语言就变成中文的了。
- 现在要创建一个项目,以便集中管理代码文件。
- 在欢迎页面找到
新建项目,点击它。 - 第一行表示项目文件所在位置,可修改,但要先创建文件夹。
- 下面解释器类型可以选择默认的
项目venv。 - PyCharm会自动检测电脑里的Python版本。
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 每个项目文件夹存放与项目相关的文件,如前后端代码、图片素材等。
- venv 文件夹:PyCharm 自动创建,表示该项目独立的 Python 虚拟环境。
- 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹,不要删除或往里添加东西。
- 创建其他 Python 项目文件夹,按相同步骤重复即可。
PyCharm:新建 Python 文件
Section titled “PyCharm:新建 Python 文件”- 在项目文件夹中,右键 -> 新建 -> Python 文件
- 命名文件,以
.py结尾 (例如:hello.py)
Python 代码:与计算机交流
Section titled “Python 代码:与计算机交流”- 更准确地说是给计算机下指令
- 计算机按指令执行,如
print("Dad!!")会在屏幕显示 Dad!! print:英语中是打印的意思,可以理解为把指定文字在屏幕上展现出来。
Python 代码书写注意事项
Section titled “Python 代码书写注意事项”print("Dad!!"):Dad!!必须放在英文引号内。- 如果内容放在括号外,
print命令无法打印。 - 标点符号:
- 必须使用英文标点,而非中文标点。
- 中文标点符号通常更宽。
| 符号类型 | 中文 | 英文 |
| — | — | — |
| 括号 | () | () |
| 逗号 | , | , |
| 分号 | ; | ; |
| 方括号 | 【】 | [] |
- 使用单引号或双引号均可,但必须是英文。
- 引号用于区分原文和其他部分,避免歧义。
- 如果不加引号,计算机不会把里面的内容当成是文字
Python 代码书写注意事项 (续)
Section titled “Python 代码书写注意事项 (续)”print("Dad!!"):Dad!!必须放在英文引号内。- 括号外的
print命令无法打印内容。 - 标点符号:
- 必须使用英文标点,而非中文标点。
- 中文标点符号通常更宽。
| 符号类型 | 中文 | 英文 |
| — | — | — |
| 括号 | () | () |
| 逗号 | , | , |
| 分号 | ; | ; |
| 方括号 | 【】 | [] |
- 使用单引号或双引号均可,但必须是英文。
- 引号用于区分原文和其他部分,避免歧义。
- 即使引号里的内容是数字,也会被识别为字符串,而不是数字。
- 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码。
PyCharm:新建 Python 文件 (续)
Section titled “PyCharm:新建 Python 文件 (续)”- 在项目文件夹中,右键 -> 新建 -> Python 文件
- 命名文件:以
.py结尾 (例如:hello.py) - 建议:文件名尽量不要有空格,避免使用emoji等特殊符号
- 推荐命名方式:英文、数字、下划线
- PyCharm 弹出窗口询问是否添加到 git,初学阶段可选择“不再询问”。
- 编写打印语句:
print(),全部小写。 print()函数内,使用英文引号包裹要打印的内容。- 运行代码:右键点击,选择运行。
- 运行结果:在下方运行窗口显示。
PyCharm 运行代码结果
Section titled “PyCharm 运行代码结果”- PyCharm 运行代码后,第一行和最后一行可以忽略。
- 重点关注第一行和最后一行之间的内容。
- 双引号里的内容可以替换成任意想要的内容,比如中文的叫妈妈也行。
- 右键选择运行,点击后,
妈妈!!就打印出来了。 - 如果代码有问题,PyCharm 会自动用红色提醒,运行的时候也能看到红色的错误提示信息。
- 注意:代码中的符号必须是英文符号,比如括号。
Python代码书写问题解决办法
Section titled “Python代码书写问题解决办法”- 如果遇到错误,PyCharm会自动用红色提醒。
- 运行代码时,也能看到红色的错误提示信息。
- 可以把红色错误信息复制到搜索引擎里进行搜索。
- 错误可能是相似的。
- 很多开发者可能遇到过相同问题,可以借鉴解决方案。
打印字符串的进阶玩法
Section titled “打印字符串的进阶玩法”- 字符串连接
- 单双引号转义
- 换行
- 三引号跨行字符串
- 字符串:用引号包裹住的一串内容。
打印字符串的进阶玩法 (续) 字符串连接
Section titled “打印字符串的进阶玩法 (续) 字符串连接”- 字符串:用引号包裹住的一串内容。
- 用加号连接字符串
print("Hello" + " world" + "!")- 输出:
Hello world! - 注意:
world前面有一个空格,所以打印出来中间才会有空格,否则两个词会黏在一起。
单双引号转义
Section titled “单双引号转义”- 字符串可以用单引号或双引号包裹,效果一样。
- 若内容本身包含引号,需注意内外引号的搭配。
- 例:
print("He said "good!"")会报错。 - Python 会将
He said识别为一个字符串,导致后续代码出错。
单双引号转义 (续)
Section titled “单双引号转义 (续)”- 若字符串内容本身包含引号,且内外引号类型相同,会引发错误。
- 示例:
print("He said "good!"")会报错,因为Python会把"He said "识别为一个字符串,导致后续代码出错。 - 转义字符:在字符串内部的引号前加上反斜杠 `` 来解决此问题。
- 反斜杠 `` 告诉Python,其后的引号应被视为字符串内容的一部分,而非字符串的结束符。
- 示例:
print("He said \"Let's go!\"")。Python会将\"识别为双引号,\'识别为单引号,作为字符串内容打印出来,而不是作为字符串的边界符。 - 实际输出将是:
He said "Let's go!"。 - 只要字符串中有反斜杠 ``,Python就会将其与后面的符号一起解读,产生特殊的含义。
打印字符串的进阶玩法 (续) 换行
Section titled “打印字符串的进阶玩法 (续) 换行”- Python里一句代码不能随便换行,会报错
- 可用
\n表示换行,是反斜杠转义符的用法之一 - 例:
print("Hello!\nHi!")
打印字符串的进阶玩法 (续) 三引号跨行字符串
Section titled “打印字符串的进阶玩法 (续) 三引号跨行字符串”- 三个单引号或双引号连在一起,包裹住文字
- Python会把新的一行当成内容的换行,而不是代码语句的结束
- 新建空白Python文件,例如:
2_more_print.py - 字符串连接示例:
print("你好" + " " + "这是一句代码")- 加号两边空格可有可无,但加上更美观
- 不要在每行开头随意加空格,PyCharm会提示错误
打印字符串的进阶玩法 (续) 单双引号转义 (续)
Section titled “打印字符串的进阶玩法 (续) 单双引号转义 (续)”- 字符串内容含引号,且内外引号类型相同时,会引发错误。
- 示例:
print("He said "good!"") - 转义字符:用反斜杠 ``。
- 示例:
print("He said \"Let's go!\"") - Python会将
\"识别为双引号,\'识别为单引号 - 实际输出:
He said "Let's go!" - 字符串中有反斜杠 ``,Python会将其与后面的符号一起解读,产生特殊的含义。
打印字符串的进阶玩法 (续) 反斜杠转义
Section titled “打印字符串的进阶玩法 (续) 反斜杠转义”- 如果使用反斜杠 ``,确保使用正确的反斜杠(键盘Enter键上面那个)。
- 正确:
print("Let's go") - 错误:
print("Let’s go")(用了正斜杠,无效) \n:表示换行符。print("我是第一行\n我是第二行")- 结果:两行输出
print("我是第一行\n我是第二行")print("\n")单独打印换行符会输出一个空行。
打印字符串的进阶玩法 (续) 三引号跨行输入
Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入”- 使用三个单引号
'''或三个双引号"""包裹字符串,可以实现跨行输入。 - `print(“”“我是第一行
我是第二行”“”)`
打印字符串的进阶玩法 (续) 三引号跨行输入 (续)
Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入 (续)”- 示例:
print("""我是第一行
我是第二行""")- 结果:两行之间会多一个空行
- 实际应用:复制诗歌等大段文字,保留原始格式。
- 字符串反复打印手机号码很麻烦,可以存储起来。
- 变量:程序里的变量相当于通讯录里的人名,可以通过人名(变量名)获取对应的值。
变量赋值操作
Section titled “变量赋值操作”- 变量:用于存储或替换值的。
- 变量名:
- 中间不能有空格。
- 不能以数字开头。
- 千万不要用引号包裹,否则就成了字符串。
- 例:
my_love = "13766666666" 赋值操作:给变量一个值的操作。- 通过变量名获取值,反复使用,无需每次都重新打一遍。
- Python 是从上到下执行的,必须要在前面先对变量进行赋值,然后才能用那个变量,否则会报错。
- 赋值后,就可以通过变量名获取那个值,反复使用,而不需要每次都重新打一遍。
- 如果对象换了号码,或者换了对象,那
my_love这个手机号也得跟着变,还是用赋值操作。
变量赋值操作 (续)二
Section titled “变量赋值操作 (续)二”- 可以用变量给变量赋值。
- 例:
my_ex = my_love - 赋值操作里,等号左边视为变量名,右边先求值。
- 示例:
my_love = "13766666666"my_ex = my_lovemy_love = "15066666666"print("当前my_love的值: " + my_love)print("当前my_ex的值: " + my_ex)print在有变量的情况下很有用。
变量赋值操作 (续)三:变量的更新和使用
Section titled “变量赋值操作 (续)三:变量的更新和使用”- 变量
greet赋值为"你好,吃了么" - 通过
print(greet + "张三")打印"你好,吃了么张三" - 更新
greet的值为"Yo what's up",所有用到greet的地方都会自动变成新的值 - 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新
变量赋值操作 (续)四:不同变量存储不同打招呼方式
Section titled “变量赋值操作 (续)四:不同变量存储不同打招呼方式”- 可以定义不同的变量来存储不同语言的打招呼方式。
- 示例:
greet_chinese = greetgreet_english = "Yo what's up"- 可以灵活切换打印不同语言的打招呼语。
- 例如,用
greet_chinese来打印中文打招呼语。
变量命名规则
Section titled “变量命名规则”- 变量名应易于理解和记忆。
- 只能由文字、数字、下划线组成。
- 不能有下划线之外的符号。
- 不能以数字开头。
- 变量名中间不能有空格。
- 避免使用
a、a1、abc等无意义名称,可能过几天就忘记用途。 - 如果违反硬性规则,Python会直接报错。
- 不报错不代表是好名字。
变量命名建议:不用拼音!
Section titled “变量命名建议:不用拼音!”- 拼音阅读速度慢,不如英文
username直观。 - 拼音不带声调易产生误解,如
gaoji可能指“高级”或“高集”。 - 平翘舌音不分者慎用拼音。
- Python 3.0后支持中文变量名,但主流仍用英文。
- 原因:控制台或日志等编码不兼容,可能显示乱码。
- 代码关键字和符号仍是英文,输入法切换麻烦。
- 搜索英文翻译不难。
Python 变量命名规范
Section titled “Python 变量命名规范”- 约定俗成使用下划线命名法:
- 字母全部小写
- 不同单词用下划线分隔开 (
user_age,user_gender) - 原本用空格的地方用下划线连接
- 其他风格:驼峰命名法 (
UserAge,UserGender) - Python 变量名一般使用下划线命名法
- 注意要点:
- 变量名大小写敏感 (
user_age和userAge是不同的变量) - 变量名不要占用 Python 的关键字 (
print等) - 关键字当前有30几个
Python 关键字
Section titled “Python 关键字”- PyCharm 会对 Python 关键字进行颜色高亮显示。
- 如果变量名是彩色的,说明是关键字,最好换成其他的。
Python 数据类型
Section titled “Python 数据类型”- Python 的整数和字符串是不同的类型。
- 整数:直接的数字,不要用引号包裹。
- 用引号包裹的数字是字符串
Python 数据类型 (续)
Section titled “Python 数据类型 (续)”- 浮点数:带小数点的数字。
- 例:
6.0 - 数学运算:
- 加减乘除:
+、-、*、/ - 乘号:
*(星号) - 除号:
/(正斜杠,shift键左边那个) - 示例:
1 + 2 - 3 / 4 * 5 - 运算顺序:先括号,然后乘方,然后乘除,最后加减
- 乘方符号:Python里是两个星号
Python 数学运算进阶:math 模块
Section titled “Python 数学运算进阶:math 模块”- 求2的三次方:
2 ** 3 - Python能做加减乘除、乘方,但更复杂的(三角函数、log、开方等)需导入
math模块。 - 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
print是函数,提供展示/输出功能。print是内置函数,Python 默认自带。math专门提供数学运算函数。- 导入&;
math&;模块:在文件开头写import math。 - 调用
math模块中的函数:math.函数名()
Python 数学运算进阶:math 模块 (续)导包及查看函数
Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”- 调用
math模块函数:math.函数名() - 计算sin 1弧度:
math.sin(1) - 计算以2为底8的对数:
math.log2(8) - 注意:单纯运算无输出,需使用
print
Python 数学运算进阶:math 模块 (续)
Section titled “Python 数学运算进阶:math 模块 (续)”- 若要展示数学计算结果,需使用
print或变量赋值。 - 示例:
import mathprint(math.log2(8))
result = math.log2(8)print(result)- 目标:编写一元二次方程求根公式计算器。
- 公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$
- 示例:计算 $-x^2 - 2x + 3 = 0$ 的实数根。
- a = -1, b = -2, c = 3
a = -1b = -2c = 3Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”- 平方根表示:
- 方法一:使用
**0.5,即 1/2 次方。 - 方法二:使用
math库中的sqrt()函数。 - 代码示例:
import math
a = -1 b = -2 c = 3
# 使用 math.sqrt() 函数 solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a) solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1) print(solution2)- 注意:数学公式中乘号可省略,但代码中不可省略。
- 一元二次方程求根公式计算器:完整代码实现及输出结果。
- 确保分子部分用括号
()括起来,再进行除法运算。 - 必须使用
print()函数才能在控制台看到计算结果。 - 示例代码:
import math
a = -1b = -2c = 3
# 第一个解:加号部分solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)print(solution2)- 运行结果:显示两个方程的解,例如
-3.0和1.0。
Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”- 只需更改变量
a、b、c的值,无需修改公式。 - 代码示例,计算 $x^2 + 9x + 20 = 0$ 的根:
import math
a = 1b = 9c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))- 结果展示正确。
- 用代码做数学计算的好处:
- 可以看到整个公式,方便检查,不易出错。
- 容易更改变量值,无需重复录入公式。
- 可通过中间变量分步骤,处理复杂公式。
- 例如,将 $b^2 - 4ac$ 赋值给
delta变量:
delta = b**2 - 4*a*c- 简化后续代码书写。
代码注释:给人看的解释
Section titled “代码注释:给人看的解释”- 用于解释代码思路,方便他人或自己理解。
- Python里,注释以
#开头,解释器会忽略该行。
代码注释 (续) 单行与多行注释
Section titled “代码注释 (续) 单行与多行注释”- 单行注释:以
#开头 - 多行注释:
- 方法一:每行开头加
# - 方法二:用三引号
"""或'''包裹
- 解释代码
- 临时禁用代码:在代码前加
#,跳过执行
PyCharm快捷键注释
Section titled “PyCharm快捷键注释”- 选中代码块,使用快捷键:
- Windows:
Ctrl + / - Mac:
Command + / - 再次使用快捷键取消注释
代码注释补充说明
Section titled “代码注释补充说明”- 多行注释可用三引号
"""或'''包裹,但跨行字符串也用三引号,注意区分。 - 建议不要在注释里过度放飞自我。
- 现实世界里食物、动物、人有不同种类,抽象世界里数字有不同种类,Python世界里数据也有不同种类。
Python 数据类型 (续)字符串 str
Section titled “Python 数据类型 (续)字符串 str”- 字符串类型
str:表示文本内容,由双引号或单引号包裹。 - 可用
len()函数获取字符串长度。 - 空格、数字、符号都占长度。
- 转义符(如
\n换行符)整体占一个长度。 - 提取字符串某位置的单个字符:字符串后跟方括号
[],内放索引。 - 索引可理解为顺序,但程序世界从
0开始计数。 - 提取字符串字符:
字符串[索引],索引从0开始。例如,"Hello"[3]返回"l"。索引为3表示第四个字符。 - 整数
int:如6、-32。 - 浮点数
float:如6.0、10.07。 - 布尔类型
bool:只有两个值:True和False。 True和False的首字母必须大写。- 空值类型
NoneType:只有一种值:None。 None不是 0,不是空字符串,也不是False。- 空值类型
NoneType:表示完全没有值 - 可先定义变量为
None None不是0,不是空字符串"",也不是False- 可用
type()函数返回对象类型 type("Hello")-><class 'str'>type(6)-><class 'int'>type(6.0)-><class 'float'>type(True)-><class 'bool'>type(None)-><class 'NoneType'>- 数据类型重要性:决定对象身上可用的函数
- 函数:负责执行某个功能
- 给函数合适的输入,它会给出正常的输出
- 例:做巧克力的机器,给可可粉才能产出巧克力
len()函数:得到字符串的长度- 用于整数身上会报错
- 除法:在整数和浮点数上用很合适,给字符串用会报错
Python 数据类型 (续)字符串 str (续)索引取值
Section titled “Python 数据类型 (续)字符串 str (续)索引取值”- 使用索引获取字符串中的单个字符:
字符串[索引] - 索引从
0开始 - 例如,
s = "Hello world!",s[0]的结果是"H" len(s):len()函数可获取字符串长度- 例如,
s = "Hello world!",len(s)的结果是12
字符串索引进阶
Section titled “字符串索引进阶”- 字符串总长度为12,索引从0开始,那么最后一个字符索引应该是11
- 获取字符串最后一个字符:
print(s[11]) - 也可以用
len()函数:print(s[len(s) - 1])
- 变量赋值:
b1 = Trueb2 = False- 注意:
True和False都需要大写开头,否则Python不识别
Python 数据类型 (续)类型使用错误示例
Section titled “Python 数据类型 (续)类型使用错误示例”- 浮点数
float:带小数点的数字,如1.5。 - 如果对布尔值
bool使用len()函数,Python 会报错。 - 了解操作对象的类型非常关键。
Python的两种执行模式
Section titled “Python的两种执行模式”- 命令行模式:
- 写好命令后,保存并运行整个文件。
- Python 解释器会逐行解析和执行文件。
Python的两种执行模式 (续) 交互模式
Section titled “Python的两种执行模式 (续) 交互模式”- 输入一行,立即执行并展示结果
- 无需创建新的
.py文件 - 进入交互式环境:
- PyCharm下方的Python控制台
- Windows的
cmd - Mac的终端输入
python3 - 显示三个尖括号
>>>,等待指令 - 输入Python命令,例如
print("hi"),回车直接执行 - 无需
print语句,直接显示执行结果
Python的两种执行模式 (续) 交互模式 (续)二
Section titled “Python的两种执行模式 (续) 交互模式 (续)二”- 查看变量当前值:输入变量名,回车
- 例如:
a = "你好!",输入a,回车,显示'你好!' - 在交互模式中,Python求值后会直接把返回结果展示出来
- 例如:输入
3 * 2,直接显示6 - 退出交互模式:
- 键入
quit(),回车 - 或者直接按
Ctrl + D - 交互模式的特点:
- 不需要创建任何
.py文件即可运行 - 不需要用
print就可以看到返回结果 - 所有输入的指令都不会被保存
- 一旦退出交互模式,就失去了之前键入的所有内容
- 交互模式像一个游乐场,让你随意玩一玩,看一看,用最简单的方式测试命令输出的结果。
- 交互模式不适合长期编码,适合快速测试和验证想法。
Python的两种执行模式 (续) 交互模式的用途
Section titled “Python的两种执行模式 (续) 交互模式的用途”- 适合快速测试和验证想法
- 也适合做一些一次性计算
- 输入算式,得到结果,然后退出关闭
- Python的
input()函数:从用户获取输入 - 用法:
input("这里是给用户的一些提示") - 标准的调用函数方式:函数名后跟括号,括号里放参数
input() 函数进阶用法
Section titled “input() 函数进阶用法”input("提示语"):从用户获取输入,提示语可选。- 运行后,会展示提示语,等待用户输入。
- 用户输入后,按下回车表示输入结束,程序继续运行。
- 注意:
input()始终返回字符串类型。 - 即使输入数字,也会被当成字符串处理。
- 若要进行数学运算,需先将字符串转换为整数类型。
- 使用变量获取
input()函数返回值:变量名 = input("提示语") - 例如:
user_age = input("请输入您的年龄:") - 之后可用该变量进行后续操作。
- 字符串转换为整数:
int("字符串") - 例如:
int("666")返回整数666。
Python 数据类型转换
Section titled “Python 数据类型转换”int():将其他类型转换为整数。- 例:
int("666")返回整数666。 - 注意:参数应能被转换为整数,否则报错。
float():将其他类型转换为浮点数。str():将其他类型转换为字符串,常用于打印。- 例:
print("知道了,你今年" + str(2) + "岁了!") - 整数不能直接和字符串连接打印,需先用
str()转换。 input()返回值是字符串,若要进行数学运算,需先用int()转换为整数。- 示例:
user_age = int(input("请输入您的年龄:"))user_age_after_10_year = user_age + 10print("您十年后会是" + str(user_age_after_10_year) + "岁")input() 函数返回值类型转换
Section titled “input() 函数返回值类型转换”user_weight = input("请输入您的体重(单位: kg):")user_height = input("请输入您的身高(单位: m):")- 问题:
user_weight和user_height都是字符串类型,不能直接用于数学计算。 - 解决方法:使用
float()函数将字符串转换为浮点数。 user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))- BMI计算公式:
user_BMI = user_weight / (user_height ** 2) - 完整代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))user_BMI = user_weight / (user_height ** 2)print(user_BMI)BMI结果格式化输出
Section titled “BMI结果格式化输出”- 目的:使输出结果更易读,保留两位小数。
- 方法:使用
f-string格式化字符串。 print(f"您的BMI是{user_BMI:.2f}"){user_BMI:.2f}:表示将user_BMI变量格式化为浮点数,并保留两位小数。- 完整代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))user_BMI = user_weight / (user_height ** 2)print(f"您的BMI是{user_BMI:.2f}")BMI分类标准
Section titled “BMI分类标准”| BMI | 范围 |
|---|---|
| 过轻 | 小于18.5 |
| 正常 | 18.5-24.9 |
| 超重 | 25-29.9 |
| 肥胖 | 大于等于30 |
if语句:根据条件执行不同代码
Section titled “if语句:根据条件执行不同代码”- 语法:
if 条件:
# 条件为真时执行的代码- 示例:
age = 20if age >= 18: print("已成年")if...else语句:条件为真或假时执行不同代码
Section titled “if...else语句:条件为真或假时执行不同代码”- 语法:
if 条件:
# 条件为真时执行的代码else:
# 条件为假时执行的代码- 示例:
age = 16if age >= 18: print("已成年")else: print("未成年")if...elif...else语句:多条件判断
Section titled “if...elif...else语句:多条件判断”- 语法:
if 条件1:
# 条件1为真时执行的代码elif 条件2:
# 条件2为真时执行的代码...else:
# 所有条件都为假时执行的代码- 示例:
score = 85if score >= 90: print("优秀")elif score >= 80: print("良好")elif score >= 60: print("及格")else: print("不及格")BMI计算器:if...elif...else实现BMI分类
Section titled “BMI计算器:if...elif...else实现BMI分类”- 根据BMI值判断身体状况(过轻、正常、超重、肥胖)。
- 代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))user_BMI = user_weight / (user_height ** 2)print(f"您的BMI是{user_BMI:.2f}")
if user_BMI < 18.5: print("您的BMI过轻")elif 18.5 <= user_BMI < 25: print("您的BMI正常")elif 25 <= user_BMI < 30: print("您的BMI超重")else: print("您的BMI肥胖")>:大于<:小于>=:大于等于<=:小于等于==:等于(注意与赋值=区分)!=:不等于
and:与(且)- 所有条件都为
True,结果才为True or:或- 只要有一个条件为
True,结果就为True not:非(取反)not True的结果是False- 示例:
age = 25if age > 18 and age < 30: print("青年")
is_student = Falseif not is_student: print("不是学生")Python 数据类型转换 (续)输出 BMI 值
Section titled “Python 数据类型转换 (续)输出 BMI 值”float(): 用于转换user_height和user_weightstr(): 用于将数值型的user_BMI转换为字符串,以便与字符串拼接输出。- 示例代码:
user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))user_BMI = user_weight / (user_height ** 2)print("您的BMI值为:" + str(user_BMI))if语句进阶:条件判断结构
Section titled “if语句进阶:条件判断结构”- 日常生活中的条件判断例子:
- 根据女朋友情绪判断今晚能否打游戏
- 根据老板脸色判断该不该提加工资
- 核心:判断条件是否满足,决定执行内容
- Python条件语句结构:
if [条件]:
# 执行内容if:表示“如果”[条件]:求值结果为True或False的布尔值- 示例:
is_happy = True # 定义布尔变量if is_happy:
# 条件为True时执行- 结合比较运算符:
==:等于号,比较两个对象的值
if 语句 (续):条件判断结构
Section titled “if 语句 (续):条件判断结构”- 注意:
if [条件]后有冒号:,表示条件结束 [执行语句]前需要缩进,建议四个空格- 所有
if下方有缩进的语句,都会被看作条件为真时要执行的内容
比较运算符 (续)
Section titled “比较运算符 (续)”==:等于,比较两个对象的值是否相等- 例:`3 == 3
返回True,“a” == “b”&;返回False` - 注意:比较运算符是两个等号
==,一个等号=是变量赋值 !=:不等于,比较两个对象的值是否不相等- 例:
"a" != "b"返回True >:大于>=:大于等于<:小于<=:小于等于- 含义和数学里比较符号相同
- 例:
5 >= 20可作为条件,值为False(布尔值)
if...else语句 (续):根据条件判断结构执行内容
Section titled “if...else语句 (续):根据条件判断结构执行内容”- 如果希望条件为假时执行语句,使用
else。 - 语法:
if [条件]:
# 条件为真时执行的语句else:
# 条件为假时执行的语句- Python 根据缩进判断语句归属。
- 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!
if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!mood_index < 60,打印为了自个儿小命,还是别打了。if和else下方的语句可以不止一行,只要注意缩进即可。
if...elif...else 语句:多重条件判断
Section titled “if...elif...else 语句:多重条件判断”- 适用于多个互斥条件的情况。
- 语法:
if 条件1:
# 条件1成立时执行的代码elif 条件2:
# 条件2成立时执行的代码else:
# 所有条件都不成立时执行的代码- Python 依据缩进判断语句归属。
- 示例:
mood_index = int(input("对象今天的心情指数是:"))if mood_index >= 90: print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")elif mood_index >= 60: print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")else: print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")- 注意缩进,
else不可独立于if存在。
if 语句进阶:嵌套条件语句
Section titled “if 语句进阶:嵌套条件语句”- 嵌套条件语句:在条件语句里面再放条件语句。
- 示例:
if [条件一]: if [条件二]: [语句A]- 语句A被执行的条件:
- 首先满足条件一为真。
- 其次还要满足条件二为真。
if [条件一]: if [条件二]: [语句A] else: [语句B]else下方的语句 B 被执行:- 必须首先满足条件一为真。
- 条件二为假。
- 缩进非常重要,Python 的缩进一般为四个空格。
if...elif...else 语句:多重条件判断 (续)二
Section titled “if...elif...else 语句:多重条件判断 (续)二”- Python 会依次判断各个条件,直到找到第一个为真的条件,执行里面的语句。
elif的数量没有上限或下限。- 这种结构相比嵌套更清晰易懂。
嵌套条件语句 (续):女友心情指数的例子
Section titled “嵌套条件语句 (续):女友心情指数的例子”- 定义变量
mood_index为 0 到 100 之间的整数,is_at_home为布尔值。 - 如果
mood_index小于 60,判断是否在家;如果mood_index大于等于 60,执行其他语句。
# mood_index 是0到100之间的整数
# is_at_home为布尔值if mood_index < 60: if is_at_home: print("放弃游戏,低调做人") else: print("自由!")- 如果对象心情指数小于60,且在家,则不能打游戏;否则,拥有自由。
- 多条件判断的关键是
elif,基本结构如下:
if [条件1]: [语句A]elif [条件2]: [语句B]elif [条件3]: [语句C]else: [语句D]- Python 从上往下执行,只会执行第一个满足条件的语句。
- 即使条件2和条件3都满足,也只会执行
elif 条件2下方的语句。 - 一旦进入某个分支,就不会再看同一层级的其他条件判断了。
- 结合多条件判断,丰富BMI计算器。
- 获取用户输入的体重和身高,转换为浮点数。
- 使用BMI计算公式:体重除以身高的平方。
- 打印计算结果。
- BMI划分标准:
- 偏瘦:计算结果小于等于18.5
- 正常:18.5 < BMI <= 25
- 偏胖:25 < BMI <= 30
- 肥胖:BMI > 30
BMI计算器:if...elif...else实现BMI分类 (续)二
Section titled “BMI计算器:if...elif...else实现BMI分类 (续)二”- BMI范围:
- 18.5 <
user_BMI<= 25 属于正常 - 25 <
user_BMI<= 30 属于偏胖 user_BMI> 30 属于肥胖- 代码实现:
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- Python里,数学表达式可以这样写:
18.5 < user_BMI <= 25 - 如果
user_BMI大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。 - 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用
else输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
- 可以尝试用嵌套条件增强计算器功能。
if语句进阶:嵌套条件语句(续)
Section titled “if语句进阶:嵌套条件语句(续)”- 例如,如果需要多个条件同时满足才能获得奖励(例如Switch),可使用嵌套
if语句。 - 如果使用嵌套,代码会变得不优雅。
多条件并列的情况
Section titled “多条件并列的情况”- 一个月内:
- 主动做家务次数超过10次
- 发红包次数超过1次
- 陪逛街次数超过4次
- 没有惹对象生气过
if red_envelope_count > 1: if shopping_count > 4: if has_been_angry == False: print("Switch!") else: print("Switch 随风散去...") else: print("Switch 随风散去...")else: print("Switch 随风散去...")Python 逻辑运算符
Section titled “Python 逻辑运算符”- Python 的逻辑运算符有三个:
and(与)、or(或)、not(非)。 and:所有条件为True时,结果才为True;只要有一个为False,结果就为False。- 示例:
x > 5 and x < 10 and x * 2 == 12 or:只要有一个条件为True,结果就为True;所有条件为False时,结果才为False。- 示例:
x > 5 or x < 10 or x * 2 == 12 not:取反。- 示例:
not x > 5表示 x 不大于 5。 and和or可以连接两个或以上的操作对象。
Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子
Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”not运算:将布尔值反转。- 如果原先操作对象是
True,返回False。 - 如果原先操作对象是
False,返回True。 and运算:类似于悲观的人,只要有一件事不开心,结果就不开心。or运算:类似于乐观的人,只要有一件事开心,结果就开心。- 逻辑运算符可以混用,但需注意运算优先级:
not>and>or。 - 可用括号改变运算顺序,与数学运算用法一致。
- 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry): print("摩擦摩擦,掌声等待Switch!")else: print("Switch 随风散去...")- 逻辑运算符比嵌套
if语句更直观和优雅。
Python 列表 (List)
Section titled “Python 列表 (List)”- 问题:如果有多个相关联的数据(例如10个购物商品),定义10个独立的变量 (
item1,item2…) 并分别赋值会非常麻烦。 - 解决方案:使用数据结构将相关数据整合在一起,Python 中的列表 (
list) 就能达到这个目的。
- 空列表:使用一对方括号
[]表示。 - 示例:
shopping_list = [] - 包含数据的列表:用方括号
[]包裹多个数据,数据之间用逗号,分隔。 - 示例:
shopping_list = ["键盘", "键帽"]
列表操作:添加元素
Section titled “列表操作:添加元素”- 若要向已定义的列表里添加新元素,可以使用列表的
append()方法。 - 示例:
shopping_list.append("显示器") - 方法和函数类似,都用于负责特定功能。
- 方法:一般在操作对象后加点,
对象.方法名() - 例如:
shopping_list.append("显示器") - 函数:
函数名(对象),里面放入操作对象 - 例如:
len(shopping_list) - 可变数据类型:列表 (
list) - 不可变数据类型:字符串 (
str)、整数 (int)、浮点数 (float)、布尔类型 (bool) - 字符串示例:
- 如果想把字符串转成大写,可以用
.upper()方法。它会返回一个把原字符串字母全部变成大写的新字符串,但是原先的字符串还是它本身。 - 需要把新的字符串再赋值给变量才行。
s = "Hello"print(s.upper())s = s.upper()print(s)- 列表是可变的,
append()方法会直接改变原列表。
Python 列表 (List) 的操作
Section titled “Python 列表 (List) 的操作”append()方法:向列表添加元素- 不需要对变量重新赋值,直接在原列表上生效
- 示例:
shopping_list.append("显示器") remove()方法:删除列表中的某个元素- 括号里放该元素的值
- 直接调用
remove()即可,在原列表上生效,不需要对变量重新赋值 - 示例:
shopping_list.remove("显示器") - 元素必须确实存在于列表中,否则会报错
- 随时打印列表:查看里面有哪些元素
Python 列表 (List) 的特点
Section titled “Python 列表 (List) 的特点”- 可以放不同类型的数据,使用起来很自由和灵活。
- 示例:
list1 = ["Hello", 66.6, True, None] - 列表和字符串一样,都可以通过
len()函数求长度 len()函数会返回列表里元素的数量- 可以通过索引获得某个位置的元素
- 列表的索引同样从0开始数
Python 列表 (List) (续) 列表操作:修改元素
Section titled “Python 列表 (List) (续) 列表操作:修改元素”- 可以利用索引赋值直接覆盖该位置原本的元素。
- 示例:
shopping_list = ["键盘", "显示器", "硬盘"] shopping_list[1] = "音响" # 索引为1的元素被更改 print(shopping_list)Python 列表 (List) (续) 列表操作:内置函数
Section titled “Python 列表 (List) (续) 列表操作:内置函数”max()函数:返回列表里的最大值。min()函数:返回列表里的最小值。sorted()函数:可以把排序好的新列表返回给你,同时不改变原先的列表。- 示例:
num_list = [1, 13, -7, 2, 96] print(max(num_list)) # 打印列表里的最大值 print(min(num_list)) # 打印列表里的最小值 print(sorted(num_list)) # 打印排序好的列表Python 列表 (List) (续) 列表操作:更多操作
Section titled “Python 列表 (List) (续) 列表操作:更多操作”shopping_list.append("音响"):添加元素到列表shopping_list.append("电竞椅"):继续添加元素print(shopping_list):打印列表内容print(len(shopping_list)):打印列表长度,结果为3- 索引:获取列表特定位置元素
print(shopping_list[0]):打印第一个元素,索引从0开始
Python 列表 (List) (续) 列表操作:索引赋值与元素修改
Section titled “Python 列表 (List) (续) 列表操作:索引赋值与元素修改”- 可以利用索引赋值直接覆盖该位置原本的元素。
- 示例:
shopping_list = ["键盘", "显示器", "硬盘"]shopping_list[1] = "硬盘" # 索引为1的元素被更改print(shopping_list)Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数
Section titled “Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数”max()函数:返回列表里的最大值。min()函数:返回列表里的最小值。sorted()函数:可以把排序好的新列表返回,不改变原先的列表。- 示例:
num_list = [1, 13, -7, 2, 96]print(max(num_list)) # 打印列表里的最大值print(min(num_list)) # 打印列表里的最小值print(sorted(num_list)) # 打印排序好的列表Python 列表 (List) 列表应用
Section titled “Python 列表 (List) 列表应用”- 定义价格列表:
price = [799, 1024, 200, 800]- 使用
max()函数获取列表最大值: max_price = max(price)- 使用
min()函数获取列表最小值: min_price = min(price)
Python 列表应用 (续) sorted()函数
Section titled “Python 列表应用 (续) sorted()函数”sorted(price):返回排序后的列表,不改变原列表price。- 使用
print()函数查看排序后的列表,例如:print(sorted_price),结果为[200, 799, 800, 1024],从小到大。
Python 字典 (Dictionary)
Section titled “Python 字典 (Dictionary)”- 目的:实现通讯录功能,通过人名查找电话号码。
- 变量的局限性:勉强实现,不灵活。
phone_number_of_xiaoming = "13700000000":为小明电话号码赋值。phone_number_of_xiaohua = "13700000001":为小华电话号码赋值。print(phone_number_of_xiaoming):打印小明电话号码。
Python 字典 (Dictionary) (续)
Section titled “Python 字典 (Dictionary) (续)”- 局限性:用列表存储联系人信息不方便通过名字查找电话号码。
- 字典 (dictionary):存储键值对 (key-value pairs) 的数据结构。
- 键 (key):用于查找值,如人名。
- 值 (value):键对应的信息,如电话号码。
- 类似于现实生活中的字典,通过字(键)查找释义(值)。
- 示例:
contacts = {},空的字典用一对花括号表示。 - 要在字典里面放入多个键值对,就用花括号把它们包住,示例:
contacts = {"小明":"13700000000", "小花":"13700000001"}
Python 字典 (Dictionary) (续)二 键的类型与元组tuple
Section titled “Python 字典 (Dictionary) (续)二 键的类型与元组tuple”- 键值对之间用冒号表示对应,键值对之间用逗号分隔。
- 获取键的值:
字典名[键] - 键的类型必须是不可变的:
- 字符串
str、整数int、浮点数float、布尔类型bool可以作为键。 - 列表
list属于可变数据类型,不能作为键。 - 元组
tuple: - 不可变但又很像列表的数据结构。
- 示例:
example_tuple = ("键盘", "键帽"),用圆括号。 - 元组里面可以放多个元素。
- 由于元组不可变,添加、删除元素等不能操作。
- 列表用方括号,元组用圆括号。
Python 字典 (Dictionary) (续) 键的类型与元组tuple
Section titled “Python 字典 (Dictionary) (续) 键的类型与元组tuple”- 元组作为键:由于元组是不可变的,所以可以作为字典的键。
- 示例:
contacts = {("张伟", 23): "15000000000"},这里("张伟", 23)就是一个元组键。 - 字典和列表一样,都属于可变数据类型,可以添加和删除键值对。
Python 字典 (Dictionary) (续) 添加与更新键值对
Section titled “Python 字典 (Dictionary) (续) 添加与更新键值对”- 添加新的键值对:
- 使用
字典名[新键] = 新值的语法。 - 示例:
contacts["美女A"] = "18600000000",会在字典中新增一个键值对。 - 更新已存在的键值对:
- 如果使用
字典名[已存在的键] = 新值的语法,会覆盖该键的原有值。 - 示例:如果
contacts中已有"美女A",再次执行contacts["美女A"] = "18600000000"会更新"美女A"对应的值。
Python 字典 (Dictionary) (续) 检查键是否存在
Section titled “Python 字典 (Dictionary) (续) 检查键是否存在”- 使用
in运算符检查键是否在字典中存在,返回一个布尔值。 - 语法:
键 in 字典名 - 示例:
print("小明" in contacts):如果存在则返回True。print("小明明" in contacts):如果不存在则返回False。
Python 字典 (Dictionary) (续) 删除键值对
Section titled “Python 字典 (Dictionary) (续) 删除键值对”- 使用
del关键字删除字典中的某个键值对。 - 语法:
del 字典名[要删除的键] - 示例:
del contacts["小明"],会从contacts字典中删除键"小明"及其对应的值。
Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典
Section titled “Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典”- 无法删除不存在的键,否则会报错
len(字典名):得到字典键值对的数量- 结合
input()、if判断,制作一个查询流行语含义的电子词典程序 - 步骤:
- 创建空字典:
slang_dict = {} - 预先放入内容:
slang_dict = {"觉醒年代": "..."} - 用逗号分隔键值对
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二”- 结合
input()、if判断,制作查询流行语含义的电子词典程序。 - 如果一行过长,可以换行,使每个词条更清晰。
- 步骤(续):
- 使用
字典名[新键] = 新值语法,添加新的键值对。 - 依次添加流行语和释义到字典中
- 现在字典里有十条内容了,可以用字典名,方括号,放入键的方式进行赋值
- 我们的查询功能是这样的,首先询问用户
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三”- 使用
input()函数提示用户输入要查询的流行语:query = input("请输入您想查询的流行语:") - 使用
in判断用户输入的词条是否在字典里:if query in slang_dict: - 如果词条在字典里,打印:
print("您查询的" + query + "含义如下") - 获取
query的释义:slang_dict[query](字典名[键]) - 如果
query不在字典中,提示:print("词条不存在")
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四”- 完整的电子词典程序代码示例:
slang_dict = { "YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火", "双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍", "元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在", "绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑", "社死": "想找个地缝钻进去", "伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻", "我看不懂,但我大受震撼": "台词", "躺赢": "形容赢得非常轻松", "集美": "姐妹", "yyds":"永远的神"}
query = input("请输入您想查询的流行语:")
if query in slang_dict: print("您查询的" + query + "含义如下:") print(slang_dict[query])else: print("词条不存在")- 运行代码,输入流行语,程序会输出对应的解释,如果输入的流行语不在字典中,程序会提示“词条不存在”。
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五”- 如果查询词条不存在,程序会打印“您查询的流行语暂未收录”。
- 程序最后会告知用户,当前词典收录了多少个词条。
- 完整代码:
slang_dict = { "YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火", "双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍", "元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在", "绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑", "社死": "想找个地缝钻进去", "伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻", "我看不懂,但我大受震撼": "台词", "躺赢": "形容赢得非常轻松", "集美": "姐妹", "yyds":"永远的神"}
query = input("请输入您想查询的流行语:")
if query in slang_dict: print("您查询的" + query + "含义如下:") print(slang_dict[query])else: print("您查询的流行语暂未收录")
print("当前本词典收录词条数为:" + str(len(slang_dict)) + "个。")len()函数:获取字典长度,即键值对数量。str()函数:将整数转换为字符串,以便拼接。- 运行结果:显示查询结果或提示未收录,并显示当前词典收录的词条数量。
Python循环语句:for循环
Section titled “Python循环语句:for循环”- 可用于列表、字典、字符串等数据结构的迭代。
- 对列表迭代:按顺序处理每个元素。
Python 循环语句 (for loop)简介
Section titled “Python 循环语句 (for loop)简介”- 用于对列表、字典或字符串等可迭代对象中的元素进行迭代操作。
for 循环基本结构
Section titled “for 循环基本结构”- 语法:
for 变量名 in 可迭代对象:
# 对每个变量做一些事情for:关键字,后跟空格。变量名:自定义变量名,代表迭代对象中的每个元素。in:关键字,后跟迭代对象。- 针对每个元素的操作写在
for的下一行,缩进表示语句属于for循环内部。
示例:检查体温列表
Section titled “示例:检查体温列表”temperature_list = [36.4, 36.6, 36.2, 37.0, 36.8]for temperature in temperature_list: if temperature >= 38: print(temperature) print("完蛋了")temperature_list:已定义的包含体温的列表。temperature:变量名,依次赋值为列表中的每个元素。- 如果体温超过38度,打印体温并输出“完蛋了”。
for 循环应用:用字典实现体温筛查
Section titled “for 循环应用:用字典实现体温筛查”- 创建字典
temperature_dict,以工号为键,体温为值。 - 使用
temperature_dict.keys()返回所有键,temperature_dict.values()返回所有值,temperature_dict.items()返回所有键值对。 - 结合
for循环和items方法,打印发烧员工的工号。 for staff_id, temperature in temperature_dict.items():- 变量会被赋值为键和值组成的元组。
- 等价于:
for temperature_tuple in temperature_dict.items(): staff_id = temperature_tuple[0] temperature = temperature_tuple[1]staff_id:工号temperature:体温- 示例代码:
temperature_dict = {"111":36.4, "112":36.6, "113":36.2, "114":38.3, "115":38.1}for staff_id, temperature in temperature_dict.items(): if temperature >= 38: print(staff_id)- 运行结果:打印体温高于或等于38度的员工的工号。
range() 函数进阶用法及示例
Section titled “range() 函数进阶用法及示例”range(起始值, 结束值, 步长):生成数字序列- 起始值:序列起始数字(包含)
- 结束值:序列结束数字(不包含)
- 步长:每次跨越几个数字,默认为1
- 示例:
range(5, 10, 2)
for num in range(1, 10, 2): print(num)- 结果:打印1到9之间的所有奇数
for 循环应用:高斯求和问题
Section titled “for 循环应用:高斯求和问题”- 计算从1加到100的和
total = 0for i in range(1, 101): total = total + iprint(total)- 结果:打印出5050
for循环进阶:日落拍摄自动化程序改进
Section titled “for循环进阶:日落拍摄自动化程序改进”- 问题:仅用
if判断,程序只判断一次,无法捕捉完整日落过程。 - 方案:用
for循环重复执行if判断。
for i in range(100):
# measure_brightness函数返回当前测量的天空亮度 if measure_brightness() >= 500:
# 拍照 take_photo()for循环会执行100次判断,但计算机速度快,可能在日落结束前就完成了。
Python 循环语句:while 循环
Section titled “Python 循环语句:while 循环”- 解决
for循环次数固定的问题。 while循环:当条件为真时,重复执行代码块。
while 循环基本结构
Section titled “while 循环基本结构”- 语法:
while 条件A: 行动Bwhile:关键词- 条件A:求值为布尔值(
True或False)
while 循环流程
Section titled “while 循环流程”- 判断条件A是否为真。
- 如果为真,执行行动B。
- 再次判断条件A是否为真,重复以上步骤,直到条件A为假,退出循环。
- 如果条件A一开始就为
False,行动B一次也不会执行。
while 条件A: 行动B+-------+| 条件A | --(假)--> 结束+-------+ | (真)| V+-------+| 行动B |+-------+Python 循环语句:while 循环 (续)日落拍摄自动化程序改进
Section titled “Python 循环语句:while 循环 (续)日落拍摄自动化程序改进”while循环用于日落拍摄自动化程序:当天空亮度 (measure_brightness()) 大于或等于 500 时,持续拍照 (take_photo()),直到亮度小于 500。- 这种情况下,
while循环比for循环更适合,因为条件何时结束是未知的。
for 循环与 while 循环的转换
Section titled “for 循环与 while 循环的转换”- 在很多情况下,
while循环和for循环可以互相转换,实现相同的功能。 - 示例:以下三段代码都用于打印列表
list1里的每个元素:
list1 = ["你", "好", "吗", "兄", "弟"]
# 第一种:简单直白的 for 循环 for char in list1: print(char)
# 第二种:for 循环和 range() 的结合 for i in range(len(list1)): print(list1[i])
# 第三种:while 循环 i = 0 while i < len(list1): print(list1[i]) i = i + 1for i in range(len(list1))&;解释:range()函数如果只放一个值(如len(list1)),默认起始值是0。- 结束值是
range()中放入的值(不包含),即list1的长度。 i会依次被赋值为0、1、2等,直到len(list1) - 1。for i in range(len(list1)):i值从0开始,直到len(list1) - 1。while循环:i初始化为0- 当
i < len(list1)时,进入循环,打印list1[i] i值加1,再次进入循环,直到i变成列表长度,退出循环- 总结:在既可用
for循环,也可用while循环的情况下,两种方式可实现相同功能。
for 循环 vs while 循环总结
Section titled “for 循环 vs while 循环总结”for循环:- 更加简单直观,所需行数更少。
- 适用于有明确循环对象或次数的情况。
while循环:- 更加通用。
- 适用于循环次数未知的情况。
- 但也更加危险,容易进入无限循环(如果忘记写对
i进行递增的行)。
while 循环应用:求平均值的计算器
Section titled “while 循环应用:求平均值的计算器”- 使用
while循环写一个对用户输入数字求平均值的计算器。
while 循环应用:求平均值的计算器 (续)程序流程实现
Section titled “while 循环应用:求平均值的计算器 (续)程序流程实现”- 用户输入任意数量的数字,输入
q结束,程序计算平均值。 - 程序开始时打印提示信息
print("哈喽呀!我是一个求平均值的程序。")。 - 使用
while循环持续获取用户输入:while True:。 input("请输入数字:")提示用户输入数字,并将输入值赋给变量number。- 如果用户输入
q,使用break语句退出循环:if number == "q": break。 - 尝试将输入的字符串转换为浮点数,并累加到
total变量中:total = total + float(number),同时增加计数器count的值:count = count + 1。 try...except结构:捕获ValueError异常。如果用户输入无法转换为浮点数的字符串,程序会执行except代码块,打印错误提示信息,并使用continue语句跳过本次循环。
while 循环应用:求平均值的计算器 (续)代码实现
Section titled “while 循环应用:求平均值的计算器 (续)代码实现”- 初始化
total和count变量:
total = 0count = 0- 循环结束后,如果
count为 0,表示没有输入任何有效数字,打印提示信息。否则,计算平均值并打印结果:
if count == 0: print("您没有输入任何数字")else: average = total / count print("平均数是:" + str(average))while 循环应用:求平均值的计算器 (续)完整代码
Section titled “while 循环应用:求平均值的计算器 (续)完整代码”print("哈喽呀!我是一个求平均值的程序。")
total = 0count = 0
while True: number = input("请输入数字:") if number == "q": break try: total = total + float(number) count = count + 1 except ValueError: print("输入有误,请输入数字或q") continue
if count == 0: print("您没有输入任何数字")else: average = total / count print("平均数是:" + str(average))- 运行上述代码,程序会提示用户输入数字,并计算平均值,直到用户输入
q结束。 - 获取用户输入后,需要赋值给一个变量:
user_input = input("请输入数字(完成所有数字输入后,请输入q终止程序):") while循环:while user_input != "q":
while 循环应用:求平均值的计算器 (续)程序流程实现(续)二
Section titled “while 循环应用:求平均值的计算器 (续)程序流程实现(续)二”- 在
while循环里,如果用户输入的不是q,先用float()函数把用户输入的内容转换为小数。 num = float(user_input):先将用户输入的内容转换为小数。total = total + num:然后把total加上这个数字。- 简化写法:
total += num - count = count + 1:
count变量加1,记录用户的输入个数。简化写法:count += 1 - 如果用户输入的内容不能转成小数,程序会报错。
- 因此需要
try...except捕获异常。
while 循环应用:求平均值的计算器 (续)添加try...except结构
Section titled “while 循环应用:求平均值的计算器 (续)添加try...except结构”- 代码:
try: num = float(user_input) total += num count += 1except: print("输入有误,请输入数字或q")try…except`代码块:
- 如果
try代码块没有错误,直接跳过except代码块。 - 如果
try代码块有错误,不继续执行try代码块,执行except代码块。 - 用户输入错误会打印提示,但程序会继续执行。输入错误后,之前的输入也会被清零。
continue关键字:跳过当前循环,不再执行continue后面的代码,回到循环开头。
while 循环应用:求平均值的计算器 (续)添加continue关键字
Section titled “while 循环应用:求平均值的计算器 (续)添加continue关键字”except模块添加continue关键字,跳过本次循环:
except: print("输入有误,请输入数字或q") continuecontinue:跳过本次循环,回到循环开头- 如果用户输入有误,则跳过本次循环,不进行后续的数值累加。
- 简化写法:
total += num和count += 1等同于total = total + num和count = count + 1。- 计算平均值:result = total / count
while 循环应用:求平均值的计算器 (续)代码优化:避免除零错误
Section titled “while 循环应用:求平均值的计算器 (续)代码优化:避免除零错误”- 问题:如用户首次输入
q终止程序,total和count均为0,导致除零错误。 - 解决方法:
- 在计算平均值前,判断
count是否为0。 - 如果
count为0,则result也等于0。 - 否则,
result才等于total / count。 - 代码:
if count == 0: result = 0else: result = total / count- 现在运行程序,如果第一次输入
q终止程序,则不会报错。
循环语句应用:求平均值的计算器(续)代码实现(续)三
Section titled “循环语句应用:求平均值的计算器(续)代码实现(续)三”result = total / count:计算平均值。print("您输入的数字平均值为:" + str(result)):输出计算结果。- 完整代码:
print("哈喽呀!我是一个求平均值的程序。")
count = 0total = 0
user_input = input("请输入数字(完成所有数字输入后,请输入q终止程序):")while user_input != "q": try: num = float(user_input) total += num count += 1 except: print("输入有误,请输入数字或q") user_input = input("请输入数字(完成所有数字输入后,请输入q终止程序):") continue user_input = input("请输入数字(完成所有数字输入后,请输入q终止程序):")
if count == 0: result = 0else: result = total / countprint("您输入的数字平均值为:" + str(result))- 运行程序,随意输入几个数字,然后输入
q,可以看到这里已经打印出了正确的平均值。 - 第一次运行的时候就输入
q,这里也打印出了正确的平均值。
for 循环应用:字符串拼接 (续) 字符串格式化方法:F-string:
Section titled “for 循环应用:字符串拼接 (续) 字符串格式化方法:F-string:”- F-string:更简洁、直观的字符串格式化方法。
- 语法:在字符串前加
f,用花括号{}包裹变量名。 - 示例:
f"字符串{变量名}",花括号可直接放入变量。 - 优势:代码更易读,减少加号连接。
- 代码示例:
contacts = ["老余", "老林", "老陈", "老曾", "老李", "老张"]year = "虎"
for name in contacts: message_content = f"律回春渐,新元肇启。\n新岁甫至,福气东来。\n金{year}贺岁,欢乐祥瑞。\n金{year}敲门,五福临门。\n给{name}及家人拜年啦!\n新春快乐,{year}年大吉!" send_message(name, message_content)- 反斜杠 ``:用于换行,使代码更易读。
- F-string优势:减少字符串拼接,代码简洁清晰。
format 方法:字符串格式化 (续)一
Section titled “format 方法:字符串格式化 (续)一”- Python 提供的字符串格式化方法,更简洁优雅。
- 语法:
"string_template".format(value1, value2, ...) string_template:包含占位符的字符串,占位符用花括号{}表示。- 花括号
{}表示会被替换的位置,里面的数字表示用.format()中第几个参数进行替换(从0开始计数)。 - 示例:
message_content = """律回春渐,新元肇启。新岁甫至,福气东来。金{0}贺岁,欢乐祥瑞。金{0}敲门,五福临门。给{1}及家人拜年啦!新春快乐,{0}年大吉!""".format(year, name){0}:会被.format()方法中的第一个参数year替换。{1}:会被.format()方法中的第二个参数name替换。- 生肖为“虎”,姓名为“老林”时,
message_content会被格式化成完整的字符串。
format 方法:字符串格式化 (续)二
Section titled “format 方法:字符串格式化 (续)二”format方法还支持根据关键词而不是位置来指定替换对象。- 示例:
message_content = """律回春渐,新元肇启。新岁甫至,福气东来。金{current_year}贺岁,欢乐祥瑞。金{current_year}敲门,五福临门。给{receiver_name}及家人拜年啦!新春快乐,{current_year}年大吉!""".format(current_year=year, receiver_name=name)- 花括号内使用关键词
current_year和receiver_name。 - 在
.format()方法中,指定current_year=year和receiver_name=name,将变量值传递给对应的关键词。 - 这种情况下,生肖和人名的位置不再重要,只看
format里的关键字。
format 方法 (续)三及F-string对比
Section titled “format 方法 (续)三及F-string对比”message_content = """\n律回春渐,新元肇启。\n新岁甫至,福气东来。\n金{year}贺岁,欢乐祥瑞。\n金{name}敲门,五福临门。\n给{name}及家人拜年啦!\n新春快乐,{year}年大吉!\n""".format(name=name, year=year)- 等号前面的部分是关键字,对应花括号里的关键字
- 等号后面的部分是参数值
F-string字符串格式化:f"字符串{变量名}",在字符串前加f,花括号里放变量名- 更简洁
Python 字典 (Dictionary) (续) 格式化输出
Section titled “Python 字典 (Dictionary) (续) 格式化输出”gpa_dict存储学生姓名和绩点信息的字典。for name, gpa in gpa_dict.items():循环遍历字典的键值对。print("{0}你好,你的当前绩点为:{1}".format(name, gpa)):使用format方法打印姓名和绩点,无需手动转换类型。- 格式化浮点数:
"{:.2f}",保留两位小数。 - 使用 F-string:
f"{name}你好,你的当前绩点为:{gpa:.2f}",效果相同。
函数 (Functions) 简介
Section titled “函数 (Functions) 简介”- 目的:避免重复代码,遵循 DRY (Don’t Repeat Yourself) 原则。
- 计算扇形面积示例:
- 多处需计算不同扇形面积,仅角度和半径不同,出现大量相似代码。
- 违反 DRY 原则。
- 函数:
- 帮助远离代码复读机行为。
- 避免重复编写相同逻辑的代码。
函数基本概念
Section titled “函数基本概念”- 函数:
- 执行特定任务的代码块。
- 接收输入(参数),进行处理,返回输出(返回值)。
- 优点:
- 代码重用:一次编写,多次调用。
- 模块化:将复杂任务分解为更小、更易管理的模块。
- 可读性:提高代码可读性和可维护性。
函数的创建与调用
Section titled “函数的创建与调用”- 定义函数:
- 使用
def关键字。 - 语法:
def 函数名(参数1, 参数2, ...):
# 函数体 return 返回值def:定义函数的关键字。函数名:自定义函数名称,遵循变量命名规则。参数:函数接收的输入值,可选。函数体:实现函数功能的代码块,需要缩进。return:返回值,可选。若无return,函数默认返回None。- 调用函数:
- 使用
函数名(参数值1, 参数值2, ...)语法。 - 示例:
result = my_function(arg1, arg2)
函数示例:扇形面积计算
Section titled “函数示例:扇形面积计算”- 定义计算扇形面积的函数:
def calculate_sector_area(central_angle, radius): pi = 3.14 area = (central_angle / 360) * pi * (radius ** 2) return area- 调用函数:
central_angle1 = 160radius1 = 30area1 = calculate_sector_area(central_angle1, radius1)print(f"扇形面积为: {area1}")- 参数:函数接收的输入值,用于函数内部计算。
- 参数类型:
- 必需参数:调用函数时必须提供的参数,顺序和数量需与函数定义一致。
- 默认参数:在函数定义时指定默认值的参数,调用时可省略。
- 可变参数:允许函数接收任意数量的参数。
- 关键字参数:允许调用者以
参数名=参数值的形式传递参数,顺序可变。
函数的参数 (续)默认参数的定义方式
Section titled “函数的参数 (续)默认参数的定义方式”- 默认参数:在定义函数时,为参数指定默认值。
- 语法:
def 函数名(参数名=默认值): - 注意:默认参数必须放在参数列表的末尾,否则会报错。
- 示例:
def greet(name, greeting="Hello"): print(f"{greeting}, {name}!")
greet("Alice") # 输出:Hello, Alice!greet("Bob", "Hi") # 输出:Hi, Bob!函数的参数 (续)默认参数定义方式
Section titled “函数的参数 (续)默认参数定义方式”- 默认参数必须放在参数列表的末尾,否则会报错。
- 错误示例:
def greet(greeting="Hello", name): print(f"{greeting}, {name}!")- Python 解释器会提示
SyntaxError: non-default argument follows default argument,表示非默认参数(没有默认值的参数)不能放在默认参数前面。
函数的参数 (续)默认参数的类型
Section titled “函数的参数 (续)默认参数的类型”- 默认参数可以是任何数据类型,包括数字、字符串、列表、字典等。
- 示例:
def append_to_list(value, my_list=[]): my_list.append(value) print(my_list)
append_to_list(1) # 输出:[1]append_to_list(2) # 输出:[1, 2]- 注意:如果默认参数是可变数据类型(如列表或字典),多次调用函数时,默认参数会被修改。
函数的参数 (续)可变参数
Section titled “函数的参数 (续)可变参数”- 可变参数:允许函数接收任意数量的位置参数。
- 语法:
def 函数名(*args): *args:表示接收任意数量的位置参数,args是一个元组,包含所有传入的参数。- 示例:
def my_sum(*args): total = 0 for num in args: total += num return total
print(my_sum(1, 2, 3)) # 输出:6print(my_sum(1, 2, 3, 4, 5)) # 输出:15函数的参数 (续)可变参数(续)
Section titled “函数的参数 (续)可变参数(续)”- 可变参数:允许函数接收任意数量的位置参数。
- 语法:
def 函数名(*args): *args:表示接收任意数量的位置参数,args是一个元组,包含所有传入的参数。- 示例:
def my_sum(*args): total = 0 for num in args: total += num return total
print(my_sum(1, 2, 3)) # 输出:6print(my_sum(1, 2, 3, 4, 5)) # 输出:15- 函数内部将
args视为元组,可用循环迭代访问每个参数。
函数的参数 (续)关键字参数
Section titled “函数的参数 (续)关键字参数”- 关键字参数:允许调用者以
参数名=参数值的形式传递参数。 - 语法:
def 函数名(**kwargs): **kwargs:表示接收任意数量的关键字参数,kwargs是一个字典,包含所有传入的参数。- 示例:
def print_info(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}")
print_info(name="Alice", age=30, city="New York")
# 输出:
# name: Alice
# age: 30
# city: New York- 函数内部将
kwargs视为字典,可用items()方法迭代访问每个参数。 - 关键词参数的顺序可以随意调整,因为函数会根据关键词来识别参数。
函数的参数 (续)关键词参数 (续)
Section titled “函数的参数 (续)关键词参数 (续)”- 关键字参数:允许调用者以
参数名=参数值的形式传递参数。 - 语法:
def 函数名(**kwargs): **kwargs:表示接收任意数量的关键字参数,kwargs是一个字典,包含所有传入的参数。- 示例:
def print_info(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}")
print_info(name="Alice", age=30, city="New York")
# 输出:
# name: Alice
# age: 30
# city: New York- 函数内部将
kwargs视为字典,可用items()方法迭代访问每个参数。 - 关键词参数的顺序可以随意调整,因为函数会根据关键词来识别参数。
函数的参数 (续)参数组合使用情况
Section titled “函数的参数 (续)参数组合使用情况”- 函数可以同时使用必需参数、默认参数、可变参数和关键字参数,但顺序必须是:必需参数、默认参数、可变参数、关键字参数。
- 示例:
def complex_function(a, b=1, *args, **kwargs): print(f"a: {a}, b: {b}") print(f"args: {args}") print(f"kwargs: {kwargs}")
complex_function(10, 20, 30, 40, name="Alice", age=30)
# 输出:
# a: 10, b: 20
# args: (30, 40)
# kwargs: {'name': 'Alice', 'age': 30}- 这种情况下,
a是必需参数,b是默认参数,args是可变参数,kwargs是关键字参数。
函数简介与自定义函数
Section titled “函数简介与自定义函数”- Python自带函数:
print、sum、type等,完成特定任务。 - 使用方式:
函数名(参数) - 不仅可以调用,还可以定义自己的函数。
- 可将定义函数想象成制作一个负责特定任务的机器。
- 一旦制作好,直接使用,无需反复定义。
- 示例:计算扇形面积的函数
- 步骤:
def关键字:表示开始定义函数。
定义函数(续)
Section titled “定义函数(续)”def关键字:表示开始定义函数。- 函数名后跟圆括号
()和冒号:。 - 缩进:用于划分代码块,表示哪些代码属于该函数。
- 定义函数时,函数体内的代码不会立即执行,只有在调用函数时才执行。
- 调用函数:
函数名(),Python会执行函数定义里的代码。 - 函数调用:
calculate_sector_1(),Python逐行执行函数体内的代码,打印扇形面积。
函数的创建与调用 (续)添加参数,提高通用性
Section titled “函数的创建与调用 (续)添加参数,提高通用性”- 通过参数,使函数变得更加通用。
- 类似于做包子的机器,机器接受肉馅和面粉,可以做多种馅料和面皮的包子。
- 优化后的代码:
def calculate_sector_area(central_angle, radius): pi = 3.14 area = (central_angle / 360) * pi * (radius ** 2) print(f"此扇形面积为: {area}")
calculate_sector_area(160, 30)calculate_sector_area(60, 15)- 计算扇形面积,只需调用
calculate_sector_area(角度, 半径),无需再定义新函数。 - 参数:定义函数时,设置的占位符。
- 实际参数:调用函数时,传递给函数的值。
函数的创建与调用 (续)添加参数,提高通用性
Section titled “函数的创建与调用 (续)添加参数,提高通用性”- 通过参数,使函数变得更加通用。
- 类似于做包子的机器,机器接受肉馅和面粉,可以做多种馅料和面皮的包子。
- 优化后的代码:
def calculate_sector_area(central_angle, radius): pi = 3.14 area = (central_angle / 360) * pi * (radius ** 2) print(f"此扇形面积为: {area}")
calculate_sector_area(160, 30)calculate_sector_area(60, 15)- 计算扇形面积,只需调用
calculate_sector_area(角度, 半径),无需再定义新函数。 - 参数:定义函数时,设置的占位符。
- 实际参数:调用函数时,传递给函数的值。
函数的创建与调用 (续)返回值,方便后续使用
Section titled “函数的创建与调用 (续)返回值,方便后续使用”- 返回值:函数执行完毕后,返回给调用者的结果。
- 例:机器做好包子,需要将包子拿出,给顾客。
- 使用
return关键字指定返回值。 - 示例:
def calculate_sector_area(central_angle, radius): pi = 3.14 area = (central_angle / 360) * pi * (radius ** 2) return area # 返回计算结果
sector_area_1 = calculate_sector_area(160, 30) # 调用函数,并将返回值赋值给变量print(f"此扇形面积为: {sector_area_1}") # 打印变量的值- 优化后,计算结果存储在变量
sector_area_1中,方便后续使用。 - 新版程序中,
sector_area_1、sector_area_2、sector_area_3都被赋值成了第一、二、三个扇形的面积。 - 后续可随时使用这些计算结果。
函数的创建与调用 (续)函数内部变量,外部无法使用
Section titled “函数的创建与调用 (续)函数内部变量,外部无法使用”- 函数内部定义的变量(如
pi、area),在函数外部无法访问。 - 作用域:变量的有效范围。
- 尝试在函数外部访问函数内部变量,会导致
NameError错误。 - 示例:
def calculate_sector_area(central_angle, radius): pi = 3.14 area = (central_angle / 360) * pi * (radius ** 2) return area
sector_area_1 = calculate_sector_area(160, 30)print(pi) # 尝试访问函数内部变量,会报错- 这种情况下,Python 解释器会提示
NameError: name 'pi' is not defined,表示变量pi未定义。
函数的创建与调用 (续)利用返回值,解决作用域问题
Section titled “函数的创建与调用 (续)利用返回值,解决作用域问题”- 如果需要在函数外部使用函数内部的变量,可以通过
return语句将变量作为返回值返回。 - 示例:
def calculate_sector_area(central_angle, radius): pi = 3.14 area = (central_angle / 360) * pi * (radius ** 2) return area, pi # 返回计算结果和 pi
sector_area_1, pi_value = calculate_sector_area(160, 30) # 调用函数,并将返回值赋值给变量print(f"扇形面积为: {sector_area_1}")print(pi_value)函数的创建与调用 (续)作用域概念讲解
Section titled “函数的创建与调用 (续)作用域概念讲解”- 作用域:变量的有效范围。
- 函数内定义的变量是局部变量,只能在函数内部访问。
- 函数外部无法访问函数内部的变量,会报错:
NameError。 - 如果要在函数外部使用函数内部变量,需通过
return返回。
函数的创建与调用 (续)使用返回值
Section titled “函数的创建与调用 (续)使用返回值”return语句:函数执行后返回结果给调用者。- 函数内部变量无法在外部直接访问,通过
return解决。 - 示例:
def func(): a = 3 print(a) # 函数内打印 return a # 返回 a 的值
return_value = func() # 调用函数,返回值赋给变量print(return_value) # 打印返回值- 函数执行顺序:先执行函数内部代码,遇到
return语句停止,将值返回。 - 返回值可用于变量赋值或直接打印。
函数的创建与调用 (续)无return语句的情况
Section titled “函数的创建与调用 (续)无return语句的情况”- 函数若没有
return语句,默认返回None,即空值。 - 例:
print、append等实际都返回None。 - 有返回值的函数,通常会将调用结果赋值给其他变量。
- 没有返回值的函数,通常直接调用,不进行变量赋值。
函数的创建与调用 (续)但并没有返回给我们扇形的面积
Section titled “函数的创建与调用 (续)但并没有返回给我们扇形的面积”- 若函数只打印结果,但未返回值,则无法在后续使用该结果。
calculate_sector_area函数只打印扇形面积,但没有返回该面积。
定义函数计算BMI值
Section titled “定义函数计算BMI值”- 函数名:
calculate_BMI - 参数:
height(身高),weight(体重) - 公式:
BMI = weight / (height ** 2) - 函数内打印BMI分类:偏瘦、正常、偏胖、肥胖
- 返回计算出的BMI值
定义函数计算BMI值 (续)计算公式和BMI分类讨论
Section titled “定义函数计算BMI值 (续)计算公式和BMI分类讨论”- 代码实现:
def calculate_BMI(weight, height): BMI = weight / (height ** 2) if BMI <= 18.5: category = "偏瘦" elif 18.5 < BMI <= 25: category = "正常"- 简化写法:
18.5 < BMI <= 25
定义函数计算BMI值 (续)计算公式和BMI分类讨论(续)
Section titled “定义函数计算BMI值 (续)计算公式和BMI分类讨论(续)”- 代码实现(续):
elif 25 < BMI <= 30: category = "偏胖" else: category = "肥胖"定义函数计算BMI值 (续)计算公式和BMI分类讨论(续)二
Section titled “定义函数计算BMI值 (续)计算公式和BMI分类讨论(续)二”- 代码实现(续):
elif 25 < BMI <= 30: category = "偏胖" else: category = "肥胖"- Python里,数学表达式可以这样写:
18.5 < user_BMI <= 25 - 如果
user_BMI大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。 - 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用
else输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
- 可以尝试用嵌套条件增强计算器功能。
定义函数计算BMI值 (续)代码实现(续)三
Section titled “定义函数计算BMI值 (续)代码实现(续)三”return BMI:返回计算出的BMI值。- 函数可以打印
BMI分类,也可以返回值,方便后续使用。 - 调用函数:
- 示例:
calculate_BMI(70, 1.8) - 输出:
您的BMI分类为:偏瘦
定义函数计算BMI值 (续)打印返回值
Section titled “定义函数计算BMI值 (续)打印返回值”result = calculate_BMI(70, 1.8)print(result):可打印函数calculate_BMI的返回值,即BMI值
避免重复造轮子
Section titled “避免重复造轮子”- 程序员常说:不要重复造轮子
- 已证实好用的东西,直接用即可
- 直接用别人写好的代码是高效行为
- 例如:对列表数字求和,使用内置函数
sum()
Python标准库的模块
Section titled “Python标准库的模块”- 模块即Python程序
- 引入模块后,里面的函数和变量都可被使用
- 如果对列表数字求和,可使用内置函数
sum(),无需自定义 - 可在Python官方文档里,查看所有内置函数
- 包含
print、len等 - 但内置函数数量有限,很多情况不能解决问题
- 比如没有可以帮助找中位数的函数
- 若要计算一串数字的中位数,可自行编写函数,或引入Python模块里的函数。
- 例如,Python有一个模块叫
statistics,用于进行统计相关计算。 statistics模块里有一个叫做median的函数,用于计算中位数。//:除完后向下取整。- 引入
statistics模块:import statistics - 使用
statistics模块里的median函数:statistics.median()
Python模块引入方法:import语句和from...import语句
Section titled “Python模块引入方法:import语句和from...import语句”median不是内置函数,需引入后使用- 常用家具(如电视)可直接摆放,不常用家具(如烧烤炉)平时放仓库,用时搬出
- 引入模块的三种方式:
import语句:
import 模块名- 使用模块函数或变量:
模块名.函数名或模块名.变量名 - 示例:
import statistics print(statistics.median([19, -5, 36])) print(statistics.mean([19, -5, 36]))from...import语句:
from 模块名 import 函数名- 直接使用函数名,无需模块名
引入模块的不同方式:import 语句 与 from...import 语句 与 from...import * 语句
Section titled “引入模块的不同方式:import 语句 与 from...import 语句 与 from...import * 语句”import语句:import 模块名- 使用模块中的函数:
模块名.函数名() from...import语句:from 模块名 import 函数名1, 函数名2, ...- 使用模块中的函数:
函数名(),无需模块名 from...import *语句:from 模块名 import *- 引入模块中所有内容,使用函数时无需模块名, 不推荐使用, 因为会引入很多不必要的函数或变量
模块引入方法进阶讨论:命名冲突与解决方案
Section titled “模块引入方法进阶讨论:命名冲突与解决方案”from 模块名 import *:若模块A和B都有名为abc的函数,使用from A import *和from B import *可能导致命名冲突。- 调用
abc()时,可能不清楚调用的是哪个模块的函数。 - 解决方案:使用
import 模块名,通过模块名.函数名()调用,明确指定模块。 - 也可以选择性地只引入模块B里的
abc函数 - Python官方文档:
- 链接:https://docs.python.org/zh-cn/3/library/functions.html
- 可查看Python标准库所有内置模块,包括处理字符串、日期时间、文件、正则、数学等。
Python标准库的模块 (续)查看第三方库源码
Section titled “Python标准库的模块 (续)查看第三方库源码”- 点击模块可查看包含的函数和变量介绍
- 如果好奇引入的函数具体怎么写的,可查看别人写的源代码
- Windows系统:按住
Control键点击函数名 - macOS系统:按住
Command键点击函数名 - 有时Python标准库里的模块不够用,可引入第三方库的模块
- 不是Python官方提供的,而是其他程序员提供的
- 数量更庞大和多样
- 引入第三方模块的语法和前面的一样,但不同的是在引入之前需要安装
Python第三方库的安装和使用
Section titled “Python第三方库的安装和使用”- 第三方库:不是Python官方提供,而是其他程序员提供
- 数量庞大、多样
- 安装:从互联网下载安装
- 类似于将家具从宜家拖到自家仓库
- 使用:
pip install安装,再用import语句引入 - 类似于把家具从自家仓库拿出使用
- 搜索第三方库:https://pypi.org/
- 示例:财经数据接口库
akshare - 可查看介绍和用法
- 安装:在终端输入
pip install akshare
面向对象编程 (OOP)
Section titled “面向对象编程 (OOP)”- 难度不一定比找一个对象低(幽默一下)。
- 本视频的目的是在脑中植入面向对象编程的概念,形成初步理解,不涉及讲解
class的具体语法,仅用Python做简单示范。
面向过程编程 vs. 面向对象编程
Section titled “面向过程编程 vs. 面向对象编程”- 在接触面向对象编程之前,我们基本都是在进行面向过程编程。
- 面向过程编程:
- 负责完成某个具体任务的代码。
- 基本可以理解为函数。
- 核心:把要实现的事情拆分成一个个步骤,依次完成。
- 示例:编写一个ATM程序
- 比如要存入50块和取出100块。
- 就按顺序写出这些步骤,并配合定义存钱和取钱的函数。
面向对象编程 vs. 面向过程编程 (续)ATM程序示例
Section titled “面向对象编程 vs. 面向过程编程 (续)ATM程序示例”- 面向过程编程:
- 记录ATM编号、银行、纸币编号等
- 补充参数,例如
存钱(面值, ATM编号, 银行, 纸币编号) - 缺点:若记录更多性质(如所属支行、发行年份等),函数参数会增加,数据混杂
- 面向对象编程:以对象为核心
面向对象编程 vs. 面向过程编程 (续)ATM程序示例
Section titled “面向对象编程 vs. 面向过程编程 (续)ATM程序示例”- 面向对象编程:以对象为核心
- 不聚焦于存钱、取钱等步骤,而是ATM本身
- ATM有编号、银行、支行等性质
- ATM可以存钱、取钱,可以被查询余额、转账等方法
- 优点:方便管理和维护
ATM类和ATM对象
Section titled “ATM类和ATM对象”类是创建对象的模板,对象是类的实例类:制造具体对象的图纸ATM类有编号、银行、支行属性ATM实例:招商银行南园支行编号001的ATM
ATM类和ATM对象 (续) ATM类和纸币类都有编号
Section titled “ATM类和ATM对象 (续) ATM类和纸币类都有编号”- ATM对象:
- 1``
- 000``
- 用对象把相关属性绑定在一起
- 有利于程序逻辑更清晰
- ``
- 面向对象编程的核心思想:将属性和方法绑定到对象上。
- 属性 (Attribute):对象拥有的性质或数据。
- 例如:ATM的颜色、大小、体积、编号;纸币的编号、面值、发行年份。
- 方法 (Method):对象能做的事情或行为。
- 例如:移动、放大、变色、打印。
- 优势:
- 相比面向过程编程,无需传递大量分散的参数(如
def 存钱(面值, ATM编号, 银行, 纸币编号, 支行, 发行年份))。 - 有了对象后,可以直接通过对象来获取与其绑定的属性,使逻辑和数据的后续流动更清晰。
面向对象编程 vs. 面向过程编程 (续)洗衣机程序示例
Section titled “面向对象编程 vs. 面向过程编程 (续)洗衣机程序示例”- 面向过程编程:类似洗衣机说明书,一步步指导
- 面向对象编程:
- 人、洗衣机是执行事务的对象
- 人能放东西、开机
- 洗衣机能清洗、烘干
- 这些可作为类的方法
- 方法:放在类里面的函数
- 属性:放在类里面的变量
- 通过类创建对象,让对象执行方法
面向过程编程 vs. 面向对象编程 (续)洗衣机程序示例二
Section titled “面向过程编程 vs. 面向对象编程 (续)洗衣机程序示例二”- 面向对象编程:
- 将事务分解到对象身上,描述对象的作用,再进行对象间的交互
- 对象不仅包含属性和方法,还能更优雅地处理复杂逻辑
- 知乎答案:面向过程是编年体,面向对象是纪传体
- 如果洗衣机的方法需要用到
容量这个信息: 容量可作为属性,在对象被创建时设置- 需要用到容量的方法可直接获取,无需作为参数传入
面向对象编程的特性:封装
Section titled “面向对象编程的特性:封装”- 在逻辑或信息复杂时,面向对象编程可使逻辑更清晰,信息更集中。
- 三个反复提及的特性:封装、继承、多态。
- 封装:将内部实现细节隐藏起来,只通过外部接口访问和使用。
- 接口可理解为提供使用的方法。
- 使用者只需知道有什么方法,方法有什么作用,具体怎么用就足够了。
- 不需要知道方法里面具体是怎么写的。
面向对象编程的特性:封装 (续)洗衣机程序示例三
Section titled “面向对象编程的特性:封装 (续)洗衣机程序示例三”- 使用者角度:操作洗衣机面板按钮。
- 无需了解内部电路和机械结构。
- 继承:面向对象编程允许创建有层次的类,类似于现实中的继承关系(儿子继承爸爸,爸爸继承爷爷)。
- 允许创建有层次的类,类似现实继承关系。
- 例如:小学生、大学生都是学生,有学号、年级属性,都要去学校。
- 可创建“学生”父类,减少重复代码。
- 允许不同类的对象对同一消息做出不同的响应。
- 例如:鸟类都有“飞”的方法,但不同鸟类的飞行方式不同。
- 面向对象编程:核心概念是对象,对象有属性和方法。
- 封装:隐藏内部细节,只暴露接口。
- 继承:创建层次结构的类,实现代码重用。
- 多态:不同对象对同一消息有不同响应。
- 小学生、大学生继承
学生类。 - 好处:父类属性、方法可被继承,减少代码冗余。
- 定义:相同接口,因对象具体类的不同而有不同表现。
- 例子:小学生、大学生都要写作业,但内容难度不同。
- “写作业”方法不能直接定义在父类,而要分别定义在子类里。
- 家长给大学生、小学生布置作业时,不用管具体写的是高难度还是低难度作业,都可调用“写作业”方法。
- 面向对象编程的多态性:无需判断,统一调用同名称方法。
- 不用类:需用
if判断类型,手动调用写作业函数。
面向过程编程 vs. 面向对象编程
Section titled “面向过程编程 vs. 面向对象编程”- 选用哪个取决于具体场景和需求。
- C是纯面向过程语言,Java是纯面向对象语言,无需纠结。
创建类和对象:深入面向对象编程
Section titled “创建类和对象:深入面向对象编程”类是模板,对象是类的实例。- 类定义对象的属性和方法。
- 对象拥有具体属性,可以不同。
- 创建类的语法:
class 类名:- 类名后跟要定义的代码。
创建类和对象:深入面向对象编程 (续)
Section titled “创建类和对象:深入面向对象编程 (续)”- 创建类的语法:
class 类名:- 类名后跟要定义的代码。
- 类名命名:使用Pascal命名风格
- 特点:首字母大写分隔单词
- 适用于类名,与变量的下划线命名法不同
- 类名后跟冒号
:,表示下方是定义类的代码 - 示例:
class CuteCat: - 思考:这个类的对象都拥有什么属性?
- 名字、年龄、花色等
- 构造函数:定义实例对象属性的特殊方法
- t__``,前后各有两个下划线
创建类和对象:深入面向对象编程 (续)构造函数
Section titled “创建类和对象:深入面向对象编程 (续)构造函数”__init__:前后双下划线,构造函数,定义实例对象属性的特殊方法
- 括号里可放任意数量参数,但第一个参数约定俗成叫
self,用于表示对象自身 self能绑定属性值到实例对象上- 例:猫猫的名字属性为
Lambton,写作`self.name =
创建类和对象:深入面向对象编程 (续)构造函数 (续)一
Section titled “创建类和对象:深入面向对象编程 (续)构造函数 (续)一”name = "Lambton":这样,在创建对象时name属性自动赋值为"Lambton"\- 调用
CuteCat()创建对象时,__init__方法会被调用 - 对象的
name属性被赋值为Lambton,一个名字为Lambton的猫猫对象就被创建完成了
创建类和对象:深入面向对象编程 (续)访问对象属性
Section titled “创建类和对象:深入面向对象编程 (续)访问对象属性”- 获取对象属性:
对象.属性名 - 例:
cat1.name,返回该对象所绑定的name属性值"Lambton" - 并非所有猫猫名字都叫
Lambton
创建类和对象:深入面向对象编程 (续)构造函数 (续)二
Section titled “创建类和对象:深入面向对象编程 (续)构造函数 (续)二”- 例:猫猫的名字属性为
Lambton,写作self.name = cat_name - 赋值后,使用
cat1 = CuteCat("Jojo")创建对象时,需在括号里传入猫猫的名字 - 此时,
__init__方法会被执行,name属性被绑定为传入的参数值 - 获得对象名字:
cat1.name(传入的参数值) - 可为猫猫添加更多属性:年龄、花色等
- 创建对象时传入对应参数即可
- 对象属性值会被绑定为传入的参数值
掌握属性定义和对象创建
Section titled “掌握属性定义和对象创建”- 已掌握定义属性和创建对象
面向对象编程进阶:对象方法
Section titled “面向对象编程进阶:对象方法”- 进一步理解面向对象编程
- 类定义对象属性外,还可定义方法,即对象能做什么
- 示例:
- 猫猫除了名字、年龄、花色属性,还有“喵喵叫”方法
- 狗有“汪汪叫”方法
- 方法:定义在类内部的函数
- 格式:
def 方法名(self, 参数): - 示例:
def say(self): self:表示对象自身- 函数体缩进
- 方法名任意,通常表达方法功能
- 示例:猫猫类添加
say方法
class CuteCat: def __init__(self, cat_name, cat_age, cat_color): self.name = cat_name self.age = cat_age self.color = cat_color
def say(self): print("喵喵喵")
cat1 = CuteCat("Jojo", 2, "橙色")cat1.say()cat1.say():调用对象方法,无需任何参数- 调用方法,对象执行特定行为
- 强调:调用方法无需额外参数,
self代表对象自身 - 对象方法能访问对象属性(如
name、age等) - 对象方法可利用对象属性,做更多有意思的事情
- 修改
say方法,打印猫猫名字:
class CuteCat: def __init__(self, cat_name, cat_age, cat_color): self.name = cat_name self.age = cat_age self.color = cat_color
def say(self): print(f"我是{self.name},喵喵喵")
cat1 = CuteCat("Jojo", 2, "橙色")cat1.say()- 定义类:
class 类名: - 定义属性:构造函数
__init__(self, ...) - 定义方法:
def 方法名(self, ...): - 创建对象:
对象名 = 类名(参数) - 调用属性:
对象.属性名 - 调用方法:
对象.方法名() - 掌握面向对象编程,可编写更复杂程序
定义对象拥有的方法
Section titled “定义对象拥有的方法”- 方法:表示对象能做什么事情
- 示例:猫猫对象可以思考、叫唤
- 定义方法类似创建普通函数,有两个区别:
- 要写在
class里面,前面要有缩进,表示属于该类的方法 一样,第一个参数被占用,用于表示对象自身,约定俗成为self`self的作用:让我们在方法里面,去获取或修改和对象绑定的属性
对象方法调用结果
Section titled “对象方法调用结果”- 方法调用结果根据属性的不同而改变
- 要调用类方法:
对象.方法名() - 括号里面放上参数进行调用
- 和构造方法一样,不需要手动把
self传入 - 方法自然也可以接受更多参数
- 思考的内容可以作为参数传入
- 例如,小猫可以思考
def think(self, content): print(f"小猫{self.name}在思考{content}...")
cat1 = CuteCat("Jojo", 1, "橙色")cat1.think("现在去抓沙发还是去撕纸箱")Python 定义学生类 (实例演示)
Section titled “Python 定义学生类 (实例演示)”- 目标:定义一个
学生类,包含姓名、学号、语数英成绩等属性,并能设置和打印成绩。 - 步骤:
- 创建类:
class Student: - 定义
__init__方法(构造函数):注意是两个下划线
Python 定义学生类 (续)参数设置
Section titled “Python 定义学生类 (续)参数设置”class Student: def __init__(self, name, student_id): self.name = name self.student_id = student_id- 构造函数
__init__的参数:self、name(姓名)、student_id(学号) self.name = name:self绑定属性值到实例对象上self.student_id = student_id- 语数英三科成绩:定义一个字典
self.grades = {}
Python 定义学生类 (续)参数设置
Section titled “Python 定义学生类 (续)参数设置”class Student: def __init__(self, name, student_id): self.name = name self.student_id = student_id- 构造函数
__init__的参数:self、name(姓名)、student_id(学号) self.name = name:self绑定属性值到实例对象上self.student_id = student_id- 语数英三科成绩:定义一个字典
self.grades = {}
Python 定义学生类 (续)创建实例和访问属性
Section titled “Python 定义学生类 (续)创建实例和访问属性”- 创建
Student类的实例: chen = Student("小陈", "100618")zeng = Student("小曾", "100622")- 访问实例的属性:
print(chen.name)会输出 “小陈”。print(zeng.grades)会输出{'语文': 0, '数学': 0, '英语': 0}。- 可以通过
对象名.属性名的方式获取各个属性值。 - 接下来需要定义一个设置成绩的方法,用于修改初始值为0的各科成绩。
Python 定义学生类 (续)设置成绩方法
Section titled “Python 定义学生类 (续)设置成绩方法”- 使用
def关键字,定义set_grade方法: def set_grade(self, course, grade):self:表示对象自身course:要修改的科目名称grade:要设置的成绩- 判断科目是否存在:
if course in self.grades: self.grades:学生对象的成绩字典course in self.grades:判断科目是否在成绩字典中- 如果科目存在,则修改成绩:
self.grades[course] = grade
Python 定义学生类 (续)设置成绩方法 (续)二
Section titled “Python 定义学生类 (续)设置成绩方法 (续)二”- 如果科目存在,则更新传入的参数
grade:self.grades[course] = grade - 现在,
set_grade方法已经完成 - 测试:把小曾的数学成绩改成95
zeng.set_grade("数学", 95)- 再次打印小曾的所有成绩,数学所对应的成绩就不再是0了
Python 定义学生类 (续)打印所有科目成绩方法
Section titled “Python 定义学生类 (续)打印所有科目成绩方法”- 定义打印该学生所有科目成绩的方法
- 还是使用
def关键字: def print_grades(self):
Python 定义学生类 (续)打印所有科目成绩方法
Section titled “Python 定义学生类 (续)打印所有科目成绩方法”- 使用
def关键字: def print_grades(self):self:表示对象自身- 打印学生相关信息:`print(f
Python 定义学生类 (续)打印所有科目成绩方法 (续)二
Section titled “Python 定义学生类 (续)打印所有科目成绩方法 (续)二”- 循环遍历
self.grades这个字典:for course in self.grades: course:对应科目,如语文、数学、英语- 打印学生姓名、学号、科目、成绩:
self.grades[course]:从字典中取值- 打印格式:f字符串
Python 定义学生类 (续)完整程序
Section titled “Python 定义学生类 (续)完整程序”- 完整程序示例:
class Student: def __init__(self, name, student_id): self.name = name self.student_id = student_id self.grades = {"语文": 0, "数学": 0, "英语": 0}
def set_grade(self, course, grade): if course in self.grades: self.grades[course] = grade
def print_grades(self): print(f"学生{self.name}(学号:{self.student_id})的成绩为:") for course in self.grades: print(f"{course}:{self.grades[course]}分")
chen = Student("小陈", "100618")zeng = Student("小曾", "100622")
chen.set_grade("语文", 80)chen.set_grade("数学", 90)chen.set_grade("英语", 100)zeng.set_grade("数学", 95)
chen.print_grades()zeng.print_grades()- 创建学生对象,设置成绩,打印成绩
Python 定义学生类 (续)程序运行结果
Section titled “Python 定义学生类 (续)程序运行结果”- 运行结果:
学生小陈(学号:100618)的成绩为:语文:80分数学:90分英语:100分学生小曾(学号:100622)的成绩为:语文:0分数学:95分英语:0分- 成功实现了设置和打印学生成绩的功能
chen.set_grade("语文", 92): 设置小陈的语文成绩为92分。chen.set_grade("数学", 94): 设置小陈的数学成绩为94分。chen.print_grades(): 打印小陈的所有成绩。- 运行结果显示:
- 小陈的语文成绩为92分。
- 小陈的数学成绩为94分。
- 英语成绩仍为0分(未设置)。
面向对象的抽象类
Section titled “面向对象的抽象类”- 人类和小猫抽象成类:
- 人类:
- 属性:名字、性别、两只眼睛、没有尾巴
- 方法:呼吸、拉屎、阅读
- 小猫:
- 属性:名字、性别、两只眼睛、有尾巴
- 方法:呼吸、拉屎、抓沙发
- DRY原则:不要重复自己。
- 可以创建有层次的类,类似现实继承关系
- 例如:儿子继承爸爸,爸爸继承爷爷
- 类也可以有子类和父类,来表示从属关系
- 子类会继承父类的属性和方法
- 例如:老龙和小龙都有两根须,老鼠和老老鼠都会打洞
- 老龙和小龙都有两根须
- 老老鼠和小老鼠都会打洞
继承代码示例
Section titled “继承代码示例”- 人类和猫都是哺乳类动物
- 他们都有两只眼睛,都会呼吸和拉屎
- 可以创建一个叫做
Mammal的哺乳类动物的类 - 把这些共享的属性和方法全部都挪进去
面向对象的抽象类 (续) 继承的应用
Section titled “面向对象的抽象类 (续) 继承的应用”- DRY原则的应用:对于人类和小猫都有的共同属性和方法,可以抽象出一个父类(也叫基类),让它们来继承。
- 例如,创建一个
Mammal(哺乳动物)类作为父类:
class Mammal: def __init__(self, name, sex): self.name = name self.sex = sex self.num_eyes = 2 # 哺乳动物通常有两只眼睛
def breathe(self): print(f"{self.name} 在呼吸...")
def poop(self): print(f"{self.name} 在拉屎...")Mammal类定义了所有哺乳动物共有的属性(如name、sex、num_eyes)和方法(如breathe、poop)。
继承的具体实现
Section titled “继承的具体实现”- 子类(也叫派生类)通过在类名后的括号中写上父类名来继承父类。
- 语法:
class 子类名(父类名): - 例如,
Human(人类)和Cat(猫)可以继承Mammal类:
class Human(Mammal): def read(self): print(f"{self.name} 在阅读...")
class Cat(Mammal): def scratch_sofa(self): print(f"{self.name} 在抓沙发...")- 此时,
Human和Cat类虽然没有直接定义__init__构造函数和breathe、poop方法,但它们都自动继承了Mammal类的这些属性和方法。
方法重写(Method Overriding)
Section titled “方法重写(Method Overriding)”- 当子类没有自己的构造函数时,创建子类实例会调用父类的构造函数,使其具备父类的属性。
- 示例:创建一个
Cat实例cat1 = Cat("Jojo", "男"),它会调用Mammal的__init__方法,从而拥有name、sex、num_eyes等属性。 - 当子类实例调用一个方法时:
- 优先查找所属子类是否有该方法。
- 如果没有,则向上查找父类是否有同名方法并调用。
- 示例:如果
Cat类没有自己的poop方法,cat1.poop()会调用Mammal类的poop方法。 - 方法重写:如果子类有与父类同名的方法,则会调用子类自己的方法,而不是父类的方法。
- 示例:如果
Cat类定义了poop方法:
class Cat(Mammal): def scratch_sofa(self): print(f"{self.name} 在抓沙发...")
def poop(self): print(f"{self.name} 在猫砂盆里拉屎...")- 此时,
cat1.poop()就会调用Cat类自己的poop方法,输出Jojo 在猫砂盆里拉屎...。 - 这种机制保证了子类可以根据自身特点,对继承自父类的方法进行定制化实现。
继承 (续) __init__ 方法的继承问题
Section titled “继承 (续) __init__ 方法的继承问题”- 问题:人类和小猫各自的
has_tail属性值不同,不能直接在父类Mammal中定义。 - 如果子类(如
Human或Cat)定义了自己的__init__方法,它会覆盖父类的__init__方法。 - 导致父类中定义的公共属性(如
name、sex、num_eyes)不会被子类实例继承。 - 解决方案:在子类的
__init__方法中,使用super().__init__(name, sex)来调用父类的构造函数。 super()方法会返回当前类的父类。- 调用
super().__init__(name, sex)确保父类的__init__被执行,从而子类实例也能拥有父类定义的公共属性。 - 这样就避免了重复代码,并实现了属性的正确继承。
何时使用继承?
Section titled “何时使用继承?”- 判断原则:如果能说“A是B”,那么A就可以是B的子类。
- 例如:“人类是动物” →
class Human(Animal): - 例如:“新能源车是车” →
class ElectricCar(Car):
实践:人力资源系统
Section titled “实践:人力资源系统”- 目标:为公司编写人力资源系统。
- 员工分类:
- 全职员工 (
FulltimeEmployee) - 兼职员工 (
ParttimeEmployee) - 共同属性(全职和兼职员工都有):
name(姓名)id(工号)- 共同方法:
print_info(打印姓名和工号信息)- 全职员工特有属性:
monthly_salary(月薪)- 兼职员工特有属性:
daily_salary(日薪)work_days(每月工作天数)- 计算月薪方法 (
calculate_monthly_pay):全职和兼职员工都有,但计算逻辑不同。
人力资源系统(续)之定义父类和构造函数
Section titled “人力资源系统(续)之定义父类和构造函数”- 定义
Employee父类: - 属性:
name(姓名)、id(工号) - 构造函数:
def __init__(self, name, id): self.name = nameself.id = id- 将
name和id属性放入构造函数。
人力资源系统(续)之打印信息和全职员工类定义
Section titled “人力资源系统(续)之打印信息和全职员工类定义”- 定义
print_info方法:打印姓名和工号 - 代码:
print(f"员工姓名:{self.name},工号:{self.id}") - 定义
FulltimeEmployee(全职员工)类,继承Employee类: - 代码:
class FulltimeEmployee(Employee): - 构造函数:姓名和工号已在父类定义,此处添加月薪属性
- 代码:
def __init__(self, name, id, monthly_salary): super().__init__(name, id) self.monthly_salary = monthly_salary- 使用
super()调用父类构造函数,初始化name和id
人力资源系统(续)之兼职员工类定义和月薪计算
Section titled “人力资源系统(续)之兼职员工类定义和月薪计算”- 定义
ParttimeEmployee(兼职员工)类,继承Employee类: - 代码:
class ParttimeEmployee(Employee): - 构造函数:姓名和工号已在父类定义,此处添加日薪和每月工作天数属性
- 代码:
def __init__(self, name, id, daily_salary, work_days): super().__init__(name, id) self.daily_salary = daily_salary self.work_days = work_days- 使用
super()调用父类构造函数,初始化name和id - 定义
calculate_monthly_pay方法:计算月薪 - 代码:
def calculate_monthly_pay(self): - 返回日薪乘以工作天数:
return self.daily_salary * self.work_days
人力资源系统(续)之方法重写
Section titled “人力资源系统(续)之方法重写”- 子类可重写父类方法,实现特定功能
calculate_monthly_pay方法:全职员工直接返回月薪,兼职员工计算月薪- 全职员工计算方式:
return self.monthly_salary - 兼职员工计算方式:
return self.daily_salary * self.work_days
人力资源系统(续)之代码实现
Section titled “人力资源系统(续)之代码实现”- 完整示例代码:
class Employee: def __init__(self, name, id): self.name = name self.id = id
def print_info(self): print(f"员工姓名:{self.name},工号:{self.id}")
class FulltimeEmployee(Employee): def __init__(self, name, id, monthly_salary): super().__init__(name, id) self.monthly_salary = monthly_salary
def calculate_monthly_pay(self): return self.monthly_salary
class ParttimeEmployee(Employee): def __init__(self, name, id, daily_salary, work_days): super().__init__(name, id) self.daily_salary = daily_salary self.work_days = work_days
def calculate_monthly_pay(self): return self.daily_salary * self.work_days人力资源系统(续)之创建对象和调用方法
Section titled “人力资源系统(续)之创建对象和调用方法”- 创建
FulltimeEmployee对象和ParttimeEmployee对象: - 代码:
fulltime_employee = FulltimeEmployee("小明", "1001", 8000)parttime_employee = ParttimeEmployee("小红", "2001", 200, 15)- 调用
print_info方法: - 代码:
fulltime_employee.print_info()parttime_employee.print_info()- 调用
calculate_monthly_pay方法并打印月薪: - 代码:
print(f"全职员工月薪:{fulltime_employee.calculate_monthly_pay()}")print(f"兼职员工月薪:{parttime_employee.calculate_monthly_pay()}")人力资源系统(续)之运行结果
Section titled “人力资源系统(续)之运行结果”- 运行结果:
员工姓名:小明,工号:1001员工姓名:小红,工号:2001全职员工月薪:8000兼职员工月薪:30000- 成功实现了员工信息的存储和月薪计算
总结:面向对象编程的实践
Section titled “总结:面向对象编程的实践”- 继承:减少代码重复,提高代码复用性
- 封装:隐藏实现细节,提供简单接口
- 多态:不同对象对同一方法有不同实现
- 三大特性使代码更易维护和扩展
- 兼职员工:
daily_salary(日薪)和work_days(每月工作天数)属性 - 代码:
def __init__(self, name, id, daily_salary, work_days): super().__init__(name, id) self.daily_salary = daily_salary self.work_days = work_days- 用
super()调用父类构造函数,初始化name和id - 计算月薪
calculate_monthly_pay:日薪乘以工作天数
实例化对象及调用方法示例 (续)二:
Section titled “实例化对象及调用方法示例 (续)二:”- 创建
FulltimeEmployee对象zhangsan,参数:姓名、工号、月薪。zhangsan = FulltimeEmployee("张三", "1001", 6000) - 创建
ParttimeEmployee对象lisi,参数:姓名、工号、日薪、每月工作天数。lisi = ParttimeEmployee("李四", "1002", 230, 15) - 调用
print_info方法打印员工信息:zhangsan.print_info()和lisi.print_info(),调用的是继承自父类的print_info方法
打印员工月薪:调用不同子类的 calculate_monthly_pay 方法
Section titled “打印员工月薪:调用不同子类的 calculate_monthly_pay 方法”- 打印
zhangsan月薪:print(zhangsan.calculate_monthly_pay()) - 打印
lisi月薪:print(lisi.calculate_monthly_pay()) - 多态:调用同一方法,不同对象产生不同结果
- 多态优点:代码更简洁,无需判断对象类型
- 在编程中,对文件的读写操作非常常见。
- 各种文件类型(如
DOC、JPG、MP3、PPT、MP4、TXT、PDF等)本质上都属于文件。 - 文件会归属于某个目录(文件夹)下面。
- 如果想修改某个文本文件,会直接去存放该文件的目录,然后打开它。
文件路径:代码如何找到文件
Section titled “文件路径:代码如何找到文件”- 当要用代码操作文件时,需要知道文件在哪里。
- 计算机操作系统有不同的目录结构来组织文件。
Unix 类操作系统 (Linux, macOS)
Section titled “Unix 类操作系统 (Linux, macOS)”- 目录结构像一棵树,只有一个根目录 (
/)。 - 所有文件和目录都存放在根目录下。
- 根目录通常用斜杠 (
/) 表示。
Windows 操作系统
Section titled “Windows 操作系统”- 每个磁盘分区(如
C:\、D:\、`E:`)都有自己的根目录。 - 根目录用分区名加反斜杠 (``) 表示,例如 `C:`。
定位文件位置的两种方法
Section titled “定位文件位置的两种方法”- 绝对路径:从根目录出发的完整路径。
- 相对路径:从当前工作目录出发的路径。
路径表示方法:绝对路径 vs 相对路径
Section titled “路径表示方法:绝对路径 vs 相对路径”- 绝对路径:从根目录出发的路径。
- Linux、macOS:以
/开头,目录间用/分隔。 - Windows:以
盘符名加反斜杠开头,目录间用反斜杠分隔。 - 相对路径:从参考位置出发,描述其他文件相对于该位置的路径。
.:表示当前目录。..:表示上一级目录。
文件路径表示方法:绝对路径 vs 相对路径 (续)
Section titled “文件路径表示方法:绝对路径 vs 相对路径 (续)”- 上级目录:用
..表示。 - 例:
../tmp/images/profile/1.jpg:表示当前文件所属目录的父目录的tmp/images/profile/1.jpg。 - 相对路径:以
.或..开头。 - 点斜杠:`.`可以省略。
- 同一目录文件:直接使用文件名。
- 编辑器复制路径:PyCharm等编辑器可复制文件路径。
文件操作的必要性
Section titled “文件操作的必要性”- 如果需要程序来计算销售数据:
- 方法一:将数据从文件一条条复制到代码里,然后执行代码获得结果
- 缺点:如果有很多不同日期的市场数据,就要反复修改程序里的变量
- 学习文件操作后:
- 可以让同一段代码读取不同的市场数据文件,只需对文件名字进行修改
Python文件操作:打开文件
Section titled “Python文件操作:打开文件”- 使用
open()函数打开文件 open(文件路径, 模式)- 文件路径:可以是相对路径或绝对路径
- 模式:字符串,指定文件打开模式
"r":读取模式(只读),默认模式"w":写入模式(只写)- 找不到文件:
FileNotFoundError,提示文件不存在 - 可选参数
encoding="utf-8" open()函数可选参数:encoding="utf-8",表示编码方式。现在文件一般编码方式是UTF-8- 传入
encoding="utf-8",会用此编码读取文件 - 如果想了解更多编码,可看相关科普视频
open()函数执行成功,会返回一个文件对象- 可对文件对象进行读取或写入操作
- 文件对象有
read()方法,调用后会一次性读取文件里面所有内容,并以字符串形式进行返回 - 代码操作的文件格式都会是简单直接的,以文本格式为例
- 代码喜欢
txt这种纯文本
文件操作 (续) read() 方法的特性
Section titled “文件操作 (续) read() 方法的特性”- Python 喜欢纯文本文件,如
.txt,因为它只包含字符,没有额外格式(字体、颜色等)。 read()方法会读取整个文件内容,并将其转换为字符串。- 注意:
- 首次调用
f.read()会读取文件全部内容。 - 再次调用
f.read()会返回空字符串。 - 原因:程序会记录文件读取位置,第一次
read()后,读取位置已在文件末尾,后续调用无内容可读。 - 处理大文件:
- 对于特别大的文件(如 15GB),不建议使用
f.read()一次性读取全部内容。 - 这会占用大量内存,可能导致内存溢出。
- 分块读取:
- 如果不想一次性读完整个文件,可以给
read()传递一个数字参数,表示要读取的字节数。 - 示例:
f.read(10)会读取文件的前 10 个字节。 - 下一次调用
f.read()会从上次读取结束的位置继续往下读。
readline() 方法:逐行读取文件
Section titled “readline() 方法:逐行读取文件”f = open("./data.txt", "r", encoding="utf-8"):打开文件,指定读取模式和编码。print(f.readline()):读取一行内容并打印。- 每次调用读取下一行。
- 换行符也会被当作内容的一部分。
- 文件读取到结尾:
readline()返回空字符串""。 - 使用
while循环逐行读取:
line = f.readline() # 读第一行 while line != "": # 判断当前行是否为空 print(line) # 不为空则打印当前行 line = f.readline() # 读取下一行- 循环判断返回值是否为空字符串,否则退出循环。
readlines() 方法
Section titled “readlines() 方法”- 读取全部文件内容,并把每行作为列表元素返回。
- 通常与
for循环结合使用。 - 先调用
readlines把所有行读出来,然后一行一行循环列表里面的所有内容。
| 方法 | 描述 |
|---|---|
| read | 返回全部文件内容的字符串 |
| readline | 返回一行文件内容的字符串 |
| readlines | 返回全部文件内容组成的列表 |
文件操作:关闭文件
Section titled “文件操作:关闭文件”- 文件对象有一个
close()方法,与open()函数作用相反,调用后会释放系统资源。 - 每次完成文件读写操作后,都应关闭文件:
f.close()。
文件操作 (续) with 语句自动关闭文件
Section titled “文件操作 (续) with 语句自动关闭文件”- 另一种更简洁、安全的处理文件方式是使用
with关键字。 - 语法:
with open(文件路径, 模式) as 文件对象名:
# 对文件对象的操作with后面跟open()函数的调用,然后是as关键字,再跟着文件对象的命名(如f)。- 在
with缩进的代码块里,可以对文件进行操作。 - 优点:当缩进的代码内容执行完毕后,文件就会被自动关闭,无需手动调用
f.close()。 - 这种写法能让代码更加简洁,且避免了忘记关闭文件可能导致的资源泄露问题。
文件操作实践:创建待读取文件
Section titled “文件操作实践:创建待读取文件”- 既然要练习读文件,首先需要创建一个用来读取的文件。
- 代码适合读取纯文本文件,不包含额外格式(如字体、颜色等)。
- 创建纯文本文件的方法:
- 可以使用 Windows 自带的记事本或 macOS 自带的文本编辑。
- 更简单的方法:直接在 PyCharm 等代码编辑器里面创建。
- 在项目文件目录中,右键。
- 选择 新建。
- 选择 文件。
创建待读取文件(续)
Section titled “创建待读取文件(续)”- 新建文件,输入文件名:
data.txt - 后缀可用
.txt,表示纯文本。 - 复制内容到
data.txt。 - 注意:文件所在位置决定了读文件时需输入的路径。
- 当前文件创建在项目文件夹下。
- 回到Python程序。
- 读文件前先打开文件,用
open()函数。 open()是Python自带的,无需import。- 第一个参数是文件路径。
- 为简洁,可使用相对路径。
- 相对路径:相对于当前正在编辑的代码文件而言。
相对路径表示
Section titled “相对路径表示”- 文件和代码文件处于同一文件夹下,相对路径简单。
.:表示当前文件夹。- 分隔符:Unix系统(斜杠
/),Windows系统(反斜杠 ``)。 - 相对路径:
"./data.txt"
open() 函数参数
Section titled “open() 函数参数”open(文件路径, 模式, encoding='utf-8')- 文件路径:相对或绝对路径。
- 模式:
"r"(读取,默认),"w"(写入)。 encoding:编码方式,一般为"utf-8"。- 模式
"r"可省略,open()函数默认读取模式。 - 执行成功,返回文件对象。
Python文件操作:打开文件 (续) encoding 参数
Section titled “Python文件操作:打开文件 (续) encoding 参数”open()函数默认encoding随系统而异,建议显式指定encoding="utf-8"。open()函数成功时会返回一个文件对象。- 示例:
f = open("./data.txt", "r", encoding="utf-8")。
Python文件操作:读取文件
Section titled “Python文件操作:读取文件”f.read()&;方法:- 读取文件所有内容,并以字符串形式返回。
- 首次调用会读取全部内容,再次调用会返回空字符串(因为文件指针已到末尾)。
- 不建议用于超大文件,可能导致内存溢出。
- 可传入数字参数,表示读取的字节数(分块读取)。
- 存储与打印:
content = f.read():将文件内容存储到变量content。print(content):打印读取到的内容。
Python文件操作:关闭文件 (续) 释放资源
Section titled “Python文件操作:关闭文件 (续) 释放资源”- 使用
f.close()方法关闭文件,释放系统资源。 - 这是一个重要步骤,防止资源泄露。
f.close()容易忘记,可用with语句代替。自动关闭文件,更简洁安全with open(文件路径, 模式) as 文件对象名:- 缩进代码块中操作文件
readline()方法:逐行读取文件- 每次调用读取下一行
- 文件读取到结尾,返回空字符串
"" readlines()方法:读取全部文件内容,并把每行作为列表元素返回- 文件操作方法:
| 方法 | 描述 |
| ——— | ––––––––––– |
| read | 返回全部文件内容的字符串 |
| readline | 返回一行文件内容的字符串 |
| readlines | 返回全部文件内容组成的列表 |
- 创建文本文件:在 PyCharm 等代码编辑器中创建
*.txt文件。 with语句中,对文件对象的所有操作都必须缩进。- 如果没有缩进,该行代码将不在
with语句块内执行。 - 当
with语句块执行完毕(即取消缩进)时,文件对象会被自动关闭。 - 此时若尝试对已关闭的文件对象进行操作,会产生
ValueError: I/O operation on closed file错误。 - 使用
readline()读取文件内容时,有时会出现额外的空行。 - 原因:
readline()方法会把每行内容及其末尾的换行符 (\n) 都读取出来。 - 同时,
print()函数自身也会在打印内容后默认添加一个换行符。 - 这两个换行符结合起来,就会导致输出中出现多余的空行。
readlines() 方法结合 for 循环
Section titled “readlines() 方法结合 for 循环”- 读取全部文件内容,并把每行作为列表元素返回。
- 通常与
for循环结合使用。 - 先调用
readlines把所有行读出来,然后一行一行循环列表里面的所有内容。 - 示例代码:
with open("./data.txt", "r", encoding="utf-8") as f: lines = f.readlines() for line in lines: print(line)- 结果:也是把文件的所有内容都打印了出来
| 方法 | 描述 |
|---|---|
| read | 返回全部文件内容的字符串 |
| readline | 返回一行文件内容的字符串 |
| readlines | 返回全部文件内容组成的列表 |
- 程序输出结果保存到文件,避免重复运行程序
- 便于结果共享
- 写文件与读文件类似
文件写入 (续) with open() as f:
Section titled “文件写入 (续) with open() as f:”- 类似读取文件,使用
with open() as f: - 模式:
"w"(写入模式) - 示例:
with open("./data.txt", "w", encoding="utf-8") as f: f.write("要写入的内容")- 若文件不存在,程序会自动创建
- 再次运行,原内容会被覆盖
文件写入 (续) "w" 模式特性
Section titled “文件写入 (续) "w" 模式特性”"w"模式:写入时会覆盖原有内容- 写入多行内容:换行符
\n f.write("我是第一行\n我是第二行"),将两行内容写入文件
文件写入 (续) "a"模式:追加写入
Section titled “文件写入 (续) "a"模式:追加写入”- 写入模式:
"w":覆盖写入"a":追加写入- `
"a"模式:追加写入,在文件末尾添加内容f.write("我是第一行\n我是第二行"):追加到文件末尾write&;不会自动换行,需手动添加\n
文件写入 (续) "a"模式:追加写入
Section titled “文件写入 (续) "a"模式:追加写入”- 若只想在文件末尾追加内容,不能使用
"w"模式,而应该使用"a"(附加模式)。 "a"模式的特点:- 不会清空原有内容,而是在文件末尾添加新内容。
- 如果文件不存在,
"a"模式会像"w"模式一样直接创建一个新文件。
文件读写模式限制
Section titled “文件读写模式限制”- 重要提示:无论是
"w"(写入)模式还是"a"(追加)模式,都无法读取文件中的原有内容。 - 尝试在
"w"或"a"模式下对文件对象调用f.read()会报错,提示UnsupportedOperation(不支持的操作)。 - 如果既需要读取文件内容,又需要写入内容,则不能在同一个
open()操作中完成。通常需要:
- 先用
"r"模式打开文件读取内容。 - 再用
"w"或"a"模式打开文件进行写入操作。
文件读写进阶
Section titled “文件读写进阶”- 使用
"r+"模式,可同时支持读写文件 f.write()会以追加的形式在文件后添加新的内容
文件操作实践:任务演示
Section titled “文件操作实践:任务演示”- 任务1:在
poem.txt文件中,写入三句诗词 - 使用
"w"模式,将内容写入全新文件。 - 代码编辑器会自动创建
poem.txt - 使用
with open() - 文件路径:
"./poem.txt"(相对路径) - 模式:
"w"(写入) - 编码:
encoding="utf-8" - 文件对象:
as f
文件写入 (续) 多行内容写入方法优化
Section titled “文件写入 (续) 多行内容写入方法优化”- 使用
\n换行,保证格式正确:
with open("./poem.txt", "w", encoding="utf-8") as f: f.write("我欲乘风归去,\n") f.write("又恐琼楼玉宇,\n") f.write("高处不胜寒。\n")- 优化:所有内容拼接成一个字符串,一次写入:
with open("./poem.txt", "w", encoding="utf-8") as f: f.write("我欲乘风归去,\n又恐琼楼玉宇,\n高处不胜寒。\n")文件写入 (续) "a"模式:追加写入 (续)任务二和代码演示
Section titled “文件写入 (续) "a"模式:追加写入 (续)任务二和代码演示”- 任务二:在上一步的
poem.txt文件结尾追加两句诗词 - 使用
"a"模式,避免覆盖原有内容 - 代码示例:
with open("./poem.txt", "a", encoding="utf-8") as f: f.write("起舞弄清影,\n") f.write("何似在人间。\n")- 注意:需要在第一句词的末尾也加上换行符,否则两句诗词会连在一起
- 运行代码,文件内容被成功追加
异常处理:try...except语句
Section titled “异常处理:try...except语句”- 目标:在程序崩溃前预测并捕获异常。
- 结构:
try:
# 可能引发异常的代码块except 异常类型1:
# 针对异常类型1的处理代码except 异常类型2:
# 针对异常类型2的处理代码...- 如果
try代码块中发生异常,程序会停止执行try块,跳转到匹配的except块。 - 如果没有匹配的
except块,异常会向上传播,可能导致程序崩溃。 - 如果
try代码块没有发生异常,则不会执行except块。 except后面可指定异常类型,如ValueError、FileNotFoundError等。- 示例:文件不存在时,不希望程序崩溃,而是输出提示信息。
try...except捕获文件不存在异常
Section titled “try...except捕获文件不存在异常”- 文件不存在会导致
FileNotFoundError。 - 代码:
try: with open("./成绩.txt", "r") as f: lines = f.readlines() for line in lines:
# 计算平均成绩except FileNotFoundError: print("文件不存在,请检查文件名或路径")- 运行:如果文件不存在,会打印提示信息,程序不会崩溃。
- 尝试
print(lines),会报错,因为lines变量仅在try代码块中定义。 try代码块外的代码不会被执行。except代码块会在try代码块发生异常后,执行。
异常处理:try...except语句 (续) 常见异常类型示例
Section titled “异常处理:try...except语句 (续) 常见异常类型示例”- 列表索引超出范围:产生
IndexError(索引错误)。 - 数字除以零:产生
ZeroDivisionError(除零错误)。 - 打开不存在的文件:产生
FileNotFoundError(找不到文件错误)。 - 字符串做乘法:产生
TypeError(类型错误)。
异常处理:try...except语句 (续) 实践演示:捕获 ValueError 错误
Section titled “异常处理:try...except语句 (续) 实践演示:捕获 ValueError 错误”- 用户输入非数字时,
float()会抛出ValueError(值错误)。 except ValueError::捕获ValueError,执行对应代码块。- 代码示例:
try: user_weight = float(input("请输入您的体重(单位: kg):")) user_height = float(input("请输入您的身高(单位: m):")) user_BMI = user_weight / (user_height ** 2) print(f"您的BMI是{user_BMI:.2f}")except ValueError: print("输入有误,请输入数字")- 用户输入非法字符,程序会提示 “输入有误,请输入数字”,不会崩溃。
- 代码健壮性提升:程序更稳定,用户体验更好。
异常处理:try...except语句 (续) else 代码块
Section titled “异常处理:try...except语句 (续) else 代码块”try...except结构添加else代码块:
try:
# 代码except 异常类型:
# 异常处理代码else:
# 没有异常时执行的代码- 示例:
try: user_weight = float(input("请输入您的体重(单位: kg):")) user_height = float(input("请输入您的身高(单位: m):"))except ValueError: print("输入有误,请输入数字")else: user_BMI = user_weight / (user_height ** 2) print(f"您的BMI是{user_BMI:.2f}")- 用户输入正确,计算 BMI 并打印;输入错误,提示信息。
异常处理:try...except语句 (续) finally 代码块
Section titled “异常处理:try...except语句 (续) finally 代码块”finally代码块:无论是否发生异常,都会执行的代码。- 示例:关闭文件、释放资源。
- 结构:
try:
# 代码except 异常类型:
# 异常处理代码finally:
# 必须执行的代码- 示例代码:
f = Nonetry: f = open("file.txt", "r")
# 读取文件内容except FileNotFoundError: print("文件不存在")finally: if f: f.close()异常处理:try...except语句 (续) try...except...else...finally 完整结构
Section titled “异常处理:try...except语句 (续) try...except...else...finally 完整结构”try...except...else...finally:完整异常处理结构。- 结构:
try:
# 代码except 异常类型:
# 异常处理代码else:
# 没有异常时执行的代码finally:
# 必须执行的代码- 示例:
f = Nonetry: f = open("file.txt", "r") print("文件打开成功")except FileNotFoundError: print("文件不存在")else: print("没有发生异常")finally: if f: f.close() print("文件已关闭")- 完整结构:保证程序健壮性,处理各种情况。
- 异常也是类:可自定义特定异常类,更好地组织代码。
class 自定义异常名(Exception)::继承Exception类。- 示例:
class MyError(Exception): def __init__(self, message): self.message = message- 抛出异常:
raise MyError("错误信息")。 raise:关键字,用于抛出异常。- 捕获自定义异常:
try:
# 代码except MyError as e: print(e.message)- 示例:
class UnderAgeError(Exception): def __init__(self, message): self.message = message
age = 17
try: if age < 18: raise UnderAgeError("未成年禁止入内")except UnderAgeError as e: print(e.message)- 抛出
UnderAgeError,并捕获打印错误信息。
- 模块化:程序分解成更小、更易管理、独立的模块。
- 模块分类:
- 标准库模块:Python 自带,无需安装,直接
import。 - 第三方模块:需要安装,例如
akshare。 - 自定义模块:自己编写的
.py文件。 - 模块化编程:代码组织方式,提高可维护性、可重用性。
- 模块:可独立运行的代码单元。
- 模块化优点:提高代码质量和可读性。
模块 (续) 模块化编程
Section titled “模块 (续) 模块化编程”- 模块化编程:一个完整的程序,由多个独立的模块组成。
- 模块:包含变量、函数、类等,完成特定功能。
- 模块化优点:
- 可维护性:修改一个模块,不影响其他模块。
- 可重用性:一个模块可在多个程序中使用。
- 可读性:代码结构更清晰,易于理解。
- 模块化:大型项目必备,提高开发效率。
模块 (续) 模块的创建
Section titled “模块 (续) 模块的创建”- 模块:本质上是 Python 文件,以
.py结尾。 - 模块名:文件名。
- 示例:创建
my_module.py文件,定义函数和变量。
def greet(name): print(f"Hello, {name}!")
version = "1.0"greet():函数,用于打印问候语。version:变量,表示模块版本。- 创建模块简单:定义函数和变量,保存为
.py文件。
模块 (续) 模块的导入
Section titled “模块 (续) 模块的导入”- 导入模块:
import 模块名。 - 导入后,使用模块中的函数和变量:
模块名.函数名或模块名.变量名。 - 示例:
import my_module
my_module.greet("Alice")print(my_module.version)import my_module:导入my_module.py文件。my_module.greet("Alice"):调用my_module模块中的greet函数。print(my_module.version):访问my_module模块中的version变量。- 模块导入后,即可使用其中定义的函数和变量。
模块 (续) from...import 语句导入模块
Section titled “模块 (续) from...import 语句导入模块”- 从模块中导入指定函数或变量:
from 模块名 import 函数名, 变量名。 - 导入后,直接使用函数名或变量名,无需模块名。
- 示例:
from my_module import greet, version
greet("Bob")print(version)from my_module import greet, version:从my_module模块中导入greet函数和version变量。greet("Bob"):直接调用greet函数。print(version):直接访问version变量。- 简化代码,更方便。
模块 (续) from...import * 语句导入模块
Section titled “模块 (续) from...import * 语句导入模块”- 从模块中导入所有内容:
from 模块名 import *。 - 导入后,直接使用所有函数和变量,无需模块名。
- 不推荐使用:可能导致命名冲突,代码可读性降低。
- 示例:
from my_module import *
greet("Charlie")print(version)- 避免使用
from...import *,维护代码清晰性。
模块 (续) 模块的搜索路径
Section titled “模块 (续) 模块的搜索路径”- 导入模块时,Python 会在指定路径中搜索模块文件。
- 搜索路径:
- 当前目录。
PYTHONPATH环境变量指定的目录。- Python 安装目录下的
site-packages目录。
- 如果模块不在搜索路径中,会报错
ModuleNotFoundError。 - 解决:
- 将模块文件放在当前目录。
- 将模块文件放在
site-packages目录。 - 设置
PYTHONPATH环境变量。
模块 (续) PYTHONPATH 环境变量的设置
Section titled “模块 (续) PYTHONPATH 环境变量的设置”PYTHONPATH:告诉 Python 解释器在哪里寻找模块。- 设置方法:
- Windows:
- 控制面板 -> 系统与安全 -> 系统 -> 高级系统设置 -> 环境变量。
- 新建系统变量,变量名
PYTHONPATH,变量值设置为模块所在目录。
- macOS/Linux:
- 编辑
~/.bash_profile或~/.zshrc文件。 - 添加
export PYTHONPATH=/path/to/your/module:$PYTHONPATH。 - 执行
source ~/.bash_profile或source ~/.zshrc使配置生效。
- 确保 Python 解释器能找到自定义模块。
模块 (续) 模块的命名空间
Section titled “模块 (续) 模块的命名空间”- 模块创建独立的命名空间:避免不同模块间的命名冲突。
- 示例:
def hello(): print("Hello from module1")
# module2.pydef hello(): print("Hello from module2")
# main.pyimport module1import module2
module1.hello()module2.hello()module1.hello()和module2.hello()调用的是不同模块中的hello函数,互不影响。- 命名空间:隔离不同模块,避免命名冲突。
模块 (续) 模块的 __name__ 属性
Section titled “模块 (续) 模块的 __name__ 属性”- 每个模块都有一个
__name__属性,用于表示模块的名称。 - 模块被直接执行时,
__name__的值为"__main__"。 - 模块被导入时,
__name__的值为模块的名称。 - 应用:
def main(): print("This is the main function")
if __name__ == "__main__": main()if __name__ == "__main__"::判断当前模块是否被直接执行。- 直接执行
my_module.py时,main()函数会被调用。 - 被导入时,
main()函数不会被调用。 __name__属性:控制模块的行为,实现代码复用。
模块 (续) __name__ 属性应用
Section titled “模块 (续) __name__ 属性应用”__name__属性:判断模块是否被直接执行,实现代码复用。- 示例:
def hello(): print("Hello!")
if __name__ == "__main__": hello() print("Module is being run directly")else: print("Module is being imported")- 直接运行
my_module.py:
Hello!Module is being run directly- 在其他文件中导入
my_module:
import my_moduleModule is being imported__name__属性:区分模块的运行方式,方便调试和测试。
包 (Package) 简介
Section titled “包 (Package) 简介”- 包:组织模块的方式,将多个相关的模块放在一个目录下。
- 解决模块数量增多带来的管理问题。
- 包:包含一个
__init__.py文件的目录,用于标识该目录为一个包。 - 示例:创建
my_package包,包含module1.py和module2.py。
my_package/ __init__.py module1.py module2.py__init__.py:可以为空,也可以包含包的初始化代码。- 包:层次化的模块组织方式,提高代码组织性和可维护性。
包 (Package) 的导入
Section titled “包 (Package) 的导入”- 导入包的模块:
import 包名.模块名。from 包名 import 模块名。
- 示例:
import my_package.module1from my_package import module2
my_package.module1.hello()module2.hello()import my_package.module1:导入my_package包中的module1模块。from my_package import module2:从my_package包中导入module2模块。- 包:模块的容器,方便代码组织和管理。
包 (Package) (续) __init__.py 文件的作用
Section titled “包 (Package) (续) __init__.py 文件的作用”__init__.py文件:标识目录为包,并可包含包的初始化代码。- 作用:
- 定义包级别的变量和函数。
- 在导入包时执行初始化操作。
- 使用
from 包名 import *语句时,控制哪些模块被导入。
- 示例:
__all__ = ["module1"]
from . import module1__all__ = ["module1"]:指定使用from my_package import *时,只导入module1模块。from . import module1:导入当前目录下的module1模块。__init__.py:灵活控制包的导入行为,提高代码可维护性。
包 (Package) (续) 相对导入
Section titled “包 (Package) (续) 相对导入”- 相对导入:在同一个包内的模块之间进行导入。
- 语法:
from . import 模块名:导入当前目录下的模块。from .. import 模块名:导入上级目录下的模块。- 示例:
from . import module2
def hello(): module2.world()
# my_package/module2.pydef world(): print("World!")from . import module2:在module1.py中导入同一个包中的module2.py。- 相对导入:简化包内部模块之间的依赖关系,提高代码可移植性。
绝对导入 vs 相对导入
Section titled “绝对导入 vs 相对导入”- 绝对导入:从项目根目录开始指定完整的模块路径。
- 相对导入:使用相对路径指定模块位置,
.表示当前目录,..表示上级目录。 - 示例:假设项目结构如下:
project/ package1/ module1.py package2/ module2.py- 在
module1.py中导入module2.py: - 绝对导入:
from project.package2 import module2 - 相对导入:
from ..package2 import module2 - 选择:
- 相对导入更简洁,适用于包内部模块间的引用。
- 绝对导入更清晰,适用于跨包引用。
- 避免混用,保持代码风格一致。
模块和包的总结
Section titled “模块和包的总结”- 模块:单个
.py文件,包含变量、函数和类。 - 包:包含
__init__.py文件的目录,用于组织多个模块。 - 作用:
- 代码组织:将代码划分为更小、更易管理的部分。
- 代码重用:在不同的项目中重复使用模块和包。
- 命名空间:避免不同模块之间的命名冲突。
- 模块和包:Python 代码组织的核心机制,提高代码质量和可维护性。
总结:Python 编程之旅
Section titled “总结:Python 编程之旅”- 基础语法:变量、数据类型、运算符、条件语句、循环语句。
- 数据结构:列表、元组、字典、集合。
- 函数:代码复用、模块化编程。
- 面向对象编程:类、对象、继承、多态、封装。
- 文件操作:读写文件、处理数据。
- 异常处理:提高代码健壮性。
- 模块和包:组织代码、实现代码重用。
- 不断实践、学习和探索,成为 Python 编程高手!
异常处理:try...except语句 (续) 捕获不同异常类型
Section titled “异常处理:try...except语句 (续) 捕获不同异常类型”ValueError:输入无法转换为数字。ZeroDivisionError:除数为零。- 代码:
try: user_weight = float(input("请输入您的体重(单位: kg):")) user_height = float(input("请输入您的身高(单位: m):")) user_BMI = user_weight / user_height ** 2except ValueError: print("输入不为合理数字,请重新运行程序,并输入正确的数字。")except ZeroDivisionError: print("身高不能为零,请重新运行程序,并输入正确的数字。")- 运行:程序可捕获不同类型异常,并给出提示。
异常处理:try...except语句 (续) 多个 except 块与通用 except
Section titled “异常处理:try...except语句 (续) 多个 except 块与通用 except”- 当有多个
except块时,程序会从上往下依次匹配错误类型。 - 一旦某个
except块捕获到对应错误,后续的&;except&;块将不再执行。 - 这与
if...elif...else的逻辑非常相似,只有第一个符合条件的分支会运行。 - 通用&;
except&;块:只写except:而不指定错误类型,可以捕获所有未被前面except块捕获的错误类型。 - 示例:
try:
# 可能产生错误的代码 user_weight = float(input("请输入您的体重(单位: kg):")) user_BMI = user_weight / user_height ** 2except ValueError: print("输入不为合理数字,请重新运行程序,并输入正确的数字。")except ZeroDivisionError: print("身高不能为零,请重新运行程序,并输入正确的数字。")except: # 捕获所有其他未知错误 print("发生了未知错误,请重新运行程序。")try/except语句的执行顺序是从上往下运行。
异常处理:try...except语句 (续) else 和 finally 语句块
Section titled “异常处理:try...except语句 (续) else 和 finally 语句块”- 除了
try和except,还可以搭配else和finally语句。 else语句块:在try块没有发生任何异常时执行。finally语句块:无论是否发生异常,都会执行。- 常用于资源清理,如关闭文件或数据库连接。
异常处理:try...except语句 (续) else 和 finally 代码块补充说明
Section titled “异常处理:try...except语句 (续) else 和 finally 代码块补充说明”else代码块:try中无异常才执行。finally代码块:无论有无异常,均执行,常用于资源清理。- 完整结构:
try...except...else...finally。 - 测试代码:确保代码无误,减少
bug。
计算机领域的Bug
Section titled “计算机领域的Bug”- 1947年:计算机科学家格蕾斯·赫柏发现机器故障原因是飞蛾进入继电器被电死
- 英语中虫子是
bug,因此计算机领域用bug表示程序错误 - 写出
bug很正常,关键在于如何快速发现和改正
- 让用户成为第一个发现
bug和体验bug的人 - 确保程序的行为和预期相同
- 验证新代码是否正确
- 验证改动老代码后,不该受影响的地方仍然按预期执行
assert 语句
Section titled “assert 语句”- 中文意思是断言
- 后面可以跟上任何布尔表达式(值为
True或False的表达式) - 测试时,在
assert后面跟上我们认为应该为True的表达式
assert 语句 (续)作用和问题 1
Section titled “assert 语句 (续)作用和问题 1”- 作用:跟随布尔表达式(
True或False) - 用于测试,若表达式为
True,无事发生,程序继续 - 若为
False,产生AssertionError(断言错误),提示“不符合预期” - 问题:产生
AssertionError后,程序会立即终止,后续代码不会执行 - 解决:使用专门测试的库
unittest 库简介
Section titled “unittest 库简介”- 对软件中最小可测试单元进行验证,如验证某函数表现是否符合预期。
- Python 自带,无需额外安装,但需
import unittest引入。 - 测试代码一般放到独立文件里,与实现代码分离。
代码组织示例
Section titled “代码组织示例”my_calculator.py:实现代码,包含加法函数my_adder。test_my_calculator.py:测试代码,引入unittest库。
unittest 库的使用 (续)需要引入测试文件
Section titled “unittest 库的使用 (续)需要引入测试文件”- 测试文件需引入要测试的函数或类
- 同一文件夹下的引入语法:
from 文件名 import 函数名或from 文件名 import 类名 - 创建测试类:以
Test开头,继承unittest.TestCase的子类 - 这样才能使用各种测试功能
- 可定义不同的测试用例,每个用例都是类下的一个方法
unittest 库的使用 (续) 测试方法编写
Section titled “unittest 库的使用 (续) 测试方法编写”- 测试方法命名必须以&;
test&;开头 unittest库自动搜索并只执行test开头的方法作为测试用例- 测试前先明确预期行为
- 如
my_adder(5, 3)应返回8 - 使用
TestCase的assertEqual方法替代assert - 通过
self.assertEqual(实际值, 预期值)验证 - 第一个参数实际结果,第二个参数预期结果,相等则通过
- 避免
AssertionError导致程序立即中断
import unittestfrom my_calculator import my_adder
class TestMyAdder(unittest.TestCase): def test_positive_with_positive(self): self.assertEqual(my_adder(5, 3), 8) def test_negative_with_positive(self):
# TODO passunittest 库的使用 (续) 运行测试
Section titled “unittest 库的使用 (续) 运行测试”- 运行命令:在终端输入
python -m unittest - 自动搜索所有继承
unittest.TestCase的子类 - 运行类中所有以
test开头的方法 - 测试结果显示:
- 告诉你运行了几个测试
- 每个通过的测试显示一个点(
.) - 失败的测试显示 F
- 详细报告失败信息
assertEqual&;行为:- 传入两个参数比较是否相等
- 相等:测试通过
- 不相等:显示测试不通过,但程序不会崩溃
# 示例测试代码 test_my_calculator.pyfrom my_calculator import my_adder
class TestMyAdder(unittest.TestCase): def test_positive_with_positive(self): self.assertEqual(my_adder(5, 3), 8)
def test_negative_with_positive(self): self.assertEqual(my_adder(-5, 3), -2)unittest 测试失败详情
Section titled “unittest 测试失败详情”- 测试负数加正数用例:
self.assertEqual(my_adder(-5, 3), -1) - 失败示例输出:
/Users/kevinlin/Desktop/Python_For_Beginners/test_my_calculator.py:10: in test_negative_with_positive self.assertEqual(my_adder(-5, 3), -1) E AssertionError: -2 != -1- 指出具体文件、方法和失败原因
- 测试总结:
Ran 2 tests in 0.008s
FAILED (failures=1)- 优势:自动运行所有测试用例,一次性展示结果和未通过详情
- 大大提高单元测试效率
- 提供一体化测试结果信息
- unittest 有进阶玩法,更高效测试和找出 bug(详见课后实践)
unittest 库的其他断言方法
Section titled “unittest 库的其他断言方法”- 除了**
assertEqual**,还有其他常用测试方法,对应特定布尔表达式 assertTrue(A):类似于assert A is TrueassertIn(A, B):类似于assert A in BassertNotIn(A, B):类似于assert A not in BassertFalse(A):类似于assert A is FalseassertNotEqual(A, B):类似于assert A != B
| 方法 | 类似于 |
|---|---|
| assertEqual(A, B) | assert A == B |
| assertTrue(A) | assert A is True |
| assertIn(A, B) | assert A in B |
| assertNotEqual(A, B) | assert A != B |
| assertFalse(A) | assert A is False |
| assertNotIn(A, B) | assert A not in B |
assertTrue可代替所有方法- 示例:
assertTrue(2 not in [1, 3 - 1])等价于assertNotIn(2, [1, 3 - 1]) - 都验证
2不存在于[1, 2]列表,结果相同 - 推荐:使用更具针对性的方法
unittest 进阶:assert not in 方法
Section titled “unittest 进阶:assert not in 方法”- 检查元素不在列表中:
assert not in - 专门针对元素和列表的方法
- 比
assert False更优:测试失败时给出更详细的失败原因
unittest 进阶:setUp 方法避免重复代码
Section titled “unittest 进阶:setUp 方法避免重复代码”- 测试类时,需要创建实例对象调用方法
- 不同测试用例独立:每个
test_方法前都要创建新对象 - 解决方案:利用
TestCase的setUp方法 - 在运行每个
test_方法前自动执行 - 创建对象等准备工作放在
setUp中,避免重复代码
unittest 测试类中的 setUp 方法
Section titled “unittest 测试类中的 setUp 方法”setUp方法在每个测试方法前会被运行一次- 用于初始化测试对象,作为当前测试的属性
- 各个测试方法通过self.属性获取已创建对象进行测试
实践:购物清单类
Section titled “实践:购物清单类”- 购物清单类包含以下方法:
- 构造函数:将传入的商品字典复制为商品列表属性
- 字典格式:
{'商品名': 价格} get_item_count():返回购物清单里有多少件商品get_total_price():返回购物清单商品总价
unittest 测试类示例
Section titled “unittest 测试类示例”- 测试文件名示例:
TestShortlist或test_shortlist.py(下划线开头,便于unittest) - import 示例:
import unittest和from shortlist import Shortlist(假设被测试类) - 继承
unittest.TestCase后,即可编写测试方法
unittest 测试购物清单类:get_item_count 方法
Section titled “unittest 测试购物清单类:get_item_count 方法”- 测试方法需以
test_&;开头,才能被unittest自动识别为测试用例 - 示例购物清单字典:
- 纸巾:8元
- 帽子:30元
- 拖鞋:15元
- 调用
get_item_count()返回购物清单中商品件数(预期为3)
unittest 测试类示例 (续) 测试购物清单方法
Section titled “unittest 测试类示例 (续) 测试购物清单方法”- 测试
get_item_count()方法:验证返回商品件数
import unittestfrom shopping_list import ShoppingList
class TestShoppingList(unittest.TestCase): def test_get_item_count(self): shopping_list = ShoppingList({'纸巾': 8, '帽子': 30, '拖鞋': 15}) self.assertEqual(shopping_list.get_item_count(), 3)- 测试
get_total_price()方法:验证返回总价 53
def test_get_total_price(self): shopping_list = ShoppingList({'纸巾': 8, '帽子': 30, '拖鞋': 15}) self.assertEqual(shopping_list.get_total_price(), 53)unittest setUp 方法:避免重复创建测试对象
Section titled “unittest setUp 方法:避免重复创建测试对象”- 测试方法重复创建
ShoppingList([{'纸巾': 8, '帽子': 30, '抱枕': 15}]) - 添加
def setUp(self):(名字必须精确),创建self.shopping_list属性 - 测试方法改为用
self.shopping_list.get_item_count()等 - 删掉本地
shopping_list = ...行 → 报错 “shopping_list 未定义” → 改用self.shopping_list
unittest 测试运行结果示例
Section titled “unittest 测试运行结果示例”- 测试通过:运行
python -m unittest,显示Ran 2 tests in 0.008s和两个点(.),表示两个测试用例都通过 - 测试失败:故意将预期值改错(如
53改为其他),运行命令后一个点变成F(failure),表示有一个测试未通过 - unittest 会详细指出具体哪个测试失败,提供失败详情
# 测试通过输出示例Ran 2 tests in 0.008sOK
# 测试失败输出示例Ran 2 tests in 0.008sFAILED (failures=1)unittest 测试失败详情与优势
Section titled “unittest 测试失败详情与优势”- 测试失败时输出详细诊断信息:
- 失败测试方法名:
FAIL: test_get_total_price (test_shopping_list.TestShoppingList) - 具体文件与行号:
/Users/Kevinlin/Desktop/Python_For_Beginners/test_shopping_list.py:12 - 失败断言:
self.assertEqual(self.shopping_list.get_total_price(), 55) - 原因:
AssertionError: 53 != 55(实际值53,预期55) - 测试总结:
Ran 2 tests in 0.000s(运行2个测试) - 单元测试核心价值:
- 确认程序行为与预期相同
- 代码修改后:验证未受影响部分仍按预期执行
- 支持直接跳转到失败行,提高调试效率
函数扩展:支持不同幂次计算
Section titled “函数扩展:支持不同幂次计算”简单版本:计算并打印平方
Section titled “简单版本:计算并打印平方”def calculate_and_print(num): result = num * num print(f"| 数字参数 | {num} |\n| 计算结果 | {result} |")
calculate_and_print(3)- 输出:
| 数字参数 | 3 || 计算结果 | 9 |扩展版本:传入幂次参数
Section titled “扩展版本:传入幂次参数”def calculate_and_print(num, power): if power == 2: result = num * num elif power == 3: result = num * num * num else: print("只支持计算平方和三次方") return print(f"| 数字参数 | {num} |\n| 计算结果 | {result} |")
calculate_and_print(3, 3)- 支持2(平方)、3(三次方),否则提示不支持并返回
- 问题:进一步扩展(如加10)会导致逻辑复杂丑陋
函数作为参数:优雅解决扩展问题
Section titled “函数作为参数:优雅解决扩展问题”- 问题根源:原
calculate_and_print(num, power)用if-elif判断幂次,扩展(如加10)会导致逻辑复杂丑陋 - 解决方案:将计算逻辑独立为小函数,作为参数传入
def calculate_square(num): return num * num
def calculate_cube(num): return num * num * num
def calculate_plus_10(num): return num + 10- 核心函数修改:接收函数参数,直接调用它计算结果并打印
- 传入函数做什么(平方/三次/加10)由调用时决定,核心函数不关心细节
# 调用示例def calculate_and_print(num, calc_func): result = calc_func(num) # 调用传入的函数 print(f""" 数字参数: {num} | 计算结果: {result}""")
calculate_and_print(3, calculate_square) # 输出平方结果calculate_and_print(7, calculate_plus_10) # 输出加10结果- 优势:扩展新计算只需新增函数,无需改动
calculate_and_print,符合开闭原则(对扩展开放,对修改关闭)
函数作为参数:高阶函数
Section titled “函数作为参数:高阶函数”- 高阶函数:把函数作为参数的函数
- 传入函数名(不带括号):表示函数本身
calculate_and_print(3, calculate_square)→ 传入calculate_square函数- 带括号:调用函数,传入执行结果
calculate_and_print(3, calculate_square())→ 传入9,不是函数
def calculate_square(num): return num * num
def calculate_plus_10(num): return num + 10
def calculate_times_5(num): return num * 5
def calculate_and_print(num, func): result = func(num) print(f"\n数字参数: {num} |") print(f"计算结果: {result} |")
calculate_and_print(3, calculate_square) # 平方calculate_and_print(7, calculate_plus_10) # 加10calculate_and_print(7, calculate_times_5) # 乘5- 优势:新增计算只需定义新函数传入,无需改
calculate_and_print,可无限扩展 - 符合开闭原则:对扩展开放,对修改关闭
函数作为参数:高阶函数 (续) 格式化函数参数化
Section titled “函数作为参数:高阶函数 (续) 格式化函数参数化”- 进一步扩展:甚至可以将格式化函数也作为高阶函数的参数传入
- 保持
calculate_and_print函数不变,同时扩展不同打印格式
def formatter(num, result): return f"\n数字参数: |{num}|\n计算结果: |{result}|"
def print_with_vertical_bar(num, result): return f"|{num}| |{result}|"
def calculate_and_print(num, func): result = func(num) print(formatter(num, result))
calculate_and_print(7, calculate_times_5)高阶函数类比:多功能美发棒
Section titled “高阶函数类比:多功能美发棒”- 现实例子:多功能美发棒的主机负责核心功能(产生气流、控制温度风速)
- 通过更换不同配件(卷发筒、吹风嘴)实现多样功能
- 一个主机达成多种目的
主机配件1 配件2 配件3 配件4
calculate_and_printcalculate_squarecalculate_cubecalculate_plus_10calculate_times_5- 类比:高阶函数如主机,作为参数的函数如配件
- 提供更多灵活性,无限扩展新功能
匿名函数(Lambda)
Section titled “匿名函数(Lambda)”- 若传递给高阶函数的函数不常用,且只想计算一次,此时用
Lambda表达式更合适。 Lambda函数无需命名,用完即扔,类似于一次性物品。- 定义:以关键字
lambda开始。 - 语法:
calculate_and_print(7, lambda num: num * 5, print_with_vertical_bar) lambda后跟变量名,然后是冒号。- 冒号前面变量名表示传递给匿名函数的参数。
- 冒号后面是函数要返回的结果,无需写
return。
Lambda 匿名函数
Section titled “Lambda 匿名函数”- 匿名函数:无需
return关键字,直接返回结果 - 适用于只需一次性调用的场景
- 可被定义后直接调用,调用方式与普通函数一样
- 匿名函数可以减少代码行数,不用起名字,不用换行缩进
- 增加参数:
lambda关键字后用逗号分隔
匿名函数(Lambda)的局限性
Section titled “匿名函数(Lambda)的局限性”- 匿名函数需被括号括住,表示整体
- 只能有一个语句或表达式
- 适用于简单场景
- 多步骤复杂逻辑、循环、递归等不适用
- 即使能写出来,可读性差
- 此时,老老实实定义普通函数更好
编程工具准备
Section titled “编程工具准备”- Python解释器和代码编辑器
- 用于在电脑上编写和运行Python
- Jupyter Notebook
- 基于网页的交互式计算环境
- 机器学习及数据科学常用
- 可编写、运行代码、查看输出、分享文档
- 代码编辑器
- PyCharm、VSCode等
- 项目开发常用
- 教学篇主要使用Jupyter Notebook
Jupyter Notebook 的优势
Section titled “Jupyter Notebook 的优势”- 可按单元格运行代码。
- 代码放在不同单元格里。
- 每次运行一格代码。
- 无需从头到尾运行,节省时间和费用。
- 更改AI模型提示时,避免重复运行。
Jupyter Notebook 的优势
Section titled “Jupyter Notebook 的优势”- 可按单元格运行代码,无需从头到尾运行,节省时间。
- 提供交互模式环境,无需
print语句查看输出。 - 支持展示更丰富的信息格式,例如使用
Markdown标记语言让注释更清晰有层级
Jupyter Notebook 安装与启动
Section titled “Jupyter Notebook 安装与启动”- Jupyter Notebook:
- 按单元格运行代码。
- 交互式运行环境。
- 可展示的信息格式更丰富。
- Windows 系统安装:
- 打开
cmd(命令提示符)。 - 输入
pip install notebook,回车开始安装。
- macOS 系统安装:
- 打开终端。
- 输入
pip install notebook或pip3 install notebook,回车开始安装。
- 启动 Jupyter Notebook:安装完成后,输入
jupyter notebook,查看是否安装成功。 - 成功启动:浏览器自动打开 Jupyter Notebook 窗口。
- 关闭 Jupyter Notebook:
- 需同时关闭浏览器窗口并终止后台服务器。
- 在启动 Jupyter Notebook 的 CMD 或终端窗口中:
- Windows:按
Ctrl + C,服务会直接终止,无需额外确认。 - macOS/Linux:按
Ctrl + C后,如询问是否确认关闭,输入y并回车即可。
温馨提示:Anaconda
Section titled “温馨提示:Anaconda”- 如果安装 Jupyter Notebook 遇到问题,可考虑安装 Anaconda。
- Anaconda 是一站式安装工具,专门针对计算科学(如数据科学、机器学习、大数据处理等)的库和环境管理工具。
- 可实现多个工具(包括 Jupyter Notebook)的安装。
Jupyter Notebook 安装与启动
Section titled “Jupyter Notebook 安装与启动”- 学习AI大模型API及应用开发框架时,主要使用
Jupyter Notebook进行代码演示。 - 启动步骤:
- Windows 系统:在菜单栏搜索
CMD,点击命令提示符,输入jupyter notebook。 - macOS 系统:点击顶部菜单栏放大镜,输入
terminal(终端),回车进入,输入jupyter notebook。
- 成功启动后,默认浏览器会自动打开一个网页,展示
Jupyter Notebook的主面板。 - 找回页面:如果不小心关闭了页面,可以在启动
Jupyter Notebook的CMD或终端窗口中找到地址。 - 其中一行会显示
Jupyter Server is running at后跟着访问地址。 - 关闭:在
CMD或终端窗口中,按Ctrl + C,然后根据提示输入y并回车确认即可关闭Jupyter Notebook服务。
Anaconda (温馨提示)
Section titled “Anaconda (温馨提示)”- 如果安装
Jupyter Notebook遇到问题,可以考虑安装Anaconda。 Anaconda是一站式安装工具,专门针对计算科学(如数据科学、机器学习、大数据处理等)的库和环境管理工具。- 可以方便地安装包括
Jupyter Notebook在内的多个工具。
Jupyter Notebook 的使用 (续)
Section titled “Jupyter Notebook 的使用 (续)”- 复制页面地址到浏览器即可。
- 启动命令的CMD或终端不要关闭,否则
Jupyter Notebook会被终止。 - 主面板展示当前目录下的文件和文件夹,可点击访问不同目录。
- 想要文件位于桌面,就点进桌面文件夹。
- 点击
New->Notebook创建新的编辑界面。 - 在桌面上也能看到一个全新的文件。
- 点击标题,输入想要的名字即可重命名。
- 标题的下面分别是菜单栏、工具条和单元格。
Jupyter Notebook 界面介绍
Section titled “Jupyter Notebook 界面介绍”- 菜单栏:常用操作
- 工具条:菜单栏常用操作快捷方式
- 单元格:用于编写
Python代码 - 点击单元格:底色变白色,进入编辑模式
- 编辑完成后:点击
Esc键或鼠标点击其他地方,底色变灰色,进入命令模式 - 工具条按钮功能:
- 保存文件
- 新建单元格
- 剪切单元格
- 复制单元格
- 粘贴单元格
- 可以按住
Shift键选择多个单元格,然后统一进行操作(如剪切、复制、粘贴)。 - 运行单元格:
- 点击工具条上的运行按钮,或使用快捷键
Shift + Enter。 - 运行中的单元格:左侧方括号会显示
[*],表示正在执行。 - 执行完成后:方括号内的
[*]会变成数字,表示该单元格的执行顺序。 - 执行顺序灵活性:
- Jupyter Notebook 允许你以任意顺序运行单元格。
- 你可以运行第三个单元格后,再回到第一个单元格再次执行。
- 也可以多次反复运行同一个单元格。
- 单元格左侧的数字会准确记录并告知代码的执行顺序,而非其在 Notebook 中的物理顺序。
Jupyter Notebook 使用技巧
Section titled “Jupyter Notebook 使用技巧”- 单元格运行顺序很重要。
- 修改变量值后,需重新运行单元格。
- 单元格代码通过交互模式运行,无需
print语句。 - 灵活拆分代码步骤,节省时间和调整。
Jupyter Notebook 使用技巧 (续)二
Section titled “Jupyter Notebook 使用技巧 (续)二”- 单元格有多条输出语句,只有最后一项会被展示,其他需要借助
print。 - 运行按钮旁边的按钮是中止执行按钮,用于停止单元格里代码的运行。
- 再右边的按钮是重启按钮,会清除所有定义过的变量。
- 例如,第一格定义变量,第二格输出变量,运行第一格后,变量的值被存储在内存中,运行第二格会输出对应的值。
- 但重启后,再运行第二格,会提示变量不存在了。
- 而且单元格旁边的数字也会从1开始,表明重启过。
Jupyter Notebook 使用技巧 (续)三
Section titled “Jupyter Notebook 使用技巧 (续)三”- 位于“重启并重新运行”按钮旁边的下拉框:切换单元格内容
- Code:代码
- Markdown:文字
- 单元格不限于代码,也可写文字
Jupyter Notebook 中的 Markdown
Section titled “Jupyter Notebook 中的 Markdown”Markdown是一种标记语言,用于给内容增加样式。- 语法非常简单。
- 标题:
- 在文字前加
#和一个空格,运行后文字会变大加粗,成为一级标题。 - 增加
#的数量可以改变标题级别,最多支持六级标题。 #数量越多,字体越小。- 示例:
# 我是最大的标题## 我是第二大的标题### 我是第三大的标题###### 我是最小的标题- 粗体和斜体:
- 粗体:用两个星号
**把文字包住,例如**我是粗体字**。 - 斜体:用一个星号
*把文字包住,例如*我是斜体字*。 - 分隔线:
- 在一行中输入三个或更多个短横线
---,运行后会生成一条水平分隔线。 - 引用:
- 在文字前加
>符号,运行后文字会变成引用样式(通常会缩进并显示一条竖线)。
Markdown 语法补充说明
Section titled “Markdown 语法补充说明”- 多打一次换行或在第一行后加两个空格:更紧凑的换行效果
- 非常常用的样式,分为两类:
- 无序列表
- 有序列表
- 无序列表:
- 在每个列表元素前加
短横杠+空格 - 短横杠是键盘上0右边的键
- 有序列表:
- 在每个列表元素前加
数字+英文句号+空格 - 都非常直观
Jupyter Notebook 界面元素操作
Section titled “Jupyter Notebook 界面元素操作”- 复制当前单元格
- 上移/下移当前单元格
Jupyter Notebook 使用进阶
Section titled “Jupyter Notebook 使用进阶”- 工具栏按钮:
- 上移单元格
- 下移单元格
- 在上方添加空单元格
- 在下方添加空单元格
- 删除当前单元格
- 快捷键(需在命令模式下使用):
A:在当前单元格上方插入新单元格B:在当前单元格下方插入新单元格- 连按两次
D:删除当前单元格 - 快捷键查看:
Help->Show Keyboard Shortcuts
Jupyter Notebook 的使用 (续) 删除单元格和运行单元格
Section titled “Jupyter Notebook 的使用 (续) 删除单元格和运行单元格”- 删除当前单元格:双击
D键 - 运行当前单元格:
Shift + Enter快捷键,效果与点击运行按钮相同 - 节省鼠标操作时间
Jupyter Notebook 重新打开步骤
Section titled “Jupyter Notebook 重新打开步骤”- 终止
Jupyter Notebook:在运行Jupyter Notebook的CMD或终端窗口里,按Ctrl + C,macOS或Linux系统还需按Y键确认。 - 刷新之前notebook页面,显示无法访问此网站
Jupyter Notebook 重启与他人创建的Notebook的打开方式
Section titled “Jupyter Notebook 重启与他人创建的Notebook的打开方式”- 关闭后,需在CMD或终端输入
jupyter notebook命令重启。 - 在主面板点击Notebook所在目录,再点击相应文件即可打开。
- 打开他人创建的Notebook流程类似,先运行
jupyter notebook,再进入Notebook所在目录点击文件。
Jupyter Notebook 界面元素
Section titled “Jupyter Notebook 界面元素”- 菜单栏:常用操作。
- 工具条:菜单栏常用操作的快捷方式。
- 单元格:编写Python代码,点击进入编辑模式,
Esc键进入命令模式。
Jupyter Notebook 快捷键操作
Section titled “Jupyter Notebook 快捷键操作”- 复制单元格、上移/下移单元格等。
- 更多快捷键:
Help->Show Keyboard Shortcuts查看。
代码控制AI交互的优势
Section titled “代码控制AI交互的优势”- 从网页上抓取AI回复比较麻烦
- 代码控制更灵活
- 可调整AI回复的长度、创造性、频率惩罚等参数
- 可使用提示模板提高效率
- 可精确控制请求参数,如限制AI回答的token数
- 可对大量数据进行批处理
- 例如,用AI一次性总结多个文档
- 可将AI集成到自己的系统或流程中
代码控制AI交互的优势 (续)API调用
Section titled “代码控制AI交互的优势 (续)API调用”- 通过API调用与大模型对话
- 无需本地配置高端硬件
- 不需模型运行所需的算力
- 模型在服务提供方的服务器上
- API(Application Programming Interface,应用程序编程接口)
- 定义两个软件程序之间的服务合约
- 双方如何使用请求和响应进行通讯
- 可以看成是如何与服务对话的说明书
- 大部分API基于HTTP协议
HTTP 请求简介
Section titled “HTTP 请求简介”- HTTP:
Hypertext Transfer Protocol(超文本传输协议)的缩写 - 客户端和服务器之间的请求-响应协议
- 过程:
- 客户端(运行代码的程序)将给AI的提示放到请求内容里
- 通过HTTP发送给AI服务提供方,如OpenAI、百度等服务器
- 服务器返回响应
- 客户端获取AI的回复以供后续使用
- HTTP请求包含多种信息,如:
- 资源路径
- 接受响应数据的类型
HTTP请求简介 (续) Python库封装
Section titled “HTTP请求简介 (续) Python库封装”- OpenAI、百度等公司为方便用户,在API基础上封装了相应的Python库。
- 无需从头构建HTTP请求,可直接使用Python库函数和方法。
使用官方Python库
Section titled “使用官方Python库”- 学习如何使用官方的Python库,如与AI对话时调用哪个方法,方法里哪个参数指定模型,消息内容放在什么数据结构里等。
- 这些都有相应文档可查询。
- 除了发送的请求,得到的响应也是API预先规定好的。
- 这样才能知道如何正确提取来自服务器的信息。
不同模型对应不同Python库
Section titled “不同模型对应不同Python库”- OpenAI的
GPT、百度的文心等,对应的Python库不同。
API密钥的重要性
Section titled “API密钥的重要性”- 调用AI大模型前,需获取 API密钥。
- 主流AI大模型都需要创建API密钥才能使用。
- API密钥:让服务提供方识别和验证客户端请求,确认请求来自哪个账号,追踪计费和使用频率等。
OpenAI API密钥创建
Section titled “OpenAI API密钥创建”- 使用代码调用AI模型,需先获取API密钥。
- 以OpenAI的GPT模型为例。
- 前往OpenAI官网的API keys页面。
- 显示账号下所有API密钥。
- 无账号需先注册。
- 点击“Create new secret key”按钮。
- 输入密钥名字(可选,用于区分)。
- 不输入名字,系统会分配默认名字。
OpenAI API密钥创建 (续) 密钥安全注意事项
Section titled “OpenAI API密钥创建 (续) 密钥安全注意事项”- 点击
Create secret key按钮后,系统会生成密钥。 - 务必复制并保存,点击
Done后无法再次查看完整密钥。 - 若忘记复制,可删除旧密钥并创建新的。
- 密钥安全:
- 严禁泄露,密钥与账户绑定。
- 泄露后,他人使用产生的费用由你承担。
- 怀疑泄露,立即删除。
OpenAI API密钥使用注意事项
Section titled “OpenAI API密钥使用注意事项”- 密钥与账户绑定,严禁泄露,否则他人使用费用由你承担
- 直接将密钥写在代码里有风险,任何看到代码的人会直接看到密钥明文
- 不小心上传到GitHub等公开代码仓库后,密钥也会暴露
- 更好方法:将密钥设置为电脑的环境变量
- 代码自动通过环境变量获取密钥的值
- 即使代码发给别人或上传到GitHub,密钥也不会暴露,安全性高很多
OpenAI API密钥使用注意事项 (续)
Section titled “OpenAI API密钥使用注意事项 (续)”- Windows系统设置环境变量步骤:
- 右键点击“此电脑”或“计算机”,选择“属性”。
- 点击“高级系统设置”。
- 选择“高级”标签,点击“环境变量”。
- 在“系统变量”下,点击“新建”。
- 变量名:
OPENAI_API_KEY(必须完全一致,不能有任何输入错误)。 - 变量值:粘贴复制的API密钥。
- 点击“确定”保存设置。
- macOS系统设置环境变量:
- 打开终端。
- 查看shell类型:输入
ps -p $$,查看输出结果是Bash还是Zsh。 - 编辑对应shell配置文件:
Bash:编辑~/.bash_profile文件。Zsh:编辑~/.zshrc文件。
- 添加环境变量:
export OPENAI_API_KEY="你的API密钥"。 - 保存文件,并执行
source ~/.bash_profile或source ~/.zshrc使配置生效。
OpenAI API密钥使用注意事项 (续)
Section titled “OpenAI API密钥使用注意事项 (续)”- 密钥与账户绑定,严禁泄露,否则他人使用费用由你承担
- 直接将密钥写在代码里有风险,任何看到代码的人会直接看到密钥明文
- 不小心上传到GitHub等公开代码仓库后,密钥也会暴露
- 更好方法:将密钥设置为电脑的环境变量
- 代码自动通过环境变量获取密钥的值
- 即使代码发给别人或上传到GitHub,密钥也不会暴露,安全性高很多
OpenAI API密钥使用注意事项 (续)
Section titled “OpenAI API密钥使用注意事项 (续)”- Windows系统设置环境变量步骤:
- 右键点击“此电脑”或“计算机”,选择“属性”。
- 点击“高级系统设置”。
- 选择“高级”标签,点击“环境变量”。
- 在“系统变量”下,点击“新建”。
- 变量名:
OPENAI_API_KEY(必须完全一致,不能有任何输入错误)。 - 变量值:粘贴复制的API密钥。
- 点击“确定”保存设置。
- macOS系统设置环境变量:
- 打开终端。
- 查看shell类型:输入
ps -p $$,查看输出结果是Bash还是Zsh。 - 编辑对应shell配置文件:
Bash:编辑~/.bash_profile文件。Zsh:编辑~/.zshrc文件。
- 添加环境变量:
export OPENAI_API_KEY="你的API密钥"。 - 保存文件,并执行
source ~/.bash_profile或source ~/.zshrc使配置生效。
OpenAI API密钥使用注意事项 (续) 安装openai库:
Section titled “OpenAI API密钥使用注意事项 (续) 安装openai库:”- 使用GPT模型的AI聊天功能,需安装
openai库。 - 在终端或
CMD输入:pip install openai(Windows),pip3 install openai(macOS)。 openai库要求Python版本3.7及以上。
OpenAI库的使用准备
Section titled “OpenAI库的使用准备”- 在Jupyter Notebook里,新建一个notebook,运行
!pip install openai !:相当于让命令在系统shell里运行- 安装完成后,就可以在Jupyter Notebook中使用
openai库了 - 使用
import语句,从openai库里导入OpenAI - ```python
from openai import OpenAI
- `OpenAI`类可以帮助创建发送给AI的请求- 创建一个`OpenAI`实例 - ```python client = OpenAI()- 确保电脑的环境变量里已经有
OpenAI的密钥了,不需要在此处输入密钥 - 环境变量的密钥值会自动传递
OpenAI API密钥使用 (续) 创建OpenAI实例:
Section titled “OpenAI API密钥使用 (续) 创建OpenAI实例:”- 如果电脑没有储存
OpenAI密钥,或想使用新密钥: - 赋值给
OpenAI构造函数的api_key参数 - 示例:
client = OpenAI(api_key="sk-XXXX-替换为你的密钥-XXXX")- 完整且实时更新的模型列表:OpenAI官网
- 模型数字越大,版本越新,性能越好;越老的模型,对话价格越便宜
- 要实现对话,调用的是
OpenAI类实例的chat.completions.create方法 model参数传入模型,支持聊天功能的GPT模型有不同种类,如gpt-3.5-turbo、gpt-4、gpt-4-turbo等
OpenAI API 使用 (续) messages 参数
Section titled “OpenAI API 使用 (续) messages 参数”messages参数:传递给AI模型的对话内容,为列表类型- 列表中每条消息用字典表示
role键:消息发送者- `
OpenAI API 使用 (续) 发送 AI 提示信息的方式:messages 参数
Section titled “OpenAI API 使用 (续) 发送 AI 提示信息的方式:messages 参数”messages参数:列表,包含字典,字典里有:role:字符串,指定消息发送者system:系统消息,给 AI 传递背景信息或角色设定(可选)user:用户消息,用户的实际提问assistant:助手消息,AI 的回复content:字符串,消息内容- 示例:
response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[ {"role": "system", "content": "你是一个乐于助人、语气友善的AI聊天助手"}, {"role": "user", "content": "你是谁"}, {"role": "assistant", "content": "我是ChatGPT,由OpenAI开发的一款大型语言模型"}, {"role": "user", "content": "四大文明古国分别有哪些"} ])- 系统消息示例:
{"role": "system", "content": "你是一个乐于助人、语气友善的AI聊天助手"} - 最简单的与 AI 对话方式:在
messages里放一条给 AI 的提示 - 运行完成后,被赋值的变量里包含 AI 回应的消息
- AI 的回复储存在
choices属性的第一个元素的message属性的content属性里 - 提取并打印 AI 回答:
print(response.choices[0].message.content) - 了解了如何给 OpenAI 的 GPT 模型发送请求并解析 AI 返回的消息
OpenAI API的计费方式
Section titled “OpenAI API的计费方式”- 绝大部分大模型API的计费基于
token数量。 - Token:文本的一个基本单位。
- 短单词可能每个词是一个
token。 - 长单词可能被拆分成多个
token。 - 中文所占的
token数量会相对更多,有些字要用一个甚至更多token表示。 - OpenAI提供的tokenizer网站:platform.openai.com/tokenizer
- 能展示任意文本如何被拆分为不同的
token。
OpenAI API的计费方式 (续) Token 详情
Section titled “OpenAI API的计费方式 (续) Token 详情”- Token:文本的基本单位。
- 英文短单词或标点通常是一个
token。 - 中文:通常每个汉字本身就是一个
token,或常用词是一个token。 - 不常见的字可能会被映射成多个
token。 - 英文文本的经验法则:1个
token大约对应4个字符(或3/4个单词),即100个token约等于75个单词。 - **更准确的&
token& OpenAI 官方tokenizer工具的计数结果。
OpenAI API的计费方式 (续) API响应中的 token 信息
Section titled “OpenAI API的计费方式 (续) API响应中的 token 信息”- 发送
GPT模型API请求后,响应中会包含token数信息。 - 在
usage字段中可以找到详细信息: completion_tokens:AI 回应中包含的token数量。prompt_tokens:用户输入(提示)中包含的token数量。total_tokens:completion_tokens和prompt_tokens的总和。
OpenAI API的计费方式 (续)
Section titled “OpenAI API的计费方式 (续)”prompt_tokens:用户输入(提示)包含的token数量。(示例:20个token)- 计费依据:
total_tokens(提示 + 回应),而非仅回应。 - OpenAI定价:查看API价格表。
- GPT-3.5 Turbo:输入约0.7人民币/1000
token,输出约1.4人民币/1000token。 - GPT-4:价格更高。
- 随着技术进步,API价格会持续下降。
- 需学习简洁提问,减少
token数量。 - 不用恐慌,费用不高。
Python 列表 (List)
Section titled “Python 列表 (List)”- 元素修改示例:
shopping_list[1] = "硬盘"- 列表操作函数:
max()min()sorted()
OpenAI API的计费方式 (续) Token 详情
Section titled “OpenAI API的计费方式 (续) Token 详情”- GPT-4:输入
$0.03/1K tokens,输出$0.06/1K tokens - GPT-4-32K:输入
$0.06/1K tokens,输出$0.12/1K tokens - 换算:1千
token约消耗人民币4毛钱。 - 旧模型比新模型便宜。
- 除API响应,还可用
OpenAI的tiktoken库: - 官方分词器,无需调用API,即可知文本
token数,估算成本。 - 安装:
Jupyter Notebook:!pip install tiktokenCMD或终端:pip install tiktoken(macOS可能用pip3 install tiktoken)- 使用:
import tiktoken- `encoding = tiktoken.encoding_for_model(
OpenAI API的计费方式 (续)
Section titled “OpenAI API的计费方式 (续)”- 可使用
OpenAI的tiktoken库:官方分词器,无需调用API,即可知文本token数,估算成本。 - 安装:
!pip install tiktoken - 使用:
import tiktokenencoding = tiktoken.encoding_for_model("gpt-3.5-turbo")- 传入模型名,返回对应编码器
encoding.encode("文本内容")- 返回
token ID列表,每个ID对应一个token len(encoding.encode("文本内容")):求文本token数,即列表长度- 估算价格:
token数乘以token单价 - 精确价格需更严谨逻辑,因为传输模型的不只是AI的提示文本,而是消息列表,包括角色等信息
- 简单估算
token数:用encode返回的列表长度估算
API控制回复Token数量上限
Section titled “API控制回复Token数量上限”- 提示
token数量可调,但AI回复token数可控 - 通过API可控制AI回复的
token数量上限
上下文窗口(Context Window)限制
Section titled “上下文窗口(Context Window)限制”- AI模型有上下文窗口限制
- 上下文窗口上限:
token数量 - 用户提示 + AI回应,超过上限,文本会被截断
- AI只能看到和处理窗口内的文本
- 可能导致不完整、不连贯或不相关的回应
上下文窗口限制 (续)
Section titled “上下文窗口限制 (续)”- AI提示不能超过上下文窗口,否则报错。
- AI回应长度受提示长度影响,提示长则回应短,甚至无法回应。
- 查看各模型上下文窗口长度:OpenAI官网
GPT-3.5-turbo:4096个token。GPT-3.5-turbo-16k:16385个token。GPT-4:8192个token。GPT-4-32k:32768个token。
上下文窗口限制 (续)二
Section titled “上下文窗口限制 (续)二”- 窗口更大的
GPT-4-1106-preview,可支持128,000个token。 - 价格:窗口更大的
GPT-4-32k比GPT-4贵一倍。
| Model | Input | Output |
|---|---|---|
| GPT-4 | $0.03 / 1K tokens | $0.06 / 1K tokens |
| GPT-4-32k | $0.06 / 1K tokens | $0.12 / 1K tokens |
针对上下文窗口限制的应对方法
Section titled “针对上下文窗口限制的应对方法”- 各种方法应对上下文窗口限制,后续会接触到。
- 了解
token的计数和计费方式。
API控制回复Token数量上限 (续) max_tokens 参数
Section titled “API控制回复Token数量上限 (续) max_tokens 参数”- 创建
GPT聊天请求时,除model和messages参数外,可添加max_tokens参数。 max_tokens:控制AI回复的token数量上限。- 示例:
max_tokens=300
response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": "四大文明古国分别有哪些"}], max_tokens=300)- 作用:避免
token超限,控制每次请求成本上限。
上下文窗口(Context Window)限制
Section titled “上下文窗口(Context Window)限制”- AI模型有上下文窗口限制
- 上下文窗口上限:
token数量 - 用户提示 + AI回应,超过上限,文本会被截断
- AI只能看到和处理窗口内的文本
- 可能导致不完整、不连贯或不相关的回应
temperature 参数:控制 AI 回复的随机性或创造性
Section titled “temperature 参数:控制 AI 回复的随机性或创造性”- 值范围:
0到2之间 - 默认值:
1 - 值越低:随机性越低,创造性越低,确定性越高
temperature为0:每次 AI 回复都差不多- 值越高:随机性越高,创造性越高,可能收到出乎意料的回答
- 但值过高,AI可能“放飞自我”,不按人类语言的规则行事,开始创造外星文
temperature 参数的物理学概念
Section titled “temperature 参数的物理学概念”- 借鉴物理学中的温度概念。
- 温度越高,粒子运动越快,运动随机性越大。
- 温度越低,粒子运动减慢,运动随机性降低。
temperature 参数与 token 的概率分布
Section titled “temperature 参数与 token 的概率分布”- 改变各个
token的概率分布。 - 温度低时,概率分布的峰很高,概率较高的词选择权重增大,概率较低的词更易被忽略,模型输出更具确定性。
- 温度高时,概率分布更趋于平坦,概率低的词被选择机会变高,模型输出更具随机性和创造性,不常连在一起的词也有机会出现。
top_p 参数:控制回复的随机性和创造性
Section titled “top_p 参数:控制回复的随机性和创造性”- 值范围:
0到1之间 - 功能:截取概率分布的子集,子集累积概率 ≥
top_p值。 top_p = 0.4:仅概率加起来 ≥ 0.4 的词纳入待选。top_p = 1:覆盖整个词汇表,不做任何概率截断,所有词都会纳入待选。
frequency_penalty 参数:惩罚重复内容程度
Section titled “frequency_penalty 参数:惩罚重复内容程度”- 值:
-2到2之间,默认为0 - 正数:基于已生成文本词频惩罚出现过的词
- 减少重复,提升多样性
- 负数:模型更可能重复文本
frequency_penalty参数深入解析
Section titled “frequency_penalty参数深入解析”- 降低后续词的出现概率,减少重复,增加文本多样性。
- 值为0:不对重复词惩罚,按原始概率分布选择。
- 正数:AI生成更丰富多变的文本,但值太高可能不合适。
- 负数:模型更可能重复文本。
示例:生成购物清单
Section titled “示例:生成购物清单”- 提示:生成至少20个物品的购物清单,用逗号分隔。
- AI回复:
- 初期:中文逗号。
- 之后:英文逗号,空格+英文逗号,空格+中文逗号。
- AI可能因训练数据格式多样而变化。
presence_penalty 参数:控制回复的重复性 (续)
Section titled “presence_penalty 参数:控制回复的重复性 (续)”- 值:
-2到2之间,默认为0 - 作用:控制生成内容的重复性
- 与
frequency_penalty的不同: frequency_penalty:正数时,看词在前文已出现的频率,出现越频繁,再次被选中的概率越低。presence_penalty:只看词是否出现,出现就降低频率。
frequency_penalty 和 presence_penalty 参数对比
Section titled “frequency_penalty 和 presence_penalty 参数对比”frequency_penalty:影响生成文本里词重复出现的频率presence_penalty:影响生成内容是否包含更多新词,不考虑具体重复次数- 都可结合使用
- 想要内容重复词少:可提高
presence_penalty - 想要减少高频词重复次数:可提高
frequency_penalty
OpenAI API 游乐场
Section titled “OpenAI API 游乐场”- OpenAI官方的API游乐场:platform.openai.com/playground
- 可在此处填写给AI的消息,更改任意参数值,如切换模型、调整
temperature、max_tokens、top_p、frequency_penalty、presence_penalty等
OpenAI API 游乐场的使用总结
Section titled “OpenAI API 游乐场的使用总结”- 在API游乐场进行参数调整后,点击
View code,可直接复制代码到代码编辑器。 - 游乐场本质上为API提供了可视化界面。
- 在游乐场的一切活动都会消耗账号API的
token。 - 游乐场最实用的功能是
View code。
调用国产大模型API的方法与步骤
Section titled “调用国产大模型API的方法与步骤”- 要切换与对话的AI大模型,要做到:
- 创建新的API密钥
- 修改请求代码
- 使用国产大模型API并非白学,因为:
- 现在大模型的API都长得很像
调用国产大模型API的方法与步骤 (续)DeepSeek 模型 API 密钥获取流程
Section titled “调用国产大模型API的方法与步骤 (续)DeepSeek 模型 API 密钥获取流程”- 注册 DeepSeek 账号以获取 API 密钥
- 访问 DeepSeek 的 API 文档官网
- 网址:
https://api.deepseek.com - 可切换为中文界面
- 点击 “Apply for API” 链接,注册或登录
- 完成登录后进入 DeepSeek 控制台
- 选择左侧的 “API Keys”
调用国产大模型API的方法与步骤 (续)DeepSeek 模型 API 密钥获取流程
Section titled “调用国产大模型API的方法与步骤 (续)DeepSeek 模型 API 密钥获取流程”- 注册 DeepSeek 账号以获取 API 密钥
- 访问 DeepSeek 的 API 文档官网
- 网址:
https://api.deepseek.com - 可切换为中文界面
- 点击 “Apply for API” 链接,注册或登录
- 完成登录后进入 DeepSeek 控制台
- 选择左侧的 “API Keys”
- 点击创建 API key 按钮
- 可以给密钥取名字,区分不同大模型应用的密钥
- 此时会直接出现一个密钥值,一定要记得复制,不然无法再次查看了
- 然后就可以关闭了
- 现在就拥有了一个可以调用DeepSeek 模型的密钥了
- 由于API是收费的,需要记得进行充值后才可以调用DeepSeek的API
- 将发送对DeepSeek模型的第一个请求
- 从
openai库里导入OpenAI - 创建一个
OpenAI的实例 - 使用DeepSeek模型,既然创建的可以是
OpenAI的实例 - 这是因为DeepSeek使用的是和OpenAI兼容的API格式
调用国产大模型API:DeepSeek
Section titled “调用国产大模型API:DeepSeek”- DeepSeek模型与OpenAI兼容API格式,可用OpenAI的Python库
- 创建
OpenAI实例时,需设置api_key和base_url参数 api_key:DeepSeek获得的密钥base_url:https://api.deepseek.com- 密钥存入环境变量更安全
- 导入
os库与操作系统交互 - 使用
os.getenv("DEEPSEEK_API_KEY")获取密钥
调用国产大模型API:DeepSeek (续)
Section titled “调用国产大模型API:DeepSeek (续)”base_url:基地址参数,决定客户端发送请求的目标服务器地址。- 将
base_url赋值为"https://api.deepseek.com",请求发送给DeepSeek服务器,而非OpenAI服务器。 model参数:需要修改为DeepSeek模型的名字,如deepseek-chat(聊天模型),deepseek-reasoner(推理模型)。
调用国产大模型API的方法与步骤 (续) DeepSeek 模型推理与通用模型区别
Section titled “调用国产大模型API的方法与步骤 (续) DeepSeek 模型推理与通用模型区别”deepseek-reasoner模型在输出最终回答前,会先输出一段思维链内容,以提升答案准确性。qwen-plus模型则直接给出最终答案。
调用国产大模型API的方法与步骤 (续) DeepSeek 模型 API 兼容性
Section titled “调用国产大模型API的方法与步骤 (续) DeepSeek 模型 API 兼容性”- DeepSeek 模型对 OpenAI API 接口兼容。
- 这意味着可以复用之前发送给 GPT 模型的请求代码,只需修改少量参数值(如
model名称和base_url),就能与 DeepSeek 模型对话。
调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程
Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程”- 要使用阿里云的通义模型,首先需要一个阿里云账号来获取 API 密钥。
- 阿里云的通义模型也使用与 OpenAI 兼容的 API 格式,可以复用 OpenAI 的 Python 库和请求代码。
调用国产大模型API的方法与步骤 (续) 阿里云通义模型代码修改
Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型代码修改”- 类似于 DeepSeek,使用阿里云通义模型时,也需要修改
base_url和model参数。 base_url应指向阿里云通义模型的 API 地址。model参数应指定为具体的通义模型,例如qwen-plus。
调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程
Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程”- 阿里云官网:aliyun.com
- 阿里云账号:获取API密钥
- 阿里云通义模型:与OpenAI兼容API格式
调用国产大模型API的方法与步骤 (续) 阿里云通义模型代码修改
Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型代码修改”base_url:阿里云通义模型的API地址model参数:指定通义模型,例如qwen-plus- 注册阿里云账号,完成注册
调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程
Section titled “调用国产大模型API的方法与步骤 (续) 阿里云通义模型 API 密钥获取流程”- 创建API密钥:
- 访问阿里云官网并注册/登录账号。
- 在控制台找到“API-KEY 管理”页面。
- 点击“创建新的API-KEY”。
- 为密钥命名(可选)。
- 务必复制并妥善保存生成的密钥,因为之后无法再次查看。
- 现在就拥有了可以调用通义模型的密钥了。
- 阿里云通义模型与 OpenAI API 接口兼容。
- 这意味着即使是调用通义模型,也可以继续使用
openaiPython库。 - 修改请求代码:
- 仍然从
openai库导入OpenAI并创建实例。 - 需要在
OpenAI实例中设置两个关键参数:api_key和base_url。 api_key:使用从阿里云获取的通义模型密钥。base_url:指向阿里云通义模型的 API 地址,例如设置为https://api.aliyun.com/dashscope/v1。model参数:需要修改为具体的通义模型名称,如qwen-plus。
from openai import OpenAIimport os
# 从环境变量获取API密钥,更安全
# 或者直接在参数中传入 api_key="sk-..."aliyun_api_key = os.getenv("ALIYUN_API_KEY")
client = OpenAI( api_key=aliyun_api_key, base_url="https://api.aliyun.com/dashscope/v1" # 指向阿里云API地址)
response = client.chat.completions.create( model="qwen-plus", # 使用通义模型名称 messages=[ {"role": "user", "content": "四大文明古国分别有哪些"} ])
print(response.choices[0].message.content)调用国产大模型API:阿里云通义模型代码修改 (续)二
Section titled “调用国产大模型API:阿里云通义模型代码修改 (续)二”- 使用
os.getenv("DASHCOPE_API_KEY")安全地从环境变量获取密钥。 - 其次,设置
base_url参数,让客户端确定目标服务器的地址。 - 赋值为
"https://dashscope.aliyuncs.com/compatible-mode/v1",将请求发送给阿里云服务器,而非OpenAI服务器。 compatible-mode/v1:兼容模式- 修改模型:将
model参数修改为通义模型的名字,如qwen-plus。
调用国产大模型API:阿里云通义模型代码修改 (续)三
Section titled “调用国产大模型API:阿里云通义模型代码修改 (续)三”- 创建
OpenAI实例,可发送请求给不同服务器 - 作为请求方,对发送目标有自由选择权:
OpenAI、阿里云、第三方服务器等 - 可复用发送给
GPT模型的请求代码 - 仅需修改
model参数:替换为通义模型名称,如qwen-turbo、qwen-plus、qwen-max等。 - 速度:
turbo最快 - 智能:
max参数最大,回答最聪明 - 平衡:
plus在速度和效果间平衡
调用国产大模型API的方法与步骤 (续)Kimi Chat背后Moonshot模型API密钥获取流程
Section titled “调用国产大模型API的方法与步骤 (续)Kimi Chat背后Moonshot模型API密钥获取流程”- 前往Moonshot AI开放平台的官网:https://platform.moonshot.cn/console/
- 点击用户中心,登录或注册账号
- 自动跳转到基本信息页面
调用国产大模型API的方法与步骤 (续)Kimi Chat背后Moonshot模型API密钥获取流程
Section titled “调用国产大模型API的方法与步骤 (续)Kimi Chat背后Moonshot模型API密钥获取流程”- 前往Moonshot AI开放平台的官网:https://platform.moonshot.cn/console/
- 点击用户中心,登录或注册账号
- 自动跳转到基本信息页面
- 点击左边的
API Key管理 - 点击新建按钮,可以给密钥取个名字,区分不同大模型应用的密钥
- 点击确定后会出现密钥值,务必复制,不然无法再次查看
- 现在就拥有了一个可以调用
Moonshot模型的密钥了 - 由于
API是收费的,需要记得进行充值后才可以调用 - 从
openai库里导入OpenAI - 创建一个
OpenAI的实例 - 因为
Moonshot AI对OpenAI的接口做了兼容,所以创建的可以是OpenAI的实例 - 在
OpenAI实例里对两个参数进行设置: api_key:赋值给我们之前复制的密钥,更好的方式是储存在环境变量里base_url- 从
openai库里导入OpenAI - 创建一个
OpenAI的实例 - 使用
DeepSeek模型,既然创建的可以是OpenAI的实例 - 这是因为
DeepSeek使用的是和OpenAI兼容的API格式
调用国产大模型API:Kimi Chat背后Moonshot模型API密钥获取流程 (续)二
Section titled “调用国产大模型API:Kimi Chat背后Moonshot模型API密钥获取流程 (续)二”- 使用
os.getenv("MOONSHOT_API_KEY")方便获取密钥 - 修改
base_url:"https://api.moonshot.cn/v1" - 修改
model:moonshot-v1-8k等,model参数取决于使用的模型
调用国产大模型API:Kimi Chat背后Moonshot模型API密钥获取流程 (续)三
Section titled “调用国产大模型API:Kimi Chat背后Moonshot模型API密钥获取流程 (续)三”- Moonshot模型:在官网文档查看对应名称
- 打印
Moonshot模型回复:与GPT模型响应文本代码一样 - 感谢
Moonshot AI对OpenAI接口的兼容 - 可复用发送给
GPT模型的请求,只需修改参数值
- 与AI大语言模型交流:提示是关键
- 提示:输入给AI的问题或指令
- AI根据提示内容给出回应
- 好的提示能极大提高AI的理解和执行效率
提示词工程 (续)
Section titled “提示词工程 (续)”- 提示工程:
- 研究如何提高和AI的沟通质量及效率。
- 核心关注提示的开发和优化。
- OpenAI 最佳实践文章:https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-openai-api
- 学习好的提示和不好的提示分别是什么样的。
提示词工程的原则
Section titled “提示词工程的原则”- 使用最新的模型:模型版本会持续迭代,一般来说:
- 开头的字母越靠后;
- 版本数字越大;
- 说明模型越新
提示词工程的原则 (续)最新模型优势
Section titled “提示词工程的原则 (续)最新模型优势”- 理解和生成能力更强
- API价格通常更高
提示词工程的原则 (续)指令清晰
Section titled “提示词工程的原则 (续)指令清晰”- 将指令放在提示的开头
- 使用
###或"""来分隔指令和上下文 - 示例:
把下文里的要点用列表进行总结 - 将要总结的文本用三个引号进行包围
提示词工程的原则 (续)具体详细要求
Section titled “提示词工程的原则 (续)具体详细要求”- 尽可能对上下文和输出的长度、格式、风格等给出具体、描述性、详细的要求
提示词工程的原则 (续)通过一些例子来阐明想要的输出格式
Section titled “提示词工程的原则 (续)通过一些例子来阐明想要的输出格式”- 要模型从文本里提取实体,包括:公司名、人名、特定主题、泛主题。
- 提供所需格式:公司用逗号,其他用
--。 - 指定输出格式也能方便后续解析。
提示词工程的原则 (续) 从零样本提示开始,效果不好,则用小样本提示
Section titled “提示词工程的原则 (续) 从零样本提示开始,效果不好,则用小样本提示”- 零样本提示:不给AI任何回应示范,直接提问或指令
- 如效果不好,可考虑给AI几个回复作为参考例子
提示词工程的原则 (续) 减少空洞和不严谨的描述
Section titled “提示词工程的原则 (续) 减少空洞和不严谨的描述”- 好的提示:用3到5句话组成一个段落描述,简洁易赅,要求清晰
提示词工程的原则 (续) 与其告知不应该做什么,不如告知应该做什么
Section titled “提示词工程的原则 (续) 与其告知不应该做什么,不如告知应该做什么”提示工程的原则 (续) 与其告知不应该做什么,不如告知应该做什么
Section titled “提示工程的原则 (续) 与其告知不应该做什么,不如告知应该做什么”- 明确告知模型主要任务。
- 指导模型参与用户文档,而非询问用户隐私数据。
提示词工程 (续) 格式控制
Section titled “提示词工程 (续) 格式控制”- 给AI提要求,指定输出格式,如
JSON、XML、YAML等。 - 告知AI不要包含任何没必要的补充信息。
- 避免额外文字影响后续解析。
提示词工程 (续) 示例
Section titled “提示词工程 (续) 示例”- 提示:生成一个由三个虚拟的订单信息所组成的列表,以
JSON格式进行返回。 JSON列表里的每个元素包含以下信息:order_id、customer_name、order_item、phone。- 所有信息都是字符串。
- 除了
JSON之外,不要输出任何额外的文本。
提示词工程 (续) 输出格式控制:JSON
Section titled “提示词工程 (续) 输出格式控制:JSON”- 严格限定输出格式的提示可增长。
- JSON (JavaScript Object Notation):常用输出格式,与
JavaScript语法关联。 - JSON对象:Python字典,大括号
{}开头结尾,键值对(键: 值)用冒号分隔,键值对之间用逗号分隔。 - JSON数组:Python列表,方括号
[]开头结尾,元素用逗号分隔。
JSON对象
Section titled “JSON对象”- 用逗号分隔每个键值对,酷似Python字典
JSON数组
Section titled “JSON数组”- 用中括号开头和结尾,酷似Python列表
- 每个值之间用逗号进行分隔
JSON与Python数据类型区别
Section titled “JSON与Python数据类型区别”- Python字典:可用整数等不可变数据类型作为键
- JSON数据:只能用字符串做键,且字符串必须被双引号包围
- JSON对象或数组里嵌套对象,规则同样适用于里面
JSON与Python数据类型区别
Section titled “JSON与Python数据类型区别”- 布尔值:
- Python中是
True和False(首字母大写)。 - JSON中是
true和false(全小写),因为JSON本质是JavaScript对象。 - 空值:
- Python中是
None(首字母大写)。 - JSON中是
null(全小写)。
编程工具准备
Section titled “编程工具准备”Jupyter Notebook 介绍
Section titled “Jupyter Notebook 介绍”- 优势:
- 基于网页的交互式计算环境。
- 机器学习和数据科学常用。
- 可按单元格运行代码,无需从头到尾运行,节省时间和费用。
- 提供交互模式,无需
print语句即可查看输出。 - 支持展示更丰富的信息格式,如使用
Markdown标记语言。 - 安装:
- Windows:
pip install notebook。 - macOS/Linux:
pip install notebook或pip3 install notebook。 - 启动:在命令行输入
jupyter notebook。 - 温馨提示:如安装遇到问题,可考虑安装Anaconda(一站式计算科学工具集,包含Jupyter)。
- 启动与关闭:
- 启动后浏览器自动打开Jupyter Notebook主面板。
- 如不小心关闭页面,可在启动命令的终端窗口中找到访问地址。
- 关闭:在终端窗口按
Ctrl + C,Windows直接终止,macOS/Linux需输入y确认。 - 界面与基本操作:
- 主面板:显示当前目录文件和文件夹,可导航。
- 新建Notebook:点击
New->Notebook。 - 重命名:点击标题进行重命名。
- 菜单栏、工具条、单元格。
- 单元格模式:
- 编辑模式:点击单元格,底色变白。
- 命令模式:按
Esc或点击其他地方,底色变灰。 - 运行单元格:
- 点击工具条运行按钮或使用快捷键
Shift + Enter。 - 运行中显示
[*],完成后显示数字(执行顺序)。 - 单元格可按任意顺序、多次反复运行。
- 输出:单元格内多条输出,只有最后一项被展示(其他需用
print)。 - 中止执行:工具条上的方形按钮。
- 重启内核:工具条上的循环箭头按钮,会清除所有已定义的变量。
- Markdown单元格:
- 切换单元格类型为
Markdown。 - 标题:
#(H1) 到######(H6)。 - 粗体:
**文本**。 - 斜体:
*文本*。 - 分隔线:
---。 - 引用:
> 文本。 - 无序列表:
- 文本。 - 有序列表:
1. 文本。 - 换行:双空行(新段落),或行末加两个空格(软换行)。
- 快捷键:
- 命令模式下:
A:上方插入新单元格。B:下方插入新单元格。DD:删除当前单元格。- 更多快捷键:
Help->Show Keyboard Shortcuts。
代码控制AI交互
Section titled “代码控制AI交互”- 比网页界面更灵活、可控。
- 可调整AI回复的长度、创造性、频率惩罚等参数。
- 可使用提示模板提高效率。
- 可精确控制请求参数(如限制AI回答的
token数)。 - 可对大量数据进行批处理(例如一次性总结多个文档)。
- 可将AI集成到自己的系统或流程中。
- API(Application Programming Interface,应用程序编程接口):定义两个软件程序之间的服务合约,规定了如何通过请求和响应进行通信。
- 大部分API基于HTTP协议。
- HTTP请求过程:
- 客户端(运行代码的程序)将提示放入请求内容。
- 通过HTTP发送给AI服务提供方(如OpenAI、百度等)服务器。
- 服务器返回响应。
- 客户端获取AI回复。
- OpenAI、百度等公司提供了封装好的Python库,简化了HTTP请求的构建。
- API的响应也是预先规定好的格式,以便正确提取信息。
- 不同AI模型(如OpenAI的GPT、百度的文心)通常有不同的Python库,但接口设计趋同。
API密钥的重要性
Section titled “API密钥的重要性”- 调用AI大模型前,必须获取API密钥。
- 作用:让服务提供方识别和验证客户端请求,确认账号、追踪计费和使用频率。
- 安全注意事项:
- 严禁泄露:密钥与账户绑定,泄露后他人使用产生的费用由你承担。
- 不宜硬编码:直接写在代码中(明文)有风险,尤其上传到公共代码仓库。
- 最佳实践:将密钥设置为电脑的环境变量。
- 代码自动通过环境变量获取密钥值,提高安全性。
- 怀疑泄露时,立即删除旧密钥并创建新密钥。
- 设置环境变量(示例):
- Windows:
- 右键“此电脑” -> “属性” -> “高级系统设置” -> “环境变量”。
- 在“系统变量”下“新建”,变量名
OPENAI_API_KEY,变量值粘贴API密钥。
- macOS/Linux:
- 打开终端,查看shell类型(
Bash或Zsh)。 - 编辑对应配置文件(
~/.bash_profile或~/.zshrc)。 - 添加
export OPENAI_API_KEY="你的API密钥"。 source配置文件使配置生效。
提示词工程 (续) 解析AI返回的JSON格式数据
Section titled “提示词工程 (续) 解析AI返回的JSON格式数据”- 当AI返回JSON格式的字符串时,需要将其转换为Python可以操作的字典或列表。
- 使用Python内置的
json库: - 首先,
import json导入库。 - 然后,使用
json.loads()方法,将AI返回的JSON字符串作为参数传入。 json.loads()会直接将JSON字符串解析成对应的Python字典或列表。- 优势:当AI的输出被明确定义为可解析的格式(如JSON),可以更容易地用代码提取信息并进行复杂处理。
提示词工程 (续) 小样本提示(Few-shot Prompting)
Section titled “提示词工程 (续) 小样本提示(Few-shot Prompting)”- 目的:调教AI给出更符合预期的回答。
- 小样本提示:在提示中给AI提供几个示例(输入-输出对),以指导其生成所需格式或风格的回答。
- 应用场景:当零样本提示(直接提问,不给示例)效果不佳时,小样本提示是一种推荐的最佳实践。
提示词工程的原则 (续) 小样本提示
Section titled “提示词工程的原则 (续) 小样本提示”- 小样本提示:给AI几个回复作为参考例子
- 利用上下文学习能力,记忆内容作为知识,像示例那样模仿回应
- 代码示例:
chat.completions.create方法的messages参数包含一系列用户和AI的对话
提示词工程 (续) 小样本提示(Few-shot Prompting) (续)二
Section titled “提示词工程 (续) 小样本提示(Few-shot Prompting) (续)二”- 在
messages参数中,role为user时,提示词示例;role为assistant时,对应回复示例。 - 示例:
response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[ {"role": "user", "content": "格式化以下信息:\n姓名 -> 张三\n年龄 -> 27\n客户ID -> 001"}, {"role": "assistant", "content": "##客户信息\n- 客户姓名:张三\n- 客户年龄:27\n- 客户ID:001"}, {"role": "user", "content": "格式化以下信息:\n姓名 -> 李四\n年龄 -> 42\n客户ID -> 002"}, {"role": "assistant", "content": "##客户信息\n- 客户姓名:李四\n- 客户年龄:42\n- 客户ID:002"}, {"role": "user", "content": "格式化以下信息:\n姓名 -> 王五\n年龄 -> 32\n客户ID -> 003"} ] ) print(response.choices[0].message.content)- 用户提示的
role值为user,AI回应的role值为assistant。 - 上述示例,AI会模仿
Markdown格式输出,并把客户姓名、年龄、客户ID作为Markdown列表的元素。 - 小样本示例能让AI快速适应新任务,且不需要对模型进行任何训练,成本低又灵活。
提示词工程 (续) 小样本提示的局限性
Section titled “提示词工程 (续) 小样本提示的局限性”- AI不擅长数学计算,即使提供正确示例,结果仍可能出错
- 例:奇数相加结果计算错误(41而非53)
- 下节将探讨更多提示工程技巧,如用思维链辅助算数和推理。
提示词工程 (续) 思维链(Chain of Thought)提示
Section titled “提示词工程 (续) 思维链(Chain of Thought)提示”- 问题:小样本提示对数学计算帮助有限
- 思维链:在小样本提示中,展示中间的推理步骤
- 示例:提示中不仅包含正确结果,也展示推理过程
- AI生成回答时,模仿生成中间步骤
- 2022年谷歌论文提出:Chain-of-Thought Prompting Elicits Reasoning in Large Language Models
- 思维链可显著提升大语言模型进行复杂推理的能力,尤其在算术、常识、符号推理任务上
提示词工程 (续) 思维链(Chain of Thought)提示
Section titled “提示词工程 (续) 思维链(Chain of Thought)提示”- 分步骤思考:将复杂问题分解,减少上下文干扰,提高AI准确率。
- 类似老师提问时,学生不直接给答案而是先讲思考步骤,获得更多思考时间,也更容易得出正确答案。
- 思维链不仅适用于数学计算,还可用于其他许多方面(如:判断物理现象、日期计算、足球运动员信息、机器人指令、字符串操作、抛硬币结果追踪)。
- 借助思维链,AI能将注意力集中在当前思考步骤上。
- 即使不用小样本提示,只需在问题后加一句
let's think step by step,也能显著提升AI的推理能力。
提示词工程 (续) 步骤思考
Section titled “提示词工程 (续) 步骤思考”- 在提示中加入
让我们分步骤思考 - AI会自行生成中间步骤进行推理
- 适用于数学计算
使用AI大模型的API做文本撰写
Section titled “使用AI大模型的API做文本撰写”- 应用场景:AI自动回复客户邮件、自动回复用户评论、自动生成产品文案等
- 导入所需库并实例化
OpenAI客户端 - 对上个视频里封装的给
OpenAI发送请求的函数进行修改,增加一个system prompt的参数,表示系统提示 role为system的消息
system prompt 的作用(续)
Section titled “system prompt 的作用(续)”- 用于给AI传递背景信息或角色设定(可选)。
- 也可以给AI安排个性或角色,或是定义输出内容的规则。
- 系统提示是可选的,没有也可以。
生成小红书文案示例
Section titled “生成小红书文案示例”- 目标:让AI根据给定的主题,自动生成小红书爆款标题和正文。
- 为此任务设计的
system prompt非常长,其中给AI的规则都是基于当下爆款小红书标题的套路。 - 示例:如“短期内即可开挂,不做XX你绝对后悔”之类。
- 提供了爆款关键词,让AI自己选择,如“好用到哭”、“宝藏”、“绝绝子”等。
提示词工程:输出格式控制
Section titled “提示词工程:输出格式控制”- 需定义输出格式,避免每次AI生成格式不一致。
- 本例要求AI根据主题生成5个标题和一段正文。
get_openai_response函数参数:client(OpenAI客户端)、xiaohongshu_system_prompt(系统提示)、用户提示。- 用户提示:可直接传入主题,如“学英语”。
- 使用AI大模型的API做文本分类。
- 是自然语言处理领域的经典任务。
- 例如:把邮件内容分类为垃圾邮件和正常邮件。
- 文本情感分类:积极、中性、消极等。
- 使用AI大模型的API做文本分类,是自然语言处理领域的经典任务。
- 例:邮件分类(垃圾邮件/正常邮件),文本情感分类(积极/中性/消极)。
- 任务:对用户的问题进行分类。
- 类别:产品规格、使用咨询、功能比较、用户反馈、价格查询、故障问题、“其它”。
- 提示:
- 告知AI:任务是对用户问题进行分类,类别是其中之一。
- 要求AI:直接输入类别名称,不要有额外描述或补充。
- 多个问题分类:使用
for循环迭代,打印所属类别。
文本分类 (续)准备提示词:数据类型转换与字符串拼接
Section titled “文本分类 (续)准备提示词:数据类型转换与字符串拼接”- 需将分类和用户问题依次插入提示词
- 定义变量
formatted_prompt - 使用
format函数 categories应为字符串,需转换- 原本
category_list为列表,需转为字符串 - ``拼接列表元素
文本分类 (续)准备提示词:数据类型转换与字符串拼接
Section titled “文本分类 (续)准备提示词:数据类型转换与字符串拼接”- 需将分类和用户问题依次插入提示词
- 定义变量
formatted_prompt - 使用
format函数 categories应为字符串,需转换- 原本
category_list为列表,需转为字符串 - ``“.join(category_list)`拼接列表元素
- 使用AI大模型的API做文本翻译。
- 指的是自然语言之间的转换,例如:英文转中文
- 后续会探索如何让AI拥有读取外部文档的能力
文本翻译 (续)提示词工程
Section titled “文本翻译 (续)提示词工程”- 对于基础翻译器,需要明确指定消息的语言。
- AI大模型可直接判断语言并翻译成中文。
- 提示词示例:
- 要求AI判断消息语言并翻译成中文。
- 尽可能保留客户原本的语气。
文本翻译 (续)
Section titled “文本翻译 (续)”- 指定输出格式:原始消息和翻译后的消息。
- 提示词工程最佳实践:用符号(
###)包裹上下文,区分指令。 - 使用
input()函数获取用户输入。
文本翻译 (续) 提示词工程 (续) 实际应用
Section titled “文本翻译 (续) 提示词工程 (续) 实际应用”- 结合
input()函数,从用户处获取翻译文本 - 在
Jupyter Notebook单元格中输入文本,观察翻译结果 - 翻译完成后,重新运行单元格可翻译其他文本
AI大模型能做的事儿:翻译
Section titled “AI大模型能做的事儿:翻译”- 可翻译自然语言,也可翻译
编程语言(JavaScript to Python) - 只需修改
prompt即可 - API基础用法示例:总结、撰写、分类、翻译
- AI还可做文本信息提取:地点、人名、公司名等
- 可做语气转换:口语转书面语
LangChain
Section titled “LangChain”- 大模型领域里最热门的开源框架,可理解为脚手架
- 能加速AI应用的开发速度、简化流程、确保质量
- AI没有记忆,可用Python列表手动储存之前的消息
- 下一次提问时,把历史对话一块发给AI
- AI能接受外部知识的长度有限
- 可以把文档内容先转换成向量
LangChain 框架简介
Section titled “LangChain 框架简介”- 解决提示词工程中的重复提示和步骤问题。
- 用于支持AI大模型应用开发的框架。
LangChain框架的用途
Section titled “LangChain框架的用途”- 减轻提示词工程中的重复提示和步骤。
- 适用于多种AI模型。
LangChain 框架组件
Section titled “LangChain 框架组件”- LangChain 不仅是调用模型 API,还能:
- 感知上下文
- 连接外部数据
- 借助外部工具与环境互动,以生成更好回复。
- LangChain 提供一系列组件和链,简化开发过程。
- 如,希望 AI 有记忆,借助 LangChain,无需手动维护消息列表。
- 可创建
ConversationBufferMemory实例,与模型链一起作为对话链参数。 - 每次对话时,新消息自动添加并传递给模型,模型被外接了记忆。
- 帮助 AI 应用开发者管理对话状态。
- 这只是 LangChain 一个简单用法。
- LangChain 提供的组件包括:
- 模型、提示模板、记忆、文件加载器、检索器、链、agent
LangChain 框架组件
Section titled “LangChain 框架组件”- 这些组件能大大降低AI应用开发的复杂度。
LangChain 的统一接口与抽象层
Section titled “LangChain 的统一接口与抽象层”- LangChain 为模型提供了统一的接口或抽象层。
- 就像一个智能PDF问答工具,用户无需关心后端是OpenAI的GPT模型还是百度的文心模型。
- 从代码实现角度看,如果不使用LangChain,切换模型需要根据各模型的API对代码进行重新调整。
- 使用LangChain后,无论是GPT、文心、Claude还是通义等,它们都可以被视为“聊天模型”(Chat Model)。
- LangChain 统一了聊天模型的接口,这就像在不同模型外面套了一层适配器,极大地简化了模型切换的复杂性。
LangChain 框架 (续) 模型切换与向量数据库集成
Section titled “LangChain 框架 (续) 模型切换与向量数据库集成”- LangChain 的统一接口或抽象层可以轻松切换不同的 AI 模型(例如从 OpenAI 的 GPT 切换到百度文心)。
- 这种适配器模式极大地简化了模型切换的复杂性,无需根据不同模型的 API 重写代码。
- 向量数据库(用于存储和检索向量化数据)也可以通过 LangChain 轻松切换,例如:
PineconeChromaFaissWeaviate- 切换不同的向量数据库时,除了导入和创建实例的语句,核心代码改动不大。
- 这极大地增加了 AI 应用开发的灵活性,也使维护和升级更加容易。
LangChain 框架组件
Section titled “LangChain 框架组件”- LangChain 提供的组件包括:
- 模型 (Models)
- 提示模板 (Prompt Templates)
- 记忆 (Memory)
- 文件加载器 (Document Loaders)
- 检索器 (Retrievers)
- 链 (Chains)
- 智能体 (Agents)
OpenAI Assistant API
Section titled “OpenAI Assistant API”- 除了原有的 API,OpenAI 后续推出了
Assistant API。 Assistant在中文里是助理的意思。- 目的:帮助在自己的应用中构建 AI 助理。
- 核心能力:
- 接收指令。
- 利用模型、工具和知识来回应用户查询。
- 内建工具类型:
Code Interpreter(代码解释器)Retrieval(检索)Function calling(函数调用)- 典型集成流程:
- 创建助理 (
Create an Assistant):定义自定义指令,选择模型。 - 创建会话 (
Create a Thread):当用户开始对话时。 - 添加消息 (
Add Messages):将用户问题添加到会话中。 - 运行助理 (
Run the Assistant):在会话上运行助理以触发响应。
OpenAI Assistant API (续)功能与优势
Section titled “OpenAI Assistant API (续)功能与优势”Assistant API基于OpenAI模型,但功能更强大:- 能维护对话历史。
- 能访问外部文件。
- 能调用外部工具。
- 核心优势:
- 自动管理对话历史:开发者无需手动维护,简化了开发流程。
- 集成多种外部工具:内置文件检索器、代码解释器,并支持自定义函数调用,有效弥补了AI大模型自身的局限性。
LangChain 与 Assistant API 的对比
Section titled “LangChain 与 Assistant API 的对比”Assistant API的功能(如维护对话历史、调用工具)听起来与LangChain框架的作用相似。- LangChain 强调:强大的AI应用不仅限于调用模型API,还能:
- 感知上下文。
- 连接外部数据。
- 借助外部工具与环境互动,以生成更优质的响应。
- 本质区别:
Assistant API和LangChain在设计理念和应用场景上存在较大差异。
LangChain 与 Assistant API 的对比
Section titled “LangChain 与 Assistant API 的对比”- 本质不同:
Assistant API本质上是API。LangChain是一个应用框架。- 支持模型范围不同:
Assistant API仅支持OpenAI模型(如GPT-4),因为它由OpenAI提供。LangChain是一个通用的开发框架,可以集成各种来源的AI模型(支持多种模型)。- 简易性与灵活性不同:
Assistant API在使用上更简单直接,许多复杂任务直接由OpenAI在后台处理。LangChain则更灵活,提供更多工具和组件来构建应用。
LangChain 与 Assistant API 的对比(续)开源与定制化:
Section titled “LangChain 与 Assistant API 的对比(续)开源与定制化:”Assistant API:开发者自定义调整有限。LangChain:- 开源,随时查看和修改代码。
- 适应复杂和定制化需求。
LangChain 与 Assistant API 的对比(续)应用范围:
Section titled “LangChain 与 Assistant API 的对比(续)应用范围:”Assistant API:构建对话型应用(如聊天机器人、虚拟助手)。LangChain:整合外部资源和接口,构建更广泛的 AI 应用(简单聊天机器人或复杂AI系统)。
快速选择建议:
Section titled “快速选择建议:”- 快速上手
OpenAI模型应用:选择Assistant API。 - 开发适用模型范围广、更灵活和定制化的复杂应用:选择
LangChain。
LangChain框架的安装方法
Section titled “LangChain框架的安装方法”- 与其他Python库类似:
pip install langchain。 - Jupyter Notebook:
!pip install langchain - 终端/CMD:
pip install langchain或pip3 install langchain
LangChain框架的安装方法
Section titled “LangChain框架的安装方法”- 与其他Python库类似:
pip install langchain。 - Jupyter Notebook:
!pip install langchain - 终端/CMD:
pip install langchain或pip3 install langchain
LangChain 框架组件
Section titled “LangChain 框架组件”- LangChain 提供的组件包括:
- 模型 (
Model): 提供语言理解和生成能力,是 AI 应用的核心。 - 记忆 (
Memory): 用于存储和管理对话历史或相关上下文信息,使 AI 能够记住之前的交互。 - 链 (
Chain): - 检索器 (
Retriever): - 智能体 (
Agent):
LangChain框架组件 (续) 链 (Chain):
Section titled “LangChain框架组件 (续) 链 (Chain):”- 把不同组件串联成结构。
- 实现复杂流程,每个组件负责特定任务。
LangChain框架组件 (续) 检索器 (Retriever):
Section titled “LangChain框架组件 (续) 检索器 (Retriever):”- 负责从外部信息源检索信息。
- 增加模型知识面,提高回答准确性。
LangChain框架组件 (续) 智能体 (Agent):
Section titled “LangChain框架组件 (续) 智能体 (Agent):”- 基于大模型,能执行一系列动作的智能体。
- 利用AI模型推理,根据任务动态评估和确定行动路径。
LangChain 框架组件 (续) 模型类型
Section titled “LangChain 框架组件 (续) 模型类型”- LangChain允许集成多种模型,主要分为两类:
- LLM(语言模型):做文本补全的模型。
- Chat Model(聊天模型):在对话方面进行调优的模型。
- 本质上都是大语言模型。
- 主要使用的接口不同。
- LLM接收一个字符串作为输入,返回一个字符串作为输出。
- Chat Model接收一个消息列表作为输入,返回一个消息作为输出。
LangChain中OpenAI的使用准备
Section titled “LangChain中OpenAI的使用准备”- 模型选择:
gpt-3.5-turbo、gpt-4等,需使用OpenAI的API密钥 - 如使用课程提供的
API密钥,需额外传入参数,详见课程配置文件 - 创建
OpenAI实例: - 从
openai库导入OpenAI:
from openai import OpenAI- 环境变量已设置密钥,则直接创建实例:
client = OpenAI()- 否则,需显式传入
api_key:
client = OpenAI(api_key="sk-...")- 常用参数:
temperature:控制回复的随机性(温度)max_tokens:限制回复的token数- 不常用参数:可作为键值对放入字典,传给
model_kwargs
LangChain中OpenAI的使用准备 (续) model_kwargs 参数
Section titled “LangChain中OpenAI的使用准备 (续) model_kwargs 参数”- 示例:
response = client.chat.completions.create( model=model.model_name, messages=messages, temperature=temperature, max_tokens=max_tokens, model_kwargs=model_kwargs)model_kwargs:接收其他不常用参数,以字典形式传入- 查看LangChain官方文档,确定可调参数及其含义
- LangChain官方文档:应是准确且实时更新的信息来源
- API密钥、
base_url、模型名称:必须参数,决定客户端消息发给谁 model_kwargs:可选参数,可控制AI行为- 使用LangChain可更好控制
OpenAI模型,理解模型如何接收消息、如何调用API、如何传入参数
LangChain中消息 Message
Section titled “LangChain中消息 Message”messages:消息列表,可包含不同类型的消息- 消息类型:
SystemMessage:系统消息,给AI传递背景信息或角色设定HumanMessage:人类消息,用户的实际提问AIMessage:AI的回复
LangChain中消息 Message (续)
Section titled “LangChain中消息 Message (续)”- 使用
from langchain.schema.messages import (SystemMessage, HumanMessage)引入 SystemMessage:构造函数的content参数赋值为消息文本- 例:`system_message = SystemMessage(content=
LangChain中消息 Message (续)获取AI回复内容
Section titled “LangChain中消息 Message (续)获取AI回复内容”- AI的回复存储在
AIMessage对象中。 - 通过
.content属性可获取AI回复的实际文本内容。
LangChain中的其他聊天模型
Section titled “LangChain中的其他聊天模型”- 除了OpenAI的模型,
langchain_community库还集成了许多其他聊天模型。 - 可以在官方文档的
langchain_community.chat_models部分查看支持的模型列表,例如: chat_models.baidu_qianfan_endpoint.QianfanChatEndpoint:百度千帆平台提供的大模型(包括文心大模型)。chat_models.hunyuan.ChatHunyuan:腾讯混元模型。chat_models.tongyi.ChatTongyi:阿里通义千问模型。- 如果对其他AI服务感兴趣,也可以申请它们的API密钥,然后切换不同模型进行尝试。
- 提示 (
Prompt):用户给大语言模型的输入内容(问题或指令)。
提示模板 (Prompt Templates)
Section titled “提示模板 (Prompt Templates)”- 当使用网页端与AI聊天时,每个提示都需要手动构建。
- 使用代码时,可在提示中插入变量,从而实现结构化提示。
- 这样做能根据需要动态调整示例或数据,灵活性和效率更高。
Prompt Template(提示模板)就是用于动态构建给模型的消息。- 聊天模型的提示模板包括:
SystemMessagePromptTemplate:针对系统消息的模板。HumanMessagePromptTemplate:针对人类消息的模板。AIMessagePromptTemplate:针对AI消息的模板。- 这些模板都位于
langchain.prompts模块下。 - 这些消息提示模板都有一个名为
from_template的方法,用于从字符串模板创建提示模板。
提示模板 (Prompt Templates) (续) 创建消息提示模板
Section titled “提示模板 (Prompt Templates) (续) 创建消息提示模板”- 接收字符串作为提示内容,字符串里可用花括号
{}包围的变量名,动态填充值。 input_language和output_language都是变量的例子。- 可用同一系统提示模板做中文翻译法语、英语翻译西班牙语等。
- 输入系统提示模板的
input_variables属性可看到,input_language和output_language被花括号包围,自动被识别成了变量,不需要专门指出来。 - 创建用户提示模板,用
HumanMessagePromptTemplate的from_template方法,传入表示提示内容的字符串。 - 如果字符串里有花括号包围的文本,它们都自动被识别成了变量。
提示模板 (Prompt Templates) (续) 动态填充变量
Section titled “提示模板 (Prompt Templates) (续) 动态填充变量”- 如果字符串里有花括号
{}包围的文本,这些文本会自动被识别为变量。 - 例如:
human_template_text = "文本: {text}\n语言风格: {style}"中的text和style会被识别为变量。 - 有了提示模板后,填入变量值很简单,使用
.format()方法传入参数即可。 - 示例:
system_prompt = system_prompt_template.format(input_language="英语", output_language="汉语") human_prompt = human_prompt_template.format(text="I'm so hungry I could eat a horse", style="文言文")SystemMessagePromptTemplate在.format()后会返回SystemMessage。HumanMessagePromptTemplate在.format()后会返回HumanMessage。- 要得到聊天模型的回复,仍然需要传入消息列表。
- 将不同角色的消息模板通过
.format()填入值后得到的消息,放入列表里作为model.invoke()的参数即可。 - 尽管使用提示模板需要多调用一次
.format(),但它提供了很大的灵活性,方便动态构建和管理提示。 - 示例:
model = ChatOpenAI(model="gpt-3.5-turbo") response = model.invoke([ system_prompt, human_prompt ]) print(response.content)提示模板 (续) 批量翻译文本:for 循环与 ChatPromptTemplate 的结合
Section titled “提示模板 (续) 批量翻译文本:for 循环与 ChatPromptTemplate 的结合”- 结合
for循环,批量翻译文本。 - 示例:
for input in input_variables: response = model.invoke([ system_prompt_template.format( input_language=input["input_language"], output_language=input["output_language"] ), human_prompt_template.format( text=input["text"], style=input["style"] ) ]) print(response.content)- 借助
for循环,用同一个模板填入不同的值。 - 可一次性得到不同语言、不同风格的多个翻译结果。
- 提示模板:
SystemMessagePromptTemplate、AIMessagePromptTemplate、HumanMessagePromptTemplate。 - 简化:引入
ChatPromptTemplate。
ChatPromptTemplate 类
Section titled “ChatPromptTemplate 类”- 包含
from_messages方法:接收一系列消息,参数为列表。 - 列表元素代表消息的模板。
ChatPromptTemplate 类 (续) 使用invoke方法填入变量值
Section titled “ChatPromptTemplate 类 (续) 使用invoke方法填入变量值”- 要填入变量的值,调用模板的
invoke方法 - 接收字典作为参数
- 输入变量的值都可通过字典的键值对进行填入
ChatPromptTemplate的好处:- 所有角色消息文本里的变量值,可以一并填入
invoke调用后的结果:得到一个ChatPromptValue的实例ChatPromptValue聊天提示值,看成是未知变量值被填入后的聊天提示模板
获得模型的回应
Section titled “获得模型的回应”- 代码示例:
- ```python
model = ChatOpenAI(model=“gpt-3.5-turbo”)
response = model.invoke(prompt_value)
```
提示词工程 (续) 小样本提示 (Few-shot Prompting)
Section titled “提示词工程 (续) 小样本提示 (Few-shot Prompting)”- 小样本提示是一种非常好的方式,让AI快速适应新任务。
- 做法:把几个对话消息作为示例,跟随提示一起发给模型。
- 好处:
- 无需对模型进行任何训练。
- 成本低,又灵活。
- 示例格式:
role: "user":来自用户的提示例子。role: "assistant":来自AI的理想回答例子。- 观察发现:这些示例的格式通常大同小异,只有具体值存在差异。
- 利用模板:既然示例格式相似,也可以利用模板来构建小样本提示。
- LangChain支持:在
langchain.prompts模块里,有一个FewShotChatMessagePromptTemplate的类,专门用于构建小样本聊天提示。
提示模板 (Prompt Templates) (续) 小样本聊天提示模板
Section titled “提示模板 (Prompt Templates) (续) 小样本聊天提示模板”FewShotChatMessagePromptTemplate类:专门用于高效构建小样本聊天提示。- 接收两个主要参数:
example_prompt:一个提示模板,用于构建每个小样本示例的输入和输出消息。- 通常使用
ChatPromptTemplate.from_messages创建,包含human和ai两个角色的消息。 - 注意:这个模板不是用来构建最终用户提示的,而是用来构建对话示例部分的。
examples:一个列表,包含用于填充example_prompt中动态变量的值。- 列表中的每个元素都是一个字典,每个字典代表一个示例,键对应
example_prompt中的变量名,值是该变量的具体内容。
FewShotChatMessagePromptTemplate 类 (续) 使用示例
Section titled “FewShotChatMessagePromptTemplate 类 (续) 使用示例”- 创建
FewShotChatMessagePromptTemplate实例: - 传入
example_prompt和examples参数 - 前者格式化每个示例,后者提供示例值
- 最终提示词模板:
final_prompt_template - 包含小样本提示和人类给模型的提示
- 前者是示例,后者是实际问题
FewShotChatMessagePromptTemplate 类 (续) 使用示例
Section titled “FewShotChatMessagePromptTemplate 类 (续) 使用示例”- 创建
FewShotChatMessagePromptTemplate实例: - 传入
example_prompt和examples参数 - 前者格式化每个示例,后者提供示例值
- 最终提示词模板:
final_prompt_template - 包含小样本提示和人类给模型的提示
- 前者是示例,后者是实际问题
代码控制 AI 交互的优势 (续)
Section titled “代码控制 AI 交互的优势 (续)”- 对 AI 回复进行后续操作,如:
- 在网页上展示
- 提取信息
- 示例:品牌网站自动更新背景颜色
- 挑战:AI 生成内容的高确定性低
- AI 本质是根据概率生成内容
LangChain的Output Parser(输出解析器)
Section titled “LangChain的Output Parser(输出解析器)”- 解决AI生成内容格式不确定问题,提高从回复中提取信息的效率。
- 作用:
- 指令模型按指定格式输出。
- 解析模型输出,提取所需信息。
- 示例:从AI回复提取颜色色号。
- 使用
langchain.output_parsers模块下的CommaSeparatedListOutputParser,逗号分隔列表输出。 - 预期模型输出:由逗号分隔的元素组成的字符串,如``
- 易于解析为Python列表。
LangChain的Output Parser(输出解析器) (续)指令获取与解析
Section titled “LangChain的Output Parser(输出解析器) (续)指令获取与解析”- 确保模型按指定格式输出;
- 解析模型输出,提取所需信息。
- 创建
CommaSeparatedListOutputParser实例。 - 使用
get_format_instructions()方法获取解析器指令。 - 指令内容示例:
Your response should be a list of comma separated values, eg: 'foo, bar, baz'
LangChain的Output Parser(输出解析器) (续)数据解析
Section titled “LangChain的Output Parser(输出解析器) (续)数据解析”- 与提示对应:解析器需与给AI的指令相符。
- 示例:
CommaSeparatedListOutputParser给AI的指令是“回应应为逗号分隔的值”。 OutputParser.invoke(response):给invoke方法传入AI的回应,返回Python列表。
LangChain的Output Parser(输出解析器) (续)数据解析
Section titled “LangChain的Output Parser(输出解析器) (续)数据解析”- 与提示对应:解析器需与给AI的指令相符。
- 示例:
CommaSeparatedListOutputParser给AI的指令是“回应应为逗号分隔的值”。 OutputParser.invoke(response):给invoke方法传入AI的回应,返回Python列表。
LangChain的Output Parser(输出解析器) (续) JSON格式化输出
Section titled “LangChain的Output Parser(输出解析器) (续) JSON格式化输出”- 目的:希望AI能从文本描述中提取书籍的
书名、作者、体裁等信息,并以特定JSON格式返回。 - 示例JSON结构:
{ "book_name": "明朝那些事儿", "author_name": "当年明月", "genres": ["历史", "小说"]}- 要求:
- AI输出的
字段名(如book_name、author_name、genres)必须与预期匹配。 - AI输出的
值类型(如book_name是字符串,genres是字符串组成的列表)必须与预期匹配。 - 问题:
- 如果AI输出的字段名不匹配(如
genres输出成genre),代码将无法正确提取数据。 - 如果AI输出的值类型不匹配(如
genres不是字符串列表),也会导致解析失败。 - 解决方案:利用LangChain的
PydanticOutputParser来获得想要的JSON输出并进行解析。 - 引入:
from langchain.output_parsers import PydanticOutputParser - 功能:
PydanticOutputParser可以指导AI输出符合特定格式要求的JSON。
PydanticOutputParser 使用准备
Section titled “PydanticOutputParser 使用准备”- 需导入
BaseModel和Field: from langchain_core.pydantic_v1 import BaseModel, FieldBaseModel:创建数据模式,可理解为数据说明书。Field:为BaseModel里的属性提供额外信息和验证条件。Pydantic:验证数据满足特定格式和类型要求。- 例:验证
genres字段存在,且值为字符串组成的列表。
PydanticOutputParser 使用准备 (续)定义BookInfo类:
Section titled “PydanticOutputParser 使用准备 (续)定义BookInfo类:”- 继承自
BaseModel,表示书籍信息。 - 定义字段:
book_name(书名),author_name(作者),genres(体裁)。 - 使用类型注解指定字段类型:
str(字符串),List[str](字符串列表)。 - 示例:
from typing import Listfrom langchain_core.pydantic_v1 import BaseModel, Field
class BookInfo(BaseModel): book_name: str = Field(description="书籍的名字") author_name: str = Field(description="书籍的作者") genres: List[str] = Field(description="书籍的体裁")genres:List[str]表示字符串列表,需从typing库引入List。- 字段名后跟冒号和类型名,指定字段类型。
- 可用
Field函数为各字段补充描述信息,供AI参考。
PydanticOutputParser 使用准备 (续) 实例化与解析
Section titled “PydanticOutputParser 使用准备 (续) 实例化与解析”- 创建
PydanticOutputParser实例,参数为pydantic_object=BookInfo。 - 作用:要求模型根据字段输出
JSON,解析为BookInfo实例。 - 示例:
output_parser = PydanticOutputParser(pydantic_object=BookInfo)- 访问解析器指令:
output_parser.get_format_instructions() - 获取AI输出格式要求。
- 使用
str函数打印指令。 - 代码示例:
from typing import Listfrom langchain_core.pydantic_v1 import BaseModel, Fieldfrom langchain.output_parsers import PydanticOutputParser
class BookInfo(BaseModel): book_name: str = Field(description="书籍的名字", example="百年孤独") author_name: str = Field(description="书籍的作者", example="加西亚·马尔克斯") genres: List[str] = Field(description="书籍的体裁", example=["小说", "文学"])
output_parser = PydanticOutputParser(pydantic_object=BookInfo)print(output_parser.get_format_instructions())- 运行:打印AI输出格式,包括
JSON模式和字段描述。 - 指令:要求模型按各字段要求输出
JSON,解析成BookInfo实例。 - 使用
PydanticOutputParser,从AI得到符合格式和内容的JSON。 - 模型输出的
JSON字符串,解析成BookInfo实例。
PydanticOutputParser 使用示例
Section titled “PydanticOutputParser 使用示例”output_parser.get_format_instructions():获取要求模型返回的格式指令。- 指令示例:
The output should be formatted as a JSON instance that conforms to the JSON schema below.
As an example, for the schema {{"properties": {{"foo": {{"title": "Foo", "type": "string"}}}, "required": ["foo"]}}}the object {{"foo": "bar"}} is a well-formatted instance of the schema. The object {{"properties": {{"foo": {{"title": "Foo", "type": "string"}}}, "required": ["foo"]}}} is not well-formatted.
Here is the output schema:Here is the output schema:后续是JSON的描述,包括书名、作者、体裁等。- 提示:要根据要求的数据模式输出对应的
JSON结果。
LangChain 循环
Section titled “LangChain 循环”- 循环语句用于根据不同条件执行不同的代码块。
- 循环结构:
while循环:在条件为真时重复执行代码块。for循环:用于对列表、字典或字符串等可迭代对象中的元素进行迭代操作。- 循环例子:
- 对列表迭代:按顺序处理每个元素。
循环语句应用:for循环
Section titled “循环语句应用:for循环”- 可用于列表、字典、字符串等数据结构的迭代。
- 对列表迭代:按顺序处理每个元素。
使用PydanticOutputParser的好处
Section titled “使用PydanticOutputParser的好处”- 确保从AI得到各字段符合格式和内容要求的
JSON。 - 保证模型输出的
JSON字符串,解析成BookInfo实例。 - 示例:定义了
BookInfo类和PydanticOutputParser,使用get_format_instructions()方法获取解析器指令
PydanticOutputParser 知道想要的JSON长什么样即可
Section titled “PydanticOutputParser 知道想要的JSON长什么样即可”- 指导AI的脏活交给解析器
- 使用
ChatPromptTemplate消息提示模板,把给AI的消息列表写出来 - 第一条消息是系统提示,后续跟上用户提示
结合input()、if判断,制作查询流行语含义的电子词典程序 (续)二
Section titled “结合input()、if判断,制作查询流行语含义的电子词典程序 (续)二”- 使用
input()函数提示用户输入要查询的流行语:query = input("请输入您想查询的流行语:") - 使用
in判断用户输入的词条是否在字典里:if query in slang_dict: - 如果词条在字典里,打印:
print("您查询的" + query + "含义如下") - 获取
query的释义:slang_dict[query](字典名[键]) - 如果
query不在字典中,提示:print("词条不存在")
提示给模型,调用invoke方法
Section titled “提示给模型,调用invoke方法”- 将提示传给模型的
invoke方法运行,输出结果完全符合要求 - 字段数量、名字与
BookInfo定义的一致,各个值的数据类型也一致
PydanticOutputParser 的解析能力
Section titled “PydanticOutputParser 的解析能力”- JSON本质是字符串,从字符串提取信息麻烦,但从类实例提取信息简单
result = output_parser.invoke(response):直接传入模型回应,得到BookInfo实例PydanticOutputParser:将模型的回复直接解析成BookInfo的一个实例- 可轻松提取信息
LangChain组件的invoke方法
Section titled “LangChain组件的invoke方法”- 提示模板、聊天模型、输出解析器都调用
invoke方法。 invoke方法是LangChain表达式语言Runnable的通用调用方法。
- 对于
Prompt Template提示模板,invoke接收表示输入变量值的字典,返回Prompt Value提示值。
- 对于
Chat Model聊天模型,invoke接收提示值或聊天消息列表,返回聊天信息。
- 对于
Output Parser输出解析器,invoke接收聊天信息,返回解析结果(类型取决于解析器)。
LangChain 组件的 invoke 方法
Section titled “LangChain 组件的 invoke 方法”- 提示模板、聊天模型、输出解析器都调用
invoke方法。 invoke方法是LangChain表达式语言Runnable的通用调用方法。
- 对于
Prompt Template提示模板,invoke接收表示输入变量值的字典,返回Prompt Value提示值。
- 对于
Chat Model聊天模型,invoke接收提示值或聊天消息列表,返回聊天信息。
- 对于
Output Parser输出解析器,invoke接收聊天信息,返回解析结果(类型取决于解析器)。
LangChain 的 Chain 组件
Section titled “LangChain 的 Chain 组件”- 多个组件的一系列调用,简称LCEL
- 调用方法也叫
invoke invoke传入的参数是给第一个组件的参数- 每个组件把上一个组件的输出作为输入
- 链可组合出复杂的流程
- 通过 LangChain 表达式语言,组建之间的上下游关系能表现得很清晰
- 聊天模型 (
Chat Model) 可替换成LLM - 提示模板和输出解析器不是必须的
视频脚本生成器:侧边栏功能
Section titled “视频脚本生成器:侧边栏功能”- 项目1是一个视频脚本一键生成器。
- 侧边栏:允许用户提供自己的
OpenAI API密钥。 - 避免只消耗网站自己的
token。 - 附上官方网站,帮助用户了解如何获取
OpenAI API密钥。 - 可替换为其他大模型的密钥。
- 针对自用网站:可移除输入框,直接在请求代码里输入,后端代码替换模型。
视频脚本生成器页面介绍
Section titled “视频脚本生成器页面介绍”- 要求用户输入视频主题和脚本时长。
- 用户可输入任意主题和数字作为时长。
- 将信息结合自定提示词传给AI模型。
- 用户还需提供视频脚本的创造力,对应API的
temperature温度参数。 - 值越低,回答的随机性越低,创造性越低。
- 值越高,随机性和创造性越高,可能收到出乎意料的回答。
视频脚本生成器:提示词工程应用实例
Section titled “视频脚本生成器:提示词工程应用实例”- 网站首先判断用户是否提供 OpenAI API 密钥。
- 用户提供密钥后,点击“生成脚本”按钮。
- 使用加载组件告知用户AI正在思考。
- 获取AI回复后,告知用户视频脚本已生成。
- 显示视频标题和脚本内容。
- 工具不仅将信息告知AI,还调用了维基百科API。
- 用户点击维基百科搜索结果,可查看搜索内容。
- 这样做是为了让模型拥有更多知识。
视频脚本生成器:代码实现准备
Section titled “视频脚本生成器:代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI() - 后续代码:使用
OpenAI模型演示
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续) 返回值
Section titled “generate_script 函数 (续) 返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- 第一个参数:
subject(视频主题),例如"sora模型"。 - 第二个参数:
video_length(时长),例如1分钟。 - 第三个参数:
creativity(创造性),例如0.7。 - 第四个参数:
api_key(API 密钥)。
generate_script 函数 (续) API 密钥获取
Section titled “generate_script 函数 (续) API 密钥获取”- API 密钥可以通过导入
os模块,然后使用os.getenv("OPENAI_API_KEY")从环境变量中获取。 - 这种方式更安全,避免将密钥直接硬编码在代码中。
generate_script 函数 (续) 代码测试与结果展示
Section titled “generate_script 函数 (续) 代码测试与结果展示”- 添加
print(),确保函数在非Jupyter Notebook环境下正确输出结果。 - 运行代码,输出维基百科搜索结果和AI生成的视频标题、脚本内容。
- 警告信息:来自
WikipediaAPIWrapper,可忽略。
网站框架搭建
Section titled “网站框架搭建”- 使用
Streamlit框架快速搭建网站,并与AI模型互动。 Streamlit:简化网页开发流程,适合快速原型设计和数据可视化。- 核心流程:
- 准备:安装
Streamlit库。 - 设计:定义网站页面元素。
网站框架搭建
Section titled “网站框架搭建”- 使用
Streamlit框架快速搭建网站,并与AI模型互动。 Streamlit:简化网页开发流程,适合快速原型设计和数据可视化。- 核心流程:
- 准备:安装
Streamlit库。 - 设计:定义网站页面元素。
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续) 返回值
Section titled “generate_script 函数 (续) 返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- 第一个参数:
subject(视频主题),例如 `
网站框架搭建 (续)
Section titled “网站框架搭建 (续)”- 创建
main.py文件,用以表示网站的主页。 - 导入
streamlit库:import streamlit as st - 导入
utils.py中的generate_script函数:from utils import generate_script - 添加网页标题:
st.title("视频脚本生成器") - 运行命令:
streamlit run main.py
网站框架搭建 (续)侧边栏设置
Section titled “网站框架搭建 (续)侧边栏设置”- 为了让用户提供自己的
API密钥,在网页上加一个侧边栏 - 使用
streamlit的sidebar - 代码:
with st.sidebar:,后续缩进的内容在侧边栏显示 - 在侧边栏上加一个密钥输入框:
st.text_input() - 参数:给用户的提示内容字符串,如“请输入OpenAI API密钥”
st.text_input()的type="password"参数:输入内容默认不可见,点击小眼睛图标可查看。- 侧边栏添加链接:使用
st.markdown()函数。 st.markdown()允许在网页上添加markdown内容。- 链接的
markdown语法:[链接标签](实际地址)。 - 方括号
[]内放链接的标签(如 “获取OpenAI API密钥”)。 - 圆括号
()内放链接的实际地址(如https://platform.openai.com/account/api-keys)。
网站框架搭建 (续) 主页面设置
Section titled “网站框架搭建 (续) 主页面设置”- 需要用户提供视频的主题,添加
st.text_input() - 参数:给用户的提示词,例如 “请输入视频的主题”
- 将结果赋值给变量,如
subject - `subject = st.text_input(
网站框架搭建 (续) 主页面设置
Section titled “网站框架搭建 (续) 主页面设置”st.text_input()必须提供label参数,即给用户的提示信息。- 视频时长应为数字,使用
st.number_input()代替st.text_input()。 st.number_input()参数:- 第一个参数:
label,给用户的提示(例如:“请输入视频的大致时长(单位:分钟)”)。 min_value:最小值,例如0.1(时长必须是正数)。step:每次点击加减按钮时数值变化的步长,例如0.1。- 将
st.number_input()的返回值赋给video_length变量。
网站框架搭建 (续)主页面设置
Section titled “网站框架搭建 (续)主页面设置”st.number_input()参数:min_value:最小值,例如0.1(时长必须是正数)。step:每次点击加减按钮时数值变化的步长,例如0.1。- 将
st.number_input()的返回值赋给video_length变量。 - 网站中可调整AI回复的创造力:用
streamlit的slider组件 - 代码:
st.slider() - 参数:
- 提示文字
- 最小值:
0 - 最大值:
1,因为温度接近2时AI的语言可能会混乱 - 默认值:如
0.2 st.slider:min_value、max_value、value、step参数- 提示文字、数值范围、默认值
- 数值类型:
float(小数) Slider value arguments must be of matching typesmin_value、max_value、step类型需统一
网站框架搭建 (续) 添加按钮交互
Section titled “网站框架搭建 (续) 添加按钮交互”- 使用
streamlit的button函数创建按钮:`st.button(
网站框架搭建 (续) 添加按钮交互
Section titled “网站框架搭建 (续) 添加按钮交互”- 使用
streamlit的button函数创建按钮:st.button("生成脚本")。 - 点击按钮后,执行相应代码。
- 使用 if 语句判断按钮是否被点击:
if submit:。 - 代码:
if submit and not openai_api_key: st.info("请输入你的OpenAI API密钥")- 如果用户点击了生成脚本按钮,但没有提供API密钥,则在页面上展示提示信息。
- 使用
streamlit的info函数展示提示信息。 - 参数:要展示的提示内容字符串,例如 “请输入你的OpenAI API密钥”。
网站框架搭建 (续) st.stop() 的作用
Section titled “网站框架搭建 (续) st.stop() 的作用”st.stop(): 停止Streamlit应用在当前位置的执行,后续代码不会再被执行。
网站框架搭建 (续) 提交按钮的条件判断
Section titled “网站框架搭建 (续) 提交按钮的条件判断”- **检查&
OpenAI API&: if submit and not openai_api_key:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供OpenAI API密钥 (openai_api_key为空,not操作使其为True)。 st.info("请输入你的OpenAI API密钥"): 显示提示信息。st.stop(): 阻止程序继续执行,直到用户输入密钥。- 检查视频主题:
if submit and not subject:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供视频主题 (subject为空,not操作使其为True)。 st.info("请输入视频的主题"): 显示提示信息。st.stop(): 阻止程序继续执行,直到用户输入主题。- 演示:在网页端清除API密钥或视频主题后点击生成脚本,会看到相应的提示信息出现,且程序停止运行。
- 增加视频长度的条件判断:
if submit and not video_length >= 0.1: - 如果视频长度小于0.1分钟,提示用户。
st.number_input返回float类型,无需类型转换。
网站框架搭建 (续) 提交按钮的条件判断
Section titled “网站框架搭建 (续) 提交按钮的条件判断”- **检查&
OpenAI API&: if submit and not openai_api_key:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供OpenAI API密钥 (openai_api_key为空,not操作使其为True)。 - `st.info(
网站框架搭建 (续) 提交按钮的条件判断
Section titled “网站框架搭建 (续) 提交按钮的条件判断”- **检查&
OpenAI API&: if submit and not openai_api_key:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供OpenAI API密钥 (openai_api_key为空,not操作使其为True)。 - `st.info(
网站框架搭建 (续) 添加按钮交互(续)
Section titled “网站框架搭建 (续) 添加按钮交互(续)”st.spinner():显示加载状态,提示用户等待。- 参数:加载时显示的文字,如
AI正在思考中,请稍后... with st.spinner(...):代码块执行完,加载提示消失。generate_script():在with代码块里调用,执行时间较长。- 网页上会显示加载效果,提升用户体验。
- 调用
generate_script()函数生成结果,赋值给search_result、title、script变量。
网站框架搭建 (续) 结果展示
Section titled “网站框架搭建 (续) 结果展示”st.subheader(title):显示视频标题。st.write(script):显示视频脚本内容。st.caption(search_result):在脚本下方显示维基百科搜索结果。
网站框架搭建 (续) 链接维基百科内容
Section titled “网站框架搭建 (续) 链接维基百科内容”search_result:展示维基百科搜索结果。- 链接搜索结果,使用
st.markdown: st.markdown(f"[查看更多关于{title}的信息](https://zh.wikipedia.org/wiki/{title})")- 链接标题和维基百科搜索结果。
网站框架搭建 (续) 网站完整代码
Section titled “网站框架搭建 (续) 网站完整代码”- 网站完整代码:
import streamlit as stimport osfrom utils import generate_script
st.title("视频脚本生成器")
with st.sidebar: openai_api_key = st.text_input("请输入OpenAI API密钥", type="password") st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")
subject = st.text_input("请输入视频的主题")video_length = st.number_input("请输入视频的大致时长(单位:分钟)", min_value=0.1, step=0.1)creativity = st.slider("请输入视频脚本的创造力(数字越大说明创造力越强)", min_value=0.0, max_value=1.0, value=0.2, step=0.1)
submit = st.button("生成脚本")
if submit and not openai_api_key: st.info("请输入你的OpenAI API密钥") st.stop()
if submit and not subject: st.info("请输入视频的主题") st.stop()
if submit and not video_length >= 0.1: st.info("视频长度需要大于或等于0.1") st.stop()
if submit: with st.spinner("AI正在思考中,请稍候..."): search_result, title, script = generate_script(subject, video_length, creativity, openai_api_key)
st.subheader(title) st.write(script) st.caption(search_result) st.markdown(f"[查看更多关于{title}的信息](https://zh.wikipedia.org/wiki/{title})")网站框架搭建 (续) 代码演示
Section titled “网站框架搭建 (续) 代码演示”- 运行代码:
streamlit run main.py - 页面提示:请输入OpenAI API密钥,请输入视频的主题,视频长度需要大于或等于0.1
- 都填好后,点击生成脚本
- 页面生成:视频标题,视频脚本,查看更多关于xxx的信息
- 点击查看更多关于xxx的信息:可以跳转到维基百科
网站框架搭建 (续) 结果展示信息
Section titled “网站框架搭建 (续) 结果展示信息”st.spinner()停止后,展示结果。st.success("视频脚本已生成!"):显示视频脚本生成成功的提示信息。- 使用
st.subheader():显示视频标题。 - 使用
st.write():显示视频脚本内容。 - 使用
st.caption():在脚本下方显示维基百科的搜索结果。 st.markdown():创建链接,指向维基百科关于该主题的页面。
视频脚本生成器:代码实现(续)维基百科搜索结果组件
Section titled “视频脚本生成器:代码实现(续)维基百科搜索结果组件”- 使用
streamlit的expander组件,对应函数st.expander()。 - 可折叠搜索结果。
- 提示:在
streamlit中,使用with语句可创建各种组件:st.sidebar、st.expander等。 - 代码:
with st.expander("维基百科搜索结果"): st.info(search_result)st.info(search_result):把搜索结果也放在下面。st.expander:可让用户点击展开/折叠维基百科搜索结果。
网站框架搭建 (续) 维基百科搜索结果组件
Section titled “网站框架搭建 (续) 维基百科搜索结果组件”- 使用
streamlit的expander组件:st.expander()。 - 可折叠搜索结果。
- 提示:在
streamlit中,使用with语句可创建各种组件:st.sidebar、st.expander等。 - 代码:
with st.expander("维基百科搜索结果"): st.info(search_result)st.info(search_result):把搜索结果也放在下面。st.expander:可让用户点击展开/折叠维基百科搜索结果。
爆款小红书AI写作助手:网页实现
Section titled “爆款小红书AI写作助手:网页实现”- 侧边栏:允许用户提供自己的
OpenAI API密钥,附官方链接 - 主页:
- 简化,仅输入框和按钮
- 提示用户提供主题
- 用户未提供密钥或主题:提示用户
爆款小红书AI写作助手:网页实现
Section titled “爆款小红书AI写作助手:网页实现”- 侧边栏:允许用户提供自己的
OpenAI API密钥,附官方链接 - 主页:
- 简化,仅输入框和按钮
- 提示用户提供主题
- 用户未提供密钥或主题:提示用户
- 下载
requirements.txt文件到项目文件夹。 - 使用命令
pip install -r requirements.txt安装所有依赖项。
streamlitopenailangchainlangchain-openai- 创建
utils.py文件:存放AI交互代码 - 定义
generate_xiaohongshu函数: - 参数:
theme(主题),openai_api_key - 函数内,串联提示模板、模型、数据解析器
- AI返回5个标题和一个正文
- 借助LangChain的JSON数据解析器
爆款小红书AI写作助手:utils.py文件 (续) 提示模板设置
Section titled “爆款小红书AI写作助手:utils.py文件 (续) 提示模板设置”- 首先,需要定义所需的提示模板。
- 为避免非常长的文本(系统提示)与代码混在一起,建议新建一个单独的文件,例如
prompt_template.py,专门用于存放模板文本。 - 在
prompt_template.py中放入系统提示文本和用户提示文本。 - 与之前的 API 示例不同,这里没有指定输出格式,因为这部分将由
LangChain的输出解析器来完成。
爆款小红书AI写作助手:utils.py文件 (续)提示模板设置
Section titled “爆款小红书AI写作助手:utils.py文件 (续)提示模板设置”- 首先,需要定义所需的提示模板。
- 为避免非常长的文本(系统提示)与代码混在一起,建议新建一个单独的文件,例如
prompt_template.py,专门用于存放模板文本。 - 在
prompt_template.py中放入系统提示文本和用户提示文本。 - 与之前的 API 示例不同,这里没有指定输出格式,因为这部分将由
LangChain的输出解析器来完成。 - 因此,我们在这里插入了一个
parser_instructions,作为模板里面的变量。 - 它在后续就会被用来填入来自于输出解析器的格式指令。
- 可以导入刚才这两个提示模板内容。
- 使用
ChatPromptTemplate构建给AI的消息列表。 - 就需要从
LangChain的prompt模块里,导入ChatPromptTemplate。 - 然后新建一个叫做
prompt变量,还是去利用ChatPromptTemplate的from_messages方法。 - 它的参数是一个列表。
爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:
Section titled “爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:”- 指定
model为gpt-3.5-turbo - 从用户处获取
OpenAI API密钥 - 代码:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)- 将提示传给模型,调用
invoke方法
爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:
Section titled “爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:”- 指定
model为gpt-3.5-turbo - 从用户处获取
OpenAI API密钥 - 代码:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)- 将提示传给模型,调用
invoke方法 - 定义解析
AI返回结果的输出解析器:PydanticOutputParser PydanticOutputParser:从langchain的output_parsers模块导入- 使用
PydanticOutputParser从AI获得JSON格式输出 PydanticOutputParser能够实现强制的类型检查,确保解析出的数据符合我们的要求
爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:
Section titled “爆款小红书AI写作助手:utils.py文件 (续)定义ChatOpenAI模型:”- 指定
model为gpt-3.5-turbo - 从用户处获取
OpenAI API密钥 - 代码:
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)- 将提示传给模型,调用
invoke方法 - 定义解析
AI返回结果的输出解析器:PydanticOutputParser PydanticOutputParser:从langchain的output_parsers模块导入- 使用
PydanticOutputParser从AI获得JSON格式输出 PydanticOutputParser能够实现强制的类型检查,确保解析出的数据符合我们的要求
PydanticOutputParser 使用准备 (续)定义XiaoHongShu类:
Section titled “PydanticOutputParser 使用准备 (续)定义XiaoHongShu类:”- 继承自
BaseModel,表示小红书信息。 - 定义字段:
titles(标题列表),content(正文)。 titles是包含5个标题的列表,需从typing库引入List。- 示例:
from typing import Listfrom langchain_core.pydantic_v1 import BaseModel, Field
class XiaoHongShu(BaseModel): titles: List[str] content: strXiaoHongShu类的titles字段:类型是List[str](字符串列表)。titles字段的描述:Field(description="小红书的5个标题")。XiaoHongShu类的content字段:类型是str(字符串)。content字段的描述:Field(description="小红书的正文内容")。- 可以对
titles字段添加元素数量校验,强制其包含5个元素。
PydanticOutputParser 使用准备 (续)五:数量校验
Section titled “PydanticOutputParser 使用准备 (续)五:数量校验”titles: List[str] = Field(description="小红书的5个标题", min_items=5, max_items=5)min_items=5:限定列表最少5个元素max_items=5:限定列表最多5个元素- 限定后,AI必须给出5个标题,保证结果符合预期
- 完整代码:
from typing import Listfrom langchain_core.pydantic_v1 import BaseModel, Field
class XiaoHongShu(BaseModel): titles: List[str] = Field(description="小红书的5个标题", min_items=5, max_items=5) content: str = Field(description="小红书的正文内容")- 现在,数据模型就定义好了
- 回到
generate_xiaohongshu函数,把PydanticOutputParser写好 - 从刚才的文件里对
XiaoHongShu进行导入
from xiaohongshu_model import XiaoHongShu- 赋值给
pydantic_object:PydanticOutputParser(pydantic_object=XiaoHongShu)
generate_xiaohongshu 函数 (续)定义链:
Section titled “generate_xiaohongshu 函数 (续)定义链:”- 将提示模板、模型、输出解析器串联起来。
- 代码:
chain = prompt | model | output_parser- 触发链:调用
chain.invoke()方法。 - 参数:提示模板里面的变量的键值对。
parser_instructions:给AI的输出格式指令。- 对应于
output_parser的get_format_instructions方法所返回的结果。
爆款小红书AI写作助手:utils.py文件 (续)代码实现
Section titled “爆款小红书AI写作助手:utils.py文件 (续)代码实现”- 现在可以调用
generate_xiaohongshu函数进行测试 - 首先传入主题,如
今天穿什么,然后再传入OpenAI API密钥: generate_xiaohongshu(theme, openai_api_key)- 运行代码,查看返回结果是否符合预期
- 返回结果:包含5个标题和一个正文
- 至此,
utils.py文件的代码就全部完成了,可以用它跟streamlit代码相结合
爆款小红书AI写作助手:main.py文件
Section titled “爆款小红书AI写作助手:main.py文件”- 创建
main.py文件:用以表示网站的主页 - 导入
streamlit库:import streamlit as st - 导入
utils.py中的generate_xiaohongshu函数:from utils import generate_xiaohongshu - 添加网页标题:
st.title("小红书文案生成器")
爆款小红书AI写作助手:main.py文件 (续)侧边栏
Section titled “爆款小红书AI写作助手:main.py文件 (续)侧边栏”- 为了让用户提供自己的
API密钥,在网页上加一个侧边栏 - 使用
streamlit的sidebar - 代码:
with st.sidebar:,后续缩进的内容在侧边栏显示 - 在侧边栏上加一个密钥输入框:
st.text_input() - 参数:给用户的提示内容字符串,如“请输入OpenAI API密钥”
st.text_input()的type="password"参数:输入内容默认不可见,点击小眼睛图标可查看。- 侧边栏添加链接:使用
st.markdown()函数。 st.markdown()允许在网页上添加markdown内容。- 链接的
markdown语法:[链接标签](实际地址)。 - 方括号
[]内放链接的标签(如 “获取OpenAI API密钥”)。 - 圆括号
()内放链接的实际地址(如https://platform.openai.com/account/api-keys)。 - 代码示例:
st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")
爆款小红书AI写作助手:main.py文件 (续)网站主页
Section titled “爆款小红书AI写作助手:main.py文件 (续)网站主页”- 使用
st.text_input()提示用户提供主题 - 参数:给用户的提示词,例如 “请输入小红书的主题”
- 赋值给变量,如
theme
爆款小红书AI写作助手:main.py文件 (续)提交按钮与信息提示
Section titled “爆款小红书AI写作助手:main.py文件 (续)提交按钮与信息提示”- 使用
streamlit的button函数创建提交按钮:st.button("生成文案") - 使用
if语句判断按钮是否被点击:if submit: - 用户点击按钮,但未提供
API密钥或主题:提示用户 - 代码:
if submit and not openai_api_key: st.info("请输入你的OpenAI API密钥")
if submit and not theme: st.info("请输入小红书的主题")爆款小红书AI写作助手:main.py文件 (续)停止代码执行:st.stop()
Section titled “爆款小红书AI写作助手:main.py文件 (续)停止代码执行:st.stop()”- 用户未输入必要信息,阻止程序继续执行
- 代码:
if submit and not openai_api_key: st.info("请输入你的OpenAI API密钥") st.stop()
if submit and not theme: st.info("请输入小红书的主题") st.stop()爆款小红书AI写作助手:main.py文件 (续)调用generate_xiaohongshu函数
Section titled “爆款小红书AI写作助手:main.py文件 (续)调用generate_xiaohongshu函数”- 确保用户填写了所有必要信息
- 使用
st.spinner()显示“正在生成”提示,增强用户体验 - 调用
generate_xiaohongshu函数,生成小红书标题和正文: - 代码:`with st.spinner(“AI正在生成小红书文案中…”):
xiaohongshu_content = generate_xiaohongshu(theme, openai_api_key)`
爆款小红书AI写作助手:main.py文件 (续)结果展示
Section titled “爆款小红书AI写作助手:main.py文件 (续)结果展示”- 使用
st.subheader显示五个小红书标题 - 代码:
st.subheader("标题") - 使用
st.write显示正文内容 - 代码:
st.write(xiaohongshu_content.content) - 代码示例:
if submit: with st.spinner("AI正在生成小红书文案中..."): xiaohongshu_content = generate_xiaohongshu(theme, openai_api_key)
st.subheader("标题") for title in xiaohongshu_content.titles: st.write(f"- {title}")
st.subheader("正文") st.write(xiaohongshu_content.content)爆款小红书AI写作助手:网页完整代码
Section titled “爆款小红书AI写作助手:网页完整代码”- 现在,完整的
main.py代码如下:
import streamlit as stimport osfrom utils import generate_xiaohongshu
st.title("小红书文案生成器")
with st.sidebar: openai_api_key = st.text_input("请输入OpenAI API密钥", type="password") st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")
theme = st.text_input("请输入小红书的主题")
submit = st.button("生成文案")
if submit and not openai_api_key: st.info("请输入你的OpenAI API密钥") st.stop()
if submit and not theme: st.info("请输入小红书的主题") st.stop()
if submit: with st.spinner("AI正在生成小红书文案中..."): xiaohongshu_content = generate_xiaohongshu(theme, openai_api_key)
st.subheader("标题") for title in xiaohongshu_content.titles: st.write(f"- {title}")
st.subheader("正文") st.write(xiaohongshu_content.content)爆款小红书AI写作助手:运行与测试
Section titled “爆款小红书AI写作助手:运行与测试”- 运行程序:
streamlit run main.py - 程序运行后可进行测试
- 点击“生成文案”按钮:
- 如果没有输入
OpenAI API密钥或主题,程序会提示相应信息 - 如果都输入了,程序会开始生成小红书文案,并显示标题和正文内容
- 掌握了用
LangChain封装AI应用,并用Streamlit做用户界面 - AI不仅可做文本相关工作:图片、音频和视频的处理等
- AI的潜力等待发掘
- 恭喜你完成了本次课程的学习
爆款小红书AI写作助手:utils.py文件 (续) 测试函数及输出格式
Section titled “爆款小红书AI写作助手:utils.py文件 (续) 测试函数及输出格式”- 调用
generate_xiaohongshu,传入主题和API密钥 print输出结果,格式不是JSON,而是XiaoHongShu类的实例- 包含
titles属性:含有5个元素的列表
*generate_xiaohongshu 函数:
- 根据小红书主题返回5个待选标题及正文
- 返回值应为包含5个元素的列表和字符串的
content属性
- 网站后端逻辑已完成,接下来制作前端
- 使用
streamlit框架,或选择其他前端框架
网站框架搭建
Section titled “网站框架搭建”- 创建
main.py文件:用以表示网站的主页 - 导入
streamlit库:import streamlit as st - 导入
utils.py中的generate_xiaohongshu函数:from utils import generate_xiaohongshu - 添加网页标题:
st.header("爆款小红书AI写作助手") - 运行命令:
streamlit run main.py
爆款小红书AI写作助手:main.py文件 (续)侧边栏
Section titled “爆款小红书AI写作助手:main.py文件 (续)侧边栏”- 使用
streamlit的sidebar - 代码:
with st.sidebar:,后续缩进的内容在侧边栏显示 - 在侧边栏上加一个密钥输入框:
st.text_input() - 参数:给用户的提示内容字符串,如“请输入OpenAI API密钥”
st.text_input()的type="password"参数:输入内容默认不可见,点击小眼睛图标可查看。- 侧边栏添加链接:使用
st.markdown()函数。 st.markdown()允许在网页上添加markdown内容。- 链接的
markdown语法:[链接标签](实际地址)。 - 方括号
[]内放链接的标签(如 “获取OpenAI API密钥”)。 - 圆括号
()内放链接的实际地址(如https://platform.openai.com/account/api-keys)。 - 代码示例:
st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")
爆款小红书AI写作助手:main.py文件 (续)网站主页
Section titled “爆款小红书AI写作助手:main.py文件 (续)网站主页”- 使用
st.text_input()提示用户提供主题 - 参数:给用户的提示词,例如 “请输入小红书的主题”
- 赋值给变量,如
theme
爆款小红书AI写作助手:main.py文件 (续)网站主页
Section titled “爆款小红书AI写作助手:main.py文件 (续)网站主页”- 使用
st.text_input()提示用户提供主题 - 参数:给用户的提示词,例如 “请输入小红书的主题”
- 赋值给变量,如
theme - 再添加一个提交按钮:
submit = st.button(“开始写作”) - 用户未点击:返回
False。 - 点击后:返回
True。
网站框架搭建 (续) 添加按钮交互 (续) st.stop() 的作用
Section titled “网站框架搭建 (续) 添加按钮交互 (续) st.stop() 的作用”st.stop(): 停止Streamlit应用在当前位置的执行,后续代码不会再被执行。
网站框架搭建 (续) 提交按钮的条件判断
Section titled “网站框架搭建 (续) 提交按钮的条件判断”- **检查&
OpenAI API&: if submit and not openai_api_key:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供OpenAI API密钥 (openai_api_key为空,not操作使其为True)。 st.info("请输入你的OpenAI API密钥"): 显示提示信息。st.stop(): 阻止程序继续执行,直到用户输入密钥。- 检查视频主题:
if submit and not subject:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供视频主题 (subject为空,not操作使其为True)。 st.info("请输入视频的主题"): 显示提示信息。st.stop(): 阻止程序继续执行,直到用户输入主题。- 演示:在网页端清除API密钥或视频主题后点击生成脚本,会看到相应的提示信息出现,且程序停止运行。
- 增加视频长度的条件判断:
if submit and not video_length >= 0.1: - 如果视频长度小于0.1分钟,提示用户。
st.number_input返回float类型,无需类型转换。
爆款小红书AI写作助手:main.py文件 (续) 调用generate_xiaohongshu函数
Section titled “爆款小红书AI写作助手:main.py文件 (续) 调用generate_xiaohongshu函数”- 当用户点击“生成文案”按钮且所有前置条件(API密钥和主题)都满足时,调用
generate_xiaohongshu函数。 - 调用代码:
result = generate_xiaohongshu(theme, openai_api_key)。 theme:来自网页上用户输入的主题。openai_api_key:来自侧边栏用户输入的API密钥。generate_xiaohongshu函数的返回值是XiaoHongShu类的实例。- 这个实例包含了AI生成的5个标题(
titles属性,一个列表)和正文内容(content属性,一个字符串)。 - 后续可从
result对象中提取titles和content属性进行展示。
- 展示AI生成标题和正文
- 使用
st.divider()分隔主题提交区和AI内容生成区 - 采用多列布局:
st.columns(2) - 返回列表,分别赋值给
left_column和right_column
st.columns(2):创建双列布局left_column:显示小红书标题- 使用索引提取
result.titles列表中的元素,索引从0开始 - 示例:
st.write(result.titles[0]),提取第一个标题 right_column:显示小红书正文- 使用
st.markdown添加五级标题 - 使用
st.write展示result.content属性
- 采用多列布局:
st.columns(2) - 返回列表,分别赋值给
left_column和right_column - 侧边栏输入密钥,主页面输入主题,点击开始写作。
- 页面加载中,显示5个待选标题和正文。
实现小样本提示
Section titled “实现小样本提示”- 在
messages参数中: role为user:提示词示例。role为assistant:对应回复示例。- 示例:用户提示的
role值为user,AI回应的role值为assistant。 - 小样本示例能让AI快速适应新任务,且不需要对模型进行任何训练,成本低又灵活。
- 也能通过往消息列表里面塞入历史对话,让模型拥有之前的对话记忆。
LangChain 实现记忆功能
Section titled “LangChain 实现记忆功能”- LangChain 有现成方法处理记忆,如:
- 初始化记忆
- 存储历史对话
- 下一轮对话时传递给模型
- 初始化记忆:
- 导入
ConversationBufferMemory类:
from langchain.memory import ConversationBufferMemory- 创建实例:
memory = ConversationBufferMemory()- 存储历史对话:将用户提示或AI回应加入记忆
- 初始化时,设置
return_messages=True,确保存储为列表而非字符串:
memory = ConversationBufferMemory(return_messages=True)- 查看记忆内容:
memory.load_memory_variables({})
# 输出 {'history': []}- 传入空字典作为参数
history对应的值是一个空列表
LangChain 实现记忆功能 (续) save_context 方法
Section titled “LangChain 实现记忆功能 (续) save_context 方法”- 存储单轮对话,作为历史消息。
- 接收两个字典作为参数:
input(用户输入)和output(AI 输出)。 - 示例:
memory.save_context({"input": "我的名字是林粒呀"}, {"output": "你好,林粒粒"})LangChain 实现记忆功能 (续) load_memory_variables 方法
Section titled “LangChain 实现记忆功能 (续) load_memory_variables 方法”- 再次运行
load_memory_variables,可查看已储存对话。 - 示例代码:
memory.load_memory_variables({})- 输出:
{'history': [HumanMessage(content='我的名字是林粒呀'), AIMessage(content='你好,林粒粒')]}- 添加多轮对话:继续调用
save_context方法,再运行load_memory_variables,历史消息会增加。
LangChain 实现记忆功能 (续)提示模板
Section titled “LangChain 实现记忆功能 (续)提示模板”- 提示模板需留出空间给历史消息。
- 历史消息应放在当前这轮给
AI的提示前面,但系统消息除外。 - 示例:
prompt = ChatPromptTemplate.from_messages([ <...对话历史...> ("human", "{user_input}")])
# 如果有系统消息prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个乐于助人的助手。") <...对话历史...> ("human", "{user_input}")])提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息
Section titled “提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息”- 从
langchain.prompts导入MessagesPlaceholder - 用于表示消息列表的模板
- 示例:
from langchain.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个乐于助人的助手。"), MessagesPlaceholder(variable_name="history"), ("human", "{user_input}"), ])MessagesPlaceholder构造函数:variable_name参数表示消息列表名history:变量名,用于指代消息列表- 未填入值的变量都会有名字,如
user_input也是自定义的变量名 - 历史消息在名为
history的变量里 - 在提示模板里,留出之后填入历史消息的位置
手动保存历史对话与Conversation Chain:
Section titled “手动保存历史对话与Conversation Chain:”- 手动保存历史对话:
memory.save_context({"input": user_input}, {"output": result.content}) - 接收两个字典:
input(用户输入),output(AI输出) - 手动加载历史对话:
history = memory.load_memory_variables({})["history"] - 可通过记忆实现与AI的多轮对话
- LangChain 也实现了现成可用的带记忆的对话链,称为
Conversation Chain。
带记忆的对话链:ConversationChain
Section titled “带记忆的对话链:ConversationChain”- 用于对话,可从内存加载上下文。
- 创建:
- 创建模型和记忆。
- 使用
ConversationChain,参数llm设为模型,memory设为记忆。 - 使用:
invoke方法,参数为表示输入的字典。 - 给模型的提示放入
input键对应的值。 - 输出结果包含:
- 给模型的输入。
- 记忆的历史消息。
- AI 的回应。
ConversationChain (续) 提示模板
Section titled “ConversationChain (续) 提示模板”- 提示模板需留出空间给历史消息。
- 历史消息应放在当前给
AI的提示前面,但系统消息除外。 - 示例:
prompt = ChatPromptTemplate.from_messages([ <...对话历史...> ("human", "{user_input}")])
# 如果有系统消息prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个乐于助人的助手。") <...对话历史...> ("human", "{user_input}")])提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息
Section titled “提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息”- 从
langchain.prompts导入MessagesPlaceholder - 用于表示消息列表的模板
- 示例:
from langchain.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个乐于助人的助手。"), MessagesPlaceholder(variable_name="history"), ("human", "{user_input}"), ])MessagesPlaceholder构造函数:variable_name参数表示消息列表名history:变量名,用于指代消息列表- 未填入值的变量都会有名字,如
user_input也是自定义的变量名 - 历史消息在名为
history的变量里 - 在提示模板里,留出之后填入历史消息的位置
手动保存历史对话与Conversation Chain:
Section titled “手动保存历史对话与Conversation Chain:”- 手动保存历史对话:
memory.save_context({"input": user_input}, {"output": result.content}) - 接收两个字典:
input(用户输入),output(AI输出) - 手动加载历史对话:
history = memory.load_memory_variables({})["history"] - 可通过记忆实现与AI的多轮对话
- LangChain 也实现了现成可用的带记忆的对话链,称为
Conversation Chain。
带记忆的对话链:ConversationChain
Section titled “带记忆的对话链:ConversationChain”- 用于对话,可从内存加载上下文。
- 创建:
- 创建模型和记忆。
- 使用
ConversationChain,参数llm设为模型,memory设为记忆。 - 使用:
invoke方法,参数为表示输入的字典。 - 给模型的提示放入
input键对应的值。 - 输出结果包含:
- 给模型的输入。
- 记忆的历史消息。
- AI 的回应。
- 前面只给链传入了
llm模型和memory记忆作为参数,但对话链也支持指定提示模板 - 提示模板能把AI的人设设置成脾气暴躁,喜欢阴阳怪气的助手。
- 模板里,表示用户输入的信息的变量名必须是
input,表示历史消息的变量名必须是history。 - 要使用
ConversationChain,需要导入它:from langchain.chains import ConversationChain
LangChain 实现记忆功能 (续) save_context 方法
Section titled “LangChain 实现记忆功能 (续) save_context 方法”- 存储单轮对话,作为历史消息。
- 接收两个字典作为参数:
input(用户输入)和output(AI 输出)。 - 示例:
memory.save_context({"input": "我的名字是林粒呀"}, {"output": "你好,林粒粒"})LangChain 实现记忆功能 (续) load_memory_variables 方法
Section titled “LangChain 实现记忆功能 (续) load_memory_variables 方法”- 再次运行
load_memory_variables,可查看已储存对话。 - 示例代码:
memory.load_memory_variables({})- 输出:
{'history': [HumanMessage(content='我的名字是林粒呀'), AIMessage(content='你好,林粒粒')]}- 添加多轮对话:继续调用
save_context方法,再运行load_memory_variables,历史消息会增加。
LangChain 实现记忆功能 (续)提示模板
Section titled “LangChain 实现记忆功能 (续)提示模板”- 提示模板需留出空间给历史消息。
- 历史消息应放在当前这轮给
AI的提示前面,但系统消息除外。 - 示例:
prompt = ChatPromptTemplate.from_messages([ <...对话历史...> ("human", "{user_input}")])
# 如果有系统消息prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个乐于助人的助手。") <...对话历史...> ("human", "{user_input}")])提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息
Section titled “提示模板 (续) 使用 MessagesPlaceholder 类:插入历史消息”- 从
langchain.prompts导入MessagesPlaceholder - 用于表示消息列表的模板
- 示例:
from langchain.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个乐于助人的助手。"), MessagesPlaceholder(variable_name="history"), ("human", "{user_input}"), ])MessagesPlaceholder构造函数:variable_name参数表示消息列表名history:变量名,用于指代消息列表- 未填入值的变量都会有名字,如
user_input也是自定义的变量名 - 历史消息在名为
history的变量里 - 在提示模板里,留出之后填入历史消息的位置
手动保存历史对话与Conversation Chain:
Section titled “手动保存历史对话与Conversation Chain:”- 手动保存历史对话:
memory.save_context({"input": user_input}, {"output": result.content}) - 接收两个字典:
input(用户输入),output(AI输出) - 手动加载历史对话:
history = memory.load_memory_variables({})["history"] - 可通过记忆实现与AI的多轮对话
- LangChain 也实现了现成可用的带记忆的对话链,称为
Conversation Chain。
带记忆的对话链:ConversationChain
Section titled “带记忆的对话链:ConversationChain”- 用于对话,可从内存加载上下文。
- 创建:
- 创建模型和记忆。
- 使用
ConversationChain,参数llm设为模型,memory设为记忆。 - 使用:
invoke方法,参数为表示输入的字典。 - 给模型的提示放入
input键对应的值。 - 输出结果包含:
- 给模型的输入。
- 记忆的历史消息。
- AI 的回应。
记忆管理:ConversationBufferWindowMemory (续)设置k值和避免窗口上限
Section titled “记忆管理:ConversationBufferWindowMemory (续)设置k值和避免窗口上限”- 调整
k值: - 针对大上下文窗口模型:可增大
k值。 - 消息过长:为避免达到窗口上限,可减小
k值。 ConversationBufferWindowMemory的优势:- 若
k值合适,可一直进行对话。 - 无需担心记忆过多撑爆上下文窗口。
- 局限性:
- 最多储存
k轮消息,对话轮数超过时,最早的信息会丢失。
记忆管理:ConversationSummaryMemory
Section titled “记忆管理:ConversationSummaryMemory”- 目的:控制储存内容的长度,且不直接丢弃之前的对话。
- 方法:
ConversationSummaryMemory,总结历史对话内容而非直接存储原始消息。
ConversationSummaryMemory 记忆组件
Section titled “ConversationSummaryMemory 记忆组件”- 先总结历史对话内容,再存储总结。
- 总结需大模型参与。
- 创建实例需传入
llm(表示做总结的大语言模型)。 - 调用链的
invoke方法后,从输出结果的history可看到此次存储的不是原始消息列表,而是对话内容的总结字符串。 - 存储总结长度可能比原始消息短,更晚达到上下文窗口上限。
- 总结内容会变得比原始对话更精炼。
- 存储传达总结比
ConversationBufferMemory更好。
记忆管理:ConversationSummaryBufferMemory
Section titled “记忆管理:ConversationSummaryBufferMemory”- 结合了
ConversationSummaryMemory和ConversationBufferMemory。 - 给记忆指定
token数量上限:max_token_limit=1000 - 储存消息少:原封不动储存原始内容,像
ConversationBufferMemory。 - 储存消息多:
- 达到
token上限后,会把压缩的信息进行储存。 - 总结过程中可能丢失细节。
- 总结需要消耗
token。
记忆管理:ConversationSummaryBufferMemory (续) 结合
Section titled “记忆管理:ConversationSummaryBufferMemory (续) 结合”- 从名字来看,结合了
ConversationSummaryMemory和ConversationBufferMemory - 结合二者优点
- 为记忆指定
token数量上限 - 在存储的消息比较少的时候,它会原封不动的存储原始内容,像
ConversationBufferMemory一样 - 而当储存的消息变多,达到
token数量上限之后,它会把压缩的信息进行储存
记忆管理:ConversationSummaryBufferMemory (续)
Section titled “记忆管理:ConversationSummaryBufferMemory (续)”- 结合了
ConversationSummaryMemory和ConversationBufferMemory。 - 给记忆指定
token数量上限:max_token_limit=1000 - 储存消息少:原封不动储存原始内容,像
ConversationBufferMemory。 - 储存消息多:
- 达到
token上限后,会把压缩的信息进行储存。 - 总结过程中可能丢失细节。
- 总结需要消耗
token。 - 和
ConversationSummaryMemory不同,没有超过token上限的消息仍然可以储存原始内容。 - 在创建
ConversationSummaryBufferMemory的实例时,需要传入模型作为参数,因为总结任务也是交给大模型做。 - 还需要指定一个
max_token_limit,它表示的是我们允许存储的消息所占的token上限。 - 如果我们把
max_token_limit设为一个比较小的数字,当调用链后可以从history看到,进行几轮对话后,前面的消息就是以总结,而不是原始内容的形式被存储了。 ConversationSummaryBufferMemory的好处是,它和ConversationSummaryMemory一样。
记忆管理:ConversationTokenBufferMemory
Section titled “记忆管理:ConversationTokenBufferMemory”- 类似于
ConversationBufferWindowMemory,但有以下不同: ConversationBufferWindowMemory:看的是已存储的对话轮数。ConversationTokenBufferMemory:看的是已存储消息的token数。- 存储消息少:原封不动存储原始内容。
- 存储消息多:达到
token上限后,将压缩信息储存,但仍消耗token。 - 设置
max_token_limit限制token数,避免超出上下文窗口。 - 最近的消息有机会以原始内容储存,模型能记得更多细节。
- 总结任务仍需消耗额外的
token。 - 代码示例:
memory = ConversationTokenBufferMemory(llm=model, max_token_limit=2000, return_messages=True) chain = ConversationChain(llm=model, memory=memory)记忆管理:ConversationTokenBufferMemory (续)实用性
Section titled “记忆管理:ConversationTokenBufferMemory (续)实用性”- 这是一个很实用的记忆类型,因为它能**限制消息长度不超过设定&
token&)。 - 当前模型有明确的上下文窗口,且窗口长度以
token为单位计算。
记忆管理总结
Section titled “记忆管理总结”- 学习了五种不同的记忆类型:
ConversationBufferMemoryConversationSummaryMemoryConversationTokenBufferMemoryConversationBufferWindowMemoryConversationSummaryBufferMemory- 每种记忆都有优缺点,可根据具体需求选择。
项目三:AI聊天助手
Section titled “项目三:AI聊天助手”- 目标是制作一个仿照
ChatGPT或文心一言等工具的网站。 - 侧边栏:
- 允许用户提供自己的
OpenAI API Key进行内容生成。 - 附有可跳转的官方链接,指导用户如何获取
OpenAI API Key。 - 功能:
- 如果用户没有提供密钥,聊天功能不会开启。
- 会提示用户输入
API Key。
AI助手记忆功能演示
Section titled “AI助手记忆功能演示”- 用户提供
API密钥后,可与AI助手连续对话。 - AI的回答出现在用户提问的下方。
- AI具有记忆功能,能记住上下文,理解提问。
- 先前项目用户只与模型进行一次性互动,每次互动之间不存在关联。
- 现在的AI助手可以根据上下文进行连续对话。
实现带记忆的对话并不难
Section titled “实现带记忆的对话并不难”- 主要任务:完成给AI的请求
- 项目后端请求非常简单:把用户的提示给AI,获得AI的回应
- 需确保AI在回答前能够得到之前对话的内容,才能实现连贯对话
- 创建好项目文件夹后,从课程配套资料里,把
requirements.txt文件下载并拖进来 - 在终端输入
pip install -r requirements.txt,对所有的依赖进行安装
网站框架搭建 (续)代码实现准备
Section titled “网站框架搭建 (续)代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=api_key) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
- 从
langchain.chains导入ConversationChain - 定义模型后,定义
chain: - 赋值为
ConversationChain,参数llm和memory - 使用对话链的好处:自动加载记忆,更新对话记忆,无需手动操作
invoke 方法的参数
Section titled “invoke 方法的参数”- 给模型提示:放入
input键对应的值 chain.invoke():返回response字典,包含用户输入、历史对话、AI模型的回应- 只需AI模型的回应:`return response[
get_chat_response函数:- 第一个参数:用户消息内容,字符串。
- 第二个参数:
memory。 - 第三个参数:
API密钥,从电脑环境变量获取。 - 导入
ConversationBufferMemory: - 代码:
from langchain.memory import ConversationBufferMemory - 创建
memory对象:memory = ConversationBufferMemory(return_messages=True),return_messages=True确保存储为消息列表。
测试记忆功能
Section titled “测试记忆功能”print(get_chat_response("牛腩提出了哪些知名的定律?", memory, os.getenv("OPENAI_API_KEY")))- 确保记忆确实在发挥作用
- 紧跟发送一个请求,询问AI上一个问题问的是什么
print(get_chat_response("我上一个问题是什么?", memory, os.getenv("OPENAI_API_KEY")))- 确认AI记住了上一个问题
- 下一节将把克隆ChatGPT网站的前端做出来
搭建网站主页:main.py 文件
Section titled “搭建网站主页:main.py 文件”- 创建
main.py文件:表示网站主页。 - 导入库:
import streamlit as stfrom utils import get_chat_response- 网页标题:
st.title("我的AI聊天助手") - 运行命令:
streamlit run main.py
- 允许用户提供
API密钥(st.text_input)。 [获取OpenAI API密钥](https://platform.openai.com/account/api-keys)````[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)。
get_chat_response 函数
Section titled “get_chat_response 函数”- 创建
get_chat_response函数,根据用户消息给予对话回应。 - 后续创建对应网页页面。
- 部署应用后,其他用户也能随时随地使用此工具和AI对话。
- 移除或注释上一节测试
get_chat_response的代码。
网页标题和侧边栏设置
Section titled “网页标题和侧边栏设置”- 使用
streamlit的st.title()添加网页标题,如st.title("克隆ChatGPT") - 为用户提供
API密钥,使用streamlit的sidebar添加侧边栏:with st.sidebar: - 侧边栏添加密钥输入框:
st.text_input(),设置type="password"隐藏输入 - 侧边栏添加链接:
st.markdown(),使用markdown语法[链接标签](实际地址)
主页面设置和记忆初始化
Section titled “主页面设置和记忆初始化”- 需要如ChatGPT那样展示两个角色之间一来一回对话的内容,并需要有文本框给用户输入消息。
- 从
langchain.memory模块导入ConversationBufferMemory。 - 创建记忆实例:
memory = ConversationBufferMemory(return_messages=True) return_messages=True:确保储存的是消息列表,而不是字符串。- 在
main.py中,导入ConversationBufferMemory:
from langchain.memory import ConversationBufferMemory- 创建记忆实例:
memory = ConversationBufferMemory(return_messages=True)- 从
utils.py导入get_chat_response函数。 - 网站主页添加历史对话展示和用户输入消息的文本框。
解决记忆被重置的问题:会话状态
Section titled “解决记忆被重置的问题:会话状态”Streamlit会从头运行代码:- 修改源码
- 用户与组件交互(输入文本、点击按钮等)
- 若每次都创建记忆,则记忆会被重置,之前对话被清空
- 解决办法:借助会话状态(
session state) - 仅在会话状态里没有记忆时才初始化记忆
解决记忆被重置的问题:会话状态
Section titled “解决记忆被重置的问题:会话状态”Streamlit会从头运行代码:- 修改源码
- 用户与组件交互(输入文本、点击按钮等)
- 若每次都创建记忆,则记忆会被重置,之前对话被清空
- 解决办法:借助会话状态(
session state) - 仅在会话状态里没有记忆时才初始化记忆
memory] = ConversationBufferMemory(return_messages=True)`- essages``] = []`
- 用户一进来就能看到的来自AI的消息
- 使用
st.columns(2):创建双列布局 left_column:显示小红书标题- 使用索引提取
result.titles列表中的元素,索引从0开始 - 示例:
st.write(result.titles[0]),提取第一个标题 right_column:显示小红书正文- 使用
st.markdown添加五级标题 - 使用
st.write展示result.content属性
代码实现:历史对话展示
Section titled “代码实现:历史对话展示”- 使用
for循环迭代st.session_state[``messages]`: - 代码:`for message in st.session_state[
- 采用多列布局:
st.columns(2) - 返回列表,分别赋值给
left_column和right_column - 侧边栏输入密钥,主页面输入主题,点击开始写作。
- 页面加载中,显示5个待选标题和正文。
代码实现:历史对话展示
Section titled “代码实现:历史对话展示”- 使用
for循环迭代st.session_state["messages"]: - 代码:
for message in st.session_state["messages"]: st.chat_message(message["role"]).write(message["content"]):在页面上展示消息。- 根据
message的role属性,用不同的样式显示(模拟不同用户)。 - 添加用户输入框:
user_prompt = st.chat_input("有什么想问的?") st.chat_input():在页面底部创建一个文本输入框,等待用户输入。- 用户输入的内容会被赋值给
user_prompt变量。
会话状态初始化
Section titled “会话状态初始化”- 使用
st.session_state,在会话状态中创建memory和messages两个键: st.session_state["memory"]:用于存储对话记忆。st.session_state["messages"]:用于存储对话消息列表。- 代码示例:
if "memory" not in st.session_state: st.session_state["memory"] = ConversationBufferMemory(return_messages=True)if "messages" not in st.session_state: st.session_state["messages"] = [{"role": "ai", "content": "你好,我是你的AI助手,有什么可以帮你的吗?"}]- 只有当会话状态中没有“memory”时,才创建记忆对象,避免每次刷新页面都重置记忆。
- 同理,只有当会话状态中没有
messages时,才初始化消息列表,列表里放入一条来自AI的消息,作为初始提示。
"role": "ai", "content": "你好,我是你的AI助手,有什么可以帮你的吗?"- 消息列表的元素是字典,每个字典都有
role和content两个键,分别表示发言人的角色和发言内容。 st.chat_message()函数:展示对话内容,根据角色展示不同头像
展示历史消息
Section titled “展示历史消息”- 目的:在界面上展示历史对话
- 使用
st.session_state获取历史消息: st.session_state["messages"]:存储所有对话消息的列表- 循环遍历消息列表:
for message in st.session_state["messages"]: st.chat_message(message["role"]).write(message["content"])st.chat_message(message["role"]):根据消息角色(message["role"]),设置消息的显示样式(例如头像)。.write(message["content"]):将消息内容(message["content"])写入到对应的消息框中。
"role": "ai", "content": "你好,我是你的AI助手,有什么可以帮你的吗?"- 展示第一条初始消息
- 往页面传入角色和消息的内容
st.chat_message(message["role"]).write(message["content"])st.chat_message():根据角色,选择不同样式(头像)write():写入消息内容
message["content"]- 消息内容对应
message的content值 - 这样,页面上就会展示该角色说的话
- 针对第一条消息,这里传入的是AI字符串
- 保存后回到页面,成功展示初始消息
- 接下来,给用户提供一个输入框
- 使用
st.chat_input()添加用户输入框 st.chat_input("有什么想问的?"):提示用户输入消息,返回字符串- 前提:用户提供
OpenAI API密钥
存储用户输入
Section titled “存储用户输入”- 用户输入内容后,存储到
messages列表 - 格式:字典,含
role和content键 - 角色设置为
user:用于区分用户和AI - 内容:
user_prompt变量的值
st.session_state["messages"].append({"role": "user", "content": user_prompt})- 存储用户输入,在网页上展示用户输入内容
使用append添加用户输入的内容
Section titled “使用append添加用户输入的内容”- 使用
append,参数是新加入的元素 - 新加入的元素要和其他元素的类型和格式保持一致,也应该是一个包含
role和content键的字典 role的值可以是human表示人类content赋值为用户刚输入的内容- 将消息展示在页面上:调用
chat_message函数 - 参数对应角色,
human字符串 - 再调用
write,传入用户刚输入的内容 - 虽然这个网页还无法获得AI的回应,但用户输入的内容应该能展示在页面上了
添加加载组件
Section titled “添加加载组件”- 使用
st.spinner(),提示用户等待。 - 参数:加载时显示的文字,如
AI正在思考中,请稍后... with st.spinner(...):代码块执行完,加载提示消失。- 调用
get_chat_response()函数: - 传入用户消息、记忆和API密钥。
- 将结果赋值给
response变量。
现在前端就搞定了,页面上测试:输入密钥和消息,AI回应。
- AI已知先前问题内容。
- 与ChatGPT等AI助手一样,可实现连贯对话。
- 可增加功能:连带页面已有对话内容都清除掉。
训练数据的影响
Section titled “训练数据的影响”- 大语言模型知识受训练数据影响
- 小众领域:AI表现可能不尽如人意
- 公司内部数据、个人私密文件:不能作为公开大语言模型的训练数据
- 提供外部文档:模型访问外部知识库
检索增强生成 (RAG)
Section titled “检索增强生成 (RAG)”- 检索增强生成 (RAG):用户提出与外部知识相关问题后,AI结合知识库内容进行回答。
- RAG步骤:
- 准备外部数据:
- 外部文档需加载并切分为文本块,因大语言模型上下文窗口有限。
- 每个文本块转成一系列向量。向量可看作固定长度的数字串。
- 向量里包含文本间的语法、语义等关系。
- 相似文本对应嵌入向量,在向量空间里距离更近。
检索增强生成 (RAG) (续)准备外部数据:
Section titled “检索增强生成 (RAG) (续)准备外部数据:”- 向量化:文本块转换为向量,捕捉文本间的语义和语法关系。
- 向量数据库:存储向量,相似文本在向量空间距离更近。
RAG 步骤 (续)用户提问后搜索
Section titled “RAG 步骤 (续)用户提问后搜索”- 用户提问被转换为向量。
- 搜索向量数据库,找到与提问向量最接近的文本块向量。
- 距离近表示内容相似。
RAG 步骤 (续)询问模型
Section titled “RAG 步骤 (续)询问模型”- 将用户查询和最接近的文本块组合。
- 传递给AI模型。
- AI将外部文档段落作为上下文,基于其中的信息返回更准确的回答。
- 用户可对外部文档里任何内容进行提问。
检索增强生成 (续)RAG优势与局限
Section titled “检索增强生成 (续)RAG优势与局限”- RAG (检索增强生成): AI结合知识库回答问题
- 优势:能对接企业或个人知识库
- 局限:
- 响应速度慢,模型需处理整个文本
- 价格贵,大上下文窗口模型收费更高
- 在外部知识库不大的情况下,可直接将文本和问题给AI
RAG (续)
Section titled “RAG (续)”- 比上下文窗口小的模型收费更高
- 完整内容给到模型会消耗更多的
token - 外部知识库非常庞大,远超上下文窗口能容纳的大小,RAG就显得尤为重要了
- RAG不是一下子就能搞定的,需要借助多个组件配合完成
- 步骤:数据源 -> 加载 -> 分割 -> 嵌入 -> 储存 -> 检索
RAG 步骤 (续)数据源与加载
Section titled “RAG 步骤 (续)数据源与加载”- 数据源:本地文件、网站、数据库等。
- 加载:使用 Document Loader 从各种来源加载内容。
- Document Loader:负责从各种来源加载内容到程序组件。
- 位于
langchain_community.document_loaders模块下。 - 多种文档加载器,例如:
TextLoader(纯文本)。 - 纯文本:不包含粗体、斜体、字号等格式的文本。
- 示例:
TXT文件。
from langchain_community.document_loaders import TextLoader
loader = TextLoader("./demo.txt")docs = loader.load()print(docs)load()方法加载文本内容。- 输出是一个列表。
RAG 步骤 (续)数据源与加载 (续)PDF文件加载示例:
Section titled “RAG 步骤 (续)数据源与加载 (续)PDF文件加载示例:”- 需先安装
PyPDF库: Jupyter:!pip install pypdfWindows:pip install pypdfmacOS:pip3 install pypdf- 导入
PyPDFLoader:from langchain_community.document_loaders import PyPDFLoader - 使用示例:
loader = PyPDFLoader("./论文介绍.pdf")docs = loader.load()print(docs)- 加载过程与
TXT文件基本一致,需安装额外库。
RAG 步骤 (续)数据源与加载 (续)维基百科加载示例:
Section titled “RAG 步骤 (续)数据源与加载 (续)维基百科加载示例:”- 需先安装
wikipedia库: Jupyter:!pip install wikipediaWindows:pip install wikipediamacOS:pip3 install wikipedia- 导入
WikipediaLoader:from langchain_community.document_loaders import WikipediaLoader - 使用示例:
from langchain_community.document_loaders import WikipediaLoader
loader = WikipediaLoader(query="颐和园", lang="zh")docs = loader.load()print(docs)query参数:指定维基百科的词条名,让加载器知道加载哪个词条的内容lang参数:指定语言,zh表示中文- 需安装额外库
- 加载后会返回一个列表
RAG 步骤 (续)数据源与加载 (续)维基百科加载示例:
Section titled “RAG 步骤 (续)数据源与加载 (续)维基百科加载示例:”- 需先安装
wikipedia库: Jupyter:!pip install wikipediaWindows:pip install wikipediamacOS:pip3 install wikipedia- 导入
WikipediaLoader:from langchain_community.document_loaders import WikipediaLoader - 使用示例:
from langchain_community.document_loaders import WikipediaLoader
loader = WikipediaLoader(query="颐和园", lang="zh", load_max_docs=3)docs = loader.load()print(docs)query参数:指定维基百科的词条名,让加载器知道加载哪个词条的内容lang参数:指定语言,zh表示中文load_max_docs参数:指定加载几个相关条目- 需安装额外库
- 加载后会返回一个列表
- 列表里
Document实例的数量应符合load_max_docs参数的要求 - LangChain 支持的文档加载器:覆盖多种类别,包括
JSON、CSV、Word、PPT等文档格式,以及X、YouTube、GitHub等互联网内容 - 文档加载器的列表相当之长,可在LangChain官方文档的
langchain_community.document_loaders查看
RAG 步骤 (续)数据分割
Section titled “RAG 步骤 (续)数据分割”- 加载后,将长文档分割成更小的块
- 文本分割Chunking:确保每个块有意义,且不超过模型上下文窗口限制
- 文本分割器:
langchain.text_splitter
RAG 步骤 (续) 分割文本
Section titled “RAG 步骤 (续) 分割文本”- 上一步加载文档内容后,需要分割内容,以便于后续嵌入。
- 文本分割器:负责分割文本。
文本分割器考虑因素
Section titled “文本分割器考虑因素”- 文本分割器听起来简单,但实际要考虑:
- 语义相关性:保证分割后的文本块有意义,避免破坏句子或段落结构。
- 文本块大小:控制文本块的长度,以便适应模型的上下文窗口限制。
文本分割器类型:
Section titled “文本分割器类型:”- 位于
langchain.text_splitter模块下。 CharacterTextSplitter:按字符分割。RecursiveCharacterTextSplitter:递归按字符分割。
文本分割器类型:CharacterTextSplitter
Section titled “文本分割器类型:CharacterTextSplitter”- 按单个字符分割文本。
- 默认分隔符:
\n\n(双换行符),通常用于分隔段落。 - 其他常用参数:
chunk_size:每个文本块的最大长度(字符数)。chunk_overlap:文本块之间的重叠长度,有助于保持上下文连贯性。separator:分隔符,默认为\n\n。CharacterTextSplitter的实际使用:- 保证分割后的文本块有意义,语义上也比较完整,但也要确保分割后的文本块的大小不能太长,不能超过我们大语言模型的上下文窗口长度的上限。
文本分割器类型:RecursiveCharacterTextSplitter
Section titled “文本分割器类型:RecursiveCharacterTextSplitter”- 递归分割文本。
- 尝试按不同分隔符分割文本,直到文本块足够小。
- 分隔符列表:默认为
[“\n\n”, “\n”, “ “, “”]。 - 递归尝试:先按
\n\n分割,若文本块过大,则尝试按\n分割,以此类推。 - 保证每个文本块尽可能小,且语义信息完整。
- 适用于处理长文本,并希望尽可能保留文本结构的场景。
- 使用示例:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
# Set a really small chunk size, just to show. chunk_size = 100, chunk_overlap = 20, length_function = len, is_separator_regex = False, )
chunk = text_splitter.create_documents([raw_text])[0]
print(chunk.page_content)文本分割器:长度计算函数
Section titled “文本分割器:长度计算函数”- 默认长度函数:
len(),按字符数计算文本块长度。 - 可自定义长度函数:如按
token数计算,更符合大语言模型处理逻辑。 - 使用
tiktoken库: - 安装:
pip install tiktoken - 代码示例:
import tiktoken
def tiktoken_len(text): tokenizer = tiktoken.get_encoding("cl100k_base") tokens = tokenizer.encode(text) return len(tokens)
text_splitter = RecursiveCharacterTextSplitter( chunk_size=200, chunk_overlap=0, length_function=tiktoken_len)- 使用自定义的
tiktoken_len函数,可更准确控制文本块的token数,避免超出上下文窗口限制。
文本分割器:其他参数
Section titled “文本分割器:其他参数”is_separator_regex:是否将分隔符视为正则表达式。- 默认值为
False,表示分隔符是普通字符串。 - 设置为
True:分隔符是正则表达式,可实现更灵活的分割。
RAG步骤 (续)嵌入(Embeddings)
Section titled “RAG步骤 (续)嵌入(Embeddings)”- 分割文本后,需将文本转换为向量。
- 向量:包含文本的语义和语法信息,用于后续的相似性搜索。
- 嵌入模型(Embedding Model):负责将文本转换为向量。
- 嵌入模型:将文本转换为向量
- 文本向量化:捕捉语义信息,便于后续搜索
- 嵌入模型:例如 OpenAI Embeddings
- 嵌入模型:将文本转换为向量
- 文本向量化:捕捉语义信息,便于后续搜索
- 嵌入模型:例如 OpenAI Embeddings
- 从
langchain_openai导入OpenAIEmbeddings:from langchain_openai import OpenAIEmbeddings - 创建嵌入模型:
- 默认使用
text-embedding-ada-002模型,这是一个常用的嵌入模型 - 代码示例:
embedding = OpenAIEmbeddings() - API密钥通过环境变量自动获取,也可手动传入
openai_api_key参数 - 如果模型未返回结果:
- 检查API密钥是否正确,是否正确设置环境变量
- 当前账号是否有权限使用该模型
嵌入模型调用:embed_documents 方法
Section titled “嵌入模型调用:embed_documents 方法”embed_documents方法:将一组文本转换为向量。- 参数:文本列表。
- 返回值:向量列表,每个向量对应一个文本。
- 示例代码:
from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings()
text_list = [ "我是第一句话", "我是第二句话", "我是第三句话",]
result = embedding.embed_documents(text_list)
print(result)- 结果:得到一个向量列表,每个向量都是一个长度为1536的数组。
嵌入模型调用:embed_query 方法
Section titled “嵌入模型调用:embed_query 方法”embed_query方法:将单个文本转换为向量。- 参数:文本字符串。
- 返回值:向量(一个长度为1536的数组)。
- 示例代码:
from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings()
text = "我是文本"
result = embedding.embed_query(text)
print(result)- 嵌入模型:将文本转换为向量,供后续使用。
RAG 步骤 (续) 向量数据库:持久化存储向量
Section titled “RAG 步骤 (续) 向量数据库:持久化存储向量”- 向量数据库:用于存储向量,并提供高效的相似性搜索功能。
- LangChain 支持多种向量数据库,包括:
ChromaFAISSPineconeWeaviate- 选择向量数据库:根据自身需求和偏好选择。
RAG 步骤 (续) 向量数据库:Chroma
Section titled “RAG 步骤 (续) 向量数据库:Chroma”Chroma:轻量级、易于使用的向量数据库,适合快速原型验证和小型项目。- 特点:
- 纯 Python 实现,无需额外依赖。
- 支持内存存储和持久化存储。
- 使用步骤:
- 安装:
pip install chromadb - 导入:
from langchain_chroma import Chroma - 创建:
vectordb = Chroma.from_documents(documents=docs, embedding=embedding, persist_directory=persist_directory)
documents:需要存储的文档列表。embedding:使用的嵌入模型。persist_directory:持久化存储目录(可选)。- 持久化存储:
- 将向量数据存储到硬盘上,下次启动程序时可直接加载,无需重新计算。
- 示例:`persist_directory =
RAG 步骤 (续)数据分割
Section titled “RAG 步骤 (续)数据分割”- 加载后,将长文档分割成更小的块
- 文本分割Chunking:确保每个块有意义,且不超过模型上下文窗口限制
- 文本分割器:
langchain.text_splitter - 分割关键:AI要能理解分割出的独立文本块,避免半句话或三分之一句话
- LangChain 常用的分割器:
RecursiveCharacterTextSplitter(字符递归分割器) - 可指定根据什么符号分割,如换行符、句号、感叹号等
- 安装:
!pip install langchain-text-splitters - 导入:
from langchain.text_splitters import RecursiveCharacterTextSplitter - 创建实例:
text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, # 每块文本的最大长度 chunk_overlap=40, # 块与块之间的重叠长度 separators=[`"\n\n"`, `"\n"`, `"。"`, `"!"`, `"?"`, `" "`, `""`])chunk_size:每块文本的最大长度chunk_overlap:块与块之间的重叠长度,避免信息丢失separators:分割的依据,如换行符、句号等
文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明
Section titled “文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明”chunk_size:每块文本的最大长度,如500。chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。- 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
- “”]``
- 保证每个文本块尽可能小且语义完整。
RAG 步骤 (续)数据分割 (续)参数说明
Section titled “RAG 步骤 (续)数据分割 (续)参数说明”chunk_size:每块文本的最大长度,如500。chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。- 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
- ``“”
]\` - 保证每个文本块尽可能小且语义完整。
RAG 步骤 (续) 数据分割 (续)更多参数
Section titled “RAG 步骤 (续) 数据分割 (续)更多参数”- 运行
texts = text_splitter.split_documents(docs):分割文档,得到文本块列表texts。
RAG 步骤 (续) 嵌入 (Embeddings)
Section titled “RAG 步骤 (续) 嵌入 (Embeddings)”- 将文本转换为向量。
- 向量:包含文本的语义和语法信息。
- 用于后续的相似性搜索。
- 嵌入模型:负责将文本转换为向量。
- 从
langchain_openai导入OpenAIEmbeddings:from langchain_openai import OpenAIEmbeddings - 创建嵌入模型:
embedding = OpenAIEmbeddings() - 默认使用
text-embedding-ada-002模型。 - 密钥从环境变量自动获取,也可手动传入
openai_api_key参数。 - 使用
embed_documents方法:将一组文本转换为向量。 - 使用
embed_query方法:将单个文本转换为向量。
RAG 步骤 (续) 向量数据库
Section titled “RAG 步骤 (续) 向量数据库”- 向量数据库:存储向量,提供相似性搜索。
Chroma:轻量级易用,适合原型验证。- 使用步骤:
- 安装:
pip install chromadb - 导入:
from langchain_chroma import Chroma - 创建:
vectordb = Chroma.from_documents(documents=docs, embedding=embedding, persist_directory=persist_directory)
- 持久化存储:
- 将向量数据存储到硬盘上,下次启动程序可直接加载。
- 示例:
persist_directory = "db"。
RAG 步骤 (续)数据分割 (续)参数说明
Section titled “RAG 步骤 (续)数据分割 (续)参数说明”chunk_size:每块文本的最大长度,如500。chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。- 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
- ``“”`]
- 保证每个文本块尽可能小且语义完整。
RAG 步骤 (续) 嵌入 (Embeddings) (续) 嵌入模型调用示例:
Section titled “RAG 步骤 (续) 嵌入 (Embeddings) (续) 嵌入模型调用示例:”from langchain_openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings()
text = "我是文本"
result = embedding.embed_query(text)
print(result)- 嵌入模型:将文本转换为向量,供后续使用。
RAG 步骤 (续) 向量数据库:持久化存储向量
Section titled “RAG 步骤 (续) 向量数据库:持久化存储向量”- 向量数据库:用于存储向量,并提供高效的相似性搜索功能。
- LangChain 支持多种向量数据库,包括:
ChromaFAISSPineconeWeaviate- 选择向量数据库:根据自身需求和偏好选择。
RAG 步骤 (续) 向量数据库:Chroma
Section titled “RAG 步骤 (续) 向量数据库:Chroma”Chroma:轻量级、易于使用的向量数据库,适合快速原型验证和小型项目。- 特点:
- 纯 Python 实现,无需额外依赖。
- 支持内存存储和持久化存储。
- 使用步骤:
- 安装:
pip install chromadb - 导入:
from langchain_chroma import Chroma - 创建:
vectordb = Chroma.from_documents(documents=docs, embedding=embedding, persist_directory=persist_directory)
documents:需要存储的文档列表。embedding:使用的嵌入模型。persist_directory:持久化存储目录(可选)。- 持久化存储:
- 将向量数据存储到硬盘上,下次启动程序时可直接加载,无需重新计算。
- 示例:
persist_directory = "db"。
RAG 步骤 (续)数据分割
Section titled “RAG 步骤 (续)数据分割”- 加载后,将长文档分割成更小的块
- 文本分割Chunking:确保每个块有意义,且不超过模型上下文窗口限制
- 文本分割器:
langchain.text_splitter - 分割关键:AI要能理解分割出的独立文本块,避免半句话或三分之一句话
- LangChain 常用的分割器:
RecursiveCharacterTextSplitter(字符递归分割器) - 可指定根据什么符号分割,如换行符、句号、感叹号等
- 安装:
!pip install langchain-text-splitters - 导入:
from langchain.text_splitters import RecursiveCharacterTextSplitter - 创建实例:
text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, # 每块文本的最大长度 chunk_overlap=40, # 块与块之间的重叠长度 separators=["\n\n", "\n", "。", "!", "?", " ", ""])chunk_size:每块文本的最大长度chunk_overlap:块与块之间的重叠长度,避免信息丢失separators:分割的依据,如换行符、句号等
文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明
Section titled “文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明”chunk_size:每块文本的最大长度,如500。chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。- 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
- ``“”`]
- 保证每个文本块尽可能小且语义完整。
RAG 步骤 (续)数据分割 (续)参数说明
Section titled “RAG 步骤 (续)数据分割 (续)参数说明”chunk_size:每块文本的最大长度,如500。chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。- 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
- ``“”`]
- 保证每个文本块尽可能小且语义完整。
RAG 步骤 (续) 嵌入 (Embeddings)
Section titled “RAG 步骤 (续) 嵌入 (Embeddings)”- 将文本转换为向量。
- 向量:包含文本的语义和语法信息。
- 用于后续的相似性搜索。
- 嵌入模型:负责将文本转换为向量。
- 从
langchain_openai导入OpenAIEmbeddings:from langchain_openai import OpenAIEmbeddings - 创建嵌入模型:
embedding = OpenAIEmbeddings() - 默认使用
text-embedding-ada-002模型。 - 密钥从环境变量自动获取,也可手动传入
openai_api_key参数。 - 使用
embed_documents方法:将一组文本转换为向量。 - 使用
embed_query方法:将单个文本转换为向量。
RAG 步骤 (续) 向量数据库
Section titled “RAG 步骤 (续) 向量数据库”- 向量数据库:存储向量,提供相似性搜索。
Chroma:轻量级易用,适合原型验证。- 使用步骤:
- 安装:
pip install chromadb - 导入:
from langchain_chroma import Chroma - 创建:
vectordb = Chroma.from_documents(documents=docs, embedding=embedding, persist_directory=persist_directory)
- 持久化存储:
- 将向量数据存储到硬盘上,下次启动程序可直接加载。
- 示例:
persist_directory = "db"。
RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库
Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库”- 传统数据库:
- 精确匹配机制,适合结构化信息查询
- 不适合非结构化信息
- 向量数据库:
- 基于向量相似度进行查询,适合非结构化信息
- 结构化信息:
- 有预定义数据模型的信息
- 例如:员工信息(工号,入职日期,级别)
- 非结构化信息:
- 没有预定义数据模型的信息
- 例如:文本、图片、音频、视频等
- 向量数据库:
- 语义搜索,找到相似的文本块
- 应用于非结构化数据
RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库
Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库”- 传统数据库:
- 精确匹配机制,适合结构化信息查询
- 不适合非结构化信息
- 向量数据库:
- 基于向量相似度进行查询,适合非结构化信息
- 结构化信息:
- 有预定义数据模型的信息
- 例如:员工信息(工号,入职日期,级别)
- 非结构化信息:
- 没有预定义数据模型的信息
- 例如:文本、图片、音频、视频等
- 向量数据库:
- 语义搜索,找到相似的文本块
- 应用于非结构化数据
RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库
Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库”- 传统数据库:
- 精确匹配机制,适合结构化信息查询
- 不适合非结构化信息
- 向量数据库:
- 基于向量相似度进行查询,适合非结构化信息
- 结构化信息:
- 有预定义数据模型的信息
- 例如:员工信息(工号,入职日期,级别)
- 非结构化信息:
- 没有预定义数据模型的信息
- 例如:文本、图片、音频、视频等
- 向量数据库:
- 语义搜索,找到相似的文本块
- 应用于非结构化数据
RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库
Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)传统数据库 vs 向量数据库”- 传统数据库:
- 精确匹配机制,适合结构化信息查询
- 不适合非结构化信息
- 向量数据库:
- 基于向量相似度进行查询,适合非结构化信息
- 结构化信息:
- 有预定义数据模型的信息
- 例如:员工信息(工号,入职日期,级别)
- 非结构化信息:
- 没有预定义数据模型的信息
- 例如:文本、图片、音频、视频等
- 向量数据库:
- 语义搜索,找到相似的文本块
- 应用于非结构化数据
RAG 步骤 (续) 向量数据库:Chroma (续)FAISS
Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)FAISS”- 从
langchain_community.vectorstores导入FAISS - 向量数据库,可用它来做相似性搜索
- 代码示例:
db = FAISS.from_documents(texts, embeddings_model) texts:切割后的文档列表embeddings_model:嵌入模型的实例- 使用向量数据库的
as_retriever方法得到检索器 - 检索器:用于从大量文本中快速检索相关信息的组件
- 由于检索器也是
Runnable,说明可以调用它的invoke方法 - 示例:`retrieved_docs = retriever.invoke(
RAG 步骤 (续)检索器
Section titled “RAG 步骤 (续)检索器”- 使用向量数据库的
as_retriever方法得到检索器 - 检索器:用于从大量文本中快速检索相关信息的组件
- 由于检索器也是
Runnable,说明可以调用它的invoke方法 - 示例:
retrieved_docs = retriever.invoke("卢浮宫这个名字怎么来的?") - 传入文本,返回检索到的相关段落
- 文本与向量数据库里的文本块相似性高
- 示例:
retrieved_docs[0].page_content retriever.invoke("卢浮宫在哪年被命名为中央艺术博物馆")- 也能获得相关文本块
| 方法 | 描述 |
| ——— | ––––––––––– |
| read | 返回全部文件内容的字符串 |
| readline | 返回一行文件内容的字符串 |
| readlines | 返回全部文件内容组成的列表 |
- 证明相似性搜索还是比较靠谱的
RAG 步骤 (续) 询问模型
Section titled “RAG 步骤 (续) 询问模型”- 要得到AI对问题的回答:
- 需要把搜索出的相关文本片段和查询请求结合到一起,一块传给AI
- 结合提示模板和记忆
- 也许不需要那么麻烦
检索增强生成对话链:ConversationalRetrievalChain
Section titled “检索增强生成对话链:ConversationalRetrievalChain”- LangChain构建的用于检索增强生成的对话链,可从
langchain.chains模块导入: from langchain.chains import ConversationalRetrievalChain- 假设已完成文档切割和向量化,得到文档检索器。
- 大语言模型是核心,创建聊天模型实例:
model = ChatOpenAI(model="gpt-3.5-turbo")- 拥有模型和检索器后,还需记忆组件实现连续对话。
- 记忆组件类型可根据需求选择,但需设置
return_messages=True。 memory_key赋值为chat_historyoutput_key也要赋值为answerConversationalRetrievalChain储存历史消息的变量叫做chat_history- AI模型的输出对应着
answer键的值 - 调用
ConversationalRetrievalChain的from_llm方法 - 将
llm参数赋值为聊天模型 - 将
retriever参数赋值为上一节里通过调用向量储存的as_retriever方法得到的检索器 - 将
memory参数赋值为刚才创建好的记忆 - 能够帮我们实现RAG的对话链就准备好了
- 仍然是通过
invoke方法
result = qa.invoke({"chat_history": memory, "query": query})- 传入
chat_history和query
检索增强生成对话链:ConversationalRetrievalChain (续)参数解释
Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)参数解释”- 传入
chat_history和query:ConversationalRetrievalChain需要chat_history和question作为键。 chat_history:对应记忆。question:对应用户查询。- 链在处理对话时,使用
chat_history键来访问和更新对话历史。 - 赋值给创建好的记忆。
question参数赋值为用户查询的字符串即可。invoke返回字典:answer对应来自AI的回应,question对应来自用户的问题。- 对话也会被自动加入
chat_history对应的记忆里。
检索增强生成对话链:ConversationalRetrievalChain (续)
Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)”- 从输出结果的
source_documents可看到: - 从向量数据库检索出的原始模型片段
- 对应从向量储存里检索出来的原始模型片段
RAG 步骤 (续) 询问模型
Section titled “RAG 步骤 (续) 询问模型”- 需要把搜索出的相关文本片段和查询请求结合到一起,一块传给AI
- 结合提示模板和记忆
- 也许不需要那么麻烦
检索增强生成对话链:ConversationalRetrievalChain
Section titled “检索增强生成对话链:ConversationalRetrievalChain”- LangChain构建的用于检索增强生成的对话链,可从
langchain.chains模块导入: from langchain.chains import ConversationalRetrievalChain- 假设已完成文档切割和向量化,得到文档检索器。
- 大语言模型是核心,创建聊天模型实例:
model = ChatOpenAI(model="gpt-3.5-turbo")- 拥有模型和检索器后,还需记忆组件实现连续对话。
- 记忆组件类型可根据需求选择,但需设置
return_messages=True。 memory_key赋值为chat_historyoutput_key也要赋值为answerConversationalRetrievalChain储存历史消息的变量叫做chat_history- AI模型的输出对应着
answer键的值 - 调用
ConversationalRetrievalChain的from_llm方法 - 将
llm参数赋值为聊天模型 - 将
retriever参数赋值为上一节里通过调用向量储存的as_retriever方法得到的检索器 - 将
memory参数赋值为刚才创建好的记忆 - 能够帮我们实现RAG的对话链就准备好了
- 仍然是通过
invoke方法
result = qa.invoke({"chat_history": memory, "query": query})- 传入
chat_history和query
检索增强生成对话链:ConversationalRetrievalChain (续)参数解释
Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)参数解释”- 传入
chat_history和query:ConversationalRetrievalChain需要chat_history和question作为键。 chat_history:对应记忆。question:对应用户查询。- 链在处理对话时,使用
chat_history键来访问和更新对话历史。 - 赋值给创建好的记忆。
question参数赋值为用户查询的字符串即可。invoke返回字典:answer对应来自AI的回应,question对应来自用户的问题。- 对话也会被自动加入
chat_history对应的记忆里。
检索增强生成对话链:ConversationalRetrievalChain (续)
Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)”- 从输出结果的
source_documents可看到: - 从向量数据库检索出的原始模型片段
- 对应从向量储存里检索出来的原始模型片段
RAG优化方法:Stuff 填充方法的局限性与替代方案
Section titled “RAG优化方法:Stuff 填充方法的局限性与替代方案”- Stuff 方法:将文档相关片段全部传递给模型。
- 优点:简单直接,模型可一次性看到所有信息。
- 缺点:当片段很长或很多时,可能超过模型的上下文窗口限制。
- 替代方案:
- Map Reduce(映射归约)
- Refine(优化)
- Map Rerank(映射-重新排序)
Map Reduce(映射归约)
Section titled “Map Reduce(映射归约)”- 不会将原始片段一次性全部传递给模型。
- 分为两个阶段:Map 和 Reduce。
- Map阶段:每个相关片段单独传递给模型,模型根据各片段对查询分别做出回答。
映射归约 (Map Reduce) 优化 RAG
Section titled “映射归约 (Map Reduce) 优化 RAG”- Map: 根据不同片段得到多个版本回答
- Reduce: 整合回答,形成统一信息合集,传递给模型
- 模型据合并后的信息,给出连贯、结合多方信息的回答
- 适用于需要广泛背景知识的查询
- 调用模型次数多
- Refine: 从第一个片段开始,得到模型针对查询的回答
RAG优化方法:Map Reduce(映射归约)(续)
Section titled “RAG优化方法:Map Reduce(映射归约)(续)”Map阶段:相关片段单独传递给模型,模型对查询做出回答。Rerank阶段:用另一模型对多个回答进行重新排序。- 选出最相关和准确的回答。
- 或组合信息,生成更全面的回答。
- 适用于:需要信息整合,但对每个信息来源的质量要求不高的场景。
- 优势:减少了不相关信息对模型的影响。
- 缺点:需要调用多个模型,成本高,速度慢。
- 类似
Map Reduce,分为Map和Rerank阶段。 Map阶段:每个片段单独传递给模型。Rerank阶段:模型对多个回答重新排序,选择最相关或组合信息。
RAG优化方法:Map Reduce(映射归约)(续)代码演示
Section titled “RAG优化方法:Map Reduce(映射归约)(续)代码演示”- 指定
chain_type参数为map_reduce: - 代码:
chain_type="map_reduce" - 完整代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm( llm=model, retriever=retriever, memory=memory, chain_type="map_reduce")- 注意:需要指定
chain_type为map_reduce,才能使用Map Reduce方法。
RAG优化方法:Refine(优化)
Section titled “RAG优化方法:Refine(优化)”- 从第一个片段开始,得到模型针对查询的回答。
- 接下来的片段,模型会:
- 将当前回答与该片段结合,优化答案。
- 或确认答案是否需要更改。
- 优点:在整合多来源信息的同时,考虑了上下文关系。
- 缺点:速度慢,成本高,因为每个片段都要传递给模型。
- 适用于:对准确性和连贯性要求高的场景。
RAG优化方法:Refine(优化)(续)代码演示
Section titled “RAG优化方法:Refine(优化)(续)代码演示”- 与
Map Reduce类似,只需给chain_type参数赋值:chain_type="refine" - 代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm( llm=model, retriever=retriever, memory=memory, chain_type="refine")RAG优化方法:Map Rerank(映射-重新排序)
Section titled “RAG优化方法:Map Rerank(映射-重新排序)”- 类似
Map Reduce,分为Map和Rerank阶段。 Map阶段:每个片段单独传递给模型。Rerank阶段:模型对多个回答重新排序,选择最相关或组合信息。- 适用于:需要信息整合,但对每个信息来源的质量要求不高的场景。
- 优势:减少了不相关信息对模型的影响。
- 缺点:需要调用多个模型,成本高,速度慢。
RAG优化方法:Map Rerank(映射-重新排序)(续)代码演示
Section titled “RAG优化方法:Map Rerank(映射-重新排序)(续)代码演示”- 与
Map Reduce类似,只需给chain_type参数赋值:chain_type="map_rerank" - 代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm( llm=model, retriever=retriever, memory=memory, chain_type="map_rerank")RAG优化方法:Map Reduce(映射归约) (续)代码演示
Section titled “RAG优化方法:Map Reduce(映射归约) (续)代码演示”- 指定
chain_type参数为map_reduce: - 代码:
chain_type="map_reduce" - 完整代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm( llm=model, retriever=retriever, memory=memory, chain_type="map_reduce")- 注意:需要指定
chain_type为map_reduce,才能使用Map Reduce方法。
RAG优化方法:Refine(优化)
Section titled “RAG优化方法:Refine(优化)”- 从第一个片段开始,得到模型针对查询的回答。
- 接下来的片段,模型会:
- 将当前回答与该片段结合,优化答案。
- 或确认答案是否需要更改。
- 优点:在整合多来源信息的同时,考虑了上下文关系。
- 缺点:速度慢,成本高,因为每个片段都要传递给模型。
- 适用于:对准确性和连贯性要求高的场景。
RAG优化方法:Refine(优化)(续)代码演示
Section titled “RAG优化方法:Refine(优化)(续)代码演示”- 与
Map Reduce类似,只需给chain_type参数赋值:chain_type="refine" - 代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm( llm=model, retriever=retriever, memory=memory, chain_type="refine")RAG优化方法:Map Rerank(映射-重新排序)
Section titled “RAG优化方法:Map Rerank(映射-重新排序)”- 类似
Map Reduce,分为Map和Rerank阶段。 Map阶段:每个片段单独传递给模型。Rerank阶段:模型对多个回答重新排序,选择最相关或组合信息。- 适用于:需要信息整合,但对每个信息来源的质量要求不高的场景。
- 优势:减少了不相关信息对模型的影响。
- 缺点:需要调用多个模型,成本高,速度慢。
RAG优化方法:Map Rerank(映射-重新排序)(续)代码演示
Section titled “RAG优化方法:Map Rerank(映射-重新排序)(续)代码演示”- 与
Map Reduce类似,只需给chain_type参数赋值:chain_type="map_rerank" - 代码:
from langchain.chains import ConversationalRetrievalChain
qa = ConversationalRetrievalChain.from_llm( llm=model, retriever=retriever, memory=memory, chain_type="map_rerank")AI智能PDF问答工具:页面功能实现
Section titled “AI智能PDF问答工具:页面功能实现”- 侧边栏:允许用户提供自己的API密钥进行内容生成。
- 需要把PDF文件进行上传才能开启提问。
- 仅允许上传
.pdf为后缀的文件,避免用户上传其他格式文件。 - 上传后,用户在文本框里对PDF内容进行提问。
AI智能PDF问答工具:页面功能实现 (续)问题提问
Section titled “AI智能PDF问答工具:页面功能实现 (续)问题提问”- 上传PDF文件后,在文本框里对PDF内容进行提问。
AI智能PDF问答工具:页面功能实现 (续)正确答案
Section titled “AI智能PDF问答工具:页面功能实现 (续)正确答案”- AI给出基于文档内容的回答,并链接文档里的其他相关信息。
- AI给出正确答案,并且把文档里的其他相关信息也返回。
AI智能PDF问答工具:页面功能实现 (续)GPT-3
Section titled “AI智能PDF问答工具:页面功能实现 (续)GPT-3”- 确定PDF文档里GPT-3有几个Transformer吗?
- AI给出了基于文档内容的回答:GPT-3有几个Transformer层。
AI智能PDF问答工具:功能演示 (续)GPT-3
Section titled “AI智能PDF问答工具:功能演示 (续)GPT-3”- 确定PDF文档里
GPT-3有几个Transformer吗? - AI给出了基于文档内容的回答:
GPT-3有96个transformer层。 - 且验证了给出的回答仍然是正确的。
- 具有创建储存对话的记忆。
- 如果用户的问题涉及到之前的对话,大模型也能基于记忆给出回答。
- 整体思路是相似的,只需要做小部分修改即可。
- AI可以基于本地知识库的内容做出回答。
- 用户不需要自行上传任何文件。
- 实现过程可参考智能PDF问答工具。
实现AI对文档的请求
Section titled “实现AI对文档的请求”- 读取用户上传的文档。
- 将文档内容和用户提问传给AI。
- 得到AI基于文档的回答。
- 加载:读取文档。
- 切割:分割文档内容。
下载requirements.txt文件
Section titled “下载requirements.txt文件”- 从课程配套资料里下载。
项目文件设置与依赖安装
Section titled “项目文件设置与依赖安装”- 安装依赖:通过
pip install -r requirements.txt安装项目所需的所有依赖项。 - 创建&;
utils.py&;文件:将所有与AI大模型交互的代码统一放入此文件中。 - 定义&;
qa_agent&;函数:该函数用于封装对AI的请求,接收openai_api_key和memory作为参数,以便处理API密钥和对话记忆。
实现AI对文档的请求
Section titled “实现AI对文档的请求”- 读取用户上传的文档。
- 将文档内容和用户提问传给AI。
- 得到AI基于文档的回答。
- 加载:读取文档。
- 切割:分割文档内容。
下载requirements.txt文件
Section titled “下载requirements.txt文件”- 从课程配套资料里下载。
qa_agent 函数 (续) 模型定义
Section titled “qa_agent 函数 (续) 模型定义”- 模型类型:
gpt-3.5-turbo - 用户提供的
API密钥:通过参数传入openai_api_key,ChatOpenAI的构造函数会使用。 - 代码示例:
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)- 需从
langchain_community.document_loaders的document_loaders模块里导入PyPDFLoader:
from langchain_community.document_loaders import PyPDFLoader- 实例化
PyPDFLoader时,遇到了一个问题:之前读取的都是本地文件,而用户上传的是文件内容
qa_agent 函数 (续) 方法选择
Section titled “qa_agent 函数 (续) 方法选择”- 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
- 适用于上传文件大小不确定,且需要重复使用的场景。
- 缺点:过程繁琐,会创建临时文件。
- 方法二:使用
PyPDFLoader的load_bytes方法。 - 适用于已经读取文件内容,且内容储存在内存里的情况。
- 更简单高效,无需写入本地文件。
- 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoaderfrom langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key) file_content = uploaded_file.read() loader = PyPDFLoader() docs = loader.load_bytes(file_content)- 将获取到的
file_content文本传进去,而不是传文件路径。 - 代码更简洁。
qa_agent 函数 (续)将内容写入临时文件:
Section titled “qa_agent 函数 (续)将内容写入临时文件:”- 使用
with open()语句,模式设置为"wb"(写入二进制文件)。 - 代码:
with open(temp_file_path, "wb") as temp_file: temp_file.write(file_content)temp_file_path:临时文件路径,类型应为字符串。- 将
uploaded_file读取的二进制内容写入临时文件:temp_file.write(file_content)。 - 代码执行后,临时文件将包含用户上传的
PDF内容。
qa_agent 函数 (续)方法选择
Section titled “qa_agent 函数 (续)方法选择”- 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
- 适用于上传文件大小不确定,且需要重复使用的场景。
- 缺点:过程繁琐,会创建临时文件。
- 方法二:使用
PyPDFLoader的load_bytes方法。 - 适用于已经读取文件内容,且内容储存在内存里的情况。
- 更简单高效,无需写入本地文件。
- 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoaderfrom langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key) file_content = uploaded_file.read() loader = PyPDFLoader() docs = loader.load_bytes(file_content)- 将获取到的
file_content文本传进去,而不是传文件路径。 - 代码更简洁。
- 加载后,需要对文档进行分割
- 导入
RecursiveCharacterTextSplitter:
from langchain.text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separators=["\n\n", "\n", " ", "",])-像chunk_size、chunk_overlap 这些
qa_agent 函数 (续)中文分词优化:separators 参数设置
Section titled “qa_agent 函数 (续)中文分词优化:separators 参数设置”- 将
separators赋值为更适合中文的分隔符。 - 代码示例:
text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", " ", ""])text_splitter.split_documents(docs):调用分割文档,得到文本块列表texts。
RAG 步骤 (续) 嵌入 (Embeddings)
Section titled “RAG 步骤 (续) 嵌入 (Embeddings)”- 将文本转换为向量。
- 向量:包含文本的语义和语法信息。
- 用于后续的相似性搜索。
- 嵌入模型:负责将文本转换为向量。
- 从
langchain_openai导入OpenAIEmbeddings:from langchain_openai import OpenAIEmbeddings - 创建嵌入模型:
embeddings_model = OpenAIEmbeddings()
RAG 步骤 (续) 向量数据库:Chroma (续)FAISS
Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)FAISS”- 从
langchain_community.vectorstores导入FAISS - 向量数据库,可用它来做相似性搜索
- 代码示例:
db = FAISS.from_documents(texts, embeddings_model) texts:切割后的文档列表embeddings_model:嵌入模型的实例- 使用向量数据库的
as_retriever方法得到检索器 - 检索器:用于从大量文本中快速检索相关信息的组件
- 由于检索器也是
Runnable,说明可以调用它的invoke方法 - 示例:
retrieved_docs = retriever.invoke("卢浮宫这个名字怎么来的?") - 传入文本,返回检索到的相关段落
- 文本与向量数据库里的文本块相似性高
- 示例:
retrieved_docs[0].page_content retriever.invoke("卢浮宫在哪年被命名为中央艺术博物馆")- 也能获得相关文本块
| 方法 | 描述 |
|---|---|
| read | 返回全部文件内容的字符串 |
| readline | 返回一行文件内容的字符串 |
| readlines | 返回全部文件内容组成的列表 |
- 证明相似性搜索还是比较靠谱的
- 从
langchain.chains模块导入ConversationalRetrievalChain - 使用
ConversationalRetrievalChain.from_llm方法: llm参数:赋值为聊天模型。retriever参数:赋值为向量储存的as_retriever方法得到的检索器。memory参数:赋值为创建好的记忆。- 能够实现RAG的对话链就准备好了
- 仍然是通过
invoke方法 - 传入
chat_history和query
检索增强生成对话链:ConversationalRetrievalChain (续)参数解释
Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)参数解释”- 传入
chat_history和query:ConversationalRetrievalChain需要chat_history和question作为键。 chat_history:对应记忆。question:对应用户查询。- 链在处理对话时,使用
chat_history键来访问和更新对话历史。 - 赋值给创建好的记忆。
question参数赋值为用户查询的字符串即可。invoke返回字典:answer对应来自AI的回应,question对应来自用户的问题。- 对话也会被自动加入
chat_history对应的记忆里。
检索增强生成对话链:ConversationalRetrievalChain (续)
Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)”- 从输出结果的
source_documents可看到: - 从向量数据库检索出的原始模型片段
- 对应从向量储存里检索出来的原始模型片段
网站框架搭建 (续)代码实现准备
Section titled “网站框架搭建 (续)代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续)返回值
Section titled “generate_script 函数 (续)返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- a模型``。
- 第二个参数:
video_length(时长),例如1分钟。 - 第三个参数:
creativity(创造性),例如0.7。 - 第四个参数:
api_key(API 密钥)。
generate_script 函数 (续) API 密钥获取
Section titled “generate_script 函数 (续) API 密钥获取”- API 密钥可以通过导入
os模块,然后使用 `os.getenv(
搭建网站主页:main.py 文件
Section titled “搭建网站主页:main.py 文件”- 创建
main.py文件:表示网站主页。 - 导入库:
import streamlit as stfrom utils import qa_agent- 网页标题:
st.title("AI智能PDF问答工具") - 运行命令:
streamlit run main.py
- 允许用户提供
API密钥(st.text_input)。 - ``st.markdown(“获取OpenAI API密钥”)`
- 采用多列布局:
st.columns(2) - 返回列表,分别赋值给
left_column和right_column - 侧边栏输入密钥,主页面输入主题,点击开始写作。
- 页面加载中,显示5个待选标题和正文。
代码实现:历史对话展示
Section titled “代码实现:历史对话展示”- 使用
for循环迭代st.session_state[``messages]`: - 代码:
for message in st.session_state[``messages]:` st.chat_message(message[``role]).write(message[``content])\:在页面上展示消息。- 根据
message的role属性,用不同的样式显示(模拟不同用户)。 if "memory" not in st.session_state::检查会话状态中是否已存在名为“memory”的键。- 如果不存在,则初始化
st.session_state["memory"]为ConversationBufferMemory实例。 return_messages=True:确保记忆存储的是消息列表,而不是一整坨字符串。memory_key="chat_history":将记忆的键设置为"chat_history",因为后端ConversationalRetrievalChain期望用此键来获取对话历史。output_key="answer":将输出结果的键设置为"answer",这是ConversationalRetrievalChain中AI模型回应的默认键。
qa_agent 函数 (续) 用户提问输入框设置
Section titled “qa_agent 函数 (续) 用户提问输入框设置”- 使用
st.text_input函数。 - 添加
disabled参数:控制输入框是否允许输入。 - 不允许输入时呈灰色,用户无法输入。
- 设置逻辑:用户未上传文件时,输入框处于禁止状态。
- 代码:
disabled=not uploaded_file - 用户提出的问题应基于PDF文件。
添加加载组件
Section titled “添加加载组件”- 使用
st.spinner(),提示用户等待。 - 参数:加载时显示的文字,如
AI正在思考中,请稍后... with st.spinner(...):代码块执行完,加载提示消失。- 调用
get_chat_response()函数: - 传入用户消息、记忆和API密钥。
- 将结果赋值给
response变量。
qa_agent 函数 (续) 响应处理
Section titled “qa_agent 函数 (续) 响应处理”qa_agent返回字典:answer键对应AI回答内容,chat_history键对应历史对话消息列表。- 使用
streamlit展示回答:st.write(response[``answer])` - 在下方展示三级标题“答案”。
- 展示
response字典中answer键对应的值。 - 历史对话信息储存在字典中。
实现历史消息展示
Section titled “实现历史消息展示”- 使用
for循环迭代st.session_state["chat_history"]: - 代码:
for i in range(0, len(st.session_state["chat_history"]), 2):,每次加2。 st.chat_message(HumanMessage).write(st.session_state["chat_history"][i].content):展示人类消息。
-st.chat_message(AIMessage).write(st.session_state["chat_history"][i+1].content):展示AI消息。
从内存中取出
Section titled “从内存中取出”- 从储存对话记忆中取出消息,并呈现在页面上
- 需使用range,并指定从零开始循环,循环到消息列表的个数,且每次加2,两两循环
- 提示:每轮对话包含两条消息(人类消息和AI消息)
代码实现:历史消息展示 (续)代码美化
Section titled “代码实现:历史消息展示 (续)代码美化”st.write(human_message.content):展示人类消息。st.write(ai_message.content):展示AI消息。st.divider():调用streamlit的divider组件,显示分割线。if i < len(st.session_state[``chat_history]) - 2:`:避免最后也加分割线。
代码实现:完整代码
Section titled “代码实现:完整代码”main.py:完整代码,实现AI聊天助手。- 导入必要的库。
- 初始化会话状态。
- 侧边栏设置(API密钥输入)。
- 历史消息展示。
- 用户输入框和AI响应。
- 详细代码请参见视频。
- 成功实现AI智能PDF问答工具。
- 核心方法:RAG (Retrieval Augmented Generation)检索增强生成。
迭代与优化方向
Section titled “迭代与优化方向”- 添加文件上传功能:支持用户上传自己的PDF文件。
- 文本信息提取:从文件提取信息(时间、地点、金额等)。
- 结合Agent:根据用户需求,自动选择工具完成任务。
- 学习过程:理论知识 -> 代码实战 -> 部署到云端,更多用户使用。
- Python基础:变量、数据类型、条件循环、函数、类、模块、异常。
- 提示词工程:设计、优化提示,控制模型行为。
- LangChain框架:简化AI应用开发,组件化、模块化。
- Streamlit框架:快速构建交互式Web应用。
- 实践和探索:持续学习,成为AI应用开发高手!
- 恭喜完成所有课程,期待AI世界探索之旅!
网站框架搭建 (续) 代码演示
Section titled “网站框架搭建 (续) 代码演示”- 运行代码:
streamlit run main.py - 页面提示:请输入OpenAI API密钥,请输入视频的主题,视频长度需要大于或等于0.1
- 都填好后,点击生成脚本
- 页面生成:视频标题,视频脚本,查看更多关于xxx的信息
- 点击查看更多关于xxx的信息:可以跳转到维基百科
网站框架搭建 (续) 结果展示信息
Section titled “网站框架搭建 (续) 结果展示信息”st.spinner()停止后,展示结果。st.success("视频脚本已生成!"):显示视频脚本生成成功的提示信息。- 使用
st.subheader():显示视频标题。 - 使用
st.write():显示视频脚本内容。 - 使用
st.caption():在脚本下方显示维基百科的搜索结果。 st.markdown():创建链接,指向维基百科关于该主题的页面。
- 仅允许上传
.pdf为后缀的文件 - 上传成功,输入框不再禁止输入,可提问。
AI大语言模型的局限性
Section titled “AI大语言模型的局限性”- 模型所了解的知识受到训练数据日期的影响
- 截止2022年1月训练完成的模型,必然不包含当年的新闻
- 模型无法得知训练完成之后发生的事情
AI大语言模型的局限性
Section titled “AI大语言模型的局限性”- 知识截断:模型知识受训练数据日期影响。
- 截止2022年1月训练完成的模型,无法得知此日期后发生的事情。
- 提问模型更新事件时,模型要么回复过时信息,要么胡编乱造。
- 重新训练模型成本高昂,且无法彻底解决数据过时问题。
- 人类可以通过上网搜索获取新信息。
- 设想:如果AI也能自行搜索互联网上不了解的知识,找到答案并告知我们,那就太好了!
- AI浏览互联网的挑战:
- 何时应该浏览互联网?
- 应该搜索什么关键词?
- 应该点进什么网站?
- 浏览时应该关注什么关键词来找相关信息?
ReAct框架
Section titled “ReAct框架”- 2022年:一篇名为《ReAct:在语言模型中协同推理与行动》的论文提出了ReAct框架。
- 注意:此ReAct框架不是热门前端框架
React。
React核心:推理与行动结合
Section titled “React核心:推理与行动结合”- 让模型进行动态推理,并与外界环境互动
- 用小样本提示展示推理与行动结合的框架
- 问题步骤拆分:推理、行动、观察
- 推理:针对问题或上一步观察的思考
- 行动:基于推理,与外部环境交互(如用搜索引擎搜索)
- 观察:对行动结果进行查看
ReAct框架的应用实例
Section titled “ReAct框架的应用实例”- 用户想知道2022年欧冠冠军,需要最新信息
- 推理:需要查找最新欧冠冠军信息
- 行动:在Bing搜索“2022 UEFA Champions League champion”
- 观察1:出现一些包含2022年欧冠冠军信息的网页
- 推理2:Sporting News的链接标题包含“2022 Champions League final”,可能包含所需信息
- 行动2:点击Sporting News的链接
- 观察2:网页上有“Real Madrid were crowned European champions…1-0 win over Liverpool in the 2022 Champions League final…”
- 推理3:需要引用皇马赢得2022年欧冠冠军的信息,为用户提供答案
- 结果:2022年欧冠冠军是皇马,他们决赛中1-0击败利物浦
ReAct框架的优势
Section titled “ReAct框架的优势”- 步骤推理与行动结合,可看到模型接近答案的过程
- 观察和行动步骤增加了与外部环境的交互
- 能够辅助模型突破一些固有限制
- 比如在搜索引擎输入关键字,查看网页上的信息
- 可以减少知识截断带来的影响
ReAct框架的Action行动特性
Section titled “ReAct框架的Action行动特性”- action不专指搜索和浏览网页,而是所支持的任何行动,包括自定义行动。
- 示例:
- 模型与代码解释器交互:运行代码可作为行动选项。
- 模型访问外部文档:从文档里查找关键字可作为行动选项。
- 模型调用某个应用的API:和应用进行交互可以被作为行动选项。
ReAct框架的推理步骤
Section titled “ReAct框架的推理步骤”- Agent 以模型为思考大脑,了解下一步行动
- 通过提示告知 Agent,它能利用的一系列工具
- Agent 相应返回下一步的行动,以及给工具的输入
- Agent 觉得任务完成,可以输出了,返回的不再是行动,而是表示完成的信息,以及给用户的响应内容
- 推理步骤的下一步:要么是行动,要么是给用户的结果
ReAct框架的行动步骤
Section titled “ReAct框架的行动步骤”- 从推理步骤得到的输入给工具
- 让工具与环境进行交互
- 实际调用工具的叫
agent executor
行动步骤 (续) 观察步骤
Section titled “行动步骤 (续) 观察步骤”- 观察是对行动得到的结果进行查看
- 观察会引发下一轮的推理
- 推理、行动和观察持续循环,直到推理步骤里
agent认为已经得到答案 - 使用 LangChain 定义
agent
LangChain的行动步骤
Section titled “LangChain的行动步骤”- 从推理步骤得到的输入给工具
- 让工具与环境进行交互
- 实际调用工具的叫
agent executor
行动步骤 (续) 观察步骤
Section titled “行动步骤 (续) 观察步骤”- 观察是对行动得到的结果进行查看
- 观察会引发下一轮的推理
- 推理、行动和观察持续循环,直到推理步骤里
agent认为已经得到答案 - 使用 LangChain 定义
agent
定义工具的实际功能
Section titled “定义工具的实际功能”- 在
agent执行过程中,如果要借助到这个工具,它的_run方法会被调用。 - 因此,就在这个方法下面实现数字功能。
- 代码非常简单:直接返回Python
len函数,对传入文本调用结果。
工具定义完成
Section titled “工具定义完成”- 到现在,
agent可以借用的文本字数计算工具就定义完成了。 - 可以把这个类的实例放到一个列表里:
tools = [TextLengthTool()]
- 这个
tools列表表示agent的执行器可以使用到的所有工具
工具定义完成
Section titled “工具定义完成”- 现在,
agent可以借用的文本字数计算工具就定义完成了。 - 可以把这个类的实例放到一个列表里:
tools = [TextLengthTool()]
- 这个
tools列表表示agent的执行器可以使用到的所有工具
LangChain Hub
Section titled “LangChain Hub”- 网址:https://smith.langchain.com/hub
- 用于管理和共享
LangChain相关资源的在线平台。 - 可从中获得用户上传的各种目的的提示词。
- 实现
ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。 hwchase17:Harrison Chase,LangChain的Co-Founder和CEO。
LangChain Hub
Section titled “LangChain Hub”- 要从 LangChain Hub 拉取内容,需先安装
langchainhub库: !pip install langchainhub(Jupyter)pip install langchainhub(Windows)pip3 install langchainhub(macOS)- 然后从
langchain导入hub:from langchain import hub - 使用
hub.pull()方法拉取提示词:prompt = hub.pull("hwchase17/structured-chat-agent") - 拉取的提示词是一个
ChatPromptTemplate。 - 这个提示词让大语言模型遵循 ReAct 框架,并将工具介绍作为变量,供后续插入相关信息。
Agent (智能体)
Section titled “Agent (智能体)”- Agent 由模型、提示词和工具组成。
- 模型:作为 Agent 的大脑。
- 提示词:让模型遵循 ReAct 框架。
- 工具:相关信息会填入提示词模板,帮助模型了解可使用的工具。
- 初始化 Agent:从
langchain.agents导入create_structured_chat_agent:from langchain.agents import create_structured_chat_agent
LangChain Hub
Section titled “LangChain Hub”- 网址:https://smith.langchain.com/hub
- 用于管理和共享
LangChain相关资源的在线平台。 - 可从中获得用户上传的各种目的的提示词。
- 实现
ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。 hwchase17:Harrison Chase,LangChain的Co-Founder和CEO。
Agent 执行器
Section titled “Agent 执行器”- 从
langchain.agents导入AgentExecutor - 调用
AgentExecutor.from_agent_and_tools方法 - 参数:
agent,tools - 之前定义
agent时也传入了tools,但那只是为了让它知道有哪些工具可以使用 agent执行器才是实际调用工具的那个- 实现连续对话,把记忆也定义出来
memory = ConversationBufferMemory( memory_key="chat_history", return_messages=True)agent_executor = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, memory=memory)Agent 执行器 (AgentExecutor)
Section titled “Agent 执行器 (AgentExecutor)”AgentExecutor用于执行Agent。- 实例化
AgentExecutor时,需要传入以下参数: agent:之前创建的agent实例。tools:agent可以使用的工具列表。memory:记忆组件。memory_key需要设置为chat_history,因为之前提示模板中对应的记忆变量名就是chat_history。ConversationBufferMemory示例:
memory = ConversationBufferMemory( memory_key='chat_history', return_messages=True)
agent_executor = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, memory=memory, handle_parsing_errors=True)handle_parsing_errors 参数
Section titled “handle_parsing_errors 参数”- 可选参数,设置为
True。 - 作用:当
agent执行器在执行过程中,如果模型没有按照 ReAct 框架的格式输出,会产生解析错误。 - 默认情况下,程序会直接终止。
- 设置为
True后,agent执行器会将错误作为观察 (Observation) 发送回大模型,让大模型自行推理并处理错误。 - 这是一个很实用的参数,可以提高
agent的鲁棒性。 - 局限性:由于大模型的输出具有不稳定性,即使
handle_parsing_errors设置为True,agent的执行仍可能出现问题。
agent执行器参数:verbose
Section titled “agent执行器参数:verbose”verbose:是否以详细模式运行- 默认为
False - 设为
True:打印执行日志 - agent 执行器在调用后直接返回最终结果
- 除非
verbose设为True
Agent执行器参数:verbose
Section titled “Agent执行器参数:verbose”verbose:是否以详细模式运行- 默认为
False - 设为
True:打印执行日志 - agent 执行器在调用后直接返回最终结果
- 除非
verbose设为True
Invoke的最终结果
Section titled “Invoke的最终结果”- 是一个包含输入、输出以及对话列表的字典
- 可直接提取
output值对应的键 - 使用之前定义
TextLengthTool得到的结果一致,因为agent执行器也是用的同一个工具 - 有效解决了计算字数时AI胡说八道的问题
- Agent 对字数不相关问题也能判断不需要借助
文本字数计算工具,直接输出答案 - Agent 通过集成适应不同需求,解决不同问题的工具,以及复杂的决策和推理过程
LangChain的现成工具:Python解释器
Section titled “LangChain的现成工具:Python解释器”- 常用工具:Python解释器。
- 使
agent可通过编写和执行Python代码来更准确地回答问题。 - 尤其适用于数学相关问题。
- 大语言模型的缺陷:无法用作计算器。
- 提问数学计算:模型可能给出错误答案。
- 模型可能给出训练数据中出现过的错误答案。
程序辅助语言模型(PAL)
Section titled “程序辅助语言模型(PAL)”- 大语言模型不擅长计算,而是让AI生成做计算的代码
- 简称PAL,2022年一篇论文里被提出
- 使用
langchain_experimental库 - 包含一些实验性的
LangChain相关代码 - 安装:
pip install langchain_experimental
LangChain 框架组件 (续)模型类型
Section titled “LangChain 框架组件 (续)模型类型”- LangChain集成的模型:
LLM(语言模型):文本补全。Chat Model(聊天模型):对话。- 本质上都是大语言模型。
- 主要使用的接口不同:
LLM接收一个字符串,返回一个字符串。Chat Model接收一个消息列表,返回一个消息。
LangChain中OpenAI的使用准备
Section titled “LangChain中OpenAI的使用准备”- 模型选择:
gpt-3.5-turbo、gpt-4等,需使用OpenAI的API密钥 - 创建
OpenAI实例,环境变量已设置密钥,则直接创建实例: - ```python
from openai import OpenAI
client = OpenAI()
- 否则,需显式传入`api_key`: - 常用参数: - `temperature`:控制回复的随机性(温度) - `max_tokens`:限制回复的`token`数 - 不常用参数:可作为键值对放入字典,传给`model_kwargs`
### LangChain中OpenAI的使用准备 (续) `model_kwargs` 参数- 可选参数,以**字典**形式传入到`model_kwargs`- LangChain官方文档:准确且实时更新的信息来源- API密钥、`base_url`、模型名称:必须参数- `model_kwargs`:可选参数,可控制AI行为
### LangChain中消息 Message- `messages`:消息列表,可包含不同类型的消息- 消息类型: - `SystemMessage`:系统消息,给AI传递背景信息或角色设定 - `HumanMessage`:人类消息,用户的实际提问 - `AIMessage`:AI的回复
### LangChain中消息 Message (续)- 使用`from langchain.schema.messages import (SystemMessage, HumanMessage)`引入- `SystemMessage`:构造函数的`content`参数赋值为消息文本- 获取AI回复内容:`AIMessage`对象,通过`.content`属性可获取AI回复的实际文本内容
### LangChain中的其他聊天模型- `langchain_community`库还集成了许多其他聊天模型- 在官方文档的`langchain_community.chat_models`部分查看支持的模型列表: - `chat_models.baidu_qianfan_endpoint.QianfanChatEndpoint`:百度千帆平台提供的大模型(包括文心大模型)。 - `chat_models.hunyuan.ChatHunyuan`:腾讯混元模型。 - `chat_models.tongyi.ChatTongyi`:阿里通义千问模型。LangChain的现成工具:Python解释器
Section titled “LangChain的现成工具:Python解释器”- 常用工具:Python解释器。
- 使
agent可通过编写和执行Python代码来更准确地回答问题。 - 尤其适用于数学相关问题。
- 大语言模型的缺陷:无法用作计算器。
- 提问数学计算:模型可能给出错误答案。
- 模型可能给出训练数据中出现过的错误答案。
程序辅助语言模型(PAL)
Section titled “程序辅助语言模型(PAL)”- 大语言模型不擅长计算,而是让AI生成做计算的代码
- 简称PAL,2022年一篇论文里被提出
- 使用
langchain_experimental库 - 包含一些实验性的
LangChain相关代码 - 安装:
pip install langchain_experimental
创建执行 Python 代码的 Agent
Section titled “创建执行 Python 代码的 Agent”- 目的:创建一个能执行Python代码的
agent执行器。 - 调用
create_python_agent函数。 llm参数:AI模型实例(ChatOpenAI模型)。tool参数:PythonREPLTool的实例。- 使用
verbose=True展示AI的思考过程。 create_python_agent不直接支持handle_parsing_errors参数。- 可将
agent_executor_kwargs赋值为一个表示更多参数的字典。 - 把
handle_parsing_errors键对应的值赋值为True。 - 获得
agent执行器。 - 可输出或打印查看各组件。
LangChain Hub
Section titled “LangChain Hub”- 网址:https://smith.langchain.com/hub
- 用于管理和共享
LangChain相关资源的在线平台。 - 可从中获得用户上传的各种目的的提示词。
- 实现
ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。 hwchase17:Harrison Chase,LangChain的Co-Founder和CEO。
LangChain Hub
Section titled “LangChain Hub”- 要从 LangChain Hub 拉取内容,需先安装
langchainhub库: !pip install langchainhub(Jupyter)pip install langchainhub(Windows)pip3 install langchainhub(macOS)- 然后从
langchain导入hub:from langchain import hub - 使用
hub.pull()方法拉取提示词:prompt = hub.pull("hwchase17/structured-chat-agent") - 拉取的提示词是一个
ChatPromptTemplate。 - 这个提示词让大语言模型遵循 ReAct 框架,并将工具介绍作为变量,供后续插入相关信息。
Agent (智能体)
Section titled “Agent (智能体)”- Agent 由模型、提示词和工具组成。
- 模型:作为 Agent 的大脑。
- 提示词:让模型遵循 ReAct 框架。
- 工具:相关信息会填入提示词模板,帮助模型了解可使用的工具。
- 初始化 Agent:从
langchain.agents导入create_structured_chat_agent:from langchain.agents import create_structured_chat_agent
LangChain Hub
Section titled “LangChain Hub”- 网址:https://smith.langchain.com/hub
- 用于管理和共享
LangChain相关资源的在线平台。 - 可从中获得用户上传的各种目的的提示词。
- 实现
ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。 hwchase17:Harrison Chase,LangChain的Co-Founder和CEO。
Agent 执行器
Section titled “Agent 执行器”- 从
langchain.agents导入AgentExecutor - 调用
AgentExecutor.from_agent_and_tools方法 - 参数:
agent,tools - 之前定义
agent时也传入了tools,但那只是为了让它知道有哪些工具可以使用 agent执行器才是实际调用工具的那个- 实现连续对话,把记忆也定义出来
memory = ConversationBufferMemory( memory_key="chat_history", return_messages=True)agent_executor = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, memory=memory)Agent 执行器 (AgentExecutor)
Section titled “Agent 执行器 (AgentExecutor)”AgentExecutor用于执行Agent。- 实例化
AgentExecutor时,需要传入以下参数: agent:之前创建的agent实例。tools:agent可以使用的工具列表。memory:记忆组件。memory_key需要设置为chat_history,因为之前提示模板中对应的记忆变量名就是chat_history。ConversationBufferMemory示例:
memory = ConversationBufferMemory( memory_key='chat_history', return_messages=True)
agent_executor = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, memory=memory, handle_parsing_errors=True)handle_parsing_errors 参数
Section titled “handle_parsing_errors 参数”- 可选参数,设置为
True。 - 作用:当
agent执行器在执行过程中,如果模型没有按照 ReAct 框架的格式输出,会产生解析错误。 - 默认情况下,程序会直接终止。
- 设置为
True后,agent执行器会将错误作为观察 (Observation) 发送回大模型,让大模型自行推理并处理错误。 - 这是一个很实用的参数,可以提高
agent的鲁棒性。 - 局限性:由于大模型的输出具有不稳定性,即使
handle_parsing_errors设置为True,agent的执行仍可能出现问题。
agent执行器参数:verbose
Section titled “agent执行器参数:verbose”verbose:是否以详细模式运行- 默认为
False - 设为
True:打印执行日志 - agent 执行器在调用后直接返回最终结果
- 除非
verbose设为True
Invoke的最终结果
Section titled “Invoke的最终结果”- 是一个包含输入、输出以及对话列表的字典
- 可直接提取
output值对应的键 - 使用之前定义
TextLengthTool得到的结果一致,因为agent执行器也是用的同一个工具 - 有效解决了计算字数时AI胡说八道的问题
- Agent 对字数不相关问题也能判断不需要借助
文本字数计算工具,直接输出答案 - Agent 通过集成适应不同需求,解决不同问题的工具,以及复杂的决策和推理过程
LangChain的现成工具:Python解释器
Section titled “LangChain的现成工具:Python解释器”- 常用工具:Python解释器。
- 使
agent可通过编写和执行Python代码来更准确地回答问题。 - 尤其适用于数学相关问题。
- 大语言模型的缺陷:无法用作计算器。
- 提问数学计算:模型可能给出错误答案。
- 模型可能给出训练数据中出现过的错误答案。
程序辅助语言模型(PAL)
Section titled “程序辅助语言模型(PAL)”- 大语言模型不擅长计算,而是让AI生成做计算的代码
- 简称PAL,2022年一篇论文里被提出
- 使用
langchain_experimental库 - 包含一些实验性的
LangChain相关代码 - 安装:
pip install langchain_experimental
LangChain 框架组件 (续)模型类型
Section titled “LangChain 框架组件 (续)模型类型”- LangChain集成的模型:
LLM(语言模型):文本补全。Chat Model(聊天模型):对话。- 本质上都是大语言模型。
- 主要使用的接口不同:
LLM接收一个字符串,返回一个字符串。Chat Model接收一个消息列表,返回一个消息。
结合ReAct框架和PythonREPLTool解决数学问题
Section titled “结合ReAct框架和PythonREPLTool解决数学问题”- 提问:7的2.3次方是多少?
- Agent先尝试运行计算代码,能得到精确到小数后数位的结果,和直接运行Python代码得到的结果一样。
- 提问:第12个斐波那契数列的数字是多少?
- Agent先写出计算斐波那契数列的代码,再进行计算,从而得到准确结果。
- 解决AI胡编乱造问题
LangChain的现成工具:Python解释器
Section titled “LangChain的现成工具:Python解释器”- 常用工具:Python解释器。
- 使
agent可通过编写和执行Python代码来更准确地回答问题。 - 尤其适用于数学相关问题。
- 大语言模型的缺陷:无法用作计算器。
- 提问数学计算:模型可能给出错误答案。
- 模型可能给出训练数据中出现过的错误答案。
程序辅助语言模型(PAL)
Section titled “程序辅助语言模型(PAL)”- 大语言模型不擅长计算,而是让AI生成做计算的代码
- 简称PAL,2022年一篇论文里被提出
- 使用
langchain_experimental库 - 包含一些实验性的
LangChain相关代码 - 安装:
pip install langchain_experimental
创建执行 Python 代码的 Agent
Section titled “创建执行 Python 代码的 Agent”- 目的:创建一个能执行Python代码的
agent执行器。 - 调用
create_python_agent函数。 llm参数:AI模型实例(ChatOpenAI模型)。tool参数:PythonREPLTool的实例。- 使用
verbose=True展示AI的思考过程。 create_python_agent不直接支持handle_parsing_errors参数。- 可将
agent_executor_kwargs赋值为一个表示更多参数的字典。 - 把
handle_parsing_errors键对应的值赋值为True。 - 获得
agent执行器。 - 可输出或打印查看各组件。
LangChain Hub
Section titled “LangChain Hub”- 网址:https://smith.langchain.com/hub
- 用于管理和共享
LangChain相关资源的在线平台。 - 可从中获得用户上传的各种目的的提示词。
- 实现
ReAct框架,LangChain官方示例使用的是hwchase17用户定义的structured-chat-agent提示模版。 hwchase17:Harrison Chase,LangChain的Co-Founder和CEO。
LangChain Hub
Section titled “LangChain Hub”- 要从 LangChain Hub 拉取内容,需先安装
langchainhub库: !pip install langchainhub(Jupyter)pip install langchainhub(Windows)pip3 install langchainhub(macOS)- 然后从
langchain导入hub:from langchain import hub - 使用
hub.pull()方法拉取提示词:`prompt = hub.pull(
使用Python分析CSV数据文件
Section titled “使用Python分析CSV数据文件”- CSV(Comma-Separated Values):用于储存数据的纯文本格式
- 全称:逗号分隔值
- Excel文件可以导出成CSV格式
- 用记事本打开:数据用英文逗号分隔,对齐后呈现表格形式
- 用Excel打开:直接呈现为表格
调用 Pandas 库操作 CSV 数据文件
Section titled “调用 Pandas 库操作 CSV 数据文件”- CSV Agent:
- 用于分析 CSV 数据文件。
- 需定义能读取 CSV、创建 DataFrame、执行 Pandas 相关方法的 Agent。
- LangChain 也有开箱即用的 Agent 执行器。
- 安装:
- Jupyter:
!pip install langchain_experimental - Windows:
pip install langchain_experimental - macOS:
pip3 install langchain_experimental - 依赖:需要安装 Pandas 和 Tabulate 库。
- 安装:
- Jupyter:
!pip install pandas/!pip install tabulate - Windows:
pip install pandas/pip install tabulate - macOS:
pip3 install pandas/pip3 install tabulate - 导入:
from langchain_experimental.agents.agent_toolkits import create_csv_agent- 使用:
agent_executor = create_csv_agent(llm=ChatOpenAI(model="gpt-3.5-turbo", temperature=0), path="house_price.csv")llm参数:模型实例。path参数:CSV 文件路径。
使用Python分析CSV数据文件
Section titled “使用Python分析CSV数据文件”- CSV(Comma-Separated Values):用于储存数据的纯文本格式
- 全称:逗号分隔值
- Excel 文件可以导出成CSV格式
- 用记事本打开:数据用英文逗号分隔,对齐后呈现表格形式
- 用Excel打开:直接呈现为表格
llm参数:要用模型实例path参数:要分析的CSV文件路径verbose=True:展示AI思考过程agent_executor_kwargs:表示更多参数的字典handle_parsing_errors: True:避免agent出错后直接报错- 可直接输出或打印,查看
agent的各个组件 create_csv_agent也定义好了一个提示模版,与AI模型说,你正在与Python的DataFrame打交道DataFrame的名字是df- 接下来是关键的思考过程格式
调用 Pandas 库操作 CSV 数据文件 (续)示例:
Section titled “调用 Pandas 库操作 CSV 数据文件 (续)示例:”- 提问:数据有多少行?用中文回复
agent_executor.invoke({"input": "数据有多少行?用中文回复"})- 提示模板本身是英文,可能影响模型输出语言
- 补充要求,要求用中文进行回复
- 思路:
- 想知道有多少行,利用DataFrame的
shape方法 - 选择和Python代码执行相关的工具
- 进入原始的CSV文件验证回答是否正确
- 输出:545行
调用 Pandas 库操作 CSV 数据文件 (续)示例操作:
Section titled “调用 Pandas 库操作 CSV 数据文件 (续)示例操作:”- 询问数据有多少行:
agent_executor.invoke({“input”: “数据有多少行?用中文回复”}) Thought:使用shape属性获取数据集的行数Action Input:df.shape[0](数据有545行)Final Answer:545行- 询问数据集包含哪些变量:
- 通过查看表格的列名了解包含的变量
- 执行输出列名的命令,然后把所有列名返回给用户
CSV Agent
Section titled “CSV Agent”- 需在行动步骤中,通过
代码执行查看变量值的种类 - 也要在推断步骤:根据变量值思考含义,给出自己的解释
- 可通过短短几行
代码,拥有可和本地数据文件交互的AI助手 - 欢迎探索和尝试更多
- https://python.langchain.com/docs/integrations/toolkits/
- 包括能执行Python代码的
Python Agent,以及能读取和分析CSV文件的CSV Agent LangChain还提供其他一些开箱即用的agent执行器- Agent 执行器:输入 ->
agent(推理)-> 工具 -> 环境 -> 结果 -> 输出
整合 Agent 工具
Section titled “整合 Agent 工具”tools列表:包含所有agent执行器可使用的工具。- 从
langchain.tools导入Tool方法。 name参数:为工具起名,例如 “Python代码执行工具”、“CSV分析工具”。description参数:描述工具功能,用于AI选择。
工具定义描述
Section titled “工具定义描述”description赋值为工具的描述。- 告知AI工具的作用和使用情况。
func 参数
Section titled “func 参数”- 需要赋值给使用工具时调用的函数或方法。
- 使用
agent执行器时,调用invoke方法。 - 把执行器的
invoke方法作为参数传入即可。
Agent 参数
Section titled “Agent 参数”llm参数:要使用的聊天模型。memory赋值为创建好的记忆实例。tools赋值为包含多个工具的列表。prompt参数赋值给提示模板,可从 LangChain Hub 上直接拉取。
Agent 执行器
Section titled “Agent 执行器”- 从
langchain.agents导入AgentExecutor - 调用
AgentExecutor.from_agent_and_tools方法 - 参数:
agent,tools - 之前定义
agent时也传入了tools,但那只是为了让它知道有哪些工具可以使用 agent执行器才是实际调用工具的那个- 实现连续对话,把记忆也定义出来
memory = ConversationBufferMemory( memory_key="chat_history", return_messages=True)agent_executor = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, memory=memory, handle_parsing_errors=True)Agent 执行器 (AgentExecutor)
Section titled “Agent 执行器 (AgentExecutor)”AgentExecutor用于执行Agent。- 实例化
AgentExecutor时,需要传入以下参数: agent:之前创建的agent实例。tools:agent可以使用的工具列表。memory:记忆组件。memory_key需要设置为chat_history,因为之前提示模板中对应的记忆变量名就是chat_history。ConversationBufferMemory示例:
memory = ConversationBufferMemory( memory_key='chat_history', return_messages=True)
agent_executor = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, memory=memory, handle_parsing_errors=True)handle_parsing_errors 参数
Section titled “handle_parsing_errors 参数”- 可选参数,设置为
True。 - 作用:当
agent执行器在执行过程中,如果模型没有按照 ReAct 框架的格式输出,会产生解析错误。 - 默认情况下,程序会直接终止。
- 设置为
True后,agent执行器会将错误作为观察 (Observation) 发送回大模型,让大模型自行推理并处理错误。 - 这是一个很实用的参数,可以提高
agent的鲁棒性。 - 局限性:由于大模型的输出具有不稳定性,即使
handle_parsing_errors设置为True,agent的执行仍可能出现问题。
agent执行器参数:verbose
Section titled “agent执行器参数:verbose”verbose:是否以详细模式运行- 默认为
False - 设为
True:打印执行日志 - agent 执行器在调用后直接返回最终结果
- 除非
verbose设为True
Invoke的最终结果
Section titled “Invoke的最终结果”- 是一个包含输入、输出以及对话列表的字典
- 可直接提取
output值对应的键 - 使用之前定义
TextLengthTool得到的结果一致,因为agent执行器也是用的同一个工具 - 有效解决了计算字数时AI胡说八道的问题
- Agent 对字数不相关问题也能判断不需要借助
文本字数计算工具,直接输出答案 - Agent 通过集成适应不同需求,解决不同问题的工具,以及复杂的决策和推理过程
调用 Pandas 库操作 CSV 数据文件 (续)Agent的工具选择
Section titled “调用 Pandas 库操作 CSV 数据文件 (续)Agent的工具选择”- Agent能正确选择合适的工具来回答问题。
- 例如,对数据分析问题选择
CSV分析工具。 - 对文本相关问题选择
文本字数计算工具。 - 总结:通过给AI加装备(提供工具),能弥补其能力短板,让AI变得更强。
项目五:CSV数据分析智能工具
Section titled “项目五:CSV数据分析智能工具”- 目的:一个基于
agent的CSV数据分析智能工具。 - 核心功能:确保AI的回答基于上传的CSV数据,而非
胡编乱造。 - 验证:可根据AI在后台打印的执行流程进行
校验。 - 能力:不仅能提供关于数据的
答案,还能进行数据的提取。
CSV数据分析智能工具演示
Section titled “CSV数据分析智能工具演示”- 网页左侧侧边栏:
- 允许用户提供自己的
OpenAI API密钥 - 主页面:
- 用户上传
CSV文件 - 仅支持
.csv后缀文件,避免解析错误 - 程序自动加载数据到网页
- 以表格形式展示数据,支持排序、搜索等交互操作
RAG 流程验证
Section titled “RAG 流程验证”- 直接将500多行数据传给大模型,基本不可能回答出正确答案
- Agent执行器不是把所有数据一股脑发给模型
- 数据集里所有房子卧室数的平均值是多少?
- 数据集里所有房子卧室数的平均值约为2.97
- 如果下载数据集并实际进行计算,会知道这个答案是正确的
CSV数据分析智能工具演示 (续)数据可视化
Section titled “CSV数据分析智能工具演示 (续)数据可视化”- 除了问题回答,还支持图表可视化:
- 散点图
- 折线图
- 条形图
- 使用条形图展示所有房子的装修状态,鼠标悬停可查看具体数据。
- ReAct 和
执行代码能提升准确性,解决token限制,节约token。 - 涉及多个步骤。
提取数据与图表展示
Section titled “提取数据与图表展示”- 工具提取数据
- 将数字通过图表展示
提取高价房源
Section titled “提取高价房源”- 提取价格高于1000万的房子
- 网页上先查看原始数据
- 排序后可看到价格高于1000万的房子
- 共八套
AI数据提取验证
Section titled “AI数据提取验证”- 点击生成回答查看提取是否正确
- AI提取的数据准确无误,并以直观的表格形式进行展示,方便进一步查看。
- CSV数据分析智能助手的具体代码将在下个视频中讲解。
文件操作实践:创建待读取文件后的操作
Section titled “文件操作实践:创建待读取文件后的操作”- 下载课程资料里的
requirements.txt文件并拖入项目 - 终端执行
pip install -r requirements.txt安装依赖 - 创建
utils.py文件,存放与AI交互代码 - 定义
dataframe_agent函数,参数: df:数据query:提问
dataframe_agent 函数参数
Section titled “dataframe_agent 函数参数”openai_api_key:用户提供的API密钥df:表示表格,具体类型为DataFramequery:用户的问题或要求,为字符串- 定义模型:
model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)
dataframe_agent 函数 (续)模型定义
Section titled “dataframe_agent 函数 (续)模型定义”- 模型类型:
gpt-3.5-turbo - 用户提供的
API密钥:通过参数传入openai_api_key,ChatOpenAI的构造函数会使用。 - 设置
temperature:遵循ReAct框架,避免发挥创造力,造成响应解析失败 - 代码示例:
from langchain_openai import ChatOpenAI
def dataframe_agent(openai_api_key, df, query): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key, temperature=0)- 从
langchain_experimental.agents.agent_toolkits这个库的agents.agent_toolkits模块导入create_csv_agent函数 LangChain提供create_dataframe_agent函数
创建 agent 变量
Section titled “创建 agent 变量”- 为了解模型思考过程,设置
verbose=True - 将结果赋值给
agent变量:
agent = create_pandas_dataframe_agent( llm=model, df=df, agent_executor_kwargs={"handle_parsing_errors": True}, verbose=True)将 query 传入 agent 的 invoke 方法
Section titled “将 query 传入 agent 的 invoke 方法”- 目标:获得AI针对
DataFrame的回答。 - 这种情况下,
agent返回的内容会直接作为字符串展示。 - 网站前端需要知道下一步是把返回的内容直接展示为字符串、表格还是图表。
- 因此不能直接传给
agent。
dataframe_agent 函数 (续)提示模版设置
Section titled “dataframe_agent 函数 (续)提示模版设置”- 代码中可找到提示模版
PROMPT_TEMPLATE - 提示词工程:指导AI如何根据用户指令返回文本、表格、柱状图等数据
- 示例:
- 请求文本:返回
answer键 - 请求表格:返回
table键 - 请求柱状图:返回
bar键 - 键值对类型:
- 键:
columns(类型:字符串列表) - 键:
data(类型:数字列表) - 借助
Streamlit组件,将数据渲染为图表,代码更清晰
根据用户请求生成图表
Section titled “根据用户请求生成图表”- 如果用户需要一个表格,按照
JSON格式回应: - 键为
table,值为字典 columns:对应表格的列名,列表data:对应表格的内容,列表- 如果用户请求图表,按
JSON格式回应: - 键为
bar:条形图 - 键为
line:折线图 - 键为
scatter:散点图 - 值:字典
columns:对应图表的轴,列表data:对应图表里面的内容,列表AI返回的都是字符串,下一步才是解析为字典
dataframe_agent 函数 (续) 提示词设置
Section titled “dataframe_agent 函数 (续) 提示词设置”- 代码中可找到提示模版
PROMPT_TEMPLATE - 提示词工程:指导AI如何根据用户指令返回文本、表格、柱状图等数据
- 示例:
- 请求文本:返回
answer键 - 请求表格:返回
table键 - 请求柱状图:返回
bar键 - 键值对类型:
- 键:
columns(类型:字符串列表) - 键:
data(类型:数字列表) - 借助
Streamlit组件,将数据渲染为图表,代码更清晰
提示词工程 (续) 输出格式控制:JSON
Section titled “提示词工程 (续) 输出格式控制:JSON”- 将所有输出作为
JSON字符串返回 - 方便解析
- 提示:
- 注意要将
columns列表和数据列表中的所有字符串都用双引号包围 - 这是属于
JSON字符串的其中一个格式要求
拼接用户要求和补充要求
Section titled “拼接用户要求和补充要求”- 将用户的问题和补充要求拼接起来
- 代码:
prompt = PROMPT_TEMPLATE + query
调用agent执行器的invoke方法
Section titled “调用agent执行器的invoke方法”- 代码:
response = agent.invoke({"input": prompt}) - 将
prompt作为输入参数
dataframe_agent 函数 (续) 代码实现
Section titled “dataframe_agent 函数 (续) 代码实现”- 使用
json.loads()方法解析JSON字符串。 - 代码:`response_dict = json.loads(response[
dataframe_agent 函数 (续)代码实现准备
Section titled “dataframe_agent 函数 (续)代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续)返回值
Section titled “generate_script 函数 (续)返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- a模型`
- 第二个参数:
video_length(时长),例如1分钟。 - 第三个参数:
creativity(创造性),例如0.7。 - 第四个参数:
api_key(API 密钥)。
generate_script 函数 (续) API 密钥获取
Section titled “generate_script 函数 (续) API 密钥获取”- API 密钥可以通过导入
os模块,然后使用
s\n## 搭建网站主页:main.py 文件
- 创建
main.py文件:表示网站主页。 - 导入库:
import streamlit as stfrom utils import qa_agent- 网页标题:`st.title(
dataframe_agent 函数 (续)准备调用
Section titled “dataframe_agent 函数 (续)准备调用”- 调用
pd.read_csv()读取CSV文件。 - 示例:`df = pd.read_csv(
网站框架搭建 (续)代码实现准备
Section titled “网站框架搭建 (续)代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续)返回值
Section titled “generate_script 函数 (续)返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- a模型`
- 第二个参数:
video_length(时长),例如1分钟。 - 第三个参数:
creativity(创造性),例如0.7。 - 第四个参数:
api_key(API 密钥)。
generate_script 函数 (续) API 密钥获取
Section titled “generate_script 函数 (续) API 密钥获取”- API 密钥可以通过导入
os模块,然后使用os.getenv("OPENAI_API_KEY")从环境变量中获取。
网站框架搭建 (续)代码实现准备
Section titled “网站框架搭建 (续)代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续)返回值
Section titled “generate_script 函数 (续)返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- a模型`
- 第二个参数:
video_length(时长),例如1分钟。 - 第三个参数:
creativity(创造性),例如0.7。 - 第四个参数:
api_key(API 密钥)。
generate_script 函数 (续) API 密钥获取
Section titled “generate_script 函数 (续) API 密钥获取”- API 密钥可以通过导入
os模块,然后使用st.sidebar - 使用
st.text_input()添加密钥输入框,type="password"隐藏输入。 - 使用
st.markdown()添加链接到 OpenAI API 密钥获取页面。
网页主页设置
Section titled “网页主页设置”- 使用
st.file_uploader()添加文件上传组件。 accept_multiple_files=False:仅允许上传单个文件。type=[``"pdf"]`:限制上传文件类型为 PDF。- 如果用户上传了文件:
if uploaded_file is not None:。 - 使用
st.info()显示上传成功的提示信息。
CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数: - 提示文字,如"上传你的数据文件 (CSV格式)" - type="csv":限制只能上传CSV文件。 - data = st.file_uploader(...):将上传的文件赋值给data变量。 - 读取并展示数据: - 用户上传CSV文件后,读取数据并用Streamlit的表格组件展示。 - 这样用户可以一边看数据内容,一边与AI交互。 - Pandas库:读取CSV数据需要借助pandas库。 - 导入pandas as pd。
Section titled “CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数: - 提示文字,如"上传你的数据文件 (CSV格式)" - type="csv":限制只能上传CSV文件。 - data = st.file_uploader(...):将上传的文件赋值给data变量。 - 读取并展示数据: - 用户上传CSV文件后,读取数据并用Streamlit的表格组件展示。 - 这样用户可以一边看数据内容,一边与AI交互。 - Pandas库:读取CSV数据需要借助pandas库。 - 导入pandas as pd。”if data:
- 使用
pd.read_csv(data)读取上传的CSV文件到DataFrame。 - 将
DataFrame存储在会话状态中:st.session_state["df"] = pd.read_csv(data) - 使用
st.expander创建一个可折叠的组件,用于显示原始数据。 - 指定
st.expander对应的文字:例如原始数据。
CSV数据分析智能工具 (续) 页面实现
Section titled “CSV数据分析智能工具 (续) 页面实现”- 在
st.expander("原始数据")代码块里,调用st.dataframe()函数来展示上传的CSV数据。 st.dataframe()参数:传入st.session_state["df"],即之前存储的DataFrame。- 这样,用户上传CSV文件后,页面会显示一个可折叠的“原始数据”组件。
- 展开后,用户能看到整个数据表格,并进行排序和搜索等交互操作。
st.dataframe还支持全屏预览等功能。- 接下来,用户还需要一个文本框来输入问题。
网页布局设置
Section titled “网页布局设置”- 使用
st.text_area(),比st.text_input()更高,可输入更多内容 - 提示文字:
"请输入你关于以上表格的问题,或者数据提取请求,或者可视化要求(支持散点图、折线图、条形图)" - 用户输入赋值给变量
query - 添加按钮:
st.button("生成回答") - 点击“生成回答”按钮后的逻辑:
if button and not openai_api_key::如果点击了按钮但未提供API密钥,则:- 提示用户输入密钥:`st.info(
网站框架搭建 (续) 添加按钮交互 (续)st.spinner() 的作用
Section titled “网站框架搭建 (续) 添加按钮交互 (续)st.spinner() 的作用”st.spinner(): 停止Streamlit应用在当前位置的执行,后续代码不会再被执行。
网站框架搭建 (续)提交按钮的条件判断
Section titled “网站框架搭建 (续)提交按钮的条件判断”- 检查&;
OpenAI API&;密钥: if submit and not openai_api_key:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供OpenAI API密钥 (openai_api_key为空,not操作使其为True)。 st.info("请输入你的OpenAI API密钥"): 显示提示信息。st.stop(): 阻止程序继续执行,直到用户输入密钥。- 检查视频主题:
if submit and not subject:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供视频主题 (subject为空,not操作使其为True)。 st.info("请输入视频的主题"): 显示提示信息。st.stop(): 阻止程序继续执行,直到用户输入主题。- 演示:在网页端清除API密钥或视频主题后点击生成脚本,会看到相应的提示信息出现,且程序停止运行。
- 增加视频长度的条件判断:
if submit and not video_length >= 0.1: - 如果视频长度小于0.1分钟,提示用户。
st.number_input返回float类型,无需类型转换。
网站框架搭建 (续) 提交按钮的条件判断
Section titled “网站框架搭建 (续) 提交按钮的条件判断”- 检查&;
OpenAI API&;密钥: if submit and not openai_api_key:- 如果用户点击了“生成脚本”按钮 (
submit为True) 且未提供OpenAI API密钥 (openai_api_key为空,not操作使其为True)。 st.info("请输入你的OpenAI API密钥"): 显示提示信息。st.stop(): 阻止程序继续执行,直到用户输入密钥。
网站框架搭建 (续) 添加按钮交互(续)
Section titled “网站框架搭建 (续) 添加按钮交互(续)”st.spinner():显示加载状态,提示用户等待。- 参数:加载时显示的文字,如
AI正在思考中,请稍后... with st.spinner(...):代码块执行完,加载提示消失。- 调用
generate_script()函数: - 调用
generate_script()函数生成结果,赋值给search_result、title、script变量.
网站框架搭建 (续) 结果展示
Section titled “网站框架搭建 (续) 结果展示”st.subheader(title):显示视频标题。st.write(script):显示视频脚本内容。st.caption(search_result):在脚本下方显示维基百科搜索结果。
网站框架搭建 (续) 链接维基百科内容
Section titled “网站框架搭建 (续) 链接维基百科内容”search_result:展示维基百科搜索结果。- 链接搜索结果,使用
st.markdown: st.markdown(f"[查看更多关于{title}的信息](https://zh.wikipedia.org/wiki/{title})")- 链接标题和维基百科搜索结果。
网站框架搭建 (续) 网站完整代码
Section titled “网站框架搭建 (续) 网站完整代码”- 网站完整代码:
import streamlit as stimport osfrom utils import generate_script
st.title("视频脚本生成器")
with st.sidebar: openai_api_key = st.text_input("请输入OpenAI API密钥", type="password") st.markdown("[获取OpenAI API密钥](https://platform.openai.com/account/api-keys)")
subject = st.text_input("请输入视频的主题")video_length = st.number_input("请输入视频的大致时长(单位:分钟)", min_value=0.1, step=0.1)creativity = st.slider("请输入视频脚本的创造力(数字越大说明创造力越强)", min_value=0.0, max_value=1.0, value=0.2, step=0.1)
submit = st.button("生成脚本")
if submit and not openai_api_key: st.info("请输入你的OpenAI API密钥") st.stop()
if submit and not subject: st.info("请输入视频的主题") st.stop()
if submit and not video_length >= 0.1: st.info("视频长度需要大于或等于0.1") st.stop()
if submit: with st.spinner("AI正在思考中,请稍候..."): search_result, title, script = generate_script(subject, video_length, creativity, openai_api_key)
st.subheader(title) st.write(script) st.caption(search_result) st.markdown(f"[查看更多关于{title}的信息](https://zh.wikipedia.org/wiki/{title})")网站框架搭建 (续) 代码演示
Section titled “网站框架搭建 (续) 代码演示”- 运行代码:
streamlit run main.py - 页面提示:请输入OpenAI API密钥,请输入视频的主题,视频长度需要大于或等于0.1
- 都填好后,点击生成脚本
- 页面生成:视频标题,视频脚本,查看更多关于xxx的信息
- 点击查看更多关于xxx的信息:可以跳转到维基百科
网站框架搭建 (续) 结果展示信息
Section titled “网站框架搭建 (续) 结果展示信息”st.spinner()停止后,展示结果。- `st.success(
dataframe_agent 函数 (续) 代码实现
Section titled “dataframe_agent 函数 (续) 代码实现”- 使用
json.loads()方法解析JSON字符串。 - t”``])`
- 从
response_dict提取信息,展示在网页上。 - 根据
response_dict包含的键,决定如何处理AI的回复。 answer键:直接显示文本。table键:将数据渲染成表格。bar、line、scatter键:将数据渲染成图表。
代码演示:response_dict 包含 answer 键
Section titled “代码演示:response_dict 包含 answer 键”- 示例:`if
dataframe_agent 函数 (续)代码实现
Section titled “dataframe_agent 函数 (续)代码实现”- 使用
json.loads()方法解析JSON字符串。 - 代码:
response_dict = json.loads(response["answer"]) - 确保
from utils import dataframe_agent。 - 将
streamlit代码和utils.py代码结合。
df = pd.DataFrame(response_dict["table"]["data"], columns=response_dict["table"]["columns"])- 从
response中获取数据并创建DataFrame。 - 调用
streamlit的table函数展示DataFrame。 - 代码:
st.table(df) - 网页可显示表格数据
网站框架搭建 (续) 网页完整代码
Section titled “网站框架搭建 (续) 网页完整代码”- 完整代码:实现数据上传、AI提问、结果展示。
- 侧边栏:API密钥。
- 主页面:上传CSV,查看数据,输入问题,生成回答。
- 使用
st.dataframe展示原始数据,支持排序和搜索。 - 使用
st.text_area接受用户提问,并使用st.button触发。 - 使用
st.spinner展示加载状态,再调用dataframe_agent生成结果。 - 根据AI返回的内容,决定使用
st.write展示文本,还是使用st.table展示表格。 - 详细代码请参见视频。
- 点击“生成回答”按钮:程序进行判断,确保API密钥和问题都已提供。
网站框架搭建 (续) 代码演示
Section titled “网站框架搭建 (续) 代码演示”- 运行程序:
streamlit run main.py - 上传CSV文件,输入问题,点击“生成回答”按钮,即可查看结果。
提示工程的总结
Section titled “提示工程的总结”- 提示词工程:设计、优化提示,控制模型行为。
- 确保从AI得到各字段符合格式和内容要求的JSON。
- 保证模型输出的JSON字符串,解析成BookInfo实例。
- 要让AI返回指定格式,不仅要给提示,还要用代码进行规范和约束。
- 在代码里对
AI添加各种形式的约束,保证程序的稳定性和可靠性。
- 学习过程:理论知识 -> 代码实战 -> 部署到云端,更多用户使用。
- Python基础:变量、数据类型、条件循环、函数、类、模块、异常。
- 提示词工程:设计、优化提示,控制模型行为。
- LangChain框架:简化AI应用开发,组件化、模块化。
- Streamlit框架:快速构建交互式Web应用。
- 实践和探索:持续学习,成为AI应用开发高手!
- 恭喜完成所有课程,期待AI世界探索之旅!
循环语句应用:for循环
Section titled “循环语句应用:for循环”- 可用于列表、字典、字符串等数据结构的迭代。
- 对列表迭代:按顺序处理每个元素。
实现小样本提示
Section titled “实现小样本提示”- 在
messages参数中: role为user:提示词示例。role为assistant:对应回复示例。- 示例:用户提示的
role值为user,AI回应的role值为assistant。 - 小样本示例能让AI快速适应新任务,且不需要对模型进行任何训练,成本低又灵活。
实现历史消息展示
Section titled “实现历史消息展示”- 使用
st.session_state获取历史消息: st.session_state["messages"]:存储所有对话消息的列表- 循环遍历消息列表:
for message in st.session_state["messages"]: st.chat_message(message["role"]).write(message["content"])st.chat_message(message["role"]):根据消息角色(message["role"]),设置消息的显示样式(例如头像)。.write(message["content"]):将消息内容(message["content"])写入到对应的消息框中。
"role": "ai", "content": "你好,我是你的AI助手,有什么可以帮你的吗?"- 展示第一条初始消息
- 往页面传入角色和消息的内容
st.chat_message(message["role"]).write(message["content"])st.chat_message():根据角色,选择不同样式(头像)write():写入消息内容
message["content"]- 消息内容对应
message的content值 - 这样,页面上就会展示该角色说的话
- 针对第一条消息,这里传入的是AI字符串
- 保存后回到页面,成功展示初始消息
- 接下来,给用户提供一个输入框
代码控制AI交互的优势
Section titled “代码控制AI交互的优势”- 从网页上抓取AI回复比较麻烦
- 代码控制更灵活
- 可调整AI回复的长度、创造性、频率惩罚等参数
- 可使用提示模板提高效率
- 可精确控制请求参数,如限制AI回答的token数
- 可对大量数据进行批处理
- 例如,用AI一次性总结多个文档
- 可将AI集成到自己的系统或流程中
LangChain 框架组件
Section titled “LangChain 框架组件”- LangChain 提供的组件包括:
- 模型 (
Model): 提供语言理解和生成能力,是 AI 应用的核心。 - 记忆 (
Memory): 用于存储和管理对话历史或相关上下文信息,使 AI 能够记住之前的交互。 - 链 (
Chain): - 检索器 (
Retriever): - 智能体 (
Agent):
Python 关键字
Section titled “Python 关键字”- PyCharm 会对 Python 关键字进行颜色高亮显示。
- 如果变量名是彩色的,说明是关键字,最好换成其他的。
Python 数据类型
Section titled “Python 数据类型”- Python 的整数和字符串是不同的类型。
- 整数:直接的数字,不要用引号包裹。
- 用引号包裹的数字是字符串
Python 数据类型 (续)
Section titled “Python 数据类型 (续)”- 浮点数:带小数点的数字。
- 例:
6.0 - 数学运算:
- 加减乘除:
+、-、*、/ - 乘号:
*(星号) - 除号:
/(正斜杠,shift键左边那个) - 示例:
1 + 2 - 3 / 4 * 5 - 运算顺序:先括号,然后乘方,然后乘除,最后加减
- 乘方符号:Python里是两个星号
Python 数学运算进阶:math 模块
Section titled “Python 数学运算进阶:math 模块”- 求2的三次方:
2 ** 3 - Python能做加减乘除、乘方,但更复杂的(三角函数、log、开方等)需导入
math模块。 - 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
print是函数,提供展示/输出功能。print是内置函数,Python 默认自带。math专门提供数学运算函数。- 导入&;
math&;模块:在文件开头写import math。 - 调用
math模块中的函数:math.函数名()
Python 数学运算进阶:math 模块 (续)导包及查看函数
Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”- 调用
math模块函数:math.函数名() - 计算sin 1弧度:
math.sin(1) - 计算以2为底8的对数:
math.log2(8) - 注意:单纯运算无输出,需使用
print
Python 数学运算进阶:math 模块 (续)
Section titled “Python 数学运算进阶:math 模块 (续)”- 若要展示数学计算结果,需使用
print或变量赋值。 - 示例:
import mathprint(math.log2(8))
result = math.log2(8)print(result)- 目标:编写一元二次方程求根公式计算器。
- 公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$
- 示例:计算 $-x^2 - 2x + 3 = 0$ 的实数根。
- a = -1, b = -2, c = 3
a = -1b = -2c = 3Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”- 平方根表示:
- 方法一:使用
**0.5,即 1/2 次方。 - 方法二:使用
math库中的sqrt()函数。 - 代码示例:
import math
a = -1 b = -2 c = 3
# 使用 math.sqrt() 函数 solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a) solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1) print(solution2)- 注意:数学公式中乘号可省略,但代码中不可省略。
- 一元二次方程求根公式计算器:完整代码实现及输出结果。
- 确保分子部分用括号
()括起来,再进行除法运算。 - 必须使用
print()函数才能在控制台看到计算结果。 - 示例代码:
import math
a = -1b = -2c = 3
# 第一个解:加号部分solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)print(solution2)- 运行结果:显示两个方程的解,例如
-3.0和1.0。
Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”- 只需更改变量
a、b、c的值,无需修改公式。 - 代码示例,计算 $x^2 + 9x + 20 = 0$ 的根:
import math
a = 1b = 9c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))- 结果展示正确。
- 用代码做数学计算的好处:
- 可以看到整个公式,方便检查,不易出错。
- 容易更改变量值,无需重复录入公式。
- 可通过中间变量分步骤,处理复杂公式。
- 例如,将 $b^2 - 4ac$ 赋值给
delta变量:
delta = b**2 - 4*a*c- 简化后续代码书写。
代码注释:给人看的解释
Section titled “代码注释:给人看的解释”- 用于解释代码思路,方便他人或自己理解。
- Python里,注释以
#开头,解释器会忽略该行。
代码注释 (续) 单行与多行注释
Section titled “代码注释 (续) 单行与多行注释”- 单行注释:以
#开头 - 多行注释:
- 方法一:每行开头加
# - 方法二:用三引号
"""或'''包裹
- 解释代码
- 临时禁用代码:在代码前加
#,跳过执行
PyCharm快捷键注释
Section titled “PyCharm快捷键注释”- 选中代码块,使用快捷键:
- Windows:
Ctrl + / - Mac:
Command + / - 再次使用快捷键取消注释
代码注释补充说明
Section titled “代码注释补充说明”- 多行注释可用三引号
"""或'''包裹,但跨行字符串也用三引号,注意区分。 - 建议不要在注释里过度放飞自我。
- 现实世界里食物、动物、人有不同种类,抽象世界里数字有不同种类,Python世界里数据也有不同种类。
Python 数据类型 (续)字符串 str
Section titled “Python 数据类型 (续)字符串 str”- 字符串类型
str:表示文本内容,由双引号或单引号包裹。 - 可用
len()函数获取字符串长度。 - 空格、数字、符号都占长度。
- 转义符(如
\n换行符)整体占一个长度。 - 提取字符串某位置的单个字符:字符串后跟方括号
[],内放索引。 - 索引可理解为顺序,但程序世界从
0开始计数。 - 提取字符串字符:
字符串[索引],索引从0开始。例如,"Hello"[3]返回"l"。索引为3表示第四个字符。 - 整数
int:如6、-32。 - 浮点数
float:如6.0、10.07。 - 布尔类型
bool:只有两个值:True和False。 True和False的首字母必须大写。- 空值类型
NoneType:只有一种值:None。 None不是 0,不是空字符串,也不是False。- 空值类型
NoneType:表示完全没有值 - 可先定义变量为
None None不是0,不是空字符串"",也不是False- 可用
type()函数返回对象类型 type("Hello")-> `<class
网页布局设置 (续)一
Section titled “网页布局设置 (续)一”- 代码:
if "bar" in response_dict: st.bar_chart(pd.DataFrame(response_dict["data"], columns=response_dict["columns"]))`- 使用
streamlit的bar_chart方法,参数: -data:图表数据 -columns:列名
网页布局设置 (续)二
Section titled “网页布局设置 (续)二”- 运行代码,上传数据文件,输入问题“用条形图展示房屋装修情况”,点击生成回答 - 展示条形图,鼠标悬停查看数据
- 除了条形图,散点图和折线图都以类似方式展示
- 集成多个工具于一身的智能agent已初步成型
- 步骤: - 用户上传数据文件 - 提出问题 - agent给出图表
- 核心:数据在本地,没有发给任何人,安全
- 学习使用LangChain连接各种工具,实现各种应用
部署AI应用到云端
Section titled “部署AI应用到云端”- 目标:创建AI应用,部署到云端,让更多人使用
- 示例:使用streamlit share免费部署AI应用
- 需要: - GitHub账号 - 包含代码的GitHub仓库 - 简单的部署知识
云部署方法步骤
Section titled “云部署方法步骤”- 创建GitHub仓库: - 存放所有代码文件 - 方便streamlit share读取
- 准备必要文件: -
requirements.txt:包含项目所有依赖项及其版本号 -main.py:包含网站代码 - 访问streamlit share:share.streamlit.io
部署AI应用到云端 (续) Streamlit Share 部署步骤
Section titled “部署AI应用到云端 (续) Streamlit Share 部署步骤”- 访问streamlit share:share.streamlit.io
- 点击“New app”按钮
- 填写信息: - 仓库 (repository):选择GitHub仓库 - 分支 (branch):选择分支,一般为main - 主脚本文件路径 (main script path):一般为main.py
- 点击“Deploy!”按钮,等待部署完成
部署AI应用到云端 (续) 部署成功
Section titled “部署AI应用到云端 (续) 部署成功”- 部署成功:浏览器自动打开新页面,显示已部署的AI应用
- 修改代码:在GitHub仓库修改代码,streamlit share会自动更新,无需重复部署
- 优势: - 简单易用,无需服务器配置 - 免费部署,降低开发成本
- 学习了Python基础语法、LangChain、Streamlit等 - 掌握了AI应用开发流程:数据准备、模型选择、提示工程、代码实现、用户界面、部署上线
RAG 步骤 (续) 网页布局
Section titled “RAG 步骤 (续) 网页布局”- 使用
st.columns(2)创建双列布局。 left_column:显示小红书标题- 使用索引提取
result.titles列表中的元素,索引从0开始 - 示例:
st.write(result.titles[0]),提取第一个标题 right_column:显示小红书正文- 使用
st.markdown添加五级标题 - 使用
st.write展示result.content属性
- 采用多列布局:
st.columns(2) - 返回列表,分别赋值给
left_column和right_column - 侧边栏输入密钥,主页面输入主题,点击开始写作。
- 页面加载中,显示5个待选标题和正文。
代码实现:历史对话展示
Section titled “代码实现:历史对话展示”- 使用
for循环迭代st.session_state[``messages]`: - 代码:
for message in st.session_state[``messages]:` st.chat_message(message[``role]).write(message[``content])\:在页面上展示消息。- 根据
message的role属性,用不同的样式显示(模拟不同用户)。 if "memory" not in st.session_state::检查会话状态中是否已存在名为“memory”的键。- 如果不存在,则初始化
st.session_state["memory"]为ConversationBufferMemory实例。 return_messages=True:确保记忆存储的是消息列表,而不是一整坨字符串。memory_key="chat_history":将记忆的键设置为"chat_history",因为后端ConversationalRetrievalChain期望用此键来获取对话历史。output_key="answer":将输出结果的键设置为"answer",这是ConversationalRetrievalChain中AI模型回应的默认键。
图表绘制前的额外操作
Section titled “图表绘制前的额外操作”Streamlit的图表函数不接受列表,需将数据转换为DataFrame:df_data = pd.DataFrame(input_data['data'], columns=input_data['columns'])data键:对应DataFrame里的内容columns键:对应列名- 设置
DataFrame的索引:df_data.set_index(input_data['columns'][0]) - 索引会被用来表示图表的横轴
网站框架搭建 (续) 绘制图表功能实现
Section titled “网站框架搭建 (续) 绘制图表功能实现”create_chart函数:- 接收
input_data和chart_type作为参数。 - 将
input_data转换为DataFrame(df_data),并设置索引。 - 根据
chart_type绘制不同图表: - 如果
chart_type为"bar"(条形图): - 调用
st.bar_chart(df_data)。 - 如果
chart_type为"line"(折线图): - 调用
st.line_chart(df_data)(后续实现)。 - 这些操作与AI大模型不直接相关,如果想了解更多数据操作,可参考相关Python数据分析课程。
图表绘制 (续)Streamlit组件调用
Section titled “图表绘制 (续)Streamlit组件调用”st.line_chart(df_data):折线图st.scatter_chart(df_data):散点图st.bar_chart(df_data):条形图- 需传入
DataFrame - 图表类型有
bar、line和scatter - 使用
elif语句 - 传给
create_chart的参数: - 数据
response_dict[``"bar"]` - 图表类型
"bar"
根据用户请求生成图表
Section titled “根据用户请求生成图表”- 如果用户需要一个表格,按照
JSON格式回应: - 键为
table,值为字典 columns:对应表格的列名,列表data:对应表格的内容,列表- 如果用户请求图表,按
JSON格式回应: - 键为
bar:条形图 - 键为
line:折线图 - 键为
scatter:散点图 - 值:字典
columns:对应图表的轴,列表data:对应图表里面的内容,列表AI返回的都是字符串,下一步才是解析为字典
dataframe_agent 函数 (续) 提示词设置
Section titled “dataframe_agent 函数 (续) 提示词设置”- 代码中可找到提示模版
PROMPT_TEMPLATE - 提示词工程:指导AI如何根据用户指令返回文本、表格、柱状图等数据
- 示例:
- 请求文本:返回
answer键 - 请求表格:返回
table键 - 请求柱状图:返回
bar键 - 键值对类型:
- 键:
columns(类型:字符串列表) - 键:
data(类型:数字列表) - 借助
Streamlit组件,将数据渲染为图表,代码更清晰
提示词工程 (续) 输出格式控制:JSON
Section titled “提示词工程 (续) 输出格式控制:JSON”- 将所有输出作为
JSON字符串返回 - 方便解析
- 提示:
- 注意要将
columns列表和数据列表中的所有字符串都用双引号包围 - 这是属于
JSON字符串的其中一个格式要求
拼接用户要求和补充要求
Section titled “拼接用户要求和补充要求”- 将用户的问题和补充要求拼接起来
- 代码:
prompt = PROMPT_TEMPLATE + query
调用agent执行器的invoke方法
Section titled “调用agent执行器的invoke方法”- 代码:
response = agent.invoke({"input": prompt}) - 将
prompt作为输入参数
dataframe_agent 函数 (续) 代码实现
Section titled “dataframe_agent 函数 (续) 代码实现”- 使用
json.loads()方法解析JSON字符串。 - 代码:
response_dict = json.loads(response["answer"])
dataframe_agent 函数 (续)代码实现准备
Section titled “dataframe_agent 函数 (续)代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续)返回值
Section titled “generate_script 函数 (续)返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- a模型`
- 第二个参数:
video_length(时长),例如1分钟。 - 第三个参数:
creativity(创造性),例如0.7。 - 第四个参数:
api_key(API 密钥)。
generate_script 函数 (续) API 密钥获取
Section titled “generate_script 函数 (续) API 密钥获取”- API 密钥可以通过导入
os模块,然后使用st.sidebar - 使用
st.text_input()添加密钥输入框,type="password"隐藏输入。 - 使用
st.markdown()添加链接到 OpenAI API 密钥获取页面。
网页主页设置
Section titled “网页主页设置”- 使用
st.file_uploader()添加文件上传组件。 accept_multiple_files=False:仅允许上传单个文件。type=["pdf"]:限制上传文件类型为 PDF。- 如果用户上传了文件:
if uploaded_file is not None:。 - 使用
st.info()显示上传成功的提示信息。
CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:
Section titled “CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:”- 提示文字,如
"上传你的数据文件 (CSV格式)" type="csv":限制只能上传CSV文件。data = st.file_uploader(...):将上传的文件赋值给data变量。- 读取并展示数据:
- 用户上传CSV文件后,读取数据并用
Streamlit的表格组件展示。 - 这样用户可以一边看数据内容,一边与AI交互。
- Pandas库:读取CSV数据需要借助
pandas库。 - 导入
pandas as pd。
if data:
- 使用
pd.read_csv(data)读取上传的CSV文件到DataFrame。 - 将
DataFrame存储在会话状态中:st.session_state["df"] = pd.read_csv(data) - 使用
st.expander创建一个可折叠的组件,用于显示原始数据。 - 指定
st.expander对应的文字:例如原始数据。
CSV数据分析智能工具 (续) 页面实现
Section titled “CSV数据分析智能工具 (续) 页面实现”- 在
st.expander("原始数据")代码块里,调用st.dataframe()函数来展示上传的CSV数据。 st.dataframe()参数:传入st.session_state["df"],即之前存储的DataFrame。- 这样,用户上传CSV文件后,页面会显示一个可折叠的“原始数据”组件。
- 展开后,用户能看到整个数据表格,并进行排序和搜索等交互操作。
st.dataframe还支持全屏预览等功能。- 接下来,用户还需要一个文本框来输入问题。
网页布局设置
Section titled “网页布局设置”- 使用
st.text_area(),比st.text_input()更高,可输入更多内容 - 提示文字:
"请输入你关于以上表格的问题,或者数据提取请求,或者可视化要求(支持散点图、折线图、条形图)" - 用户输入赋值给变量
query - 添加按钮:
st.button("生成回答") - 点击“生成回答”按钮后的逻辑:
if button and not openai_api_key::如果点击了按钮但未提供API密钥,则:- 提示用户输入密钥:`st.info(
CSV数据分析智能助手演示 (续)数据可视化
Section titled “CSV数据分析智能助手演示 (续)数据可视化”- 除了问题回答,还支持图表可视化:
- 散点图
- 折线图
- 条形图
- 使用条形图展示所有房子的装修状态,鼠标悬停可查看具体数据。
- ReAct 和
执行代码能提升准确性,解决token限制,节约token。 - 涉及多个步骤。
从结果来看,在这个数据里面好像没有特别明显的关系,如果尝试时发现会绘制失败,可以切换小一点的数据集试一试。欢迎在这个CSV智能工具的基础上继续扩展,让它变得更加强大。来适应你的私人分析需求。再见!
Assistant API 概念
Section titled “Assistant API 概念”- 助手(Assistant)
- 能使用
OpenAI模型,并能调用相关工具的AI。 - 需要指定助手背后的模型、名字、描述(系统指令)以及可使用的工具。
- 线程(Thread)
- 表示助手和用户之间的一系列对话。
- 线程存储消息,并且当超过模型上下文窗口时,对对话进行截断。
- 消息(Message)
- 表示来自助手或用户的消息。
- 格式可以是文本、图片、文件等。
- 消息会以列表形式存储在线程上。
- 运行(Run)
- 表示在某个线程上调用助手的动作。
Assistant API 的使用
Section titled “Assistant API 的使用”- 可使用代码解释器(
Code Interpreter)创建数学助手 - 使用
Assistant API,只需用到openai库
创建 OpenAI 实例
Section titled “创建 OpenAI 实例”- 确保电脑环境变量有
OpenAI密钥
Assistant API 支持的工具
Section titled “Assistant API 支持的工具”Code Interpreter(代码解释器)Knowledge Retrieval(文件检索)Function Calling(自定义函数调用)
OpenAI Assistant API 使用准备
Section titled “OpenAI Assistant API 使用准备”- 从
openai库导入OpenAI:
from openai import OpenAI- 创建一个
OpenAI实例:
client = OpenAI()- 电脑的环境变量里有
OpenAI密钥,环境变量的密钥值会自动传递 - 函数名
beta是测试的意思,说明当前OpenAI觉得这个assistant API还有测试和完善的空间
OpenAI Assistant API 的使用 (续)
Section titled “OpenAI Assistant API 的使用 (续)”- platform.openai.com/docs/assistants 访问此链接以查看相关信息。
- 目标:创建一个能准确回答数学问题的助手。
- 函数接收的参数:包括
model模型名,例如:gpt-3.5-turbo。 name:赋值为给助手起的名字,例如:"数学助手"。instructions:需要赋值为给助手的一些指令,例如:助手的角色是什么,它可以做什么来回答用户问题等。- 在
instructions里,要求它通过运行代码来回答数学相关问题。
创建数学助手:tools 参数
Section titled “创建数学助手:tools 参数”tools参数:client.beta.assistants.create方法,用于指定助手可使用的工具,需为列表- 列表元素表示AI可用的工具
- 主要用到代码解释器
- 需传入
type键,其值为code_interpreter的字典 - ```python
tools=([“type”: “code_interpreter”])
- 表示使用**代码解释器**- 定义助手后下一步是创建线程 - 不同用户对应独立线程,避免历史对话消息混淆 - 同个用户也可有不同对话线程 - 像在ChatGPT上,也可开启多个对话窗口Assistant API 的线程 (Thread)操作
Section titled “Assistant API 的线程 (Thread)操作”- 使用
client.beta.threads.create()函数创建线程。 - 每个线程都有自己的
ID,用于识别不同线程,可使用thread.id输出。 - 向线程添加消息,调用
client.beta.threads.messages.create()函数。
message = client.beta.threads.messages.create:调用客户端的函数thread_id=thread.id:线程IDrole="user":需要赋值为角色- 用户对应
"user" - 助手对应
"assistant" content赋值为消息内容
Assistant API 的线程操作
Section titled “Assistant API 的线程操作”- 使用
client.beta.threads.create()函数创建线程。 - 每个线程有自己的
ID,用于识别不同线程,如thread.id。 - 向线程添加消息,调用
client.beta.threads.messages.create()函数。 - 消息格式:文本、图片、文件等。
Assistant API 使用中的参数传递
Section titled “Assistant API 使用中的参数传递”thread_id:赋予给线程的ID属性。assistant_id:赋予给助手ID属性。instructions:赋值字符串,提供额外运行指令。- 确保正确传递参数。
Assistant API的运行状态检索函数
Section titled “Assistant API的运行状态检索函数”- 运行状态:初始为
queued(排队中),然后是in_progress(生成中) - 最终结果未出
- 使用
client.beta.threads.runs.retrieve函数:传入线程ID,查询运行状态
Assistant API 的线程 (Thread)操作
Section titled “Assistant API 的线程 (Thread)操作”- 使用
client.beta.threads.create()函数创建线程。 - 每个线程有自己的
ID,用于识别不同线程,如thread.id。 - 向线程添加消息,调用
client.beta.threads.messages.create()函数。 - 消息格式:文本、图片、文件等。
Assistant API 使用中的参数传递
Section titled “Assistant API 使用中的参数传递”thread_id:赋予给线程的ID属性。assistant_id:赋予给助手ID属性。instructions:赋值字符串,提供额外运行指令。- 确保正确传递参数。
Assistant API的运行状态检索函数 (续)参数传递
Section titled “Assistant API的运行状态检索函数 (续)参数传递”- 运行状态:初始为
queued(排队中),然后是in_progress(生成中) - 最终结果未出
- 使用
client.beta.threads.runs.retrieve函数:传入线程ID,查询运行状态 - 赋予给线程的
ID属性 - 赋予给助手
ID属性 - 赋值字符串,提供额外运行指令
- 确保正确传递参数
Assistant API 的线程操作
Section titled “Assistant API 的线程操作”- 使用
client.beta.threads.create()函数创建线程。 - 每个线程有自己的
ID,用于识别不同线程,如thread.id。 - 向线程添加消息,调用
client.beta.threads.messages.create()函数。 - 消息格式:文本、图片、文件等。
Assistant API 使用中的参数传递
Section titled “Assistant API 使用中的参数传递”thread_id:赋予给线程的ID属性。assistant_id:赋予给助手ID属性。instructions:赋值字符串,提供额外运行指令。- 确保正确传递参数。
Assistant API的运行状态检索函数
Section titled “Assistant API的运行状态检索函数”- 运行状态:初始为
queued(排队中),然后是in_progress(生成中) - 最终结果未出
- 使用
client.beta.threads.runs.retrieve函数:传入线程ID,查询运行状态
Assistant API 的线程 (Thread)操作
Section titled “Assistant API 的线程 (Thread)操作”- 使用
client.beta.threads.create()函数创建线程。 - 每个线程有自己的
ID,用于识别不同线程,如thread.id。 - 向线程添加消息,调用
client.beta.threads.messages.create()函数。 - 消息格式:文本、图片、文件等。
Assistant API 使用中的参数传递
Section titled “Assistant API 使用中的参数传递”thread_id:赋予给线程的ID属性。assistant_id:赋予给助手ID属性。instructions:赋值字符串,提供额外运行指令。- 确保正确传递参数。
Assistant API 的线程操作
Section titled “Assistant API 的线程操作”- 使用
client.beta.threads.messages.list()函数:传入线程ID,获取消息列表 - 代码:
messages = client.beta.threads.messages.list(thread_id=thread_id.thread_id) - 获取所有与线程相关的消息
messages.data:返回message的列表,包含所有消息的相关信息- 使用
for循环打印每个消息的内容 print(data.content)- 消息内容位于
content属性的第0个元素
打印消息属性
Section titled “打印消息属性”- 使用循环和
text.value打印来自用户的原始消息和AI回复。 - 每次创建新消息和更新都需要经过完整步骤。
- 可将步骤封装到一个函数中,方便调用。
- 函数接收助手、线程和用户提示词。
- 函数示例:
def get_response_from_assistant(assistant, thread, prompt, run_instruction): message = client.beta.threads.messages.create( thread_id=thread.id, role="user", content=content_prompt )
run = client.beta.threads.runs.create( thread_id=thread.id, assistant_id=assistant.id, instructions=run_instruction )
while run.status != "completed": keep_retrieving_run = client.beta.threads.runs.retrieve( thread_id=thread.id, run_id=run.id ) print(f"Run Status: {keep_retrieving_run.status}") if keep_retrieving_run.status == "completed": break
for data in messages.data: print(data.content[0].text.value) print("---")- 步骤:接收助手、线程、用户提示词以及运行指令。
Assistant API 的使用 (续) run_instruction 参数
Section titled “Assistant API 的使用 (续) run_instruction 参数”run_instruction:针对此次运行的额外指令参数- 可选,类型为字符串
- 当需要对特定运行进行调整或指示时使用
- 不需要时,可使用空字符串作为默认值,保持代码简洁
- 代码示例:
def get_response_from_assistant(assistant, thread, prompt, run_instruction=\Assistant API的检索器
Section titled “Assistant API的检索器”- 创建文件内容问答助手
- 过程与前一节相似
- 从
openai库导入OpenAI
file = client.files.create
- 需要传入
file参数的值 - 应为一个文件对象
- 使用
open函数获取文件对象 open函数为 Python 自带
Assistant API 的文件操作
Section titled “Assistant API 的文件操作”- 使用
client.files.create()创建文件对象。 - 需要指定文件路径,例如
client.files.create(file=open("论文介绍.pdf", "rb"), purpose="assistants")。 file参数:文件路径,并以"rb"(读取二进制)模式打开。purpose参数:指定文件用途,此处为"assistants",表示文件供助手使用。- 运行后,会得到一个 OpenAI 文件对象实例。
Assistant API 创建助手
Section titled “Assistant API 创建助手”- 创建助手是下一步操作。
- 对应的函数在前面已经介绍过。
OpenAI Assistant API 的使用 (续)
Section titled “OpenAI Assistant API 的使用 (续)”- 创建文件内容问答助手时,需要创建一个
Assistant实例。 assistant = client.beta.assistants.create():调用client.beta.assistants.create函数来创建助手。- 参数设置:
model="gpt-3.5-turbo":指定使用的模型。name="AI论文问答助手":为助手命名。instructions="你是一个智能助手,可以协助用户来回答人工智能论文的常见问题。":定义助手的角色和回答用户问题的指令。tools=[{"type": "code_interpreter"}]:指定助手可使用的工具列表,这里使用了代码解释器。- 代码解释器工具的类型为
code_interpreter。 - 定义助手后,下一步是创建线程 (
Thread)。
tools 参数的赋值
Section titled “tools 参数的赋值”- 需要赋值为一个列表
- 列表的每个元素表示一个
AI可使用的工具 tools=["type": "retrieval"]type键的值为retrieval的字典- 助手需根据文件内容回答问题
- 还需要把
file_ids这个参数赋值为一个列表 - 里面放上之前创建的文件实例的
ID - 想要助手阅读多个文件,只需把其他文件的
ID也放进去
Assistant API 的使用 (续)
Section titled “Assistant API 的使用 (续)”file_ids参数:指定Assistant能够访问的文件,需为列表。- 放入之前创建的文件实例的
ID即可:file_ids=[file.id] - 如果需要
Assistant阅读多个文件,将其他文件的ID也添加到列表中。 - 那么现在助手就定义好了。
- 下一步是创建线程。
- 调用客户端实例的
beta.threads.create函数:
thread = client.beta.threads.create()Assistant API 的线程操作
Section titled “Assistant API 的线程操作”- 使用
client.beta.threads.messages.list()函数:传入线程ID,获取消息列表 - 代码:
messages = client.beta.threads.messages.list(thread_id=thread_id.thread_id) - 获取所有与线程相关的消息
messages.data:返回message的列表,包含所有消息的相关信息- 使用
for循环打印每个消息的内容 print(data.content)- 消息内容位于
content属性的第0个元素
打印消息属性
Section titled “打印消息属性”- 使用循环和
text.value打印来自用户的原始消息和AI回复。 - 每次创建新消息和更新都需要经过完整步骤。
- 可将步骤封装到一个函数中,方便调用。
- 函数接收助手、线程和用户提示词。
- 函数示例:
def get_response_from_assistant(assistant, thread, prompt, run_instruction): message = client.beta.threads.messages.create( thread_id=thread.id, role="user", content=content_prompt )
run = client.beta.threads.runs.create( thread_id=thread.id, assistant_id=assistant.id, instructions=run_instruction )
while run.status != "completed": keep_retrieving_run = client.beta.threads.runs.retrieve( thread_id=thread.id, run_id=run.id ) print(f"Run Status: {keep_retrieving_run.status}") if keep_retrieving_run.status == "completed": break
for data in messages.data: print(data.content[0].text.value) print("---")- 步骤:接收助手、线程、用户提示词以及运行指令。
Assistant API 的使用 (续) run_instruction 参数
Section titled “Assistant API 的使用 (续) run_instruction 参数”run_instruction:针对此次运行的额外指令参数- 可选,类型为字符串
- 当需要对特定运行进行调整或指示时使用
- 不需要时,可使用空字符串作为默认值,保持代码简洁
- 代码示例:
def get_response_from_assistant(assistant, thread, prompt, run_instruction=Assistant API的检索器
Section titled “Assistant API的检索器”- 创建文件内容问答助手
- 过程与前一节相似
- 从
openai库导入OpenAI - 从
openai库导入OpenAI
file = client.files.create
- 需要传入
file参数的值 - 应为一个文件对象
- 使用
open函数获取文件对象 open函数为 Python 自带
Assistant API 的文件操作
Section titled “Assistant API 的文件操作”- 使用
client.files.create()创建文件对象。 - 需要指定文件路径,例如 `client.files.create(file=open(
Assistant API 文件操作注意事项
Section titled “Assistant API 文件操作注意事项”- 访问platform.openai.com/docs/assistants查看
Assistant API文档。 OpenAI按文件体积按天收费。- 同一文件附加给多个助手,每个助手都会消耗费用。
- 删除助手:访问platform.openai.com/assistants,点击助手进行删除。
- 删除文件:访问platform.openai.com/storage,查看并删除文件。
Streamlit框架简介
Section titled “Streamlit框架简介”- 简化网页开发流程,适合快速原型设计和数据可视化
- Streamlit的官方介绍:几分钟内把Python脚本变成可分享的网站
- 仅需纯Python,无需前端经验
- 支持免费部署,通过链接进入网站
- 一个Streamlit ≈ 前端框架 + 后端框架 + 云服务器
- 比如要做个自己的ChatGPT,通过Streamlit只需要写代码
- 甚至支持免费部署,让任何人可以通过链接进入你的网站
Streamlit使用步骤
Section titled “Streamlit使用步骤”- 第一步:安装这个库
- 先新建一个空白的项目文件夹
- 命令:
pip install streamlit - 终端输入:
streamlit run 文件名.py
Streamlit 安装与测试
Section titled “Streamlit 安装与测试”- 在项目终端输入
pip install streamlit - 安装完成后,输入
streamlit hello - 成功:浏览器打开
localhost开头的网站 - 可通过侧边栏切换页面
- 该网站是 Streamlit 官方示例,帮助了解其实现效果
Streamlit服务器终止与新建页面
Section titled “Streamlit服务器终止与新建页面”- 终端按
Ctrl+C终止Streamlit服务器。 - 刷新网页,会发现网站无法访问。
- 下一节:从空白网页添加内容,了解常用组件。
新建空白Python文件
Section titled “新建空白Python文件”- 新建
page1.py。
使用streamlit
Section titled “使用streamlit”- 代码中
import streamlit。
运行streamlit程序
Section titled “运行streamlit程序”- 代码:
import streamlit as st后,按照惯例: import streamlit as st- 因为
streamlit这个名字比较长,所以给它取个更简短的别名st - 就可以调用这个库的
write函数 - 里面放上字符串,
write的作用是让字符串在网页上显示出来 - 运行后网页上应该有
早上好!字样 - 在项目的终端输入
streamlit run Python代码文件的路径
Streamlit 使用技巧 (续)四
Section titled “Streamlit 使用技巧 (续)四”Markdown是一种标记语言,用于增加样式。- 语法简单。
- 标题:
- 在文字前加
#和一个空格,变大加粗,成为一级标题。 - 增加
#数量改变标题级别,最多六级。 #数量越多,字体越小。- 示例:
# 我是最大的标题## 我是第二大的标题### 我是第三大的标题###### 我是最小的标题- 粗体和斜体:
- 粗体:用两个星号
**把文字包住,例如**我是粗体字**。 - 斜体:用一个星号
*把文字包住,例如*我是斜体字*。 - 分隔线:
- 在一行中输入三个或更多个短横线
---,生成一条水平分隔线。 - 引用:
- 在文字前加
>符号,会缩进并显示一条竖线。
Streamlit 自动刷新与界面元素修改
Section titled “Streamlit 自动刷新与界面元素修改”- 代码更改自动检测,点击 Rerun 按钮更新网页。
- 开启“始终重新运行”:避免手动点击 Rerun。
- 修改标题级别:更改
st.write中#数量。
Streamlit 更多技巧
Section titled “Streamlit 更多技巧”- 不调用
write函数时: - 变量名单独一行,自动展示值。
- 适用于快速查看中间结果,无需
print。
Streamlit 使用 (续)
Section titled “Streamlit 使用 (续)”- 甚至支持免费部署,让任何人可以通过链接进入你的网站
Streamlit使用步骤
Section titled “Streamlit使用步骤”- 第一步:安装这个库
- 先新建一个空白的项目文件夹
- 命令:
pip install streamlit - 终端输入:
streamlit run 文件名.py
Streamlit 安装与测试
Section titled “Streamlit 安装与测试”- 在项目终端输入
pip install streamlit - 安装完成后,输入
streamlit hello - 成功:浏览器打开
localhost开头的网站 - 可通过侧边栏切换页面
- 该网站是 Streamlit 官方示例,帮助了解其实现效果
Streamlit服务器终止与新建页面
Section titled “Streamlit服务器终止与新建页面”- 终端按
Ctrl+C终止Streamlit服务器。 - 刷新网页,会发现网站无法访问。
- 下一节:从空白网页添加内容,了解常用组件。
新建空白Python文件
Section titled “新建空白Python文件”- 新建
page1.py。
使用streamlit
Section titled “使用streamlit”- 代码中
import streamlit。
运行streamlit程序
Section titled “运行streamlit程序”- 代码:
import streamlit as st后,按照惯例: import streamlit as st- 因为
streamlit这个名字比较长,所以给它取个更简短的别名st - 就可以调用这个库的
write函数 - 里面放上字符串,
write的作用是让字符串在网页上显示出来 - 运行后网页上应该有
早上好!字样 - 在项目的终端输入
streamlit run Python代码文件的路径
Streamlit 使用技巧 (续)四
Section titled “Streamlit 使用技巧 (续)四”Markdown是一种标记语言,用于增加样式。- 语法简单。
- 标题:
- 在文字前加
#和一个空格,变大加粗,成为一级标题。 - 增加
#数量改变标题级别,最多六级。 #数量越多,字体越小。- 示例:
# 我是最大的标题## 我是第二大的标题### 我是第三大的标题###### 我是最小的标题- 粗体和斜体:
- 粗体:用两个星号
**把文字包住,例如**我是粗体字**。 - 斜体:用一个星号
*把文字包住,例如*我是斜体字*。 - 分隔线:
- 在一行中输入三个或更多个短横线
---,生成一条水平分隔线。 - 引用:
- 在文字前加
>符号,会缩进并显示一条竖线。
Markdown 语法补充说明
Section titled “Markdown 语法补充说明”- 多打一次换行或在第一行后加两个空格:更紧凑的换行效果
- 非常常用的样式,分为两类:
- 无序列表
- 有序列表
- 无序列表:
- 在每个列表元素前加
短横杠+空格 - 短横杠是键盘上0右边的键
- 有序列表:
- 在每个列表元素前加
数字+英文句号+空格 - 都非常直观
Jupyter Notebook 界面元素操作
Section titled “Jupyter Notebook 界面元素操作”- 复制当前单元格
- 上移/下移当前单元格
Jupyter Notebook 使用进阶
Section titled “Jupyter Notebook 使用进阶”- 工具栏按钮:
- 上移单元格
- 下移单元格
- 在上方添加空单元格
- 在下方添加空单元格
- 删除当前单元格
- 快捷键(需在命令模式下使用):
A:在当前单元格上方插入新单元格B:在当前单元格下方插入新单元格- 连按两次
D:删除当前单元格 - 快捷键查看:
Help->Show Keyboard Shortcuts
Jupyter Notebook 的使用 (续) 删除单元格和运行单元格
Section titled “Jupyter Notebook 的使用 (续) 删除单元格和运行单元格”- 删除当前单元格:双击
D键 - 运行当前单元格:
Shift + Enter快捷键,效果与点击运行按钮相同 - 节省鼠标操作时间
Python代码书写问题解决办法
Section titled “Python代码书写问题解决办法”- 如果遇到错误,PyCharm会自动用红色提醒。
- 运行代码时,也能看到红色的错误提示信息。
- 可以把红色错误信息复制到搜索引擎里进行搜索。
- 错误可能是相似的。
- 很多开发者可能遇到过相同问题,可以借鉴解决方案。
Streamlit的image函数
Section titled “Streamlit的image函数”- 用于在网页上添加图片
- 需传入图片的路径
- 示例:
st.image("头像.png") - 文件和代码文件处于同一文件夹下,因此使用相对路径
Markdown 语法补充说明
Section titled “Markdown 语法补充说明”- 多打一次换行或在第一行后加两个空格:更紧凑的换行效果
- 非常常用的样式,分为两类:
- 无序列表
- 有序列表
- 无序列表:
- 在每个列表元素前加
短横杠+空格 - 短横杠是键盘上0右边的键
- 有序列表:
- 在每个列表元素前加
数字+英文句号+空格 - 都非常直观
Streamlit 图像与数据展示
Section titled “Streamlit 图像与数据展示”st.image()函数的width参数:可以额外指定图片的宽度,让图片按指定宽度显示。
Streamlit 的数据展示能力
Section titled “Streamlit 的数据展示能力”- Streamlit 主要面向数据科学和机器学习领域的 Python 用户。
- 展示表格数据是 Streamlit 的一项强大能力。
Pandas 库
Section titled “Pandas 库”- 目的:创建规整的数据。
- 作用:一个强大且灵活的数据分析库,提供易于使用的数据结构。
- 最常用:
DataFrame,用于表示表格数据。 - 安装:在终端输入
pip install pandas来安装该库。
DataFrame展示与streamlit结合
Section titled “DataFrame展示与streamlit结合”- 导入
pandas as pd。 - 调用
pd.DataFrame()创建DataFrame,参数为字典。 - 字典的键:表示列名的字符串,如
学号、班级、成绩。 - 值:包含该列所有值的列表。
- 调用
streamlit的dataframe函数: - 展示数据:
st.dataframe(DataFrame)
Streamlit 的表格展示能力 (续)二
Section titled “Streamlit 的表格展示能力 (续)二”- 运行
streamlit run main.py,上传数据文件,输入问题“用条形图展示房屋装修情况”,点击生成回答 - 展示条形图,鼠标悬停查看数据
- 除了条形图,散点图和折线图都以类似方式展示
Streamlit组件调用
Section titled “Streamlit组件调用”st.line_chart(df_data):折线图st.scatter_chart(df_data):散点图st.bar_chart(df_data):条形图- 需传入
DataFrame - 图表类型有
bar、line和scatter - 使用
elif语句 - 传给
create_chart的参数: - 数据
response_dict[``"bar"] - 图表类型
"bar"
根据用户请求生成图表
Section titled “根据用户请求生成图表”- 如果用户需要一个表格,按照
JSON格式回应: - 键为
table,值为字典 columns:对应表格的列名,列表data:对应表格的内容,列表- 如果用户请求图表,按
JSON格式回应: - 键为
bar:条形图 - 键为
line:折线图 - 键为
scatter:散点图 - 值:字典
columns:对应图表的轴,列表data:对应图表里面的内容,列表AI返回的都是字符串,下一步才是解析为字典
dataframe_agent 函数 (续) 提示词设置
Section titled “dataframe_agent 函数 (续) 提示词设置”- 代码中可找到提示模版
PROMPT_TEMPLATE - 提示词工程:指导AI如何根据用户指令返回文本、表格、柱状图等数据
- 示例:
- 请求文本:返回
answer键 - 请求表格:返回
table键 - 请求柱状图:返回
bar键 - 键值对类型:
- 键:
columns(类型:字符串列表) - 键:
data(类型:数字列表) - 借助
Streamlit组件,将数据渲染为图表,代码更清晰
提示词工程 (续) 输出格式控制:JSON
Section titled “提示词工程 (续) 输出格式控制:JSON”- 将所有输出作为
JSON字符串返回 - 方便解析
- 提示:
- 注意要将
columns列表和数据列表中的所有字符串都用双引号包围 - 这是属于
JSON字符串的其中一个格式要求
拼接用户要求和补充要求
Section titled “拼接用户要求和补充要求”- 将用户的问题和补充要求拼接起来
- 代码:
prompt = PROMPT_TEMPLATE + query
调用agent执行器的invoke方法
Section titled “调用agent执行器的invoke方法”- 代码:
response = agent.invoke({"input": prompt}) - 将
prompt作为输入参数
dataframe_agent 函数 (续) 代码实现
Section titled “dataframe_agent 函数 (续) 代码实现”- 使用
json.loads()方法解析JSON字符串。 - 代码:
response_dict = json.loads(response["answer"])
dataframe_agent 函数 (续)代码实现准备
Section titled “dataframe_agent 函数 (续)代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息。
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续)返回值
Section titled “generate_script 函数 (续)返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- a模型`
- 第二个参数:
video_length(时长),例如1分钟。 - 第三个参数:
creativity(创造性),例如0.7。 - 第四个参数:
api_key(API 密钥)。
generate_script 函数 (续) API 密钥获取
Section titled “generate_script 函数 (续) API 密钥获取”- API 密钥可以通过导入
os模块,然后使用st.sidebar - 使用
st.text_input()添加密钥输入框,type="password"隐藏输入。 - 使用
st.markdown()添加链接到 OpenAI API 密钥获取页面。
网页主页设置
Section titled “网页主页设置”- 使用
st.file_uploader()添加文件上传组件。 accept_multiple_files=False:仅允许上传单个文件。type=["pdf"]:限制上传文件类型为 PDF.- 如果用户上传了文件:
if uploaded_file is not None:。 - 使用
st.info()显示上传成功的提示信息。
CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:
Section titled “CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:”- 提示文字,如
"上传你的数据文件 (CSV格式)" type="csv":限制只能上传CSV文件。data = st.file_uploader(...):将上传的文件赋值给data变量。- 读取并展示数据:
- 用户上传CSV文件后,读取数据并用
Streamlit的表格组件展示。 - 这样用户可以一边看数据内容,一边与AI交互。
- Pandas库:读取CSV数据需要借助
pandas库。 - 导入
pandas as pd。
if data:
- 使用
pd.read_csv(data)读取上传的CSV文件到DataFrame。 - 将
DataFrame存储在会话状态中:st.session_state["df"] = pd.read_csv(data) - 使用
st.expander创建一个可折叠的组件,用于显示原始数据。 - 指定
st.expander对应的文字:例如原始数据。
CSV数据分析智能工具 (续) 页面实现
Section titled “CSV数据分析智能工具 (续) 页面实现”- 在
st.expander("原始数据")代码块里,调用st.dataframe()函数来展示上传的CSV数据. st.dataframe()参数:传入st.session_state["df"],即之前存储的DataFrame。- 这样,用户上传CSV文件后,页面会显示一个可折叠的“原始数据”组件。
- 展开后,用户能看到整个数据表格,并进行排序和搜索等交互操作。
st.dataframe还支持全屏预览等功能。- 接下来,用户还需要一个文本框来输入问题。
网页布局设置
Section titled “网页布局设置”- 使用
st.text_area(),比st.text_input()更高,可输入更多内容 - 提示文字:
"请输入你关于以上表格的问题,或者数据提取请求,或者可视化要求(支持散点图、折线图、条形图)" - 用户输入赋值给变量
query - 添加按钮:
st.button("生成回答") - 点击“生成回答”按钮后的逻辑:
if button and not openai_api_key::如果点击了按钮但未提供API密钥,则:- 提示用户输入密钥:
st.info(
Streamlit 组件:st.divider()
Section titled “Streamlit 组件:st.divider()”- 用于在网页上添加分隔线,使内容更清晰。
- 示例:
st.divider() - 作用:在不同内容之间添加分隔线,使页面结构更清晰。
Streamlit 输入组件
Section titled “Streamlit 输入组件”- 网页有时需要和用户交互。
- 需要允许用户输入文字、数字或选择等。
Streamlit 网页服务器终止
Section titled “Streamlit 网页服务器终止”- 在终端输入了
streamlit run命令的终端按Ctrl+C
Streamlit 组件与页面搭建
Section titled “Streamlit 组件与页面搭建”- 包括文字输入、数字输入、勾选框、按钮等。
- 可在之前创建的项目中,新建一个 Python 文件,例如
page2.py。 - 使用
streamlit run page2.py命令运行。 - 页面为空时,先导入
streamlit:import streamlit as st。 - 接收用户文字输入:使用
streamlit的text_input函数。 - 参数:表示提示信息的字符串。
Streamlit 输入组件
Section titled “Streamlit 输入组件”- 标签字符串:
st.text_input("请输入你的名字") - 向用户说明输入内容
- 获取用户输入内容:赋值给变量,如
name
name = st.text_input("请输入你的名字")if name: st.write(f"你好,{name}")if name::判断name变量是否为None,再决定是否打印问候语- 字符串连接:
f"你好,{name}" - 文字输入框出现,标签与
st.text_input函数参数一致 - 完成输入并回车后,文字框内容赋给
name变量 Streamlit从上到下重新运行整个Python文件name值更新,问候内容相应改变- 点击
Always rerun也可运行整个Python文件
Streamlit 界面元素
Section titled “Streamlit 界面元素”st.divider():添加分隔线,使内容更清晰。st.text_input():添加文本输入组件,用于接收用户文字输入。type="password":文本输入框显示为密码形式。
Streamlit 运行
Section titled “Streamlit 运行”- 修改源码或与组件交互:程序会从头到尾重新运行。
- 页面会重新加载,更新变量值。
Streamlit 组件:st.text_area()
Section titled “Streamlit 组件:st.text_area()”- 用于多行文本输入,可输入较长内容。
- 参数:提示信息字符串,如
"请输入一段自我介绍"。 - 示例:
paragraph = st.text_area("请输入一段自我介绍") - 用于用户输入较长内容。
- 允许用户提供
API密钥(st.text_input)。 - 。
Streamlit组件:st.number_input
Section titled “Streamlit组件:st.number_input”- 获得数字输入,例如年龄。
- 默认情况下,初始值为0,精度为两位小数。
- 参数:显示文字标签字符串。
- 数字输入框:改变默认初始值、精度。
Streamlit 组件:st.number_input()
Section titled “Streamlit 组件:st.number_input()”- 提示用户输入数值
- 示例:
age = st.number_input("请输入你的年龄", value=20, min_value=0, max_value=150) value:默认值min_value:最小值max_value:最大值- 可使用户输入合理年龄
- 限制最小值和最大值:
min_value=0max_value=150- 限制后:输入范围外数字,显示错误提示
- 递增/减数量:
step参数 - 例:
step=5,每次增减5 - 无限制:鼠标随意拖动
Streamlit 组件:st.number_input (续)
Section titled “Streamlit 组件:st.number_input (续)”min_value:最小值,例如0.1(时长必须是正数)。step:每次点击加减按钮时数值变化的步长,例如0.1。- 将
st.number_input()的返回值赋给video_length变量。
Streamlit 输入组件 (续) st.checkbox()
Section titled “Streamlit 输入组件 (续) st.checkbox()”- 勾选框也是常见的输入组件。
- 调用
st.checkbox()函数来创建。 - 参数:传入勾选框对应的文本内容,例如
"我同意以上条款"。 - 返回值:一个布尔值。
True:表示用户已勾选。False:表示用户未勾选。- 可以通过
if条件语句,根据st.checkbox()的返回值来控制内容的显示。 - 如果用户勾选了,则展示特定内容。
- 如果用户没有勾选,则不展示。
- 示例代码:
checked = st.checkbox("我同意以上条款")if checked: st.write("感谢你的同意!")Streamlit 组件:st.checkbox
Section titled “Streamlit 组件:st.checkbox”- 复选框:勾选表示用户同意。
- 代码:
checked = st.checkbox("我同意以上条款") type="password"
Streamlit 的条件判断if语句
Section titled “Streamlit 的条件判断if语句”- 布尔值:
True或False。 if checked::如果用户勾选,则checked为True。- 勾选后展示信息:
st.write("感谢你的同意!")Streamlit 组件:st.button
Section titled “Streamlit 组件:st.button”- 按钮:常用组件。
- 代码:
submitted = st.button("提交") - 返回值:布尔值,
True表示用户点击过,False反之。 - 结合
if语句:在用户点击后执行相应动作。
if submitted: st.write("提交成功")Streamlit 输入组件的更多探索
Section titled “Streamlit 输入组件的更多探索”- 点击“提交”按钮:`st.button(
Streamlit的单选按钮组件:st.radio
Section titled “Streamlit的单选按钮组件:st.radio”- 用于创建单选按钮。
- `st.radio(“你的性别是什么?”, [“男性”, “女性”, “跨性别”])
`
- 第一个参数:介绍输入信息的字符串,如问题描述。
- 第二个参数:选项列表,列表中的每个元素表示一个选项。
- 默认选中第一个选项。
- 点击 “Always rerun” 按钮可显示单选按钮。
Streamlit组件:st.radio的index参数
Section titled “Streamlit组件:st.radio的index参数”index参数:为单选框预设默认选项- 赋值为选项的索引,索引从0开始
- 示例:
index=1,默认选择第二个选项 - 赋值为
None:不预设默认选项
Streamlit组件:st.radio的返回值
Section titled “Streamlit组件:st.radio的返回值”- 返回用户选择的选项
- 使用变量接收返回值:
gender = st.radio(...) - 如果用户选择了某个选项,则将该选项写入网页:
st.write(f"你选择的性别是{gender}") st.selectbox():单选下拉框- 语法与
st.radio类似 - 需传入介绍性字符串和选项列表
- 返回用户选择的选项
- 可用变量赋值:
contact = st.selectbox("希望通过什么方式联系?", ["电话", "邮件", "微信", "QQ", "其他"])
Streamlit组件:st.selectbox 和 st.multiselect
Section titled “Streamlit组件:st.selectbox 和 st.multiselect”st.selectbox:单选下拉框- 参数:标签字符串、选项列表
- 返回值:用户选择的选项
st.multiselect:多选下拉框- 参数:标签字符串、选项列表
- 用户可选择多个选项
Streamlit 组件:st.multiselect
Section titled “Streamlit 组件:st.multiselect”- 用于创建多选框。
st.multiselect("你喜欢的水果是什么?", ["苹果", "香蕉", "橙子", "梨", "西瓜"])- 参数1:介绍性字符串,如问题描述。
- 参数2:选项列表。
- 用户可选择多个选项。
- 返回值:所选选项的列表。
- 示例代码:
import streamlit as st
fruits = st.multiselect("你喜欢的水果是什么?", ["苹果", "香蕉", "橙子", "梨", "西瓜"])for fruit in fruits: st.write(f"你选择的水果是{fruit}")- 运行代码,选择多个水果,点击OK,页面展示所有选择。
Streamlit 组件:st.slider
Section titled “Streamlit 组件:st.slider”- 滑块:
st.slider("你的身高是多少厘米?", value=170, min_value=100, max_value=230, step=1) - 设置身高数据
- 限制最小值和最大值
- 滑块组件:通过滑动改变数值
- 仍然可以把返回的值给变量进行赋值
st.file_uploader:文件上传器。
Streamlit 组件:st.file_uploader
Section titled “Streamlit 组件:st.file_uploader”- 首先传入一个介绍字符串。
- 限制用户上传文件的格式:添加
type参数。 - 赋值为列表:放上允许的文件格式的后缀,比如
png、jpg、jpeg等。 - 例如:
st.file_uploader("上传文件", type=["png", "jpg", "jpeg"]) - 网页会展示所限定的文件格式后缀
Streamlit组件:st.file_uploader(续)
Section titled “Streamlit组件:st.file_uploader(续)”type参数:限制上传文件类型- 例如,
type=['py']只允许上传 Python 代码文件 - 示例:PNG图片无法上传,但
.py文件可以 - 返回值:
UploadedFile类的实例,而非简单字符串 - 具有name属性,对应文件名
- 可在网页上显示文件名
Streamlit 组件:st.file_uploader (续) 文件名显示
Section titled “Streamlit 组件:st.file_uploader (续) 文件名显示”- 如果用户上传了文件 (
uploaded_file不为空),可以使用st.write()显示上传文件的名称。 - 示例:
st.write(f"你上传的文件是{uploaded_file.name}") uploaded_file.name会返回上传文件的文件名。- 上传文件后,文件名会正确显示在网页上。
Streamlit 组件:st.file_uploader (续) 读取文件内容
Section titled “Streamlit 组件:st.file_uploader (续) 读取文件内容”- 如果上传的文件是纯文本(如
.pyPython 代码文件或.txt文本文件),uploaded_file对象还有一个read()方法。 read()方法可以用来读取文件里面的内容。- 示例:
st.write(f"文件内容:{uploaded_file.read()}") - 这样可以将上传的纯文本文件的内容直接打印到网页上。
UploadedFile 实例属性
Section titled “UploadedFile 实例属性”name:对应文件名。- 示例:
st.write(f"你上传的文件是{uploaded_file.name}") - 如果文件是图片等非文本格式,直接读取内容意义不大,因为读取的是二进制字符。
- 纯文本文件,如
.txt或.py,读取后可读性较好。
Streamlit 布局组件:侧边栏、分列、选项卡与折叠展开
Section titled “Streamlit 布局组件:侧边栏、分列、选项卡与折叠展开”- 网页内容:自上而下排布
- 复杂布局:使用侧边栏、分列、选项卡、折叠展开等组件
- 选项卡组件:允许用户切换
Tab查看不同内容 - 折叠展开组件:
- 用户想查看内容时点击展开
- 不想看时点击折叠
Streamlit 添加侧边栏
Section titled “Streamlit 添加侧边栏”- 使用
with st.sidebar:,后续缩进在侧边栏显示 - 侧边栏加密钥输入框:
st.text_input()
- 使用
st.markdown()添加链接 - 语法:
[链接标签](实际地址)
Streamlit多列布局
Section titled “Streamlit多列布局”- 使用
st.columns()函数实现多列布局。 - 参数:指定列数,如
st.columns(2)分为两列。 - 返回值:一个列表,可将列表元素分别赋值给不同的列变量。
历史信息的展示
Section titled “历史信息的展示”- 使用
st.session_state["messages"]获取历史消息。 - 循环遍历消息列表,使用
st.chat_message()和write()展示。 st.chat_message():根据角色设置消息样式(头像)。write():写入消息内容。
Streamlit 页面元素
Section titled “Streamlit 页面元素”st.divider():添加分隔线,使内容更清晰。st.text_input():添加文本输入组件。type="password":文本输入框显示为密码形式.
使用 st.columns() 实现多列布局
Section titled “使用 st.columns() 实现多列布局”st.columns(3)返回一个列表。- 将列表元素赋值给多个变量:
column1, column2, column3 = st.columns(3)- 使用
with关键字将内容添加到指定列:
with column1:
# 添加到第一列的内容- 常用于在网页上并排显示组件。
Streamlit 列布局 (续)三列布局
Section titled “Streamlit 列布局 (续)三列布局”- 代码:
column1, column2, column3 = st.columns(3) - 在
with column1:、with column2:、with column3:里添加组件
Streamlit 列布局 (续)代码缩进
Section titled “Streamlit 列布局 (续)代码缩进”- 代码有缩进,表示该组件属于此列
- 代码没有缩进,表示不属于任何一列
st.checkbox不在column3缩进代码块内,不会出现在第三列
Streamlit 列布局 (续)自定义列宽度
Section titled “Streamlit 列布局 (续)自定义列宽度”- 使各列宽度不均分:代码实现调整
- 回到调用
columns的地方
Streamlit 多列布局 (续)
Section titled “Streamlit 多列布局 (续)”st.columns():输入数字列表作为参数,表示列所占宽度大小- 例:
st.columns([1, 2, 1]) - 第二列宽度是第一列和第三列的两倍
- 通过给
columns传入数字列表作为参数,可以调整各列的宽度
Streamlit 选项卡组件 (st.tabs)
Section titled “Streamlit 选项卡组件 (st.tabs)”- 使用
st.tabs()创建选项卡。 - 参数:列表,表示选项卡名称。
- ```联系方式````联系方式
性 别,联系方式,爱好])`
Streamlit 代码缩进
Section titled “Streamlit 代码缩进”- 组件在列中显示,代码需缩进。
- 无缩进代码,组件不属于任何列。
- 使用
streamlit创建选项卡:tab1,tab2, `tab3 = st.tabs([``
Streamlit 选项卡组件 (st.tabs) (续)
Section titled “Streamlit 选项卡组件 (st.tabs) (续)”st.multiselect()也可以放在选项卡里,比如tab3。- 用户可以在不同选项卡之间任意切换,之前输入的信息会保留,不用担心切换后信息丢失。
Streamlit 折叠展开组件 (st.expander)
Section titled “Streamlit 折叠展开组件 (st.expander)”- 用于折叠/展开内容,展示一些非关键信息时很有用。
- 比如,可以将页面上的一些内容先折叠起来,需要时再展开,这样能提高页面上的信息展示效率。
- 语法:
with st.expander("折叠组件标题"):
# 折叠起来的内容Streamlit 组件:st.slider (续)
Section titled “Streamlit 组件:st.slider (续)”- 视频中展示了
st.slider()和st.divider()也在tab3中使用。
with tab3: fruits = st.multiselect("你喜欢的水果是什么?", ["苹果", "香蕉", "橙子", "梨", "西瓜"]) for fruit in fruits: st.write(f"你选择的水果是{fruit}")
st.divider()
height = st.slider("你的身高是多少厘米?", value=170, min_value=100, max_value=230, step=1) st.write(f"你的身高是{height}厘米")Streamlit组件:st.expander
Section titled “Streamlit组件:st.expander”- 然后调用
streamlit的expander。 - 参数:传入一个介绍字符串,例如身高信息。
- 别忘了结尾的冒号。
- 下方缩进部分的所有内容都会纳入到组件里面。
- 用户可以通过点击去折叠和展开。
Streamlit程序
Section titled “Streamlit程序”- 变量
a的初始值为0。 - 网页上有个加一按钮。
- 每次用户点击后,
a的值都会增加1。
按钮增加数值Bug修复
Section titled “按钮增加数值Bug修复”a=0:初始值为0- 点击“加1”后
a+=1:A的值会增加1 - 每次点击按钮,
a的值始终为1,不再增加 - 程序存在bug,需修复
- Streamlit在两种情况下会重新运行整个Python文件:
- 修改源码
- 用户与组件交互(如点击按钮)
- 记忆会被重置,之前对话被清空
Streamlit程序运行逻辑分析
Section titled “Streamlit程序运行逻辑分析”- 源代码修改或与组件交互后,程序会重新运行。
- 每次运行,变量
a初始化为0,点击按钮后变为1。 - 无论点击多少次,展示结果总是1。
- 使用会话状态解决此问题。
- 可借助会话状态(
session state)存储变量的值。 - 只要用户没有关闭浏览器标签,会话里面的状态就可以被保留。
- 因此可以借助会话中的变量对某些数据进行保存,这样
a的值就不会在每次重新运行时丢失了。
使用streamlit库的session_state
Section titled “使用streamlit库的session_state”- 如果要使用
session_state,需使用streamlit库的session_state。 - 这样
a的值就不会在每次重新运行时丢失了。
Streamlit程序运行逻辑分析
Section titled “Streamlit程序运行逻辑分析”- 源代码修改或与组件交互后,程序会重新运行。
- 每次运行,变量
a初始化为0,点击按钮后变为1。 - 无论点击多少次,展示结果总是1。
- 使用会话状态解决此问题.
解决记忆被重置的问题:会话状态
Section titled “解决记忆被重置的问题:会话状态”Streamlit会从头运行代码:- 修改源码
- 用户与组件交互(输入文本、点击按钮等)
- 若每次都创建记忆,则记忆会被重置,之前对话被清空
- 解决办法:借助会话状态(
session state) - 仅在会话状态里没有记忆时才初始化记忆
- ] = ConversationBufferMemory(return_messages=True)
- essages``] = []
- 用户一进来就能看到的来自AI的消息
- 使用
st.columns(2):创建双列布局 left_column:显示小红书标题- 使用索引提取
result.titles列表中的元素,索引从0开始 - 示例:
st.write(result.titles[0]),提取第一个标题 right_column:显示小红书正文- 使用
st.markdown添加五级标题 - 使用
st.write展示result.content属性
代码实现:历史对话展示
Section titled “代码实现:历史对话展示”- 使用
for循环迭代st.session_state[``messages]``: - 代码:
for message in st.session_state[``messages]:` st.chat_message(message[``role]).write(message[``content])\:在页面上展示消息。- 根据
message的role属性,用不同的样式显示(模拟不同用户)。 - 添加用户输入框:`user_prompt = st.chat_input(
会话状态的使用
Section titled “会话状态的使用”a只是一个普通变量,不会存储在会话状态里。- 写入:
st.session_state.a = 0 - 读取:
st.session_state.a
- 每次点击都能使
a增加 1 - 每次点击都会把
a储存进对话状态。
Streamlit 多页面应用
Section titled “Streamlit 多页面应用”- Streamlit 简化网站搭建。
- 可用之前所有代码文件。
- 将所有页面归于同一网站,而非每个页面单独网站。
- 需先选择一个页面作为主页,如
page1.py。 - 创建名为
pages的文件夹。 - 将其他页面移动到
pages文件夹下。 - 注意:文件夹名必须为
pages。
页面切换与会话状态的保持
Section titled “页面切换与会话状态的保持”- 多出来一个侧边栏,展示
pages文件夹下的所有文件,对应名字都出现在侧边栏里面。 - 点击侧边栏的名称,就能去到它所对应的页面。
- 在不同页面之间跳转,只要不关闭这个标签页,会话就在,值会被保留。
- 说明了会话状态的意义。
Streamlit Share 部署步骤
Section titled “Streamlit Share 部署步骤”- 访问
share.streamlit.io。 - 点击“New app”。
- 填写:
- 仓库 (repository):选择GitHub仓库
- 分支 (branch):选择分支,一般为
main - 主脚本文件路径 (main script path):一般为
main.py - 点击“Deploy!”,等待部署完成。
- 成功:浏览器自动打开已部署的AI应用。
- 修改GitHub代码:streamlit share会自动更新,无需重复部署。
- 优势:
- 简单易用,无需服务器配置。
- 免费部署,降低开发成本。
requirements.txt 文件
Section titled “requirements.txt 文件”- 应用的依赖项,如库名,放在
requirements.txt文件中。
部署 AI 应用到云端 (续)Streamlit Share 部署步骤
Section titled “部署 AI 应用到云端 (续)Streamlit Share 部署步骤”- 访问
share.streamlit.io - 点击“New app”按钮
- 填写信息:
- 仓库 (repository):选择GitHub仓库
- 分支 (branch):选择分支,一般为main
- 主脚本文件路径 (main script path):一般为main.py
- 点击“Deploy!”按钮,等待部署完成
部署AI应用到云端 (续) 部署成功
Section titled “部署AI应用到云端 (续) 部署成功”- 部署成功:浏览器自动打开新页面,显示已部署的AI应用
- 修改代码:在GitHub仓库修改代码,streamlit share会自动更新,无需重复部署
- 优势:
- 简单易用,无需服务器配置
- 免费部署,降低开发成本
- 学习了Python基础语法、LangChain、Streamlit等
- 掌握了AI应用开发流程:数据准备、模型选择、提示工程、代码实现、用户界面、部署上线
requirements.txt 文件更新
Section titled “requirements.txt 文件更新”- 运行
pip freeze > requirements.txt,生成项目依赖库清单。 pip freeze命令:列出环境中的所有包及其版本。- 依赖库多:包含依赖的依赖项。
项目上传到 GitHub
Section titled “项目上传到 GitHub”- 将项目上传到 GitHub,因为 Streamlit Share 从 GitHub 读取代码。
GitHub 账号注册与登录
Section titled “GitHub 账号注册与登录”- GitHub 是世界上最大的代码托管网站和开源社区。
- 可在上面管理代码、追踪代码历史记录,并查看其他开发者的项目代码。
- 注册:
- 如果没有 GitHub 账号,点击右上角的
Sign up。 - 输入 Email 地址,点击
Continue。 - 输入密码,要求至少 8位,包含数字和字母。
- 登录:如果有账号,点击
Sign In。
GitHub注册步骤 (续) 用户名设置
Section titled “GitHub注册步骤 (续) 用户名设置”- 用户名只能包含字母、数字、短横杠 (
-)。 - 中文字符不支持。
GitHub注册步骤 (续) 完成注册
Section titled “GitHub注册步骤 (续) 完成注册”- 选择是否接收宣传邮件,可留空。
- 验证是否为机器人。
- 邮箱接收验证码并输入。
创建代码仓库
Section titled “创建代码仓库”- 所有文件需在代码仓库下才能上传至 GitHub。
- 代码仓库可看作项目文件夹。
GitHub仓库创建新代码仓库
Section titled “GitHub仓库创建新代码仓库”- 点击
New按钮 - 仓库命名规则:字母、数字、英文标点、下划线、短横线
- 例:
cloned-chatgpt Description:用中文简短描述仓库- 选择
Public或Private决定他人是否可见 - 分享他人看,不要选
Private - 是否添加
README file:提供项目介绍
GitHub 代码仓库设置 (续)
Section titled “GitHub 代码仓库设置 (续)”- README.md 文件: 用于给进入代码仓库的人提供更多信息
- 后缀名为
.md,是 Markdown 文件 - 可勾选“创建README.md”选项,或稍后自行上传
- .gitignore: 可先忽略
- License: 软件许可,用于规定和限制软件用户使用代码的权利
- 不同的许可协议有不同规定(署名、商用等)
- 了解不同许可协议含义:choosealicense.com
GitHub仓库准备
Section titled “GitHub仓库准备”- 必须要有,Streamlit Share从GitHub读取代码
- 点击
Add file->Upload files - 拖拽项目所有相关文件到指定区域,包括:
main.pyrequirements.txtutils.py- 注意:
- 虚拟环境相关的文件(如
venv文件夹)不需要上传 - 占用体积大,且并非项目源代码
上传GitHub代码仓库后的操作
Section titled “上传GitHub代码仓库后的操作”- 上传成功后,仓库文件会更新
- 点击文件名可查看代码文件内容
- 删除文件:
- 进入文件
- 点击右上角三个点
- 选择
Delete file - 点击绿色
Commit changes按钮提交 Commit表示提交,任何改动都要commit以后
GitHub 文件操作
Section titled “GitHub 文件操作”- 删除文件:在GitHub仓库中,选择文件,点击“删除”按钮,输入提交消息后确认,文件即被删除。
- 更新文件:只需将同名文件再次上传到仓库,旧内容就会被新内容覆盖。
Git 版本控制系统
Section titled “Git 版本控制系统”- GitHub的核心在于其背后的版本控制系统 Git。
- 作用:
- 记录项目每次做了什么改动,由谁改动。
- 可以随时切换到之前某个版本的状态。
- 优势:在团队协作中非常重要,可以追踪代码历史,方便回溯和管理。
项目部署到云端:Streamlit Share
Section titled “项目部署到云端:Streamlit Share”- 上传项目到GitHub后,下一步是利用Streamlit的社区云免费部署,让任何人可通过链接访问和使用应用。
- Streamlit Share部署步骤:
- 输入链接:
share.streamlit.io - 注册或登录(可用GitHub账号)。
- 点击“New app”创建应用。
- 填写信息:
- 仓库(repository):选择GitHub仓库。
- 分支(branch):选择分支(通常是
main)。 - 主脚本文件路径 (main script path):默认为
main.py。
- 点击“Deploy!”,等待部署完成。首次部署可能需要几分钟。
- 首次部署后,后续代码修改会自动更新。
- Streamlit Share优点:简单易用、无需服务器配置、免费部署。
Streamlit Share 部署设置
Section titled “Streamlit Share 部署设置”- 授权
Streamlit使用GitHub信息。 - 填写必要信息:名称、邮箱、所在国家等。
- 点击
New app,开始部署流程。 Repository:上传到GitHub的项目的仓库名。Branch:要部署的分支(通常无需修改)。Main file path:主脚本文件路径。- 如果不小心关闭页面,可以在启动命令的终端窗口找到访问地址。
Streamlit Share部署步骤 (续)
Section titled “Streamlit Share部署步骤 (续)”Streamlit项目网站主文件:对应Streamlit run后面跟着的.py文件,例如main.py。URL:部署后网站的链接,Streamlit自动生成,可修改(绿色表示未被占用)。- 点击
Deploy开始部署。 - 部署过程:出现加载动画,点击
Manage app可查看背后运行的命令。 requirements.txt:包含所有依赖项,会被逐个安装。
Streamlit Share 部署步骤
Section titled “Streamlit Share 部署步骤”- 访问
share.streamlit.io - 点击“New app”按钮
- 填写信息:
- 仓库 (repository):选择GitHub仓库
- 分支 (branch):选择分支,一般为
main - 主脚本文件路径 (main script path):一般为
main.py - 点击“Deploy!”按钮,等待部署完成
部署AI应用到云端 (续) 部署成功
Section titled “部署AI应用到云端 (续) 部署成功”- 部署成功:浏览器自动打开新页面,显示已部署的AI应用
- 修改代码:在GitHub仓库修改代码,streamlit share会自动更新,无需重复部署
- 优势:
- 简单易用,无需服务器配置
- 免费部署,降低开发成本
- 学习了Python基础语法、LangChain、Streamlit等
- 掌握了AI应用开发流程:数据准备、模型选择、提示工程、代码实现、用户界面、部署上线
AI开发门槛降低
Section titled “AI开发门槛降低”- 2022-2023年:人工智能新发岗位平均薪资持续增长
- 大语言模型的出现:降低AI开发门槛
- 优势:
- 即使没有AI经验也能上手
- 现有大模型上手即用,可完成各类任务
- 理解及生成自然语言能力极强
大语言模型交互优势
Section titled “大语言模型交互优势”- 传统机器学习:需要用代码调整模型。
- 大语言模型:允许我们直接用自然语言提出要求,模型能理解并做出相应回应。
- 即使没有AI背景,不会Python编程,也能赶上AI热潮。
- 讲师个人介绍:
- 毕业于计算机科学全球排名前15的院校。
- 曾任职多个Top级互联网大厂,如亚马逊Alexa AI自然语言处理领域工程师。
- 编程课在B站播放量数百万,好评如潮。
- 课程内容:针对2023年开始流行的大模型应用开发技术。
- 课程分为四大部分:
- 理论科普:AI常见技术。
- API基础:API计费、参数、应用示例。
- 提示工程:最佳实践、限定输出格式、零样本/小样本提示、思维链。
- 应用开发实战:LangChain框架、AI模型输入输出、AI模型记忆、AI模型读取外部文件、AI模型调用外部工具(agent、自定义工具、Python解释器、CSV分析)。
课程概览:构建流行AI应用
Section titled “课程概览:构建流行AI应用”- 目标:手把手带大家做市面上流行的AI应用项目。
- 即使是代码零基础的小白,学习后也能快速做出能根据上传的任意PDF文件回答相关问题的智能AI助手。
- 课程不以传统机器学习所需的统计学、算法等作为基础,而是以大模型API作为基础。
- 通过提示工程更好地调教AI。
- 核心理念:通过代码武装AI模型,使其变得更强大,满足各类需求。
- 课程使用的编程语言是Python,AI领域最热门的语言,即使不会Python也无需担心。
AI应用架构示意
Section titled “AI应用架构示意”历史对话消息 (记忆) <-----------------> |外部知识库 (TXT, PDF, DOC, Web, YouTube, GitHub) -> 向量数据库 <---> 大模型API <---> 外部工具 (Python代码运行, CSV分析, Bing搜索, Zapier自动化, 自定义工具) | <-----------------> 提示 | V 回应原始AI模型的局限性
Section titled “原始AI模型的局限性”- 无法记忆历史对话。
- 不会阅读外部文档。
- 不擅长数学计算。
- 不懂如何上网。
课程解决的AI模型增强方向
Section titled “课程解决的AI模型增强方向”- 给模型添加记忆。
- 给模型读取外部知识库的能力。
- 通过推理协调,让模型根据任务要求自主调用一系列外部工具。
课程概览与总结
Section titled “课程概览与总结”- 面向对象:专为没有Python基础的同学准备,聚焦于AI大模型应用开发领域。
- 核心理念:无论使用国内/国外、云端/本地、闭源/开源模型,其开发过程和技能都是相似且可迁移的。
- 时代红利属于先行者,越早掌握越有机会。
实战项目(5个)
Section titled “实战项目(5个)”- 视频脚本生成器:根据主题生成视频脚本。
- 爆款小红书AI写作助手:生成小红书风格的文案。
- 克隆ChatGPT:实现带记忆的AI聊天助手。
- CSV数据分析智能工具:分析CSV数据并提供洞察。
- 智能PDF问答工具:基于PDF内容进行问答。
- 项目价值:
- 亲自动手巩固知识,实现独立AI应用开发。
- 在项目基础上进行定制化,实现副业变现。
- 将项目放入简历,提升求职竞争力。
赠送教程与资源
Section titled “赠送教程与资源”- Assistant API教程:深入学习OpenAI的Assistant API。
- Streamlit网站搭建教程:快速构建AI应用的Web界面。
- AI应用部署教程:将AI应用部署到云端,供他人使用。
- AI聊天实用指南:提供与AI高效沟通的技巧。
- AI应用流程检查清单:确保AI应用开发的完整性和质量。
AI课程特点
Section titled “AI课程特点”- 配有学员专属AI讨论社群,让进修之路不孤单
- 大量图片和动画,配合生活化例子,直观生动讲解,减轻学习痛苦
- 直击重点的精炼知识,高效掌握技能
视频脚本生成器:功能介绍
Section titled “视频脚本生成器:功能介绍”- 侧边栏:
- 允许用户提供自己的
OpenAI API密钥 - 提供官方网站链接,方便用户获取密钥
- 主页面:
- 要求用户输入视频的主题和脚本大致时长
- 使用户可调整视频脚本的创造力(对应
temperature参数) - 数值越大,创造力越强
视频脚本生成器:提示词工程应用实例
Section titled “视频脚本生成器:提示词工程应用实例”- 网站判断用户是否提供 OpenAI API 密钥。
- 用户提供密钥后,点击“生成脚本”按钮。
- 使用加载组件告知用户AI正在思考。
- 获取AI回复后,告知用户视频脚本已生成。
- 显示视频标题和脚本内容。
- 工具不仅将信息告知AI,还调用了维基百科API。
- 用户点击维基百科搜索结果,可查看搜索内容。
- 这样做是为了让模型拥有更多知识。
视频脚本生成器:代码实现准备
Section titled “视频脚本生成器:代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示该项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性.
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息.
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
视频脚本生成器 (续) 提示词工程应用实例
Section titled “视频脚本生成器 (续) 提示词工程应用实例”- 使用了加载组件告知用户AI正在思考中。
- 获取AI回复后,告知用户视频脚本已生成。
- 展示视频标题和脚本内容。
- 工具不仅将信息告知AI,还调用了维基百科API。
- 用户点击维基百科搜索结果,可查看搜索内容。
- 这样做是为了让模型拥有更多知识。
- 模型拥有的知识天然受到训练日期的影响
- 像是
Sora模型,是2024年2月才公开的
视频脚本生成器:代码实现 (续)维基百科搜索结果组件
Section titled “视频脚本生成器:代码实现 (续)维基百科搜索结果组件”- 使用
streamlit的expander组件:st.expander()。 - 可折叠搜索结果。
- 提示:在
streamlit中,使用with语句可创建各种组件:st.sidebar、st.expander等。 - 代码:
with st.expander("维基百科搜索结果"): st.info(search_result)st.info(search_result):把搜索结果也放在下面。st.expander:可让用户点击展开/折叠维基百科搜索结果。- 运行程序,随意输入几个数字,然后输入
q,可以看到这里已经打印出了正确的平均值。 - 第一次运行的时候就输入
q,这里也打印出了正确的平均值。
爆款小红书AI写作助手:网页实现
Section titled “爆款小红书AI写作助手:网页实现”- 侧边栏:允许用户提供自己的
OpenAI API密钥,附官方链接 - 主页:
- 简化,仅输入框和按钮
- 提示用户提供主题
- 用户未提供密钥或主题:提示用户
爆款小红书AI写作助手:网页实现
Section titled “爆款小红书AI写作助手:网页实现”- 侧边栏:允许用户提供自己的
OpenAI API密钥,附官方链接 - 主页:
- 简化,仅输入框和按钮
- 提示用户提供主题
- 用户未提供密钥或主题:提示用户
项目 3:AI 聊天助手
Section titled “项目 3:AI 聊天助手”- 目标:仿照 ChatGPT、文心一言等工具制作网站
- 侧边栏:允许用户提供自己的
OpenAI API密钥 - 功能:用户提供密钥后,可与 AI 助手连续对话
- AI 回答出现在用户提问下方
- AI 具有记忆功能,能记住上下文
实现带记忆的对话
Section titled “实现带记忆的对话”项目4:智能PDF问答工具
Section titled “项目4:智能PDF问答工具”- 基于RAG(检索增强生成)
- 用户上传任意PDF内容 + 提问 → AI智能回答
- 辅助用户阅读PDF
- 侧边栏:提供OpenAI API密钥
- 拆解步骤见下回分解
AI智能PDF问答工具:页面功能实现 (续)问题提问
Section titled “AI智能PDF问答工具:页面功能实现 (续)问题提问”- 上传PDF文件后,在文本框里对PDF内容进行提问。
AI智能PDF问答工具:页面功能实现 (续)正确答案
Section titled “AI智能PDF问答工具:页面功能实现 (续)正确答案”- AI给出基于文档内容的回答,并链接文档里的其他相关信息。
- AI给出正确答案,并且把文档里的其他相关信息也返回。
AI智能PDF问答工具:页面功能实现 (续)GPT-3
Section titled “AI智能PDF问答工具:页面功能实现 (续)GPT-3”- 确定PDF文档里GPT-3有几个Transformer吗?
- AI给出了基于文档内容的回答:GPT-3有几个Transformer层。
AI智能PDF问答工具:功能演示 (续)GPT-3
Section titled “AI智能PDF问答工具:功能演示 (续)GPT-3”- 确定PDF文档里
GPT-3有几个Transformer吗? - AI给出了基于文档内容的回答:
GPT-3有96个transformer层。 - 且验证了给出的回答仍然是正确的。
- 具有创建储存对话的记忆。
- 如果用户的问题涉及到之前的对话,大模型也能基于记忆给出回答。
- 整体思路是相似的,只需要做小部分修改即可。
- AI可以基于本地知识库的内容做出回答。
- 用户不需要自行上传任何文件。
实现AI对文档的请求
Section titled “实现AI对文档的请求”- 读取用户上传的文档。
- 将文档内容和用户提问传给AI。
- 得到AI基于文档的回答。
- 加载:读取文档。
- 切割:分割文档内容。
下载requirements.txt文件
Section titled “下载requirements.txt文件”- 从课程配套资料里下载。
项目文件设置与依赖安装
Section titled “项目文件设置与依赖安装”- 安装依赖:通过
pip install -r requirements.txt安装项目所需的所有依赖项。 - 创建&;
utils.py&;文件:将所有与AI大模型交互的代码统一放入此文件中。 - 定义&;
qa_agent&;函数:该函数用于封装对AI的请求,接收openai_api_key和memory作为参数,以便处理API密钥和对话记忆。
实现AI对文档的请求
Section titled “实现AI对文档的请求”- 读取用户上传的文档。
- 将文档内容和用户提问传给AI。
- 得到AI基于文档的回答。
- 加载:读取文档。
- 切割:分割文档内容。
下载requirements.txt文件
Section titled “下载requirements.txt文件”- 从课程配套资料里下载。
qa_agent 函数 (续) 模型定义
Section titled “qa_agent 函数 (续) 模型定义”- 模型类型:
gpt-3.5-turbo - 用户提供的
API密钥:通过参数传入openai_api_key,ChatOpenAI的构造函数会使用。 - 代码示例:
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)- 需从
langchain_community.document_loaders的document_loaders模块里导入PyPDFLoader:
from langchain_community.document_loaders import PyPDFLoader- 实例化
PyPDFLoader时,遇到了一个问题:之前读取的都是本地文件,而用户上传的是文件内容
qa_agent 函数 (续) 方法选择
Section titled “qa_agent 函数 (续) 方法选择”- 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
- 适用于上传文件大小不确定,且需要重复使用的场景。
- 缺点:过程繁琐,会创建临时文件。
- 方法二:使用
PyPDFLoader的load_bytes方法。 - 适用于已经读取文件内容,且内容储存在内存里的情况。
- 更简单高效,无需写入本地文件。
- 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoaderfrom langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key) file_content = uploaded_file.read() loader = PyPDFLoader() docs = loader.load_bytes(file_content)- 将获取到的
file_content文本传进去,而不是传文件路径。 - 代码更简洁。
qa_agent 函数 (续)将内容写入临时文件:
Section titled “qa_agent 函数 (续)将内容写入临时文件:”- 使用
with open()语句,模式设置为"wb"(写入二进制文件)。 - 代码:
with open(temp_file_path, "wb") as temp_file: temp_file.write(file_content)temp_file_path:临时文件路径,类型应为字符串。- 将
uploaded_file读取的二进制内容写入临时文件:temp_file.write(file_content)。 - 代码执行后,临时文件将包含用户上传的
PDF内容。
qa_agent 函数 (续) 方法选择
Section titled “qa_agent 函数 (续) 方法选择”- 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
- 适用于上传文件大小不确定,且需要重复使用的场景。
- 缺点:过程繁琐,会创建临时文件。
- 方法二:使用
PyPDFLoader的load_bytes方法。 - 适用于已经读取文件内容,且内容储存在内存里的情况。
- 更简单高效,无需写入本地文件。
- 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoaderfrom langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key) file_content = uploaded_file.read() loader = PyPDFLoader() docs = loader.load_bytes(file_content)- 将获取到的
file_content文本传进去,而不是传文件路径。 - 代码更简洁。
- 加载后,需要对文档进行分割
- 导入
RecursiveCharacterTextSplitter:
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", " ", ""])-像chunk_size、chunk_overlap 这些
qa_agent 函数 (续)中文分词优化:separators 参数设置
Section titled “qa_agent 函数 (续)中文分词优化:separators 参数设置”- 将
separators赋值为更适合中文的分隔符。 - 代码示例:
text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", " ", ""])text_splitter.split_documents(docs):调用分割文档,得到文本块列表texts。
RAG 步骤 (续) 嵌入 (Embeddings)
Section titled “RAG 步骤 (续) 嵌入 (Embeddings)”- 将文本转换为向量。
- 向量:包含文本的语义和语法信息。
- 用于后续的相似性搜索。
- 嵌入模型:负责将文本转换为向量。
- 从
langchain_openai导入OpenAIEmbeddings:from langchain_openai import OpenAIEmbeddings - 创建嵌入模型:
embeddings_model = OpenAIEmbeddings() - 默认使用
text-embedding-ada-002模型。 - 密钥从环境变量自动获取,也可手动传入
openai_api_key参数。
文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明
Section titled “文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明”chunk_size:每块文本的最大长度,如500。chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。- 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
- ``“”]
- 保证每个文本块尽可能小且语义完整。
文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明
Section titled “文本分割器类型:RecursiveCharacterTextSplitter (续)参数说明”chunk_size:每块文本的最大长度,如500。chunk_overlap:块与块之间的重叠长度,如40,避免信息丢失,保证上下文连贯。separators:指定分割依据的字符列表,如换行符、句号等。排序有先后,排在前面的字符会被优先选择分割文本。- 递归分割:若按当前分隔符分割后文本块仍过长,则尝试列表中下一个分隔符,以此类推。
- ``“”]
- 保证每个文本块尽可能小且语义完整。
RAG 步骤 (续) 向量数据库:Chroma (续)FAISS
Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)FAISS”- 从
langchain_community.vectorstores导入FAISS - 向量数据库,可用它来做相似性搜索
- 代码示例:
db = FAISS.from_documents(texts, embeddings_model) texts:切割后的文档列表embeddings_model:嵌入模型的实例- 使用向量数据库的
as_retriever方法得到检索器 - 检索器:用于从大量文本中快速检索相关信息的组件
- 由于检索器也是
Runnable,说明可以调用它的invoke方法 - 示例:
retrieved_docs = retriever.invoke("卢浮宫这个名字怎么来的?") - 传入文本,返回检索到的相关段落
- 文本与向量数据库里的文本块相似性高
- 示例:
retrieved_docs[0].page_content retriever.invoke("卢浮宫在哪年被命名为中央艺术博物馆")- 也能获得相关文本块
| 方法 | 描述 |
|---|---|
| read | 返回全部文件内容的字符串 |
| readline | 返回一行文件内容的字符串 |
| readlines | 返回全部文件内容组成的列表 |
- 证明相似性搜索还是比较靠谱的
- 从
langchain.chains模块导入ConversationalRetrievalChain - 使用
ConversationalRetrievalChain.from_llm方法: llm参数:赋值为聊天模型。retriever参数:赋值为向量储存的as_retriever方法得到的检索器。memory参数:赋值为创建好的记忆。- 能够实现RAG的对话链就准备好了
- 仍然是通过
invoke方法 - 传入
chat_history和query
检索增强生成对话链:ConversationalRetrievalChain (续)参数解释
Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)参数解释”- 传入
chat_history和query:ConversationalRetrievalChain需要chat_history和question作为键。 chat_history:对应记忆。question:对应用户查询。- 链在处理对话时,使用
chat_history键来访问和更新对话历史。 - 赋值给创建好的记忆。
question参数赋值为用户查询的字符串即可。invoke返回字典:answer对应来自AI的回应,question对应来自用户的问题。- 对话也会被自动加入
chat_history对应的记忆里。
检索增强生成对话链:ConversationalRetrievalChain (续)
Section titled “检索增强生成对话链:ConversationalRetrievalChain (续)”- 从输出结果的
source_documents可看到: - 从向量数据库检索出的原始模型片段
- 对应从向量储存里检索出来的原始模型片段
网站框架搭建 (续)代码实现准备
Section titled “网站框架搭建 (续)代码实现准备”- 创建独立的网站项目,先创建项目文件夹
- 把所有和网站相关的代码放入其中
- 下一节:讲解如何通过代码实现该工具
PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放项目相关文件(前后端代码、图片等)。
- venv 文件夹:
PyCharm自动创建,表示项目独立的 Python 虚拟环境。 - 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹。虚拟环境可以让我们给不同的项目去使用不同版本的解释器和库,比如允许项目一用Python 3.8,项目2用Python 3.10, 如果项目1要用库A的1.0版本,项目2要用库B,但库B依赖于库A的1.1版本,我们不需要为了项目2把库A升级到1.1版本,也不需要为了项目1而降级库A,通过虚拟环境可以轻松实现.
虚拟环境的缺点
Section titled “虚拟环境的缺点”- 每个虚拟环境都复制一次解释器和库。
- 占用空间大。
- 临时练手的小项目,可不创建虚拟环境。
requirements.txt
Section titled “requirements.txt”- 存储项目运行所需的依赖库及精确版本号。
- 确保项目在不同环境下的一致性。
requirements.txt 文件的重要性
Section titled “requirements.txt 文件的重要性”- 确保不同环境安装相同版本的依赖库。
- 命令:
pip install -r requirements.txt - 包含项目所需的所有依赖库及其版本信息.
项目关键依赖库
Section titled “项目关键依赖库”streamlitlangchainlangchain-communitylangchain-corelangchain-openai
生成 requirements.txt 文件的方法
Section titled “生成 requirements.txt 文件的方法”- 命令:``pip freeze > requirements.txt`
pip freeze:列出当前虚拟环境中安装的所有包及其精确版本号- 把这些信息输入到
requirements.txt文件中
生成utils.py文件
Section titled “生成utils.py文件”- 新建Python文件:
utils.py - 将所有与AI大模型交互的代码放入此文件
- 定义
generate_script函数,参数: subject:视频主题video_length:视频时长creativity:视频脚本的创造性
generate_script 函数的参数
Section titled “generate_script 函数的参数”subject:视频主题video_length:视频时长creativity:视频脚本的创造性api_key:用户提供的API密钥
generate_script 函数要做的事
Section titled “generate_script 函数要做的事”- 获得视频标题
- 调用维基百科的API获得相关信息
- 获得视频的脚本内容
- 先定义第一个和第三个任务所需的提示模板
- 从
langchain.prompts导入ChatPromptTemplate
generate_script 函数 (续) 提示模板设置
Section titled “generate_script 函数 (续) 提示模板设置”- 设置视频标题提示模板:
title_template - 使用
ChatPromptTemplate.from_messages方法 - 接收消息列表作为参数
- 消息里可带变量
- 视频主题:模板里待填入值的变量
- 从AI获得脚本内容提示模板:
script_template - 仍然调用
from_messages方法 - 传入消息列表
generate_script 函数 (续)模型定义
Section titled “generate_script 函数 (续)模型定义”- 从
langchain_openai导入ChatOpenAI: - 代码:
from langchain_openai import ChatOpenAI - 定义模型:
model = ChatOpenAI(openai_api_key=api_key, temperature=creativity) - 用户提供的
API密钥通过参数传入 - 视频脚本的创造性参数
creativity也传入 - 如果使用的是课程提供的
API密钥,需提供openai_api_base参数 - 提示模板和模型都有了,把获得视频标题以及脚本的链给组装起来
视频标题提示模板
Section titled “视频标题提示模板”title_template包含变量subject。invoke传入字典,指定subject的值:title_chain.invoke({"subject": subject})。script_chain类似。
从 langchain_community.utilities 导入维基百科 API 包装器
Section titled “从 langchain_community.utilities 导入维基百科 API 包装器”WikipediaAPIWrapper类用于通过维基百科的官方 API 进行搜索,并返回搜索结果的摘要。- 代码:
from langchain_community.utilities import WikipediaAPIWrapper search = WikipediaAPIWrapper(lang="zh")lang参数:指定搜索语言。默认为英语,zh表示中文。script_chain.invoke的参数:title:之前从AI获得的标题。duration:对应video_length,直接来自用户输入。wikipedia_search:填充search_result,即维基百科搜索结果。invoke调用后会得到一个AI消息,需要通过.content属性来获取实际内容。- 将获取到的脚本内容赋值给
script变量:script = script_chain.invoke(...) .content。
generate_script 函数 (续)返回值
Section titled “generate_script 函数 (续)返回值”- 函数最后返回三个值:
search_result(维基百科搜索结果)、title(视频标题)、script(视频脚本内容)。
generate_script 函数 (续) 调用与测试
Section titled “generate_script 函数 (续) 调用与测试”- 为了测试函数是否正常工作,可以调用
generate_script函数并传入参数。 - 示例调用:
generate_script("sora模型", 1, 0.7, os.getenv("OPENAI_API_KEY"))- 参数说明:
- a模型`
- 第二个参数:
video_length(时长),例如1分钟。 - 第三个参数:
creativity(创造性),例如0.7。 - 第四个参数:
api_key(API 密钥)。
generate_script 函数 (续) API 密钥获取
Section titled “generate_script 函数 (续) API 密钥获取”- API 密钥可以通过导入
os模块,然后使用st.sidebar - 使用
st.text_input()添加密钥输入框,type="password"隐藏输入。 - 使用
st.markdown()添加链接到 OpenAI API 密钥获取页面。
网页主页设置
Section titled “网页主页设置”- 使用
st.file_uploader()添加文件上传组件。 accept_multiple_files=False:仅允许上传单个文件。type=["pdf"]:限制上传文件类型为 PDF.- 如果用户上传了文件:
if uploaded_file is not None:。 - 使用
st.info()显示上传成功的提示信息。
CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:
Section titled “CSV数据分析智能工具 - 文件上传:使用st.file_uploader()函数,参数:”- 提示文字,如
"上传你的数据文件 (CSV格式)" type="csv":限制只能上传CSV文件。data = st.file_uploader(...):将上传的文件赋值给data变量。- 读取并展示数据:
- 用户上传CSV文件后,读取数据并用
Streamlit的表格组件展示。 - 这样用户可以一边看数据内容,一边与AI交互。
- Pandas库:读取CSV数据需要借助
pandas库。 - 导入
pandas as pd。
if data:
- 使用
pd.read_csv(data)读取上传的CSV文件到DataFrame。 - 将
DataFrame存储在会话状态中:st.session_state["df"] = pd.read_csv(data) - 使用
st.expander创建一个可折叠的组件,用于显示原始数据。 - 指定
st.expander对应的文字:例如原始数据。
CSV数据分析智能工具 (续) 页面实现
Section titled “CSV数据分析智能工具 (续) 页面实现”- 在
st.expander("原始数据")代码块里,调用st.dataframe()函数来展示上传的CSV数据. st.dataframe()参数:传入st.session_state["df"],即之前存储的DataFrame。- 这样,用户上传CSV文件后,页面会显示一个可折叠的“原始数据”组件。
- 展开后,用户能看到整个数据表格,并进行排序和搜索等交互操作。
st.dataframe还支持全屏预览等功能。- 接下来,用户还需要一个文本框来输入问题。
网页布局设置
Section titled “网页布局设置”- 使用
st.text_area(),比st.text_input()更高,可输入更多内容 - 提示文字:
"请输入你关于以上表格的问题,或者数据提取请求,或者可视化要求(支持散点图、折线图、条形图)" - 用户输入赋值给变量
query - 添加按钮:
st.button("生成回答") - 点击“生成回答”按钮后的逻辑:
if button and not openai_api_key::如果点击了按钮但未提供API密钥,则:- 提示用户输入密钥:
st.info(
网页布局设置 (续)一
Section titled “网页布局设置 (续)一”- 代码:
if "bar" in response_dict: st.bar_chart(pd.DataFrame(response_dict["data"], columns=response_dict["columns"]))`- 使用
streamlit的bar_chart方法,参数: data:图表数据columns:列名
网页布局设置 (续)二
Section titled “网页布局设置 (续)二”- 运行代码,上传数据文件,输入问题“用条形图展示房屋装修情况”,点击生成回答
- 展示条形图,鼠标悬停查看数据
- 除了条形图,散点图和折线图都以类似方式展示
- 集成多个工具于一身的智能agent已初步成型
- 步骤:
- 用户上传数据文件
- 提出问题
- agent给出图表
- 核心:数据在本地,没有发给任何人,安全
- 学习使用LangChain连接各种工具,实现各种应用
部署AI应用到云端
Section titled “部署AI应用到云端”- 目标:创建AI应用,部署到云端,让更多人使用
- 示例:使用streamlit share免费部署AI应用
- 需要:
- GitHub账号
- 包含代码的GitHub仓库
- 简单的部署知识
云部署方法步骤
Section titled “云部署方法步骤”- 创建GitHub仓库:
- 存放所有代码文件
- 方便streamlit share读取
- 准备必要文件:
requirements.txt:包含项目所有依赖项及其版本号main.py:包含网站代码
- 访问streamlit share:share.streamlit.io
部署AI应用到云端 (续) Streamlit Share 部署步骤
Section titled “部署AI应用到云端 (续) Streamlit Share 部署步骤”- 访问streamlit share:share.streamlit.io
- 点击“New app”按钮
- 填写信息:
- 仓库 (repository):选择GitHub仓库
- 分支 (branch):选择分支,一般为main
- 主脚本文件路径 (main script path):一般为main.py
- 点击“Deploy!”按钮,等待部署完成
部署AI应用到云端 (续) 部署成功
Section titled “部署AI应用到云端 (续) 部署成功”- 部署成功:浏览器自动打开新页面,显示已部署的AI应用
- 修改代码:在GitHub仓库修改代码,streamlit share会自动更新,无需重复部署
- 优势:
- 简单易用,无需服务器配置
- 免费部署,降低开发成本
- 学习了Python基础语法、LangChain、Streamlit等
- 掌握了AI应用开发流程:数据准备、模型选择、提示工程、代码实现、用户界面、部署上线
RAG 步骤 (续) 网页布局
Section titled “RAG 步骤 (续) 网页布局”- 使用
st.columns(2)创建双列布局。 left_column:显示小红书标题- 使用索引提取
result.titles列表中的元素,索引从0开始 - 示例:
st.write(result.titles[0]),提取第一个标题 right_column:显示小红书正文- 使用
st.markdown添加五级标题 - 使用
st.write展示result.content属性
- 采用多列布局:
st.columns(2) - 返回列表,分别赋值给
left_column和right_column - 侧边栏输入密钥,主页面输入主题,点击开始写作。
- 页面加载中,显示5个待选标题和正文。
代码实现:历史对话展示
Section titled “代码实现:历史对话展示”- 使用
for循环迭代st.session_state[``messages] - 代码:
for message in st.session_state[``messages]:` st.chat_message(message[``role]).write(message[``content])\:在页面上展示消息。- 根据
message的role属性,用不同的样式显示(模拟不同用户)。
创建代码仓库
Section titled “创建代码仓库”- 所有文件需在代码仓库下才能上传至 GitHub。
- 代码仓库可看作项目文件夹。
GitHub仓库创建新代码仓库
Section titled “GitHub仓库创建新代码仓库”- 点击
New按钮 - 仓库命名规则:字母、数字、英文标点、下划线、短横线
- 例:
cloned-chatgpt Description:用中文简短描述仓库- 选择
Public或Private决定他人是否可见 - 分享他人看,不要选
Private - 是否添加
README file:提供项目介绍
AI智能PDF问答工具:功能演示 (续)正确答案
Section titled “AI智能PDF问答工具:功能演示 (续)正确答案”- AI给出基于文档内容的回答,并链接文档里的其他相关信息。
- AI给出正确答案,并且把文档里的其他相关信息也返回。
AI智能PDF问答工具:功能演示 (续)GPT-3
Section titled “AI智能PDF问答工具:功能演示 (续)GPT-3”- 确定PDF文档里GPT-3有几个Transformer吗?
- AI给出了基于文档内容的回答:GPT-3有几个Transformer层。
AI智能PDF问答工具:功能演示 (续)GPT-3
Section titled “AI智能PDF问答工具:功能演示 (续)GPT-3”- 确定PDF文档里
GPT-3有几个Transformer吗? - AI给出了基于文档内容的回答:
GPT-3有96个transformer层。 - 且验证了给出的回答仍然是正确的。
- 具有创建储存对话的记忆。
- 如果用户的问题涉及到之前的对话,大模型也能基于记忆给出回答。
- 整体思路是相似的,只需要做小部分修改即可。
- AI可以基于本地知识库的内容做出回答。
- 用户不需要自行上传任何文件。
实现AI对文档的请求
Section titled “实现AI对文档的请求”- 读取用户上传的文档。
- 将文档内容和用户提问传给AI。
- 得到AI基于文档的回答。
- 加载:读取文档。
- 切割:分割文档内容。
下载requirements.txt文件
Section titled “下载requirements.txt文件”- 从课程配套资料里下载。
项目文件设置与依赖安装
Section titled “项目文件设置与依赖安装”- 安装依赖:通过
pip install -r requirements.txt安装项目所需的所有依赖项。 - 创建&;
utils.py&;文件:将所有与AI大模型交互的代码统一放入此文件中。 - 定义&;
qa_agent&;函数:该函数用于封装对AI的请求,接收openai_api_key和memory作为参数,以便处理API密钥和对话记忆。
实现AI对文档的请求
Section titled “实现AI对文档的请求”- 读取用户上传的文档。
- 将文档内容和用户提问传给AI。
- 得到AI基于文档的回答。
- 加载:读取文档。
- 切割:分割文档内容。
下载requirements.txt文件
Section titled “下载requirements.txt文件”- 从课程配套资料里下载。
qa_agent 函数 (续) 模型定义
Section titled “qa_agent 函数 (续) 模型定义”- 模型类型:
gpt-3.5-turbo - 用户提供的
API密钥:通过参数传入openai_api_key,ChatOpenAI的构造函数会使用。 - 代码示例:
from langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key)- 需从
langchain_community.document_loaders的document_loaders模块里导入PyPDFLoader:
from langchain_community.document_loaders import PyPDFLoader- 实例化
PyPDFLoader时,遇到了一个问题:之前读取的都是本地文件,而用户上传的是文件内容
qa_agent 函数 (续) 方法选择
Section titled “qa_agent 函数 (续) 方法选择”- 方法一:将读取到的内存文件内容写入本地文件,然后将路径传递给加载器。
- 适用于上传文件大小不确定,且需要重复使用的场景。
- 缺点:过程繁琐,会创建临时文件。
- 方法二:使用
PyPDFLoader的load_bytes方法。 - 适用于已经读取文件内容,且内容储存在内存里的情况。
- 更简单高效,无需写入本地文件。
- 采取方式2,代码如下:
from langchain_community.document_loaders import PyPDFLoaderfrom langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key) file_content = uploaded_file.read() loader = PyPDFLoader() docs = loader.load_bytes(file_content)- 将获取到的
file_content文本传进去,而不是传文件路径。 - 代码更简洁。
- 代码:
from langchain_community.document_loaders import PyPDFLoaderfrom langchain_openai import ChatOpenAI
def qa_agent(openai_api_key, memory, uploaded_file, question): model = ChatOpenAI(model="gpt-3.5-turbo", openai_api_key=openai_api_key) file_content = uploaded_file.read() loader = PyPDFLoader() docs = loader.load_bytes(file_content)- 将获取到的
file_content文本传进去,而不是传文件路径。 - 代码更简洁。
- 加载后,需要对文档进行分割
- 导入
RecursiveCharacterTextSplitter:
from langchain.text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", " ", ""])-像chunk_size、chunk_overlap 这些
qa_agent 函数 (续)中文分词优化:separators 参数设置
Section titled “qa_agent 函数 (续)中文分词优化:separators 参数设置”- 将
separators赋值为更适合中文的分隔符。 - 代码示例:
text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", " ", ""])text_splitter.split_documents(docs):调用分割文档,得到文本块列表texts。
RAG 步骤 (续) 嵌入 (Embeddings)
Section titled “RAG 步骤 (续) 嵌入 (Embeddings)”- 将文本转换为向量。
- 向量:包含文本的语义和语法信息。
- 用于后续的相似性搜索。
- 嵌入模型:负责将文本转换为向量。
- 从
langchain_openai导入OpenAIEmbeddings:from langchain_openai import OpenAIEmbeddings - 创建嵌入模型:
embedding = OpenAIEmbeddings() - 默认使用
text-embedding-ada-002模型。 - 密钥从环境变量自动获取,也可手动传入
openai_api_key参数。 - 使用
embed_documents方法:将一组文本转换为向量。 - 使用
embed_query方法:将单个文本转换为向量。
RAG 步骤 (续) 向量数据库:Chroma (续)FAISS
Section titled “RAG 步骤 (续) 向量数据库:Chroma (续)FAISS”- 从
langchain_community.vectorstores导入FAISS - 向量数据库,可用它来做相似性搜索
- 代码示例:
db = FAISS.from_documents(texts, embeddings_model) texts:切割后的文档列表embeddings_model:嵌入模型的实例- 使用向量数据库的
as_retriever方法得到检索器 - 检索器:用于从大量文本中快速检索相关信息的组件
- 由于检索器也是
Runnable,说明可以调用它的invoke方法 - 示例:`retrieved_docs = retriever.invoke(
AI智能PDF问答工具:记忆功能
Section titled “AI智能PDF问答工具:记忆功能”- 工具具有创建储存对话的记忆。
- 大模型基于记忆给出回答。
- AI可以基于本地知识库的内容做出回答。
- 不需要自行上传文件。
- 实现过程参考智能PDF问答工具。
- 只需要做小部分修改即可。
- 下一节,介绍问答工具的具体代码。
AIGC:AI生成内容
Section titled “AIGC:AI生成内容”- 指AI生成文本、代码、图片、音频、视频等内容
- 让人难以分辨创作者是人类还是AI
AIGC与生成式AI
Section titled “AIGC与生成式AI”- AIGC:AI生成内容的简称
- 海外更流行词:Generative AI(生成式AI)
- 生成式AI所生成内容即AIGC
- ChatGPT、GitHub Copilot、Midjourney等属于生成式AI
AIGC:AI生成内容
Section titled “AIGC:AI生成内容”- 指AI生成文本、代码、图片、音频、视频等内容
- 让人难以分辨创作者是人类还是AI
机器学习(Machine Learning)
Section titled “机器学习(Machine Learning)”- 是AI的一个子集
- 核心在于:
- 无需人类做显式编程
- 让计算机通过算法自行学习和改进
- 识别模式,做出预测和决策
- 示例:
- 显式编程:图片里有红色说明是玫瑰
- 机器学习:给电脑大量玫瑰和向日葵的图片,让电脑自行识别模式、总结规律,从而对没见过的图片进行预测和判断
- 领域下有多个分支:监督学习、无监督学习、强化学习
- 目标:学习输入和输出之间的映射关系
- 训练数据:包括输入特征和期望的输出值(标签)
- 算法目标:学习输入和输出的映射关系,从而在给定新的输入特征后,能够准确预测输出值
- 任务类型:
- 分类:将数据划分为不同的类别
- 回归:对数值进行预测
- 示例:
- 用猫狗照片和对应标签训练模型,然后让模型识别没见过的照片
监督学习的回顾与分类、回归的区别
Section titled “监督学习的回顾与分类、回归的区别”- 分类:预测类别(如猫或狗)。
- 回归:预测数值(如房价,与面积、卧室数等特征相关)。
- 无监督学习:
- 数据无标签。
- 算法自主发现数据里的模式或规律。
- 经典任务:聚类,将数据进行分组。
- 例:新闻文章按主题自动分组。
- 强化学习:
- 模型在环境中采取行动。
- 从反馈中学习,最大化奖励或最小化损失。
- 从反馈里学习,采取最佳行动,最大化奖励或最小化损失
- 训练小狗示例:观察动作和奖励,接近期望
- ChatGPT模型:扮演AI助手
- 人类评估员打分:基于3H原则
- Helpful(有用性):遵循指令,推理指令的能力
- Honest(真实性):产生幻觉(编造事实)的倾向
- Harmless(无害性):输出是否适当,是否诋毁或包含贬义内容
- 打分高:再接再厉
- 打分低:予以改正
- 深度学习不是监督学习、无监督学习或强化学习的子类
- 深度学习是机器学习的一个方法
- 核心:使用人工神经网络,模拟人脑处理信息的方式
- 层级化方法:提取和表示数据特征
- 神经网络:由计算和存储单元组成,这些单元被称为神经元
- 神经元通过层连接处理数据
- 深度学习模型通常有很多层,因此称为“深度”
- 例如:识别小猫的照片
- 数据先传递到输入层,像人类的眼睛看到图像
- 数据通过多个隐藏层
深度学习 (Deep Learning)中的神经网络
Section titled “深度学习 (Deep Learning)中的神经网络”- 每层都会对数据进行复杂的数学运算,帮助计算机理解图片中的特征,如猫的耳朵、眼睛等。
- 最后输出一个答案,判断是否为猫的图片。
- 用于监督学习、无监督学习、强化学习。
- 深度学习不属于它们的子集.
生成式AI (Generative AI)
Section titled “生成式AI (Generative AI)”- 是深度学习的一种应用。
- 利用神经网络识别现有内容的模式和结构,学习生成新的内容。
- 内容形式:文本、代码、图片、音频、视频等。
大语言模型 (Large Language Model, LLM)
Section titled “大语言模型 (Large Language Model, LLM)”- 也是深度学习的一种应用,专门用于进行自然语言处理任务.
大语言模型的核心
Section titled “大语言模型的核心”- 专门用于进行自然语言处理任务
- 参数量非常大
- 数十亿甚至上万亿个
- 需要海量文本数据集训练
- 从而更好地理解自然语言,生成高质量文本
- 示例:GPT、LLaMA、ERNIE、ChatGLM
- 以GPT-3为例:根据输入提示和前面生成过的词,逐步生成下一个词或
token来输出文本序列
BERT 模型
Section titled “BERT 模型”- Google 的 BERT 模型是一个例子
- 参数量:3.4 亿
- 应用:
- 理解上下文能力强,用于搜索
- 提高搜索排名和信息筛除的准确性
- 情感分析、文本分类等任务
BERT模型
Section titled “BERT模型”- BERT模型:不擅长文本生成,擅长以下任务:
- 情感分析:判断文本的情感倾向。
- 文本分类:将文本归类到不同主题。
- 命名实体识别:识别文本中的人名、地名、日期等。
AIGC概念要素
Section titled “AIGC概念要素”AI+ 机器学习 + 监督学习 + 分类 + 回归 + 无监督学习 + 聚类 + 强化学习+ 深度学习 + 生成式AI + 大语言模型- 以上概念共同构成了生成式AI的核心要素。
大语言模型(LLM)
Section titled “大语言模型(LLM)”- 也叫LLM (Large Language Model)
- 用于做自然语言相关任务的深度学习模型
- 给模型一些文本内容输入,它能返回相应的输出
- 完成的具体任务可以是:生成、分类、总结、改写等
- 需要通过大量文本进行无监督学习
- 以GPT-3为例:训练数据有多个互联网文本语料库,覆盖线上书籍、新闻文章、科学论文、维基百科、社交媒体帖子等等
- 训练数据规模:**3000亿
token**单位
大语言模型的参数规模的增加
Section titled “大语言模型的参数规模的增加”- GPT-1:1.17亿个参数
- GPT-2:15亿个参数
- GPT-3:1750亿个参数
- 参数数量的增加,大语言模型不再局限于单项或某几项任务,而是具有更加广泛的能力
- 制作蛋糕的原料:牛奶、苏打粉、可可粉的量,烤箱的时长和温度
- 大语言模型由于可以调整的变量更多,更能让AI模仿做出更好吃的蛋糕
大语言模型发展历史 (续)
Section titled “大语言模型发展历史 (续)”- 2017年6月:谷歌团队发表论文Attention is All You Need,提出Transformer架构,改变了自然语言处理的发展方向
- 随后出现一系列基于Transformer的模型:
- 2018年:OpenAI发布GPT 1.0,谷歌发布BERT
大语言模型发展历史 (续)
Section titled “大语言模型发展历史 (续)”- 2019年:OpenAI发布 GPT 2.0,百度发布 A0 1.0 等
- 大语言模型发展早已如火如荼,并非很多人以为的2022年才突破
- ChatGPT成功原因:直接向公众开放,支持网页对话交互,体验流畅,从而吸引大众目光
ChatGPT背后的模型
Section titled “ChatGPT背后的模型”- 首字母分别表示Generative Pre-trained Transformer
- 生成、预训练、Transformer
- 表明Transformer是大语言模型的关键,无法跳过
语言模型历史:RNN架构
Section titled “语言模型历史:RNN架构”- 主流架构:循环神经网络(RNN)
- 按顺序逐字处理
- 每一步输出依赖先前隐藏状态和当前输入
- 串行计算:上一步完成后才能进行下一步
- 无法并行计算,计算效率低
- 不擅长处理长序列(长文本)
- 由于RNN架构特点,时间距离越远效果越差
语言模型历史:RNN架构的局限性
Section titled “语言模型历史:RNN架构的局限性”- RNN:循环神经网络按顺序逐字处理
- 每一步输出依赖于先前的隐藏状态和当前输入
- 串行计算:上一步完成后才能进行下一步
- 无法并行计算,计算效率低
- 不擅长处理长序列(长文本)
- 距离越远,效果越差
语言模型历史:LSTM架构
Section titled “语言模型历史:LSTM架构”- 循环神经网络(RNN)的改良版本:LSTM(长短期记忆网络)
- 解决RNN无法并行计算的问题
- 擅长学习输入序列里所有词的相关性和上下文
- 不会受到短时记忆的影响
- Transformer架构:七彩祥云般出现
- 能学习输入序列里所有词的相关性和上下文
- 不会受到短时记忆的影响
- 自注意力机制
Transformer自注意力机制的优势 (续)示例句子分析:
Section titled “Transformer自注意力机制的优势 (续)示例句子分析:”- 示例句子:
The animal didn't cross the street because it was too tired - 自注意力机制:捕获
it与animal的强依赖,关注更远的animal - 每个词与其他词有不同权重,反映相关性
- 即使词位置隔很远,仍能专注于输入中真正重要部分
位置编码(Positional Encoding)
Section titled “位置编码(Positional Encoding)”- 语言顺序重要:相同词不同序,含义大变
小处不可随便vs不可随便小处- 序列:一系列按特定顺序排列的元素
- Transformer:位置编码提供顺序信息
位置编码(Positional Encoding)
Section titled “位置编码(Positional Encoding)”- 语言顺序重要:相同词不同序,含义大变
- “小处不可随便” vs “不可随便小处”
- 位置:小处(0) 不可(1) 随便(2) → 不同含义
- 序列:一系列按特定顺序排列的元素
- Transformer关键创新:位置编码,提供顺序信息
RNN处理瓶颈回顾
Section titled “RNN处理瓶颈回顾”- RNN按顺序串行处理(如人类阅读)
- 无法并行学习所有信息 → 训练速度慢
Transformer架构的核心思想
Section titled “Transformer架构的核心思想”- 预测出现概率最高的下一个词,实现文本生成
- 类似于搜索引擎的自动补全功能
- 通过大量数据训练,学习每个词的出现概率
Transformer架构组成 (续)两个核心部分:编码器和解码器
Section titled “Transformer架构组成 (续)两个核心部分:编码器和解码器”- 编码器(Encoder)
- 解码器(Decoder)
- 任务示例:英语翻译法语
- 编码器:输入英语
- 解码器:返回法语
Transformer架构组成 (续)编码器工作原理
Section titled “Transformer架构组成 (续)编码器工作原理”- Token化:将输入文本拆分成
token - 理解为文本的基本单位
- 短单词:每个词是一个
token - 长单词:拆成多个
token - 每个
token会用一个整数数字表示
编码器工作原理
Section titled “编码器工作原理”- 给编码器输入一句英文,解码器返回对应的法语。
- 输入文本首先会被token化
- 将输入拆分为各个
token。 Token是文本的基本单位。- 短单词可能每个词是一个
token,长单词可能被拆成多个token。 - 每个
token会用一个整数数字表示,称为token ID。 - 计算机内部无法直接存储文字,任何字符最终都需用数字表示。
- 有了数字表示的输入文本后,再把它传入嵌入层
嵌入层(Embedding Layer):将token ID转换为向量表示。- 向量是一串数字,能包含比单个数字更多的语法和语义信息。
- 为什么用向量?
- 单个数字难以表达词语的复杂含义和关系。
- 向量能表示词语在多维度上的特征,捕捉词语间的相似性和差异性。
编码器工作原理
Section titled “编码器工作原理”- 计算机内部无法直接存储文字,任何字符最终都需用数字表示。
嵌入层(Embedding Layer):将token ID转换为向量表示。向量是一串数字,能包含比单个数字更多的语法和语义信息。- 向量的长度实际可以非常长,图示为简化展示。
- 为什么用向量?
- 单个数字难以表达词语的复杂含义和关系。
- 向量能表示词语在多维度上的特征,捕捉词语间的相似性和差异性。
- 例如,“man” 和 “woman” 都指人类,但性别不同。如果只用一个数字表示,很难同时体现这种相似和差异。多维向量可以更好地在不同维度上区分它们。
词嵌入向量 (续) - 向量维度: - 简化表示:三维向量空间 - 实际:Transformer 论文中,向量长度为512 - GPT-3:12288 - 向量表示的意义: - 第一个数字:可以表示词性的程度 - 第二个数字:可以表示年龄大小的程度 - 第三个数字:可以表示社会阶层高低的程度 - 词汇关系: - 词嵌入向量包含词汇之间的语法语义关系 - 相似的词,对应的嵌入向量在向量空间里距离更近 - 无关系的词,距离更远 - 作用: - 帮助模型利用数学计算向量空间里的距离 - 捕捉不同词在语义和语法等方面的相似性 - 示例: - “男人”与“国王”的差异,和“女人”与“女王”的差异可以被看作是相似的 - 总结: - 词向量不仅可以帮模型理解词的语义,也可以捕捉词与词之间的复杂关系
Section titled “词嵌入向量 (续) - 向量维度: - 简化表示:三维向量空间 - 实际:Transformer 论文中,向量长度为512 - GPT-3:12288 - 向量表示的意义: - 第一个数字:可以表示词性的程度 - 第二个数字:可以表示年龄大小的程度 - 第三个数字:可以表示社会阶层高低的程度 - 词汇关系: - 词嵌入向量包含词汇之间的语法语义关系 - 相似的词,对应的嵌入向量在向量空间里距离更近 - 无关系的词,距离更远 - 作用: - 帮助模型利用数学计算向量空间里的距离 - 捕捉不同词在语义和语法等方面的相似性 - 示例: - “男人”与“国王”的差异,和“女人”与“女王”的差异可以被看作是相似的 - 总结: - 词向量不仅可以帮模型理解词的语义,也可以捕捉词与词之间的复杂关系”- 词嵌入向量:不仅理解词义,还能捕捉词与词之间的复杂关系。
- 示例:在三维向量空间中,“man”到“king”的向量与“woman”到“queen”的向量平行,表示相似的关系。
- Transformer论文中,向量长度为512。
- GPT-3中,向量长度为12288,可见其包含的信息量巨大。
编码器工作原理 (续) 词向量与位置向量结合
Section titled “编码器工作原理 (续) 词向量与位置向量结合”- 编码器通过
嵌入层获得词向量后,下一步是进行位置编码。 - 位置编码:表示每个词在文本中顺序的向量。
- 将词向量与位置向量相加,得到新的向量表示,并传递给编码器。
- 意义:模型既能理解词的语义,又能捕获词在句子中的位置,从而理解词之间的顺序关系。
编码器工作原理 (续)
Section titled “编码器工作原理 (续)”- 编码器的主要任务:
- 把输入转换成更抽象的表示形式,也是向量。
- 既保留了输入文本的词汇信息和顺序关系,又补充了语法语义上的关键特征。
- 捕捉关键特征的核心是编码器的自注意力机制。
Transformer的自注意力机制
Section titled “Transformer的自注意力机制”- 模型处理每个词时,不仅关注词本身和附近词,还关注输入序列里所有其他词。
- Attention is all you need —— 注意力就是一切
编码器输出的表示结果:不仅包含词语本身信息,还融合了上下文中的相关信息。- 上下文在语言中非常重要,能揭示相同词语的不同含义。
- 示例:“人要是行,干一行行一行,一行行行行,行行行行干哪行都行,要是不行,干一行不行一行,一行不行行行不行,行行不行,干哪行都不行”。
- 每个词的向量会根据上下文信息进行调整。
- 同一个词在不同上下文中有不同的抽象表示。
Transformer架构深入理解 (续)
Section titled “Transformer架构深入理解 (续)”- Transformer 实际上使用了多头自注意力(Multi-Head Attention)
- 编码器不只有一个自注意力模块,而是多个
- 每个“头”有自己的注意力权重,关注文本不同特征或方面:
- 动词
- 修饰词
- 情感
- 命名实体
- 并行运算:各“头”计算互不影响
- 权重学习:模型在大量文本训练中学习和调整
- 编码器有多层,每层结构相同,但不共享权重
解码器工作原理 (续)多头自注意力机制和前馈神经网络
Section titled “解码器工作原理 (续)多头自注意力机制和前馈神经网络”- 编码器和解码器都是多个堆叠在一起,可以增加模型的性能,有助于处理复杂的输入输出关系。
- 解码器的最后阶段:
- 包含一个线性层和一个 Softmax 层。
- 作用:把解码器输出表示转换为词汇表的概率分布。
- 词汇表的概率分布代表下一个被生成
token的概率。 - 模型会选择概率最高的
token作为下一个输出。 - 模型幻觉:模型一本正经地胡说八道。
- 解码器会重复多次,新的
token会持续生成,直到生成的是一个用来表示输出序列结束的特殊token。
解码器工作原理 (续)多头自注意力机制和前馈神经网络
Section titled “解码器工作原理 (续)多头自注意力机制和前馈神经网络”- 编码器和解码器都是多个堆叠在一起,可以增加模型的性能,有助于处理复杂的输入输出关系。
- 解码器的最后阶段:
- 包含一个线性层和一个 Softmax 层。
- 作用:把解码器输出表示转换为词汇表的概率分布。
- 词汇表的概率分布代表下一个被生成
token的概率。 - 模型会选择概率最高的
token作为下一个输出。 - 模型幻觉:模型一本正经地胡说八道。
- 解码器会重复多次,新的
token会持续生成,直到生成的是一个用来表示输出序列结束的特殊token。
解码器工作原理 (续)带掩码的多头自注意力
Section titled “解码器工作原理 (续)带掩码的多头自注意力”- 解码器中使用
带掩码的多头自注意力,针对已生成的输出序列。 - 解码器还有个
多头自注意力层:利用编码器输出的输入序列抽象表示。 - 注意力:捕捉编码器的输出和解码器即将生成的输出之间的对应关系,融合原始输入序列信息。
- 解码器里的
前馈神经网络:作用与编码器类似,增强模型表达能力。
解码器工作原理 (续)多头自注意力机制和前馈神经网络
Section titled “解码器工作原理 (续)多头自注意力机制和前馈神经网络”- 编码器和解码器都是多个堆叠在一起,可以增加模型的性能,有助于处理复杂的输入输出关系。
- 解码器的最后阶段:
- 包含一个线性层和一个 Softmax 层。
- 作用:把解码器输出表示转换为词汇表的概率分布。
- 词汇表的概率分布代表下一个被生成
token的概率。 - 模型会选择概率最高的
token作为下一个输出。 - 模型幻觉:模型一本正经地胡说八道。
- 解码器会重复多次,新的
token会持续生成,直到生成的是一个用来表示输出序列结束的特殊token。
Transformer架构的变体:仅编码器/自编码模型
Section titled “Transformer架构的变体:仅编码器/自编码模型”- 例子:BERT
- 用途:掩码语言建模、情感分析等
- 适用场景:理解语言的任务
Transformer架构的变体:仅解码器/自回归模型
Section titled “Transformer架构的变体:仅解码器/自回归模型”- 例子:GPT-2、GPT-3
- 用途:文本生成
- 适用场景:通过预测下一个词来实现文本生成
Transformer架构组成(续)编码器-解码器
Section titled “Transformer架构组成(续)编码器-解码器”- 编码器-解码器模型,也叫序列到序列模型
- 例子:T5、BART
- 用途:翻译、总结等
- 适用场景:一个序列转换为另一个序列的任务
ChatGPT炼成步骤 (续) 监督微调
Section titled “ChatGPT炼成步骤 (续) 监督微调”- 对基座模型进行微调。
- 微调后的模型具备更好的对话能力。
- 基座模型有预测下一个
token的能力,但并不擅长对话。 - 模型可以模仿上文生成更多问题,但不回答问题。
ChatGPT炼成步骤 (续) 监督微调
Section titled “ChatGPT炼成步骤 (续) 监督微调”- 基座模型进行微调。
- 微调后的模型具备更好的对话能力。
- 基座模型有预测下一个
token的能力,但并不擅长对话。 - 模型可以模仿上文生成更多问题,但不回答问题。
监督学习 vs 无监督学习 (续)
Section titled “监督学习 vs 无监督学习 (续)”- 为了解决模型不回答问题,需要进行第二步:监督微调。
ChatGPT炼成步骤 (续)
Section titled “ChatGPT炼成步骤 (续)”- 监督微调:在已有模型上进一步训练,调整模型内部参数,使其更适应特定任务。
- 给基座模型更多对话数据。
- 微调成本低于预训练,因为所需数据规模更小,训练时长更短。
- 模型从人类撰写的高质量对话中学习,获得人类中意的回答,属于监督学习。
- 这一过程称为监督微调(Supervised Fine-Tuning),简称SFT。
- 完成后得到SFT模型,更擅长对问题做出回答。
- 强化学习:让
SFT模型进行强化学习,学会如何生成更优质的回复。
ChatGPT 炼成步骤 (续) 无监督预训练
Section titled “ChatGPT 炼成步骤 (续) 无监督预训练”- 需要海量文本作为原料,让模型自动学习。
- 例如:GPT-3 的训练数据。
| Dataset | Quantity (tokens) | Weight in training mix |
|---|---|---|
| Common Crawl | 410 billion | 60% |
| WebText2 | 19 billion | 22% |
| Books1 | 12 billion | 8% |
| Books2 | 55 billion | 8% |
| Wikipedia | 3 billion | 3% |
- 覆盖书籍、新闻文章、科学论文、维基百科、社交媒体帖子等。
- 训练数据的整体规模:3000亿的
token。
- 大语言模型的一个基本文本单位。
- 像短的英文单词或一个标点符号。
- 中文的话,所占的
token数量会相对更多,有些字要用一个甚至更多token表示。
ChatGPT炼成步骤(续)
Section titled “ChatGPT炼成步骤(续)”- 强化学习:
- 利用强化学习技术,让模型学会如何生成更优质的回复。
- 人工标注数据反馈给模型,不断调整优化。
监督学习 vs 无监督学习
Section titled “监督学习 vs 无监督学习”- 监督学习:模型接受带有标签的训练数据,标签是期望的输出值。
- 每个训练数据点包含输入特征和期望输出值。
- 无监督学习:模型在没有标签的数据上进行训练。
- 模型自己找出数据中的结构和模式。
- 例:GPT-3 利用海量文本,自行学习人类语言的语法、语义,了解表达结构和模式。
监督学习 vs 无监督学习
Section titled “监督学习 vs 无监督学习”- 无监督学习:模型在没有标签的数据上进行训练。
- 模型自己找出数据中的结构和模式。
- 例:
GPT-3利用海量文本,自行学习人类语言的语法、语义,了解表达结构和模式。
模型预测Token
Section titled “模型预测Token”- 模型先看到一部分文本,基于上下文尝试预测下一个
token。 - 通过比较正确答案和预测,模型不断学习和调整,变得越来越准确。
ChatGPT炼成步骤 (续) 无监督预训练
Section titled “ChatGPT炼成步骤 (续) 无监督预训练”- 需要海量文本作为原料,让模型自动学习。
- 例如:GPT-3 的训练数据。
| Dataset | Quantity (tokens) | Weight in training mix |
| — | — | — |
| Common Crawl | 410 billion | 60% |
| WebText2 | 19 billion | 22% |
| Books1 | 12 billion | 8% |
| Books2 | 55 billion | 8% |
| Wikipedia | 3 billion | 3% |
- 训练数据的整体规模:3000亿的
token。
- 大语言模型的一个基本文本单位。
- 像短的英文单词或一个标点符号。
ChatGPT炼成步骤(续)
Section titled “ChatGPT炼成步骤(续)”- 强化学习:
- 利用强化学习技术,让模型学会如何生成更优质的回复。
- 人工标注数据反馈给模型,不断调整优化。
监督学习 vs 无监督学习
Section titled “监督学习 vs 无监督学习”- 监督学习:模型接受带有标签的训练数据,标签是期望的输出值。
- 每个训练数据点包含输入特征和期望输出值。
- 无监督学习:模型在没有标签的数据上进行训练。
- 模型自己找出数据中的结构和模式。
- 例:GPT-3 利用海量文本,自行学习人类语言的语法、语义,了解表达结构和模式。
模型预测Token
Section titled “模型预测Token”- 模型先看到一部分文本,基于上下文尝试预测下一个
token。 - 通过比较正确答案和预测,模型不断学习和调整,变得越来越准确。
ChatGPT炼成步骤 (续) 监督微调
Section titled “ChatGPT炼成步骤 (续) 监督微调”- 对基座模型进行微调。
- 微调后的模型具备更好的对话能力。
- 基座模型有预测下一个
token的能力,但并不擅长对话。 - 模型可以模仿上文生成更多问题,但不回答问题。
监督学习 vs 无监督学习 (续)
Section titled “监督学习 vs 无监督学习 (续)”- 为了解决模型不回答问题,需要进行第二步:监督微调。
ChatGPT炼成步骤 (续)
Section titled “ChatGPT炼成步骤 (续)”- 监督微调:在已有模型上进一步训练,调整模型内部参数,使其更适应特定任务。
- 给基座模型更多对话数据。
- 微调成本低于预训练,因为所需数据规模更小,训练时长更短。
- 模型从人类撰写的高质量对话中学习,获得人类中意的回答,属于监督学习。
- 这一过程称为监督微调(Supervised Fine-Tuning),简称SFT。
- 完成后得到SFT模型,更擅长对问题做出回答。
- 强化学习:让
SFT模型进行强化学习,学会如何生成更优质的回复。
ChatGPT炼成步骤 (续)监督微调
Section titled “ChatGPT炼成步骤 (续)监督微调”- 对基座模型进行微调。
- 微调后的模型具备更好的对话能力。
- 基座模型有预测下一个
token的能力,但并不擅长对话。 - 模型可以模仿上文生成更多问题,但不回答问题。
监督学习 vs 无监督学习 (续)
Section titled “监督学习 vs 无监督学习 (续)”- 为了解决模型不回答问题,需要进行第二步:监督微调。
ChatGPT炼成步骤 (续)
Section titled “ChatGPT炼成步骤 (续)”- 监督微调:在已有模型上进一步训练,调整模型内部参数,使其更适应特定任务。
- 给基座模型更多对话数据。
- 微调成本低于预训练,因为所需数据规模更小,训练时长更短。
- 模型从人类撰写的高质量对话中学习,获得人类中意的回答,属于监督学习。
- 这一过程称为监督微调(Supervised Fine-Tuning),简称SFT。
- 完成后得到SFT模型,更擅长对问题做出回答。
- 强化学习:让
SFT模型进行强化学习,学会如何生成更优质的回复。
ChatGPT炼成步骤 (续) 强化学习
Section titled “ChatGPT炼成步骤 (续) 强化学习”- 强化学习让模型在环境里采取行动。
- 从反馈里学习,从而能在给定情况下采取最佳行动,来最大化奖励或最小化损失。
- 训练小狗类似:
- 小狗通过观察动作和奖励之间的联系,逐渐接近训练师的期望。
- 让ChatGPT模型扮演一个乐于助人的AI助手也是一样的道理。
- 可以让ChatGPT对问题做出回答,然后让人类评估员去给回答打分。
- 打分主要基于3H原则:
- Helpful(有用性):判断模型遵循用户指令以及推理指令的能力。
- Honest(真实性):判断模型产生幻觉(编造事实)的倾向。
- Harmless(无害性):判断模型的输出是否适当,是否诋毁或包含贬义内容。
- 如果打分高,模型能学到要再接再厉;如果打分低,模型能学到要予以改正。
- 但靠人类给回答打分,成本极高,效率极低。
ChatGPT炼成步骤 (续) 强化学习
Section titled “ChatGPT炼成步骤 (续) 强化学习”- 训练奖励模型:
- 让
SFT模型对每个问题生成多个回答。 - 人工标注员对回答质量排序。
- 利用排序数据训练奖励模型,使其学习预测回答的评分。
- 强化学习:
- ChatGPT模型的初始参数来自之前的
SFT模型,但会随着训练被更新。 - 奖励模型的参数则不再会被更新。
- 奖励模型的任务是对模型生成的内容打分。
- 模型会不断优化策略,回答的质量会进一步提升。
ChatGPT炼成步骤 (续) 强化学习
Section titled “ChatGPT炼成步骤 (续) 强化学习”- 让模型在环境里采取行动。
- 从反馈里学习,从而能在给定情况下采取最佳行动,来最大化奖励或最小化损失。
- 训练小狗类似:
- 小狗通过观察动作和奖励之间的联系,逐渐接近训练师的期望。
- 让ChatGPT模型扮演一个乐于助人的AI助手也是一样的道理。
- 可以让ChatGPT对问题做出回答,然后让人类评估员去给回答打分。
- 打分主要基于3H原则:
- Helpful(有用性):判断模型遵循用户指令以及推理指令的能力。
- Honest(真实性):判断模型产生幻觉(编造事实)的倾向。
- Harmless(无害性):判断模型的输出是否适当,是否诋毁或包含贬义内容。
- 如果打分高,模型能学到要再接再厉;如果打分低,模型能学到要予以改正。
- 但靠人类给回答打分,成本极高,效率极低。
ChatGPT炼成步骤 (续) 强化学习
Section titled “ChatGPT炼成步骤 (续) 强化学习”- 训练奖励模型:
- 让
SFT模型对每个问题生成多个回答。 - 人工标注员对回答质量排序。
- 利用排序数据训练奖励模型,使其学习预测回答的评分。
- 强化学习:
- ChatGPT模型的初始参数来自之前的
SFT模型,但会随着训练被更新。 - 奖励模型的参数则不再会被更新。
- 奖励模型的任务是对模型生成的内容打分。
- 模型会不断优化策略,回答的质量会进一步提升。
ChatGPT炼成步骤 (续) 强化学习
Section titled “ChatGPT炼成步骤 (续) 强化学习”- 训练奖励模型:
- 让
SFT模型对每个问题生成多个回答。 - 人工标注员对回答质量排序。
- 利用排序数据训练奖励模型,使其学习预测回答的评分。
- 强化学习:
- ChatGPT模型的初始参数来自之前的
SFT模型,但会随着训练被更新。 - 奖励模型的参数则不再会被更新。
- 奖励模型的任务是对模型生成的内容打分。
- 模型会不断优化策略,回答的质量会进一步提升。
编写Python代码前的准备
Section titled “编写Python代码前的准备”- 2022年11月:ChatGPT对外发布,生成式AI元年。
- 编写Python代码前需准备:
- 安装 Python解释器
- 机器无法直接读取Python代码,需要解释器。
- Python运行过程:翻译一行,执行一行。
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- PyCharm:
- 专门为Python设计的集成开发环境(IDE)。
- 提供代码补全、自动格式化、拼写检查等。
- 内含调试器和版本控制工具。
- 作为新手,无需一次性学会所有功能,随经验增加逐步掌握。
- 安装步骤:
- 从Python官网下载Python解释器和PyCharm。
编写Python代码前的准备 (续) - 安装完成后,随着经验增加,你上手的功能会越来越多。- 接下来的视频会介绍如何在Windows或macOS系统上安装Python和PyCharm。- Python解释器安装: - 访问 www.python.org 下载。 - 首先,搜索Python官网。 - 找到有“官方”标志的网页点击进入。 - 或者在浏览器地址栏输入www.python.org。
Section titled “编写Python代码前的准备 (续) - 安装完成后,随着经验增加,你上手的功能会越来越多。- 接下来的视频会介绍如何在Windows或macOS系统上安装Python和PyCharm。- Python解释器安装: - 访问 www.python.org 下载。 - 首先,搜索Python官网。 - 找到有“官方”标志的网页点击进入。 - 或者在浏览器地址栏输入www.python.org。”编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- Python解释器安装:
- 访问 www.python.org 下载。
- 点击 Downloads。
- 网站会自动识别系统。
- 点击大黄按钮开始下载。
- 安装时,务必勾选
"Add Python to PATH",将Python路径添加到环境变量中,让电脑识别Python安装位置。 - 点击
"Install Now"开始安装。
编写Python代码前的准备 (续) Python解释器安装完毕后:
Section titled “编写Python代码前的准备 (续) Python解释器安装完毕后:”- 务必勾选
"Add Python to PATH":将Python路径添加到环境变量中,让电脑识别Python安装位置 - 点击
"Install Now"开始安装 - 出现路径长度提示,点击并忽略
编写Python代码前的准备 (续)验证Python是否安装成功:
Section titled “编写Python代码前的准备 (续)验证Python是否安装成功:”- 在菜单栏搜索
cmd进入命令提示符 - 输入
python(全小写),点击回车 - 显示Python版本信息,表示安装成功
编写Python代码前的准备 (续)安装PyCharm:
Section titled “编写Python代码前的准备 (续)安装PyCharm:”- 搜索PyCharm官网 www.jetbrains.com/pycharm/
- 点击 Download
- PyCharm有两个版本:专业版(收费)和社区版(免费)
- 纯Python开发者社区版够用
PyCharm安装
Section titled “PyCharm安装”- 访问
www.jetbrains.com/pycharm/下载。 - PyCharm有两个版本:专业版(收费)和社区版(免费)。
- 纯Python开发者社区版足够用。
- 下载免费Community版本。
- 安装步骤:
- 打开下载的安装包。
- 点击“下一步”,选择安装位置。
- 勾选创建桌面快捷方式(可选)。
- 勾选所有
.py文件用PyCharm打开(可选)。 - 点击“下一步”,等待安装完成。
- 点击“完成”,关闭安装窗口。
- 首次打开PyCharm:
- 选择语言和地区(可选择中文)。
- 同意用户协议。
- 询问是否分享匿名数据,可选择不分享。
- 可能会弹出提示,询问文件访问权限,点击“好”即可。
- 如果电脑有安装其他代码编辑器,会询问是否导入配置,不需要可跳过。
- 完成初始化后,即可开始创建项目和编写代码。
编写Python代码前的准备 (续) - 想让所有Python文件都用PyCharm打开的话,最后这个也可以勾选上。 - 点击下一步,等待安装完成。因为PyCharm这个软件挺大的,需要花一些时间安装。 - 点击完成,关闭安装窗口。 - 接下来打开PyCharm,它会弹出一个窗口让我们选择语言和地区,因为我的操作系统是中文的,所以它默认也是中文了。但如果你的不是中文也没有关系,我们后续也会教你如何把它设置成中文的。那我们点击下一个。 - 然后我们需要先同意用户协议,像我平时就是不太看用户协议的。 - 如果你有安装其它的代码编辑器,它会问你要不要导入其中的配置。
Section titled “编写Python代码前的准备 (续) - 想让所有Python文件都用PyCharm打开的话,最后这个也可以勾选上。 - 点击下一步,等待安装完成。因为PyCharm这个软件挺大的,需要花一些时间安装。 - 点击完成,关闭安装窗口。 - 接下来打开PyCharm,它会弹出一个窗口让我们选择语言和地区,因为我的操作系统是中文的,所以它默认也是中文了。但如果你的不是中文也没有关系,我们后续也会教你如何把它设置成中文的。那我们点击下一个。 - 然后我们需要先同意用户协议,像我平时就是不太看用户协议的。 - 如果你有安装其它的代码编辑器,它会问你要不要导入其中的配置。”编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- PyCharm初始化后:可创建项目和编写代码。
- Mac电脑安装Python和PyCharm:
- 访问 www.python.org 下载Python解释器。
- 网站自动识别系统。
- 点击大黄按钮下载。
- 确保下载的版本正确匹配电脑的系统。
编写Python代码前的准备 (续)
Section titled “编写Python代码前的准备 (续)”- Python解释器安装 (Mac):
- 下载安装包后打开,一路点击下一步
- 需要管理员权限,输入Mac用户名和密码
- 稍等片刻,等待安装完毕
- 关闭安装窗口
- 验证Python是否安装成功:
- 打开电脑终端
- 点击顶部菜单栏放大镜图标,输入“终端”
- 或者,点击“访达”,顶部选择“前往”-“实用工具”,找到“终端”打开
- 输入
python3(全小写),回车 - 显示Python版本信息,说明安装成功
编写Python代码前的准备 (续) Python解释器安装 (Mac)
Section titled “编写Python代码前的准备 (续) Python解释器安装 (Mac)”- 下载安装包后打开,一路点击下一步。
- 需要管理员权限,输入Mac用户名和密码。
- 稍等片刻,等待安装完毕。
- 关闭安装窗口。
编写Python代码前的准备 (续) 验证Python是否安装成功 (Mac)
Section titled “编写Python代码前的准备 (续) 验证Python是否安装成功 (Mac)”- 打开电脑终端:
- 点击顶部菜单栏放大镜图标,输入“终端”。
- 或者,点击“访达”,顶部选择“前往”->“实用工具”,找到“终端”打开。
- 输入
python3(全小写),回车。 - 如显示Python版本信息,说明安装成功。
编写Python代码前的准备 (续) PyCharm安装 (Mac)
Section titled “编写Python代码前的准备 (续) PyCharm安装 (Mac)”- 下载:点击黑色 Download 按钮下载免费 Community 版本。
- 安装步骤:将下载好的
PyCharm拖入应用程序文件夹。 - 打开
PyCharm即可开始使用。 - 首次打开 PyCharm:
- 弹出窗口让你选择语言和地区,可以选择中文。
- 同意用户协议。
- 询问是否分享匿名数据,可选择不分享。
- 可能会弹出提示,询问文件访问权限,点击“好”即可。
- 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过。
- 完成初始化后,可以开始创建项目和编写代码了。
PyCharm 安装
Section titled “PyCharm 安装”- 点击黑色 Download 按钮下载免费 Community 版本。
- 安装步骤:
- 打开下载完成的安装包。
- 点击下一步,选择安装位置。
- 勾选创建桌面快捷方式(可选)。
- 勾选所有
.py文件用 PyCharm 打开(可选)。 - 点击下一步,等待安装完成。
- 点击完成,关闭安装窗口.
- 打开 PyCharm:选择语言和地区(默认中文)。
- 同意用户协议。
- 下载完成后,把 PyCharm 拖入应用程序文件夹。
- 打开 PyCharm 即可开始使用。
- 首次打开 PyCharm 会弹出窗口让你选择语言和地区,可以选择中文。
- 接下来需要同意用户协议。
- 然后会询问是否分享匿名数据,可选择不分享。
- 可能会弹出提示,询问文件访问权限,点击好即可。
- 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过.
- 完成初始化后,可以开始创建项目和编写代码了。
PyCharm 安装 (Mac): - 打开 PyCharm:选择语言和地区(默认中文)。 - 同意用户协议。 - 询问是否分享匿名数据,可选择不分享。 - 可能会弹出提示,询问文件访问权限,点击好即可。 - 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过。 - 完成初始化后,可以开始创建项目和编写代码了。
Section titled “PyCharm 安装 (Mac): - 打开 PyCharm:选择语言和地区(默认中文)。 - 同意用户协议。 - 询问是否分享匿名数据,可选择不分享。 - 可能会弹出提示,询问文件访问权限,点击好即可。 - 如果电脑有安装其他代码编辑器,会询问是否导入其中的配置,不需要的话可以跳过。 - 完成初始化后,可以开始创建项目和编写代码了。”PyCharm 设置中文界面
Section titled “PyCharm 设置中文界面”- 如果 PyCharm 界面是英文,可通过以下步骤设置为中文:
- 点击左下角设置图标(或 Windows 系统下的 Settings)。
- 选择
Plugins(插件)。 - 在插件页面的搜索框输入
chinese。 - 找到
Chinese (Simplified) Language Pack中文语言包。
- 如果在
Marketplace找不到,可能是已默认安装,转到Installed查看。
- 如果中文语言包是灰色禁用状态,点击启用。
PyCharm 设置中文界面 (续)
Section titled “PyCharm 设置中文界面 (续)”- 如果中文语言包是灰色禁用状态,点击启用。
- 点击右下角的
Apply,然后点击OK。 - 再次点击左下角设置图标(或 Windows 系统下的 Settings)。
- 搜索
language,找到Language and Region。 - 在这里选择中文,点击
OK。 - 然后点击
Restart重启。 - 现在界面上的语言就变成中文的了。
- 现在要创建一个项目,以便集中管理代码文件。
- 在欢迎页面找到
新建项目,点击它。 - 第一行表示项目文件所在位置,可修改,但要先创建文件夹。
- 下面解释器类型可以选择默认的
项目venv。 - PyCharm会自动检测电脑里的Python版本。
PyCharm 设置中文界面
Section titled “PyCharm 设置中文界面”- 如果 PyCharm 界面是英文:
- 点击左下角设置图标(或 Windows 系统下的 Settings)。
- 选择
Plugins(插件)。 - 在插件页面的搜索框输入
chinese。 - 找到
Chinese (Simplified) Language Pack中文语言包。
- 如果在
Marketplace找不到,可能是已默认安装,转到Installed查看。
- 如果中文语言包是灰色禁用状态,点击启用。
PyCharm 设置中文界面 (续) - 再次点击左下角设置图标(或 Windows 系统下的 Settings)。 - 搜索language,找到Language and Region。 - 在这里选择中文,点击OK。 - 然后点击Restart重启。 - 现在界面上的语言就变成中文的了。 - 现在要创建一个项目,以便集中管理代码文件。 - 在欢迎页面找到新建项目,点击它。 - 第一行表示项目文件所在位置,可修改,但要先创建文件夹。 - 下面解释器类型可以选择默认的项目venv。 - PyCharm会自动检测电脑里的Python版本。
Section titled “PyCharm 设置中文界面 (续) - 再次点击左下角设置图标(或 Windows 系统下的 Settings)。 - 搜索language,找到Language and Region。 - 在这里选择中文,点击OK。 - 然后点击Restart重启。 - 现在界面上的语言就变成中文的了。 - 现在要创建一个项目,以便集中管理代码文件。 - 在欢迎页面找到新建项目,点击它。 - 第一行表示项目文件所在位置,可修改,但要先创建文件夹。 - 下面解释器类型可以选择默认的项目venv。 - PyCharm会自动检测电脑里的Python版本。”PyCharm 项目设置
Section titled “PyCharm 项目设置”- 项目文件夹:存放与项目相关的文件,如前后端代码、图片素材等。
venv文件夹:PyCharm自动创建,表示该项目独立的 Python 虚拟环境。- 目的:不同项目可用不同的解释器版本和第三方库。
- 不要动此文件夹,不要删除或往里添加东西。
- 创建其他 Python 项目文件夹,按相同步骤重复即可。
新建 Python 文件
Section titled “新建 Python 文件”- 右键单击项目文件夹 -> 新建 -> Python 文件
- 命名:以
.py结尾,例如hello.py - 你就拥有了一个可以编辑代码的地方
代码编写:与计算机交流
Section titled “代码编写:与计算机交流”- 更准确地说是给计算机下指令
Python 代码书写注意事项 (续)标点符号
Section titled “Python 代码书写注意事项 (续)标点符号”- 必须使用英文标点,而非中文标点
- 中文标点符号通常更宽
| 符号类型 | 中文 | 英文 |
| — | — | — |
| 括号 | () | () |
| 逗号 | , | , |
| 分号 | ; | ; |
| 方括号 | 【】 | [] |
- 使用单引号或双引号均可,但必须是英文
- 引号用于区分原文和其他部分,避免歧义
- 即使引号里的内容是数字,也会被识别为字符串,而不是数字
- 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码
Python 代码书写注意事项 (续) - print("Dad!!"):Dad!! 必须放在英文引号内。 - 括号外的print命令无法打印内容。 - 标点符号: - 必须使用英文标点,而非中文标点。 - 中文标点符号通常更宽。 | 符号类型 | 中文 | 英文 | | — | — | — | | 括号 | () | () | | 逗号 | , | , | | 分号 | ; | ; | | 方括号 | 【】 | [] | - 使用单引号或双引号均可,但必须是英文。 - 引号用于区分原文和其他部分,避免歧义。 - 即使引号里的内容是数字,也会被识别为字符串,而不是数字。 - 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码。
Section titled “Python 代码书写注意事项 (续) - print("Dad!!"):Dad!! 必须放在英文引号内。 - 括号外的print命令无法打印内容。 - 标点符号: - 必须使用英文标点,而非中文标点。 - 中文标点符号通常更宽。 | 符号类型 | 中文 | 英文 | | — | — | — | | 括号 | () | () | | 逗号 | , | , | | 分号 | ; | ; | | 方括号 | 【】 | [] | - 使用单引号或双引号均可,但必须是英文。 - 引号用于区分原文和其他部分,避免歧义。 - 即使引号里的内容是数字,也会被识别为字符串,而不是数字。 - 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码。”Python 代码:与计算机交流
Section titled “Python 代码:与计算机交流”- 更准确地说是给计算机下指令
- 计算机按指令执行,如
print("Dad!!")会在屏幕显示 Dad!! print:英语中是打印的意思,可以理解为把指定文字在屏幕上展现出来。
Python 代码书写注意事项
Section titled “Python 代码书写注意事项”print("Dad!!"):Dad!!必须放在英文引号内。- 如果内容放在括号外,
print命令无法打印。 - 标点符号:
- 必须使用英文标点,而非中文标点。
- 中文标点符号通常更宽。
| 符号类型 | 中文 | 英文 |
| — | — | — |
| 括号 | () | () |
| 逗号 | , | , |
| 分号 | ; | ; |
| 方括号 | 【】 | [] |
- 使用单引号或双引号均可,但必须是英文。
- 引号用于区分原文和其他部分,避免歧义。
- 如果不加引号,计算机不会把里面的内容当成是文字
PyCharm:新建 Python 文件
Section titled “PyCharm:新建 Python 文件”- 在项目文件夹中,右键 -> 新建 -> Python 文件
- 命名文件,以
.py结尾 (例如:hello.py)
Python 代码:与计算机交流
Section titled “Python 代码:与计算机交流”- 更准确地说是给计算机下指令
- 计算机按指令执行,如
print("Dad!!")会在屏幕显示 Dad!! print:英语中是打印的意思,可以理解为把指定文字在屏幕上展现出来。
Python 代码书写注意事项
Section titled “Python 代码书写注意事项”print("Dad!!"):Dad!!必须放在英文引号内。- 如果内容放在括号外,
print命令无法打印。 - 标点符号:
- 必须使用英文标点,而非中文标点。
- 中文标点符号通常更宽。
| 符号类型 | 中文 | 英文 |
| — | — | — |
| 括号 | () | () |
| 逗号 | , | ‘,’,
| 分号 | ; | ; |
| 方括号 | 【】 | [] |
- 使用单引号或双引号均可,但必须是英文。
- 引号用于区分原文和其他部分,避免歧义。
- 如果不加引号,计算机不会把里面的内容当成是文字
PyCharm:新建 Python 文件 (续)
Section titled “PyCharm:新建 Python 文件 (续)”- 在项目文件夹中,右键 -> 新建 -> Python 文件
- 命名文件:以
.py结尾 (例如:hello.py) - 建议:文件名尽量不要有空格,避免使用emoji等特殊符号
- 推荐命名方式:英文、数字、下划线
- PyCharm 弹出窗口询问是否添加到 git,初学阶段可选择“不再询问”。
PyCharm:新建 Python 文件
Section titled “PyCharm:新建 Python 文件”- 在项目文件夹中,右键 -> 新建 -> Python 文件
- 命名文件,以
.py结尾 (例如:hello.py) - PyCharm 弹出窗口询问是否添加到 git,初学阶段可选择“不再询问”。
- 编写打印语句:
print(),全部小写。 print()函数内,使用英文引号包裹要打印的内容。- 运行代码:右键点击,选择运行。
- 运行结果:在下方运行窗口显示。
PyCharm 运行代码结果
Section titled “PyCharm 运行代码结果”- PyCharm 运行代码后,第一行和最后一行可以忽略。
- 重点关注第一行和最后一行之间的内容。
- 双引号里的内容可以替换成任意想要的内容,比如中文的叫妈妈也行。
- 右键选择运行,点击后,
妈妈!!就打印出来了。 - 如果代码有问题,PyCharm 会自动用红色提醒,运行的时候也能看到红色的错误提示信息。
- 注意:代码中的符号必须是英文符号,比如括号。
PyCharm 运行代码结果
Section titled “PyCharm 运行代码结果”- PyCharm 运行代码后,第一行和最后一行可以忽略。
- 重点关注第一行和最后一行之间的内容。
- 双引号里的内容可以替换成任意想要的内容,比如中文的叫妈妈也行。
- 右键选择运行,点击后,
妈妈!!就打印出来了。 - 如果代码有问题,PyCharm 会自动用红色提醒,运行的时候也能看到红色的错误提示信息。
- 注意:代码中的符号必须是英文符号,比如括号。
Python代码书写问题解决办法
Section titled “Python代码书写问题解决办法”- 如果遇到错误,PyCharm会自动用红色提醒。
- 运行代码时,也能看到红色的错误提示信息。
- 可以把红色错误信息复制到搜索引擎里进行搜索。
- 错误可能是相似的。
- 很多开发者可能遇到过相同问题,可以借鉴解决方案。
打印字符串的进阶玩法 (续) 字符串连接
Section titled “打印字符串的进阶玩法 (续) 字符串连接”- 字符串:用引号包裹住的一串内容。
- 用加号连接字符串
print("Hello" + " world" + "!")- 输出:
Hello world! - 注意:
world前面有一个空格,所以打印出来中间才会有空格,否则两个词会黏在一起。
打印字符串的进阶玩法 (续) 单双引号转义
Section titled “打印字符串的进阶玩法 (续) 单双引号转义”- 字符串内容含引号,且内外引号类型相同时,会引发错误。
- 示例:
print("He said "good!"" - 转义字符:用反斜杠 ``。
- 示例:
print("He said \"Let's go!\"") - Python会将
\"识别为双引号,\'识别为单引号 - 实际输出:
He said "Let's go!" - 字符串中有反斜杠 ``,Python会将其与后面的符号一起解读,产生特殊的含义.
打印字符串的进阶玩法 (续) 反斜杠转义
Section titled “打印字符串的进阶玩法 (续) 反斜杠转义”- 如果使用反斜杠 `,确保使用正确的反斜杠(键盘Enter键上面那个)。
- )``
- )``(用了正斜杠,无效)
- ``\n`:表示换行符。
- ``print(“我是第一行\n我是第二行”)`
- 结果:两行输出
- ``print(“\n”)`单独打印换行符会输出一个空行。
打印字符串的进阶玩法 (续) 三引号跨行输入
Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入”- 使用三个单引号
'''或三个双引号"""包裹字符串,可以实现跨行输入。 - `print(“”“我是第一行
我是第二行”“”)`
打印字符串的进阶玩法 (续) 三引号跨行输入 (续)
Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入 (续)”- 示例:
print("""我是第一行
我是第二行""")- 结果:两行之间会多一个空行
- 实际应用:复制诗歌等大段文字,保留原始格式。
- 字符串反复打印手机号码很麻烦,可以存储起来。
- 变量:程序里的变量相当于通讯录里的人名,可以通过人名(变量名)获取对应的值。
打印字符串的进阶玩法 (续) 三引号跨行字符串
Section titled “打印字符串的进阶玩法 (续) 三引号跨行字符串”- 三个单引号或双引号连在一起,包裹住文字
- Python会把新的一行当成内容的换行,而不是代码语句的结束
- 新建空白Python文件,例如:
2_more_print.py - 字符串连接示例:
print("你好" + " " + "这是一句代码")- 加号两边空格可有可无,但加上更美观
- 不要在每行开头随意加空格,PyCharm会提示错误
打印字符串的进阶玩法 (续) 字符串连接
Section titled “打印字符串的进阶玩法 (续) 字符串连接”- 字符串:用引号包裹住的一串内容。
- 用加号连接字符串
print("你好" + " " + "这是一句代码")- 加号两边空格可有可无,但加上更美观
- 不要在每行开头随意加空格,PyCharm会提示错误
打印字符串的进阶玩法 (续) 反斜杠转义
Section titled “打印字符串的进阶玩法 (续) 反斜杠转义”- 如果使用反斜杠 ``,确保使用正确的反斜杠(键盘Enter键上面那个)。
- 正确:
print("Let's go") - 错误:
print("Let’s go")(用了正斜杠,无效) \n:表示换行符。print("我是第一行\n我是第二行")- 结果:两行输出
print("\n")单独打印换行符会输出一个空行。
打印字符串的进阶玩法 (续) 三引号跨行输入
Section titled “打印字符串的进阶玩法 (续) 三引号跨行输入”- 使用三个单引号
'''或三个双引号"""包裹字符串,可以实现跨行输入。 - Python 会把新的一行当成内容的换行,而不是代码语句的结束。
- 示例:
print("""我欲乘风归去,又恐琼楼玉宇,高处不胜寒。""")- 运行后,诗歌会按原格式打印,包括换行符。
- 实际应用:复制诗歌等大段文字,保留原始格式。
变量 (Variable)
Section titled “变量 (Variable)”- 当有需要频繁使用的字符串(如手机号),且字符串很长时,反复输入很麻烦,也容易记不住。
- 变量:程序中用来存储或替换值的。就像通讯录里的人名,通过人名(变量名)获取对应的手机号(值)。
赋值操作:给变量一个值的操作,使用=符号。- 示例:
my_love = "13766666666" - 赋值后,可以通过变量名反复使用这个值,无需每次都重新输入。
- Python代码是从上到下执行的,必须先对变量赋值,才能使用它,否则会报错。
- 变量的值可以更新,再次赋值即可覆盖旧值。
- 示例:
my_love = "15066666666" - 变量之间也可以互相赋值。
- 示例:
my_ex = my_love - 在赋值操作中,等号左边是变量名,右边是先求值。
my_love = "13766666666" # 第一次赋值my_ex = my_love # 将my_love的当前值赋给my_exmy_love = "15066666666" # 更新my_love的值
print("当前my_love的值: " + my_love) # 输出 15066666666print("当前my_ex的值: " + my_ex) # 输出 13766666666- 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新。
变量赋值操作
Section titled “变量赋值操作”- 变量:用于存储或替换值的。
- 变量名:
- 中间不能有空格。
- 不能以数字开头。
- 千万不要用引号包裹,否则就成了字符串。
- 例:
my_love = "13766666666" 赋值操作:给变量一个值的操作。- 通过变量名获取值,反复使用,无需每次都重新打一遍。
- Python 是从上到下执行的,必须要在前面先对变量进行赋值,然后才能用那个变量,否则会报错。
- 赋值后,就可以通过变量名获取那个值,反复使用,而不需要每次都重新打一遍。
- 如果对象换了号码,或者换了对象,那
my_love这个手机号也得跟着变,还是用赋值操作。
变量赋值操作 (续)一
Section titled “变量赋值操作 (续)一”- 可以用变量给变量赋值。
- 例:
my_ex = my_love - 赋值操作里,等号左边视为变量名,右边先求值。
- 示例:
my_love = "13766666666"my_ex = my_lovemy_love = "15066666666"print("当前my_love的值: " + my_love)print("当前my_ex的值: " + my_ex)print在有变量的情况下很有用。
变量赋值操作 (续)二:变量的更新和使用
Section titled “变量赋值操作 (续)二:变量的更新和使用”- 变量
greet赋值为"你好,吃了么" - 通过
print(greet + "张三")打印"你好,吃了么张三" - 更新
greet的值为"Yo what's up",所有用到greet的地方都会自动变成新的值 - 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新
变量赋值操作 (续)三:不同变量存储不同打招呼方式
Section titled “变量赋值操作 (续)三:不同变量存储不同打招呼方式”- 可以定义不同的变量来存储不同语言的打招呼方式。
- 示例:
greet_chinese = greetgreet_english = "Yo what's up"- 可以灵活切换打印不同语言的打招呼语。
- 例如,用
greet_chinese来打印中文打招呼语。
变量命名规则
Section titled “变量命名规则”- 变量名应易于理解和记忆。
- 只能由文字、数字、下划线组成。
- 不能有下划线之外的符号。
- 不能以数字开头。
- 变量名中间不能有空格。
- 避免使用
a、a1、abc等无意义名称,可能过几天就忘记用途。 - 如果违反硬性规则,Python会直接报错。
- 不报错不代表是好名字。
变量命名建议:不用拼音!
Section titled “变量命名建议:不用拼音!”- 拼音阅读速度慢,不如英文
username直观。 - 拼音不带声调易产生误解,如
gaoji可能指“高级”或“高集”。 - 平翘舌音不分者慎用拼音。
- Python 3.0后支持中文变量名,但主流仍用英文。
- 原因:控制台或日志等编码不兼容,可能显示乱码。
- 代码关键字和符号仍是英文,输入法切换麻烦。
- 搜索英文翻译不难。
Python 变量命名规范
Section titled “Python 变量命名规范”- 约定俗成使用下划线命名法:
- 字母全部小写
- 不同单词用下划线分隔开 (
user_age,user_gender) - 原本用空格的地方用下划线连接
- 其他风格:驼峰命名法 (
UserAge,UserGender) - Python 变量名一般使用下划线命名法
- 注意要点:
- 变量名大小写敏感 (
user_age和userAge是不同的变量) - 变量名不要占用 Python 的关键字 (
print等) - 关键字当前有30几个
Python 关键字
Section titled “Python 关键字”- PyCharm 会对 Python 关键字进行颜色高亮显示。
- 如果变量名是彩色的,说明是关键字,最好换成其他的。
Python 数据类型
Section titled “Python 数据类型”- Python 的整数和字符串是不同的类型。
- 整数:直接的数字,不要用引号包裹。
- 用引号包裹的数字是字符串
Python 数据类型 (续)
Section titled “Python 数据类型 (续)”- 浮点数:带小数点的数字。
- 例:
6.0 - 数学运算:
- 加减乘除:
+、-、*、/ - 乘号:
*(星号) - 除号:
/(正斜杠,shift键左边那个) - 示例:
1 + 2 - 3 / 4 * 5 - 运算顺序:先括号,然后乘方,然后乘除,最后加减
- 乘方符号:Python里是两个星号
Python 数学运算进阶:math 模块
Section titled “Python 数学运算进阶:math 模块”- 求2的三次方:
2 ** 3 - Python能做加减乘除、乘方,但更复杂的(三角函数、log、开方等)需导入
math模块。 - 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
print是函数,提供展示/输出功能。print是内置函数,Python 默认自带。math专门提供数学运算函数。- 导入&;
math&;模块:在文件开头写import math。 - 调用
math模块中的函数:math.函数名()
Python 数学运算进阶:math 模块 (续)导包及查看函数
Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”- 调用
math模块函数:math.函数名() - 计算sin 1弧度:
math.sin(1) - 计算以2为底8的对数:
math.log2(8) - 注意:单纯运算无输出,需使用
print
Python 数学运算进阶:math 模块 (续)
Section titled “Python 数学运算进阶:math 模块 (续)”- 若要展示数学计算结果,需使用
print或变量赋值。 - 示例:
import mathprint(math.log2(8))
result = math.log2(8)print(result)- 目标:编写一元二次方程求根公式计算器。
- 公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$
- 示例:计算 $-x^2 - 2x + 3 = 0$ 的实数根。
- a = -1, b = -2, c = 3
a = -1b = -2c = 3Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”- 平方根表示:
- 方法一:使用
**0.5,即 1/2 次方。 - 方法二:使用
math库中的sqrt()函数。 - 代码示例:
import math
a = -1 b = -2 c = 3
# 使用 math.sqrt() 函数 solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a) solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1) print(solution2)- 注意:数学公式中乘号可省略,但代码中不可省略。
- 一元二次方程求根公式计算器:完整代码实现及输出结果。
- 确保分子部分用括号
()括起来,再进行除法运算。 - 必须使用
print()函数才能在控制台看到计算结果。 - 示例代码:
import math
a = -1b = -2c = 3
# 第一个解:加号部分solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)print(solution2)- 运行结果:显示两个方程的解,例如
-3.0和1.0。
Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”- 只需更改变量
a、b、c的值,无需修改公式。 - 代码示例,计算 $x^2 + 9x + 20 = 0$ 的根:
import math
a = 1b = 9c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))- 结果展示正确。
- 用代码做数学计算的好处:
- 可以看到整个公式,方便检查,不易出错。
- 容易更改变量值,无需重复录入公式。
- 可通过中间变量分步骤,处理复杂公式。
- 例如,将 $b^2 - 4ac$ 赋值给
delta变量:
delta = b**2 - 4*a*c- 简化后续代码书写。
代码注释:给人看的解释
Section titled “代码注释:给人看的解释”- 用于解释代码思路,方便他人或自己理解。
- Python里,注释以
#开头,解释器会忽略该行。
代码注释 (续) 单行与多行注释
Section titled “代码注释 (续) 单行与多行注释”- 单行注释:以
#开头 - 多行注释:
- 方法一:每行开头加
# - 方法二:用三引号
"""或'''包裹
- 解释代码
- 临时禁用代码:在代码前加
#,跳过执行
PyCharm快捷键注释
Section titled “PyCharm快捷键注释”- 选中代码块,使用快捷键:
- Windows:
Ctrl + / - Mac:
Command + / - 再次使用快捷键取消注释
代码注释补充说明
Section titled “代码注释补充说明”- 多行注释可用三引号
"""或'''包裹,但跨行字符串也用三引号,注意区分。 - 建议不要在注释里过度放飞自我。
- 现实世界里食物、动物、人有不同种类,抽象世界里数字有不同种类,Python世界里数据也有不同种类。
Python 数据类型 (续)字符串 str
Section titled “Python 数据类型 (续)字符串 str”- 字符串类型
str:表示文本内容,由双引号或单引号包裹。 - 可用
len()函数获取字符串长度。 - 空格、数字、符号都占长度。
- 转义符(如
\n换行符)整体占一个长度。 - 提取字符串某位置的单个字符:字符串后跟方括号
[],内放索引。 - 索引可理解为顺序,但程序世界从
0开始计数。 - 提取字符串字符:
字符串[索引],索引从0开始。例如,"Hello"[3]返回"l"。索引为3表示第四个字符。 - 整数
int:如6、-32。 - 浮点数
float:如6.0、10.07。 - 布尔类型
bool:只有两个值:True和False。 True和False的首字母必须大写。- 空值类型
NoneType:只有一种值:None。 None不是 0,不是空字符串,也不是False。- 空值类型
NoneType:表示完全没有值 - 可先定义变量为
None None不是0,不是空字符串"",也不是False- 可用
type()函数返回对象类型 type("Hello")-><class 'str'>type(6)-><class 'int'>type(6.0)-><class 'float'>type(True)-><class 'bool'>type(None)-><class 'NoneType'>- 数据类型重要性:决定对象身上可用的函数
- 函数:负责执行某个功能
- 给函数合适的输入,它会给出正常的输出
- 例:做巧克力的机器,给可可粉才能产出巧克力
len()函数:得到字符串的长度- 用于整数身上会报错
- 除法:在整数和浮点数上用很合适,给字符串用会报错
Python 数据类型 (续)字符串 str (续)索引取值
Section titled “Python 数据类型 (续)字符串 str (续)索引取值”- 使用索引获取字符串中的单个字符:
字符串[索引] - 索引从
0开始 - 例如,
s = "Hello world!",s[0]的结果是"H" len(s):len()函数可获取字符串长度- 例如,
s = "Hello world!",len(s)的结果是12
字符串索引进阶
Section titled “字符串索引进阶”- 字符串总长度为12,索引从0开始,那么最后一个字符索引应该是11
- 获取字符串最后一个字符:
print(s[11]) - 也可以用
len()函数:print(s[len(s) - 1])
- 变量赋值:
b1 = Trueb2 = False- 注意:
True和False都需要大写开头,否则Python不识别
Python 数据类型 (续)类型使用错误示例
Section titled “Python 数据类型 (续)类型使用错误示例”- 浮点数
float:带小数点的数字,如1.5。 - 如果对布尔值
bool使用len()函数,Python 会报错。 - 了解操作对象的类型非常关键。
Python的两种执行模式
Section titled “Python的两种执行模式”- 命令行模式:
- 写好命令后,保存并运行整个文件。
- Python 解释器会逐行解析和执行文件。
Python的两种执行模式 (续) 交互模式
Section titled “Python的两种执行模式 (续) 交互模式”- 输入一行,立即执行并展示结果
- 无需创建新的
.py文件 - 进入交互式环境:
- PyCharm下方的Python控制台
- Windows的
cmd - Mac的终端输入
python3 - 显示三个尖括号
>>>,等待指令 - 输入Python命令,例如
print("hi"),回车直接执行 - 无需
print语句,直接显示执行结果
Python的两种执行模式 (续) 交互模式 (续)二
Section titled “Python的两种执行模式 (续) 交互模式 (续)二”- 查看变量当前值:输入变量名,回车
- 例如:
a = "你好!",输入a,回车,显示 `
变量赋值操作 (续)二
Section titled “变量赋值操作 (续)二”- 可以用变量给变量赋值。
- 例:
my_ex = my_love - 赋值操作里,等号左边视为变量名,右边先求值。
- 示例:
my_love = "13766666666"my_ex = my_lovemy_love = "15066666666"print("当前my_love的值: " + my_love)print("当前my_ex的值: " + my_ex)print在有变量的情况下很有用。
打印字符串的进阶玩法 (续) 变量赋值操作
Section titled “打印字符串的进阶玩法 (续) 变量赋值操作”- 如果对象换了号码,或者换了对象,那
my_love这个手机号也得跟着变,还是用赋值操作。
变量赋值操作 (续)一
Section titled “变量赋值操作 (续)一”- 可以用变量给变量赋值。
- 例:
my_ex = my_love - 赋值操作里,等号左边视为变量名,右边先求值。
- 示例:
my_love = "13766666666"my_ex = my_lovemy_love = "15066666666"print("当前my_love的值: " + my_love)print("当前my_ex的值: " + my_ex)print在有变量的情况下很有用。
变量赋值操作 (续)二:变量的更新和使用
Section titled “变量赋值操作 (续)二:变量的更新和使用”- 变量
greet赋值为"你好,吃了么" - 通过
print(greet + "张三")打印"你好,吃了么张三" - 更新
greet的值为"Yo what's up",所有用到greet的地方都会自动变成新的值 - 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新
变量赋值操作 (续)三:不同变量存储不同打招呼方式
Section titled “变量赋值操作 (续)三:不同变量存储不同打招呼方式”- 可以定义不同的变量来存储不同语言的打招呼方式。
- 示例:
greet_chinese = greetgreet_english = "Yo what's up"- 可以灵活切换打印不同语言的打招呼语。
- 例如,用
greet_chinese来打印中文打招呼语。
变量命名规则
Section titled “变量命名规则”- 变量名应易于理解和记忆。
- 只能由文字、数字、下划线组成。
- 不能有下划线之外的符号。
- 不能以数字开头。
- 变量名中间不能有空格。
- 避免使用
a、a1、abc等无意义名称,可能过几天就忘记用途。 - 如果违反硬性规则,Python会直接报错。
- 不报错不代表是好名字。
变量命名建议:不用拼音!
Section titled “变量命名建议:不用拼音!”- 拼音阅读速度慢,不如英文
username直观。 - 拼音不带声调易产生误解,如
gaoji可能指“高级”或“高集”。 - 平翘舌音不分者慎用拼音。
- Python 3.0后支持中文变量名,但主流仍用英文。
- 原因:控制台或日志等编码不兼容,可能显示乱码。
- 代码关键字和符号仍是英文,输入法切换麻烦。
- 搜索英文翻译不难。
Python 变量命名规范
Section titled “Python 变量命名规范”- 约定俗成使用下划线命名法:
- 字母全部小写
- 不同单词用下划线分隔开 (
user_age,user_gender) - 原本用空格的地方用下划线连接
- 其他风格:驼峰命名法 (
UserAge,UserGender) - Python 变量名一般使用下划线命名法
- 注意要点:
- 变量名大小写敏感 (
user_age和userAge是不同的变量) - 变量名不要占用 Python 的关键字 (
print等) - 关键字当前有30几个
Python 关键字
Section titled “Python 关键字”- PyCharm 会对 Python 关键字进行颜色高亮显示。
- 如果变量名是彩色的,说明是关键字,最好换成其他的。
Python 数据类型
Section titled “Python 数据类型”- Python 的整数和字符串是不同的类型。
- 整数:直接的数字,不要用引号包裹。
- 用引号包裹的数字是字符串
变量赋值操作 (续)三:变量的更新和使用
Section titled “变量赋值操作 (续)三:变量的更新和使用”- 变量
greet赋值为"你好,吃了么" - 通过
print(greet + "张三")打印"你好,吃了么张三" - 更新
greet的值为"Yo what's up",所有用到greet的地方都会自动变成新的值 - 使用变量的好处:只需更新变量的值,所有用到该变量的地方都会自动更新
变量赋值操作 (续)四:不同变量存储不同打招呼方式
Section titled “变量赋值操作 (续)四:不同变量存储不同打招呼方式”- 可以定义不同的变量来存储不同语言的打招呼方式。
- 示例:
greet_chinese = greetgreet_english = "Yo what's up"- 可以灵活切换打印不同语言的打招呼语。
- 例如,用
greet_chinese来打印中文打招呼语。
变量赋值操作 (续)四:不同变量存储不同打招呼方式
Section titled “变量赋值操作 (续)四:不同变量存储不同打招呼方式”- 可以定义不同的变量来存储不同语言的打招呼方式。
- 示例:
greet_chinese = greetgreet_english = "Yo what's up"- 可以灵活切换打印不同语言的打招呼语。
- 例如,用
greet_chinese来打印中文打招呼语。
变量命名建议:不要用拼音!(续)二
Section titled “变量命名建议:不要用拼音!(续)二”- 示例:
gaoji = "1",别人看不懂要干啥 - 拼音阅读速度慢,不如英文
username直观 - 拼音不带声调易产生误解,如
gaoji可能指“高级”或“高集” - 平翘舌音不分者慎用拼音
- Python 3.0后支持中文变量名,但主流仍用英文
- 原因:控制台或日志等编码不兼容,可能显示乱码
- 代码关键字和符号仍是英文,输入法切换麻烦
- 搜索英文翻译不难
变量命名约定
Section titled “变量命名约定”- 下划线命名法:
user_age,user_gender - 小写字母
- 空格用下划线连接
- 其他风格:驼峰命名法 (
UserAge,UserGender) - Python 变量名一般使用下划线命名法
- 变量名大小写敏感 (
user_age和userAge不同) - 变量名不要占用 Python 的关键字 (
print等) - 关键字当前有30几个
Python 变量命名规范
Section titled “Python 变量命名规范”- 约定俗成使用下划线命名法:
- 字母全部小写
- 不同单词用下划线分隔开 (
user_age,user_gender) - 原本用空格的地方用下划线连接
- 其他风格:驼峰命名法 (
UserAge,UserGender) - Python 变量名一般使用下划线命名法
- 注意要点:
- 变量名大小写敏感 (
user_age和userAge是不同的变量) - 变量名不要占用 Python 的关键字 (
print等) - 关键字当前有30几个
Python 变量命名规范 (续)下划线命名法:
Section titled “Python 变量命名规范 (续)下划线命名法:”- 字母全部小写
- 不同单词用下划线分隔开 (``user_age
,user_gender`) - 原本用空格的地方用下划线连接
- 其他风格:驼峰命名法 (``UserAge
,UserGender`) - Python 变量名一般使用下划线命名法
- 注意要点:
- 变量名大小写敏感 (``user_age
和userAge` 不同) - 变量名不要占用 Python 的关键字 (``print`等)
- 关键字当前有30几个
- PyCharm 会对 Python 关键字进行颜色高亮显示。
- 如果变量名是彩色的,说明是关键字,最好换成其他的。
Python 数据类型 (续)类型使用错误示例
Section titled “Python 数据类型 (续)类型使用错误示例”- 浮点数
float:带小数点的数字,如1.5。 - 如果对布尔值
bool使用len()函数,Python 会报错。 - 了解操作对象的类型非常关键。
Python 数据类型 (续)字符串 str
Section titled “Python 数据类型 (续)字符串 str”- 字符串类型
str:表示文本内容,由双引号或单引号包裹。 - 可用
len()函数获取字符串长度。 - 空格、数字、符号都占长度。
- 转义符(如
\n换行符)整体占一个长度。 - 提取字符串某位置的单个字符:字符串后跟方括号
[],内放索引。 - 索引可理解为顺序,但程序世界从
0开始计数。 - 提取字符串字符:
字符串[索引],索引从0开始。例如,"Hello"[3]返回"l"。索引为3表示第四个字符。 - 整数
int:如6、-32。 - 浮点数
float:如6.0、10.07。 - 布尔类型
bool:只有两个值:True和False。 True和False的首字母必须大写。- 空值类型
NoneType:只有一种值:None。 None不是 0,不是空字符串,也不是False。- 空值类型
NoneType:表示完全没有值 - 可先定义变量为
None None不是0,不是空字符串"",也不是False- 可用
type()函数返回对象类型 type("Hello")->type(6)->type(6.0)->type(True)->type(None)->- 数据类型重要性:决定对象身上可用的函数
- 函数:负责执行某个功能
- 给函数合适的输入,它会给出正常的输出
- 例:做巧克力的机器,给可可粉才能产出巧克力
len()函数:得到字符串的长度- 用于整数身上会报错
- 除法:在整数和浮点数上用很合适,给字符串用会报错
Python 数学运算
Section titled “Python 数学运算”- 数学运算符号:
- 加号:
+ - 减号:
- - 乘号:
*(星号) - 除号:
/(正斜杠,shift键左边那个) - 示例:
1 + 2 - 3 / 4 * 5 - 运算顺序:先括号,然后乘方,然后乘除,最后加减
Python 数据类型 (续)字符串 str (续)索引取值
Section titled “Python 数据类型 (续)字符串 str (续)索引取值”- 使用索引获取字符串中的单个字符:
字符串[索引] - 索引从
0开始 - 例如,
s = "Hello world!",s[0]的结果是"H" len(s):len()函数可获取字符串长度- 例如,
s = "Hello world!",len(s)的结果是12
Python 数学运算进阶:math 模块
Section titled “Python 数学运算进阶:math 模块”- 求2的三次方:
2 ** 3 - Python能做加减乘除、乘方,但更复杂的(三角函数、log、开方等)需导入
math模块。 - 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
print是函数,提供展示/输出功能。print是内置函数,Python 默认自带。math专门提供数学运算函数。- 导入&;
math&;模块:在文件开头写import math。 - 调用
math模块中的函数:math.函数名()
Python 数学运算进阶:math 模块
Section titled “Python 数学运算进阶:math 模块”- 函数库:可视为工具箱,每个函数是一个工具,负责一个功能。
print是内置函数,Python 默认自带。math专门提供数学运算函数。- 导入&;
math&;模块:在文件开头写import math。 - 调用
math模块中的函数:math.函数名()。
Python 数学运算进阶:math 模块 (续)导包及查看函数
Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”- 调用
math模块函数:math.函数名() - 计算sin 1弧度:
math.sin(1) - 计算以2为底8的对数:
math.log2(8) - 注意:单纯运算无输出,需使用
print
Python 数学运算进阶:math 模块 (续)
Section titled “Python 数学运算进阶:math 模块 (续)”- 若要展示数学计算结果,需使用
print或变量赋值。 - 示例:
import mathprint(math.log2(8))
result = math.log2(8)print(result)- 目标:编写一元二次方程求根公式计算器。
- 公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$
- 示例:计算 $-x^2 - 2x + 3 = 0$ 的实数根。
- a = -1, b = -2, c = 3
a = -1b = -2c = 3Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”- 平方根表示:
- 方法一:使用
**0.5,即 1/2 次方。 - 方法二:使用
math库中的sqrt()函数。 - 代码示例:
import math
a = -1 b = -2 c = 3
# 使用 math.sqrt() 函数 solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a) solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1) print(solution2)- 注意:数学公式中乘号可省略,但代码中不可省略。
- 一元二次方程求根公式计算器:完整代码实现及输出结果。
- 确保分子部分用括号
()括起来,再进行除法运算。 - 必须使用
print()函数才能在控制台看到计算结果。 - 示例代码:
import math
a = -1b = -2c = 3
# 第一个解:加号部分solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)print(solution2)- 运行结果:显示两个方程的解,例如
-3.0和1.0。
Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”- 只需更改变量
a、b、c的值,无需修改公式。 - 代码示例,计算 $x^2 + 9x + 20 = 0$ 的根:
import math
a = 1b = 9c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))- 结果展示正确。
- 用代码做数学计算的好处:
- 可以看到整个公式,方便检查,不易出错。
- 容易更改变量值,无需重复录入公式。
- 可通过中间变量分步骤,处理复杂公式。
- 例如,将 $b^2 - 4ac$ 赋值给
delta变量:
delta = b**2 - 4*a*c- 简化后续代码书写。
Python 数学运算进阶:math 模块 (续)导包及查看函数
Section titled “Python 数学运算进阶:math 模块 (续)导包及查看函数”- 调用
math模块函数:math.函数名() - 计算sin 1弧度:
math.sin(1) - 计算以2为底8的对数:
math.log2(8) - 注意:单纯运算无输出,需使用
print
Python 数学运算进阶:一元二次方程求根公式计算器
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器”- 目标:编写一元二次方程求根公式计算器
- 公式:\(x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}\)
- 示例:计算 \(-x^2 - 2x + 3 = 0\) 的实数根
- a = -1, b = -2, c = 3
a = -1b = -2c = 3Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”- 平方根表示:
- 方法一:使用
**0.5,即 1/2 次方。 - 方法二:使用
math库中的sqrt()函数。 - 代码示例:
import math
a = -1 b = -2 c = 3
# 使用 math.sqrt() 函数 solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a) solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1) print(solution2)- 注意:数学公式中乘号可省略,但代码中不可省略。
- 一元二次方程求根公式计算器:完整代码实现及输出结果。
- 确保分子部分用括号
()括起来,再进行除法运算。 - 必须使用
print()函数才能在控制台看到计算结果。 - 示例代码:
import math
a = -1b = -2c = 3
# 第一个解:加号部分solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)print(solution2)- 运行结果:显示两个方程的解,例如
-3.0和1.0。
Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”- 只需更改变量
a、b、c的值,无需修改公式。 - 代码示例,计算 的根:
import math
a = 1b = 9c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))- 结果展示正确。
- 用代码做数学计算的好处:
- 可以看到整个公式,方便检查,不易出错。
- 容易更改变量值,无需重复录入公式。
- 可通过中间变量分步骤,处理复杂公式。
- 例如,将 赋值给
delta变量:
delta = b**2 - 4*a*c- 简化后续代码书写。
Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”- 平方根表示:
- 方法一:使用
**0.5,即 1/2 次方。 - 方法二:使用
math库中的sqrt()函数。 - 代码示例:
import math
a = -1 b = -2 c = 3
# 使用 math.sqrt() 函数 solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a) solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1) print(solution2)- 注意:数学公式中乘号可省略,但代码中不可省略。
- 一元二次方程求根公式计算器:完整代码实现及输出结果。
- 确保分子部分用括号
()括起来,再进行除法运算。 - 必须使用
print()函数才能在控制台看到计算结果。 - 示例代码:
import math
a = -1b = -2c = 3
# 第一个解:加号部分solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)print(solution2)- 运行结果:显示两个方程的解,例如
-3.0和1.0.
Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 平方根的表示”- 平方根表示:
- 方法一:使用
**0.5,即 1/2 次方。 - 方法二:使用
math库中的sqrt()函数。 - 代码示例:
import math
a = -1 b = -2 c = 3
# 使用 math.sqrt() 函数 solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a) solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1) print(solution2)- 注意:数学公式中乘号可省略,但代码中不可省略。
- 一元二次方程求根公式计算器:完整代码实现及输出结果。
- 确保分子部分用括号
()括起来,再进行除法运算。 - 必须使用
print()函数才能在控制台看到计算结果。 - 示例代码:
import math
a = -1b = -2c = 3
# 第一个解:加号部分solution1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
# 第二个解:减号部分solution2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
print(solution1)print(solution2)- 运行结果:显示两个方程的解,例如
-3.0和1.0。 - 使用
math.sqrt(),需先import math - 调用:
math.sqrt()
Python 数学运算进阶:一元二次方程求根公式计算器 (续)代码实现(续)三
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续)代码实现(续)三”print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a)):第一种解:加号部分print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a)):第二种解:减号部分- 运行代码,显示两个方程的解,例如:
-3.0和1.0
Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结
Section titled “Python 数学运算进阶:一元二次方程求根公式计算器 (续) 优化及总结”- 只需更改变量
a、b、c的值,无需修改公式。 - 代码示例,计算 \(x^2 + 9x + 20 = 0\) 的根:
import math
a = 1b = 9c = 20
print((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))print((-b - math.sqrt(b**2 - 4*a*c)) / (2*a))- 结果展示正确。
- 用代码做数学计算的好处:
- 可以看到整个公式,方便检查,不易出错。
- 容易更改变量值,无需重复录入公式。
- 可通过中间变量分步骤,处理复杂公式。
- 例如,将 \(b^2 - 4ac\) 赋值给
delta变量:
delta = b**2 - 4*a*c- 简化后续代码书写。
代码注释:给人看的解释
Section titled “代码注释:给人看的解释”- 用于解释代码思路,方便他人或自己理解。
- Python里,注释以
#开头,解释器会忽略该行。
代码注释 (续) 单行与多行注释
Section titled “代码注释 (续) 单行与多行注释”- 单行注释:以
#开头 - 多行注释:
- 方法一:每行开头加
# - 方法二:用三引号
"""或'''包裹
- 解释代码
- 临时禁用代码:在代码前加
#,跳过执行
PyCharm快捷键注释
Section titled “PyCharm快捷键注释”- 选中代码块,使用快捷键:
- Windows:
Ctrl + / - Mac:
Command + / - 再次使用快捷键取消注释
代码注释补充说明
Section titled “代码注释补充说明”- 多行注释可用三引号
"""或'''包裹,但跨行字符串也用三引号,注意区分。 - 建议不要在注释里过度放飞自我。
- 现实世界里食物、动物、人有不同种类,抽象世界里数字有不同种类,Python世界里数据也有不同种类。
Python 数据类型 (续)字符串 str
Section titled “Python 数据类型 (续)字符串 str”- 字符串类型
str:表示文本内容,由双引号或单引号包裹。 - 可用
len()函数获取字符串长度。 - 空格、数字、符号都占长度。
- 转义符(如
\n换行符)整体占一个长度。 - 提取字符串某位置的单个字符:字符串后跟方括号
[],内放索引。 - 索引可理解为顺序,但程序世界从
0开始计数。 - 提取字符串字符:
字符串[索引],索引从0开始。例如,"Hello"[3]返回"l"。索引为3表示第四个字符。 - 整数
int:如6、-32。 - 浮点数
float:如6.0、10.07。 - 布尔类型
bool:只有两个值:True和False。 True和False的首字母必须大写。- 空值类型
NoneType:只有一种值:None。 None不是 0,不是空字符串,也不是False。- 空值类型
NoneType:表示完全没有值 - 可先定义变量为
None None不是0,不是空字符串"",也不是False- 可用
type()函数返回对象类型 type("Hello")->type(6)->type(6.0)->type(True)->type(None)->- 数据类型重要性:决定对象身上可用的函数
- 函数:负责执行某个功能
- 给函数合适的输入,它会给出正常的输出
- 例:做巧克力的机器,给可可粉才能产出巧克力
len()函数:得到字符串的长度- 用于整数身上会报错
- 除法:在整数和浮点数上用很合适,给字符串用会报错
Python 数据类型 (续)字符串 str (续)索引取值
Section titled “Python 数据类型 (续)字符串 str (续)索引取值”- 使用索引获取字符串中的单个字符:
字符串[索引] - 索引从
0开始 - 例如,
s = "Hello world!",s[0]的结果是"H" len(s):len()函数可获取字符串长度- 例如,
s = "Hello world!",len(s)的结果是12
字符串索引进阶
Section titled “字符串索引进阶”- 字符串总长度为12,索引从0开始,那么最后一个字符索引应该是11
- 获取字符串最后一个字符:
print(s[11]) - 也可以用
len()函数:print(s[len(s) - 1])
- 变量赋值:
b1 = Trueb2 = False- 注意:
True和False都需要大写开头,否则Python不识别
Python 数据类型 (续)类型使用错误示例
Section titled “Python 数据类型 (续)类型使用错误示例”- 浮点数
float:带小数点的数字,如1.5。 - 如果对布尔值
bool使用len()函数,Python 会报错。 - 了解操作对象的类型非常关键。
Python的两种执行模式
Section titled “Python的两种执行模式”- 命令行模式:
- 写好命令后,保存并运行整个文件。
- Python 解释器会逐行解析和执行文件。
Python的两种执行模式 (续) 交互模式
Section titled “Python的两种执行模式 (续) 交互模式”- 输入一行,立即执行并展示结果
- 无需创建新的
.py文件 - 进入交互式环境:
- PyCharm下方的Python控制台
- Windows的
cmd - Mac的终端输入
python3 - 显示三个尖括号
>>>,等待指令 - 输入Python命令,例如
print("hi"),回车直接执行 - 无需
print语句,直接显示执行结果
Python的两种执行模式 (续) 交互模式 (续)二
Section titled “Python的两种执行模式 (续) 交互模式 (续)二”- 查看变量当前值:输入变量名,回车
- 例如:
a = "你好!",输入a,回车,显示
变量赋值操作 (续)二
Section titled “变量赋值操作 (续)二”- 可以用变量给变量赋值。
- 例:
my_ex = my_love - 赋值操作里,等号左边视为变量名,右边先求值。
- 示例:
my_love = "13766666666"my_ex = my_lovemy_love = "15066666666"print("当前my_love的值: " + my_love)print("当前my_ex的值: " + my_ex)print在有变量的情况下很有用。
打印字符串的进阶玩法 (续) 变量赋值操作
Section titled “打印字符串的进阶玩法 (续) 变量赋值操作”- 如果对象换了号码,或者换了对象,那
my_love这个手机号也得跟着变,还是用赋值操作。
变量赋值操作 (续)一
Section titled “变量赋值操作 (续)一”- 可以用变量给变量赋值。
- 例:
my_ex = my_love - 赋值操作里,等号左边视为变量名,右边先求值。
- 示例:
my_love = "13766666666"my_ex = my_lovemy_love = "15066666666"print("当前my_love的值: " + my_love)print("当前my_ex的值: " + my_ex)print在有变量的情况下很有用。
变量赋值操作 (续)二:变量的更新和使用
Section titled “变量赋值操作 (续)二:变量的更新和使用”- 变量
greet赋值为"你好,吃了么" - 通过
print(greet + "张三")打印"你好,吃了么张三" - 更新
greet的值为 `“Yo what
Python 代码书写注意事项 (续)标点符号
Section titled “Python 代码书写注意事项 (续)标点符号”- 必须使用英文标点,而非中文标点
- 中文标点符号通常更宽
| 符号类型 | 中文 | 英文 |
| — | — | — |
| 括号 | () | () |
| 逗号 | , | , |
| 分号 | ; | ; |
| 方括号 | 【】 | [] |
- 使用单引号或双引号均可,但必须是英文
- 引号用于区分原文和其他部分,避免歧义
- 即使引号里的内容是数字,也会被识别为字符串,而不是数字
- 打开 PyCharm,找到之前创建的项目,双击打开即可开始编写代码
PyCharm:新建 Python 文件 (续)
Section titled “PyCharm:新建 Python 文件 (续)”- 建议:文件名尽量不要有空格,避免使用emoji等特殊符号
- 推荐命名方式:英文、数字、下划线
- PyCharm 弹出窗口询问是否添加到 git,初学阶段可选择“不再询问”。
- 编写打印语句:
print(),全部小写。 print()函数内,使用英文引号包裹要打印的内容。- 运行代码:右键点击,选择运行。
- 运行结果:在下方运行窗口显示。
PyCharm 运行代码结果
Section titled “PyCharm 运行代码结果”- PyCharm 运行代码后,第一行和最后一行可以忽略。
- 重点关注第一行和最后一行之间的内容。
- 双引号里的内容可以替换成任意想要的内容,比如中文的叫妈妈也行。
- 右键选择运行,点击后,
妈妈!!就打印出来了。 - 如果代码有问题,PyCharm 会自动用红色提醒,运行的时候也能看到红色的错误提示信息。
- 注意:代码中的符号必须是英文符号,比如括号。
Python代码书写问题解决办法
Section titled “Python代码书写问题解决办法”- 如果遇到错误,PyCharm会自动用红色提醒。
- 运行代码时,也能看到红色的错误提示信息。
- 可以把红色错误信息复制到搜索引擎里进行搜索。
- 错误可能是相似的。
- 很多开发者可能遇到过相同问题,可以借鉴解决方案。
代码注释:给人看的解释
Section titled “代码注释:给人看的解释”- Python里,注释以
#开头,解释器会忽略该行。
代码注释 (续) 单行与多行注释
Section titled “代码注释 (续) 单行与多行注释”- 单行注释:以
#开头 - 多行注释:
- 方法一:每行开头加
# - 方法二:用三引号
"""或'''包裹
代码注释作用
Section titled “代码注释作用”- 解释代码
- 临时禁用代码:在代码前加
#,跳过执行
PyCharm快捷键注释
Section titled “PyCharm快捷键注释”- 选中代码块,使用快捷键:
- Windows:
Ctrl + / - Mac:
Command + / - 再次使用快捷键取消注释
Python 数据类型 (续)字符串 str
Section titled “Python 数据类型 (续)字符串 str”- 字符串类型
str:表示文本内容,由双引号或单引号包裹。 - 可用
len()函数获取字符串长度。 - 空格、数字、符号都占长度。
- 转义符(如
\n换行符)整体占一个长度。 - 提取字符串某位置的单个字符:字符串后跟方括号
[],内放索引。 - 索引可理解为顺序,但程序世界从
0开始计数。 - 提取字符串字符:
字符串[索引],索引从0开始。例如,"Hello"[3]返回"l"。索引为3表示第四个字符。 - 整数
int:如6、-32。 - 浮点数
float:如6.0、10.07。 - 布尔类型
bool:只有两个值:True和False。 True和False的首字母必须大写。
PyCharm快捷键注释
Section titled “PyCharm快捷键注释”- 选中代码块,使用快捷键:
- Windows:
Ctrl + / - Mac:
Command + / - 再次使用快捷键取消注释
代码注释补充说明
Section titled “代码注释补充说明”- 多行注释可用三引号
"""或'''包裹,但跨行字符串也用三引号,注意区分。 - 建议不要在注释里过度放飞自我。
Python 代码书写问题解决办法
Section titled “Python 代码书写问题解决办法”- 如果遇到错误,PyCharm会自动用红色提醒。
- 运行代码时,也能看到红色的错误提示信息。
- 可以把红色错误信息复制到搜索引擎里进行搜索。
- 错误可能是相似的。
- 很多开发者可能遇到过相同问题,可以借鉴解决方案。
打印字符串的进阶玩法
Section titled “打印字符串的进阶玩法”- 字符串连接
- 单双引号转义
- 换行
- 三引号跨行字符串
- 字符串:用引号包裹住的一串内容。
打印字符串的进阶玩法 (续) 字符串连接
Section titled “打印字符串的进阶玩法 (续) 字符串连接”- 字符串:用引号包裹住的一串内容。
- 用加号连接字符串
print("Hello" + " world" + "!")- 输出:
Hello world! - 注意:
world前面有一个空格,所以打印出来中间才会有空格,否则两个词会黏在一起。
单双引号转义
Section titled “单双引号转义”- 字符串可以用单引号或双引号包裹,效果一样。
- 若内容本身包含引号,需注意内外引号的搭配。
- 例:
print("He said "good!"")会报错。 - Python 会将
He said识别为一个字符串,导致后续代码出错。
单双引号转义 (续)
Section titled “单双引号转义 (续)”- 若字符串内容本身包含引号,且内外引号类型相同,会引发错误。
- 示例:
print("He said "good!"")会报错,因为Python会把"He said "识别为一个字符串,导致后续代码出错。 - 转义字符:在字符串内部的引号前加上反斜杠 ` 来解决此问题。
- 反斜杠 ` 告诉Python,其后的引号应被视为字符串内容的一部分,而非字符串的结束符。
- 示例:
print("He said \"Let's go!\"")。Python会将\"识别为双引号,\'识别为单引号,作为字符串内容打印出来,而不是作为字符串的边界符。 - 实际输出将是:`He said “Let
Python 数据类型
Section titled “Python 数据类型”- Python的世界里,物种叫做数据类型。
- 包括:
- 字符串 (
str) - 整数 (
int) - 浮点数 (
float) - 布尔类型 (
bool) - 空值类型 (
NoneType)
字符串 str
Section titled “字符串 str”- 字符串类型 (
str):用引号(单引号或双引号)包裹的一串字符,表示文本内容。 - 使用
len()函数获取字符串长度。
数据类型总结
Section titled “数据类型总结”| 数据类型 | 示例 | 描述 |
|---|
| 字符串 (str) | `
Python 数据类型 (续)
Section titled “Python 数据类型 (续)”- 整数
int:如6、-32。 - 浮点数
float:如6.0、10.07。 - 布尔类型
bool:只有两个值:True和False。 True和False都需要大写开头,否则Python不识别- 空值类型
NoneType:只有一种值:None。 None不是0,不是空字符串"",也不是False- 可用
type()函数返回对象类型 type("Hello")-><class 'str'>type(6)-><class 'int'>type(6.0)-><class 'float'>type(True)-><class 'bool'>type(None)-><class 'NoneType'>
Python 数据类型 (续)NoneType
Section titled “Python 数据类型 (续)NoneType”- 空值类型
NoneType:表示完全没有值 - 可先定义变量为
None None不是0,不是空字符串"",也不是False- 可用
type()函数返回对象类型 type("Hello")-><class 'str'>type(6)-><class 'int'>type(6.0)-><class 'float'>type(True)-><class 'bool'>type(None)-><class 'NoneType'>- 数据类型重要性:决定对象身上可用的函数
- 函数:负责执行某个功能
- 给函数合适的输入,它会给出正常的输出
- 例:做巧克力的机器,给可可粉才能产出巧克力
- 你非要给它丢个石头进去,它就炸了
len()函数:得到字符串的长度- 用于整数身上会报错
- 除法:在整数和浮点数上用很合适,给字符串用会报错
len() 函数使用注意事项
Section titled “len() 函数使用注意事项”- 可获取字符串长度,如
len("Hello")返回5 - 对整数使用
len()会报错 - 除法在整数和浮点数上适用,但字符串会报错
- 需使用
print或变量赋值展示计算结果
Python 数据类型 (续)字符串 str (续)索引取值
Section titled “Python 数据类型 (续)字符串 str (续)索引取值”- 使用索引获取字符串中的单个字符:
字符串[索引] - 索引从
0开始 - 例如,
s = "Hello world!",s[0]的结果是"H" len(s):len()函数可获取字符串长度- 例如,
s = "Hello world!",len(s)的结果是12
字符串索引进阶
Section titled “字符串索引进阶”- 字符串总长度为12,索引从0开始,最后一个字符索引为11
- 获取字符串最后一个字符:
print(s[11]) - 也可以用
len()函数:print(s[len(s) - 1])
- 变量赋值:
b1 = Trueb2 = False- 注意:
True和False都需要大写开头,否则Python不识别
Python 数据类型 (续)类型使用错误示例
Section titled “Python 数据类型 (续)类型使用错误示例”- 浮点数
float:带小数点的数字,如1.5。 - 如果对布尔值
bool使用len()函数,Python 会报错。 - 了解操作对象的类型非常关键.
Python的两种执行模式
Section titled “Python的两种执行模式”- 命令行模式:
- 写好命令后,保存并运行整个文件。
- Python 解释器会逐行解析和执行文件。
- 交互模式:
- 输入一行,立即执行并展示结果。
- 无需创建新的
.py文件。
Python的两种执行模式 (续) 交互模式 (续)一
Section titled “Python的两种执行模式 (续) 交互模式 (续)一”- 查看变量当前值:输入变量名,回车
- 例如:
a = "你好!",输入a,回车,显示'你好!' - 在交互模式中,Python求值后会直接把返回结果展示出来
- 例如:输入
3 * 2,直接显示6 - 退出交互模式:
- 键入
quit(),回车 - 或者直接按
Ctrl + D - 交互模式的特点:
- 不需要创建任何
.py文件即可运行 - 不需要用
print就可以看到返回结果 - 所有输入的指令都不会被保存
- 一旦退出交互模式,就失去了之前键入的所有内容
- 交互模式像一个游乐场,让你随意玩一玩,看一看,用最简单的方式测试命令输出的结果。
- 交互模式不适合长期编码,适合快速测试和验证想法。
Python的两种执行模式 (续) 交互模式的用途
Section titled “Python的两种执行模式 (续) 交互模式的用途”- 适合快速测试和验证想法
- 也适合做一些一次性计算
- 输入算式,得到结果,然后退出关闭
- Python的
input()函数:从用户获取输入 - 用法:
input("这里是给用户的一些提示") - 标准的调用函数方式:函数名后跟括号,括号里放参数
Python的两种执行模式 (续) 交互模式的特点
Section titled “Python的两种执行模式 (续) 交互模式的特点”- 不需要创建任何
.py文件即可运行 - 不需要用
print就可以看到返回结果 - 所有输入的指令都不会被保存
- 一旦退出交互模式,就失去了之前键入的所有内容
- 交互模式像一个游乐场,让你随意玩一玩,看一看,用最简单的方式测试命令输出的结果。
- 交互模式不适合长期编码,适合快速测试和验证想法。
Python的两种执行模式 (续) 交互模式的用途
Section titled “Python的两种执行模式 (续) 交互模式的用途”- 适合快速测试和验证想法
- 也适合做一些一次性计算
- 输入算式,得到结果,然后退出关闭
- Python的
input()函数:从用户获取输入 - 用法:
input("这里是给用户的一些提示") - 标准的调用函数方式:函数名后跟括号,括号里放参数
input() 函数进阶用法
Section titled “input() 函数进阶用法”input("提示语"):从用户获取输入,提示语可选。- 运行后,会展示提示语,等待用户输入。
- 用户输入后,按下回车表示输入结束,程序继续运行。
- 注意:
input()始终返回字符串类型。 - 即使输入数字,也会被当成字符串处理。
- 若要进行数学运算,需先将字符串转换为整数类型.
- 使用变量获取
input()函数返回值:变量名 = input("提示语") - 例如:
user_age = input("请输入您的年龄:") - 之后可用该变量进行后续操作.
- 字符串转换为整数:
int("字符串") - 例如:
int("666")返回整数666。
input() 函数返回值类型转换
Section titled “input() 函数返回值类型转换”input()函数在用户输入后,会把内容进行返回。- 需用变量来获取
input()函数返回的值,例如:user_age = input("请输入您的年龄:") - 重要提示:
input()函数一律返回字符串类型。 - 即使你输入的是数字,它也会被当作字符串来看待。
- 如果直接拿
user_age(字符串类型)去做数学运算(例如user_age + 10),Python 会报错(类型错误)。 - 解决方案:Python 提供了函数能把字符串 (
str) 类型转换成整数 (int) 类型。 - 使用
int()函数进行转换。
Python 数据类型 (续)int
Section titled “Python 数据类型 (续)int”- 比如 ``int(“666”)`会返回整数666
input()返回值是字符串,若要进行数学运算,需用int()转换为整数- 注意:参数应能被转换为整数,否则报错
Python 数据类型 (续)float
Section titled “Python 数据类型 (续)float”float(): 用于转换user_height和user_weight- 代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))
Python 数据类型 (续)打印时数据类型转换
Section titled “Python 数据类型 (续)打印时数据类型转换”str(): 用于将数值型的user_BMI转换为字符串,以便与字符串拼接输出。- 整数不能直接和字符串连接打印,需先用
str()转换。 - 例:
print("知道了,你今年" + str(2) + "岁了!") - 示例代码:
print("您的BMI值为:" + str(user_BMI))
input() 函数返回值类型转换 (续)BMI计算示例
Section titled “input() 函数返回值类型转换 (续)BMI计算示例”- BMI计算公式:
user_BMI = user_weight / (user_height ** 2) - 完整代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))user_BMI = user_weight / (user_height ** 2)print(user_BMI)BMI结果格式化输出
Section titled “BMI结果格式化输出”- 目的:使输出结果更易读,保留两位小数。
- 方法:使用
f-string格式化字符串。 - 示例代码:
print(f"您的BMI是{user_BMI:.2f}") {user_BMI:.2f}:表示将user_BMI变量格式化为浮点数,并保留两位小数。
BMI分类标准
Section titled “BMI分类标准”| BMI | 范围 |
|---|---|
| 过轻 | 小于18.5 |
| 正常 | 18.5-24.9 |
| 超重 | 25-29.9 |
| 肥胖 | 大于等于30 |
if语句:根据条件执行不同代码
Section titled “if语句:根据条件执行不同代码”- 语法:
if 条件:
# 条件为真时执行的代码if...else语句:条件为真或假时执行不同代码
Section titled “if...else语句:条件为真或假时执行不同代码”- 语法:
if 条件:
# 条件为真时执行的代码else:
# 条件为假时执行的代码if...elif...else语句:多条件判断
Section titled “if...elif...else语句:多条件判断”- 语法:
if 条件1:
# 条件1为真时执行的代码elif 条件2:
# 条件2为真时执行的代码...else:
# 所有条件都为假时执行的代码BMI计算器:if...elif...else实现BMI分类
Section titled “BMI计算器:if...elif...else实现BMI分类”- 代码示例:
if user_BMI < 18.5: print("您的BMI过轻")elif 18.5 <= user_BMI < 25: print("您的BMI正常")elif 25 <= user_BMI < 30: print("您的BMI超重")else: print("您的BMI肥胖")>:大于<:小于>=:大于等于<=:小于等于==:等于(注意与赋值=区分)!=:不等于
and:与(且)- 所有条件都为
True,结果才为True or:或- 只要有一个条件为
True,结果就为True not:非(取反)not True的结果是False
input() 函数返回值类型转换
Section titled “input() 函数返回值类型转换”input()函数将用户输入的内容返回。- 需要用变量来获取返回值,例如:
user_age = input("请输入您的年龄:")。 - 重要提示:
input()函数一律返回字符串类型,即使输入的是数字。 - 如果直接用字符串类型的变量进行数学运算(例如
user_age + 10),Python 会报错(类型错误)。 - 解决方案:Python 提供了函数能把字符串 (
str) 类型转换成整数 (int) 类型。 - 使用
int()函数进行转换。
Python 数据类型转换
Section titled “Python 数据类型转换”int():将其他类型转换为整数。- 例:
int("666")返回整数666。 - 注意:参数应能被转换为整数,否则报错。
float():将其他类型转换为浮点数。str():将其他类型转换为字符串,常用于打印。- 例:
print("知道了,你今年" + str(2) + "岁了!") - 整数不能直接和字符串连接打印,需先用
str()转换。 input()返回值是字符串,若要进行数学运算,需先用int()或float()转换为数字类型。- 示例:
user_age = int(input("请输入您的年龄:"))user_age_after_10_year = user_age + 10print("您十年后会是" + str(user_age_after_10_year) + "岁")BMI计算器实践
Section titled “BMI计算器实践”- 目标:编写一个简单的身体质量指数 (BMI) 计算器。
- 计算公式:
BMI = 体重 / (身高 ** 2),其中体重单位为千克,身高单位为米。 - 步骤:
- 定义变量
user_weight获取用户输入的体重。 - 定义变量
user_height获取用户输入的身高。 - 使用
input()函数获取用户输入,并提供提示信息(如:“请输入您的体重(单位: kg):”)。 input()函数返回的是字符串,因此需要使用float()函数将其转换为浮点数,以便进行数学运算。
user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))
- 计算 BMI:
user_BMI = user_weight / (user_height ** 2)。 - 打印 BMI 结果:
print(user_BMI)。
Python 数据类型转换
Section titled “Python 数据类型转换”int():将其他类型转换为整数。- 例:
int("666")返回整数666。 - 注意:参数应能被转换为整数,否则报错。
float():将其他类型转换为浮点数。str():将其他类型转换为字符串,常用于打印。- 例:
print("知道了,你今年" + str(2) + "岁了!") - 整数不能直接和字符串连接打印,需先用
str()转换。 input()返回值是字符串,若要进行数学运算,需先用int()转换为整数。- 示例:
user_age = int(input("请输入您的年龄:"))user_age_after_10_year = user_age + 10print("您十年后会是" + str(user_age_after_10_year) + "岁")input() 函数返回值类型转换
Section titled “input() 函数返回值类型转换”user_weight = input("请输入您的体重(单位: kg):")user_height = input("请输入您的身高(单位: m):")- 问题:
user_weight和user_height都是字符串类型,不能直接用于数学计算。 - 解决方法:使用
float()函数将字符串转换为浮点数。 user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))- BMI计算公式:
user_BMI = user_weight / (user_height ** 2) - 完整代码示例:
user_weight = float(input("请输入您的体重(单位: kg):"))user_height = float(input("请输入您的身高(单位: m):"))user_BMI = user_weight / (user_height ** 2)print(user_BMI)if 语句:条件判断结构
Section titled “if 语句:条件判断结构”- 日常生活中的条件判断例子:
- 根据女朋友情绪判断今晚能否打游戏
- 根据老板脸色判断该不该提加工资
- 核心:判断条件是否满足,决定执行内容
- Python条件语句结构:
if [条件]: [执行内容]if:表示“如果”[条件]:求值结果为True或False的布尔值- 示例:
is_happy = True # 定义布尔变量if is_happy:
# 条件为True时执行- 结合比较运算符:
==:等于号,比较两个对象的值
if 语句 (续):条件判断结构
Section titled “if 语句 (续):条件判断结构”- 注意:
if [条件]后有冒号:,表示条件结束 [执行语句]前需要缩进,建议四个空格- 所有
if下方有缩进的语句,都会被看作条件为真时要执行的内容
比较运算符 (续)
Section titled “比较运算符 (续)”==:等于,比较两个对象的值是否相等- 例:``3 == 3
返回True,“a” == “b”` 返回 `False`` - 注意:比较运算符是两个等号
==,一个等号=是变量赋值 !=:不等于,比较两个对象的值是否不相等- 例:
"a" != "b"返回True >:大于>=:大于等于<:小于<=:小于等于- 含义和数学里比较符号相同
- 例:
5 >= 20可作为条件,值为False(布尔值)
if...else语句 (续):根据条件判断结构执行内容
Section titled “if...else语句 (续):根据条件判断结构执行内容”- 如果希望条件为假时执行语句,使用
else。 - 语法:
if [条件]:
# 条件为真时执行的语句else:
# 条件为假时执行的语句- Python 根据缩进判断语句归属。
- 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!
if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!mood_index < 60,打印为了自个儿小命,还是别打了。if和else下方的语句可以不止一行,只要注意缩进即可。
if...elif...else 语句:多重条件判断
Section titled “if...elif...else 语句:多重条件判断”- 适用于多个互斥条件的情况。
- 语法:
if 条件1:
# 条件1成立时执行的代码elif 条件2:
# 条件2成立时执行的代码else:
# 所有条件都不成立时执行的代码- Python 依据缩进判断语句归属。
- 示例:
mood_index = int(input("对象今天的心情指数是:"))if mood_index >= 90: print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")elif mood_index >= 60: print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")else: print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")- 注意缩进,
else不可独立于if存在。
if 语句进阶:嵌套条件语句
Section titled “if 语句进阶:嵌套条件语句”- 嵌套条件语句:在条件语句里面再放条件语句。
- 示例:
if [条件一]: if [条件二]: [语句A]- 语句A被执行的条件:
- 首先满足条件一为真。
- 其次还要满足条件二为真。
if [条件一]: if [条件二]: [语句A] else: [语句B]else下方的语句 B 被执行:- 必须首先满足条件一为真。
- 条件二为假。
- 缩进非常重要,Python 的缩进一般为四个空格。
if...elif...else 语句:多重条件判断 (续)二
Section titled “if...elif...else 语句:多重条件判断 (续)二”- Python 会依次判断各个条件,直到找到第一个为真的条件,执行里面的语句。
elif的数量没有上限或下限。- 这种结构相比嵌套更清晰易懂。
嵌套条件语句 (续):女友心情指数的例子
Section titled “嵌套条件语句 (续):女友心情指数的例子”- 定义变量
mood_index为 0 到 100 之间的整数,is_at_home为布尔值。 - 如果
mood_index小于 60,判断是否在家;如果mood_index大于等于 60,执行其他语句。
# mood_index 是0到100之间的整数
# is_at_home为布尔值if mood_index < 60: if is_at_home: print("放弃游戏,低调做人") else: print("自由!")- 如果对象心情指数小于60,且在家,则不能打游戏;否则,拥有自由。
- 多条件判断的关键是
elif,基本结构如下:
if [条件1]: [语句A]elif [条件2]: [语句B]elif [条件3]: [语句C]else: [语句D]- Python 从上往下执行,只会执行第一个满足条件的语句。
- 即使条件2和条件3都满足,也只会执行
elif 条件2下方的语句。 - 一旦进入某个分支,就不会再看同一层级的其他条件判断了。
- 结合多条件判断,丰富BMI计算器。
- 获取用户输入的体重和身高,转换为浮点数。
- 使用BMI计算公式:体重除以身高的平方。
- 打印计算结果。
- BMI划分标准:
- 偏瘦:计算结果小于等于18.5
- 正常:18.5 < BMI <= 25
- 偏胖:25 < BMI <= 30
- 肥胖:BMI > 30
BMI计算器:if...elif...else实现BMI分类 (续)二
Section titled “BMI计算器:if...elif...else实现BMI分类 (续)二”- BMI范围:
- 18.5 <
user_BMI<= 25 属于正常 - 25 <
user_BMI<= 30 属于偏胖 user_BMI> 30 属于肥胖- 代码实现:
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- Python里,数学表达式可以这样写:
18.5 < user_BMI <= 25 - 如果
user_BMI大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。 - 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用
else输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
- 可以尝试用嵌套条件增强计算器功能。
if语句进阶:嵌套条件语句(续)
Section titled “if语句进阶:嵌套条件语句(续)”- 例如,如果需要多个条件同时满足才能获得奖励(例如Switch),可使用嵌套
if语句。 - 如果使用嵌套,代码会变得不优雅。
多条件并列的情况
Section titled “多条件并列的情况”- 一个月内:
- 主动做家务次数超过10次
- 发红包次数超过1次
- 陪逛街次数超过4次
- 没有惹对象生气过
if red_envelope_count > 1: if shopping_count > 4: if has_been_angry == False: print("Switch!") else: print("Switch 随风散去...") else: print("Switch 随风散去...")else: print("Switch 随风散去...")Python 逻辑运算符
Section titled “Python 逻辑运算符”- Python 的逻辑运算符有三个:
and(与)、or(或)、not(非)。 and:所有条件为True时,结果才为True;只要有一个为False,结果就为False。- 示例:
x > 5 and x < 10 and x * 2 == 12 or:只要有一个条件为True,结果就为True;所有条件为False时,结果才为False。- 示例:
x > 5 or x < 10 or x * 2 == 12 not:取反。- 示例:
not x > 5表示 x 不大于 5。 and和or可以连接两个或以上的操作对象。
Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子
Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”not运算:将布尔值反转。- 如果原先操作对象是
True,返回False。 - 如果原先操作对象是
False,返回True。 and运算:类似于悲观的人,只要有一件事不开心,结果就不开心。or运算:类似于乐观的人,只要有一件事开心,结果就开心。- 逻辑运算符可以混用,但需注意运算优先级:
not>and>or。 - 可用括号改变运算顺序,与数学运算用法一致。
- 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry): print("摩擦摩擦,掌声等待Switch!")else: print("Switch 随风散去...")- 逻辑运算符比嵌套
if语句更直观和优雅。
Python 列表 (List)
Section titled “Python 列表 (List)”- 问题:如果有多个相关联的数据(例如10个购物商品),定义10个独立的变量 (
item1,item2…) 并分别赋值会非常麻烦。 - 解决方案:使用数据结构将相关数据整合在一起,Python 中的列表 (
list) 就能达到这个目的。
- 空列表:使用一对方括号
[]表示。 - 示例:
shopping_list = [] - 包含数据的列表:用方括号
[]包裹多个数据,数据之间用逗号,分隔。 - 示例:
shopping_list = ["键盘", "键帽"]
列表操作:添加元素
Section titled “列表操作:添加元素”- 若要向已定义的列表里添加新元素,可以使用列表的
append()方法。 - 示例:
shopping_list.append("显示器") - 方法和函数类似,都用于负责特定功能。
- 方法:一般在操作对象后加点,
对象.方法名() - 例如:
shopping_list.append("显示器") - 函数:
函数名(对象),里面放入操作对象 - 例如:
len(shopping_list) - 可变数据类型:列表 (
list) - 不可变数据类型:字符串 (
str)、整数 (int)、浮点数 (float)、布尔类型 (bool) - 字符串示例:
- 如果想把字符串转成大写,可以用
.upper()方法。它会返回一个把原字符串字母全部变成大写的新字符串,但是原先的字符串还是它本身。 - 需要把新的字符串再赋值给变量才行。
s = "Hello"print(s.upper())s = s.upper()print(s)- 列表是可变的,
append()方法会直接改变原列表。
Python 列表 (List) 的操作
Section titled “Python 列表 (List) 的操作”append()方法:向列表添加元素- 不需要对变量重新赋值,直接在原列表上生效
- 示例:
shopping_list.append("显示器") remove()方法:删除列表中的某个元素- 括号里放该元素的值
- 直接调用
remove()即可,在原列表上生效,不需要对变量重新赋值 - 示例:
shopping_list.remove("显示器") - 元素必须确实存在于列表中,否则会报错
- 随时打印列表:查看里面有哪些元素
Python 列表 (List) 的特点
Section titled “Python 列表 (List) 的特点”- 可以放不同类型的数据,使用起来很自由和灵活。
- 示例:
list1 = ["Hello", 66.6, True, None] - 列表和字符串一样,都可以通过
len()函数求长度 len()函数会返回列表里元素的数量- 可以通过索引获得某个位置的元素
- 列表的索引同样从0开始数
Python 列表 (List) (续) 列表操作:修改元素
Section titled “Python 列表 (List) (续) 列表操作:修改元素”- 可以利用索引赋值直接覆盖该位置原本的元素。
- 示例:
shopping_list = ["键盘", "显示器", "硬盘"] shopping_list[1] = "音响" # 索引为1的元素被更改 print(shopping_list)Python 列表 (List) (续) 列表操作:内置函数
Section titled “Python 列表 (List) (续) 列表操作:内置函数”max()函数:返回列表里的最大值。min()函数:返回列表里的最小值。sorted()函数:可以把排序好的新列表返回给你,同时不改变原先的列表。- 示例:
num_list = [1, 13, -7, 2, 96] print(max(num_list)) # 打印列表里的最大值 print(min(num_list)) # 打印列表里的最小值 print(sorted(num_list)) # 打印排序好的列表Python 列表 (List) (续) 列表操作:更多操作
Section titled “Python 列表 (List) (续) 列表操作:更多操作”shopping_list.append("音响"):添加元素到列表shopping_list.append("电竞椅"):继续添加元素print(shopping_list):打印列表内容print(len(shopping_list)):打印列表长度,结果为3- 索引:获取列表特定位置元素
print(shopping_list[0]):打印第一个元素,索引从0开始
Python 列表 (List) (续) 列表操作:索引赋值与元素修改
Section titled “Python 列表 (List) (续) 列表操作:索引赋值与元素修改”- 可以利用索引赋值直接覆盖该位置原本的元素。
- 示例:
shopping_list = ["键盘", "显示器", "硬盘"]shopping_list[1] = "硬盘" # 索引为1的元素被更改print(shopping_list)Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数
Section titled “Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数”max()函数:返回列表里的最大值。min()函数:返回列表里的最小值。sorted()函数:可以把排序好的新列表返回,不改变原先的列表。- 示例:
num_list = [1, 13, -7, 2, 96]print(max(num_list)) # 打印列表里的最大值print(min(num_list)) # 打印列表里的最小值print(sorted(num_list)) # 打印排序好的列表Python 列表 (List) 列表应用
Section titled “Python 列表 (List) 列表应用”- 定义价格列表:
price = [799, 1024, 200, 800]- 使用
max()函数获取列表最大值: max_price = max(price)- 使用
min()函数获取列表最小值: min_price = min(price)
Python 列表应用 (续) sorted()函数
Section titled “Python 列表应用 (续) sorted()函数”sorted(price):返回排序后的列表,不改变原列表price。- 使用
print()函数查看排序后的列表,例如:print(sorted_price),结果为[200, 799, 800, 1024],从小到大。
Python 字典 (Dictionary)
Section titled “Python 字典 (Dictionary)”- 目的:实现通讯录功能,通过人名查找电话号码。
- 变量的局限性:勉强实现,不灵活。
phone_number_of_xiaoming = "13700000000":为小明电话号码赋值。phone_number_of_xiaohua = "13700000001":为小华电话号码赋值。print(phone_number_of_xiaoming):打印小明电话号码。
Python 字典 (Dictionary) (续)
Section titled “Python 字典 (Dictionary) (续)”- 局限性:用列表存储联系人信息不方便通过名字查找电话号码。
- 字典 (dictionary):存储键值对 (key-value pairs) 的数据结构。
- 键 (key):用于查找值,如人名。
- 值 (value):键对应的信息,如电话号码。
- 类似于现实生活中的字典,通过字(键)查找释义(值)。
- 示例:
contacts = {},空的字典用一对花括号表示。 - 要在字典里面放入多个键值对,就用花括号把它们包住,示例:
contacts = {"小明":"13700000000", "小花":"13700000001"}
Python 字典 (Dictionary) (续)二 键的类型与元组tuple
Section titled “Python 字典 (Dictionary) (续)二 键的类型与元组tuple”- 键值对之间用冒号表示对应,键值对之间用逗号分隔。
- 获取键的值:
字典名[键] - 键的类型必须是不可变的:
- 字符串
str、整数int、浮点数float、布尔类型bool可以作为键。 - 列表
list属于可变数据类型,不能作为键。 - 元组
tuple: - 不可变但又很像列表的数据结构。
- 示例:
example_tuple = ("键盘", "键帽"),用圆括号。 - 元组里面可以放多个元素。
- 由于元组不可变,添加、删除元素等不能操作。
- 列表用方括号,元组用圆括号。
Python 字典 (Dictionary) (续) 键的类型与元组tuple
Section titled “Python 字典 (Dictionary) (续) 键的类型与元组tuple”- 元组作为键:由于元组是不可变的,所以可以作为字典的键。
- 示例:
contacts = {("张伟", 23): "15000000000"},这里("张伟", 23)就是一个元组键。 - 字典和列表一样,都属于可变数据类型,可以添加和删除键值对。
Python 字典 (Dictionary) (续) 添加与更新键值对
Section titled “Python 字典 (Dictionary) (续) 添加与更新键值对”- 添加新的键值对:
- 使用
字典名[新键] = 新值的语法。 - 示例:
contacts["美女A"] = "18600000000",会在字典中新增一个键值对。 - 更新已存在的键值对:
- 如果使用
字典名[已存在的键] = 新值的语法,会覆盖该键的原有值。 - 示例:如果
contacts中已有"美女A",再次执行contacts["美女A"] = "18600000000"会更新"美女A"对应的值。
Python 字典 (Dictionary) (续) 检查键是否存在
Section titled “Python 字典 (Dictionary) (续) 检查键是否存在”- 使用
in运算符检查键是否在字典中存在,返回一个布尔值。 - 语法:
键 in 字典名 - 示例:
print("小明" in contacts):如果存在则返回True。print("小明明" in contacts):如果不存在则返回False。
Python 字典 (Dictionary) (续) 删除键值对
Section titled “Python 字典 (Dictionary) (续) 删除键值对”- 使用
del关键字删除字典中的某个键值对。 - 语法:
del 字典名[要删除的键] - 示例:
del contacts["小明"],会从contacts字典中删除键"小明"及其对应的值。
Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典
Section titled “Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典”- 无法删除不存在的键,否则会报错
len(字典名):得到字典键值对的数量- 结合
input()、if判断,制作一个查询流行语含义的电子词典程序 - 步骤:
- 创建空字典:
slang_dict = {} - 预先放入内容:
slang_dict = {"觉醒年代": "..."} - 用逗号分隔键值对
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二”- 结合
input()、if判断,制作查询流行语含义的电子词典程序。 - 如果一行过长,可以换行,使每个词条更清晰。
- 步骤(续):
- 使用
字典名[新键] = 新值语法,添加新的键值对。 - 依次添加流行语和释义到字典中
- 现在字典里有十条内容了,可以用字典名,方括号,放入键的方式进行赋值
- 我们的查询功能是这样的,首先询问用户
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三”- 使用
input()函数提示用户输入要查询的流行语:query = input("请输入您想查询的流行语:") - 使用
in判断用户输入的词条是否在字典里:if query in slang_dict: - 如果词条在字典里,打印:
print("您查询的" + query + "含义如下") - 获取
query的释义:slang_dict[query](字典名[键]) - 如果
query不在字典中,提示:print("词条不存在")
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四”- 完整的电子词典程序代码示例:
slang_dict = { "YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火", "双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍", "元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在", "绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑", "社死": "想找个地缝钻进去", "伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻", "我看不懂,但我大受震撼": "台词", "躺赢": "形容赢得非常轻松", "集美": "姐妹", "yyds":"永远的神"}
query = input("请输入您想查询的流行语:")
if query in slang_dict: print("您查询的" + query + "含义如下:") print(slang_dict[query])else: print("词条不存在")- 运行代码,输入流行语,程序会输出对应的解释,如果输入的流行语不在字典中,程序会提示“词条不存在”。
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五”- 如果查询词条不存在,程序会打印“您查询的流行语暂未收录”。
- 程序最后会告知用户,当前词典收录了多少个词条。
- 完整代码:
slang_dict = { "YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火", "双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍", "元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在", "绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑", "社死": "想找个地缝钻进去", "伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻", "我看不懂,但我大受震撼": "台词", "躺赢": "形容赢得非常轻松", "集美": "姐妹", "yyds":"永远的神"}
query = input("请输入您想查询的流行语:")
if query in slang_dict: print("您查询的" + query + "含义如下:") print(slang_dict[query])else: print("您查询的流行语暂未收录")
print("当前本词典收录词条数为:" + str(len(slang_dict)) + "个。")len()函数:获取字典长度,即键值对数量。str()函数:将整数转换为字符串,以便拼接。- 运行结果:显示查询结果或提示未收录,并显示当前词典收录的词条数量。
Python循环语句:for循环
Section titled “Python循环语句:for循环”- 可用于列表、字典、字符串等数据结构的迭代。
- 对列表迭代:按顺序处理每个元素。
>:大于<:小于>=:大于等于<=:小于等于==:等于(注意与赋值=区分)- 比较两个对象的值是否相等
- 例:``3 == 3
返回True,“a” == “b”&;返回False` - 注意:比较运算符是两个等号
==,一个等号=是变量赋值 !=:不等于,比较两个对象的值是否不相等- 例:
"a" != "b"返回True - 含义和数学里比较符号相同
- 例:
5 >= 20可作为条件,值为False(布尔值)
and:与(且)- 所有条件都为
True,结果才为True or:或- 只要有一个条件为
True,结果就为True not:非(取反)not True的结果是False- 示例:
age = 25if age > 18 and age < 30: print("青年")
is_student = Falseif not is_student: print("不是学生")循环语句:for 循环基本结构
Section titled “循环语句:for 循环基本结构”- 语法:
for 变量名 in 可迭代对象:
# 对每个变量做一些事情for:关键字,后跟空格。变量名:自定义变量名,代表迭代对象中的每个元素。in:关键字,后跟迭代对象。- 针对每个元素的操作写在
for的下一行,缩进表示语句属于for循环内部。
示例:检查体温列表
Section titled “示例:检查体温列表”temperature_list = [36.4, 36.6, 36.2, 37.0, 36.8]for temperature in temperature_list: if temperature >= 38: print(temperature) print("完蛋了")temperature_list:已定义的包含体温的列表。temperature:变量名,依次赋值为列表中的每个元素。- 如果体温超过38度,打印体温并输出“完蛋了”。
for 循环应用:用字典实现体温筛查
Section titled “for 循环应用:用字典实现体温筛查”- 创建字典
temperature_dict,以工号为键,体温为值。 - 使用
temperature_dict.keys()返回所有键,temperature_dict.values()返回所有值,temperature_dict.items()返回所有键值对。 - 结合
for循环和items方法,打印发烧员工的工号。 for staff_id, temperature in temperature_dict.items():- 变量会被赋值为键和值组成的元组。
- 等价于:
for temperature_tuple in temperature_dict.items(): staff_id = temperature_tuple[0] temperature = temperature_tuple[1]staff_id:工号temperature:体温- 示例代码:
temperature_dict = {"111":36.4, "112":36.6, "113":36.2, "114":38.3, "115":38.1}for staff_id, temperature in temperature_dict.items(): if temperature >= 38: print(staff_id)- 运行结果:打印体温高于或等于38度的员工的工号。
range() 函数进阶用法及示例
Section titled “range() 函数进阶用法及示例”range(起始值, 结束值, 步长):生成数字序列- 起始值:序列起始数字(包含)
- 结束值:序列结束数字(不包含)
- 步长:每次跨越几个数字,默认为1
- 示例:
range(5, 10, 2)
for num in range(1, 10, 2): print(num)- 结果:打印1到9之间的所有奇数
for 循环应用:高斯求和问题
Section titled “for 循环应用:高斯求和问题”- 计算从1加到100的和
total = 0for i in range(1, 101): total = total + iprint(total)- 结果:打印出5050
for循环进阶:日落拍摄自动化程序改进
Section titled “for循环进阶:日落拍摄自动化程序改进”- 问题:仅用
if判断,程序只判断一次,无法捕捉完整日落过程。 - 方案:用
for循环重复执行if判断。
for i in range(100):
# measure_brightness函数返回当前测量的天空亮度 if measure_brightness() >= 500:
# 拍照 take_photo()for循环会执行100次判断,但计算机速度快,可能在日落结束前就完成了。
if...else语句 (续):根据条件判断结构执行内容
Section titled “if...else语句 (续):根据条件判断结构执行内容”- 如果希望条件为假时执行语句,使用
else。 - 语法:
if [条件]:
# 条件为真时执行的语句else:
# 条件为假时执行的语句- Python 根据缩进判断语句归属。
- 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!
if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!mood_index < 60,打印为了自个儿小命,还是别打了。if和else下方的语句可以不止一行,只要注意缩进即可。
if...else语句 (续):根据条件判断结构执行内容
Section titled “if...else语句 (续):根据条件判断结构执行内容”- 如果希望条件为假时执行语句,使用
else。 - 语法:
if [条件]:
# 条件为真时执行的语句else:
# 条件为假时执行的语句- Python 根据缩进判断语句归属。
- 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。- ``
if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!mood_index < 60,打印为了自个儿小命,还是别打了。if和else下方的语句可以不止一行,只要注意缩进即可。
if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!mood_index < 60,打印为了自个儿小命,还是别打了。if和else下方的语句可以不止一行,只要注意缩进即可。
if...else语句 (续):根据条件判断结构执行内容
Section titled “if...else语句 (续):根据条件判断结构执行内容”- 如果希望条件为假时执行语句,使用
else。 - 语法:
if [条件]: [条件为真时执行的语句]else: [条件为假时执行的语句]- Python 根据缩进判断语句归属。
- 示例:写一个判断今晚是否可以打游戏的程序。
mood_index = input("对象今天的心情指数是:")if...else语句 (续):补充说明
Section titled “if...else语句 (续):补充说明”mood_index = input("对象今天的心情指数是:")返回字符串,需要用int()转换为整数才能比较。mood_index = int(input("对象今天的心情指数是:"))else部分可以加上,冒号回车后注意缩进。mood_index >= 60,打印恭喜,今晚应该可以打游戏,去吧皮卡丘!
if...elif...else 语句:多重条件判断
Section titled “if...elif...else 语句:多重条件判断”- 适用于多个互斥条件的情况。
- 语法:
if 条件1: [条件1成立时执行的代码]elif 条件2: [条件2成立时执行的代码]else: [所有条件都不成立时执行的代码]- Python 依据缩进判断语句归属。
- 示例:
mood_index = int(input("对象今天的心情指数是:"))if mood_index >= 90: print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")elif mood_index >= 60: print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")else: print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")- 注意缩进,
else不可独立于if存在。
if 语句进阶:嵌套条件语句
Section titled “if 语句进阶:嵌套条件语句”- 嵌套条件语句:在条件语句里面再放条件语句。
- 示例:
if [条件一]: if [条件二]: [语句A]- 语句A被执行的条件:
- 首先满足条件一为真。
- 其次还要满足条件二为真。
if [条件一]: if [条件二]: [语句A] else: [语句B]else下方的语句 B 被执行:- 必须首先满足条件一为真。
- 条件二为假。
- 缩进非常重要,Python 的缩进一般为四个空格。
if...elif...else 语句:多重条件判断
Section titled “if...elif...else 语句:多重条件判断”- 适用于多个互斥条件的情况。
- 语法:
if 条件1:
# 条件1成立时执行的代码elif 条件2:
# 条件2成立时执行的代码else:
# 所有条件都不成立时执行的代码- Python 依据缩进判断语句归属。
- 示例:
mood_index = int(input("对象今天的心情指数是:"))if mood_index >= 90: print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")elif mood_index >= 60: print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")else: print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")- 注意缩进,
else不可独立于if存在。
if 语句进阶:嵌套条件语句
Section titled “if 语句进阶:嵌套条件语句”- 嵌套条件语句:在条件语句里面再放条件语句。
- 示例:
if [条件一]: if [条件二]: [语句A]- 语句A被执行的条件:
- 首先满足条件一为真。
- 其次还要满足条件二为真。
if [条件一]: if [条件二]: [语句A] else: [语句B]else下方的语句 B 被执行:- 必须首先满足条件一为真。
- 条件二为假。
- 缩进非常重要,Python 的缩进一般为四个空格。
BMI计算器:if...elif...else实现BMI分类 (续)二
Section titled “BMI计算器:if...elif...else实现BMI分类 (续)二”- BMI范围:
- 18.5 <
user_BMI<= 25 属于正常 - 25 <
user_BMI<= 30 属于偏胖 user_BMI> 30 属于肥胖- 代码实现:
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- Python里,数学表达式可以这样写:
18.5 < user_BMI <= 25 - 如果
user_BMI大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。 - 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用
else输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
- 可以尝试用嵌套条件增强计算器功能。
if语句进阶:嵌套条件语句(续)
Section titled “if语句进阶:嵌套条件语句(续)”- 例如,如果需要多个条件同时满足才能获得奖励(例如Switch),可使用嵌套
if语句。 - 如果使用嵌套,代码会变得不优雅。
多条件并列的情况
Section titled “多条件并列的情况”- 一个月内:
- 主动做家务次数超过10次
- 发红包次数超过1次
- 陪逛街次数超过4次
- 没有惹对象生气过
if red_envelope_count > 1: if shopping_count > 4: if has_been_angry == False: print("Switch!") else: print("Switch 随风散去...") else: print("Switch 随风散去...")else: print("Switch 随风散去...")Python 逻辑运算符
Section titled “Python 逻辑运算符”- Python 的逻辑运算符有三个:
and(与)、or(或)、not(非)。 and:所有条件为True时,结果才为True;只要有一个为False,结果就为False。- 示例:
x > 5 and x < 10 and x * 2 == 12 or:只要有一个条件为True,结果就为True;所有条件为False时,结果才为False。- 示例:
x > 5 or x < 10 or x * 2 == 12 not:取反。- 示例:
not x > 5表示 x 不大于 5。 and和or可以连接两个或以上的操作对象。
Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子
Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”not运算:将布尔值反转。- 如果原先操作对象是
True,返回False。 - 如果原先操作对象是
False,返回True。 and运算:类似于悲观的人,只要有一件事不开心,结果就不开心。or运算:类似于乐观的人,只要有一件事开心,结果就开心。- 逻辑运算符可以混用,但需注意运算优先级:
not>and>or。 - 可用括号改变运算顺序,与数学运算用法一致。
- 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry): print("摩擦摩擦,掌声等待Switch!")else: print("Switch 随风散去...")- 逻辑运算符比嵌套
if语句更直观和优雅。
Python 列表 (List)
Section titled “Python 列表 (List)”- 问题:如果有多个相关联的数据(例如10个购物商品),定义10个独立的变量 (
item1,item2…) 并分别赋值会非常麻烦。 - 解决方案:使用数据结构将相关数据整合在一起,Python 中的列表 (
list) 就能达到这个目的。
- 空列表:使用一对方括号
[]表示。 - 示例:
shopping_list = [] - 包含数据的列表:用方括号
[]包裹多个数据,数据之间用逗号,分隔。 - 示例:
shopping_list = ["键盘", "键帽"]
列表操作:添加元素
Section titled “列表操作:添加元素”- 若要向已定义的列表里添加新元素,可以使用列表的
append()方法。 - 示例:
shopping_list.append("显示器") - 方法和函数类似,都用于负责特定功能。
- 方法:一般在操作对象后加点,
对象.方法名() - 例如:
shopping_list.append("显示器") - 函数:
函数名(对象),里面放入操作对象 - 例如:
len(shopping_list) - 可变数据类型:列表 (
list) - 不可变数据类型:字符串 (
str)、整数 (int)、浮点数 (float)、布尔类型 (bool) - 字符串示例:
- 如果想把字符串转成大写,可以用
.upper()方法。它会返回一个把原字符串字母全部变成大写的新字符串,但是原先的字符串还是它本身。 - 需要把新的字符串再赋值给变量才行。
s = "Hello"print(s.upper())s = s.upper()print(s)- 列表是可变的,
append()方法会直接改变原列表。
Python 列表 (List) 的操作
Section titled “Python 列表 (List) 的操作”append()方法:向列表添加元素- 不需要对变量重新赋值,直接在原列表上生效
- 示例:
shopping_list.append("显示器") remove()方法:删除列表中的某个元素- 括号里放该元素的值
- 直接调用
remove()即可,在原列表上生效,不需要对变量重新赋值 - 示例:
shopping_list.remove("显示器") - 元素必须确实存在于列表中,否则会报错
- 随时打印列表:查看里面有哪些元素
Python 列表 (List) 的特点
Section titled “Python 列表 (List) 的特点”- 可以放不同类型的数据,使用起来很自由和灵活。
- 示例:
list1 = ["Hello", 66.6, True, None] - 列表和字符串一样,都可以通过
len()函数求长度 len()函数会返回列表里元素的数量- 可以通过索引获得某个位置的元素
- 列表的索引同样从0开始数
Python 列表 (List) (续) 列表操作:修改元素
Section titled “Python 列表 (List) (续) 列表操作:修改元素”- 可以利用索引赋值直接覆盖该位置原本的元素。
- 示例:
shopping_list = ["键盘", "显示器", "硬盘"] shopping_list[1] = "音响" # 索引为1的元素被更改 print(shopping_list)Python 列表 (List) (续) 列表操作:内置函数
Section titled “Python 列表 (List) (续) 列表操作:内置函数”max()函数:返回列表里的最大值。min()函数:返回列表里的最小值。sorted()函数:可以把排序好的新列表返回给你,同时不改变原先的列表。- 示例:
num_list = [1, 13, -7, 2, 96] print(max(num_list)) # 打印列表里的最大值 print(min(num_list)) # 打印列表里的最小值 print(sorted(num_list)) # 打印排序好的列表Python 列表 (List) (续) 列表操作:更多操作
Section titled “Python 列表 (List) (续) 列表操作:更多操作”shopping_list.append("音响"):添加元素到列表shopping_list.append("电竞椅"):继续添加元素print(shopping_list):打印列表内容print(len(shopping_list)):打印列表长度,结果为3- 索引:获取列表特定位置元素
print(shopping_list[0]):打印第一个元素,索引从0开始
Python 列表 (List) (续) 列表操作:索引赋值与元素修改
Section titled “Python 列表 (List) (续) 列表操作:索引赋值与元素修改”- 可以利用索引赋值直接覆盖该位置原本的元素。
- 示例:
shopping_list = ["键盘", "显示器", "硬盘"]shopping_list[1] = "硬盘" # 索引为1的元素被更改print(shopping_list)Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数
Section titled “Python 列表 (List) (续) 列表操作:max(),min()和sorted()函数”max()函数:返回列表里的最大值。min()函数:返回列表里的最小值。sorted()函数:可以把排序好的新列表返回,不改变原先的列表。- 示例:
num_list = [1, 13, -7, 2, 96]print(max(num_list)) # 打印列表里的最大值print(min(num_list)) # 打印列表里的最小值print(sorted(num_list)) # 打印排序好的列表Python 列表 (List) 列表应用
Section titled “Python 列表 (List) 列表应用”- 定义价格列表:
price = [799, 1024, 200, 800]- 使用
max()函数获取列表最大值: max_price = max(price)- 使用
min()函数获取列表最小值: min_price = min(price)
Python 列表应用 (续) sorted()函数
Section titled “Python 列表应用 (续) sorted()函数”sorted(price):返回排序后的列表,不改变原列表price。- 使用
print()函数查看排序后的列表,例如:print(sorted_price),结果为[200, 799, 800, 1024],从小到大。
Python 字典 (Dictionary)
Section titled “Python 字典 (Dictionary)”- 目的:实现通讯录功能,通过人名查找电话号码。
- 变量的局限性:勉强实现,不灵活。
phone_number_of_xiaoming = "13700000000":为小明电话号码赋值。phone_number_of_xiaohua = "13700000001":为小华电话号码赋值。print(phone_number_of_xiaoming):打印小明电话号码。
Python 字典 (Dictionary) (续)
Section titled “Python 字典 (Dictionary) (续)”- 局限性:用列表存储联系人信息不方便通过名字查找电话号码。
- 字典 (dictionary):存储键值对 (key-value pairs) 的数据结构。
- 键 (key):用于查找值,如人名。
- 值 (value):键对应的信息,如电话号码。
- 类似于现实生活中的字典,通过字(键)查找释义(值)。
- 示例:
contacts = {},空的字典用一对花括号表示。 - 要在字典里面放入多个键值对,就用花括号把它们包住,示例:
contacts = {"小明":"13700000000", "小花":"13700000001"}
Python 字典 (Dictionary) (续)二 键的类型与元组tuple
Section titled “Python 字典 (Dictionary) (续)二 键的类型与元组tuple”- 键值对之间用冒号表示对应,键值对之间用逗号分隔。
- 获取键的值:
字典名[键] - 键的类型必须是不可变的:
- 字符串
str、整数int、浮点数float、布尔类型bool可以作为键。 - 列表
list属于可变数据类型,不能作为键。 - 元组
tuple: - 不可变但又很像列表的数据结构。
- 示例:
example_tuple = ("键盘", "键帽"),用圆括号。 - 元组里面可以放多个元素。
- 由于元组不可变,添加、删除元素等不能操作。
- 列表用方括号,元组用圆括号。
Python 字典 (Dictionary) (续) 键的类型与元组tuple
Section titled “Python 字典 (Dictionary) (续) 键的类型与元组tuple”- 元组作为键:由于元组是不可变的,所以可以作为字典的键。
- 示例:
contacts = {("张伟", 23): "15000000000"},这里("张伟", 23)就是一个元组键。 - 字典和列表一样,都属于可变数据类型,可以添加和删除键值对。
Python 字典 (Dictionary) (续) 添加与更新键值对
Section titled “Python 字典 (Dictionary) (续) 添加与更新键值对”- 添加新的键值对:
- 使用
字典名[新键] = 新值的语法。 - 示例:
contacts["美女A"] = "18600000000",会在字典中新增一个键值对。 - 更新已存在的键值对:
- 如果使用
字典名[已存在的键] = 新值的语法,会覆盖该键的原有值。 - 示例:如果
contacts中已有"美女A",再次执行contacts["美女A"] = "18600000000"会更新"美女A"对应的值。
Python 字典 (Dictionary) (续) 检查键是否存在
Section titled “Python 字典 (Dictionary) (续) 检查键是否存在”- 使用
in运算符检查键是否在字典中存在,返回一个布尔值。 - 语法:
键 in 字典名 - 示例:
print("小明" in contacts):如果存在则返回True。print("小明明" in contacts):如果不存在则返回False。
Python 字典 (Dictionary) (续) 删除键值对
Section titled “Python 字典 (Dictionary) (续) 删除键值对”- 使用
del关键字删除字典中的某个键值对。 - 语法:
del 字典名[要删除的键] - 示例:
del contacts["小明"],会从contacts字典中删除键"小明"及其对应的值。
Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典
Section titled “Python 字典 (Dictionary) (续) len()函数及应用:制作电子词典”- 无法删除不存在的键,否则会报错
len(字典名):得到字典键值对的数量- 结合
input()、if判断,制作一个查询流行语含义的电子词典程序 - 步骤:
- 创建空字典:
slang_dict = {} - 预先放入内容:
slang_dict = {"觉醒年代": "..."} - 用逗号分隔键值对
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)二”- 结合
input()、if判断,制作查询流行语含义的电子词典程序。 - 如果一行过长,可以换行,使每个词条更清晰。
- 步骤(续):
- 使用
字典名[新键] = 新值语法,添加新的键值对。 - 依次添加流行语和释义到字典中
- 现在字典里有十条内容了,可以用字典名,方括号,放入键的方式进行赋值
- 我们的查询功能是这样的,首先询问用户
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)三”- 使用
input()函数提示用户输入要查询的流行语:query = input("请输入您想查询的流行语:") - 使用
in判断用户输入的词条是否在字典里:if query in slang_dict: - 如果词条在字典里,打印:
print("您查询的" + query + "含义如下") - 获取
query的释义:slang_dict[query](字典名[键]) - 如果
query不在字典中,提示:print("词条不存在")
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)四”- 完整的电子词典程序代码示例:
slang_dict = { "YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火", "双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍", "元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在", "绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑", "社死": "想找个地缝钻进去", "伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻", "我看不懂,但我大受震撼": "台词", "躺赢": "形容赢得非常轻松", "集美": "姐妹", "yyds":"永远的神"}
query = input("请输入您想查询的流行语:")
if query in slang_dict: print("您查询的" + query + "含义如下:") print(slang_dict[query])else: print("词条不存在")- 运行代码,输入流行语,程序会输出对应的解释,如果输入的流行语不在字典中,程序会提示“词条不存在”。
Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五
Section titled “Python 字典 (Dictionary) (续) 添加元素到字典中并创建电子词典程序 (续)五”- 如果查询词条不存在,程序会打印“您查询的流行语暂未收录”。
- 程序最后会告知用户,当前词典收录了多少个词条。
- 完整代码:
slang_dict = { "YYDS": "永远的神,用于表达对某个人或事物的极致赞美,2021年爆火", "双厨狂喜": "如果两件喜欢的东西出现在一起,喜悦翻倍", "元宇宙": "具有想象力及发展潜力,使尽力失方感到焦虑,现实存在", "绝绝子": "节目中一些粉丝用“绝绝子”为选手加油,多用于搞笑", "社死": "想找个地缝钻进去", "伤害性不高,侮辱性极强": "网络视频中,男女各界相互攻", "我看不懂,但我大受震撼": "台词", "躺赢": "形容赢得非常轻松", "集美": "姐妹", "yyds":"永远的神"}
query = input("请输入您想查询的流行语:")
if query in slang_dict: print("您查询的" + query + "含义如下:") print(slang_dict[query])else: print("您查询的流行语暂未收录")
print("当前本词典收录词条数为:" + str(len(slang_dict)) + "个。")len()函数:获取字典长度,即键值对数量。str()函数:将整数转换为字符串,以便拼接。- 运行结果:显示查询结果或提示未收录,并显示当前词典收录的词条数量。
Python循环语句:for循环
Section titled “Python循环语句:for循环”- 可用于列表、字典、字符串等数据结构的迭代。
- 对列表迭代:按顺序处理每个元素。
if...elif...else语句:多条件判断 (续)BMI计算器实现
Section titled “if...elif...else语句:多条件判断 (续)BMI计算器实现”- 代码示例:
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- 数学表达式:
18.5 < user_BMI <= 25 user_BMI大于25且小于等于30:输出“此BMI值属于偏胖范围”- 所有条件为假:BMI值大于30,用
else输出“此BMI值属于肥胖范围”。
>:大于<:小于>=:大于等于<=:小于等于==:等于(注意与赋值=区分)!=:不等于
if...elif...else语句 (续):多重条件判断
Section titled “if...elif...else语句 (续):多重条件判断”- 适用于多个互斥条件的情况。
- 语法:
if 条件1: [条件1成立时执行的代码]elif 条件2: [条件2成立时执行的代码]else: [所有条件都不成立时执行的代码]- Python 依据缩进判断语句归属。
- 示例:
mood_index = int(input("对象今天的心情指数是:"))if mood_index >= 90: print("(≧▽≦) 恭喜,今晚不但可以打游戏,还可以double date!")elif mood_index >= 60: print("(= ̄ω ̄=) 恭喜,今晚应该可以打游戏,去吧皮卡丘!")else: print("o(╥﹏╥)o 为了自个儿小命,还是别打了。")- 注意缩进,
else不可独立于if存在。
BMI计算器:if...elif...else实现BMI分类 (续)二
Section titled “BMI计算器:if...elif...else实现BMI分类 (续)二”- BMI范围:
- 18.5 < ``user_BMI` <= 25 属于正常
- 25 < ``user_BMI` <= 30 属于偏胖
- ``user_BMI` > 30 属于肥胖
- 代码实现:
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- Python里,数学表达式可以这样写:
18.5 < user_BMI <= 25 - 如果
user_BMI大于 25 且小于等于 30,输出“此BMI值属于偏胖范围”。 - 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用
else输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- 运行代码,输入体重和身高,程序输出正确的 BMI 分类。
- 可以尝试用嵌套条件增强计算器功能。
- 如果前面的所有条件都为假,则说明 BMI 值大于 30,直接用
else输出“此BMI值属于肥胖范围”。
if user_BMI < 18.5: print("此BMI值属于偏瘦范围")elif 18.5 < user_BMI <= 25: print("此BMI值属于正常范围")elif 25 < user_BMI <= 30: print("此BMI值属于偏胖范围")else: print("此BMI值属于肥胖范围")- 运行代码,输入体重
78kg,身高1.8m,程序会输出正确的 BMI 分类,例如 BMI 值为24.07,属于“正常范围”。 - 课后作业:尝试使用嵌套条件语句来丰富计算器功能,例如根据用户性别输出“先生您好”或“女士您好”。
嵌套条件语句 (续):女友心情指数的例子
Section titled “嵌套条件语句 (续):女友心情指数的例子”- 定义变量
mood_index为 0 到 100 之间的整数,is_at_home为布尔值。 - 如果
mood_index小于 60,判断是否在家;如果mood_index大于等于 60,执行其他语句。
# mood_index 是0到100之间的整数
# is_at_home为布尔值if mood_index < 60: if is_at_home: print("放弃游戏,低调做人") else: print("自由!")- 如果对象心情指数小于60,且在家,则不能打游戏;否则,拥有自由。
- 多条件判断的关键是
elif,基本结构如下:
if [条件1]: [语句A]elif [条件2]: [语句B]elif [条件3]: [语句C]else: [语句D]- Python 从上往下执行,只会执行第一个满足条件的语句。
- 即使条件2和条件3都满足,也只会执行
elif 条件2下方的语句。 - 一旦进入某个分支,就不会再看同一层级的其他条件判断了。
- 结合多条件判断,丰富BMI计算器。
- 获取用户输入的体重和身高,转换为浮点数。
- 使用BMI计算公式:体重除以身高的平方。
- 打印计算结果。
- BMI划分标准:
- 偏瘦:计算结果小于等于18.5
- 正常:18.5 < BMI <= 25
- 偏胖:25 < BMI <= 30
- 肥胖:BMI > 30
Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子
Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”not运算:将布尔值反转。- 如果原先操作对象是
True,返回False。 - 如果原先操作对象是
False,返回True。 and运算:类似于悲观的人,只要有一件事不开心,结果就不开心。or运算:类似于乐观的人,只要有一件事开心,结果就开心。- 逻辑运算符可以混用,但需注意运算优先级:
not>and>or。 - 可用括号改变运算顺序,与数学运算用法一致。
- 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry): print("摩擦摩擦,掌声等待Switch!")else: print("Switch 随风散去...")- 逻辑运算符比嵌套
if语句更直观和优雅。
Python 逻辑运算符 (续) 与、或、非的记忆技巧
Section titled “Python 逻辑运算符 (续) 与、或、非的记忆技巧”- and:所有条件为
True,结果才为True。类似于悲观的人,只有每件事都开心,结果才开心。 - or:只要有一个条件为
True,结果就为True。类似于乐观的人,只要有一件事开心,结果就开心。 - not:将布尔值反转。
Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子
Section titled “Python 逻辑运算符 (续)运算优先级和结合逻辑运算的例子”not运算:将布尔值反转。- 如果原先操作对象是
True,返回False。 - 如果原先操作对象是
False,返回True。 and运算:类似于悲观的人,只要有一件事不开心,结果就不开心。or运算:类似于乐观的人,只要有一件事开心,结果就开心。- 逻辑运算符可以混用,但需注意运算优先级:
not>and>or。 - 可用括号改变运算顺序,与数学运算用法一致。
- 结合逻辑运算的例子:
if (house_work_count > 10 and red_envelope_count > 1 and shopping_count > 4 and not has_been_angry): print("摩擦摩擦,掌声等待Switch!")else: print("Switch 随风散去...")- 逻辑运算符比嵌套
if语句更直观和优雅。