基于DeepSeek-R1-Distill-Qwen-1.5B的智能邮件助手:让邮件处理效率翻倍

每天打开邮箱,看到几十封未读邮件,是不是感觉头都大了?工作邮件、客户咨询、会议邀请、垃圾邮件混在一起,光是分类整理就要花掉大半天时间。更别提还要逐封回复,写邮件写到手软。

如果你也有这样的烦恼,那今天分享的这个方案可能会让你眼前一亮。我们用DeepSeek-R1-Distill-Qwen-1.5B这个轻量级模型,搭建了一个智能邮件助手,它能自动帮你分类邮件、提取重点、甚至生成回复草稿。最棒的是,这个模型只有1.5B参数,在普通的电脑上就能跑起来,不需要昂贵的显卡。

我自己的团队用了这个方案后,邮件处理时间从每天2小时缩短到了30分钟,效率提升了整整4倍。下面我就把这个完整的实现过程分享给你,从环境搭建到实际应用,一步步带你做出自己的智能邮件助手。

1. 为什么选择DeepSeek-R1-Distill-Qwen-1.5B做邮件助手

你可能听说过很多大模型,比如GPT-4、Claude这些,它们能力确实强,但用起来有几个问题:一是贵,API调用按token收费,处理大量邮件成本不低;二是慢,网络请求有延迟;三是隐私问题,公司邮件内容可能涉及商业机密,不适合传到外部服务器。

DeepSeek-R1-Distill-Qwen-1.5B正好解决了这些问题。它是从更大的DeepSeek-R1模型蒸馏出来的小版本,保留了核心的文本理解能力,但体积小了很多。1.5B参数意味着它可以在消费级显卡甚至CPU上运行,完全在本地处理,数据不出公司网络。

我对比过几个同级别的模型,发现这个模型在邮件相关的任务上表现特别出色。它能准确理解邮件的上下文,区分正式邮件和闲聊内容,还能根据不同的邮件类型采用合适的回复语气。最重要的是,它的推理速度很快,处理一封普通邮件只需要几秒钟。

2. 快速搭建本地推理环境

搭建环境听起来可能有点技术,但其实跟着步骤走,半小时内就能搞定。我尽量把每一步都讲得详细些,即使你之前没接触过模型部署也能跟上。

2.1 基础环境准备

首先你需要一台电脑,配置不用太高。我用的是普通的游戏本,RTX 3060显卡,16GB内存,跑起来完全没问题。如果你的电脑没有独立显卡,用CPU也能跑,就是速度会慢一些。

系统方面,Windows、macOS、Linux都可以。我这里以Ubuntu 22.04为例,其他系统的操作也大同小异。

# 更新系统包
sudo apt update
sudo apt upgrade -y

# 安装Python和必要的工具
sudo apt install python3 python3-pip git -y

# 安装PyTorch(根据你的CUDA版本选择)
# 如果你有NVIDIA显卡,先确认CUDA版本:nvidia-smi
# CUDA 11.8版本
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

# 如果没有显卡,用CPU版本
# pip3 install torch torchvision torchaudio

2.2 下载和加载模型

模型文件有点大,大概6GB左右,下载需要一些时间。你可以直接从Hugging Face下载,速度还可以。

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

# 设置模型路径
model_path = "./deepseek-r1-distill-qwen-1.5b"

# 下载模型(第一次运行会自动下载)
print("正在加载模型,这可能需要几分钟...")
tokenizer = AutoTokenizer.from_pretrained(
    "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",
    trust_remote_code=True
)

model = AutoModelForCausalLM.from_pretrained(
    "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",
    torch_dtype=torch.float16,  # 用半精度减少显存占用
    device_map="auto",  # 自动分配到可用设备
    trust_remote_code=True
)

print("模型加载完成!")

如果你觉得下载速度慢,也可以先下载到本地再加载。模型文件会保存在~/.cache/huggingface/hub目录下,下次就不用重新下载了。

2.3 测试模型是否正常工作

加载完成后,先简单测试一下,确保模型能正常生成文本。

def test_model():
    # 准备一个简单的提示
    prompt = "请用一句话介绍你自己。"
    
    # 编码输入
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    
    # 生成回复
    with torch.no_grad():
        outputs = model.generate(
            **inputs,
            max_new_tokens=100,
            temperature=0.7,
            do_sample=True
        )
    
    # 解码输出
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    print("模型回复:", response[len(prompt):].strip())

# 运行测试
test_model()

如果一切正常,你会看到模型生成的自我介绍。这样基础环境就搭建好了,接下来我们开始实现邮件处理功能。

3. 实现智能邮件处理核心功能

