用 mitmproxy 重定向 OpenAI 请求到 OpenRouter

- LLM 网络

背景

最近在尝试使用一些基于 GPT 开发的工具,但遇到了一些网络相关的小问题。因为支付方式的限制,我自己并没有 OpenAI 的账户,实际使用的 API 是其他中间商(aka 二道贩子)转卖而来的, OpenRouter 就是其中一家。(实际上 OpenRouter 做的还更多一些,更像是 LLM 的聚合提供商,除了 OpenAI 也有其他家的 LLM,如 Claude 或是 LLama。)但是很多开源工具并未考虑到这种情况,基本上都是假定用户使用的就是 OpenAI 的官方 API 端点,所以很多时候并不能直接使用各类预先构建好的产物(例如 docker 镜像),而是得把源码 clone 下来,找到 import openai 或者是类似的调用发起位置,再在附近补充一些参数才能正常使用。手动改代码固然不是不行,但是总归还是有些繁琐,出问题的时候还额外增加了一个需要排查的环节。

问题

有没有更好的,更自动化的方式,例如在网络上加个代理层,在第三方工具无需修改的前提下,就可以将 OpenAI 的请求转换成 OpenRouter 的请求呢?

解决

那既然都写到这里了,当然是有的。这里的核心是一个 man-in-the-middle (mitm / 中间人)代理,在请求到达代理的时候,修改请求中的内容,使之符合我们的要求,之后再继续对外发送就可以了。mitmproxy 就是这样一个工具。当然它的功能远不止修改请求,在完善的 Python API 的加成下还能做很多其他的事。(同类的工具其他工具,如 Fiddler,应该也能实现,但方法就需要给位自行探索了。)以下就是实现本次需求的核心代码,应该不需要太多解释。

import json
from mitmproxy import http

def request(flow: http.HTTPFlow) -> None:
    # 只处理 HOST 为 api.openai.com,且请求体为 JSON 的 POST 请求
    if flow.request.host == "api.openai.com" and flow.request.method == "POST" and flow.request.headers.get("content-type", "").startswith("application/json"):
        try:
            flow.request.host = "openrouter.ai"
            flow.request.path = "/api/v1/chat/completions"
            flow.request.headers["authorization"] = "Bearer sk-xxxxxxxxxx" # token
            flow.request.headers["http-referer"] = "http://localhost:8080/my_great_app" # 应用标识
            request_data = json.loads(flow.request.get_text())

            # 甚至可以在这里切换模型
            # request_data["model"] = "anthropic/claude-instant-v1"

            flow.request.set_text(json.dumps(request_data))
            pass
        except json.JSONDecodeError:
            pass

# 需要声明回包支持 stream,否则会等待全部数据到达再返回给应用,无法实现 LLM 打字效果
def responseheaders(flow):
    flow.response.stream = True

启动 mitmproxy 时需要带上 Python 脚本参数,以及如果有上游代理则需要再声明:

mitmweb --mode upstream:http://{upstream_addr} -s openrouter.py

启动后会弹出 mitmproxy 的网页控制台,这时候就用第三方工具发请求试试了,一切顺利的话可以看到结果正常返回且网页上显示请求数据。如果出现问题也可以看命令行窗口的输出。如果第三方工具本身支持设置应用内代理(如 Chatbox)则最理想;不支持的话可以考虑设置系统代理、用 mitmproxy 的透明代理模式、或者用 Proxifer 这类工具来强制应用代理。