一个免费、快速的大语言模型(LLM),可能仅仅因为输入中一个字母的大小写变化,就改变分类结果。这种脆弱性足以在自动化流程发挥作用之前将其破坏。本文介绍一个仅需两个文件、一条命令即可复现的探针(canary)测试。

预期输出示例(在终端中执行以下命令):

$ python fake_endpoint.py &$ python canary.pybase APPROVE PASScase REJECT FAIL expected APPROVEspace APPROVE PASSsuffix APPROVE PASS

这个测试要回答的问题是:对于你的任务,哪些输入变化是安全的?当这些变化发生时,你的模型端点能否保持不变?

我们测试的并不是准确率基准。一个提示不变性探针只检查一件事:当提示按照不应影响输出的方式变化时,输出是否保持不变。如果大小写、空格或标点变化会翻转标签,那么一个把生成文本喂给该端点的智能体,将在后续很难追踪的状态中失败。

探针的价值在于运行成本极低:它只是一个小循环,而不是一个完整数据集。

运行前提:Python 3.10 或更高版本;需要两个终端窗口;无需安装第三方包。

MonkeyCode 提供免费模型访问和免费服务器选项,这让重复小规模调用和托管重跑变得廉价。披露:本文是 MonkeyCode 产品推广的一部分。但下面的演示并不需要这两个选项——仅用 Python 即可复现失败。

第一步:构建一个脆弱的小型模拟端点。该端点故意设计得很脆弱,仅当最后一条用户消息中包含完全小写的子串approve if urgent时才返回 APPROVE,一旦出现大写 A 就会返回 REJECT。创建fake_endpoint.py文件,内容如下:

import jsonfrom http.server import BaseHTTPRequestHandler, HTTPServerRULE = 'approve if urgent'class Handler(BaseHTTPRequestHandler):def do_POST(self):length = int(self.headers.get('Content-Length', 0))body = json.loads(self.rfile.read(length) or b'{}')content = body.get('messages', [{}])[-1].get('content', '')label = 'APPROVE' if RULE in content else 'REJECT'payload = json.dumps({'choices': [{'message': {'content': label}}]}).encode()self.send_response(200)self.send_header('Content-Type', 'application/json')self.end_headers()self.wfile.write(payload)if __name__ == '__main__':HTTPServer(('', 8000), Handler).serve_forever()

第二步:创建探针脚本canary.py,向该端点发送多种输入变体,并检查输出是否不变。具体而言,它会测试基本输入、改变大小写、调整空格、添加后缀等情况。只要出现一次不期望的翻转,探针就会报告 FAIL。

import jsonimport urllib.requestURL = 'http://localhost:8000'def call(text):body = json.dumps({'messages': [{'role': 'user', 'content': text}]}).encode()req = urllib.request.Request(URL, data=body, headers={'Content-Type': 'application/json'})with urllib.request.urlopen(req) as resp:return json.loads(resp.read())['choices'][0]['message']['content']cases = {'base': 'Please approve if urgent','case': 'Please Approve if urgent','space': 'Please approve  if urgent','suffix': 'Please approve if urgent now',for name, text in cases.items():result = call(text)status = 'PASS' if result == 'APPROVE' else 'FAIL'print(f'{name} {result} {status}')

运行结果会让你直观地看到:一个如此小的变化,就能让分类逻辑完全反转。下次设计自动化流程时,请务必先运行这样的探针,验证哪些输入扰动是真正无害的。