Python 简单 AI 应用开发指南
人工智能及大模型的基础概念,对比了本地部署与 API 调用的优缺点。详细讲解了 Ollama 本地部署流程、HTTP 协议基础及 Apifox 接口测试方法。重点演示了如何使用 Python 的 Streamlit 库构建交互式 Web 应用,实现 AI 智能伴侣功能,包括会话记忆、流式输出、侧边栏配置及历史会话保存加载等完整代码示例。

人工智能及大模型的基础概念,对比了本地部署与 API 调用的优缺点。详细讲解了 Ollama 本地部署流程、HTTP 协议基础及 Apifox 接口测试方法。重点演示了如何使用 Python 的 Streamlit 库构建交互式 Web 应用,实现 AI 智能伴侣功能,包括会话记忆、流式输出、侧边栏配置及历史会话保存加载等完整代码示例。

API:应用程序编程接口 (Application Programming Interface),是软件间的标准化的'桥梁',允许开发者无需知晓内部细节即可调用外部功能或数据。
Ollama 是一个在本地运行、管理大语言模型的工具。官网:https://ollama.com/
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 官方提供的对话产品类似,具备会话记忆功能。
主流的大模型(如:DeepSeek、Kimi 等)官方都提供了开放 API,无需部署,就可以直接调用访问。
HTTP 协议 - 响应数据格式
[图片:HTTP 响应格式]
HTTP 协议 - 请求数据格式
[图片:HTTP 请求格式]
OSI 网络模型:全球网络互连标准模型,TCP/IP 网络模型:可以认为是 OSI 的简化版
[图片:OSI 与 TCP/IP 模型]
端口号 (Port) 是整数,取值范围在 0-65535,它是用来标识计算机设备中的运行中的程序。
[图片:端口号说明]
Apifox 调用 deepseek
[图片:Apifox 调用示例]
[图片:Apifox 响应示例]
与 AI 大模型的交互本质是无状态的,每一次请求响应都是相互独立的。(AI 大模型本身没有真正的会话记忆能力)
处理方式:会话历史滚雪球
[图片:会话历史处理]
知识回顾:JSON
列表:用 [] 表示,[] 中是列表的元素,多个元素以,分割。
[图片:JSON 结构示例]
调用 DeepSeek
[图片:DeepSeek 调用截图]
第一次使用需要从第三方库安装 openai
[图片:安装 openai 提示]
将 DEEPSEEK_API_KEY 的值配置到环境变量中(配置完成后将 pycharm 重启才能使用这个值)
[图片:环境变量配置 PyCharm]
PyPI:全程为 Python Package Index,是由 Python 官方和社区共同维护的 Python 第三方软件包的官方仓库。 pip:pip 是 Python 官方提供的 Python 包的管理工具,提供了对 Python 包的查找、下载、安装、卸载等功能。
提供输入输出的示例,eg:可以参考《人类群星闪耀时》的叙事风格。请不要列出冗长的日期列表
[图片:提示词示例]
https://streamlit.io[图片:Streamlit 界面示例]
准备工作:在 pycharm 中安装 lingma 插件,安装完成后重启 IDE
[图片:Lingma 插件安装]
[图片:Lingma 界面]
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 智能伴侣")
# logo
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)
# 初始化聊天信息
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})
*st.session_state.messages修改回复代码 通过 Apifox 调试,分析响应信息
[图片: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)
...
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,],
...
编码:是将字符 (文字、数字、符号) 转换为计算机能够存储和处理的数字代码的规则系统,如:ASCII、GBK、UTF-8。 注意:如果操作完文件,并未调用 close 方法关闭文件,同时程序没有停止运行,那么这个文件将一直被 Python 程序占用,无法操作。
[图片:文件操作示例]
with open() 方法 (推荐,最佳实践)
[图片:With 语句示例]
提示:with 语句 (上下文管理器) 的核心作用就是确保资源的总是被正确获取和释放(即使发生异常,也会被正确释放),也是项目开发中的推荐方式。
文件操作扩展
[图片:文件操作扩展]
indent:会在输出的 json 数据中添加缩进(格式化)
[图片:JSON 缩进示例]
# 生成会话标识函数
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
}
# 如果 sessions 目录不存在,则创建
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)
# 会话标识
if "current_session" not in st.session_state:
st.session_state.current_session = generate_session_name()
......
# 新建会话
if st.button("新建会话", width="stretch", icon="✏️"):
# 1. 保存当前会话信息
save_session()
# 2. 创建新的会话
if st.session_state.messages:
# 如果聊天信息非空,True; 否则,False
st.session_state.messages = []
st.session_state.current_session = generate_session_name()
save_session()
st.rerun()
# 重新运行当前页面
# 加载所有的会话列表信息
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 将一行分为若干列
三元运算符:语法:<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}")
# 删除指定会话
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()
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
}
# 如果 sessions 目录不存在,则创建
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)
# 加载所有的会话列表信息
():
session_list = []
os.path.exists():
file_list = os.listdir()
filename file_list:
filename.endswith():
session_list.append(filename[:-])
session_list.sort(reverse=)
session_list
():
:
os.path.exists():
(, , encoding=) f:
session_data = json.load(f)
st.session_state.messages = session_data[]
st.session_state.nick_name = session_data[]
st.session_state.nature = session_data[]
st.session_state.current_session = session_name
Exception:
st.error()
():
:
os.path.exists():
os.remove()
session_name == st.session_state.current_session:
st.session_state.messages = []
st.session_state.current_session = generate_session_name()
Exception:
st.error()
st.title()
st.logo()
system_prompt =
st.session_state:
st.session_state.messages = []
st.session_state:
st.session_state.nick_name =
st.session_state:
st.session_state.nature =
st.session_state:
st.session_state.current_session = generate_session_name()
st.text()
message st.session_state.messages:
st.chat_message(message[]).write(message[])
client = OpenAI(api_key=os.environ.get(), base_url=)
st.sidebar:
st.subheader()
st.button(, width=, icon=):
save_session()
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()
session session_list:
col1, col2 = st.columns([, ])
col1:
st.button(session, width=, icon=, key=, = session == st.session_state.current_session ):
load_session(session)
st.rerun()
col2:
st.button(, width=, icon=, key=):
delete_session(session)
st.rerun()
st.divider()
st.subheader()
nick_name = st.text_input(, placeholder=, value=st.session_state.nick_name)
nick_name:
st.session_state.nick_name = nick_name
nature = st.text_area(, placeholder=, value=st.session_state.nature)
nature:
st.session_state.nature = nature
prompt = st.chat_input()
prompt:
st.chat_message().write(prompt)
(, prompt)
st.session_state.messages.append({:,: prompt})
response = client.chat.completions.create(
model=,
messages=[{:,: system_prompt %(st.session_state.nick_name, st.session_state.nature)}, *st.session_state.messages],
stream=
)
response_message = st.empty()
full_response =
chunk response:
chunk.choices[].delta.content :
content = chunk.choices[].delta.content
full_response += content
response_message.chat_message().write(full_response)
st.session_state.messages.append({:,: full_response})
save_session()

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online