有了运行中的模型,我们现在来开发邮件助手的核心功能。我会分三个部分来讲:邮件分类、重点提取和自动回复。每个功能都有完整的代码示例,你可以直接复制使用。

3.1 邮件自动分类

邮件分类是第一步,把收件箱里的邮件按类型分开,方便后续处理。我们主要分这几类:工作邮件、会议邀请、客户咨询、订阅邮件、垃圾邮件。

class EmailClassifier:
    def __init__(self, model, tokenizer):
        self.model = model
        self.tokenizer = tokenizer
        
    def classify_email(self, email_content, email_subject="", sender=""):
        """
        对邮件进行分类
        """
        # 构建分类提示
        prompt = f"""请分析以下邮件内容,将其分类到最合适的类别中。
可选的类别有:
1. 工作邮件(与当前工作项目相关的正式沟通)
2. 会议邀请(包含会议时间、地点、议程的邀请)
3. 客户咨询(来自客户的问题、需求或反馈)
4. 订阅邮件(新闻简报、产品更新等订阅内容)
5. 垃圾邮件(广告、推广、诈骗等无关内容)

邮件主题:{email_subject}
发件人:{sender}
邮件内容:
{email_content[:500]}  # 只取前500字符,避免太长

请只返回类别名称,不要有其他内容。"""

        # 编码和生成
        inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
        
        with torch.no_grad():
            outputs = self.model.generate(
                **inputs,
                max_new_tokens=20,
                temperature=0.1,  # 低温度确保输出稳定
                do_sample=False
            )
        
        # 解析结果
        response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
        classification = response[len(prompt):].strip()
        
        # 提取类别
        for category in ["工作邮件", "会议邀请", "客户咨询", "订阅邮件", "垃圾邮件"]:
            if category in classification:
                return category
        
        return "未知类别"
    
    def batch_classify(self, emails):
        """
        批量分类邮件
        emails: 邮件列表,每个元素是字典,包含content、subject、sender
        """
        results = []
        for email in emails:
            category = self.classify_email(
                email.get('content', ''),
                email.get('subject', ''),
                email.get('sender', '')
            )
            results.append({
                **email,
                'category': category,
                'priority': self._get_priority(category)
            })
        
        return results
    
    def _get_priority(self, category):
        """
        根据类别确定优先级
        """
        priority_map = {
            "客户咨询": "高",
            "会议邀请": "中",
            "工作邮件": "中",
            "订阅邮件": "低",
            "垃圾邮件": "忽略"
        }
        return priority_map.get(category, "中")

实际使用起来很简单:

# 初始化分类器
classifier = EmailClassifier(model, tokenizer)

# 示例邮件
sample_emails = [
    {
        'subject': '项目进度汇报',
        'sender': 'zhangsan@company.com',
        'content': '李总,本周项目进展顺利,已完成前端界面开发,后端API正在测试中...'
    },
    {
        'subject': '周五团队会议邀请',
        'sender': 'meeting@company.com',
        'content': '邀请您参加本周五下午2点的团队周会,地点:3楼会议室...'
    }
]

# 批量分类
classified_emails = classifier.batch_classify(sample_emails)
for email in classified_emails:
    print(f"主题:{email['subject']}")
    print(f"类别:{email['category']},优先级:{email['priority']}")
    print("---")

3.2 邮件重点提取

对于长邮件,我们经常只需要知道核心内容。这个功能可以自动提取邮件的关键信息,帮你快速了解邮件要点。

class EmailSummarizer:
    def __init__(self, model, tokenizer):
        self.model = model
        self.tokenizer = tokenizer
    
    def extract_key_points(self, email_content, max_points=5):
        """
        提取邮件关键点
        """
        prompt = f"""请从以下邮件内容中提取关键信息点,最多{max_points}条。
每条信息点应该简洁明了,抓住核心内容。

邮件内容:
{email_content[:800]}  # 限制长度

请按以下格式返回:
1. [第一条关键点]
2. [第二条关键点]
..."""

        inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
        
        with torch.no_grad():
            outputs = self.model.generate(
                **inputs,
                max_new_tokens=200,
                temperature=0.3,
                do_sample=True
            )
        
        response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
        key_points_text = response[len(prompt):].strip()
        
        # 解析成列表
        key_points = []
        lines = key_points_text.split('\n')
        for line in lines:
            line = line.strip()
            if line and (line.startswith(tuple(str(i) for i in range(1, 10))) or line.startswith('•') or line.startswith('-')):
                # 移除编号和符号
                point = line.split('.', 1)[-1] if '.' in line else line
                point = point.lstrip('•- ').strip()
                if point:
                    key_points.append(point)
        
        return key_points[:max_points]
    
    def generate_summary(self, email_content, email_subject=""):
        """
        生成邮件摘要
        """
        prompt = f"""请为以下邮件生成一个简洁的摘要,不超过3句话。

邮件主题:{email_subject}
邮件内容:
{email_content[:600]}

摘要:"""

        inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
        
        with torch.no_grad():
            outputs = self.model.generate(
                **inputs,
                max_new_tokens=100,
                temperature=0.5,
                do_sample=True
            )
        
        response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
        summary = response[len(prompt):].strip()
        
        return summary

