跳到主要内容
Python 简单 AI 应用开发指南 | 极客日志
Python AI 大前端 算法
Python 简单 AI 应用开发指南 综述由AI生成 人工智能及大模型的基础概念,对比了本地部署与 API 调用的优缺点。详细讲解了 Ollama 本地部署流程、HTTP 协议基础及 Apifox 接口测试方法。重点演示了如何使用 Python 的 Streamlit 库构建交互式 Web 应用,实现 AI 智能伴侣功能,包括会话记忆、流式输出、侧边栏配置及历史会话保存加载等完整代码示例。
女王 发布于 2026/3/29 更新于 2026/5/29 29 浏览1 基础
AI:人工智能(Artificial Intelligence) ,是一个学科领域的统称,目标就是使机器能够像人类一样思考、学习、推理和解决问题。
AI 大模型 :也称为大语言模型(Large Language Models, LLM),是 AI 技术的一个分支。其实就是一个用代码模拟人脑神经网络的程序(参数量极其庞大,通常达到数十亿至数千亿级别),通过大量的数据训练后,使其具备理解人类语言、思考、推理并输出人类语言的能力。
AI 应用 :是指将 AI 大模型技术落地到具体的业务场景中,用来解决实际问题的产品或者服务。
1.1 大模型部署
本地部署
优点:数据安全、自主可控、长期成本低
缺点:初始成本高、需长期维护、性能受限
官方开放 API
优点:前期成本低、无需部署和维护、随时访问
缺点:隐私不能保障、长期成本高、可控性差
云服务平台
优点:前期成本低、无需部署和维护、选择度高
缺点:安全及隐私不能保障、长期成本高
API:应用程序编程接口 (Application Programming Interface),是软件间的标准化的'桥梁',允许开发者无需知晓内部细节即可调用外部功能或数据。
1.1.1 本地部署
Ollama 是一个在本地运行、管理大语言模型的工具。官网:https://ollama.com/
下载后双击即可安装,默认 Ollama 是安装在 C 盘中的,具体的安装位置如下:
默认安装后的目录:C:\Users\用户名\AppData\Local\Programs\Ollama
默认安装的模型目录:C:\Users\用户名.ollama
默认的配置文件目录:C:\Users\用户名\AppData\Local\Ollama
自定义安装:
在 OllamaSetup.exe 所在目录打开 cmd 命令行,然后命令:OllamaSetup.exe /DIR=你要安装的目录位置
运行模型
选择自己合适的模型后,点击对应的链接,ollama 会给出运行模型的命令:
[图片:运行模型命令示例]
查找模型
ollama 是一个模型管理工具和平台,它提供了很多国内外常见的模型,我们可以在其官网上搜索自己需要的模型:**https://ollama.com/search**。如图,我们可以直接在搜索栏搜索 deepseek,目前热度排第一的就是 deepseek-r1,点击进入 deepseek-r1 页面,会发现 deepseek-r1 也有很多版本:1.5b,7b,8b,14b,32b,70b,671b。这些就是模型的参数大小,越大推理能力就越强,需要的算力也越高。671b 版本就是最强的满血版 deepseek-r1 了。需要注意的是,Ollama 提供的 DeepSeek 是量化压缩版本,对比官网的蒸馏版会更小,对显卡要求更低。对比如下 :
[图片:DeepSeek 版本对比]
配置环境变量:OLLAMA_MODELS=你想要保存下载的模型的目录
[图片:环境变量配置]
注意:首次运行命令需要下载模型,根据模型大小不同下载时长在 5 分钟~1 小时不等,请耐心等待下载完成。ollama 控制台是一个封装好的 AI 对话产品,与 ChatGPT、DeepSeek 官方提供的对话产品类似,具备会话记忆功能。
Ollama 是一个模型管理工具,所有的命令如下:
ollama serve # 启动 Ollama
ollama create # 创建模型
ollama show # 查看模型的详细信息
ollama run # 运行一个模型
ollama stop # 停止正在运行的模型
ollama pull # 推送一个模型到远端
ollama push # 拉取 (下载) 一个模型
ollama list # 列出所有的模型
ollama ps # 列出正在运行的模型
ollama cp # 拷贝模型
ollama rm # 删除模型
ollama help # 查看帮助文档
1.1.2 官方开放 API 主流的大模型(如:DeepSeek、Kimi 等)官方都提供了开放 API,无需部署,就可以直接调用访问。
注册账号
登录 DeepSeek
充值
创建 API Key
1.2 大模型调用
1.2.1 网络基础知识
IP 地址 可以理解为就是设备在互联网中的地址 (唯一身份证),每一个连入网络的设备都有一个自己的 IP 地址,用来定位设备在互联网中的位置。IPv4 地址:32 位二进制,IPv6 地址:128 位二进制
域名 (Domain Name) ,是由一串用点分隔的英文字母组成的。IP 地址不便于记忆,因此设计出了域名,并通过 DNS(域名解析服务器)来将域名和 IP 地址相互映射,便于记忆和访问。
HTTP 协议 概念:Hyper Text Transfer Protocol,超文本传输协议,规定了客户端和服务器之间数据传输的规则。(只有在请求及响应中都遵循了统一的规则,服务端才能读懂客户端发送来的请求,客户端才能解析服务端响应的结果)
特点:
基于文本的协议:请求和响应的部分的协议内容为文本格式,底层通过 TCP 协议传输, 稳定性强。
基于请求 - 响应模型:一次请求对应一次响应,必须由客户端先发起请求,服务端才会返回响应。
无状态:服务端不会记忆与客户端的历史交互信息,每次请求 - 响应都是独立的 。
请求方式:
GET: 请求参数在请求行中,没有请求体。如:/api/courses?name=Python&status=1。GET 请求请求参数大小在浏览器中是有限制的。
POST: 请求参数在请求体中,POST 请求大小是没有限制的。
OSI 网络模型 :全球网络互连标准模型,TCP/IP 网络模型 :可以认为是 OSI 的简化版
端口号 (Port) 是整数,取值范围在 0-65535,它是用来标识计算机设备中的运行中的程序。
1.2.2 Apifox 测试
Apifox 是一款 API 设计、开发、测试的一体化协作平台,是项目开发中进行 API 接口测试的神器。
与 AI 大模型的交互本质是无状态的,每一次请求响应都是相互独立的。(AI 大模型本身没有真正的会话记忆能力)
JSON(JavaScript Object Notation) 是前端的一种对象表示方法。表示形式类似于 Python 中的字典,都是 key:value 这种形式,不过所有的 key 都必须使用双引号引起来,值可以是任何类型:
对象:用{}表示,{}之间是键值对形式,键是字符串,值可以是任意其它类型
数字:整数和小数都是数字,例如:12、3.14
字符串:用""引起来,例如:'jack'
布尔:有两种值:true 或 false
列表:用 [] 表示,[] 中是列表的元素,多个元素以,分割。
1.2.3 代码调用测试
如何安装第三方的软件包?
安装软件包(最新版本):pip install openai
安装软件包(指定版本):pip install openai=2.13.0
卸载软件包:pip uninstall openai
列出已安装的包:pip list
查看包详情:pip show openai
将 DEEPSEEK_API_KEY 的值配置到环境变量中(配置完成后将 pycharm 重启才能使用这个值)
PyPI:全程为 Python Package Index,是由 Python 官方和社区共同维护的 Python 第三方软件包的官方仓库。
pip:pip 是 Python 官方提供的 Python 包的管理工具,提供了对 Python 包的查找、下载、安装、卸载等功能。
1.3 提示词工程
提示词 (Prompt) :是引导大模型 (LLM) 进行内容生成的命令(一句话、一个问题等),一个好的提示词需要引导 AI 思考,约束其输出范围,并明确你期望的结果
提示词工程 (Prompt Engineering) :通过有技巧的编写提示词,使大模型生成出尽可能符合预期的内容,这一持续性的过程就称为提示词工程。
角色
给大模型设定角色与能力,eg:你是一名经验丰富的高中历史老师,擅长生动有趣的讲解复杂历史事件
任务
明确核心请求与任务,eg:请向一位高中生解释法国大革命爆发的主要原因
按步骤拆解复杂任务,eg:请先概述背景,然后分政治、经济、思想三个方面阐述,每点配一个例子
要求
指定风格与语气,eg:请使用简洁、口语化、充满热情的语气 (避免使用过于学术的术语)
明确要求输出格式,eg:请严格按照如下结构输出:…
提供输入输出的示例,eg:可以参考《人类群星闪耀时》的叙事风格。请不要列出冗长的日期列表
2 AI 应用
2.1 Streamlit
Streamlit 是一个开源的 Python 库,专为数据工程师及机器学习工程师设计,用来快速基于 Python 代码构建交互式的 web 网站 (无需掌握前端技术)。官方网站:https://streamlit.io
入门使用:
安装 streamlit:pip install streamlit
在 python 文件中引入 streamlit 模块
基于 streamlit 中提供的 API 来构建 Web 应用
运行程序:streamlit run xxxx.py
2.2 AI 智能伴侣 - 基本交互 准备工作:在 pycharm 中安装 lingma 插件,安装完成后重启 IDE
import streamlit as st
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ.get('DEEPSEEK_API_KEY' ), base_url="https://api.deepseek.com" )
system_prompt = "你是一名可爱的 AI 助手,你的名字叫小甜甜"
st.set_page_config(
page_title="AI 智能伴侣" ,
page_icon="🤖" ,
layout="wide" ,
initial_sidebar_state="expanded" ,
menu_items={}
)
st.title("AI 智能伴侣" )
st.logo("./resources/logo.png" )
prompt = st.chat_input("请输入您的问题" )
if prompt:
st.chat_message("user" ).write(prompt)
print ("-------->调用 AI 大模型,提示词:" , prompt)
response = client.chat.completions.create(
model="deepseek-chat" ,
messages=[{"role" :"system" ,"content" : system_prompt},{"role" :"user" ,"content" : prompt}],
stream=False
)
st.chat_message("assistant" ).write(response.choices[0 ].message.content)
print ("<--------AI 大模型返回结果:" , response.choices[0 ].message.content)
界面消息展示
问题:运行界面基本布局代码会发现每次问题都会覆盖上次的问题以及回复,如何显示所有的记录
回答:使用 st.session_state 将历史信息存入
if "messages" not in st.session_state:
st.session_state.messages = []
for message in st.session_state.messages:
st.chat_message(message["role" ]).write(message["content" ])
st.session_state.messages.append({"role" :"user" ,"content" : prompt})
st.session_state.messages.append({"role" :"assistant" ,"content" : response.choices[0 ].message.content})
2.3 AI 智能伴侣 - 会话记忆
会话记忆问题
可以用之前提到的会话历史滚雪球:*st.session_state.messages
流式输出
修改回复代码
通过 Apifox 调试,分析响应信息
response_messages = st.empty()
full_response = ""
for chunk in response:
if chunk.choices[0 ].delta.content is not None :
full_response += chunk.choices[0 ].delta.content
response_messages.chat_message("assistant" ).write(full_response)
st.session_state.messages.append({"role" :"assistant" ,"content" : full_response})
print ("<--------AI 大模型返回结果:" , full_response)
2.4 AI 智能伴侣 - 侧边栏功能 ...
system_prompt = """
你叫%s,现在是用户的真实伴侣,请完全代入伴侣角色。
规则:
1. 每次只回 1 条消息
2. 禁止任何场景或状态描述性文字
3. 匹配用户的语言
4. 回复简短,像微信聊天一样
5. 有需要的话可以用❤️🌸等 emoji 表情
6. 用符合伴侣性格的方式对话
7. 回复的内容,要充分体现伴侣的性格特征
伴侣性格:
- %s
你必须严格遵守上述规则来回复用户。
"""
...
if "nick_name" not in st.session_state:
st.session_state.nick_name = "小甜甜"
if "character" not in st.session_state:
st.session_state.character = "一个豪爽的东北姑娘"
with st.sidebar:
st.sidebar.subheader("伴侣信息" )
nick_name = st.text_input("昵称" , value="小甜甜" , placeholder="请输入昵称" )
if nick_name:
st.session_state.nick_name = nick_name
character = st.text_area("性格" , value="一个豪爽的东北姑娘" , placeholder="请输入昵称" )
if character:
st.session_state.character = character
...
messages=[{"role" :"system" ,"content" : system_prompt %(st.session_state.nick_name, st.session_state.character)}, *st.session_state.messages,],
...
2.5 文件操作
文件的操作(读/写)
打开:open() 函数
读/写:read() 方法、write() 方法
关闭:close() 方法
编码:是将字符 (文字、数字、符号) 转换为计算机能够存储和处理的数字代码的规则系统,如:ASCII、GBK、UTF-8。
注意:如果操作完文件,并未调用 close 方法关闭文件,同时程序没有停止运行,那么这个文件将一直被 Python 程序占用,无法操作。
问题:如果操作文件过程中出现了异常,文件就无法关闭了,怎么解决?
提示:with 语句 (上下文管理器) 的核心作用就是确保资源的总是被正确获取和释放(即使发生异常,也会被正确释放),也是项目开发中的推荐方式。
读取 json 格式
JSON 是软件开发中最常用的数据交换格式,而为了简化 JSON 数据的处理,在 Python 标准库中就提供了处理 JSON 数据的核心模块 json。
dump():将 python 对象序列化为 json 格式字符串并写入文件
load():从文件中读取 json 格式数据,并将其反序列化为 python 对象
ensure_ascii:默认值为 True,确保所有数据输出都是 ascii 编码(非 ASCII 码会进行转义);值为 False 非 ascii 码保留原样输出
路径写法:
相对路径:从当前文件所在目录开始查找
.:当前目录,如./resource/test.txt(./可以省略)
…:上一级目录,如…/第二章/file/test.txt
绝对路径:从文件系统根目录开始查找,文件位置的完整路径(注意:\ 在字符串中标识转义字符,\n \t)
方式一:D://project//python_project//py_p1//resources//静夜思.txt
方式二:D:/project/python_project/py_p1/resources\静夜思.txt
indent:会在输出的 json 数据中添加缩进(格式化)
2.6 保存当前会话
def generate_session_name ():
return datetime.now().strftime("%Y-%m-%d_%H-%M-%S" )
def save_session ():
if st.session_state.current_session:
session_data = {
"nick_name" : st.session_state.nick_name,
"nature" : st.session_state.nature,
"current_session" : st.session_state.current_session,
"messages" : st.session_state.messages
}
if not os.path.exists("sessions" ):
os.mkdir("sessions" )
with open (f"sessions/{st.session_state.current_session} .json" , "w" , encoding="utf-8" ) as f:
json.dump(session_data, f, ensure_ascii=False , indent=2 )
2.7 新建会话
if "current_session" not in st.session_state:
st.session_state.current_session = generate_session_name()
......
if st.button("新建会话" , width="stretch" , icon="✏️" ):
save_session()
if st.session_state.messages:
st.session_state.messages = []
st.session_state.current_session = generate_session_name()
save_session()
st.rerun()
2.8 展示历史会话
def load_session_list ():
session_list = []
if os.path.exists("./session" ):
for file in os.listdir("./session" ):
if file.endswith(".json" ):
session_list.append(file[:-5 ])
return session_list
......
st.text("历史会话" )
for session in load_session_list():
col1, col2 = st.columns([4 , 1 ])
with col1:
if st.button(session, key=f"load_{session} " , icon="📝" , width="stretch" ):
pass
with col2:
if st.button("" , key=f"delete_{session} " , icon="🗑️" , width="stretch" ):
pass
st.button 如果是空的,需要指定唯一 key,否则会报错
st.columns 将一行分为若干列
2.9 加载指定历史会话
三元运算符:语法:<true_value> if 条件表达式 else <false_value>,如果 if 条件为真,返回前面那个值,否则返回后面那个值
选中历史会话时,高亮按钮
在主页面显示当前会话名称
每次模型回复后,保存一下会话信息
def load_session (session_name ):
try :
if os.path.exists(f"./session/{session_name} .json" ):
with open (f"./session/{session_name} .json" , "r" , encoding="utf-8" ) as f:
session_data = json.load(f)
st.session_state.nick_name = session_data["nick_name" ]
st.session_state.character = session_data["character" ]
st.session_state.current_session = session_name
st.session_state.messages = session_data["messages" ]
except Exception:
st.error("加载会话失败!!" )
...............
with col1:
if st.button(session, key=f"load_{session} " , icon="📝" , width="stretch" , type ="primary" if session == st.session_state.current_session else "secondary" ):
load_session(session)
st.rerun()
...................
st.text(f"当前会话:{st.session_state.current_session} " )
2.10 删除指定会话
def delete_session (session_name ):
try :
if os.path.exists(f"./session/{session_name} .json" ):
os.remove(f"./session/{session_name} .json" )
if session_name == st.session_state.current_session:
st.session_state.current_session = generate_session_name()
st.session_state.messages.clear()
except Exception:
st.error("删除失败!" )
.......
with col2:
if st.button("" , key=f"delete_{session} " , icon="🗑️" , width="stretch" ):
delete_session(session)
st.rerun()
2.11 完整代码 import streamlit as st
import os
from openai import OpenAI
from datetime import datetime
import json
st.set_page_config(
page_title="AI 智能伴侣" ,
page_icon="🤖" ,
layout="wide" ,
initial_sidebar_state="expanded" ,
menu_items={}
)
def generate_session_name ():
return datetime.now().strftime("%Y-%m-%d_%H-%M-%S" )
def save_session ():
if st.session_state.current_session:
session_data = {
"nick_name" : st.session_state.nick_name,
"nature" : st.session_state.nature,
"current_session" : st.session_state.current_session,
"messages" : st.session_state.messages
}
if not os.path.exists("sessions" ):
os.mkdir("sessions" )
with open (f"sessions/{st.session_state.current_session} .json" , "w" , encoding="utf-8" ) as f:
json.dump(session_data, f, ensure_ascii=False , indent=2 )
def load_sessions ():
session_list = []
if os.path.exists("sessions" ):
file_list = os.listdir("sessions" )
for filename in file_list:
if filename.endswith(".json" ):
session_list.append(filename[:-5 ])
session_list.sort(reverse=True )
return session_list
def load_session (session_name ):
try :
if os.path.exists(f"sessions/{session_name} .json" ):
with open (f"sessions/{session_name} .json" , "r" , encoding="utf-8" ) as f:
session_data = json.load(f)
st.session_state.messages = session_data["messages" ]
st.session_state.nick_name = session_data["nick_name" ]
st.session_state.nature = session_data["nature" ]
st.session_state.current_session = session_name
except Exception:
st.error("加载会话失败!" )
def delete_session (session_name ):
try :
if os.path.exists(f"sessions/{session_name} .json" ):
os.remove(f"sessions/{session_name} .json" )
if session_name == st.session_state.current_session:
st.session_state.messages = []
st.session_state.current_session = generate_session_name()
except Exception:
st.error("删除会话失败!" )
st.title("AI 智能伴侣" )
st.logo("resources/logo.png" )
system_prompt = """
你叫 %s,现在是用户的真实伴侣,请完全代入伴侣角色。
规则:
1. 每次只回 1 条消息
2. 禁止任何场景或状态描述性文字
3. 匹配用户的语言
4. 回复简短,像微信聊天一样
5. 有需要的话可以用❤️🌸等 emoji 表情
6. 用符合伴侣性格的方式对话
7. 回复的内容,要充分体现伴侣的性格特征
伴侣性格:
- %s
你必须严格遵守上述规则来回复用户。
"""
if "messages" not in st.session_state:
st.session_state.messages = []
if "nick_name" not in st.session_state:
st.session_state.nick_name = "小甜甜"
if "nature" not in st.session_state:
st.session_state.nature = "活泼开朗的东北姑娘"
if "current_session" not in st.session_state:
st.session_state.current_session = generate_session_name()
st.text(f"会话名称:{st.session_state.current_session} " )
for message in st.session_state.messages:
st.chat_message(message["role" ]).write(message["content" ])
client = OpenAI(api_key=os.environ.get('DEEPSEEK_API_KEY' ), base_url="https://api.deepseek.com" )
with st.sidebar:
st.subheader("AI 控制面板" )
if st.button("新建会话" , width="stretch" , icon="✏️" ):
save_session()
if st.session_state.messages:
st.session_state.messages = []
st.session_state.current_session = generate_session_name()
save_session()
st.rerun()
st.text("会话历史" )
session_list = load_sessions()
for session in session_list:
col1, col2 = st.columns([4 , 1 ])
with col1:
if st.button(session, width="stretch" , icon="📄" , key=f"load_{session} " , type ="primary" if session == st.session_state.current_session else "secondary" ):
load_session(session)
st.rerun()
with col2:
if st.button("" , width="stretch" , icon="❌️" , key=f"delete_{session} " ):
delete_session(session)
st.rerun()
st.divider()
st.subheader("伴侣信息" )
nick_name = st.text_input("昵称" , placeholder="请输入昵称" , value=st.session_state.nick_name)
if nick_name:
st.session_state.nick_name = nick_name
nature = st.text_area("性格" , placeholder="请输入性格" , value=st.session_state.nature)
if nature:
st.session_state.nature = nature
prompt = st.chat_input("请输入您要问的问题" )
if prompt:
st.chat_message("user" ).write(prompt)
print ("----------> 调用 AI 大模型,提示词:" , prompt)
st.session_state.messages.append({"role" :"user" ,"content" : prompt})
response = client.chat.completions.create(
model="deepseek-chat" ,
messages=[{"role" :"system" ,"content" : system_prompt %(st.session_state.nick_name, st.session_state.nature)}, *st.session_state.messages],
stream=True
)
response_message = st.empty()
full_response = ""
for chunk in response:
if chunk.choices[0 ].delta.content is not None :
content = chunk.choices[0 ].delta.content
full_response += content
response_message.chat_message("assistant" ).write(full_response)
st.session_state.messages.append({"role" :"assistant" ,"content" : full_response})
save_session()
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
随机西班牙地址生成器 随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online