Spaces:
Runtime error
Runtime error
| # Modal Deployment: MiniCPM-o-4_5 via llama.cpp | |
| ## 概述 | |
| 在 Modal.com 的 **T4 GPU** 上部署 MiniCPM-o-4_5 模型,通过 llama-cpp-python (CUDA pre-built wheel) 提供 OpenAI 兼容的 API 接口。 | |
| ## 架构 | |
| ``` | |
| 用户请求 → FastAPI (ASGI) → llama-server (OpenAI 兼容) → MiniCPM-o-4_5 GGUF | |
| ↓ | |
| /v1/chat/completions (文本 + 图片多模态) | |
| /v1/embeddings | |
| /health | |
| ``` | |
| ## 前置条件 | |
| 1. Modal 账号: https://modal.com/ | |
| 2. 安装 Modal CLI: `pip install modal` | |
| 3. 登录: `modal token new` | |
| ## 模型文件 | |
| 部署需要 3 个核心 GGUF 文件(Volume 中需包含): | |
| | 文件 | 大小 | 用途 | | |
| |------|------|------| | |
| | `MiniCPM-o-4_5-Q4_K_M.gguf` | ~12 GB | 主模型(文本推理) | | |
| | `vision/MiniCPM-o-4_5-vision-F16.gguf` | ~1 GB | 视觉投影层(可选,用于图片理解) | | |
| | `audio/MiniCPM-o-4_5-audio-F16.gguf` | ~630 MB | 音频投影层(当前未使用) | | |
| ⚠️ **关键变更**:`--mmproj` 只传 vision 投影层,**不能**传入多个 .gguf 文件。旧代码使用 `find_mmproj_files()` 递归搜索导致传入 9 个文件而崩溃。 | |
| ### 上传步骤 | |
| ```bash | |
| # 上传模型到 Modal Volume(只需一次) | |
| modal volume put minicpm-o-4_5-models /path/to/models/MiniCPM-o-4_5-gguf / | |
| # 验证 | |
| modal volume ls minicpm-o-4_5-models / | |
| ``` | |
| ## 部署 | |
| ```bash | |
| cd modal_deploy | |
| # 部署为 Modal App(持续运行的服务) | |
| modal deploy deploy.py | |
| # 或开发模式(热重载,日志在前台) | |
| modal serve deploy.py | |
| ``` | |
| 部署后 Modal 会输出一个 URL,如 `https://your-org--prego-pal-minicpm-serve.modal.run` | |
| ## API 接口 | |
| ### 1. 健康检查 | |
| ```bash | |
| GET /health | |
| ``` | |
| 返回:`{"status": "ok"}` | |
| ### 2. 模型列表 | |
| ```bash | |
| GET /v1/models | |
| ``` | |
| ### 3. 文本对话 (OpenAI 兼容) | |
| ```bash | |
| POST /v1/chat/completions | |
| Content-Type: application/json | |
| { | |
| "model": "MiniCPM-o-4_5", | |
| "messages": [ | |
| {"role": "user", "content": "今天孕妇可以吃什么?"} | |
| ], | |
| "max_tokens": 1024, | |
| "temperature": 0.7, | |
| "stream": false | |
| } | |
| ``` | |
| ### 4. 多模态对话(图片理解) | |
| llama-server (b4690+) 原生支持 OpenAI 多模态格式,通过 `/v1/chat/completions` 即可: | |
| ```bash | |
| POST /v1/chat/completions | |
| Content-Type: application/json | |
| { | |
| "model": "MiniCPM-o-4_5", | |
| "messages": [ | |
| {"role": "user", "content": [ | |
| {"type": "text", "text": "这张图片里有什么食物?"}, | |
| {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,..."}} | |
| ]} | |
| ], | |
| "max_tokens": 1024, | |
| "temperature": 0.7 | |
| } | |
| ``` | |
| ### 5. 嵌入向量 | |
| ```bash | |
| POST /v1/embeddings | |
| Content-Type: application/json | |
| { | |
| "model": "MiniCPM-o-4_5", | |
| "input": ["孕期营养建议"] | |
| } | |
| ``` | |
| ## 测试 | |
| ```bash | |
| # 快速测试模型能否加载和推理 | |
| modal run modal_deploy/deploy.py::test_inference | |
| # 上传模型 | |
| modal run modal_deploy/deploy.py::upload_models | |
| ``` | |
| ## 配置 | |
| 在 `deploy.py` 中可调整的参数: | |
| - `container_idle_timeout=300` — 空闲 5 分钟后自动关闭 | |
| - `gpu="T4"` — GPU 类型(16GB VRAM,$0.50/hr。也可用 A100: $1.50/hr) | |
| - `n_ctx=8192` — 上下文窗口大小 | |
| - `n_gpu_layers=-1` — GPU 层数(-1=全部到 GPU) | |
| ## 与 PregoPal 集成 | |
| 其他服务通过 HTTP 调用此 API: | |
| ```python | |
| import requests | |
| API_BASE = "https://your-app.modal.run" | |
| def ask_minicpm(prompt: str) -> str: | |
| r = requests.post(f"{API_BASE}/v1/chat/completions", json={ | |
| "messages": [{"role": "user", "content": prompt}], | |
| "max_tokens": 512, | |
| "temperature": 0.7, | |
| }) | |
| return r.json()["choices"][0]["message"]["content"] | |
| ``` | |
| ## 注意事项 | |
| 1. **冷启动**:无请求 >5 分钟后容器关闭,下次请求需等待 ~30-60 秒(模型加载) | |
| 2. **成本**:T4 约 $0.50/小时(vs A100 $1.50/hr),按实际使用计费。降级节省 **67%** | |
| 3. **模型上传**:Volume 是持久化的,模型只需上传一次 | |
| 4. **并发**:`@modal.concurrent(max_inputs=10)` 支持 10 个并发请求 | |
| 5. **VRAM 使用**:Q4_K_M 模型 4.7GB + vision 0.5GB + KV cache ≈ 6GB,T4 16GB 完全够用 | |
| 6. **修复说明**:旧 deploy.py 的 `find_mmproj_files()` 递归搜索到 9 个 .gguf 文件并全部作为 `--mmproj` 传入,导致启动失败。新版已明确指定 `--mmproj` 使用 vision 投影层(仅一个文件)。 | |