Transformer 不是某个能一键下载、双击运行的软件,它是一个模型架构,也是当前几乎所有主流语言模型、多模态模型的底层骨架。很多人已经把各类 AI 助手用得很熟,但真要自己在本地起一个基于 Transformer 的生成模型,反而会卡在环境、显存、接口封装这些工程问题上。这篇文章就把 Transformer 当成一个可以部署、可测试、可调接口的技术组件来拆解,而不是复述注意力机制的数学推导。
Transformer 最核心的几个特性:自注意力机制让每个 token 都能直接看到序列里的其他 token,解决了长距离依赖问题;位置编码让模型知道 token 的先后顺序;多头注意力把关注点拆到多个子空间,提升表达力;残差连接和 LayerNorm 让深层网络可以稳定训练。从工程角度看,它还有三个关键点:可以并行计算,可以用 GPU 加速,可以通过 HuggingFace Transformers 这类工具链直接加载开源权重。
这篇文章会带你走一遍完整流程:核心能力速览、适用场景与边界、环境准备、最小代码实现、加载预训练模型、功能测试、接口 API 封装、批量任务、显存与性能观察、常见问题排查、最佳实践。适合三类读者:刚接触 Transformer 想动手验证的算法实习生,要接文本生成能力的后端工程师,以及在做本地推理服务选型的 AI 应用开发者。如果你只关心“能不能在普通机器上跑起来、怎么跑、效果怎么验证”,这篇可以直接收藏。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 模型类型 | 序列建模架构,可覆盖文本、语音、图像等多模态任务 |
| 核心机制 | 自注意力、多头注意力、位置编码、残差连接、LayerNorm |
| 典型应用 | 文本生成、文本分类、机器翻译、摘要、代码补全、嵌入表示、多模态理解 |
| 硬件门槛 | CPU 可以跑推理但速度偏慢;大模型推理以 GPU 为主,实际显存按模型参数量和上下文长度定 |
| 支持框架 | PyTorch、TensorFlow、JAX、PaddlePaddle 等 |
| 启动方式 | 代码实现 + HuggingFace/Transformers 加载 + FastAPI 封装 |
| 接口 API | 可用 FastAPI、Flask 自建推理服务 |
| 批量任务 | 可通过 DataLoader、文件队列脚本批处理 |
| 应用场景 | 本地测试、内容生成、知识库问答、嵌入检索、批量文本处理 |
| 适合读者 | 算法工程师、后端工程师、AI 应用开发者 |
Transformer 对硬件的要求不是固定的。小规模模型在 CPU 上也能跑,但生成速度会明显慢于 GPU;参数量较大的开源模型,建议使用 8GB 以上显存的显卡,并在加载时关注显存占用。举例来说,7B 参数量的模型在 fp16 精度下,权重文件本身大约在 14GB 左右,这只是模型权重,还没算 KV Cache 和输入输出缓存。所以实际部署时,不能只看显存有没有 8GB,还要看上下文长度、批量大小和推理框架是否有优化。
2. 适用场景与使用边界
Transformer 适合处理序列数据,最成熟的场景是自然语言处理。文本生成、摘要、情感分类、翻译、代码补全、检索嵌入和知识库问答,都可以用同一套架构加不同任务头来实现。对后端工程师来说,最实用的方式是加载一个训练好的开源模型,把它封装成 HTTP 接口,这样前后端分离,调用方不需要关心模型细节。
它不适合所有场景。如果只是做简单的短文本分类,传统机器学习或者小型的 CNN/LSTM 可能更轻量,不需要引入大模型。延迟敏感的低端设备上,直接跑大模型也不现实,需要蒸馏、量化或者部署到专门推理框架。参数量越大的 Transformer 并不代表一定更好用,选型时要在效果、显存、推理速度和业务成本之间做权衡。
使用边界需要特别注意。Transformer 模型本身是技术工具,但训练数据来自互联网,输出可能存在偏见、幻觉或不当内容,生产环境必须加内容审核和人工复核。涉及用户隐私数据时要做脱敏处理,不要直接把私密文本送进公共 API。商用场景要检查模型许可证,遵守开源协议。涉及人脸、声音、版权素材的生成任务,必须确认授权来源,避免侵权和欺诈风险。
3. 环境准备与前置条件
3.1 操作系统与 Python 环境
Transformer 的部署基本支持 Linux、Windows 和 macOS。Linux 在 GPU 驱动和 CUDA 支持上最省心,Windows 也可以跑,只是某些依赖安装时会多几步。建议使用 Python 3.9 及以上版本,并用虚拟环境隔离项目依赖,避免不同项目之间产生版本冲突。
安装基础环境:
python -m venv .venv source .venv/bin/activate pip install --upgrade pip pip install torch transformers如果只需要 CPU 推理,安装默认的 PyTorch 即可。如果需要 GPU 加速,需要根据本机 CUDA 版本选择对应安装命令,具体命令以 PyTorch 官方网站为准。安装完成后,用一段代码验证环境是否正常:
import torch print(torch.__version__) print(torch.cuda.is_available())输出torch.cuda.is_available()为True,说明 GPU 可用。如果为False,就需要检查显卡驱动和 PyTorch 安装版本是否匹配。这一步先确认好,后面加载模型时才不会摸不清方向。
3.2 GPU 与 CUDA
GPU 不是必须的,但如果你想体验比较流畅的生成效果,建议使用 NVIDIA 显卡。显存大小直接决定你能加载多大参数的模型。粗略估算,加载一个 1.5B 参数的模型需要 3GB 左右显存,7B 参数量的模型在 fp16 精度下权重就需要约 14GB。这还只是权重部分,实际推理时还有 KV Cache 和激活值,所以显存不足时常见做法是选小模型、打开量化或者降低上下文长度。
CUDA 环境要检查三部分:显卡驱动版本、CUDA 版本、PyTorch 编译对应的 CUDA 版本。大多数情况下,驱动版本较新就能兼容多个 CUDA 版本,关键在 PyTorch 是否使用了正确的轮子。建议安装 PyTorch 前先执行nvidia-smi确认驱动,再去 PyTorch 官网选择匹配的安装命令。
3.3 磁盘空间与模型文件
预训练模型的体积通常不小。小模型可能几百 MB,大模型几十 GB。下载前先在磁盘上预留足够空间。建议把模型目录和数据目录分开,比如models/存放权重文件,data/存放输入素材,outputs/存放推理结果。这样清理缓存、替换模型、导出结果时都非常方便。
还建议配置 HuggingFace 缓存目录,避免每次下载模型都占满系统盘:
export HF_HOME=/path/to/your/hf_home4. Transformer 最小实现与启动方式
4.1 不依赖大模型库的最小实现
如果你想搞清楚 Transformer 的内部结构,最好的方式是自己写一个极简版本。下面代码是一个完整的、可运行的 Transformer Block,包含多头自注意力、前馈网络、残差连接和 LayerNorm。
import math import torch import torch.nn as nn class MultiHeadSelfAttention(nn.Module): def __init__(self, d_model, n_heads): super().__init__() assert d_model % n_heads == 0 self.d_model = d_model self.n_heads = n_heads self.head_dim = d_model // n_heads self.w_q = nn.Linear(d_model, d_model) self.w_k = nn.Linear(d_model, d_model) self.w_v = nn.Linear(d_model, d_model) self.w_o = nn.Linear(d_model, d_model) def forward(self, x, mask=None): batch, seq_len, _ = x.shape q = self.w_q(x).view(batch, seq_len, self.n_heads, self.head_dim).transpose(1, 2) k = self.w_k(x).view(batch, seq_len, self.n_heads, self.head_dim).transpose(1, 2) v = self.w_v(x).view(batch, seq_len, self.n_heads, self.head_dim).transpose(1, 2) scores = q @ k.transpose(-2, -1) / math.sqrt(self.head_dim) if mask is not None: scores = scores.masked_fill(mask == 0, float("-inf")) attn = torch.softmax(scores, dim=-1) out = attn @ v out = out.transpose(1, 2).contiguous().view(batch, seq_len, self.d_model) return self.w_o(out) class FeedForward(nn.Module): def __init__(self, d_model, d_ff): super().__init__() self.net = nn.Sequential( nn.Linear(d_model, d_ff), nn.ReLU(), nn.Linear(d_ff, d_model) ) def forward(self, x): return self.net(x) class TransformerBlock(nn.Module): def __init__(self, d_model, n_heads, d_ff): super().__init__() self.attn = MultiHeadSelfAttention(d_model, n_heads) self.ffn = FeedForward(d_model, d_ff) self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) def forward(self, x, mask=None): x = x + self.attn(self.norm1(x), mask) x = x + self.ffn(self.norm2(x)) return x class SinusoidalPositionalEncoding(nn.Module): def __init__(self, d_model, max_len=512): super().__init__() pe = torch.zeros(max_len, d_model) position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] = torch.sin(position * div_term) pe[:, 1::2] = torch.cos(position * div_term) pe = pe.unsqueeze(0) self.register_buffer("pe", pe) def forward(self, x): return x + self.pe[:, :x.size(1)] class MinimalTransformer(nn.Module): def __init__(self, vocab_size, d_model=128, n_heads=4, d_ff=512, num_layers=2, max_len=512): super().__init__() self.embed = nn.Embedding(vocab_size, d_model) self.pos = SinusoidalPositionalEncoding(d_model, max_len) self.blocks = nn.ModuleList([ TransformerBlock(d_model, n_heads, d_ff) for _ in range(num_layers) ]) self.norm = nn.LayerNorm(d_model) self.lm_head = nn.Linear(d_model, vocab_size) def forward(self, x): h = self.embed(x) h = self.pos(h) for block in self.blocks: h = block(h) h = self.norm(h) logits = self.lm_head(h) return logits这个实现没有用现成的 Transformer 封装层,每一步都是可读的原生 PyTorch 代码。可以用随机输入验证结构是否能跑通:
model = MinimalTransformer(vocab_size=1000, d_model=128, n_heads=4, d_ff=512, num_layers=2) x = torch.randint(0, 1000, (2, 32)) logits = model(x) print(logits.shape) # torch.Size([2, 32, 1000])前向传播能输出[batch, seq_len, vocab_size]的张量,说明网络的层与层之间的连接没有问题。这个玩具模型本身没有训练数据,所以不会生成有意义的内容,它存在的意义是帮助你理解 Transformer 各组件是如何拼接在一起的。实际业务中,更高效的方式是直接加载预训练权重,而不是从零训练。
4.2 用 HuggingFace Transformers 加载预训练模型
从零训练 Transformer 需要海量数据和算力,日常工程中很少会这么做。更常见的方式是使用 HuggingFace Transformers 库加载开源预训练模型。先安装依赖:
pip install transformers accelerate然后在 Python 中加载模型和分词器:
from transformers import AutoTokenizer, AutoModelForCausalLM model_name = "your-org/your-model" # 替换成实际模型 ID tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForCausalLM.from_pretrained(model_name)这里model_name需要替换为实际可用的开源模型 ID,例如你选择的对话模型、生成模型或代码模型。加载时如果显存不足,可以尝试load_in_8bit=True或load_in_4bit=True参数,但需要bitsandbytes支持:
model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", load_in_4bit=True )加载成功后,模型会自动根据device_map分配到可用的 GPU 或 CPU 上。
4.3 文本生成与第一次验证
首次启动时最值得做的验证是生成一段文字,确认模型、分词器和推理流程都正常。示例:
input_text = "Transformer 的核心机制是" inputs = tokenizer(input_text, return_tensors="pt") outputs = model.generate(**inputs, max_new_tokens=64) print(tokenizer.decode(outputs[0], skip_special_tokens=True))如果输出是一段通顺的文本,说明整个链路已经跑通。生成速度取决于模型大小、硬件条件和max_new_tokens的设置。第一次跑不建议直接生成太长内容,先把流程跑通,再逐步加长。这里还需要注意,生成任务自带随机性,每次输出不一定相同,这是正常现象。
5. 功能测试与效果验证
5.1 文本生成测试
文本生成是 Transformer 最常用的能力。测试时可以从几个维度验证。
首先是提示词长度测试。短提示词下,模型输出是否稳定;长提示词下,模型是否能保持上下文连贯。其次是生成长度测试,先设置max_new_tokens=32,观察输出是否完整;再设置max_new_tokens=256,看是否会重复、跑题或截断。然后是不同温度参数测试,temperature较低时输出更保守,temperature较高时输出更多样。
outputs = model.generate( **inputs, max_new_tokens=128, temperature=0.7, do_sample=True, top_p=0.9 )判断生成质量的标准不是单一的“像不像人话”,而是从任务角度判断:写摘要时是否抓住关键信息,写代码时语法是否正确,翻译时是否忠实原文。建议准备一组固定测试用例,每次改动模型或参数后跑同一批用例,才好对比效果。
5.2 文本分类测试
Transformer 不只是生成模型,也可以做分类。使用AutoModelForSequenceClassification加载带分类头的模型,输出的是每个类别的概率。
from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch model_name = "your-org/your-classification-model" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForSequenceClassification.from_pretrained(model_name) texts = ["服务很好", "等待时间太长"] inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt") with torch.no_grad(): outputs = model(**inputs) probs = torch.softmax(outputs.logits, dim=-1) print(probs)分类模型测试重点看三部分:标签分布是否合理、样本是否被正确分类、批量输入的 padding 和 truncation 是否正确处理。如果分类结果出现所有样本都集中到某一个标签,需要检查数据分布、模型训练质量或标签定义。
5.3 批量文本推理测试
批量推理是后端集成的常见需求。最简单的方式是循环遍历输入列表,逐条调用模型。如果显存足够,可以把多条样本放在同一个 batch 里,用 padding 对齐长度后一次性前向推理,这样吞吐量更高。但要注意,不同样本长度差距太大时,padding 会浪费算力,此时动态 batching 更合适。
批量测试建议先用 2 到 4 条样本跑通流程,再逐步增加 batch size。如果出现显存溢出,优先降低 batch size 或者缩短max_length。批量推理时要记录成功条数和失败条数,失败时要保留原始输入,方便定位是模型推理问题还是输入格式问题。判断批量任务成功的标准是:全部样本完成推理,输出文件和输入样本一一对应,且失败样本有明确原因记录。
6. 接口 API 与批量任务
6.1 FastAPI 封装推理接口
本地脚本调用模型虽然方便,但生产环境更适合把模型封装成 HTTP 服务。FastAPI 是常用的选择,异步支持好,文档自动生成,调用方通过 REST 接口访问推理能力。下面是一个最小可用的服务示例:
from fastapi import FastAPI from pydantic import BaseModel from transformers import AutoTokenizer, AutoModelForCausalLM app = FastAPI() class GenerateRequest(BaseModel): prompt: str max_new_tokens: int = 64 model_name = "your-org/your-model" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForCausalLM.from_pretrained(model_name) @app.post("/generate") def generate(req: GenerateRequest): inputs = tokenizer(req.prompt, return_tensors="pt") outputs = model.generate(**inputs, max_new_tokens=req.max_new_tokens) text = tokenizer.decode(outputs[0], skip_special_tokens=True) return {"text": text}模型在服务启动时加载,第一次请求不需要重复初始化。启动命令:
uvicorn app:app --host 127.0.0.1 --port 8000生产环境一般把host设为内网地址,避免直接把推理服务暴露到公网。如果端口被占用,可以更换--port参数。启动后访问http://127.0.0.1:8000/docs可以看到自动生成的接口文档,直接在里面测试请求。
6.2 curl 与 Python 调用
接口启动后,可以用 curl 做一次快速验证:
curl -X POST http://127.0.0.1:8000/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "用一句话介绍 Transformer", "max_new_tokens": 128}'用 Python 调用同样简单:
import requests url = "http://127.0.0.1:8000/generate" payload = { "prompt": "用一句话介绍 Transformer", "max_new_tokens": 128 } response = requests.post(url, json=payload, timeout=60) print(response.json())调用接口时要注意超时时间。大模型生成耗时通常比普通 HTTP 请求长,如果max_new_tokens设置得比较大,建议客户端把timeout调到 60 秒或更高,避免请求被提前断开。服务端也可以考虑把同步生成改成异步任务队列,但复杂度会上升,先用同步接口把流程跑通是更务实的路径。
6.3 批量任务设计与重试
批量任务建议用文件驱动的方式组织。输入文件用 JSONL 格式,每行一条样本,包含唯一 ID 和输入内容。处理脚本逐行读取、调用 API、把结果写入输出文件。
import json import time import requests results = [] with open("input.jsonl", "r", encoding="utf-8") as f: for line in f: item = json.loads(line) for attempt in range(3): try: resp = requests.post( "http://127.0.0.1:8000/generate", json={"prompt": item["prompt"], "max_new_tokens": 128}, timeout=60, ) resp.raise_for_status() results.append({"id": item["id"], "text": resp.json()["text"]}) break except Exception as exc: print(f"attempt {attempt + 1} failed: {exc}") time.sleep(2) else: results.append({"id": item["id"], "text": None}) with open("output.jsonl", "w", encoding="utf-8") as f: for r in results: f.write(json.dumps(r, ensure_ascii=False) + "\n")批量任务的关键是可控和可恢复。加日志、记录每个样本的状态、失败时重试,都是必须的。如果服务端不支持并发,客户端就不要盲目开多线程,否则模型排队时会把显存或内存打爆。可以先跑 10 条样本确认延迟,再决定是否提高并发数。
7. 资源占用与性能观察
7.1 如何观察显存占用
部署 Transformer 时,最直观的瓶颈往往是显存。观察显存的常用方式是nvidia-smi,在命令行持续刷新:
watch -n 1 nvidia-smi如果不想一直盯着终端,可以用 PyTorch 在代码里记录显存峰值:
import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0)) print(torch.cuda.max_memory_allocated() / 1024 ** 3)max_memory_allocated()返回的是当前进程分配的显存峰值,不包含 CUDA context 等额外开销,所以实际占用可能会略高一些。观察显存时,不仅要看模型加载后的占用,还要看生成过程中显存是否会继续上涨。长文本生成时,KV Cache 会占用大量显存,输入越长、输出越长,显存占用越高。
7.2 推理延迟与吞吐量
推理性能通常看两个指标:单次请求延迟和单位时间吞吐量。文本生成是逐步解码的,max_new_tokens越长,耗时越高。影响延迟的因素主要包括模型参数量、输入输出长度、硬件类型、推理框架优化和是否使用量化。CPU 推理在小模型上可以跑,但延迟明显高于 GPU;大模型在 CPU 上生成速度会很慢,交互式场景基本不建议。
性能测试时建议固定一组标准问题,分别测试不同长度输入下的响应时间。记录模型加载时间、单次生成时间、显存峰值和 CPU 内存占用。如果单次生成时间太长,优先检查是不是max_new_tokens设置过大、输入文本过长或者模型没有正确加载到 GPU。
7.3 降低显存占用的常用手段
显存不足时,可以按优先级尝试这几种方法。
调整生成参数最直接。减少max_new_tokens和输入长度,关闭采样或调低num_beams,能明显降低计算和显存压力。其次是用半精度或混合精度推理,PyTorch 里常用torch.float16或torch.bfloat16,显存占用大约比 fp32 降低一半。再进一步就是量化,8bit 或 4bit 量化能大幅降低显存占用,但输出质量可能会有轻微损失。
model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", torch_dtype=torch.float16, )最后是换小模型。如果任务本身不复杂,参数量更小的模型往往够用,推理速度和显存占用都更友好。实际占用需以本机测试为准,不同模型、不同上下文长度、不同推理框架的差异非常大,不要只看网上别人报的参数。
8. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 启动时无法导入 torch | 虚拟环境未激活或依赖安装不完整 | 检查pip list中 torch 是否存在 | 重新安装 PyTorch,确认安装命令与系统匹配 |
| CUDA 不可用 | 驱动版本过旧或 PyTorch 版本不匹配 | 运行nvidia-smi和torch.cuda.is_available() | 升级驱动,按 PyTorch 官方文档选择对应版本 |
| 加载模型时显存不足 | 模型参数过大或上下文长度过长 | 观察nvidia-smi显存占用 | 换小模型、开启量化、减少输入长度或 batch size |
| 模型文件下载失败 | 网络不稳定或磁盘空间不足 | 检查磁盘剩余空间和下载日志 | 清理磁盘,重新下载,配置 HF 缓存目录 |
| 生成输出质量差 | 提示词不清晰或模型规模太小 | 对比不同提示词和不同模型输出 | 优化提示词,换更大或更合适领域模型 |
| API 请求超时 | 模型推理慢或max_new_tokens过大 | 查看服务端日志和请求耗时 | 增加客户端 timeout,减小生成长度,优化推理配置 |
| 多线程并发请求卡死 | 模型实例并发不安全 | 观察请求队列和服务端日志 | 接口层加锁或改为单线程队列,使用推理框架做动态 batching |
| 中文输出乱码 | 分词器选择错误或解码参数问题 | 打印 tokenizer 的 decode 结果 | 使用与模型匹配的分词器,不手动修改特殊 token |
| 批量任务中途失败 | 某条输入格式异常或服务不可用 | 记录失败条目 ID 和错误信息 | 在脚本中加入重试机制,并保留失败输入用于复测 |
排查问题时有一个基本原则:先缩小范围。先确认是环境问题、模型问题还是代码问题,再逐步拆解。比如生成内容乱码,先检查输入编码,再检查分词器,最后检查模型输出,不要一上来就换模型。
9. 最佳实践与使用建议
第一次接触 Transformer 时,不要直接追求最大参数量的模型。先选择一个能在本机跑通的小模型,完成整个流程,再根据实际需求决定是否升级。这样能快速积累对环境、推理、接口封装的经验,也更容易定位问题。
项目目录建议分清楚:models/放权重文件,data/放输入数据,outputs/放生成结果,logs/放运行日志。不要把所有文件堆在一个目录里,后期维护会很痛苦。每次修改配置或模型时,把关键参数记录到实验笔记里,方便对比效果差异。
批量任务必须考虑失败重试。网络抖动、显存不足、单条输入格式异常都可能导致任务中断。脚本要记录每个样本的处理状态,支持断点续跑。断点续跑最简单的方式是输出文件按行追加,同时记录已处理样本 ID,下次运行时跳过这些 ID。
接口服务要注意访问控制。如果服务部署在服务器上,不要把端口直接暴露到公网。可以加 API Key 认证或放在内网访问。模型输出必须增加审核机制,尤其是面向用户的生成内容,避免未经审核的文本直接发布。
涉及人像、声音、版权素材的任务,必须确认授权。Transformer 能生成越来越逼真的文本和图像,但也意味着更容易被滥用。生成内容要标明来源,商用前要复核版权和合规性。数据用于训练或微调时,要检查数据来源是否合法,是否涉及个人隐私。
10. 总结与下一步
Transformer 不是某一个具体的模型,而是当前 AI 应用的主干架构。理解它的核心机制,会帮助你判断一个模型为什么适合某个任务,也会帮助你在部署遇到性能问题时找到方向。最有价值的点是整个部署路径很清晰:准备环境、加载权重、跑通生成、封装 API、加入批量任务和监控,每一步都能独立验证。
先跑通最小流程,再逐步扩展。刚上手时建议选择一个参数量适中的开源模型,先完成本地文本生成测试,观察显存占用和响应时间。然后封装成 FastAPI 接口,用 curl 和 Python 各调用一次,确保外部系统也能访问。最后再设计批量任务脚本,增加日志和重试机制。这一套流程走完,你对 Transformer 就不仅是知道注意力机制是怎么回事,而是真正能把它用起来了。
最容易踩的坑有两个:第一是显存估算失误,只看模型权重大小,忽略了 KV Cache 和上下文长度;第二是接口超时设置不合理,把大模型当成普通 HTTP 接口来调,结果生成还没结束就断连。先小参数测试、再加批量任务,是避免这两个问题最有效的方式。后续可以继续扩展的方向包括:用向量数据库接入私域知识库、尝试量化推理框架、把单机推理改成多 GPU 推理,以及探索多模态 Transformer 模型的实际落地。