Qwen1.5-1.8B-GPTQ-Int4 Chainlit集成:对接企业微信/钉钉机器人通知系统
本文介绍了如何在星图GPU平台上自动化部署通义千问1.5-1.8B-Chat-GPTQ-Int4镜像,并实现与Chainlit前端及企业微信/钉钉机器人的集成。该方案能将轻量级大语言模型快速转化为具备主动通知能力的智能助手,典型应用场景包括在完成长文本总结或报告生成等任务后,自动向用户发送消息通知,从而提升工作效率。
Qwen1.5-1.8B-GPTQ-Int4 Chainlit集成:对接企业微信/钉钉机器人通知系统
1. 引言:当AI助手遇上企业通讯
想象一下这个场景:你部署了一个轻量级的AI助手,它正在后台默默处理着各种文本任务。突然,一个重要的任务完成了,或者系统遇到了一个需要你立刻关注的错误。这时候,你是希望每隔几分钟就去刷新一下页面查看状态,还是希望AI助手能主动“敲敲你的门”,通过你每天都会打开的企业微信或钉钉,直接把消息推送到你的手机上?
这就是我们今天要解决的问题。基于vLLM部署的Qwen1.5-1.8B-Chat-GPTQ-Int4模型,配合Chainlit的友好前端,已经能提供一个不错的对话体验。但要让这个AI助手真正融入我们的日常工作流,让它变得“主动”起来,与企业的即时通讯工具打通是至关重要的一步。
本文将带你一步步实现这个目标:为你的Qwen1.5模型和Chainlit应用,集成企业微信或钉钉的机器人通知系统。无论模型生成了重要的结果,还是应用运行出现了异常,你都能第一时间在手机上收到通知。整个过程不复杂,但非常实用,能显著提升AI应用的可用性和响应效率。
2. 核心组件与准备工作
在开始动手之前,我们先快速了解一下要用到的几个核心部分,以及需要提前准备好的东西。
2.1 技术栈概览
我们的整个系统由几个关键部分组成,它们各自扮演着不同的角色:
- Qwen1.5-1.8B-Chat-GPTQ-Int4模型:这是我们AI能力的核心。它是一个经过量化(GPTQ-Int4)的大语言模型,体积小巧(约1.8B参数),推理速度快,非常适合在资源有限的环境下部署,提供高质量的文本生成和对话能力。
- vLLM推理引擎:这是模型的“发动机”。vLLM以其高效的PagedAttention等优化技术而闻名,能极大地提升大模型的服务吞吐量和推理速度,确保我们的AI助手响应迅速。
- Chainlit前端框架:这是用户与模型交互的“窗口”。它提供了一个类似ChatGPT的Web聊天界面,让调用模型变得像聊天一样简单直观。
- 企业微信/钉钉机器人:这是我们本次集成的“信使”。它们是企业通讯平台提供的开放接口,允许我们通过发送HTTP请求的方式,将消息推送到指定的群聊或对话中。
2.2 环境与账号准备
在写代码之前,请确保以下几件事已经就绪:
- 基础环境运行正常:你的Qwen1.5模型应该已经通过vLLM成功部署,并且Chainlit前端可以正常访问和调用。你可以通过之前提供的
cat /root/workspace/llm.log命令查看服务日志,确认模型加载成功。 - 获取机器人Webhook地址:这是集成的关键。你需要在你使用的企业通讯工具中创建一个“群机器人”或“自定义机器人”,并获取到它的Webhook URL。这个URL看起来像一串很长的、包含密钥的链接,它是机器人接收消息的唯一入口。
- 企业微信:在需要接收通知的群聊中,点击右上角
...->添加群机器人-> 创建后即可获得Webhook URL。 - 钉钉:在需要接收通知的群聊中,点击右上角
设置->智能群助手->添加机器人->自定义,创建后即可获得Webhook URL。 - 重要提示:请妥善保管这个URL,不要泄露到公开代码仓库中。
- 企业微信:在需要接收通知的群聊中,点击右上角
3. 构建通知发送模块
有了Webhook地址,我们就可以开始编写最核心的功能:一个能向机器人发送消息的Python模块。这个模块将作为我们Chainlit应用的“通知中心”。
3.1 创建通知工具函数
我们创建一个独立的Python文件,比如叫做 notifier.py。这个文件负责处理所有与消息推送相关的逻辑。
# notifier.py
import json
import requests
from typing import Dict, Any, Optional
import logging
# 配置日志,方便调试
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class RobotNotifier:
"""
企业微信/钉钉机器人通知器
由于两者消息格式高度相似,我们可以用一个类来兼容处理。
"""
def __init__(self, webhook_url: str, robot_type: str = "dingtalk"):
"""
初始化通知器
Args:
webhook_url: 机器人的Webhook地址
robot_type: 机器人类型,'dingtalk' 或 'wechat_work'
"""
self.webhook_url = webhook_url
self.robot_type = robot_type.lower()
self.session = requests.Session() # 使用Session保持连接
def send_text(self, content: str, at_all: bool = False, at_mobiles: list = None):
"""
发送纯文本消息
Args:
content: 要发送的文本内容
at_all: 是否@所有人(钉钉有效,企业微信需在内容中手动@all)
at_mobiles: 要@的特定手机号列表(钉钉)
"""
if self.robot_type == "dingtalk":
message = {
"msgtype": "text",
"text": {
"content": content
},
"at": {
"isAtAll": at_all,
"atMobiles": at_mobiles if at_mobiles else []
}
}
elif self.robot_type == "wechat_work":
# 企业微信的@all需要在content中手动添加
if at_all and "@all" not in content:
content += "\n<@all>"
message = {
"msgtype": "text",
"text": {
"content": content
}
}
else:
raise ValueError(f"不支持的机器人类型: {self.robot_type}")
return self._send_message(message)
def send_markdown(self, title: str, text: str, at_all: bool = False):
"""
发送Markdown格式消息,支持更丰富的排版
Args:
title: 消息标题(会显示在通知摘要里)
text: Markdown格式的正文
at_all: 是否@所有人
"""
if self.robot_type == "dingtalk":
message = {
"msgtype": "markdown",
"markdown": {
"title": title,
"text": text
},
"at": {
"isAtAll": at_all
}
}
elif self.robot_type == "wechat_work":
message = {
"msgtype": "markdown",
"markdown": {
"content": text # 企业微信markdown没有单独的title字段
}
}
# 企业微信markdown内@all
if at_all and "@all" not in text:
text += "\n<@all>"
message["markdown"]["content"] = text
else:
raise ValueError(f"不支持的机器人类型: {self.robot_type}")
return self._send_message(message)
def _send_message(self, message: Dict[str, Any]) -> Dict[str, Any]:
"""
内部方法:实际发送HTTP请求到Webhook
Args:
message: 符合机器人API要求的消息字典
Returns:
机器人API的响应结果
"""
headers = {'Content-Type': 'application/json'}
try:
# 注意:企业微信和钉钉的机器人API都要求JSON格式
response = self.session.post(
self.webhook_url,
data=json.dumps(message),
headers=headers,
timeout=10 # 设置超时,避免长时间等待
)
response.raise_for_status() # 如果状态码不是200,抛出异常
result = response.json()
logger.info(f"消息发送成功: {result}")
return result
except requests.exceptions.RequestException as e:
logger.error(f"发送消息失败: {e}")
# 在实际生产环境中,这里可以加入重试逻辑或降级处理
return {"errcode": -1, "errmsg": str(e)}
except json.JSONDecodeError as e:
logger.error(f"解析响应失败: {e}")
return {"errcode": -2, "errmsg": "Invalid JSON response"}
# 示例:创建一个全局的通知器实例(在实际应用中,配置应从环境变量或配置文件中读取)
# WEBHOOK_URL = "你的机器人Webhook地址"
# notifier = RobotNotifier(webhook_url=WEBHOOK_URL, robot_type="dingtalk")
这个类封装了发送文本和Markdown消息的基本功能,并对企业微信和钉钉的细微差异做了兼容处理。使用它非常简单:
# 示例用法
# from notifier import RobotNotifier
# notifier = RobotNotifier(WEBHOOK_URL, "dingtalk")
# notifier.send_text("AI模型处理完成啦!")
# notifier.send_markdown("任务报告", "### 模型推理完成\n- **任务ID**: 12345\n- **状态**: 成功\n- **耗时**: 2.3秒")
3.2 设计通知触发场景
有了发送消息的工具,接下来我们需要决定:在Chainlit应用的哪些环节触发通知?这里有几个非常实用的场景:
- 重要任务完成通知:当用户提交了一个复杂的、耗时的生成任务(比如生成长篇报告、总结多篇文档),任务完成后主动通知用户。
- 系统异常告警:如果模型服务(vLLM)意外宕机,或者Chainlit应用本身出现未捕获的异常,立即发送告警。
- 每日/每周使用报告:在固定时间点,统计当天或当周模型被调用的次数、平均响应时间等,形成简报发送。
- 特定关键词触发:当用户的问题中包含如“紧急”、“重要”、“请通知我”等关键词时,在回复的同时发送一条通知。
在本文中,我们将重点实现前两个最常用、最核心的场景。
4. 将通知集成到Chainlit应用中
现在,我们将上面创建的通知模块,与Chainlit应用深度集成。Chainlit提供了丰富的回调函数(Callback)和装饰器,让我们可以在对话生命周期的不同阶段插入自定义逻辑。
4.1 在Chainlit中初始化通知器
首先,我们需要在Chainlit的应用文件中(通常是 app.py 或 chainlit.md 所在的入口文件)初始化我们的通知器,并使其在应用上下文中可用。
# app.py (或你的Chainlit主文件)
import chainlit as cl
from notifier import RobotNotifier
import os
# 从环境变量中读取机器人配置,这样更安全,便于不同环境部署
WEBHOOK_URL = os.getenv("ROBOT_WEBHOOK_URL", "") # 默认值为空,如果没配置就不发通知
ROBOT_TYPE = os.getenv("ROBOT_TYPE", "dingtalk") # 默认钉钉
# 初始化通知器(如果配置了Webhook)
notifier = None
if WEBHOOK_URL:
try:
notifier = RobotNotifier(webhook_url=WEBHOOK_URL, robot_type=ROBOT_TYPE)
print(f"机器人通知器初始化成功,类型: {ROBOT_TYPE}")
except Exception as e:
print(f"初始化机器人通知器失败: {e}")
notifier = None
else:
print("未配置 ROBOT_WEBHOOK_URL,通知功能已禁用")
@cl.on_chat_start
async def on_chat_start():
"""
当新的聊天会话开始时触发。
这里我们可以把notifier存入用户会话中,方便后续使用。
"""
# 将notifier存入用户会话数据中
cl.user_session.set("notifier", notifier)
# 可选:发送一条聊天开始的欢迎通知(如果配置了通知)
if notifier:
# 使用异步方式发送,避免阻塞主流程
import asyncio
asyncio.create_task(
send_notification_async(notifier, "新的对话已开始", f"用户开始了与AI助手的对话。")
)
# 原有的初始化逻辑,比如设置系统提示词等
# await cl.Message(content="你好!我是你的AI助手。").send()
async def send_notification_async(notifier_obj, title, text):
"""一个简单的异步包装函数,用于在后台发送通知"""
# 注意:我们的RobotNotifier是同步的,这里用线程池来避免阻塞asyncio事件循环
import asyncio
from concurrent.futures import ThreadPoolExecutor
loop = asyncio.get_event_loop()
with ThreadPoolExecutor() as pool:
await loop.run_in_executor(
pool,
lambda: notifier_obj.send_markdown(title, text)
)
4.2 在消息处理完成后发送通知
接下来,我们可以在用户消息处理完成后,根据处理结果来决定是否发送通知。例如,当模型生成了一个特别长的回复,或者我们检测到回复内容非常重要时。
# 接上面的 app.py
@cl.on_message
async def on_message(message: cl.Message):
"""
处理用户发送的每一条消息。
"""
user_msg = message.content
notifier = cl.user_session.get("notifier") # 从会话中取出通知器
# 1. 先给用户一个“正在思考”的提示
msg = cl.Message(content="")
await msg.send()
# 2. 模拟调用你的Qwen1.5模型(这里需要替换成你实际的模型调用代码)
# 例如,如果你是通过API调用vLLM服务:
# model_response = await call_vllm_api(user_msg)
# 为了示例,我们模拟一个生成过程
import time
time.sleep(1) # 模拟推理耗时
# 假设这是模型生成的回复
simulated_response = f"这是针对您的问题『{user_msg}』的模拟回答。在实际应用中,这里应替换为调用vLLM部署的Qwen1.5模型的真实返回结果。"
# 3. 将模型的回复流式地发送给前端
for token in simulated_response:
await msg.stream_token(token)
await msg.update()
# 4. 判断是否触发“任务完成”通知
# 规则示例:如果用户输入包含“总结”或“报告”,或者生成的回复长度超过200字符,则发送通知
should_notify = False
notify_reason = ""
if "总结" in user_msg or "报告" in user_msg:
should_notify = True
notify_reason = "用户请求了总结/报告类任务"
elif len(simulated_response) > 200:
should_notify = True
notify_reason = "生成了较长篇幅的回复"
# 5. 如果满足条件且配置了通知器,则发送通知
if should_notify and notifier:
# 构建通知内容
notification_title = "AI任务处理完成"
notification_text = f"""
### 任务完成通知
**用户问题**: {user_msg[:50]}...
**处理结果**: 模型已生成回复。
**触发原因**: {notify_reason}
**回复长度**: {len(simulated_response)} 字符
**时间**: {time.strftime('%Y-%m-%d %H:%M:%S')}
"""
# 异步发送通知,不阻塞当前消息响应
import asyncio
asyncio.create_task(
send_notification_async(notifier, notification_title, notification_text)
)
4.3 捕获全局异常并发送告警
一个健壮的系统还需要有异常处理机制。我们可以设置一个全局的异常处理器,当应用发生未捕获的错误时,自动发送告警通知。
# 接上面的 app.py
import traceback
@cl.on_error
async def on_error(error: Exception):
"""
Chainlit全局错误处理器。
当应用发生未捕获的异常时,会调用此函数。
"""
print(f"捕获到全局错误: {error}")
error_traceback = traceback.format_exc()
# 获取通知器(尝试从当前会话获取,如果失败则用全局的)
notifier = cl.user_session.get("notifier") if cl.user_session.get("notifier") else globals().get("notifier")
if notifier:
# 构建错误告警通知
alert_title = "⚠️ AI助手应用发生错误"
alert_text = f"""
### 系统异常告警
**错误类型**: {type(error).__name__}
**错误信息**: {str(error)[:200]}...
**发生时间**: {time.strftime('%Y-%m-%d %H:%M:%S')}
**错误详情(截取)**:
{error_traceback[:500]}...
请及时登录服务器查看完整日志。
"""
# 错误告警需要立即关注,这里我们同步发送(或使用更可靠的方式)
try:
# 对于告警,我们可以考虑直接同步发送,确保不丢失
notifier.send_markdown(alert_title, alert_text, at_all=True) # @所有人
except Exception as e:
print(f"发送错误告警通知失败: {e}")
# 给用户一个友好的错误提示
await cl.Message(
content="抱歉,处理您的请求时出了点问题。系统管理员已收到通知。请稍后再试或尝试简化您的问题。"
).send()
# 注意:这里我们打印了错误但并没有重新抛出,避免了Chainlit默认的错误页面。
# 根据你的需求,也可以选择不发送用户消息,或者进行其他处理。
5. 部署、测试与效果验证
代码写好了,现在让我们把它跑起来,看看效果如何。
5.1 配置与运行
-
设置环境变量:在运行Chainlit应用之前,通过环境变量配置你的机器人信息。
# Linux/macOS export ROBOT_WEBHOOK_URL="你的钉钉或企业微信机器人Webhook地址" export ROBOT_TYPE="dingtalk" # 或 "wechat_work" # Windows (PowerShell) $env:ROBOT_WEBHOOK_URL="你的Webhook地址" $env:ROBOT_TYPE="dingtalk" -
启动应用:像往常一样启动你的Chainlit应用。
chainlit run app.py -
验证通知器初始化:观察应用启动日志,应该能看到
机器人通知器初始化成功或未配置...通知功能已禁用的提示。
5.2 测试通知功能
打开Chainlit的Web界面,开始进行测试:
-
测试场景一:触发任务完成通知 输入一个包含“总结”二字的问题,或者等待一个模拟的“长回复”。发送后,稍等片刻,检查你的企业微信或钉钉群,应该会收到一条格式清晰的Markdown通知消息。
-
测试场景二:触发异常告警 为了安全测试,我们可以在代码中临时模拟一个错误。在
on_message函数中,在调用模型之前,手动抛出一个异常:if “触发错误” in user_msg: raise ValueError(“这是一个测试异常!”)然后向助手发送包含“触发错误”的消息。前端会收到友好提示,同时你的手机应该会收到一条@所有人的紧急告警通知。
5.3 实际效果展示
当一切配置正确后,你在企业通讯工具中收到的通知将会是这样的:
钉钉通知效果:
AI任务处理完成
任务完成通知
用户问题: 请帮我总结一下本周的项目进展...
处理结果: 模型已生成回复。
触发原因: 用户请求了总结/报告类任务
回复长度: 450 字符
时间: 2024-01-15 14:30:25
企业微信通知效果: 消息会以卡片形式呈现,标题醒目,Markdown内容清晰易读。
这种主动推送的方式,让你无需守在电脑前刷新页面,就能随时掌握AI助手的工作状态,特别是在处理长时间任务或监控应用健康度时,效率提升非常明显。
6. 总结
通过本文的步骤,我们成功地将一个部署在vLLM上的轻量级Qwen1.5模型,从一个被动的“问答机”,升级为一个能够主动融入企业工作流的“智能助理”。核心在于利用Chainlit的回调机制和机器人Webhook,实现了 “状态主动上报” 和 “异常即时告警” 两大关键功能。
回顾一下我们完成的工作:
- 构建了通用的机器人通知模块,兼容了企业微信和钉钉,支持文本和Markdown消息。
- 将通知模块与Chainlit深度集成,在聊天开始、消息处理完成、应用发生错误等关键节点植入了通知逻辑。
- 设计了实用的触发场景,让通知变得有意义,而不是骚扰信息。
- 确保了代码的健壮性,通过环境变量管理敏感配置,并处理了异常情况。
你可以在此基础上继续扩展,例如增加更多触发规则(如敏感词监控)、发送更丰富的内容(如图片、链接),甚至将通知与你的业务系统(如工单系统、CRM)联动。让AI的能力,以更自然、更及时的方式,触达需要它的人。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐



所有评论(0)