Skip to content

MamoWorks/notegpt-openai-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

NoteGPT OpenAI 兼容代理

Go Version API Streaming Tools Runtime

一个基于 Go 标准库实现的轻量级网关服务,用于将 NoteGPT 的聊天接口封装为 OpenAI 兼容 API。

服务接收标准 OpenAI Chat Completions 请求,将消息历史整理为单条上游提示词,请求 NoteGPT 的流式聊天接口,再将返回结果转换为 OpenAI 风格的 JSON 或 SSE 流式响应。对于上游原生不支持的函数调用,本项目在网关层提供了兼容型 tools / tool_choice shim,可对外返回标准 tool_calls。默认场景面向带本地 proxy-pool 的沙盒或网关部署环境。

项目特点

  • 提供标准化网关入口:
    • GET /healthz
    • GET /v1/models
    • POST /v1/chat/completions
  • 同时支持流式与非流式聊天补全
  • 支持 OpenAI toolstool_choiceparallel_tool_calls 的兼容型函数调用
  • 默认从本地 proxy-pool 动态拉取可用 HTTP 代理
  • 上游出现访客登录或额度类错误时自动切换出口并重试
  • 每次上游请求自动生成新的访客标识
  • 仅依赖 Go 标准库,部署简单,运行足迹小
  • 对外仅暴露规范模型名,不泄露内部上游模型值
  • 工具调用场景下自动将模型输出映射为标准 message.tool_calls

适用场景

  • 为 OpenAI SDK、OpenWebUI、SillyTavern、LangChain 等客户端提供兼容接入层
  • 将现有依赖 OpenAI Chat Completions 的应用快速接入 NoteGPT
  • 在多代理出口环境下构建轻量级模型网关
  • 为测试、联调或沙盒环境提供统一模型接口

接口能力

路径 方法 说明
/healthz GET 健康检查
/v1/models GET 返回公开模型列表
/v1/chat/completions POST OpenAI 兼容聊天接口,支持 stream=truetoolstool_choice

工作原理

请求处理链路如下:

  1. 客户端发送 POST /v1/chat/completions
  2. 网关解析模型名并转换为内部上游模型值
  3. proxy-pool 选择一个可用代理出口
  4. 将 OpenAI messages 压平成上游可接受的单条提示词
  5. 请求 NoteGPT 的 /api/v2/chat/stream
  6. 将上游事件流改写为 OpenAI JSON 或 SSE 输出
  7. 当请求携带 tools 时,在网关层执行函数调用提示词编排与 tool_calls 响应映射

支持模型

当前 /v1/models 对外公开的模型名如下:

  • basic
  • deepseek-r1
  • deepseek-v3
  • deepseek-v3.2
  • gemini-2.5-flash
  • gemini-3-flash
  • gemini-3.1-flash-lite
  • gpt-4.1-mini
  • gpt-4o-mini
  • gpt-5-mini

说明:

  • /v1/models 只显示对外规范模型名。
  • 服务内部仍保留对历史别名和上游原始模型值的兼容输入能力,避免破坏已有调用。
  • 未命中的模型名会继续透传到上游,是否可用取决于 NoteGPT 当前匿名访客策略。

快速开始

cd /root/notegpt-openai-proxy
go run .

默认监听地址为 :8099

配置说明

服务通过环境变量完成配置。

变量名 默认值 说明
LISTEN_ADDR :8099 HTTP 监听地址
API_KEY 网关 Bearer Token;为空时不鉴权
PROXY_POOL_URL http://127.0.0.1:8090/api/proxies 本地 proxy-pool API 地址
FIXED_PROXY_URL 固定使用单个出口代理,设置后跳过代理池
UPSTREAM_URL https://notegpt.io/api/v2/chat/stream NoteGPT 上游流式接口
DEFAULT_MODEL gemini-3.1-flash-lite-preview 请求未显式指定模型时的默认上游模型
RETRY_COUNT 3 最多跨代理重试次数
PROXY_COOLDOWN 10m 代理被判定失败后的冷却时间
NOTEGPT_LANGUAGE auto 上游请求中的 language 字段
NOTEGPT_TONE default 上游请求中的 tone 字段
NOTEGPT_LENGTH moderate 上游默认输出长度
NOTEGPT_CHAT_MODE standard 上游聊天模式

补充说明:

  • API_KEY 为空时,网关不校验客户端身份。
  • FIXED_PROXY_URL 设置后,服务不会再访问 proxy-pool
  • PROXY_POOL_URL 为空时,服务会直接访问上游。

启动方式

开发运行:

API_KEY=sk-demo go run .

编译二进制:

go build -o notegpt-openai-proxy .

生产环境示例:

LISTEN_ADDR=:8099 \
API_KEY=sk-demo \
PROXY_POOL_URL=http://127.0.0.1:8090/api/proxies \
./notegpt-openai-proxy

调用示例

查询模型列表

