大模型本地部署与远程调用 — 从 API 到 Agent

摘要:本文档系统梳理大模型(文本与图像)的远程 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_urlmodel 名字------不同模型的 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 文件内部包含三部分:

  1. 模型权重:按层级组织的浮点参数(支持 2-bit 到 8-bit 多种量化精度)
  2. Tokenizer 词表:文本↔Token ID 的映射表(模型不再需要外部 tokenizer 文件)
  3. 模型配置元数据:层数、隐藏维度、头数、上下文长度、量化方式等超参数

.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 会:

  1. 判断需要调用 generate_image 工具
  2. 提取 Prompt = "猫的图片"
  3. 执行 MCP 工具 → 调 SiliconFlow API → 返回图片 URL
  4. 将 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 可接入图片生成等任意能力

配套阅读

相关推荐
猿的天空1 小时前
AI视觉原生统一!商汤开源视觉任务大统一模型SenseNova-Vision
人工智能·计算机·ai·程序员·大模型·编程·智能体
码农进化录1 小时前
Java 程序员的 AI 进化论 | Spring Boot 接入 OpenAI 的六个坑,全帮你踩了
java·spring boot·openai
EAIReport1 小时前
2026开源AI应用平台深度对比:Dify vs AIFlowy 企业落地选型指南
人工智能·开源
神奇小汤圆1 小时前
Loop Engineering 实战:/goal 命令让 AI 自己写完整项目
人工智能
Anova.YJ1 小时前
AI Notebook
人工智能·python·机器学习
秦先生在广东1 小时前
Agent Island:把 Claude Code / Codex 的会话状态塞进刘海儿屏
人工智能
疯狂成瘾者1 小时前
Java 常见集合方法
java·windows·python
从此以后自律1 小时前
ConcurrentHashMap 超详细详解
java
阿里云大数据AI技术1 小时前
EMR Serverless Daft 如何简化多模态数据处理:视频抽帧、清洗、标注全流程与具身智能实践
人工智能·spark