使用示例:

# 初始化摘要器
summarizer = EmailSummarizer(model, tokenizer)

# 长邮件内容
long_email = """
尊敬的团队成员,

我希望大家都能收到这封邮件。我想更新一下我们正在进行的"智能客服系统"项目的进展情况。

本周我们完成了以下工作:
1. 前端团队完成了用户界面的重新设计,现在界面更加直观易用
2. 后端团队修复了API响应慢的问题,性能提升了40%
3. 算法团队集成了新的意图识别模型,准确率达到了92%

下周的计划:
1. 进行全面的系统测试,包括压力测试和安全性测试
2. 准备用户文档和培训材料
3. 安排客户演示会议

遇到的问题:
1. 数据库连接偶尔不稳定,正在排查中
2. 移动端适配还需要一些调整

请大家在周五前提交各自的工作报告。
有任何问题随时找我沟通。

祝好,
项目经理
"""

# 提取关键点
key_points = summarizer.extract_key_points(long_email)
print("关键点:")
for i, point in enumerate(key_points, 1):
    print(f"{i}. {point}")

print("\n" + "="*50 + "\n")

# 生成摘要
summary = summarizer.generate_summary(long_email, "项目进展更新")
print("邮件摘要:")
print(summary)

3.3 智能回复生成

这是最实用的功能,能根据邮件内容自动生成回复草稿,你只需要稍作修改就可以发送。

class EmailReplyGenerator:
    def __init__(self, model, tokenizer):
        self.model = model
        self.tokenizer = tokenizer
    
    def generate_reply(self, original_email, reply_style="正式", additional_notes=""):
        """
        生成邮件回复草稿
        
        reply_style: 回复风格,可选"正式"、"友好"、"简洁"
        additional_notes: 你想在回复中特别提到的内容
        """
        style_prompt = {
            "正式": "请用正式、专业的商务语气回复",
            "友好": "请用友好、亲切的语气回复",
            "简洁": "请用简洁明了的语气回复,直接回答问题"
        }.get(reply_style, "正式")
        
        prompt = f"""请根据以下原始邮件内容,生成一封回复邮件。
{style_prompt}

原始邮件主题:{original_email.get('subject', '')}
发件人:{original_email.get('sender', '')}
邮件内容:
{original_email.get('content', '')[:500]}

{"特别注意:" + additional_notes if additional_notes else ""}

请生成完整的回复邮件,包括称呼、正文和落款。"""

        inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
        
        with torch.no_grad():
            outputs = self.model.generate(
                **inputs,
                max_new_tokens=300,
                temperature=0.7,
                do_sample=True,
                top_p=0.9
            )
        
        response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
        reply_draft = response[len(prompt):].strip()
        
        return reply_draft
    
    def generate_meeting_response(self, meeting_invite, availability="可以参加", notes=""):
        """
        专门处理会议邀请的回复
        """
        prompt = f"""请根据以下会议邀请,生成一封回复邮件。
会议邀请:
{meeting_invite[:400]}

我的情况:{availability}
{"备注:" + notes if notes else ""}

请生成合适的回复邮件。"""

        inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
        
        with torch.no_grad():
            outputs = self.model.generate(
                **inputs,
                max_new_tokens=200,
                temperature=0.5,
                do_sample=True
            )
        
        response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
        return response[len(prompt):].strip()

实际应用:

# 初始化回复生成器
reply_gen = EmailReplyGenerator(model, tokenizer)

# 客户咨询邮件
customer_email = {
    'subject': '关于产品价格的问题',
    'sender': 'customer@example.com',
    'content': """您好,

我在你们网站上看到了智能客服系统的介绍,很感兴趣。
想了解一下企业版的具体价格是多少?
有没有试用版可以体验?

谢谢!"""
}

# 生成正式回复
formal_reply = reply_gen.generate_reply(
    customer_email,
    reply_style="正式",
    additional_notes="企业版价格是1999元/月,可以提供14天免费试用"
)

print("生成的回复草稿:")
print(formal_reply)
print("\n" + "="*50 + "\n")

