1小时前
|
|
|
把 **Ollama** 装进 **Hugging Face Spaces** 的免费 Docker 容器,让 1-4B 小模型一键上线,随时通过 HTTPS 调用。
---
## 1 创建 Spaces 容器
1. 登录 [https://huggingface.co](https://huggingface.co) → 右上角 **New Space**
2. Space 名称随意(例 `ollama-gemma`)、**Docker** 类型、硬件选 **CPU basic**(免费 2 vCPU / 16 GB,足够 1-4B 量化模型)。
3. 选 **Public**(私有需 PRO),点 **Create Space**。
---
## 2 本地克隆仓库(后面要推送)
```bash
git clone https://huggingface.co/spaces/<你的用户名>/ollama-gemma
cd ollama-gemma
```
---
## 3 一键可用文件清单(全部放在仓库根目录)
| 文件 | 作用 |
|---|---|
| `Dockerfile` | 基于 ollama/ollama 官方镜像,装 Python、依赖、暴露 7860 |
| `entrypoint.sh` | 启动 ollama 服务 → 拉模型 → 启动 FastAPI 代理 |
| `app.py` | 透传 `/generate` 接口,把客户端 JSON 原样发给 Ollama |
| `requirements.txt` | 仅 3 行:fastapi / uvicorn / requests |
下面直接给出内容,复制即可。
### 3.1 Dockerfile
```dockerfile
# 使用 ollama 官方镜像作为底包
FROM ollama/ollama:latest
# 1. 安装系统依赖(curl + python3)
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
python3 \
python3-pip \
python3-venv \
python-is-python3 && \
rm -rf /var/lib/apt/lists/*
# 2. 创建并启用虚拟环境(避开 PEP-668 限制)
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# 3. 复制 requirements 并安装 Python 依赖
COPY requirements.txt /tmp/
RUN pip install --upgrade pip && \
pip install -r /tmp/requirements.txt
# 4. 复制业务代码
WORKDIR /code
COPY . .
# 5. 暴露 Hugging Face 要求的端口
EXPOSE 7860
# 6. 启动脚本
ENTRYPOINT ["bash", "entrypoint.sh"]
```
### 3.2 entrypoint.sh
```bash
#!/bin/bash
set -e
# 设置环境变量
export OLLAMA_MAX_LOADED_MODELS=2
echo "Set OLLAMA_MAX_LOADED_MODELS=$OLLAMA_MAX_LOADED_MODELS"
echo "Set OLLAMA_KEEP_ALIVE=-1"
echo "Starting Ollama service..."
# 1. 后台启动 ollama 服务
ollama serve &
OLLAMA_PID=$!
# 等待服务就绪(最多等待120秒)
echo "Waiting for Ollama to be ready..."
COUNTER=0
until curl -s http://localhost:11434/api/tags > /dev/null 2>&1; do
echo "Waiting for Ollama... ($COUNTER/120)"
sleep 3
COUNTER=$((COUNTER + 3))
if [ $COUNTER -ge 120 ]; then
echo "ERROR: Ollama failed to start within 120 seconds"
kill $OLLAMA_PID 2>/dev/null || true
exit 1
fi
done
echo "Ollama is ready!"
# 2. 拉取模型
echo "Pulling models..."
ollama pull nomic-embed-text || echo "Failed to pull nomic-embed-text"
ollama pull qwen2.5:1.5b || echo "Failed to pull qwen2.5:1.5b"
# 3. 保持模型在内存中运行
echo "Loading models into memory..."
# 启动 nomic-embed-text 模型并保持运行
ollama run nomic-embed-text > /dev/null 2>&1 &
EMBED_PID=$!
# 启动 qwen2.5:1.5b 模型并保持运行
ollama run qwen2.5:1.5b > /dev/null 2>&1 &
CHAT_PID=$!
# 等待模型加载完成
echo "Waiting for models to load into memory..."
sleep 15
# 验证模型是否可用
echo "Checking available models..."
curl -s http://localhost:11434/api/tags
# 4. 启动 FastAPI 接口
echo "Starting FastAPI server..."
exec uvicorn app:app --host 0.0.0.0 --port 7860
```
### 3.3 app.py(透传版)
```python
# app.py
import requests
from fastapi import FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware
OLLAMA_BASE_URL = "http://localhost:11434"
app = FastAPI(title="Ollama-raw-proxy")
# 可选:解决浏览器跨域
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
@app.post("/api/{endpoint}")
async def proxy_ollama_dynamic(endpoint: str, raw: Request):
"""
动态转发请求到 Ollama API
例如: /api/chat → http://localhost:11434/api/chat
/api/generate → http://localhost:11434/api/generate
/api/embed → http://localhost:11434/api/embed
"""
# 构建目标 URL
target_url = f"{OLLAMA_BASE_URL}/api/{endpoint}"
body = await raw.body() # bytes,保持原样
headers = {"Content-Type": "application/json"}
# 转发请求到对应的 Ollama API
r = requests.post(target_url,
data=body,
headers=headers,
timeout=60)
return Response(content=r.content,
status_code=r.status_code,
headers=r.headers)
# 保持向后兼容的别名路由
@app.post("/chat")
async def proxy_ollama_chat(raw: Request):
"""向后兼容:/chat → /api/chat"""
return await proxy_ollama_dynamic("chat", raw)
@app.post("/embed")
async def proxy_ollama_embed(raw: Request):
"""向后兼容:/embed → /api/embed"""
return await proxy_ollama_dynamic("embed", raw)
@app.get("/")
def root():
return {"message": "Ollama raw proxy is running"}
```
### 3.4 requirements.txt
```
fastapi
uvicorn[standard]
requests
```
---
## 4 推送并部署
```bash
git add .
git commit -m "feat: ollama qwen3 1.7b on HF Spaces"
git push origin main
```
Space 页面会实时刷构建日志,看到 `Ollama is running` 说明容器已就绪。
---
## 5 快速测试
### 5.1 查看模型列表
```bash
curl https://<你的-space>.hf.space/api/tags
```
### 5.2 生成文本
```bash
curl https://<你的-space>.hf.space/generate \
-H "Content-Type: application/json" \
-d '{"model":"qwen2.5:1.5b","prompt":"天空为什么是蓝色的?","stream":false}'
```
返回示例
```json
{"model":"qwen2.5:1.5b","response":"天空呈现蓝色是由于瑞利散射现象……","done":true}
```
### 5.3 Python 客户端
```python
import requests
url = "https://<你的-space>.hf.space/generate"
payload = {
"model": "qwen2.5:1.5b",
"prompt": "用三句话介绍量子计算",
"stream": False
}
print(requests.post(url, json=payload).json()["response"])
```
---
## 6 常见问题速查
| 现象 | 解决 |
|---|---|
| curl: command not found | Dockerfile 里 `apt install curl` |
| externally-managed-environment | 用 python3-venv 或 `--break-system-packages` |
| 502/504 | 模型尚未拉完,看日志等 1-2 分钟 |
| 想跑 7B+ | Spaces 硬件切到 GPU(收费)再拉 `qwen3:7b` |
---
## 7 进阶玩法
1. 换模型:把 `entrypoint.sh` 里的 `ollama pull qwen2.5:1.5b` 改成 `gemma3:1b`、`nomic-embed-text:latest` 等,重新 push 即可。
2. 流式输出:把 `stream=true` 并在客户端逐行读取 `response` 字段。
3. 嵌入模型:用 `/api/embeddings` 端点,见 示例。
---
至此,你已经拥有了一个**公网可访问、24 h 在线、免费 CPU 运行**的 Ollama 推理节点。
把接口地址填到 ChatBox、Open-WebUI、AnythingLLM 等客户端,就能随时与本地/线上小模型对话啦!
🫵 来啊,说点有用的废话!
▲