一个基于 Streamlit 和 DeepSeek API 的轻量级聊天伴侣,支持角色定制、会话持久化、流式输出,参数调节和导出功能(开源链接:不染/agent)


一、项目速览

主要功能模块

  • 多角色切换(内置 5 种预设模板 + 自定义)
  • 会话历史管理(新建、加载、删除)
  • 实时流式对话(逐字输出)
  • 模型与参数调节(temperature、top_p、max_tokens)
  • 聊天记录导出

二、技术栈与环境配置

表格

组件 选型
前端 / UI 框架 Streamlit(纯 Python,无需 HTML/CSS)
LLM API DeepSeek(兼容 OpenAI SDK)
存储 本地 JSON 文件(会话数据)
依赖管理 pip + requirements.txt

关键配置:API 密钥

应用通过环境变量 DEEPSEEK_API_KEY 读取密钥,这是唯一的外部依赖。在启动前需设置:

bash

运行

export DEEPSEEK_API_KEY="sk-xxxx"   
# Linux/macOS
# 或 Windows PowerShell:
$env:DEEPSEEK_API_KEY="sk-xxxx"

代码中初始化 OpenAI 客户端时直接引用:

client = OpenAI(
    api_key=os.environ.get('DEEPSEEK_API_KEY'),
    base_url="https://api.deepseek.com"
)

若未设置,界面会显示错误提示,并阻止 API 调用。


三、核心模块深入解析

1. 状态管理(Streamlit Session State)

整个应用的 “大脑” 是 st.session_state,它跨页面重绘保持数据。我们维护了四个关键状态:

python

运行

if "messages" not in st.session_state:
    st.session_state.messages = []          # 对话历史 [{role, content}, ...]
if "nick_name" not in st.session_state:
    st.session_state.nick_name = ""         # AI昵称
if "nature" not in st.session_state:
    st.session_state.nature = ""            # AI性格描述
if "current_session" not in st.session_state:
    st.session_state.current_session = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

所有交互(发送消息、切换角色、加载会话)都通过修改这些状态来驱动 UI 更新。

2. 角色定制与系统提示词

角色性格通过动态构建系统提示词(system prompt)传递给模型。我们定义了一个生成函数:

def build_system_prompt():
    nick_name = st.session_state.nick_name or "AI助手"
    nature = st.session_state.nature or "友好、热情、乐于助人"
    return f"""你是 {nick_name}。
性格特点:{nature}"""

侧边栏提供了两种方式定制角色:

  • 预设模板:一键套用 “温柔学姐” 等 5 种配置,直接修改 st.session_state.nick_namenature
  • 手动输入:通过文本输入框和文本区域自由修改。

当用户选择模板时,触发 st.rerun() 刷新界面,新角色立即生效。

3. 会话持久化(保存与加载)

会话数据以 JSON 格式保存在 session_data/ 目录,每个文件以会话创建时间命名(如 2026-06-29 10-30-45.json)。

保存函数 save_session() 关键代码:

def save_session():
    """保存当前会话到JSON文件"""
    session_data = {
        "messages": st.session_state.messages,
        "nick_name": st.session_state.nick_name,
        "nature": st.session_state.nature,
        "current_session": st.session_state.current_session
    }

    session_dir = os.path.join(os.path.dirname(__file__), "session_data")
    if not os.path.exists(session_dir):
        os.makedirs(session_dir)

    safe_filename = st.session_state.current_session.replace(":", "-")
    file_path = os.path.join(session_dir, f"{safe_filename}.json")

    with open(file_path, "w", encoding="utf-8") as f:
        json.dump(session_data, f, ensure_ascii=False, indent=2)

加载函数 load_session() 将 JSON 内容恢复到 session_state