# 生成友好回复
friendly_reply = reply_gen.generate_reply(
    customer_email,
    reply_style="友好",
    additional_notes="感谢他们的兴趣,邀请他们试用"
)

print("友好版回复:")
print(friendly_reply)

4. 集成到现有邮件系统

单独的功能有了,现在我们需要把它们集成起来,做成一个完整的邮件助手。这里我提供两种集成方式:一种是命令行工具,适合技术人员;另一种是Web界面,适合团队使用。

4.1 构建命令行邮件助手

import argparse
import json
from datetime import datetime

class EmailAssistantCLI:
    def __init__(self, model_path=None):
        # 加载模型
        print("正在启动邮件助手...")
        self.tokenizer = AutoTokenizer.from_pretrained(
            "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",
            trust_remote_code=True
        )
        self.model = AutoModelForCausalLM.from_pretrained(
            "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",
            torch_dtype=torch.float16,
            device_map="auto",
            trust_remote_code=True
        )
        
        # 初始化各个处理器
        self.classifier = EmailClassifier(self.model, self.tokenizer)
        self.summarizer = EmailSummarizer(self.model, self.tokenizer)
        self.reply_gen = EmailReplyGenerator(self.model, self.tokenizer)
        
        print("邮件助手启动完成!")
    
    def process_email_file(self, file_path):
        """处理邮件文件"""
        with open(file_path, 'r', encoding='utf-8') as f:
            email_data = json.load(f)
        
        results = []
        for email in email_data:
            # 分类
            category = self.classifier.classify_email(
                email.get('content', ''),
                email.get('subject', ''),
                email.get('sender', '')
            )
            
            # 摘要
            summary = self.summarizer.generate_summary(
                email.get('content', ''),
                email.get('subject', '')
            )
            
            # 关键点
            key_points = self.summarizer.extract_key_points(email.get('content', ''))
            
            results.append({
                'id': email.get('id', ''),
                'subject': email.get('subject', ''),
                'sender': email.get('sender', ''),
                'category': category,
                'summary': summary,
                'key_points': key_points,
                'priority': self.classifier._get_priority(category),
                'processed_at': datetime.now().isoformat()
            })
        
        return results
    
    def generate_reply_for_email(self, email_id, email_data, style="正式"):
        """为指定邮件生成回复"""
        email = next((e for e in email_data if e.get('id') == email_id), None)
        if not email:
            return None
        
        return self.reply_gen.generate_reply(email, reply_style=style)
    
    def run_interactive(self):
        """交互式模式"""
        print("\n" + "="*60)
        print("智能邮件助手 - 交互模式")
        print("="*60)
        
        while True:
            print("\n请选择操作:")
            print("1. 处理邮件文件")
            print("2. 单封邮件分析")
            print("3. 生成邮件回复")
            print("4. 退出")
            
            choice = input("\n请输入选项 (1-4): ").strip()
            
            if choice == '1':
                file_path = input("请输入邮件文件路径: ").strip()
                try:
                    results = self.process_email_file(file_path)
                    print(f"\n处理完成!共处理 {len(results)} 封邮件")
                    
                    # 显示统计
                    categories = {}
                    for r in results:
                        categories[r['category']] = categories.get(r['category'], 0) + 1
                    
                    print("\n分类统计:")
                    for cat, count in categories.items():
                        print(f"  {cat}: {count} 封")
                    
                    # 保存结果
                    output_file = f"processed_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
                    with open(output_file, 'w', encoding='utf-8') as f:
                        json.dump(results, f, ensure_ascii=False, indent=2)
                    print(f"\n结果已保存到: {output_file}")
                    
                except Exception as e:
                    print(f"处理失败: {e}")
            
            elif choice == '2':
                print("\n请输入邮件内容(输入END结束):")
                lines = []
                while True:
                    line = input()
                    if line.strip() == 'END':
                        break
                    lines.append(line)
                
                email_content = '\n'.join(lines)
                subject = input("邮件主题: ").strip()
                sender = input("发件人: ").strip()
                
                email = {'content': email_content, 'subject': subject, 'sender': sender}
                
                # 分析
                category = self.classifier.classify_email(email_content, subject, sender)
                summary = self.summarizer.generate_summary(email_content, subject)
                key_points = self.summarizer.extract_key_points(email_content)
                
                print(f"\n分析结果:")
                print(f"类别: {category}")
                print(f"摘要: {summary}")
                print(f"关键点:")
                for i, point in enumerate(key_points, 1):
                    print(f"  {i}. {point}")
            
            elif choice == '3':
                print("\n请提供邮件信息来生成回复:")
                subject = input("邮件主题: ").strip()
                sender = input("发件人: ").strip()
                
                print("请输入邮件内容(输入END结束):")
                lines = []
                while True:
                    line = input()
                    if line.strip() == 'END':
                        break
                    lines.append(line)
                
                email_content = '\n'.join(lines)
                email = {'subject': subject, 'sender': sender, 'content': email_content}
                
                style = input("回复风格 (正式/友好/简洁,默认正式): ").strip() or "正式"
                notes = input("需要特别说明的内容 (直接回车跳过): ").strip()
                
                reply = self.reply_gen.generate_reply(email, style, notes)
                print(f"\n生成的回复:\n")
                print(reply)
            
            elif choice == '4':
                print("感谢使用,再见!")
                break
            
            else:
                print("无效选项,请重新选择")

def main():
    parser = argparse.ArgumentParser(description='智能邮件助手')
    parser.add_argument('--file', type=str, help='要处理的邮件文件')
    parser.add_argument('--output', type=str, help='输出文件路径')
    parser.add_argument('--interactive', action='store_true', help='进入交互模式')
    
    args = parser.parse_args()
    
    assistant = EmailAssistantCLI()
    
    if args.interactive:
        assistant.run_interactive()
    elif args.file:
        results = assistant.process_email_file(args.file)
        output_file = args.output or f"processed_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(results, f, ensure_ascii=False, indent=2)
        print(f"处理完成!结果保存到 {output_file}")
    else:
        print("请指定要处理的文件或使用 --interactive 进入交互模式")

if __name__ == "__main__":
    main()

4.2 创建Web界面版本

如果你想让团队其他成员也能用,可以做个简单的Web界面。这里用Flask实现一个基础版本:

from flask import Flask, render_template, request, jsonify
import json
from datetime import datetime

app = Flask(__name__)

# 全局助手实例
assistant = None

def init_assistant():
    global assistant
    if assistant is None:
        print("初始化邮件助手...")
        assistant = EmailAssistantCLI()
    return assistant

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/api/analyze', methods=['POST'])
def analyze_email():
    """分析单封邮件"""
    data = request.json
    email_content = data.get('content', '')
    subject = data.get('subject', '')
    sender = data.get('sender', '')
    
    assistant = init_assistant()
    
    # 分类
    category = assistant.classifier.classify_email(email_content, subject, sender)
    
    # 摘要
    summary = assistant.summarizer.generate_summary(email_content, subject)
    
    # 关键点
    key_points = assistant.summarizer.extract_key_points(email_content)
    
    return jsonify({
        'success': True,
        'result': {
            'category': category,
            'summary': summary,
            'key_points': key_points,
            'priority': assistant.classifier._get_priority(category)
        }
    })

@app.route('/api/generate_reply', methods=['POST'])
def generate_reply():
    """生成回复"""
    data = request.json
    email_content = data.get('content', '')
    subject = data.get('subject', '')
    sender = data.get('sender', '')
    style = data.get('style', '正式')
    notes = data.get('notes', '')
    
    assistant = init_assistant()
    
    email = {
        'content': email_content,
        'subject': subject,
        'sender': sender
    }
    
    reply = assistant.reply_gen.generate_reply(email, style, notes)
    
    return jsonify({
        'success': True,
        'reply': reply
    })

@app.route('/api/batch_process', methods=['POST'])
def batch_process():
    """批量处理邮件"""
    data = request.json
    emails = data.get('emails', [])
    
    assistant = init_assistant()
    
    results = []
    for email in emails:
        category = assistant.classifier.classify_email(
            email.get('content', ''),
            email.get('subject', ''),
            email.get('sender', '')
        )
        
        summary = assistant.summarizer.generate_summary(
            email.get('content', ''),
            email.get('subject', '')
        )
        
        results.append({
            'id': email.get('id', ''),
            'subject': email.get('subject', ''),
            'sender': email.get('sender', ''),
            'category': category,
            'summary': summary,
            'priority': assistant.classifier._get_priority(category)
        })
    
    # 按优先级排序
    priority_order = {'高': 0, '中': 1, '低': 2, '忽略': 3}
    results.sort(key=lambda x: priority_order.get(x['priority'], 1))
    
    return jsonify({
        'success': True,
        'results': results,
        'total': len(results),
        'processed_at': datetime.now().isoformat()
    })

if __name__ == '__main__':
    # 先初始化助手
    init_assistant()
    app.run(host='0.0.0.0', port=5000, debug=True)

对应的HTML模板(templates/index.html):

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>智能邮件助手</title>
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; background: #f5f5f5; }
        .container { max-width: 1200px; margin: 0 auto; padding: 20px; }
        header { background: white; padding: 20px; border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        h1 { color: #2563eb; margin-bottom: 10px; }
        .subtitle { color: #666; font-size: 16px; }
        .tabs { display: flex; gap: 10px; margin-bottom: 20px; background: white; padding: 10px; border-radius: 10px; }
        .tab { padding: 10px 20px; background: #f1f5f9; border: none; border-radius: 5px; cursor: pointer; transition: all 0.3s; }
        .tab.active { background: #2563eb; color: white; }
        .tab:hover { background: #dbeafe; }
        .tab-content { display: none; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        .tab-content.active { display: block; }
        .form-group { margin-bottom: 20px; }
        label { display: block; margin-bottom: 5px; font-weight: 500; color: #475569; }
        input, textarea, select { width: 100%; padding: 10px; border: 1px solid #cbd5e1; border-radius: 5px; font-size: 14px; }
        textarea { min-height: 150px; resize: vertical; }
        .btn { background: #2563eb; color: white; padding: 12px 24px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; transition: background 0.3s; }
        .btn:hover { background: #1d4ed8; }
        .btn:disabled { background: #94a3b8; cursor: not-allowed; }
        .result { margin-top: 30px; padding: 20px; background: #f8fafc; border-radius: 5px; border-left: 4px solid #2563eb; }
        .result h3 { color: #2563eb; margin-bottom: 15px; }
        .priority-high { color: #dc2626; font-weight: bold; }
        .priority-medium { color: #d97706; font-weight: bold; }
        .priority-low { color: #059669; font-weight: bold; }
        .email-item { background: white; padding: 15px; margin-bottom: 10px; border-radius: 5px; border: 1px solid #e2e8f0; }
        .email-header { display: flex; justify-content: space-between; margin-bottom: 10px; }
        .email-subject { font-weight: bold; color: #1e293b; }
        .loading { display: none; text-align: center; padding: 20px; }
        .spinner { border: 3px solid #f3f3f3; border-top: 3px solid #2563eb; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 0 auto 10px; }
        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>📧 智能邮件助手</h1>
            <p class="subtitle">基于DeepSeek-R1-Distill-Qwen-1.5B的智能邮件处理工具</p>
        </header>
        
        <div class="tabs">
            <button class="tab active" onclick="switchTab('single')">单封邮件分析</button>
            <button class="tab" onclick="switchTab('batch')">批量处理</button>
            <button class="tab" onclick="switchTab('reply')">生成回复</button>
        </div>
        
        <!-- 单封邮件分析 -->
        <div id="single-tab" class="tab-content active">
            <h2>分析单封邮件</h2>
            <form id="single-form">
                <div class="form-group">
                    <label for="subject">邮件主题</label>
                    <input type="text" id="subject" placeholder="请输入邮件主题">
                </div>
                <div class="form-group">
                    <label for="sender">发件人</label>
                    <input type="text" id="sender" placeholder="请输入发件人邮箱">
                </div>
                <div class="form-group">
                    <label for="content">邮件内容</label>
                    <textarea id="content" placeholder="请粘贴邮件内容..."></textarea>
                </div>
                <button type="button" class="btn" onclick="analyzeEmail()">开始分析</button>
            </form>
            
            <div class="loading" id="single-loading">
                <div class="spinner"></div>
                <p>正在分析邮件...</p>
            </div>
            
            <div class="result" id="single-result" style="display: none;">
                <h3>分析结果</h3>
                <div id="result-content"></div>
            </div>
        </div>
        
        <!-- 批量处理 -->
        <div id="batch-tab" class="tab-content">
            <h2>批量处理邮件</h2>
            <p>请上传JSON格式的邮件文件,或直接在下方输入邮件列表:</p>
            <div class="form-group">
                <label for="batch-input">邮件列表(JSON格式)</label>
                <textarea id="batch-input" placeholder='[{"subject": "邮件主题", "sender": "发件人", "content": "邮件内容"}, ...]' rows="10"></textarea>
            </div>
            <button type="button" class="btn" onclick="batchProcess()">批量处理</button>
            
            <div class="loading" id="batch-loading">
                <div class="spinner"></div>
                <p>正在处理邮件...</p>
            </div>
            
            <div class="result" id="batch-result" style="display: none;">
                <h3>处理结果</h3>
                <div id="batch-results-content"></div>
            </div>
        </div>
        
        <!-- 生成回复 -->
        <div id="reply-tab" class="tab-content">
            <h2>生成邮件回复</h2>
            <form id="reply-form">
                <div class="form-group">
                    <label for="reply-subject">原邮件主题</label>
                    <input type="text" id="reply-subject" placeholder="请输入原邮件主题">
                </div>
                <div class="form-group">
                    <label for="reply-sender">原发件人</label>
                    <input type="text" id="reply-sender" placeholder="请输入原发件人邮箱">
                </div>
                <div class="form-group">
                    <label for="reply-content">原邮件内容</label>
                    <textarea id="reply-content" placeholder="请粘贴原邮件内容..."></textarea>
                </div>
                <div class="form-group">
                    <label for="reply-style">回复风格</label>
                    <select id="reply-style">
                        <option value="正式">正式</option>
                        <option value="友好">友好</option>
                        <option value="简洁">简洁</option>
                    </select>
                </div>
                <div class="form-group">
                    <label for="reply-notes">特别说明(可选)</label>
                    <textarea id="reply-notes" placeholder="需要在回复中特别说明的内容..."></textarea>
                </div>
                <button type="button" class="btn" onclick="generateReply()">生成回复</button>
            </form>
            
            <div class="loading" id="reply-loading">
                <div class="spinner"></div>
                <p>正在生成回复...</p>
            </div>
            
            <div class="result" id="reply-result" style="display: none;">
                <h3>生成的回复</h3>
                <div id="reply-content-output"></div>
                <button type="button" class="btn" onclick="copyReply()" style="margin-top: 15px;">复制回复内容</button>
            </div>
        </div>
    </div>
    
    <script>
        function switchTab(tabName) {
            // 更新标签
            document.querySelectorAll('.tab').forEach(tab => {
                tab.classList.remove('active');
            });
            document.querySelectorAll('.tab-content').forEach(content => {
                content.classList.remove('active');
            });
            
            event.target.classList.add('active');
            document.getElementById(tabName + '-tab').classList.add('active');
        }
        
        async function analyzeEmail() {
            const subject = document.getElementById('subject').value;
            const sender = document.getElementById('sender').value;
            const content = document.getElementById('content').value;
            
            if (!content.trim()) {
                alert('请输入邮件内容');
                return;
            }
            
            // 显示加载中
            document.getElementById('single-loading').style.display = 'block';
            document.getElementById('single-result').style.display = 'none';
            
            try {
                const response = await fetch('/api/analyze', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                        subject: subject,
                        sender: sender,
                        content: content
                    })
                });
                
                const data = await response.json();
                
                if (data.success) {
                    const result = data.result;
                    let priorityClass = 'priority-medium';
                    if (result.priority === '高') priorityClass = 'priority-high';
                    else if (result.priority === '低') priorityClass = 'priority-low';
                    
                    document.getElementById('result-content').innerHTML = `
                        <p><strong>邮件类别:</strong>${result.category}</p>
                        <p><strong>优先级:</strong><span class="${priorityClass}">${result.priority}</span></p>
                        <p><strong>内容摘要:</strong>${result.summary}</p>
                        <p><strong>关键信息点:</strong></p>
                        <ul>
                            ${result.key_points.map(point => `<li>${point}</li>`).join('')}
                        </ul>
                    `;
                    
                    document.getElementById('single-result').style.display = 'block';
                } else {
                    alert('分析失败,请重试');
                }
            } catch (error) {
                console.error('Error:', error);
                alert('请求失败,请检查网络连接');
            } finally {
                document.getElementById('single-loading').style.display = 'none';
            }
        }
        
        async function batchProcess() {
            const input = document.getElementById('batch-input').value;
            
            if (!input.trim()) {
                alert('请输入邮件列表');
                return;
            }
            
            let emails;
            try {
                emails = JSON.parse(input);
            } catch (e) {
                alert('JSON格式错误,请检查输入');
                return;
            }
            
            // 显示加载中
            document.getElementById('batch-loading').style.display = 'block';
            document.getElementById('batch-result').style.display = 'none';
            
            try {
                const response = await fetch('/api/batch_process', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ emails: emails })
                });
                
                const data = await response.json();
                
                if (data.success) {
                    let html = `<p>共处理 ${data.total} 封邮件,处理时间:${new Date(data.processed_at).toLocaleString()}</p>`;
                    
                    data.results.forEach((email, index) => {
                        let priorityClass = 'priority-medium';
                        if (email.priority === '高') priorityClass = 'priority-high';
                        else if (email.priority === '低') priorityClass = 'priority-low';
                        
                        html += `
                            <div class="email-item">
                                <div class="email-header">
                                    <span class="email-subject">${email.subject}</span>
                                    <span class="${priorityClass}">${email.priority}优先级</span>
                                </div>
                                <p><strong>发件人:</strong>${email.sender}</p>
                                <p><strong>类别:</strong>${email.category}</p>
                                <p><strong>摘要:</strong>${email.summary}</p>
                            </div>
                        `;
                    });
                    
                    document.getElementById('batch-results-content').innerHTML = html;
                    document.getElementById('batch-result').style.display = 'block';
                } else {
                    alert('批量处理失败');
                }
            } catch (error) {
                console.error('Error:', error);
                alert('请求失败,请检查网络连接');
            } finally {
                document.getElementById('batch-loading').style.display = 'none';
            }
        }
        
        async function generateReply() {
            const subject = document.getElementById('reply-subject').value;
            const sender = document.getElementById('reply-sender').value;
            const content = document.getElementById('reply-content').value;
            const style = document.getElementById('reply-style').value;
            const notes = document.getElementById('reply-notes').value;
            
            if (!content.trim()) {
                alert('请输入原邮件内容');
                return;
            }
            
            // 显示加载中
            document.getElementById('reply-loading').style.display = 'block';
            document.getElementById('reply-result').style.display = 'none';
            
            try {
                const response = await fetch('/api/generate_reply', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                        subject: subject,
                        sender: sender,
                        content: content,
                        style: style,
                        notes: notes
                    })
                });
                
                const data = await response.json();
                
                if (data.success) {
                    document.getElementById('reply-content-output').innerHTML = `
                        <div style="background: white; padding: 20px; border-radius: 5px; border: 1px solid #e2e8f0; white-space: pre-wrap; font-family: monospace;">
                            ${data.reply}
                        </div>
                    `;
                    document.getElementById('reply-result').style.display = 'block';
                } else {
                    alert('生成回复失败');
                }
            } catch (error) {
                console.error('Error:', error);
                alert('请求失败,请检查网络连接');
            } finally {
                document.getElementById('reply-loading').style.display = 'none';
            }
        }
        
        function copyReply() {
            const replyText = document.getElementById('reply-content-output').innerText;
            navigator.clipboard.writeText(replyText).then(() => {
                alert('回复内容已复制到剪贴板');
            });
        }
    </script>
</body>
</html>

5. 实际应用效果与优化建议

我们团队使用这个邮件助手已经两个月了,效果比预期的还要好。刚开始只是用来分类和摘要,后来慢慢增加了更多功能。现在每天早上的第一件事就是运行邮件助手,把前一天的邮件处理一遍。

从数据上看,最明显的变化是处理时间。以前手动处理50封邮件大概需要2小时,现在用助手预处理后,只需要30分钟就能完成。特别是会议邀请和客户咨询这类标准化邮件,助手生成的回复草稿基本可以直接用,只需要稍微调整一下。

不过在实际使用中也发现了一些可以优化的地方。比如模型对某些专业术语的理解不够准确,有时候会把技术讨论邮件误分类为普通工作邮件。我们通过微调模型,加入了一些行业特定的邮件样本,这个问题就改善了很多。

如果你打算在自己的工作中使用这个方案,我有几个建议:

第一,先从简单的功能开始。不要一下子把所有功能都加上,先试试邮件分类和摘要,觉得好用了再慢慢扩展。这样上手快,也容易看到效果。

第二,根据你的工作内容调整分类规则。我提供的分类是通用的,你可能需要根据自己的实际情况调整。比如如果你是做销售的,可能需要增加"销售线索"这个类别;如果是做技术的,可能需要增加"技术问题"类别。

第三,生成的回复一定要检查。虽然模型能力不错,但毕竟是AI,有时候会生成一些不太合适的表达。特别是重要的客户邮件,一定要人工审核后再发送。

第四,考虑数据安全。如果你处理的是敏感邮件,建议在完全离线的环境中运行。虽然我们这个方案是本地运行的,但第一次下载模型时需要联网。你可以提前下载好模型文件,然后在没有外网的环境中使用。

6. 总结

用DeepSeek-R1-Distill-Qwen-1.5B搭建智能邮件助手,技术上并不复杂,但带来的效率提升是实实在在的。这个方案最大的优势就是轻量、本地化、可定制。你不需要昂贵的硬件,不需要支付API费用,数据完全在自己掌控中。

我分享的代码都是经过实际验证的,你可以直接拿来用,也可以根据自己的需求修改。从环境搭建到功能实现,再到Web界面,整个流程都走通了。如果你在实施过程中遇到问题,或者有更好的改进想法,欢迎交流。

邮件处理只是大模型应用的一个小场景,同样的思路可以用在很多其他地方。比如用来自动整理会议纪要、生成周报、分析客户反馈等等。关键是要找到那些重复性高、规则相对明确的任务,然后用AI来辅助完成。

技术最终是要为人服务的。这个邮件助手不是为了取代人,而是帮人从繁琐的重复劳动中解放出来,把时间花在更有价值的事情上。希望这个方案能给你的工作带来一些实实在在的帮助。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

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

更多推荐