curl -s http://127.0.0.1:8099/v1/models \
  -H 'Authorization: Bearer sk-demo'

非流式聊天

curl -s http://127.0.0.1:8099/v1/chat/completions \
  -H 'Authorization: Bearer sk-demo' \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "basic",
    "stream": false,
    "messages": [
      {"role": "user", "content": "用一句话解释反向代理。"}
    ]
  }'

流式聊天

curl -N http://127.0.0.1:8099/v1/chat/completions \
  -H 'Authorization: Bearer sk-demo' \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "deepseek-v3.2",
    "stream": true,
    "messages": [
      {"role": "user", "content": "请只回答三个英文单词。"}
    ]
  }'

函数调用

curl -s http://127.0.0.1:8099/v1/chat/completions \
  -H 'Authorization: Bearer sk-demo' \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "deepseek-v3.2",
    "stream": false,
    "messages": [
      {"role": "user", "content": "北京现在天气怎么样?"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "查询指定城市的实时天气",
          "parameters": {
            "type": "object",
            "properties": {
              "city": {"type": "string"}
            },
            "required": ["city"]
          }
        }
      }
    ],
    "tool_choice": {
      "type": "function",
      "function": {"name": "get_weather"}
    }
  }'

返回示例:

{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_xxx",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"北京\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ]
}

工具结果回传示例:

curl -s http://127.0.0.1:8099/v1/chat/completions \
  -H 'Authorization: Bearer sk-demo' \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "deepseek-v3.2",
    "messages": [
      {"role": "user", "content": "北京现在天气怎么样?"},
      {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_weather_1",
            "type": "function",
            "function": {
              "name": "get_weather",
              "arguments": "{\"city\":\"北京\"}"
            }
          }
        ]
      },
      {
        "role": "tool",
        "tool_call_id": "call_weather_1",
        "content": "{\"city\":\"北京\",\"condition\":\"晴\",\"temperature_c\":24}"
      }
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "查询指定城市的实时天气",
          "parameters": {
            "type": "object",
            "properties": {
              "city": {"type": "string"}
            },
            "required": ["city"]
          }
        }
      }
    ],
    "tool_choice": "auto"
  }'

兼容性说明

尽管 /v1/models 仅返回规范模型名,服务仍兼容以下历史输入类型:

  • 旧版自定义别名
  • 内部上游原始模型值
  • 已存在客户端缓存中的旧模型名

这意味着你可以逐步迁移客户端到新的公开模型名,而不需要一次性切断旧调用。

工具调用支持

本项目支持 OpenAI Chat Completions 风格的以下工具调用字段:

  • tools
  • tool_choice
  • parallel_tool_calls
  • assistant.tool_calls
  • tool 角色消息与 tool_call_id

实现方式说明:

  • NoteGPT 上游并不直接返回 OpenAI 原生 tool_calls
  • 网关会将工具定义注入提示词,并要求模型按约定格式输出
  • 网关随后将该输出转换为标准 OpenAI message.tool_calls 或流式 delta.tool_calls
  • 客户端执行工具后,可将 tool 结果按标准消息继续回传,网关会在下一轮继续编排上下文

当前限制:

  • 仅支持 type=function
  • 工具调用的 stream=true 为兼容型流式输出:网关会先收完整个上游响应,再输出 OpenAI SSE 事件
  • 工具参数要求为合法 JSON;如果模型未按协议返回,网关会返回错误而不是伪造工具结果
  • parallel_tool_calls=false 时,网关会将工具调用限制为单个函数请求
  • tool_choice="none" 时,网关会退回普通聊天模式,不启用工具 shim

已验证行为:

  • 强制 tool_choice 的首轮工具请求
  • assistant.tool_calls + tool 结果回传后的二轮最终回答
  • 非流式 message.tool_calls 输出
  • 流式 delta.tool_calls 输出

错误处理策略

当上游返回已知的访客登录错误或额度错误时,服务会将当前代理标记为暂时不可用,并尝试切换到新的出口代理后重新请求,直到达到 RETRY_COUNT 上限。

如果所有代理重试都失败,网关将向客户端返回 OpenAI 风格的错误结构。

运维与排障

  • usage 为估算值,因为上游不提供 OpenAI 风格的 token 计量
  • 响应头附带 X-Upstream-Proxy,便于定位实际使用的出口代理
  • 响应头附带 X-Conversation-Id,便于关联上游会话
  • 若某个代理连续触发登录或额度类错误,会进入冷却期并被暂时跳过

实现说明

  • messages 会先被压平成单条提示词后再提交给上游
  • 流式场景会将上游 SSE 事件改写为 OpenAI Chat Completions chunk
  • 非流式场景会完整收集上游文本后再返回 OpenAI 风格 JSON
  • 工具调用场景会在网关层注入工具协议提示词,并将模型输出映射为标准 tool_calls

About

将 NoteGPT 聊天接口封装为 OpenAI 兼容 API 的轻量级 Go 网关

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages