飞书智能自动回复系统 – 技术文档
1. 系统概述
1.1 项目背景
本系统是一个基于飞书开放平台的智能自动回复系统,通过集成本地大语言模型(LM Studio),实现飞书群聊消息的自动获取、智能回复和状态管理。
1.2 核心功能
- 消息同步
:自动从飞书群聊获取历史消息 - 数据存储
:将消息持久化到 SQLite 数据库 - 智能回复
:调用本地大语言模型生成回复 - 状态管理
:跟踪消息处理状态(未回复/正在回复/已回复) - 指令控制
:支持通过飞书消息控制回复格式
1.3 技术栈
- 后端语言
:Python 3.x - 数据库
:SQLite3 - API 框架
:Requests(HTTP 客户端) - 大模型
:LM Studio(本地部署) - 开放平台
:飞书开放平台
2. 系统架构
2.1 整体架构图
┌─────────────────────────────────────────────────────────────────┐
│ 飞书智能自动回复系统 │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 飞书API │◄──►│ 核心业务 │◄──►│ 本地模型 │ │
│ │ 客户端 │ │ 逻辑层 │ │ 客户端 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ SQLite 数据库 │ │
│ │ (消息存储、状态管理、历史记录) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
2.2 核心组件
2.2.1 FeishuAPI 类
职责:封装飞书开放平台 API 调用
核心方法:
get_access_token()
:获取应用访问令牌 get_chat_messages()
:分页获取群聊消息 send_message()
:发送消息到群聊
分页逻辑:
while has_more and page_count < max_pages:
# 请求当前页数据
response = requests.get(url, params=params, headers=headers)
# 处理响应数据
all_messages.extend(messages)
# 更新分页参数
params["page_token"] = data.get("data", {}).get("page_token", "")
page_count += 1
2.2.2 DatabaseManager 类
职责:SQLite 数据库操作和状态管理
数据表结构:
CREATE TABLE feishu_messages_full (
id INTEGERPRIMARY KEY AUTOINCREMENT,
message_id TEXT UNIQUENOT NULL, -- 消息唯一标识
root_id TEXT, -- 根消息ID(用于回复链)
parent_id TEXT, -- 父消息ID
chat_id TEXT, -- 群聊ID
create_time INTEGER, -- 创建时间戳(毫秒)
create_time_str TEXT, -- 创建时间(可读格式)
update_time INTEGER, -- 更新时间戳
update_time_str TEXT, -- 更新时间(可读格式)
msg_type TEXT, -- 消息类型
deleted INTEGERDEFAULT0, -- 是否删除
content TEXT, -- 解析后的消息内容
body_content TEXT, -- 原始消息内容
sender_id TEXT, -- 发送者ID
sender_type TEXT, -- 发送者类型(user/app)
sender_id_type TEXT, -- ID类型
tenant_key TEXT, -- 租户标识
mentions TEXT, -- @提及信息(JSON)
reactions TEXT, -- 表情回复(JSON)
is_replying INTEGERDEFAULT0, -- 是否正在回复
is_replied INTEGERDEFAULT0, -- 是否已回复
reply_content TEXT, -- 回复内容
reply_time TIMESTAMP, -- 回复时间
reply_message_id TEXT, -- 回复消息ID
inserted_at TIMESTAMP, -- 插入时间
updated_at TIMESTAMP-- 更新时间
);
状态流转:
未回复 (is_replying=0, is_replied=0)
↓
正在回复 (is_replying=1, is_replied=0)
↓
已回复 (is_replying=0, is_replied=1, reply_content=内容)
2.2.3 LocalModelClient 类
职责:本地大语言模型客户端
API 调用:
POST /v1/chat/completions
{
"model": "qwen/qwen3-8b",
"messages": [
{"role": "system", "content": "系统提示"},
{"role": "user", "content": "用户消息"}
],
"temperature": 0.7,
"max_tokens": 1000
}
重试机制:
max_retries = 3
for attempt inrange(max_retries):
reply = self.model_client.chat_completion(messages)
if reply:
break
if attempt < max_retries - 1:
time.sleep(2) # 等待2秒后重试
3. 核心流程
3.1 主循环流程
┌─────────────┐
│ 启动系统 │
└──────┬──────┘
▼
┌─────────────┐
│ 初始化配置 │
│ - 加载config │
│ - 初始化DB │
└──────┬──────┘
▼
┌─────────────┐ ┌──────────────────┐
│ 同步飞书消息 │◄────│ 每30秒循环一次 │
│ - 获取token │ └──────────────────┘
│ - 分页获取 │ ▲
│ - 写入数据库 │ │
└──────┬──────┘ │
▼ │
┌─────────────┐ │
│ 处理未回复 │ │
│ - 查询10分钟内│ │
│ 未回复消息 │ │
│ - 排除机器人 │ │
└──────┬──────┘ │
▼ │
┌─────────────┐ │
│ 生成智能回复 │ │
│ - 调用模型 │ │
│ - 重试3次 │ │
│ - 过滤标签 │ │
└──────┬──────┘ │
▼ │
┌─────────────┐ │
│ 发送回复 │ │
│ - 发送到飞书 │ │
│ - 更新数据库 │──────────────┘
└─────────────┘
3.2 消息处理详细流程
3.2.1 消息获取与过滤
# 1. 分页获取消息(最多10页,每页50条)
messages = feishu_api.get_chat_messages(chat_id, page_size=50, max_pages=10)
# 2. 反转消息顺序(最新的在前)
messages.reverse()
# 3. 过滤条件
- 排除 sender_type = "app" 的消息(机器人消息)
- 检查 message_id 是否已存在于数据库
3.2.2 未回复消息查询
# 查询条件
SELECT * FROM feishu_messages_full
WHERE (reply_content IS NULL OR reply_content = '')
AND sender_type = 'user'# 只处理用户消息
AND create_time >= ? # 10分钟内的消息
AND is_replying = 0# 不在处理中
ORDER BY create_time ASC # 按时间先后顺序
LIMIT 5# 最多5条
3.2.3 智能回复生成
# 1. 构建对话历史
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": "用户: {content}"}
]
# 2. 调用模型(带重试)
for attempt inrange(3):
reply = model_client.chat_completion(messages)
if reply:
break
time.sleep(2)
# 3. 标签过滤(根据 show_think 标志)
ifnot show_think:
reply = re.sub(r'<think>.*?</think>', '', reply, flags=re.DOTALL)
4. 配置说明
4.1 配置文件结构
{
"feishu":{
"app_id":"cli_xxxxx",// 飞书应用ID
"app_secret":"xxxxx",// 应用密钥
"chat_id":"oc_xxxxx"// 群聊ID
},
"model":{
"url":"http://127.0.0.1:1234",// LM Studio 服务地址
"api_key":"sk-local",// API密钥
"name":"qwen/qwen3-8b"// 模型名称
},
"chat":{
"poll_interval":30,// 轮询间隔(秒)
"max_history":10,// 最大历史消息数
"system_prompt":"...",// 系统提示词
"message_time_window":35// 消息时间窗口(分钟)
}
}
4.2 环境要求
-
Python 3.8+ -
SQLite3 -
LM Studio(本地运行) -
飞书应用(已开通消息读取和发送权限)
5. 指令系统
5.1 控制指令
| 指令 | 功能 | 权限 | |——|——|——| | /showthink | 显示 <think> 标签内容 | 所有用户 | | /hidethink | 隐藏 <think> 标签内容 | 所有用户 | | /thinkstatus | 查询当前标签显示状态 | 所有用户 |
5.2 指令处理逻辑
content_lower = content.lower().strip()
if content_lower == "/showthink":
show_think = True
send_message("✅ 已开启 <think> 标签显示")
elif content_lower == "/hidethink":
show_think = False
send_message("✅ 已关闭 <think> 标签显示")
elif content_lower == "/thinkstatus":
status = "开启"if show_think else"关闭"
send_message(f"📊 当前 <think> 标签显示状态: {status}")
5.3 默认行为
- 默认状态
: /hidethink(隐藏思考标签) -
正常消息默认按照 /hidethink方式处理
6. 错误处理
6.1 模型调用失败
try:
reply = model_client.chat_completion(messages)
ifnot reply:
# 重试3次
for attempt inrange(3):
reply = model_client.chat_completion(messages)
if reply:
break
time.sleep(2)
ifnot reply:
# 发送失败提示
send_message("抱歉,我暂时无法生成回复,请稍后再试 😔")
except Exception as e:
logger.error(f"模型调用异常: {e}")
6.2 数据库锁定
retry_count = 0
while retry_count < max_retries:
try:
conn = sqlite3.connect(db_name, timeout=10.0)
# 执行操作
conn.commit()
returnTrue
except sqlite3.Error as e:
if"locked"instr(e).lower():
retry_count += 1
time.sleep(0.5 * retry_count) # 指数退避
else:
raise
6.3 API 令牌失效
defget_access_token(self):
# 检查token是否有效(提前5分钟刷新)
ifself.access_token andself.token_expire_time:
if datetime.now().timestamp() < self.token_expire_time - 300:
returnself.access_token
# 重新获取token
response = requests.post(url, json=payload)
# 更新token和过期时间
7. 数据库设计
7.1 索引设计
-- 主键索引
CREATE INDEX idx_message_id ON feishu_messages_full(message_id);
-- 查询优化索引
CREATE INDEX idx_sender_id ON feishu_messages_full(sender_id);
CREATE INDEX idx_create_time ON feishu_messages_full(create_time);
CREATE INDEX idx_is_replied ON feishu_messages_full(is_replied);
CREATE INDEX idx_is_replying ON feishu_messages_full(is_replying);
7.2 数据保留策略
-
消息数据:永久保留 -
回复内容:永久保留 -
状态标记:实时更新
8. 性能优化
8.1 分页策略
-
每页获取 50 条消息 -
最多获取 10 页(500 条消息) -
页间延迟 0.5 秒,避免请求过快
8.2 数据库优化
-
使用连接池(上下文管理器) -
批量插入替代单条插入 -
合理使用索引加速查询
8.3 缓存策略
-
Token 缓存(提前 5 分钟刷新) -
消息去重检查(基于 message_id)
9. 安全考虑
9.1 数据脱敏
-
配置文件中的敏感信息(app_id, app_secret)需要妥善保管 -
日志中不输出完整的消息内容(仅输出前 100 字符) -
数据库文件设置适当权限
9.2 访问控制
-
飞书应用需要配置 IP 白名单 -
API 调用频率限制 -
Token 定期刷新机制
10. 部署与运维
10.1 启动方式
python feishu_auto_reply.py
10.2 停止方式
-
按 Ctrl+C优雅停止 -
系统会自动完成当前轮询后退出
10.3 日志监控
-
日志文件: feishu_auto_reply.log -
日志级别:INFO -
关键指标: -
消息同步数量 -
模型调用成功率 -
回复发送成功率
10.4 健康检查
# 系统状态统计
{
"total_messages": 54, # 总消息数
"unreplied": 34, # 未回复数
"replying": 1, # 正在回复数
"replied": 19# 已回复数
}
11. 扩展性设计
11.1 多群聊支持
可通过修改配置支持多个群聊:
CHAT_IDS = ["chat_id_1", "chat_id_2", "chat_id_3"]
for chat_id in CHAT_IDS:
process_chat(chat_id)
11.2 多模型支持
可通过配置切换不同模型:
{
"model":{
"provider":"lmstudio",// 或 "openai", "anthropic"
"name":"qwen/qwen3-8b"
}
}
11.3 插件系统
预留扩展接口:
defprocess_with_plugin(message, plugin_name):
plugin = load_plugin(plugin_name)
return plugin.process(message)
12. 附录
12.1 术语表
| 术语 | 说明 | |——|——| | message_id | 飞书消息唯一标识 | | sender_type | 发送者类型(user/app) | | is_replying | 消息是否正在处理中 | | is_replied | 消息是否已回复 | | reply_content | 模型生成的回复内容 | | show_think | 是否显示思考标签 |
12.2 相关文档
- 飞书开放平台文档
- LM Studio API 文档
- SQLite 文档
夜雨聆风
