LLM 这个词大家已经看得很多了,但真正自己部署、写接口、接工作流的时候,问题往往不是“模型不会回答”,而是环境起不来、请求超时、批量任务跑一半卡死、框架选错重来。这篇文章专门梳理 LLM 落地过程中最常遇到的工程问题,从框架选型、本地部署、API 调用,到资源占用和批量任务,再到一个很具体的场景:ComfyUI 接入 LLM 时,两边是不是必须放在同一台电脑上。
如果你正在做 LLM 本地部署、准备做 LLM 应用集成,或者想把 LLM 接进 ComfyUI 工作流,这篇文章可以直接收藏。
1. LLM 落地核心问题速览
网上聊 LLM 大多在聊模型效果,但工程落地真正要关心的是下面这些维度。
| 能力项 | 问题说明 |
|---|---|
| 硬件门槛 | 模型规模决定显存压力,需要按模型参数量、量化等级实际测算 |
| 框架选型 | Ollama、vLLM、llama.cpp 各有偏向,选错后面要返工 |
| 启动方式 | 不同框架启动命令差异较大,端口、服务形态不统一 |
| API 兼容性 | 多数框架提供 OpenAI 风格接口,但部分参数和返回结构有差异 |
| 批量任务 | 高并发下显存抖动、超时、队列堆积是常见问题 |
| 跨机调用 | LLM 服务和 ComfyUI、业务系统可以通过 HTTP API 分离部署 |
| 资源观察 | 显存、内存、吞吐需要按实际推理参数测试,不能只看模型大小 |
| 合规边界 | 人脸、声音、版权素材、隐私数据都不应直接交给未授权服务 |
从这些维度看,LLM 工程化的第一原则是:先用小模型把链路跑通,再上大模型。
2. LLM 落地时最容易踩的几类问题
2.1 模型文件不知道为什么缺失
很多本地 LLM 项目采用“启动时自动下载”的设计。启动脚本会自动拉取模型文件,但网络不稳定、磁盘空间不足、下载中断都会导致模型文件不完整。启动日志里经常出现model file not found或corrupted file这类信息。
排查顺序是:
- 查看日志中模型文件的实际保存路径。
- 检查该目录剩余磁盘空间。
- 对比模型文件的预期大小与实际大小。
- 保留记录中断条件,手动恢复下载或删除残留文件重新拉取。
2.2 启动成功但端口未监听
服务进程在跑,页面或接口却访问不了。这种问题通常是服务绑定地址写成了127.0.0.1,局域网内其他机器无法访问;或者端口被防火墙拦截;或者启动过程因显存不足被系统杀掉,但日志被刷屏掩盖。
建议统一用下面的方式检查:
# 查看监听端口 netstat -ano | grep 8080 # 或 lsof -i :8080如果端口正常监听,再用 curl 验证接口:
curl http://127.0.0.1:8080/v1/models2.3 框架版本变化导致代码不兼容
不同 LLM 推理框架虽然大多兼容 OpenAI 格式,但实现细节经常变化。例如某些框架对max_tokens、temperature的校验更严格,数值超范围会直接报错;另一些框架对stream参数的处理不同,流式返回格式可能多出data:前缀。调用代码里应避免同时依赖太多框架特有能力,优先使用稳定的 OpenAI 接口子集字段。
3. 环境准备与硬件门槛
在部署任何 LLM 项目之前,先按下面的清单检查环境。注意,本文不写死版本号,实际要以项目官方文档为准。
| 检查项 | 说明 |
|---|---|
| 操作系统 | Windows / Linux / macOS 均可,但 CUDA 环境以 Linux 更成熟 |
| GPU 驱动 | 建议使用较新的 NVIDIA 驱动 + CUDA 工具包 |
| Python 版本 | 常见 LLM 框架要求 3.9 至 3.12 区间,具体看项目 |
| GPU 显存 | 7B 模型量化后可尝试在 6G 至 8G 显存运行;更大模型需按量化方案测试 |
| CPU 内存 | 即使使用 GPU,内存仍建议 16G 以上 |
| 磁盘空间 | 模型文件通常数 GB 到数十 GB,预留充足空间 |
| 网络环境 | 安装依赖和下载模型需要稳定的网络 |
显存是第一个要确认的参数。很多人问“8G 显存能不能跑 7B”,这个问题不能一概而论,因为量化等级、上下文长度、并发数都会改变显存占用。更稳妥的做法是查看模型卡片的requirements说明,然后先用最小参数跑一次,观察nvidia-smi输出。
4. LLM 推理框架怎么选
LLM 框架非常多,但大多数项目最终都落在几类方案上。可以从“能不能用、好不好启动、要不要 deep 定制”三个角度来判断。
4.1 常用框架对比
| 框架 | 定位 | 启动复杂度 | 适合场景 |
|---|---|---|---|
| Ollama | 本地一键运行模型 | 低 | 个人开发、快速测试、API 简单调用 |
| llama.cpp | 底层推理库 / CLI | 中 | CPU 推理、嵌入式设备、量化研究 |
| vLLM | 高吞吐推理服务 | 中高 | 批量任务、并发接口、生产服务 |
| Transformers | 模型加载与训练基础设施 | 中高 | 调试、微调、研究场景 |
| LM Studio / 同类 GUI | 桌面可视化运行 | 低 | 新手体验、本地对话测试 |
4.2 快速选型建议
- 一个人本地测试,最省事的是Ollama。
- 要接大批量任务、高并发 API,优先看vLLM 或同类高吞吐方案。
- CPU 机器或需要极低资源占用,可以尝试llama.cpp。
- 要修改模型内部结构、做微调分析,走Transformers路线。
框架不是越重越好。如果目标是验证“ComfyUI 后端调用 LLM 是否可行”,先用 Ollama 这种轻量方案启动一个 API 服务,比直接上 vLLM 更高效。
5. 本地部署启动与验证流程
以最常见且低门槛的 Ollama 为例,给出通用部署模板。不同系统的安装命令有所不同,这里的思路是通用的。
5.1 安装依赖与启动服务
# 安装 Ollama(以官方脚本流程为例,具体以当前项目说明为准) curl -fsSL https://ollama.com/install.sh | sh安装完成后先查看服务状态:
systemctl status ollama如果没有安装为系统服务,也可以用前台方式运行,方便看日志:
ollama serve5.2 拉取并运行模型
# 拉取一个小模型测试链路 ollama pull llama3.2:1b # 运行模型 ollama run llama3.2:1b第一条命令会自动下载模型文件,下载量取决于模型大小。如果网络不稳定,注意观察下载进度,避免中断后残留不完整文件。
在ollama run交互窗口里输入一段测试文本,比如“用一句话说明什么是 API”,能正常返回即可确认模型推理链路是通的。
5.3 验证服务是否可访问
curl http://127.0.0.1:11434/v1/models能返回模型列表,说明本地 LLM 服务已经以 API 形式对外提供能力。此时项目目录里已经出现一个完整可调用的 LLM 服务,后面的业务系统、ComfyUI 工作流都可以基于这个地址接入。
6. LLM 接口 API 调用示例
一旦 LLM 服务启动,后续业务集成基本都是 API 调用。大多数框架都提供 OpenAI 兼容接口,下面给出一套通用示例,实际字段以项目文档为准。
6.1 基础对话请求
curl http://127.0.0.1:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "llama3.2:1b", "messages": [ {"role": "system", "content": "你是一个技术助手。"}, {"role": "user", "content": "请解释什么是 LLM 推理框架"} ] }'响应里的choices[0].message.content就是模型生成的文本。如果接口返回 404,说明该框架的接口路径不是这个,需要查阅项目文档。
6.2 Python 调用示例
import requests url = "http://127.0.0.1:11434/v1/chat/completions" payload = { "model": "llama3.2:1b", "messages": [ {"role": "user", "content": "写一个 Python 函数读取当前目录下所有 txt 文件"} ], "temperature": 0.7, "max_tokens": 500 } response = requests.post(url, json=payload, timeout=120) data = response.json() print(data["choices"][0]["message"]["content"])6.3 流式返回处理
长文本生成建议使用流式接口,避免长时间等待。浏览器或业务端可以逐步渲染内容:
import requests url = "http://127.0.0.1:11434/v1/chat/completions" payload = { "model": "llama3.2:1b", "messages": [{"role": "user", "content": "列出 5 个适合 LLM 自动化的任务"}], "stream": True } with requests.post(url, json=payload, stream=True, timeout=180) as resp: for line in resp.iter_lines(): if line: decoded = line.decode("utf-8").strip() if decoded.startswith("data:"): print(decoded.removeprefix("data:"))流式解析时要注意不同框架的data:前缀格式可能不同,有的还会有[DONE]结束标记。这类差异做跨框架兼容时需要单独处理。
7. ComfyUI 与 LLM 必须在同一台电脑上吗
很多人会在 ComfyUI 工作流里加入 LLM 节点,用来生成提示词、解释图片内容、做批量文案改写。这里的关键问题就是:ComfyUI 和 LLM 是不是必须装在同一台电脑上?
结论很明确:不是必须。ComfyUI 通过 HTTP API 调用 LLM 服务,两者只要网络能互通即可。
7.1 本机部署联调
如果一台显卡不错的机器同时跑 ComfyUI 和 LLM,只需要在 ComfyUI 的自定义节点中配置 LLM 服务地址为:
llm_api_base=http://127.0.0.1:11434/v1这种方式适合个人使用,链路简单,排查方便。缺点是显存会被两个服务竞争,可能出现图像生成到一半显存不足的情况。
7.2 跨机部署调用
生产环境更推荐把 ComfyUI 和 LLM 分开:
| 服务器 | 职责 | 建议硬件 |
|---|---|---|
| A 机 | ComfyUI 图像生成 | 高显存 GPU |
| B 机 | LLM 推理服务 | 按模型显存需求配置 GPU |
A 机调用 B 机的接口时,把127.0.0.1改成 B 机的局域网 IP:
llm_api_base=http://192.168.1.100:11434/v1注意跨机调用时,LLM 服务启动参数需要允许局域网访问。Ollama 默认监听127.0.0.1,要开放局域网访问需要修改环境变量或用--host参数指定监听地址,具体以项目说明为准。
还需要考虑防火墙和网络权限。如果 A 机访问 B 机接口超时,先检查端口是否监听、防火墙是否放行,再检查 IP 配置。
跨机部署的最大收益是资源隔离。图像生成和文本推理不会互相抢占显存,批量任务也能各自提速。缺点是需要额外维护一台服务,故障点增多。
8. 批量任务与稳定性设计
LLM 接口一旦跑通,下一步通常是批量调用。批量场景最容易出现三类问题:超时、限流、进程卡死。
8.1 批量任务目录结构
把输入、输出、日志分离是批量任务的基本要求:
batch_task/ ├── inputs/ # 输入文本或待处理文件 ├── outputs/ # 生成结果 ├── logs/ # 运行日志 └── config.yaml # 批量参数配置8.2 批量配置示例
# config.yaml input_dir: ./inputs output_dir: ./outputs model: llama3.2:1b concurrency: 2 retry_times: 3 timeout: 120这里的concurrency不建议一开始就很高。并发数过大会导致显存暴涨或触发框架排队,先设为 1 到 2,确认稳定后再逐步上调。
8.3 批量处理 Python 示例
import json import os import time from pathlib import Path import requests INPUT_DIR = Path("./inputs") OUTPUT_DIR = Path("./outputs") LOG_DIR = Path("./logs") URL = "http://127.0.0.1:11434/v1/chat/completions" MODEL = "llama3.2:1b" OUTPUT_DIR.mkdir(exist_ok=True) LOG_DIR.mkdir(exist_ok=True) def process_one(file_path: Path, max_retries: int = 3): text = file_path.read_text(encoding="utf-8") payload = { "model": MODEL, "messages": [ {"role": "user", "content": f"请总结下面的内容:\n{text}"} ], "temperature": 0.3, "max_tokens": 500 } for attempt in range(1, max_retries + 1): try: resp = requests.post(URL, json=payload, timeout=120) resp.raise_for_status() result = resp.json()["choices"][0]["message"]["content"] output_file = OUTPUT_DIR / f"{file_path.stem}_summary.json" output_file.write_text( json.dumps({"input": file_path.name, "output": result}, ensure_ascii=False, indent=2), encoding="utf-8" ) log_file = LOG_DIR / "success.log" with open(log_file, "a", encoding="utf-8") as f: f.write(f"[OK] {file_path.name} (attempt {attempt})\n") return True except Exception as exc: log_file = LOG_DIR / "error.log" with open(log_file, "a", encoding="utf-8") as f: f.write(f"[FAIL] {file_path.name} attempt {attempt}: {exc}\n") time.sleep(2) return False if __name__ == "__main__": files = list(INPUT_DIR.glob("*.txt")) for f in files: print(f"Processing {f.name} ...") process_one(f)这段脚本的核心思路是:单文件独立处理、失败自动重试、成功和失败分别记录日志。批量任务必须保留失败日志,否则跑完一轮发现 500 个文件里只有 300 个结果,都不知道是哪些文件失败了。
9. 资源占用与性能观察方法
LLM 运行时资源占用是大家最关心的。这里不写死显存数字,因为模型、量化方式、上下文长度、并发数都会影响。给出一套观察和优化方法。
9.1 如何观察 GPU 显存和利用率
nvidia-smi重点看Memory-Usage和Volatile GPU-Util两列。前者是显存占用,后者是 GPU 计算利用率。
在服务运行过程中每隔几秒采集一次,能看出显存是稳定在一个值还是持续上涨。持续上涨通常说明存在显存泄漏,需要检查后端推理框架的版本和配置。
9.2 CPU 推理与 GPU 推理的差异
CPU 推理可以运行,但速度明显偏慢,尤其生成长文本时 CPU 占用会很高。GPU 推理响应更快,但显存是硬约束。如果显存不够,可以选择:
- 更小的模型参数量。
- 更激进的量化等级。
- 缩短最大生成长度。
- 降低并发数。
9.3 影响性能的核心参数
| 参数 | 影响 |
|---|---|
| max_tokens | 生成越长,显存占用越高,耗时越长 |
| temperature | 不影响性能,影响结果随机性 |
| batch size / 并发数 | 越高显存越吃紧 |
| 上下文长度 | 过长会增加 KV Cache 显存压力 |
| 量化等级 | 等级越低显存占用越小,质量可能略有下降 |
9.4 显存不足时的降级方案
如果调用时出现CUDA out of memory,优先做三件事:
- 调整并发数为 1。
- 降低最大生成长度。
- 换更小或量化程度更高的模型。
10. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 启动时报依赖安装失败 | Python 版本不匹配或依赖源不稳定 | 查看安装日志,确认当前 Python 版本 | 按项目文档切换 Python 版本,或更换依赖源重试 |
| 模型文件缺失 | 下载中断或磁盘空间不足 | 检查模型目录大小和磁盘剩余空间 | 删除不完整文件后重新下载 |
| CUDA 相关报错 | 显卡驱动或 CUDA 版本不匹配 | 运行nvidia-smi查看驱动版本 | 按框架要求调整驱动或 CUDA 环境 |
| 接口返回 404 | 接口路径不对或服务未启动 | 用 curl 访问/v1/models验证 | 查阅项目文档确认接口地址 |
| 请求超时 | 生成文本过长或并发过高 | 查看服务端日志和任务队列 | 降低 max_tokens,降低并发数 |
| 批量任务卡住 | 某个输入触发异常循环或网络挂起 | 检查 error.log 和进程状态 | 增加超时时间,加入失败重试逻辑 |
| 局域网访问不了 | 服务只监听 127.0.0.1 | 查看监听地址 | 修改启动参数,开放局域网访问 |
| 显存不足 | 模型过大或并发过高 | 观察 nvidia-smi | 换小模型、降量化、降低并发 |
| 输出质量不稳定 | 采样参数不适合当前任务 | 固定 seed、调整 temperature | 先用较低 temperature 测试 |
排除问题时最忌讳不看日志。LLM 服务运行期的日志通常包含请求耗时、Tokens 数量、报错堆栈,信息量远大于页面上的错误提示。
11. 工程化最佳实践与合规边界
11.1 工程化建议
- 第一次部署先用最小模型、最小参数跑通整个链路,再逐步加大模型和并发。
- 保留一套最小可运行配置,防止后续调参把环境弄坏。
- 模型文件、输入素材、输出结果、日志分区存放,避免混在一个目录里。
- 批量任务必须设计失败重试和断点续跑,不能只做一轮 after-loop 盲目重跑。
- API 服务如果暴露到局域网或公网,必须加访问控制。简单做法是用 Token 校验或只监听信任网段。
- 如果跨机调用 LLM,在两个机器上都确认防火墙规则和监听地址。
11.2 合规与安全边界
- 涉及人脸、声音、肖像的生成或处理,必须先确认授权,不得使用未授权素材。
- 涉及版权文本、商业文档、隐私数据,不应扔到未控制的远程服务。
- 本地 LLM 服务虽然隔离性更好,但模型输出也可能存在偏见、错误信息,商用前必须做内容复核。
- 如果项目只用于技术验证,建议使用测试数据,不要直接使用线上真实业务数据。
LLM 能做的事情很多,但工程上每个环节都需要验证。把部署、接口、批量、资源观察这几条链路都跑通,后面的业务扩展会流畅很多。
12. 总结与下一步
这篇文章把 LLM 落地的核心问题集中梳理了一遍:框架怎么选、服务怎么起、接口怎么调、批量任务怎么设计、资源占用怎么观察,以及 ComfyUI 与 LLM 是否必须同一台电脑。
最值得先验证的是:用 Ollama 或者你选定的框架拉起一个最小模型,跑通/v1/chat/completions接口。这一步成功,后续接入业务系统或 ComfyUI 就只差地址配置。
最容易踩的坑是:模型文件下载不完整、端口监听地址不对、批量任务没有失败重试。这三件事几乎会在每个 LLM 工程里遇到,建议写进项目检查清单。
下一步可以做的事:
- 用本地小模型做一个提示词生成节点,接入 ComfyUI 工作流。
- 把单文件批量脚本改造成带进度、日志、断点恢复的任务队列。
- 对比不同框架在同一模型下的响应速度和显存占用。
- 设计一套 Token 用量和花费统计,便于评估后续更大模型或云端 API 的成本。
LLM 工程的本质是链路工程。模型只是链路中的一环,把环境、服务、接口、批量、监控全部跑顺,这个项目才算真正可用。