| --- |
| title: UnlimitedAI ToolCall Proxy |
| emoji: 🛠️ |
| colorFrom: blue |
| colorTo: purple |
| sdk: docker |
| app_port: 7860 |
| pinned: false |
| --- |
| |
| # UnlimitedAI ToolCall Proxy for Hugging Face Spaces |
|
|
| 这个 Space 对外提供 OpenAI 兼容接口,并通过 Toolify 给不原生支持函数调用的上游模型模拟 `tools` / `tool_calls` 能力。 |
|
|
| 架构: |
|
|
| ```text |
| OpenAI SDK / Cherry Studio / 你的应用 |
| ↓ /v1/chat/completions, tools |
| Toolify, port 7860,对外暴露 |
| ↓ 内部 OpenAI 兼容请求 |
| UnlimitedAI upstream proxy, 127.0.0.1:9000 |
| ↓ |
| https://app.unlimitedai.chat/api/chat |
| ``` |
|
|
| ## 上传到 Hugging Face |
|
|
| 1. 新建 Hugging Face Space,SDK 选择 **Docker**。 |
| 2. 上传本项目全部文件。 |
| 3. 在 Space 的 **Settings → Secrets** 添加: |
|
|
| | Secret | 必填 | 说明 | |
| | --- | --- | --- | |
| | `UAI_COOKIES` | 是 | 浏览器 Network 里 `/api/chat` 请求的完整 Cookie,不要带 `cookie:` 前缀 | |
| | `UAI_DEVICE_ID` | 是 | Cookie 里的 `u_device_id` 值 | |
| | `PROXY_API_KEY` | 强烈建议 | 客户端调用这个代理时使用的 API Key | |
| | `DEFAULT_MODEL` | 否 | 默认 `chat-model-reasoning` | |
| | `ALLOWED_MODELS` | 否 | 逗号分隔,例如 `chat-model-reasoning,my-model` | |
| | `UAI_LOCALE` | 否 | 默认 `zh` | |
| | `TARGET_API` | 否 | 默认 `https://app.unlimitedai.chat/api/chat` | |
| | `CHAT_ID_STRATEGY` | 否 | 默认 `stable`,让同一段 OpenAI 历史消息复用同一个 UnlimitedAI `chatId` | |
| | `UAI_CHAT_ID` | 否 | 配合 `CHAT_ID_STRATEGY=fixed` 或 `cookie` 使用;也可手动指定固定会话 ID | |
| | `LOG_LEVEL` | 否 | 默认 `INFO`,可设 `DEBUG` | |
|
|
| > 你如果不设置 `PROXY_API_KEY`,默认 key 是 `sk-change-me`。公开 Space 一定要改。 |
|
|
|
|
| ## Chat ID 复用说明 |
|
|
| 这版修复了原始示例里每次请求都随机生成 `chatId` 的问题。默认: |
|
|
| ```text |
| CHAT_ID_STRATEGY=stable |
| ``` |
|
|
| 网关会根据 OpenAI 消息历史里的第一条 `user` 消息生成稳定 UUID,所以第一次工具调用请求和后续带 `role=tool` 结果的请求会复用同一个 UnlimitedAI 上游会话。 |
|
|
| 可选策略: |
|
|
| | 值 | 行为 | |
| | --- | --- | |
| | `stable` | 默认;根据第一条用户消息稳定生成 `chatId`,推荐用于 tool calling | |
| | `cookie` | 优先使用 Cookie 里的 `home_chat_id`,没有则回退到 `stable` | |
| | `fixed` / `static` | 固定使用 `UAI_CHAT_ID`,所有请求共享一个上游会话 | |
| | `random` | 老行为;每次请求生成新的上游会话,不推荐 tool calling | |
|
|
| 如果客户端支持额外参数,也可以显式固定某个会话: |
|
|
| ```python |
| resp = client.chat.completions.create( |
| model="chat-model-reasoning", |
| messages=[{"role": "user", "content": "查一下上海天气"}], |
| tools=tools, |
| tool_choice="auto", |
| extra_body={"chat_id": "my-weather-session-001"}, |
| ) |
| ``` |
|
|
| 显式 `chat_id` 会被转换成稳定 UUID,优先级高于 `CHAT_ID_STRATEGY`。 |
|
|
| ## OpenAI SDK 调用 |
|
|
| 把 base_url 改成你的 Space 地址: |
| |
| ```python |
| from openai import OpenAI |
| |
| client = OpenAI( |
| base_url="https://YOUR-SPACE.hf.space/v1", |
| api_key="你的 PROXY_API_KEY", |
| ) |
| |
| resp = client.chat.completions.create( |
| model="chat-model-reasoning", |
| messages=[{"role": "user", "content": "你好"}], |
| ) |
| |
| print(resp.choices[0].message.content) |
| ``` |
| |
| ## Tool Call 示例 |
| |
| ```python |
| from openai import OpenAI |
|
|
| client = OpenAI( |
| base_url="https://YOUR-SPACE.hf.space/v1", |
| api_key="你的 PROXY_API_KEY", |
| ) |
| |
| tools = [ |
| { |
| "type": "function", |
| "function": { |
| "name": "get_weather", |
| "description": "获取城市天气", |
| "parameters": { |
| "type": "object", |
| "properties": { |
| "city": {"type": "string", "description": "城市名"} |
| }, |
| "required": ["city"] |
| } |
| } |
| } |
| ] |
| |
| resp = client.chat.completions.create( |
| model="chat-model-reasoning", |
| messages=[{"role": "user", "content": "查一下上海天气"}], |
| tools=tools, |
| tool_choice="auto", |
| ) |
| |
| msg = resp.choices[0].message |
| print(msg.tool_calls) |
| ``` |
| |
| 如果返回了 `tool_calls`,你的客户端需要执行对应函数,然后把结果作为 `role='tool'` 消息继续发回模型。这和标准 OpenAI tool calling 流程一致。 |
|
|
| ## 流式 Tool Call |
|
|
| ```python |
| stream = client.chat.completions.create( |
| model="chat-model-reasoning", |
| messages=[{"role": "user", "content": "查一下北京天气"}], |
| tools=tools, |
| tool_choice="auto", |
| stream=True, |
| ) |
| |
| for chunk in stream: |
| print(chunk) |
| ``` |
|
|
| ## 本地 Docker 测试 |
|
|
| ```bash |
| docker build -t uai-toolcall-proxy . |
| docker run --rm -p 7860:7860 \ |
| -e UAI_COOKIES='你的完整 Cookie' \ |
| -e UAI_DEVICE_ID='你的 device id' \ |
| -e PROXY_API_KEY='test-key' \ |
| uai-toolcall-proxy |
| ``` |
|
|
| 然后访问: |
|
|
| ```text |
| http://localhost:7860/v1/models |
| ``` |
|
|
| 调用时加 header: |
|
|
| ```text |
| Authorization: Bearer test-key |
| ``` |
|
|
| ## 注意 |
|
|
| - 这里的 tool calling 是 Toolify 通过提示词和解析实现的“兼容层”,不是 UnlimitedAI 官方原生工具调用。 |
| - 模型有概率不按格式输出;本项目已启用 Toolify 的函数调用解析失败重试,但仍不能保证 100%。 |
| - 不要把 Cookie 提交到仓库;只放到 Hugging Face Secrets。 |
| - 建议把 Space 设置为 Private。 |
| - 本包包含 Toolify 源码,遵循其 GPL-3.0-or-later 许可证。 |
|
|