[博客翻译]Show HN:用Ollama诱骗短信垃圾邮件发送者


原文地址:https://evan.widloski.com/software/sms_llm/


短信大语言模型(SMS LLM)

项目文件

我偶尔会收到一些房产经纪人的短信,他们想在我家乡购买特定的房产,而我在那里既没有房产也不居住。我猜他们是从白页(WhitePages)上抓取了手机号码,然后广撒网,希望能得到回复。
典型的垃圾短信
我父母在镇中心有一些未开发的土地,大部分位于洪水区,实际可用的面积比纸面上看起来要少得多。当然,经纪人并不知道这一点,所以购买一大块几十年来一直空置的土地,价格便宜,可能让他们垂涎三尺。
在圣诞节假期期间,我开发了一个系统,可以通过MQTT从运行Ollama的远程工作站控制我手机的短信应用程序。以下是系统的概述:

安卓手机         大语言模型服务器  
          +---------------+   |             
          | 短信应用程序 |   |            
 短信受害者 ------|   应用    |               
          +---------------+   |            
              |       |            
          +---------------+       +---------------+
          | 网关应用 |--------------| MQTT代理 |
          +---------------+       +---------------+
                      |        |    
                      |    +---------------+
                          |  llm.py   |
                      |    +---------------+
                      |        |    
                          +---------------+
                      |    | Ollama服务器 |
                      |    +---------------+

将短信传输到大语言模型

第一步是将短信以某种方式转发到大语言模型工作站。F-Droid和Play商店上都有几个短信转发工具,但大多数只支持通过POST请求将收到的短信单向转发到某个REST端点。我看到有一个应用程序支持将消息POST回手机,但由于手机位于CGLAN后面,我确实希望有一种与工作站保持长连接的方式。
最终我找到了一个名字很长的应用Android-SMS-Gateway-MQTT,它在后台运行,等待发送/接收消息,并且无需更改默认的短信应用程序。
出于某种原因,该应用程序可以通过MQTT发送消息,但接收到的消息只能通过POST请求转发。我做了一些修改,使MQTT可以双向通信。
我其实不太喜欢碰安卓开发,所以我尝试用Cursor.ai来修改代码,结果第一次就成功了!我使用的提示如下:

[SMSListener.java (41-46)]
如何将这个POST请求转换为MQTT消息?如果可能的话,我想使用文件`BackgroundService.java`中已经存在的MQTT连接。

修改后的网关应用
为了确保应用程序在后台可靠运行,必须禁用电池优化。幸运的是,该应用的功耗非常低。.apk文件可以在项目文件中找到。

Python脚本

Python脚本的任务很简单,就是监听MQTT上的新短信,并将生成的大语言模型响应发送回安卓应用程序。我希望语言模型能够根据上下文给出有意义的回复,因此我将每个正在进行的对话存储在一个单独的JSON文件中,并在生成响应时将最后N条消息提供给语言模型。

[
  {
    "role": "user",
    "content": "我忘记注册ece500了 :("
  },
  {
    "role": "assistant",
    "content": "兄弟,这太糟糕了,你跟教授谈过要加入吗?"
  },
  {
    "role": "user",
    "content": "啥"
  },
  {
    "role": "assistant",
    "content": "哈哈,你啥意思,你是想蹭课吗?"
  },
  {
    "role": "user",
    "content": "你好"
  },
  {
    "role": "assistant",
    "content": "嘿,最近咋样,我刚练完腿,现在浑身酸痛"
  },
  {
    "role": "user",
    "content": "好吧兄弟"
  }
]

对话的JSON日志
其中一大乐趣是能够创建各种荒谬的角色和背景故事。Python脚本从配置文件中读取,我可以为不同的对话分配不同的角色。
Ollama的TUI(终端用户界面)也使得实验不同的提示和更新这些角色变得非常方便。我甚至不需要重启脚本!

[evan@copernicus ~] ollama run llama3.3
>>> /set system "你是一个通过短信回复的大学生。你想卖掉你的房产。你只用单句回复,并使用千禧一代的俚语。你的回复非常简短,且不使用大写字母。你总是想卖东西。你写的所有内容都是小写的,你的房产正在出售。你应该愿意谈判,甚至可以接受低价"
设置系统消息。
>>> 嘿,我是[redacted]的Bob。我们想购买你在[redacted]附近的空地。你有兴趣接受一个合理的报价吗?
我在[redacted]的房产很棒,我愿意以不错的价格出售,给我个报价吧兄弟
>>> /save llama3.3bro

在Ollama shell中进行实验

图库

现在是你期待的部分!这些截图中的第一条消息是我写的,目的是在我将对话加入白名单后让对方回复。目前我只有这些聊天记录,但随着更多垃圾短信的到来,我可能会回来添加更多内容。
健身兄弟 英国绅士 Python脚本中的一个错误导致对一条短信生成了5个不同的回复,但对方似乎并不介意。

其他随想

  • 我最初使用Phi4进行这个项目,但很难让大语言模型的回复保持简短。切换到llama3.3后,这个问题有了很大改善。
  • 我不确定同意出售我甚至不拥有的土地会有什么法律后果,所以最近我指示模型不要真正达成任何交易。
  • 有人提到,回复垃圾短信有助于“预热”号码,建立运营商声誉,从而发送更多垃圾短信。我觉得在玩够了之后举报并屏蔽这些号码是一个合理的折衷方案。
  • 除了短信,我确实也会收到一些垃圾电话,但到目前为止我还没有注意到两者的数量有所增加。

Evan Widloski - 使用Legoman渲染