基于LLM与向量数据库构建具备记忆能力的邮件智能体实战指南 📅 发布时间:2026/8/24 21:22:51 👁 浏览次数: 在邮件处理日益繁重的今天你是否也渴望拥有一个能理解上下文、自动处理邮件的智能助手无论是处理客户咨询、管理团队沟通还是筛选重要通知一个具备“记忆”能力的邮件智能体都能大幅提升效率。本文将深入探讨如何构建一个类似“Lindy”的邮件智能体重点实现其核心能力记忆与自动回复。我们将从概念入手逐步拆解技术架构并提供一套完整的、可运行的代码实现方案涵盖从环境搭建到核心逻辑开发的每一个步骤。无论你是对AI Agent感兴趣的后端开发者还是希望将自动化引入工作流的工程师都能从本文获得可直接复用的实战经验。1. 邮件智能体的核心概念与价值在深入代码之前我们有必要厘清几个核心概念理解为什么“记忆”对于邮件智能体至关重要。1.1 什么是邮件智能体邮件智能体Email Agent是一个基于人工智能尤其是大语言模型的自动化程序它能够模拟人类处理电子邮件的行为。其核心功能通常包括邮件解析读取并理解邮件主题、正文、发件人、附件等信息。意图识别判断邮件的目的是咨询、投诉、通知、会议邀请还是垃圾邮件。上下文理解结合历史对话记录理解当前邮件所指代的具体事务。决策与执行根据意图和上下文决定如何响应。例如直接回复、转发给特定人员、创建待办事项或者标记为已读。自动回复生成符合语境、语气得当的回复内容。一个基础的自动回复机器人只能根据关键词进行固定回复而一个真正的智能体其核心差异就在于上下文理解能力这直接依赖于其“记忆”系统。1.2 “记忆”在智能体中的作用对于邮件处理场景“记忆”远不止是记住历史对话。它是一个结构化的信息存储与检索系统主要包括会话记忆单次对话的上下文。例如用户在一封邮件里问了产品A的价格在下一封邮件里说“那我订一个”智能体需要记住“产品A”和“价格”这个上下文才能正确理解“订一个”的含义。这是短期记忆。长期记忆跨会话、跨时间的知识。例如客户张三的历史购买记录、偏好某个项目组的固定工作流程公司的常见问答知识库。这需要持久化存储。工具记忆智能体调用外部工具如查询数据库、创建日历事件的历史记录和结果用于后续决策。没有记忆的智能体每次处理邮件都像是“第一次见面”无法提供个性化、连贯的服务。记忆机制使得智能体能够进行多轮有效对话积累用户画像实现真正的智能化。1.3 技术架构概览一个具备记忆功能的邮件智能体其典型技术栈如下接入层使用IMAP/SMTP协议或Gmail API、Outlook Graph API等来收取和发送邮件。处理引擎大语言模型LLM作为“大脑”负责理解、推理和生成。记忆模块向量数据库如Chroma, Pinecone, Weaviate用于存储和语义检索长期记忆传统数据库如SQLite, PostgreSQL或缓存Redis用于存储结构化会话和用户数据。工具系统让LLM能够调用外部API如查询CRM、创建工单、检查日历。编排框架使用LangChain、LangGraph或自定义工作流来组织以上组件控制处理逻辑。接下来我们将从零开始构建一个简化但功能完整的原型系统。2. 环境准备与项目初始化我们选择Python作为开发语言因为它拥有丰富的AI和邮件处理库。本项目将使用OpenAI的GPT模型作为LLMChroma作为向量数据库LangChain作为编排框架。2.1 环境与依赖操作系统Windows/macOS/Linux均可。Python版本建议使用Python 3.10或3.11。首先创建项目目录并初始化虚拟环境mkdir email_agent cd email_agent python -m venv venv # Windows 激活 venv\Scripts\activate # macOS/Linux 激活 source venv/bin/activate安装核心依赖库pip install openai langchain langchain-openai chromadb langchain-chroma pip install python-dotenv email-protector # 用于处理邮件内容 pip install imapclient smtplib # Python标准库通常无需额外安装openai,langchain-openai: 用于调用OpenAI API。langchain: AI应用编排的核心框架。chromadb,langchain-chroma: 轻量级本地向量数据库及其LangChain集成。python-dotenv: 管理环境变量如API密钥。email-protector: 一个示例库用于更安全地解析邮件实际中可根据需要选择。2.2 项目结构规划创建如下项目结构使代码清晰可维护email_agent/ ├── .env # 存储敏感配置如API密钥不提交到Git ├── main.py # 主程序入口 ├── config.py # 配置文件 ├── mail_client.py # 邮件收发客户端 ├── memory_system.py # 记忆系统核心 ├── agent_core.py # 智能体逻辑与工作流 ├── tools/ # 自定义工具目录 │ └── calendar_tool.py # 示例日历查询工具 ├── storage/ # 数据存储目录由Chroma等自动创建 └── requirements.txt # 依赖列表初始化requirements.txt:pip freeze requirements.txt2.3 配置文件与环境变量创建.env文件并确保将其加入.gitignore# .env OPENAI_API_KEYyour_openai_api_key_here OPENAI_MODELgpt-4o-mini # 或 gpt-3.5-turbo根据需求选择 # 邮件账户配置 (以Gmail为例使用应用专用密码或OAuth) EMAIL_ACCOUNTyour_emailgmail.com EMAIL_PASSWORDyour_app_specific_password IMAP_SERVERimap.gmail.com IMAP_PORT993 SMTP_SERVERsmtp.gmail.com SMTP_PORT587 # Chroma 持久化路径 CHROMA_PERSIST_DIR./storage/chroma_db创建config.py来加载配置# config.py import os from dotenv import load_dotenv load_dotenv() # 加载 .env 文件中的变量 class Config: # OpenAI OPENAI_API_KEY os.getenv(OPENAI_API_KEY) OPENAI_MODEL os.getenv(OPENAI_MODEL, gpt-4o-mini) # Email EMAIL_ACCOUNT os.getenv(EMAIL_ACCOUNT) EMAIL_PASSWORD os.getenv(EMAIL_PASSWORD) IMAP_SERVER os.getenv(IMAP_SERVER) IMAP_PORT int(os.getenv(IMAP_PORT, 993)) SMTP_SERVER os.getenv(SMTP_SERVER) SMTP_PORT int(os.getenv(SMTP_PORT, 587)) # Memory CHROMA_PERSIST_DIR os.getenv(CHROMA_PERSIST_DIR) classmethod def validate(cls): 验证必要配置是否存在 required_vars [OPENAI_API_KEY, EMAIL_ACCOUNT, EMAIL_PASSWORD] missing [var for var in required_vars if not getattr(cls, var)] if missing: raise ValueError(fMissing required environment variables: {missing}) # 初始化时验证 Config.validate()3. 构建邮件客户端我们需要一个可靠的客户端来获取新邮件并发送回复。这里使用Python标准库imaplib和smtplib并做简单封装。# mail_client.py import imaplib import email from email.header import decode_header import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import logging from config import Config logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) class EmailClient: def __init__(self): self.imap_server Config.IMAP_SERVER self.imap_port Config.IMAP_PORT self.smtp_server Config.SMTP_SERVER self.smtp_port Config.SMTP_PORT self.account Config.EMAIL_ACCOUNT self.password Config.EMAIL_PASSWORD def fetch_unread_emails(self, limit10): 获取未读邮件列表 emails [] try: # 连接IMAP服务器 with imaplib.IMAP4_SSL(self.imap_server, self.imap_port) as mail: mail.login(self.account, self.password) mail.select(INBOX) # 选择收件箱 # 搜索未读邮件 status, messages mail.search(None, UNSEEN) if status ! OK: logger.warning(No unread emails found or search failed.) return emails email_ids messages[0].split() # 限制获取数量 for e_id in email_ids[:limit]: status, msg_data mail.fetch(e_id, (RFC822)) if status ! OK: continue # 解析邮件 raw_email msg_data[0][1] msg email.message_from_bytes(raw_email) # 解析主题和发件人 subject, encoding decode_header(msg[Subject])[0] if isinstance(subject, bytes): subject subject.decode(encoding if encoding else utf-8, errorsignore) elif subject is None: subject (No Subject) from_ msg.get(From) # 解析正文 (优先取纯文本部分) body if msg.is_multipart(): for part in msg.walk(): content_type part.get_content_type() content_disposition str(part.get(Content-Disposition)) if content_type text/plain and attachment not in content_disposition: try: body part.get_payload(decodeTrue).decode() except: pass if body: break else: content_type msg.get_content_type() if content_type text/plain: try: body msg.get_payload(decodeTrue).decode() except: pass if not body: body [邮件内容无法解析或为非文本格式] email_info { id: e_id.decode(), subject: subject, from: from_, body: body.strip(), raw_message: msg } emails.append(email_info) logger.info(fFetched email from {from_}, subject: {subject[:50]}...) except Exception as e: logger.error(fError fetching emails: {e}) return emails def send_reply(self, original_msg, reply_body, in_reply_toNone): 回复邮件 try: # 创建回复邮件 msg MIMEMultipart() msg[From] self.account msg[To] original_msg[from] msg[Subject] fRe: {original_msg[subject]} if in_reply_to: msg[In-Reply-To] in_reply_to msg[References] in_reply_to msg.attach(MIMEText(reply_body, plain, utf-8)) # 发送 with smtplib.SMTP(self.smtp_server, self.smtp_port) as server: server.starttls() # 安全连接 server.login(self.account, self.password) server.send_message(msg) logger.info(fReply sent to {original_msg[from]}) return True except Exception as e: logger.error(fError sending reply: {e}) return False def mark_as_read(self, email_id): 将邮件标记为已读 try: with imaplib.IMAP4_SSL(self.imap_server, self.imap_port) as mail: mail.login(self.account, self.password) mail.select(INBOX) mail.store(email_id, FLAGS, \\Seen) logger.info(fMarked email {email_id} as read.) except Exception as e: logger.error(fError marking email as read: {e})这个客户端提供了三个核心方法获取未读邮件、发送回复、标记已读。注意使用Gmail时需要开启IMAP/SMTP并可能使用应用专用密码。4. 实现智能体的记忆系统记忆系统是智能体的核心。我们将实现一个双层次记忆向量存储长期记忆和会话缓存短期记忆。4.1 长期记忆 - 向量数据库存储我们使用ChromaDB存储邮件对话的摘要、用户偏好、项目信息等以便进行语义搜索。# memory_system.py from langchain_chroma import Chroma from langchain_openai import OpenAIEmbeddings from langchain.schema import Document from langchain.text_splitter import RecursiveCharacterTextSplitter import hashlib from datetime import datetime from config import Config import logging logger logging.getLogger(__name__) class LongTermMemory: def __init__(self): # 初始化嵌入模型和向量库 self.embeddings OpenAIEmbeddings( openai_api_keyConfig.OPENAI_API_KEY, modeltext-embedding-3-small # 性价比高的嵌入模型 ) self.persist_dir Config.CHROMA_PERSIST_DIR # 创建或加载向量库。collection_name可理解为“表名”这里按用户或全局分类。 self.vectorstore Chroma( persist_directoryself.persist_dir, embedding_functionself.embeddings, collection_nameemail_agent_memory ) self.text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50 ) def _generate_doc_id(self, sender, content_snippet): 生成文档的唯一ID unique_string f{sender}_{content_snippet[:50]}_{datetime.now().timestamp()} return hashlib.md5(unique_string.encode()).hexdigest() def store_conversation(self, sender, email_subject, email_body, agent_response, metadataNone): 存储一次完整的邮件交互到长期记忆 try: # 将对话内容组合成一个文档 full_text f 发件人: {sender} 主题: {email_subject} 用户来信: {email_body} 助理回复: {agent_response} 时间: {datetime.now().isoformat()} if metadata: full_text f\n元数据: {metadata} # 分割文本以适应嵌入模型的上下文长度 texts self.text_splitter.split_text(full_text) documents [] for i, text in enumerate(texts): doc_id self._generate_doc_id(sender, text) f_{i} doc Document( page_contenttext, metadata{ sender: sender, subject: email_subject, timestamp: datetime.now().isoformat(), chunk_index: i, **(metadata or {}) }, iddoc_id ) documents.append(doc) # 添加到向量库 self.vectorstore.add_documents(documents) logger.info(fStored conversation with {sender} about {email_subject} into long-term memory.) except Exception as e: logger.error(fFailed to store conversation to long-term memory: {e}) def search_memory(self, query, sender_filterNone, k3): 从长期记忆中搜索相关上下文 try: # 可以添加元数据过滤 filter_dict {} if sender_filter: filter_dict[sender] sender_filter # 执行相似性搜索 results self.vectorstore.similarity_search( query, kk, filterfilter_dict if filter_dict else None ) # 格式化搜索结果 context_pieces [] for doc in results: context_pieces.append(f[记忆片段] {doc.page_content}) return \n\n.join(context_pieces) if context_pieces else 暂无相关历史记忆 except Exception as e: logger.error(fFailed to search long-term memory: {e}) return 4.2 短期记忆 - 会话缓存短期记忆用于保持单次对话或近期对话的连贯性通常存储在内存或快速键值库中。# memory_system.py (续) from collections import defaultdict import json class ShortTermMemory: def __init__(self, max_session_length10): # 使用字典存储会话键为发件人值为最近的对话列表 self.sessions defaultdict(list) self.max_session_length max_session_length # 每个会话保留的最大轮次 def add_interaction(self, sender, user_message, agent_response): 添加一次交互到短期记忆 session self.sessions[sender] interaction { user: user_message, agent: agent_response, time: datetime.now().isoformat() } session.append(interaction) # 限制会话长度移除最旧的记录 if len(session) self.max_session_length: session.pop(0) logger.debug(fAdded interaction to short-term memory for {sender}. Session length: {len(session)}) def get_session_context(self, sender, last_n5): 获取指定发件人的最近对话上下文 session self.sessions.get(sender, []) # 取最近 last_n 轮对话 recent session[-last_n:] if last_n 0 else session context_lines [] for i, interaction in enumerate(recent): # 可以简化格式只保留核心内容 context_lines.append(f用户: {interaction[user][:200]}...) context_lines.append(f助理: {interaction[agent][:200]}...) return \n.join(context_lines) if context_lines else 这是本次会话的第一条消息 def clear_session(self, sender): 清除指定发件人的会话缓存 if sender in self.sessions: del self.sessions[sender] logger.info(fCleared short-term memory for {sender}) class MemorySystem: 记忆系统总入口整合长短期记忆 def __init__(self): self.long_term LongTermMemory() self.short_term ShortTermMemory() def remember(self, sender, current_query): 根据当前查询和发件人检索相关记忆。 返回一个整合了长短期记忆的上下文字符串。 # 1. 获取短期记忆会话上下文 short_term_ctx self.short_term.get_session_context(sender) # 2. 从长期记忆中搜索语义相关的历史 # 搜索查询可以结合当前邮件内容和发件人 search_query f{sender}: {current_query} long_term_ctx self.long_term.search_memory(search_query, sender_filtersender) # 3. 整合记忆 memory_context if short_term_ctx: memory_context f【本次会话历史】\n{short_term_ctx}\n\n if long_term_ctx: memory_context f【相关历史记录】\n{long_term_ctx}\n\n return memory_context.strip() def memorize(self, sender, email_subject, email_body, agent_response, metadataNone): 记忆一次完整的交互 # 存入短期记忆 self.short_term.add_interaction(sender, email_body, agent_response) # 存入长期记忆 self.long_term.store_conversation(sender, email_subject, email_body, agent_response, metadata)这个记忆系统实现了核心功能remember用于在回复前检索相关记忆memorize用于在回复后保存交互记录。5. 构建智能体核心与工作流现在我们将记忆系统、LLM和工具调用整合起来形成智能体的决策与生成核心。5.1 定义工具首先定义智能体可以调用的工具。这里以一个简单的“查询日历”工具为例。# tools/calendar_tool.py import logging from datetime import datetime, timedelta logger logging.getLogger(__name__) class CalendarTool: 一个模拟的日历查询工具 def __init__(self, user_email): self.user_email user_email # 模拟一些日历事件 self.mock_events [ {title: 团队周会, start: 2024-06-10 10:00, end: 2024-06-10 11:00}, {title: 产品评审, start: 2024-06-11 14:00, end: 2024-06-11 15:30}, {title: 与客户A通话, start: 2024-06-12 09:30, end: 2024-06-12 10:15}, ] def check_availability(self, date_strNone, duration_minutes60): 检查指定日期时间的可用性。 参数: date_str: 日期字符串格式 YYYY-MM-DD 或 YYYY-MM-DD HH:MM。如果为None则检查明天。 duration_minutes: 需要的会议时长分钟。 返回: 可用时间段或冲突信息。 try: if date_str: if in date_str: target_time datetime.strptime(date_str, %Y-%m-%d %H:%M) else: target_time datetime.strptime(date_str, %Y-%m-%d) target_time target_time.replace(hour9, minute0) # 默认上午9点 else: # 默认检查明天上午9点 target_time datetime.now() timedelta(days1) target_time target_time.replace(hour9, minute0, second0, microsecond0) end_time target_time timedelta(minutesduration_minutes) # 检查冲突 conflicts [] for event in self.mock_events: event_start datetime.strptime(event[start], %Y-%m-%d %H:%M) event_end datetime.strptime(event[end], %Y-%m-%d %H:%M) # 简单的时间段重叠检查 if not (end_time event_start or target_time event_end): conflicts.append(event[title]) if conflicts: return f在 {target_time.strftime(%Y-%m-%d %H:%M)} 开始的 {duration_minutes} 分钟时间段内与以下事件冲突{, .join(conflicts)}。 else: return f{target_time.strftime(%Y-%m-%d %H:%M)} 开始时长 {duration_minutes} 分钟的时间段是可用的。 except Exception as e: logger.error(fCalendar tool error: {e}) return 抱歉处理日历查询时出现错误。 # 可以添加更多方法如创建事件、列出全天事件等5.2 智能体核心逻辑使用LangChain的LCELLangChain Expression Language来编排工作流。# agent_core.py from langchain_openai import ChatOpenAI from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.schema import SystemMessage, HumanMessage, AIMessage from langchain.tools import Tool from langchain.agents import create_react_agent, AgentExecutor from langchain.memory import ConversationBufferMemory from tools.calendar_tool import CalendarTool from memory_system import MemorySystem from config import Config import logging import json logger logging.getLogger(__name__) class EmailAgent: def __init__(self, user_email): self.llm ChatOpenAI( modelConfig.OPENAI_MODEL, openai_api_keyConfig.OPENAI_API_KEY, temperature0.2, # 较低的温度使回复更稳定 streamingFalse ) self.user_email user_email self.memory_system MemorySystem() self.calendar_tool CalendarTool(user_email) # 将工具包装成LangChain Tool格式 self.tools [ Tool( nameCheckCalendarAvailability, funcself.calendar_tool.check_availability, description检查指定日期时间的日历可用性。输入应为JSON字符串包含date_str可选格式YYYY-MM-DD或YYYY-MM-DD HH:MM和duration_minutes可选默认60字段。例如{{date_str: 2024-06-15 14:00, duration_minutes: 30}}。如果date_str为空则检查明天上午9点。 ), # 未来可以添加更多工具如查询知识库、创建工单等 ] # 系统提示词定义智能体的角色和能力 self.system_prompt f 你是一个专业的邮件助理负责处理发送到 {self.user_email} 的邮件。 你的目标是理解用户意图利用记忆和工具提供准确、有帮助的回复。 核心能力 1. **记忆**你能记住与每位联系人的历史对话。在回复前你会看到【本次会话历史】和【相关历史记录】。 2. **工具使用**你可以调用工具来获取信息如检查日历可用性。调用工具时请严格按照工具描述的输入格式。 3. **邮件回复**你的回复将直接作为邮件正文发送。请保持专业、清晰、简洁。 回复原则 - 如果用户询问日程安排请调用日历工具。 - 如果用户提到之前讨论过的事情请引用相关记忆确保回复的连贯性。 - 如果无法确定或需要人工介入请礼貌说明并建议用户提供更多信息或联系相关人员。 - 不要编造你不知道的信息。 # 使用ReAct代理框架 self.agent_executor self._create_agent() def _create_agent(self): 创建LangChain ReAct代理执行器 from langchain import hub # 从LangChain Hub拉取一个标准的ReAct提示词可本地化 prompt hub.pull(hwchase17/react-chat) # 我们需要自定义提示词以融入系统指令和记忆 custom_prompt ChatPromptTemplate.from_messages([ SystemMessage(contentself.system_prompt), MessagesPlaceholder(variable_namechat_history), HumanMessage(content{input}), MessagesPlaceholder(variable_nameagent_scratchpad) # ReAct框架的思考空间 ]) # 创建代理 agent create_react_agent( llmself.llm, toolsself.tools, promptcustom_prompt ) # 创建执行器并传入一个简单的对话内存用于ReAct框架内部的步骤记忆 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) executor AgentExecutor( agentagent, toolsself.tools, memorymemory, verboseTrue, # 设置为True可以看到代理的思考过程生产环境可设为False handle_parsing_errorsTrue, max_iterations3 # 限制工具调用次数防止死循环 ) return executor def process_email(self, sender, subject, body): 处理一封邮件生成回复 logger.info(fProcessing email from {sender}: {subject}) # 1. 检索记忆 memory_context self.memory_system.remember(sender, body) # 2. 构建给LLM的完整输入包含记忆和当前邮件 full_input f {memory_context} 【新邮件】 发件人: {sender} 主题: {subject} 内容: {body} 请根据以上信息包括历史记忆和当前邮件内容进行回复。如果需要可以使用工具。 你的回复将直接发送给发件人。 # 3. 调用代理生成回复 try: response self.agent_executor.invoke({input: full_input}) agent_reply response[output] # 4. 记忆本次交互 self.memory_system.memorize( sendersender, email_subjectsubject, email_bodybody, agent_responseagent_reply, metadata{processed: True} ) return agent_reply except Exception as e: logger.error(fAgent processing failed: {e}) # 降级处理生成一个简单的回复 fallback_reply f您好 我已收到您关于“{subject}”的邮件。 目前我的自动处理系统遇到一点技术问题已记录您的问题。我会尽快通过其他方式跟进。 祝好 {self.user_email}的自动助理 return fallback_reply6. 主程序与完整工作流最后我们将所有组件串联起来形成一个可以定时运行或由事件触发的完整邮件处理流水线。# main.py import time import logging from mail_client import EmailClient from agent_core import EmailAgent from config import Config logging.basicConfig(levellogging.INFO, format%(asctime)s - %(name)s - %(levelname)s - %(message)s) logger logging.getLogger(__name__) def main_loop(poll_interval_seconds60): 主循环定期检查邮件并处理 logger.info(Starting Email Agent...) # 初始化组件 mail_client EmailClient() agent EmailAgent(Config.EMAIL_ACCOUNT) logger.info(fAgent initialized for {Config.EMAIL_ACCOUNT}. Polling every {poll_interval_seconds} seconds.) try: while True: logger.info(Checking for new emails...) # 1. 获取未读邮件 unread_emails mail_client.fetch_unread_emails(limit5) if not unread_emails: logger.info(No new unread emails.) else: logger.info(fFound {len(unread_emails)} new email(s).) for email_info in unread_emails: sender email_info[from] subject email_info[subject] body email_info[body] email_id email_info[id] # 2. 使用智能体处理邮件生成回复 logger.info(fProcessing email from {sender}) reply_body agent.process_email(sender, subject, body) # 3. 发送回复 if reply_body: # 在实际回复中可以获取原始邮件的Message-ID作为In-Reply-To success mail_client.send_reply(email_info, reply_body) if success: logger.info(fSuccessfully sent reply to {sender}) # 4. 将邮件标记为已读可选根据业务逻辑决定 mail_client.mark_as_read(email_id) else: logger.error(fFailed to send reply to {sender}) else: logger.warning(fAgent generated empty reply for email from {sender}. Skipping.) # 等待下一次轮询 time.sleep(poll_interval_seconds) except KeyboardInterrupt: logger.info(Shutdown signal received. Stopping agent.) except Exception as e: logger.error(fUnexpected error in main loop: {e}, exc_infoTrue) if __name__ __main__: # 验证配置 Config.validate() # 启动主循环每120秒检查一次 main_loop(poll_interval_seconds120)7. 运行、测试与常见问题7.1 如何运行填写配置将你的OpenAI API密钥和邮箱配置使用应用专用密码填入.env文件。安装依赖确保在虚拟环境中执行pip install -r requirements.txt。运行程序在项目根目录下执行python main.py。程序将开始轮询你的收件箱处理未读邮件并自动回复。7.2 测试你的智能体为了安全测试建议先创建一个专门的测试邮箱或者修改代码使其不实际发送邮件而是将回复打印到控制台。可以修改main.py中的发送逻辑# 在 main.py 的循环中注释掉发送行改为打印 # success mail_client.send_reply(email_info, reply_body) print(f\n 拟发送给 {sender} 的回复 \n) print(reply_body) print(\n 回复结束 \n) # mail_client.mark_as_read(email_id) # 也暂时注释掉7.3 常见问题与排查问题现象可能原因解决思路无法连接到IMAP服务器1. 网络问题。2. 邮箱配置错误服务器地址、端口。3. 未开启IMAP服务Gmail需在设置中开启。4. 使用密码错误Gmail需使用应用专用密码而非登录密码。1. 检查网络。2. 核对.env中的IMAP_SERVER和IMAP_PORT。3. 登录网页邮箱在设置中开启“IMAP”。4. 为Gmail生成16位应用专用密码。OpenAI API调用失败1. API密钥错误或过期。2. 网络问题或OpenAI服务中断。3. 达到速率限制或额度耗尽。1. 检查.env中的OPENAI_API_KEY。2. 访问OpenAI状态页检查服务状态。3. 登录OpenAI控制台检查额度和用量。ChromaDB持久化错误1. 存储路径storage/chroma_db权限不足。2. 不同版本ChromaDB的兼容性问题。1. 确保程序对存储目录有读写权限。2. 尝试删除storage/目录让程序重新创建。代理陷入循环或回复无关1. 提示词system_prompt不够清晰。2. 工具描述不准确导致LLM误用。3.max_iterations设置过高。1. 细化系统提示词明确边界和回复格式。2. 检查工具的描述 (description) 是否清晰无歧义。3. 将max_iterations调低如设为3。处理速度慢1. 网络延迟。2. LLM生成回复耗时。3. 向量数据库搜索耗时。1. 考虑使用异步IO (asyncio) 优化网络请求。2. 换用更快的LLM模型如gpt-3.5-turbo。3. 限制向量搜索返回的数量 (k参数)。8. 最佳实践与进阶优化方向构建一个可用于生产环境的邮件智能体还需要考虑以下方面8.1 安全与隐私最小权限原则邮箱账户使用应用专用密码并定期更换。内容过滤在处理前过滤掉明显敏感如含密码、银行卡号或垃圾邮件的内容。数据加密长期记忆中的对话内容应考虑加密存储尤其是涉及个人或商业信息时。人工审核对于重要邮件或智能体置信度低的回复应转入待审核队列而非直接发送。8.2 性能与稳定性异步处理使用asyncio或任务队列如 Celery处理邮件避免主循环阻塞。错误重试与降级对API调用如OpenAI、邮件服务器实现指数退避的重试机制。主逻辑必须有降级方案如返回固定模板回复。监控与日志记录每封邮件的处理状态、耗时、使用的工具和最终回复便于问题追踪和效果分析。向量数据库优化对于大量记忆考虑使用云向量数据库如Pinecone并建立高效的索引策略。8.3 记忆系统增强记忆摘要长时间的会话会占用大量上下文窗口。可以定期使用LLM对旧会话进行摘要将摘要存入长期记忆原始细节可归档。记忆更新与遗忘实现记忆的“衰减”或主动清理机制删除过时或无用的信息。多维度记忆除了对话内容还可以记忆用户偏好如喜欢何时开会、常用称呼、项目状态等结构化信息。8.4 工具扩展知识库查询集成RAG检索增强生成让智能体能够从公司文档、FAQ中查找信息再回复。任务创建与Jira、Trello、Asana等项目管理工具集成将邮件请求转化为任务。信息查询连接CRM系统在回复客户时附带其历史订单或支持工单状态。8.5 工作流编排进阶使用LangGraph对于更复杂的、有状态的工作流如需要多轮确认的预约流程可以使用LangGraph来精确控制状态转移和工具调用顺序。条件分支根据邮件分类咨询、投诉、会议请求进入不同的处理子流程。多智能体协作可以设计专门的“分类智能体”、“信息提取智能体”、“回复生成智能体”进行流水线作业。通过本文的实践你已经掌握了一个具备记忆和自动回复能力的邮件智能体的核心构建方法。从基础的邮件收发、记忆存储与检索到利用LangChain构建可调用工具的智能体最终形成一个完整的自动化流程。这个原型系统为你打下了坚实的基础你可以根据实际业务需求在安全、性能、功能和用户体验等多个维度上进行深化和扩展打造出真正属于自己的高效邮件处理助手。