我们要做什么
把前面几篇笔记学到的知识串起来,做一个真正能用的东西:
$ python ai_chat.py
🤖 AI 助手已启动(输入 /quit 退出,/clear 清空记忆)
你 > 用一句话介绍 Python
AI > Python 是一种简洁易读、生态丰富的通用编程语言。
你 > 它适合做什么
AI > (记得上文)Python 特别适合数据分析、AI 开发、自动化脚本……
功能清单:
- 流式输出(打字机效果)
- 多轮对话记忆
/quit、/clear、/save斜杠命令- 配置文件管理 API Key
- 打包成 exe 双击即用
第 1 步:基础对话循环
# ai_chat.py
import os
import sys
from openai import OpenAI
# 从环境变量读 key,不要硬编码
client = OpenAI(
api_key=os.environ.get("DEEPSEEK_API_KEY", "sk-在这里填你的key"),
base_url="https://api.deepseek.com",
)
MODEL = "deepseek-chat"
# 对话历史:system 人设 + 历轮问答
history = [
{"role": "system", "content": "你是简洁专业的 AI 助手,回答控制在 300 字以内"}
]
def chat(user_input: str) -> None:
"""发送消息并流式打印回复"""
history.append({"role": "user", "content": user_input})
stream = client.chat.completions.create(
model=MODEL, messages=history, stream=True
)
print("AI > ", end="", flush=True)
full_reply = ""
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True) # 逐块打印 = 打字机效果
full_reply += delta
print()
# 关键:把 AI 的回复存回历史,实现记忆
history.append({"role": "assistant", "content": full_reply})
def main() -> None:
print("🤖 AI 助手已启动(/quit 退出,/clear 清空记忆)\n")
while True:
try:
user_input = input("你 > ").strip()
except (KeyboardInterrupt, EOFError): # Ctrl+C / Ctrl+D 优雅退出
print("\n再见!")
break
if not user_input:
continue
if user_input == "/quit":
print("再见!")
break
if user_input == "/clear":
history[:] = history[:1] # 只保留 system 人设
print("(记忆已清空)\n")
continue
try:
chat(user_input)
except Exception as e:
print(f"出错了:{e}\n") # 网络错误不退出,下次还能用
print()
if __name__ == "__main__":
main()
到这里已经是一个能用的 AI 助手了:流式输出、有记忆、能清空、出错不崩。
第 2 步:控制记忆长度
对话历史无限增长会撞上两个天花板:模型的上下文窗口、以及你的余额(历史每轮都重新计费)。加一个滑动窗口:
MAX_HISTORY = 20 # 最多保留最近 20 条消息
def trim_history() -> None:
"""保留 system + 最近的对话,超出的最旧记录删掉"""
if len(history) > MAX_HISTORY + 1:
del history[1 : len(history) - MAX_HISTORY]
在 chat() 开头调用一次 trim_history() 即可。更精细的方案是按 token 数裁剪,但按条数对日常使用已足够。
第 3 步:保存对话记录
/save 命令把当前会话存成 Markdown 文件:
from datetime import datetime
def save_history() -> str:
"""导出对话到 Markdown 文件,返回文件名"""
lines = [f"# AI 对话记录 {datetime.now():%Y-%m-%d %H:%M}\n"]
for msg in history[1:]: # 跳过 system
role = "**你**" if msg["role"] == "user" else "**AI**"
lines.append(f"{role}:{msg['content']}\n")
filename = f"chat_{datetime.now():%Y%m%d_%H%M%S}.md"
with open(filename, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
return filename
在主循环里加分支:
if user_input == "/save":
print(f"(已保存到 {save_history()})\n")
continue
第 4 步:配置文件管理 Key
Key 写死在代码里既危险又不方便分享,改用配置文件:
# config.py
import json
from pathlib import Path
CONFIG_PATH = Path.home() / ".ai_chat_config.json"
def load_config() -> dict:
"""读取配置,没有则引导用户创建"""
if not CONFIG_PATH.exists():
key = input("首次使用,请输入你的 API Key:").strip()
CONFIG_PATH.write_text(
json.dumps({"api_key": key, "model": "deepseek-chat"}, ensure_ascii=False, indent=2),
encoding="utf-8",
)
print(f"配置已保存到 {CONFIG_PATH}\n")
return json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
主程序里:
config = load_config()
client = OpenAI(api_key=config["api_key"], base_url="https://api.deepseek.com")
MODEL = config["model"]
配置文件放在用户主目录,既不用每次输入,也不会误提交进 Git。
第 5 步:打包成 exe
让没有 Python 环境的朋友也能用:
pip install pyinstaller
pyinstaller --onefile --name ai-chat ai_chat.py
产物在 dist/ai-chat.exe,双击即用,体积约 15MB(含 Python 运行时)。
几个实用参数:
pyinstaller --onefile --name ai-chat --clean ai_chat.py
# --onefile 打成单个 exe
# --clean 清掉上次构建缓存,改代码后重新打包建议加上
完整效果与扩展方向
最终成品是一个 100 行左右的单文件工具。跑通之后,可以按需扩展:
加「温度」调节:/temp 0.3 命令动态调整创造性参数。
加预设角色:/role 翻译 切换 system 人设,一个工具当多个助手用。
统计用量:从响应里取 usage 字段,显示本次消耗了多少 token、约合多少钱:
# 非流式响应可直接读 usage;流式需设置 stream_options={"include_usage": True}
stream = client.chat.completions.create(
model=MODEL, messages=history, stream=True,
stream_options={"include_usage": True},
)
# 最后一个 chunk 里有 usage 信息
接入本地模型:把 base_url 换成 http://localhost:11434/v1(Ollama),这个工具就变成了离线版 AI 助手——代码一行都不用改,这就是 OpenAI 兼容接口的妙处。
回顾:这个项目用到了什么
| 知识点 | 出处 |
|---|---|
| 虚拟环境管理依赖 | 笔记 1 |
| 第三方库调用网络 API | 笔记 2 |
| 异常处理与优雅退出 | 笔记 6 |
| 配置文件与文件读写 | 笔记 6/7 |
| 字符串处理 | 笔记 9 |
这就是我们 Python 专题的初衷:学语法的最好方式是做东西。这个命令行助手可能就是你以后每天用 AI 的方式之一——自己动手做的工具,用起来总是格外顺手。







评论 (0)
还没有评论,快来抢沙发吧~