摘要:本文档系统梳理大模型(文本与图像)的远程 API 调用、本地部署方案,以及 Agent(以 Claude Code 为典型)的架构与接入方式。目标是在"调 API"和"自己搭服务"之间建立完整认知。
一、两种使用模式概述
1.1 远程 API 模式
模型运行在服务商的 GPU 集群上,用户通过 HTTP 请求调用。本地无需显卡,按量付费。
用户代码 → HTTP 请求 → 服务商网关 → 负载均衡 → 模型推理集群(GPU)→ 返回结果
优点 :零硬件投入、开箱即用、自动享受最新模型和最优化推理。
缺点:数据需上传至第三方、按量付费、受网络延迟影响。
1.2 本地部署模式
将模型权重文件下载到本地,在自己的 GPU(或 CPU)上运行推理。
bash
# 文本模型本地部署
ollama run qwen2.5:7b
# 图片模型本地部署
python generate.py # 启动 diffusers 管线
优点 :数据不出本地、长期高频使用时成本趋近于零、完全可控。
缺点:需要 GPU 硬件、环境配置复杂、模型管理需自行维护。
1.3 混合模式
高频小任务本地跑(省成本),低频大任务调远程 API(免硬件投入)。
小模型本地(7B-14B)→ 日常问答、代码补全、简单图片生成
大模型远程(70B+ / 图片视频)→ 复杂推理、高质图片、视频生成
1.4 远程 API 与本地部署的深度对比
运行原理
两种模式在物理链路和计算归属上存在根本差异。
远程 API 模式 本地部署模式
════════════ ════════════
┌──────────┐ ┌──────────┐
│ 你的电脑 │ 纯客户端 │ 你的电脑 │ 既是客户端也是服务器
│ │ 只发 HTTP 请求 │ │ 模型加载在本进程或子进程
└────┬─────┘ └────┬─────┘
│ │
│ HTTPS(公网) │ 本地进程间通信
│ 延迟:50-500ms │ 延迟:<5ms(同机)
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ API 网关 │ 鉴权、限流、路由 │ 本地推理引擎 │ Ollama / vLLM
└──────┬───────┘ │ / diffusers │
│ └──────┬───────┘
▼ │
┌──────────────┐ ▼
│ 推理集群 │ ┌──────────────┐
│ - 多卡 A100/H100│ │ 你的 GPU │ RTX 4060 / 4090
│ - TensorRT 编译 │ │ - fp16 推理 │
│ - Batch 合并 │ │ - 单用户独占 │
│ - KV Cache 复用 │ │ - 无批处理合并 │
│ - 模型已预热 │ │ - 首次加载 5-30s│
└──────┬───────┘ └──────┬───────┘
│ │
▼ ▼
返回 JSON 响应 返回 Python 对象 / JSON
关键差异:
| 维度 | 远程 API | 本地部署 |
|---|---|---|
| 计算归属 | 服务商 GPU 集群 | 自有 GPU/CPU |
| 通信链路 | 公网 HTTPS,单次 50-500ms | 本机进程间通信,<5ms |
| 推理优化 | TensorRT 编译、Batch 合并、KV Cache 复用 | 通常为 PyTorch 原生推理或 llama.cpp |
| 模型加载 | 服务端常驻显存,随时可用 | 需手动加载,首次有 5-30 秒冷启动 |
| 并发模型 | 多用户共享 GPU,高并发下自动排队 | 单用户独占,批次 = 1 |
| 数据流 | 输入/输出经公网传输 | 数据全程不离开本机 |
优缺点对比
| 远程 API | 本地部署 | |
|---|---|---|
| 硬件成本 | ✅ 无需 GPU | ❌ 需要显卡(8GB VRAM 起步) |
| 使用成本 | ❌ 按量付费,高频使用累积成本高 | ✅ 硬件一次性投入,边际成本极低 |
| 部署复杂度 | ✅ 注册 → 拿 key → 3 行代码 | ❌ 环境配置 + 模型下载 + 服务启动 |
| 模型选择 | ✅ 即时访问最新/最大模型 | ❌ 受限于本地显存,大模型跑不动 |
| 推理质量 | ✅ 可按需选用最强模型 | ⚠️ 消费级显卡只能用中小模型 |
| 推理速度 | ✅ A100/H100 集群,推理极快 | ⚠️ 取决于本地显卡性能 |
| 网络依赖 | ❌ 断网即不可用 | ✅ 完全离线运行 |
| 数据隐私 | ❌ Prompt 和图片上传至第三方 | ✅ 数据不出本机 |
| 延迟稳定性 | ❌ 受公网波动影响,偶尔超时 | ✅ 本地通信,延迟稳定可预测 |
| 可定制性 | ❌ 不能改模型、不能加 LoRA | ✅ 完全控制管线、可加载 LoRA/ControlNet |
| 运维负担 | ✅ 服务商负责模型更新与故障处理 | ❌ 模型更新、显存管理、进程守护需自行维护 |
| 合规性 | ❌ 数据跨境风险,部分行业不可用 | ✅ 满足数据不出域的安全合规要求 |
按场景选择
场景 推荐方案
──── ────────
个人学习、调试、探索 本地(Ollama / diffusers)
偶发生成几张图 / 几次问答 远程 API
每天大量使用(客服/代码生成/批量出图) 本地(高频)+ 远程(大任务)
处理敏感数据(医疗/金融/企业内部) 本地(合规要求)
需要最新最强模型(GPT-5/FLUX-Pro/Veo) 远程 API
需要自定义模型(LoRA/微调/特殊管线) 本地(完全可控)
需要视频生成 远程 API(消费级显卡难以视频推理)
团队多人共享一个模型 远程 API 或 vLLM 本地服务
离线环境(飞机上、内网隔离区) 本地
文本模型与图片模型的差异
两种模型在本地部署方面的差别,源于其内部结构的根本不同:
| 文本模型 | 图片模型 | |
|---|---|---|
| 模型结构 | 单一 Transformer(Decoder-Only) | 管线:Text Encoder + UNet/DiT + VAE + Scheduler |
| 权重文件数 | 1 个 .gguf 或 .safetensors |
3-5 个 .safetensors + 配置文件 |
| 推理过程 | Token → Token 自回归生成 | 噪声 → 逐步去噪 → VAE 解码 |
| 推理并发 | 支持连续批处理(Continuous Batching) | 通常单张处理,批次能力有限 |
| 统一运行时 | ✅ Ollama / vLLM(标准 chat API) | ❌ 不存在等价工具,需 diffusers 或 ComfyUI |
| 远程 API | ✅ /v1/chat/completions |
✅ /v1/images/generations(但端点不同) |
| 本地最低显存 | 4GB(7B-q4 量化) | 8GB(SANA-1.5)/ 12GB(FLUX-schnell) |
根本原因:文本模型经过多年工程优化,已形成"单模型文件、标准 API、一键部署"的成熟生态(GGUF 量化格式 + llama.cpp 推理引擎 + Ollama 管理层)。图片模型由于多子模型管线结构,每个子模型的输入输出各异------Text Encoder 输出向量、UNet 输出噪声预测、VAE 输出像素------难以用统一的"一键工具"覆盖所有模式(文生图、图生图、Inpainting、超分各有不同的输入组合)。
二、远程 API 调用
2.1 OpenAI 兼容协议 --- 事实标准
当前几乎所有厂商的 API 都兼容 OpenAI 的请求/响应格式。掌握一套写法即可对接所有平台。
文本对话:
python
from openai import OpenAI
client = OpenAI(
base_url="https://api.your-provider.com/v1", # 各厂商的唯一差异
api_key="sk-xxxxxxxx"
)
response = client.chat.completions.create(
model="model-name",
messages=[
{"role": "system", "content": "你是一个有用的助手。"},
{"role": "user", "content": "解释什么是扩散模型"}
]
)
print(response.choices[0].message.content)
图片生成:
python
response = client.images.generate(
model="flux-1.1-pro",
prompt="一只橘猫在沙滩上,日落光线",
size="1024x1024"
)
print(response.data[0].url)
2.2 主流厂商接入速查
文本模型
| 厂商 | base_url | 可用模型 | 注册地址 |
|---|---|---|---|
| DeepSeek | https://api.deepseek.com |
deepseek-chat, deepseek-reasoner | platform.deepseek.com |
| 智谱 | https://open.bigmodel.cn/api/paas/v4 |
glm-4.6, glm-4.7 | open.bigmodel.cn |
| 阿里百炼 | https://dashscope.aliyuncs.com/compatible-mode/v1 |
qwen3, qwen3.5 | bailian.console.aliyun.com |
| 硅基流动 | https://api.siliconflow.cn/v1 |
DeepSeek, Qwen, Llama 全系列 | cloud.siliconflow.cn |
| 月之暗面 | https://api.moonshot.cn/v1 |
moonshot-v1 系列 | platform.moonshot.cn |
| OpenAI | https://api.openai.com/v1 |
gpt-5, gpt-5.4 | platform.openai.com |
python
# 示例:DeepSeek
client = OpenAI(base_url="https://api.deepseek.com", api_key="sk-xxx")
response = client.chat.completions.create(model="deepseek-chat", messages=[...])
# 示例:智谱
client = OpenAI(base_url="https://open.bigmodel.cn/api/paas/v4", api_key="xxx")
response = client.chat.completions.create(model="glm-4.6", messages=[...])
# 示例:阿里百炼
client = OpenAI(base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", api_key="sk-xxx")
response = client.chat.completions.create(model="qwen3.5", messages=[...])
# 示例:硅基流动(模型种类最多,按需切换模型名即可)
client = OpenAI(base_url="https://api.siliconflow.cn/v1", api_key="sk-xxx")
response = client.chat.completions.create(model="deepseek-ai/DeepSeek-V3", messages=[...])
图片模型
| 厂商 | 端点类型 | 可用模型 |
|---|---|---|
| 硅基流动 | OpenAI 兼容 /v1/images/generations |
FLUX.1-dev, SD 3.5, SANA-1.5 |
| 智谱 | 官方 SDK client.images.generations |
CogView-4 |
| 阿里百炼 | 官方 SDK ImageSynthesis.call |
Qwen-Image 2.0, 通义万相 |
python
# 硅基流动 --- 文生图
from openai import OpenAI
client = OpenAI(base_url="https://api.siliconflow.cn/v1", api_key="sk-xxx")
resp = client.images.generate(
model="black-forest-labs/FLUX.1-dev",
prompt="一只猫在沙发上午睡",
size="1024x1024"
)
print(resp.data[0].url)
# 智谱 --- CogView-4(支持对话式迭代编辑)
from zhipuai import ZhipuAI
client = ZhipuAI(api_key="xxx")
resp = client.images.generations(
model="cogview-4",
prompt="一只猫在沙发上午睡",
size="1024x1024"
)
# 阿里百炼 --- Qwen-Image(中文文字渲染领先)
import dashscope
from dashscope import ImageSynthesis
resp = ImageSynthesis.call(
api_key="sk-xxx", model="qwen-image-max",
prompt="一只猫在沙发上午睡", n=1, size="1024*1024"
)
2.3 多模型统一接入
当需要在一个项目里灵活切换不同厂商的模型时,在服务端加一层统一的 API 网关。
方案 A:one-api(Go 实现,Web 管理界面)
bash
# 部署后,所有模型通过同一个 base_url 访问
# 在管理界面配置各厂商的渠道和模型映射
# 客户端只需改 model 名称即可切换厂商
客户端 → one-api (http://localhost:3000/v1)
├── model="deepseek-chat" → 转发至 DeepSeek API
├── model="glm-4.6" → 转发至 智谱 API
└── model="qwen3.5" → 转发至 阿里百炼 API
方案 B:LiteLLM(Python 库 + 代理服务)
python
# pip install litellm
from litellm import completion
# 模型名格式:provider/model_name
response = completion(
model="deepseek/deepseek-chat",
messages=[{"role": "user", "content": "你好"}]
)
response = completion(
model="openai/gpt-5",
messages=[{"role": "user", "content": "你好"}]
)
# 同一套代码,切换模型只需改 model 字符串
2.4 切换模型时的 Token 成本变化
切换模型(如从 DeepSeek 换到 GLM)不只是改一行 base_url 和 model 名字------不同模型的 Tokenizer 不同,相同文本产生的 Token 数量差异可能很大。
Tokenizer 对比示例(以同一句中文为例):
输入文本:"解释一下 Java 中 AbstractQueuedSynchronizer 的工作原理"
DeepSeek V3 Tokenizer(BBPE,词表约 10 万):
Token 数 ≈ 18
GLM-4 Tokenizer(BPE,词表约 6.5 万):
Token 数 ≈ 22(词表更小 → 更多短词被拆分为多个 Token)
Qwen2.5 Tokenizer(BPE,词表约 15 万):
Token 数 ≈ 15(词表更大 → 长词更可能被编码为单个 Token)
对成本的影响:
| 模型 | 英文 Token 效率 | 中文 Token 效率 | 代码 Token 效率 |
|---|---|---|---|
| DeepSeek V3 | 约 1.3 Token/词 | 约 1.5 Token/字 | 约 0.4 Token/字符 |
| Qwen 2.5 | 约 1.2 Token/词 | 约 1.2 Token/字 | 约 0.5 Token/字符 |
| GLM-4 | 约 1.4 Token/词 | 约 1.8 Token/字 | 约 0.5 Token/字符 |
实用建议:
- 中英文混合内容(如代码注释)→ Qwen 的 Tokenizer 效率最高(词表大、覆盖面广)
- 纯代码补全 → DeepSeek 的 BBPE Tokenizer 对代码常用模式有优化
- 评估成本时要实测 Token 数 ------不要用"字符数 ÷ 2 = Token 数"这种粗略估算。最可靠的方式是直接查看厂商 API 返回的
usage.prompt_tokens字段
三、本地部署 --- 文本模型
3.1 方案总览
Ollama 最简单的本地部署方案,一行命令下载+启动
适合:个人使用、快速体验、开发调试
不适合:高并发生产环境
llama.cpp C++ 实现的纯推理引擎,CPU 推理优化最佳
适合:无显卡场景、嵌入式设备、底层定制
不适合:需要 HTTP API 的场景(需自己封装)
vLLM 生产级高并发推理服务,OpenAI 兼容 API
适合:团队共享、需要高吞吐的服务
不适合:消费级显卡(显存开销大)
PyTorch + 灵活度最高的方案,研究/训练/自定义模型
transformers 适合:微调模型、研究实验、自定义推理逻辑
不适合:快速部署(代码量大)
3.2 Ollama --- 最简本地部署
安装:
bash
# Linux / macOS
curl -fsSL https://ollama.com/install.sh | sh
# Windows:下载安装包 https://ollama.com/download
使用:
bash
# 下载并运行模型(首次运行自动下载)
ollama run qwen2.5:7b # 7B 量化版,约 4GB
ollama run qwen2.5:14b # 14B 量化版,约 9GB
ollama run deepseek-r1:7b # DeepSeek R1 推理模型
# 查看已下载的模型
ollama list
# 启动 API 服务(默认 http://localhost:11434)
ollama serve
调用 Ollama API(OpenAI 兼容格式):
python
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:11434/v1", # Ollama 本地地址
api_key="ollama" # Ollama 不需要真实 key
)
response = client.chat.completions.create(
model="qwen2.5:7b",
messages=[{"role": "user", "content": "你好"}]
)
print(response.choices[0].message.content)
Ollama 内部架构:
ollama run qwen2.5:7b
│
▼
┌─────────────────────────────────────┐
│ Ollama (Go 编写的管理程序) │
│ - 管理模型下载(从 ollama.com 拉取) │
│ - 管理模型加载/卸载(显存调度) │
│ - 暴露 HTTP API (:11434) │
│ - 提供 OpenAI 兼容端点 │
├─────────────────────────────────────┤
│ llama.cpp (C++ 推理引擎) │
│ - 加载 GGUF 格式的量化模型权重 │
│ - 执行 Transformer 推理 │
│ - GPU (CUDA/Metal) + CPU 混合推理 │
└─────────────────────────────────────┘
3.3 llama.cpp --- 纯推理引擎
Ollama 底层使用的推理引擎。适合需要底层控制或 CPU-only 部署的场景。
GGUF 格式是什么 :GGUF(GPT-Generated Unified Format)是一种将模型推理所需全部数据打包为单个文件的格式。一个
.gguf文件内部包含三部分:
- 模型权重:按层级组织的浮点参数(支持 2-bit 到 8-bit 多种量化精度)
- Tokenizer 词表:文本↔Token ID 的映射表(模型不再需要外部 tokenizer 文件)
- 模型配置元数据:层数、隐藏维度、头数、上下文长度、量化方式等超参数
.gguf的价值在于自包含------一个文件就是完整的模型,不需要 PyTorch、不需要 Python、不需要多个 safetensors 文件。llama.cpp 直接读取 GGUF 即可执行推理。Ollama 在下载模型时自动转换为 GGUF 格式存储。
bash
# 编译
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp && make
# 下载模型(GGUF 格式,从 HuggingFace 获取)
wget https://huggingface.co/Qwen/Qwen2.5-7B-Instruct-GGUF/resolve/main/qwen2.5-7b-instruct-q4_k_m.gguf
# 交互式对话
./llama-cli -m qwen2.5-7b-instruct-q4_k_m.gguf -p "你好" -n 256
# 启动 HTTP 服务
./llama-server -m qwen2.5-7b-instruct-q4_k_m.gguf --port 8080
与 Ollama 的区别:Ollama 替你管理了 llama.cpp 的编译、参数调优、模型下载和 API 封装。直接使用 llama.cpp 可以获得更精细的控制(自定义量化参数、调整 GPU 层数等),但需要更多手动配置。
3.4 vLLM --- 生产级推理服务
用于需要高并发、低延迟的团队共享场景。
bash
# 安装
pip install vllm
# 启动(自动加载模型,暴露 OpenAI 兼容 API)
vllm serve Qwen/Qwen2.5-7B-Instruct \
--host 0.0.0.0 --port 8000 \
--max-model-len 8192 \
--gpu-memory-utilization 0.9
# 如果使用 AWQ/GPTQ 量化模型以节省显存(7B 模型从 14GB 降至 ~4GB):
vllm serve Qwen/Qwen2.5-7B-Instruct-AWQ \
--quantization awq \
--host 0.0.0.0 --port 8000
python
# 客户端调用 --- 与调 OpenAI API 完全一致
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="unused")
response = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[{"role": "user", "content": "你好"}]
)
vLLM 的核心优化:
| 优化技术 | 效果 |
|---|---|
| PagedAttention | 将 KV Cache 分页管理,显存利用率提升 2-4 倍 |
| Continuous Batching | 动态合并请求,GPU 利用率大幅提升 |
| Tensor Parallelism | 单模型拆分到多张显卡并行推理 |
| Prefix Caching | 相同前缀(System Prompt)只计算一次 |
| AWQ/GPTQ 量化 | 加载 4-bit 量化模型,显存占用降至原始的 1/4,质量损失极小 |
附:KV Cache 的工作原理与显存计算
KV Cache 是理解大模型推理性能的关键概念。PagedAttention、Prefix Caching 等所有高级优化都建立在 KV Cache 之上。
为什么需要 KV Cache:
Transformer 的自注意力机制中,每个 Token 需要与所有之前的 Token 计算注意力权重。在自回归生成(逐 Token 输出)时,如果没有缓存:
生成第 1 个 Token:计算 "你好" 的 Key 和 Value
生成第 2 个 Token:重新计算 "你好"+"," 的 Key 和 Value(前面算过的白算了)
生成第 3 个 Token:重新计算 "你好"+","+"世界" 的 Key 和 Value
...
KV Cache 的做法:每次只计算新 Token 的 K/V,把之前所有 Token 的 K/V 保存到显存中,下次直接读取。
生成第 1 个 Token:计算 "你好" 的 K/V → 存入 Cache
生成第 2 个 Token:从 Cache 读取 "你好" 的 K/V + 只计算 "," 的 K/V → 存入 Cache
生成第 3 个 Token:从 Cache 读取前 2 个的 K/V + 只计算 "世界" 的 K/V
...
计算量从 O(n²) 降为 O(n),其中 n 是已生成的 Token 数量。
KV Cache 的显存占用公式:
KV Cache 显存 = 2 × batch_size × num_layers × num_kv_heads × head_dim × seq_len × dtype_bytes
参数说明:
2 → Key + Value 两份(各占一半)
batch_size → 同时处理的请求数(vLLM 的 Continuous Batching 中可能 >1)
num_layers → Transformer 的层数(7B 模型通常 28-32 层)
num_kv_heads → KV 注意力头数(GQA 模型会少于 Query 头数)
head_dim → 每个注意力头的维度(通常 128)
seq_len → 序列长度(Prompt + 已生成的 Token)
dtype_bytes → 数据类型字节数(fp16=2, bf16=2, fp8=1)
实际案例:
Qwen2.5-7B-Instruct(num_layers=28, num_kv_heads=4, head_dim=128, dtype=fp16):
单请求(batch=1)、序列长度 4096 Token:
KV Cache = 2 × 1 × 28 × 4 × 128 × 4096 × 2 ≈ 235 MB
单请求、序列长度 32768 Token(vLLM 默认 max-model-len):
KV Cache = 2 × 1 × 28 × 4 × 128 × 32768 × 2 ≈ 1.88 GB
8 并发请求、序列长度 8192 Token:
KV Cache = 2 × 8 × 28 × 4 × 128 × 8192 × 2 ≈ 3.76 GB
权重本身(bf16):约 14 GB
峰值显存(权重 + KV Cache + 临时计算):14 + 3.76 + ~2 = 约 20 GB(需要 24GB 显卡)
这意味着什么:
- 上下文越长,KV Cache 占比越大(长对话场景下 KV Cache 可能超过模型权重本身)
- vLLM 的 PagedAttention 正是通过分页管理 KV Cache 来提高利用率------未使用的"页"可以换出或共享
- DeepSeek-V3(671B MoE,激活 37B)等大模型在长上下文下的 KV Cache 压力是其工程优化的核心战场
三方案选型:
个人电脑、想立刻用 → Ollama
服务器、多人共享 → vLLM
嵌入设备、无 GPU → llama.cpp
做研究、要改模型 → PyTorch + transformers
四、本地部署 --- 图片模型
4.1 为什么没有"图片版 Ollama"
文本模型的本地部署可以一行命令搞定(ollama run qwen2.5:7b),是因为文本模型的结构高度标准化------一个模型文件、统一输入(Token 序列)、统一输出(Token 序列)。
图片模型的情况不同:
文本模型 图片模型
──────── ────────
结构 单个 Transformer Text Encoder + UNet + VAE + Scheduler
一个 .gguf 文件 一套 .safetensors 文件(3-5 个)
+ model_index.json(索引配置)
输入 文字 Prompt 文字 + 可选图片 + 可选遮罩 + 可选控制图
只有一种 多种输入形态组合
输出 文字 像素矩阵(还需后处理)
只有一种 不同任务输出格式各异
统一工具 ✅ Ollama ❌ 不存在等价的一键工具
标准 chat API 最接近的是 ComfyUI(可视化)
但仍需理解管线概念才能使用
4.2 方案 A:diffusers + Python 脚本(最灵活)
python
# 文生图 --- 最简示例
from diffusers import AutoPipelineForText2Image
import torch
pipe = AutoPipelineForText2Image.from_pretrained(
"black-forest-labs/FLUX.1-schnell",
torch_dtype=torch.bfloat16
).to("cuda")
image = pipe(
prompt="一只橘猫在沙滩上",
num_inference_steps=4,
).images[0]
image.save("output.jpg")
优点 :完全掌控管线、可自由组合 LoRA/ControlNet/IP-Adapter。
缺点:需要编写代码处理每种任务、无内置 HTTP 接口。
4.3 方案 B:ComfyUI --- 可视化工作流 + API 模式
ComfyUI 提供可视化节点编排界面,同时内置 API 模式,可被外部程序调用。
安装与启动:
bash
git clone https://github.com/comfyanonymous/ComfyUI.git
cd ComfyUI
pip install -r requirements.txt
python main.py --listen 0.0.0.0 --port 8188
# API 模式启动后,可通过 HTTP 提交工作流 JSON
通过 API 调用 ComfyUI:
python
import json, requests, urllib
# 1. 加载工作流模板(在 ComfyUI 界面搭好后导出为 JSON)
with open("workflow.json") as f:
workflow = json.load(f)
# 2. 修改 Prompt
workflow["6"]["inputs"]["text"] = "一只橘猫在沙滩上,日落光线"
# 3. 提交任务
resp = requests.post(
"http://127.0.0.1:8188/prompt",
json={"prompt": workflow}
)
prompt_id = resp.json()["prompt_id"]
# 4. 轮询结果
import time
while True:
history = requests.get(f"http://127.0.0.1:8188/history/{prompt_id}").json()
if prompt_id in history:
for output in history[prompt_id]["outputs"].values():
for img in output.get("images", []):
# 下载生成的图片
img_data = requests.get(
f"http://127.0.0.1:8188/view?filename={img['filename']}"
).content
with open(img["filename"], "wb") as f:
f.write(img_data)
break
time.sleep(1)
ComfyUI 的优势:不用写推理代码,在界面里拖拽节点构建管线(文生图、图生图、Inpainting 等),调好参数后导出为 JSON,之后通过 API 批量调用。
4.4 方案 C:diffusers + FastAPI 自建服务
如果需要完全编程控制且希望封装为 HTTP API,手动服务化是最灵活的方式:
python
# image_service.py
from fastapi import FastAPI, Form
from fastapi.responses import Response
from diffusers import AutoPipelineForText2Image
import io, torch
app = FastAPI()
pipe = None
@app.on_event("startup")
async def load_model():
global pipe
pipe = AutoPipelineForText2Image.from_pretrained(
"black-forest-labs/FLUX.1-schnell",
torch_dtype=torch.bfloat16
).to("cuda")
@app.post("/generate")
async def generate(prompt: str = Form(...)):
image = pipe(prompt=prompt).images[0]
buf = io.BytesIO()
image.save(buf, format="JPEG", quality=95)
return Response(content=buf.getvalue(), media_type="image/jpeg")
# 启动:uvicorn image_service:app --port 8000
# 调用:curl -X POST http://localhost:8000/generate -F "prompt=一只猫" -o cat.jpg
4.5 图片模型部署三方案对比
| diffusers 脚本 | ComfyUI | FastAPI 自建 | |
|---|---|---|---|
| 使用门槛 | 需编写 Python | 可视化拖拽,低代码 | 需编写 Python + HTTP |
| 灵活性 | 最高(完全编程控制) | 中(受节点能力限制) | 最高(完全编程控制) |
| API 化 | 需手动封装 | 内置 API | 本意就是 API |
| 批量生产 | 手动循环 | API 批量调用 | 天然支持并发队列 |
| 适合谁 | 研究者、调试者 | 设计师、非程序员 | 后端工程师 |
五、模型运行时、Agent 与模型的关系
这是初学者最容易混淆的三层概念。
5.1 三层架构
┌─────────────────────────────────────────────────────────┐
│ Agent(智能体) │
│ │
│ Claude Code / Cursor / Copilot / 自建 Agent │
│ │
│ "大脑的额叶"------决策层 │
│ 职责:接收任务 → 拆解步骤 → 决定调什么工具 → 分析结果 │
│ → 决定是否继续 → 最终回复用户 │
├─────────────────────────────────────────────────────────┤
│ 模型运行时(Model Runtime) │
│ │
│ Ollama / vLLM / llama.cpp / PyTorch / diffusers │
│ │
│ "大脑的神经元"------执行层 │
│ 职责:接收文本请求 → 运行模型推理 → 返回推理结果 │
│ 不关心"为什么"调它,只关心"怎么算" │
├─────────────────────────────────────────────────────────┤
│ 模型(Model) │
│ │
│ Qwen / DeepSeek / FLUX / SD 3.5 ... │
│ │
│ "大脑存储的知识"------知识层 │
│ 职责:权重文件(.gguf / .safetensors),网络结构定义 │
│ 本身不执行任何计算,需运行时加载后才能"工作" │
└─────────────────────────────────────────────────────────┘
5.2 三层关系
Ollama 不是 Agent。
Ollama 是模型运行时------它只负责"收文本 → 模型计算 → 返回文本"。
Claude Code 是 Agent。
它调用的模型运行时可以是 DeepSeek 远程 API、可以是 Ollama 本地服务、
可以是 OpenAI API------Agent 不关心运行时是谁,只关心它能收到文本回复。
模型是纯粹的数据 + 结构定义,不包含任何执行逻辑。
没有运行时加载,模型文件只是一堆字节。
5.3 常见 Agent 形态
| Agent | 底层模型(可换) | 工具调用 | 适用场景 |
|---|---|---|---|
| Claude Code | Claude / DeepSeek(可换) | Bash, Read, Edit, MCP | 命令行编程助手 |
| Cursor | GPT / Claude / 自定义 | 代码编辑、终端、LSP | IDE 内编程助手 |
| GitHub Copilot | GPT / Claude | 代码补全、Chat、Agent | IDE 内编程助手 |
| 自建 Agent | 任意(OpenAI 兼容即可) | 自定义工具集 | 特定业务场景 |
六、Claude Code 深度拆解
Claude Code 是当前最典型的 Agent 实现之一。以下拆解其核心机制。
6.1 启动时做了什么
用户执行 claude(或在 IDE 中打开 Claude Code)
│
▼
┌─────────────────────────────────────────┐
│ 1. 读取配置 │
│ - settings.json(用户权限、MCP 服务器) │
│ - CLAUDE.md(项目指令) │
│ - .claude/ 目录(Memory、Corrections) │
│ - 环境变量(API key、代理配置等) │
├─────────────────────────────────────────┤
│ 2. 建立与模型的连接 │
│ - 根据配置 base_url + api_key │
│ - 验证连接可用性 │
├─────────────────────────────────────────┤
│ 3. 加载 MCP 服务器 │
│ - 启动配置中列出的 MCP 子进程 │
│ - 获取各 MCP 提供的工具列表 │
│ - 将工具定义注册到 Agent 的工具集 │
├─────────────────────────────────────────┤
│ 4. 构建系统提示词(System Prompt) │
│ - 注入项目指令(CLAUDE.md 内容) │
│ - 注入 Memory(当前项目的记忆文件) │
│ - 注入可用工具列表及使用说明 │
│ - 注入行为约束规则 │
├─────────────────────────────────────────┤
│ 5. 等待用户输入 │
└─────────────────────────────────────────┘
6.2 每次对话做了什么
用户输入消息
│
▼
┌─────────────────────────────────────────┐
│ 1. 组装请求体 │
│ system: 系统提示词(含工具定义) │
│ messages: 对话历史(经过上下文管理) │
│ tools: 可用工具列表(JSON Schema) │
├─────────────────────────────────────────┤
│ 2. 发送 POST 请求至模型 API │
│ POST /v1/chat/completions │
│ Body: { model, messages, tools, ... } │
├─────────────────────────────────────────┤
│ 3. 接收模型响应 │
│ 情况 A:返回纯文本 → 展示给用户,结束 │
│ 情况 B:返回工具调用 → 进入工具循环 │
└─────────────────────────────────────────┘
6.3 工具调用循环(Agent 的核心机制)
模型回复:"我需要执行 read_file 来查看代码"
│
▼
┌──────────────────────────────────────────────┐
│ 模型返回的不是文字,而是一个结构化的工具调用: │
│ { │
│ "tool_calls": [{ │
│ "function": { │
│ "name": "read_file", │
│ "arguments": {"file_path": "/a/b.py"} │
│ } │
│ }] │
│ } │
├──────────────────────────────────────────────┤
│ 1. Claude Code 收到这个 JSON │
│ 2. 检查权限:该工具是否需要用户批准? │
│ - 需要批准 → 弹出确认框等待用户操作 │
│ - 不需要 → 直接执行 │
│ 3. 执行工具(如:读取文件) │
│ 4. 将工具执行结果作为新消息追加到对话历史: │
│ {"role": "tool", "content": "文件内容..."} │
│ 5. 再次调用模型(带上工具结果) │
│ 6. 模型基于结果继续推理 → 可能再调工具或回复文字 │
│ 7. 循环直到模型回复纯文本(不再调工具) │
└──────────────────────────────────────────────┘
一个典型的对话轨迹:
[user] "帮我修复 test.py 中的 bug"
↓
[model] "我先看看 test.py 的内容" → tool_call: Read("test.py")
↓ (工具执行)
[tool] "文件内容是:def foo():\n return 1/0"
↓
[model] "找到了,是除零错误" → tool_call: Edit("test.py", ...)
↓ (工具执行)
[tool] "文件已修改"
↓
[model] "已修复。将 `1/0` 改为 `1/1`,现在运行测试验证一下?"
↓ (如果用户说"运行")
[model] → tool_call: Bash("python -m pytest test.py")
↓
[tool] "测试通过"
↓
[model] "测试全部通过,修复完成。"
6.4 上下文管理
每次调用模型都需要携带对话历史。但对话历史会随着使用不断增长,超出模型的上下文窗口。Claude Code 通过以下机制处理:
| 机制 | 作用 |
|---|---|
| 上下文压缩(Compaction) | 当对话过长时,将早前的内容压缩为摘要,释放上下文空间 |
| Memory 系统 | 将关键事实持久化到 ~/.claude/projects/<项目>/memory/,跨会话保留 |
| CLAUDE.md 注入 | 项目指令始终在 System Prompt 中,不随对话增长而丢失 |
| 子 Agent 隔离 | 使用 Agent 工具启动子任务,子 Agent 有独立上下文,完成后只返回结果 |
6.5 MCP 协议 --- 扩展能力的标准接口
MCP(Model Context Protocol)是 Claude Code 扩展工具能力的标准机制。通过配置 MCP Server,Claude Code 可以获得超出内置工具(Bash/Read/Edit)之外的能力。
MCP 的工作原理:
┌──────────────────┐ MCP 协议 ┌──────────────────┐
│ Claude Code │ ←─────────────→ │ MCP Server │
│ (MCP Client) │ JSON-RPC │ (独立进程) │
│ │ over stdio/SSE │ │
│ │ │ │
│ "帮我搜索数据库" │ ① 列出可用工具 │ PostgreSQL MCP │
│ │ ② 调用工具 │ → 执行 SQL 查询 │
│ │ ③ 返回结果 │ │
└──────────────────┘ └──────────────────┘
MCP 的配置示例 (settings.json):
json
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-chrome-devtools"]
},
"context7": {
"command": "npx",
"args": ["-y", "@context7/mcp-server"]
},
"custom-image-gen": {
"command": "python",
"args": ["D:/tools/image_mcp_server.py"]
}
}
}
七、如何扩展 Claude Code 的能力
7.1 更换对话模型
Claude Code 通过 base_url + api_key 连接对话模型。只要目标模型支持 OpenAI 兼容的 /v1/chat/completions 端点(且支持 Tool Calling),即可替换。
bash
# 环境变量方式
export ANTHROPIC_BASE_URL="https://api.deepseek.com"
export ANTHROPIC_API_KEY="sk-xxxxxxxx"
# 或在 settings.json 中配置
注意:不是所有模型都支持 Tool Calling(函数调用)。如果模型不支持工具调用,Agent 的核心循环就无法运作------模型只能回复文字,不会触发工具执行。选择替代模型时需确认其支持 Function Calling / Tool Use。
7.2 通过 MCP 接入图片生成能力
Claude Code 本身是文本 Agent,不能直接生成图片。但通过 MCP,可以接入图片生成能力:
python
# image_gen_mcp_server.py --- 一个最简单的图片生成 MCP Server
import json
import sys
from openai import OpenAI
client = OpenAI(
base_url="https://api.siliconflow.cn/v1",
api_key="sk-xxx"
)
async def handle_request(request):
"""处理 JSON-RPC 请求"""
req = json.loads(request)
method = req.get("method")
if method == "tools/list":
# 返回可用工具列表
return json.dumps({
"tools": [{
"name": "generate_image",
"description": "根据文字描述生成图片,返回图片URL",
"inputSchema": {
"type": "object",
"properties": {
"prompt": {"type": "string", "description": "图片描述"}
},
"required": ["prompt"]
}
}]
})
elif method == "tools/call":
# 执行工具调用
args = req["params"]["arguments"]
resp = client.images.generate(
model="black-forest-labs/FLUX.1-dev",
prompt=args["prompt"],
size="1024x1024"
)
return json.dumps({
"content": [{"type": "text", "text": f"图片已生成:{resp.data[0].url}"}]
})
# stdio 模式下循环读取请求
for line in sys.stdin:
response = handle_request(line)
sys.stdout.write(response + "\n")
sys.stdout.flush()
配置后,在 Claude Code 中说出"帮我生成一张猫的图片",Agent 会:
- 判断需要调用
generate_image工具 - 提取 Prompt = "猫的图片"
- 执行 MCP 工具 → 调 SiliconFlow API → 返回图片 URL
- 将 URL 展示给你
7.3 通过 MCP 接入其他能力
| MCP Server 类型 | 赋予的能力 |
|---|---|
| 文件系统 | 浏览/编辑本地文件 |
| 数据库 (PostgreSQL/MySQL/SQLite) | 执行 SQL 查询、查看表结构 |
| 浏览器 (Playwright/Puppeteer) | 打开网页、截图、点击、填表 |
| 搜索引擎 (Brave/Google) | 网络搜索 |
| 代码仓库 (GitHub/GitLab) | 创建 Issue、提交 PR、搜索代码 |
| 知识库 (Context7) | 查询最新框架文档 |
| 图片生成 | 远程调图片 API |
| 自定义业务 | 任何能封装成 API 的企业内部系统 |
7.4 MCP Server 的两种通信模式
stdio 模式(标准输入输出): SSE 模式(Server-Sent Events):
Claude Code ──启动子进程──→ MCP Server Claude Code ──HTTP 长连接──→ MCP Server
│ │ │ │
└── JSON 通过 stdin/stdout ──┘ └── JSON 通过 HTTP ────────┘
适合:本地工具、单用户 适合:远程工具、多用户共享
八、全文回顾
远程 API 调用 本地部署
═════════════ ══════════
文本模型:OpenAI 兼容协议 文本模型:Ollama(简单)/ vLLM(生产)
调 DeepSeek/智谱/阿里... llama.cpp(纯引擎)/ PyTorch(研究)
图片模型:也有 OpenAI 兼容端点 图片模型:无"图片版 Ollama"
调 SiliconFlow/智谱/阿里 diffusers 脚本 / ComfyUI / FastAPI 自建
和文本 API 只是端点不同 管线复杂、子模型多,暂无统一一键工具
Agent(Claude Code)
═════════════════
模型无关(可换 base_url)
核心 = 工具调用循环
MCP = 扩展能力的标准协议
通过 MCP 可接入图片生成等任意能力
配套阅读:
- 《AI图片视频处理学习.md》------图片/视频 AI 的原理与实操
- 《AI图片视频处理-工具使用手册.md》------图片/视频 AI 的可执行命令速查
- 《AI专题学习手册.md》------AI 应用开发系统学习(Prompt/RAG/Agent/工程化)