技术背景
想必最近有在部署DeepSeek大模型的人,看标题就知道这篇文章在做什么事情了。由于Ollama对于IP的监听缺乏安全防护,并且内网部署的Ollama模型对于外网来说也是不可见的,而如果使用一些公网API,又存在隐私数据泄露的风险。这里提供一个方案:使用端到端加密的通讯软件,将消息内容转为token传输给Ollama本地部署的模型,然后接收token作为消息,通过加密通讯返回给用户。但是考虑到加密通讯软件的用户群体并不是很大,这里仅仅使用Slack作为一个演示。需要注意的是,Slack公司也有自己的AI模型SlackAI,在用户数据安全防护这一块有多大的可靠性,留给大家自行判断。
Slack应用注册流程
我们先假定你已经有一个Slack账号和相应的Slack工作区了,那么可以进入到app界面去创建一个自己的应用:
我选择的是scratch创建模式:
这样就能在网页界面上进行配置。选择好自己的工作区,配置该机器人在工作区中的名字:
创建完成后大概是这样的:
然后可以进入到APP的设置界面:
要打开Socket模式:
权限配置在Event Subscriptions和OAuth & Permissions中:
但是权限配置这一块需要后面单独开一个章节,请继续往下看。配置完成后,可以把应用安装到自己的工作区:
安装完成后,打开本地的Slack客户端,找到应用-添加应用,在列表中属于该工作区的应用会排在最前面,可以直接将其加入工作区:
这样以后就可以在应用列表看到自己定义的应用了。
关键信息
Slack应用创建之后,有几个关键的tokens信息(可以自己在Slack APP网页找到相关的字符串)需要保存到本地:
- SLACK_BOT_TOKEN,是一串xoxb-开头的字符串,用QAuth&
ermissions里面的Bot User OAuth Token;
- SLACK_APP_TOKEN,是一串xapp-开头的字符串,从Basic Information里面的APP Level Tokens里面找,注意权限配置;
- SLACK_SIGNING_SECRET,是一串普通的随机字符串,从Basic Information里面找。
关键配置
想要正常的使用SlackBot,有几个关键的权限配置,如果权限配置错误,会导致SlackBot无法正确的读取消息或者正确地对消息进行反应。
首先是APP Level Tokens的配置(参考这里的ChatBotApp里面的配置):
然后是Event Subscriptions中的配置信息:
最后是两个QAuth& ermissions的配置参数:
需要注意的是,这些都是个人配置信息,仅供参考。
slack_bolt环境配置
slack_bolt可以允许你从本地Python启动服务,调用SlackBot的API,监听Slack应用程序中的对话,并且可以按照不同的权限跟用户进行对话。可以使用pip安装slack_bolt:- $ python3 -m pip install slack_bolt
- Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
- Collecting slack_bolt
- Downloading https://pypi.tuna.tsinghua.edu.cn/packages/5d/2d/fb23c998c43ff8398d7fa1e58bb82e7e735fbdaa0bd4ddaac04b3865bd4c/slack_bolt-1.22.0-py2.py3-none-any.whl (229 kB)
- Collecting slack_sdk<4,>=3.33.5 (from slack_bolt)
- Downloading https://pypi.tuna.tsinghua.edu.cn/packages/25/2d/8724ef191cb64907de1e4e4436462955501e00f859a53d0aa794d0d060ff/slack_sdk-3.34.0-py2.py3-none-any.whl (292 kB)
- Installing collected packages: slack_sdk, slack_bolt
- Successfully installed slack_bolt-1.22.0 slack_sdk-3.34.0
复制代码 然后根据前面重要配置信息中提到的,配置Token:- # export SLACK_BOT_TOKEN=xxx
- # export SLACK_APP_TOKEN=xxx
- # export SLACK_SIGNING_SECRET=xxx
复制代码 先测试一个简单的Python脚本:- import os
- from slack_bolt import App
- from slack_bolt.adapter.socket_mode import SocketModeHandler
- # Install the Slack app and get xoxb- token in advance
- app = App(token=os.environ["SLACK_BOT_TOKEN"])
- if __name__ == "__main__":
- SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
复制代码 运行效果:- $ python3 slack_chatbot.py
- ⚡️ Bolt app is running!
复制代码 这就表示本地SlackBot安装成功了,当然,这个程序本身没有附带任何的功能。可以稍微升级一下SlackBot的测试功能:- import os
- from slack_bolt import App
- from slack_bolt.adapter.socket_mode import SocketModeHandler
- # Initializes your app with your bot token and socket mode handler
- app = App(token=os.environ.get("SLACK_BOT_TOKEN"), signing_secret=os.environ.get("SLACK_SIGNING_SECRET"))
- # Listens to incoming messages that contain "hello"
- # To learn available listener arguments,
- # visit https://tools.slack.dev/bolt-python/api-docs/slack_bolt/kwargs_injection/args.html
- @app.message("hello")
- def message_hello(message, say):
- # say() sends a message to the channel where the event was triggered
- say(f"Hey there <@{message['user']}>!")
- @app.event("app_mention")
- def handle_mentions(event, say):
- say(text="Hello!", channel=event["channel"])
- # Start your app
- if __name__ == "__main__":
- SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
复制代码 在这个案例中,我们的程序会对一个事件和一个关键词起反应。例如我们只@slackbot的话,会返回一个hello:
如果@slackbot并且带上指定的字符串,那么就会做出相应的特别处理:
SlackBot对接Ollama模型
在上述章节中已经完成了本地通信的一些配置,接下来我们可以把SlackBot对接到Ollama模型中,原理也很简单:触发SlackBot之后,将消息作为token转发给Ollama的API,然后等待回复再回传给Slack聊天界面。这就是我做的一个简单的框架,接下来看看具体实施。
首先安装Ollama通信相关依赖:- $ python3 -m pip install requests python-dotenv
复制代码 直接上D老师给的代码:
[code]import osimport reimport requestsfrom slack_bolt import Appfrom slack_bolt.adapter.socket_mode import SocketModeHandlerfrom dotenv import load_dotenv# 加载环境变量load_dotenv()# 初始化 Slack 应用app = App( token=os.environ["SLACK_BOT_TOKEN"], signing_secret=os.environ["SLACK_SIGNING_SECRET"])# Ollama 配置(可通过环境变量覆盖)OLLAMA_ENDPOINT = os.getenv("OLLAMA_ENDPOINT", "http://localhost:11434/api/generate")OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "deepseek-r1:14b")OLLAMA_PARAMS = { "num_ctx": int(os.getenv("OLLAMA_NUM_CTX", 4096)), "num_gpu": int(os.getenv("OLLAMA_NUM_GPU", 64)), "keep_alive": os.getenv("OLLAMA_KEEP_ALIVE", "2h")}def query_ollama(prompt: str) -> str: """向 Ollama 发送请求并获取完整响应""" payload = { "model": OLLAMA_MODEL, "prompt": f"请先输出思考过程(用THINKING:开头),再输出最终答案(用ANSWER:开头):\n\n{prompt}", "stream": False, # "options": OLLAMA_PARAMS } try: response = requests.post(OLLAMA_ENDPOINT, json=payload, timeout=6000) response.raise_for_status() return response.json()["response"] except Exception as e: return f"Ollama 请求失败: {str(e)}"def format_slack_response(raw_response: str) -> str: """将原始响应分割为思考过程和最终答案""" thinking_match = re.search(r"THINKING .*?)(ANSWER:|\Z)", raw_response, re.DOTALL) answer_match = re.search(r"ANSWER .*)", raw_response, re.DOTALL) thinking = thinking_match.group(1).strip() if thinking_match else "未提供思考过程" answer = answer_match.group(1).strip() if answer_match else raw_response return ( f"*
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |