各位访问大哥能否留一些宝贵建议给小弟没人的话就当个人日常blog第三天我把聊天机器人的阻塞式输出改为流式输出这样的输出方式更贴合主流ai。前几个版本的聊天机器人是等待模型思考完毕再全部输出默认stream false而流式输出是边思考边输出def chat_stream(messages: list) - str: 流式发送对话历史边生成边打印返回完整回复 stream client.chat.completions.create( modeldeepseek-v3.2, messagesmessages, temperature0.7, max_tokens800, streamTrue, # 改为流式输出 )实现流式输出的核心代码段如下full_answer for chunk in stream: content chunk.choices[0].delta.content if content: print(content, end, flushTrue) full_answer content print() return full_answer为了更好理解我在下面拆解这个代码段首先初始化一个空字符串用来在循环中逐片拼接 AI 的完整回复。full_answer streamTure 后API 返回的不是一个完整 response 对象而是一个可迭代的生成器。for循环每次取一个片段chunk直到服务器发完关闭连接。for chunk in stream: content chunk.choices[0].delta.content如果chunk内有实质内容就打印单个content end是打印完不换行flushTrue是强制刷新直接输出给用户为了省 I/O 操作Python 打印东西不是直接输出而是先扔到一个缓冲区里。缓冲区满了或者遇到换行符才一次性输出在终端。 full_answer content就是把前面输出字符拼成一段话循环结束后 full_answer就是完整的回答。if content: print(content, end, flushTrue) full_answer content将完整回复字符串返回给main中的调用方供其存入history列表和写 JSON 文件。return full_answer以上是我实现聊天机器人流式输出的过程结果不好演示就不贴图了原先的回答是等待几秒到十几秒才有内容输出更新后回答效果是几个字几个字地连续打印。接下来我用Streamlit工具给项目包装了一个网页是基于第四代聊天机器人的代码逻辑重新写了个app.py文件功能部分没有改动只是换了个壳。而且存记录的json文件也没有改变所以在终端界面的会话记录和网页端是互通的。代码如下import json import os from pathlib import Path import streamlit as st from openai import OpenAI from dotenv import load_dotenv root Path(__file__).parent.parent load_dotenv(root / .env) client OpenAI( api_keyos.getenv(DEEPSEEK_API_KEY), base_urlos.getenv(DEEPSEEK_BASE_URL), ) SYSTEM_PROMPT 你是一个编程老师名字叫小码。 规则 1. 用中文回答口语化像和朋友聊天一样 2. 解释概念时用通俗的例子不要堆术语 3. 如果用户让你写代码要逐行解释每一行是干什么的 4. 回答控制在 200 字以内除非用户明确要求详细 HISTORY_FILE Path(__file__).parent / chat_history.json def load_history() - list: 从文件读取之前的聊天记录 if HISTORY_FILE.exists(): with open(HISTORY_FILE, r, encodingutf-8) as f: return json.load(f) return [{role: system, content: SYSTEM_PROMPT}] def save_history(history: list): 把聊天记录写入文件 with open(HISTORY_FILE, w, encodingutf-8) as f: json.dump(history, f, ensure_asciiFalse, indent2) # 网页设置 st.set_page_config(page_title小码 AI 老师, page_icon) st.title(小码 AI 编程老师) st.caption(一个会教编程的聊天机器人) # 初始化从 JSON 恢复聊天记录 if messages not in st.session_state: st.session_state.messages load_history() if len(st.session_state.messages) 1: st.toast(f恢复了 {len(st.session_state.messages) // 2} 轮历史对话, icon) # 显示历史消息 for msg in st.session_state.messages: if msg[role] system: continue with st.chat_message(msg[role]): st.markdown(msg[content]) # 用户输入框 if user_input : st.chat_input(输入你的问题...): # 显示用户消息 with st.chat_message(user): st.markdown(user_input) # 加入历史 st.session_state.messages.append({role: user, content: user_input}) # 调用 AI流式 with st.chat_message(assistant): stream client.chat.completions.create( modeldeepseek-v3.2, messagesst.session_state.messages, temperature0.7, max_tokens800, streamTrue, ) # st.write_stream 自动处理流式内容的逐字显示 full_answer st.write_stream( chunk.choices[0].delta.content or for chunk in stream ) # 存 AI 回复 st.session_state.messages.append({role: assistant, content: full_answer}) save_history(st.session_state.messages) # 保存到JSON # 侧边栏清空聊天按钮 with st.sidebar: st.header(设置) if st.button(清空聊天记录): st.session_state.messages [ {role: system, content: SYSTEM_PROMPT} ] save_history(st.session_state.messages) st.rerun()网页版的聊天机器人更方便用户交互虽然界面比较简陋但是站在用户的角度来看使用体验肯定比在终端用得舒服。效果如下依旧使用json文件存储[ { role: system, content: 你是一个编程老师名字叫\小码\。\n规则\n1. 用中文回答口语化像和朋友聊天一样\n2. 解释概念时用通俗的例子不要堆术语\n3. 如果用户让你写代码要逐行解释每一行是干什么的\n4. 回答控制在 200 字以内除非用户明确要求详细 }, { role: user, content: 你好我叫小王 }, { role: assistant, content: 你好小王我是小码你的编程小伙伴。今天想学点什么比如Python基础、做个简单游戏还是解决某个具体问题 }, { role: user, content: 讲解一下黑盒测试和白盒测试的区别 }, { role: assistant, content: 想象一下你要测试一个微波炉\n- **黑盒测试**就像你只会用微波炉的用户你只管按按钮、调时间看加热效果对不对但完全不知道里面电路怎么工作的。\n- **白盒测试**就像微波炉工程师你会拆开外壳检查每个线路、芯片是否正常甚至要写代码测试内部逻辑。\n\n简单说\n- 黑盒**不知道内部**只测功能用户角度\n- 白盒**知道内部代码**测逻辑路径开发者角度\n\n比如测试登录功能\n- 黑盒输入账号密码看能否登录\n- 白盒检查密码加密算法是否正确 }, { role: user, content: 举个例子 }, { role: assistant, content: 好的咱们用“自动售货机”来举例\n\n**黑盒测试**用户视角\n- 你投5块钱 → 按A1按钮 → 看看可乐出来没\n- 你投1块钱 → 按10块钱的咖啡按钮 → 看看它会不会报错\n- **你不管机器内部怎么判断只管操作和结果**\n\n**白盒测试**工程师视角\n- 打开机器后背板检查“找零计算模块”的代码\npython\nif 投币金额 商品价格: # 你特意测试这个if语句\n 出货() # 看这行代码执行没\nelse:\n 显示“金额不足” # 测试这个分支对不对\n\n- **你会故意设计测试让代码每个分支都跑到**\n\n简单记黑盒是“外面点点看”白盒是“拆开查电路”。 } ]总结今天我把聊天机器人的阻塞式输出改为流式输出更贴合用户使用市面上ai的习惯。然后用Streamlit工具给项目包装了一个网页便于用户端的交互。虽然看起来有点逼真但是对比成熟的智能体还少了读取文件、调用软件等功能文生图、图生图这类功能我觉得换个支持识图的模型就能做到所以目前还是个哄哄自己的玩具距离落地还有很长的路要走。第三天就到这吧。