def load_session(session_name):
    """加载指定会话"""
    try:
        session_dir = os.path.join(os.path.dirname(__file__), "session_data")
        file_path = os.path.join(session_dir, f"{session_name}.json")
        if os.path.exists(file_path):
            with open(file_path, "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
            st.success(f"已加载会话:{session_name}")
            st.rerun()
        else:
            st.error(f"会话文件不存在:{session_name}")
    except Exception as e:
        st.error(f"无法加载会话:{session_name},错误:{str(e)}")

侧边栏动态列出所有会话文件,并为每个会话生成 “加载” 和 “删除” 按钮,实现完整的 CRUD 操作。

4. 流式对话实现

这是应用的核心交互逻辑。当用户输入问题后,我们调用 DeepSeek API 并启用 stream=True

response = client.chat.completions.create(
    model=st.session_state.model,          # 可选 deepseek-chat / reasoner
    messages=[
        {"role": "system", "content": build_system_prompt()},
        *st.session_state.messages,
    ],
    stream=True,
    temperature=temperature,
    max_tokens=max_tokens,
    top_p=top_p
)

响应以块(chunk)形式返回,我们在循环中逐块追加内容并实时更新界面,实现打字机效果:

with st.chat_message("assistant"):
    message_placeholder = st.empty()
    full_response = ""
    for chunk in response:
        if chunk.choices[0].delta.content is not None:
            full_response += chunk.choices[0].delta.content
            message_placeholder.markdown(full_response + "▌")  # 闪烁光标
    message_placeholder.markdown(full_response)
    st.session_state.messages.append({"role": "assistant", "content": full_response})
    save_session()   # 每次回复完成后自动保存

错误处理:若 API 调用失败,会移除刚添加的用户消息,避免状态不一致。

生成参数详解:温度、Top‑P 与最大长度

5.生成参数详解:温度、Top‑P 与最大长度

在“AI智能伴侣”的侧边栏中,提供了三个核心滑块,它们直接决定了模型回复的风格多样性长度

① 温度(Temperature)—— 创造力的调节阀

原理

温度控制模型在每一步选择词时的“冒险程度”。它通过对原始概率分布进行缩放来实现:

  • 低温度(如 0.1~0.5):概率分布被“压尖”,高概率的词优势更明显,模型几乎总是选最稳妥的词。输出确定性强、逻辑严谨,适合数学解题、代码生成。

  • 高温度(如 1.2~2.0):概率分布被“抹平”,原本概率较低的词也有机会被选中。输出充满随机性、创意丰富,适合头脑风暴、故事创作。

建议:日常聊天保持 0.7 左右,兼顾逻辑与趣味;需要事实性回答时降至 0.2

② Top‑P(核采样)—— 候选词的“动态过滤器”

你之前提到 Top‑K,但 DeepSeek(遵循 OpenAI 标准)采用更先进的 Top‑P(Nucleus Sampling),它比固定 K 值更灵活。

原理

模型将候选词按概率从高到低排序,然后不断累加概率,直到累加和达到阈值 P(例如 0.95)。只有落在这个“累积概率池”里的词才参与随机采样。

  • 低 Top‑P(如 0.1~0.5):池子很小,只包含最确定的少数词,输出集中、精准

  • 高 Top‑P(如 0.9~1.0):池子很大,包含大量可能词,输出丰富、多样

建议:将 Top‑P 固定在 0.9 左右,只通过温度来调节多样性,这样更容易控制输出质量。

③ 最大长度(Max Tokens)—— 回复的“字数天花板”

原理

这里的 tokens 是大模型处理文本的最小单位(中文一个汉字通常占 1~2 个 token)。该参数硬性限制模型生成回复的 token 总数。一旦达到这个值,无论句子是否完整,生成都会立即截断。

  • 设置合理的长度可以控制 API 费用(按 token 计费)并避免 AI 过度啰嗦

  • 对于需要详细解释的问题,应适当增大此值。

建议:一般问答 1024 足够;代码生成或长文写作可设为 4096 以上。

6. 导出功能

generate_export_content() 函数根据 format_type 生成 Markdown 或纯文本格式的聊天记录,包含会话元信息(时间、角色名、性格)和所有对话。然后通过 st.download_button 提供下载:

def generate_export_content(format_type="md"):
    """生成聊天记录导出内容"""
    if not st.session_state.messages:
        return ""
    
    if format_type == "md":
        content = f"# AI智能伴侣 - 聊天记录\n\n"
        content += f"**会话时间**: {st.session_state.current_session}\n\n"
        content += f"**角色昵称**: {st.session_state.nick_name or 'AI助手'}\n\n"
        content += f"**性格特点**: {st.session_state.nature or '友好、热情、乐于助人'}\n\n"
        content += "---\n\n"
        
        for msg in st.session_state.messages:
            role = "用户" if msg["role"] == "user" else (st.session_state.nick_name or "AI助手")
            content += f"**{role}**:\n\n{msg['content']}\n\n---\n\n"
    else:
        content = f"AI智能伴侣 - 聊天记录\n"
        content += f"会话时间: {st.session_state.current_session}\n"
        # ... TXT格式
    return content

四、页面布局与交互流程

布局结构

  • 侧边栏:集中所有控制项(新建会话、会话列表、模型参数、角色模板、导出按钮)。
  • 主区域:顶部显示标题和 Logo,中间区域展示历史消息(按时间顺序),底部固定输入框。

典型操作流程

  1. 启动应用:自动生成一个空会话(时间戳命名)。
  2. 定制角色:在侧边栏选择模板或手动输入昵称和性格,立即生效。
  3. 开始对话:在底部输入框输入消息,AI 回复以流式方式逐字显示,同时自动保存会话。
  4. 管理会话:点击 “新建会话” 保存当前并创建新会话;在会话列表中点击任意项加载历史对话,点击垃圾桶删除。
  5. 导出记录:点击导出按钮,选择 Markdown 或 TXT 格式下载当前会话的完整聊天记录。


五、扩展方向

可扩展方向

  • RAG 增强:接入本地文档,实现知识库问答。
  • 多模态支持:若 DeepSeek 推出图像识别,可增加图片输入。
  • 云同步:将会话数据迁移到 Firebase 或 Supabase,实现跨设备访问。
  • 对话摘要:为长对话自动生成标题,改善列表显示。

立即体验:克隆仓库https://gitee.com/buaichiyudexiaoli/agent,设置 API 密钥,运行 streamlit run my_streamlit_app.py,即可拥有你的专属 AI 伙伴。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