Qwen大模型应用开发完全教程
本文全面介绍阿里云通义千问(Qwen)系列大模型的技术架构、能力特点、接入方式、部署方案与实战应用,帮助开发者快速掌握Qwen模型的工程化应用。
目录
1. Qwen2.5系列模型架构与能力
1.1 模型家族概览
Qwen2.5是阿里巴巴通义实验室推出的最新一代大语言模型系列,覆盖从0.5B到72B的多种规模。
| 模型 | 参数量 | 上下文长度 | 特点 | 适用场景 |
|---|---|---|---|---|
| Qwen2.5-0.5B | 5亿 | 32K | 超轻量,手机端可运行 | 边缘设备、移动端 |
| Qwen2.5-1.5B | 15亿 | 32K | 轻量级,速度快 | 嵌入式、IoT |
| Qwen2.5-3B | 30亿 | 32K | 平衡性能与资源 | 端侧推理 |
| Qwen2.5-7B | 70亿 | 128K | 主力开源模型 | 通用任务、RAG |
| Qwen2.5-14B | 140亿 | 128K | 高性能 | 复杂推理、专业领域 |
| Qwen2.5-32B | 320亿 | 128K | 接近顶级 | 企业级应用 |
| Qwen2.5-72B | 720亿 | 128K | 旗舰开源模型 | 最强能力,需大显存 |
| Qwen2.5-Turbo | 闭源 | 1M | 百万级上下文 | 超长文档处理 |
| Qwen2.5-Plus | 闭源 | 128K | 高性能API | 生产级API服务 |
| Qwen2.5-Max | 闭源 | 128K | 旗舰API | 最高精度需求 |
1.2 技术架构
Qwen2.5基于Transformer架构,采用多项关键优化:
- GQA(Grouped Query Attention):分组查询注意力,减少KV缓存显存占用
- RoPE(Rotary Position Embedding):旋转位置编码,支持长上下文
- SwiGLU激活函数:比ReLU更好的梯度流动
- RMSNorm:替代LayerNorm,训练更稳定
- YaRN扩展:将上下文从32K扩展到128K甚至1M
1.3 核心能力矩阵
| 能力维度 | Qwen2.5表现 | 说明 |
|---|---|---|
| 中文理解 | ⭐⭐⭐⭐⭐ | 国产模型中顶尖水平 |
| 英文能力 | ⭐⭐⭐⭐☆ | 接近GPT-4水平 |
| 代码生成 | ⭐⭐⭐⭐⭐ | Qwen2.5-Coder系列专精 |
| 数学推理 | ⭐⭐⭐⭐⭐ | Qwen2.5-Math系列专精 |
| 长文本 | ⭐⭐⭐⭐⭐ | 原生支持128K,Turbo支持1M |
| 多模态 | ⭐⭐⭐⭐☆ | Qwen2.5-VL支持图像和视频 |
| 工具调用 | ⭐⭐⭐⭐⭐ | 原生支持Function Calling |
| 多语言 | ⭐⭐⭐⭐☆ | 支持29+语言 |
2. API接入实战
2.1 DashScope API(阿里云官方)
# 安装SDK
# pip install dashscope
from dashscope import Generation
import dashscope
dashscope.api_key = "sk-your-dashscope-key"
# 基础对话
response = Generation.call(
model="qwen-turbo-latest",
messages=[
{"role": "system", "content": "你是一个专业的技术顾问"},
{"role": "user", "content": "解释一下什么是RAG?"}
],
result_format="message",
temperature=0.7,
max_tokens=2000
)
print(response.output.choices[0].message.content)
2.2 OpenAI兼容接口
Qwen提供了与OpenAI完全兼容的API接口,这意味着你可以直接使用OpenAI SDK:
from openai import OpenAI
client = OpenAI(
api_key="sk-your-dashscope-key",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 流式输出
stream = client.chat.completions.create(
model="qwen-plus",
messages=[
{"role": "system", "content": "你是一个Python编程专家"},
{"role": "user", "content": "写一个快速排序算法"}
],
stream=True,
temperature=0.3,
max_tokens=1500
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
2.3 Function Calling(工具调用)
from openai import OpenAI
import json
client = OpenAI(
api_key="sk-your-key",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 定义工具
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如'北京'"
},
"date": {
"type": "string",
"description": "日期,格式YYYY-MM-DD,默认今天"
}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "search_knowledge",
"description": "搜索内部知识库",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "搜索关键词"},
"top_k": {"type": "integer", "description": "返回结果数量"}
},
"required": ["query"]
}
}
}
]
# 工具执行函数
def execute_tool(name: str, args: dict):
if name == "get_weather":
return {"city": args["city"], "temperature": "25°C", "weather": "晴"}
elif name == "search_knowledge":
return {"results": [{"title": "RAG入门", "content": "..."}]}
# 多轮工具调用
messages = [{"role": "user", "content": "今天北京天气怎么样?帮我查一下"}]
response = client.chat.completions.create(
model="qwen-plus",
messages=messages,
tools=tools,
tool_choice="auto"
)
# 处理工具调用
while response.choices[0].message.tool_calls:
tool_calls = response.choices[0].message.tool_calls
messages.append(response.choices[0].message)
for tc in tool_calls:
result = execute_tool(
tc.function.name,
json.loads(tc.function.arguments)
)
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result, ensure_ascii=False)
})
response = client.chat.completions.create(
model="qwen-plus",
messages=messages,
tools=tools
)
print(response.choices[0].message.content)
2.4 多模态API调用
from openai import OpenAI
client = OpenAI(
api_key="sk-your-key",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 图片理解
response = client.chat.completions.create(
model="qwen-vl-plus",
messages=[
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"url": "https://example.com/image.jpg"}
},
{
"type": "text",
"text": "详细描述这张图片的内容"
}
]
}
]
)
print(response.choices[0].message.content)
2.5 API参数调优指南
| 参数 | 推荐值 | 说明 |
|---|---|---|
temperature |
0.1-0.3(任务型)/ 0.7-0.9(创作型) | 控制随机性 |
top_p |
0.8-0.95 | 核采样,与temperature二选一调节 |
max_tokens |
根据任务设定 | 避免不必要的长输出 |
presence_penalty |
0.0-0.5 | 抑制重复,创意任务可调高 |
seed |
固定值 | 需要可复现结果时使用 |
3. 本地部署方案
3.1 使用vLLM部署(推荐)
vLLM是高性能推理引擎,支持PagedAttention优化:
# 安装vLLM
pip install vllm
# 启动Qwen2.5-7B服务
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-7B-Instruct \
--served-model-name qwen2.5-7b \
--host 0.0.0.0 \
--port 8000 \
--max-model-len 32768 \
--gpu-memory-utilization 0.85 \
--tensor-parallel-size 1 \
--quantization awq
多卡部署72B模型:
# 4卡Tensor并行部署72B
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-72B-Instruct \
--served-model-name qwen2.5-72b \
--tensor-parallel-size 4 \
--max-model-len 131072 \
--gpu-memory-utilization 0.90 \
--enable-prefix-caching
3.2 使用Ollama部署(最简单)
# 安装Ollama
curl -fsSL https://ollama.com/install.sh | sh
# 一键拉取并运行
ollama run qwen2.5:7b
# 或使用量化版本
ollama run qwen2.5:7b-instruct-q4_K_M
# API调用(与OpenAI兼容)
curl http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5:7b",
"messages": [{"role": "user", "content": "你好"}],
"stream": false
}'
3.3 使用llama.cpp部署(边缘设备)
# 编译llama.cpp
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp && make
# 下载GGUF格式模型
# 从Hugging Face下载 Qwen2.5-7B-Instruct-Q4_K_M.gguf
# 启动服务
./llama-server \
-m ./models/qwen2.5-7b-instruct-q4_k_m.gguf \
--host 0.0.0.0 \
--port 8080 \
-c 8192 \
--n-gpu-layers 99
3.4 显存需求参考
| 模型 | FP16 | INT8 | INT4(GPTQ/AWQ) |
|---|---|---|---|
| 0.5B | ~1GB | ~0.5GB | ~0.3GB |
| 1.5B | ~3GB | ~1.5GB | ~1GB |
| 3B | ~6GB | ~3GB | ~2GB |
| 7B | ~14GB | ~7GB | ~4GB |
| 14B | ~28GB | ~14GB | ~8GB |
| 32B | ~64GB | ~32GB | ~18GB |
| 72B | ~144GB | ~72GB | ~40GB |
3.5 量化部署
使用AutoGPTQ进行INT4量化:
from transformers import AutoModelForCausalLM, AutoTokenizer
# 使用已量化的AWQ模型
model_name = "Qwen/Qwen2.5-7B-Instruct-AWQ"
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map="auto",
trust_remote_code=True
).eval()
# 推理
messages = [{"role": "user", "content": "什么是深度学习?"}]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tokenizer([text], return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=512)
print(tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True))
4. 多模态理解(Qwen-VL)
Qwen2.5-VL是通义千问的多模态版本,支持图像和视频理解。
4.1 图像理解
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
"Qwen/Qwen2.5-VL-7B-Instruct",
torch_dtype="auto",
device_map="auto"
)
processor = AutoProcessor.from_pretrained("Qwen/Qwen2.5-VL-7B-Instruct")
# 单图理解
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": "https://example.com/photo.jpg"},
{"type": "text", "text": "这张图片里有什么?请详细描述"}
]
}
]
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(
text=[text],
images=image_inputs,
videos=video_inputs,
padding=True,
return_tensors="pt"
).to(model.device)
generated_ids = model.generate(**inputs, max_new_tokens=512)
output = processor.decode(generated_ids[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
print(output)
4.2 视频理解
messages = [
{
"role": "user",
"content": [
{
"type": "video",
"video": "file:///path/to/video.mp4",
"max_pixels": 360 * 420, # 控制分辨率
"fps": 1.0 # 每秒采样帧数
},
{"type": "text", "text": "总结这个视频的主要内容"}
]
}
]
4.3 OCR与文档理解
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": "file:///path/to/document_scan.jpg"},
{"type": "text", "text": "提取图片中的所有文字,保持原始格式"}
]
}
]
4.4 图表与数据理解
messages = [
{
"role": "user",
"content": [
{"type": "image", "image": "file:///path/to/chart.png"},
{"type": "text", "text": "分析这张图表中的数据趋势,并给出关键洞察"}
]
}
]
5. 代码生成(Qwen-Coder)
Qwen2.5-Coder是专门针对代码任务优化的模型系列。
5.1 代码生成能力
from openai import OpenAI
client = OpenAI(
api_key="sk-your-key",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 生成代码
response = client.chat.completions.create(
model="qwen-coder-plus",
messages=[
{
"role": "system",
"content": "你是一个高级Python开发工程师,写出高质量、有注释的代码"
},
{
"role": "user",
"content": """
实现一个线程安全的LRU缓存,要求:
1. 支持get和put操作,时间复杂度O(1)
2. 支持设置最大容量和过期时间
3. 支持缓存统计(命中率、淘汰次数)
4. 提供完整的类型注解和docstring
"""
}
],
temperature=0.2
)
print(response.choices[0].message.content)
5.2 代码审查与重构
code_to_review = '''
def process_data(data):
result = []
for i in range(len(data)):
if data[i] != None:
result.append(data[i] * 2)
return result
'''
response = client.chat.completions.create(
model="qwen-coder-plus",
messages=[
{"role": "system", "content": "你是一个代码审查专家"},
{"role": "user", "content": f"""
审查以下Python代码,指出问题并提供改进版本:
```python
{code_to_review}
请从以下角度审查:
- 代码风格和PEP 8规范
- 性能优化
- 类型安全
- 边界条件处理
- 可读性改进 """} ] ) print(response.choices[0].message.content)
### 5.3 本地代码助手配置
在VS Code中使用Qwen作为代码助手:
```json
// .vscode/settings.json
{
"continue.models": [
{
"title": "Qwen2.5-Coder",
"provider": "openai",
"model": "qwen2.5-coder:7b",
"apiBase": "http://localhost:11434/v1",
"contextLength": 32768
}
]
}
6. 数学推理
Qwen2.5-Math系列在数学推理方面表现出色。
6.1 数学问题求解
response = client.chat.completions.create(
model="qwen-plus",
messages=[
{
"role": "system",
"content": "你是一个数学教师,请用清晰的步骤解答数学问题"
},
{
"role": "user",
"content": """
解以下微积分问题:
求函数 f(x) = x³ - 3x² + 2 在区间 [-1, 3] 上的最大值和最小值。
要求:
1. 求导并找到所有驻点
2. 计算端点和驻点的函数值
3. 比较得出最值
"""
}
],
temperature=0.1 # 数学任务用低温度
)
print(response.choices[0].message.content)
6.2 数学推理链式提示
math_prompt = """
请用以下结构化方法解决这个数学问题:
问题:{question}
解决步骤:
1. **理解题意**:重新表述问题,明确已知条件和求解目标
2. **建立模型**:用数学语言描述问题
3. **求解过程**:逐步推导,每一步都要说明依据
4. **验证答案**:反向验证结果的正确性
5. **总结**:给出最终答案
请严格按照以上步骤进行。
"""
7. RAG集成
7.1 Qwen + LlamaIndex RAG
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
# 配置Qwen作为LLM
Settings.llm = OpenAI(
model="qwen-plus",
api_key="sk-your-key",
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
temperature=0.1
)
# 使用通义Embedding
Settings.embed_model = OpenAIEmbedding(
model="text-embedding-v3",
api_key="sk-your-key",
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 构建RAG
documents = SimpleDirectoryReader("./knowledge_base").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine(similarity_top_k=5)
response = query_engine.query("公司的核心竞争优势是什么?")
print(response)
7.2 Qwen + LangChain RAG
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 配置Qwen
llm = ChatOpenAI(
model="qwen-plus",
openai_api_key="sk-your-key",
openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
temperature=0.1
)
# Embedding
embeddings = OpenAIEmbeddings(
model="text-embedding-v3",
openai_api_key="sk-your-key",
openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 加载与分块
loader = DirectoryLoader("./docs", glob="**/*.txt")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)
# 向量存储
vectorstore = FAISS.from_documents(chunks, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
# RAG链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=retriever,
return_source_documents=True
)
result = qa_chain.invoke({"query": "产品定价策略是什么?"})
print(result["result"])
print(f"来源: {[doc.metadata['source'] for doc in result['source_documents']]}")
7.3 检索策略优化
# 混合检索:结合语义检索和关键词检索
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
bm25_retriever = BM25Retriever.from_documents(chunks, k=5)
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.3, 0.7] # BM25权重0.3,向量检索权重0.7
)
# 重排序
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
compressor = CohereRerank(top_n=3)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=ensemble_retriever
)
8. Agent应用
8.1 Qwen Function Calling Agent
from openai import OpenAI
import json
client = OpenAI(
api_key="sk-your-key",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 定义工具集
tools = [
{
"type": "function",
"function": {
"name": "query_database",
"description": "查询业务数据库",
"parameters": {
"type": "object",
"properties": {
"sql": {"type": "string", "description": "SQL查询语句"}
},
"required": ["sql"]
}
}
},
{
"type": "function",
"function": {
"name": "send_email",
"description": "发送邮件通知",
"parameters": {
"type": "object",
"properties": {
"to": {"type": "string", "description": "收件人邮箱"},
"subject": {"type": "string", "description": "邮件主题"},
"body": {"type": "string", "description": "邮件内容"}
},
"required": ["to", "subject", "body"]
}
}
},
{
"type": "function",
"function": {
"name": "create_report",
"description": "生成报告文档",
"parameters": {
"type": "object",
"properties": {
"title": {"type": "string", "description": "报告标题"},
"content": {"type": "string", "description": "报告内容"},
"format": {"type": "string", "enum": ["pdf", "markdown", "html"]}
},
"required": ["title", "content"]
}
}
}
]
class QwenAgent:
"""基于Qwen的Agent框架"""
def __init__(self, model="qwen-plus"):
self.client = client
self.model = model
self.messages = []
def register_tool(self, name: str, func):
self.tool_functions[name] = func
def run(self, task: str, max_steps: int = 10):
self.messages = [
{"role": "system", "content": "你是一个智能助手,可以使用工具完成任务。请逐步分析并执行。"},
{"role": "user", "content": task}
]
for step in range(max_steps):
response = self.client.chat.completions.create(
model=self.model,
messages=self.messages,
tools=tools,
tool_choice="auto"
)
msg = response.choices[0].message
self.messages.append(msg)
if not msg.tool_calls:
return msg.content # 最终回答
# 执行工具调用
for tc in msg.tool_calls:
result = self._execute_tool(tc.function.name, json.loads(tc.function.arguments))
self.messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": json.dumps(result, ensure_ascii=False)
})
return "达到最大步骤数限制"
def _execute_tool(self, name: str, args: dict):
# 实际项目中对接真实工具
if name == "query_database":
return {"rows": [{"col1": "value1"}], "count": 1}
elif name == "send_email":
return {"status": "sent", "message_id": "xxx"}
elif name == "create_report":
return {"url": "https://example.com/report.pdf"}
return {"error": f"Unknown tool: {name}"}
# 使用
agent = QwenAgent()
result = agent.run("查询上个月的销售数据,生成报告并发邮件给 manager@company.com")
print(result)
8.2 LangChain + Qwen Agent
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
@tool
def search_web(query: str) -> str:
"""搜索互联网获取最新信息"""
return f"搜索结果: 关于'{query}'的最新信息..."
@tool
def calculate(expression: str) -> str:
"""计算数学表达式"""
try:
return str(eval(expression))
except Exception as e:
return f"计算错误: {e}"
@tool
def get_current_time() -> str:
"""获取当前时间"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
llm = ChatOpenAI(
model="qwen-plus",
openai_api_key="sk-your-key",
openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个有用的AI助手,可以使用工具来帮助用户。"),
MessagesPlaceholder(variable_name="chat_history", optional=True),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
agent = create_tool_calling_agent(llm, [search_web, calculate, get_current_time], prompt)
executor = AgentExecutor(agent=agent, tools=[search_web, calculate, get_current_time], verbose=True)
result = executor.invoke({"input": "现在几点了?另外帮我算一下 15% 的复利年化收益,本金10万,5年后是多少?"})
print(result["output"])
9. 微调实战
9.1 数据准备
微调数据格式(JSON Lines):
{"messages": [{"role": "system", "content": "你是一个法律助手"}, {"role": "user", "content": "什么是合同违约?"}, {"role": "assistant", "content": "合同违约是指合同当事人一方不履行合同义务或履行合同义务不符合约定的行为..."}]}
{"messages": [{"role": "system", "content": "你是一个法律助手"}, {"role": "user", "content": "劳动仲裁的流程是什么?"}, {"role": "assistant", "content": "劳动仲裁流程包括以下步骤:1. 提交申请..."}]}
数据准备脚本:
import json
from datasets import load_dataset
def prepare_finetune_data(raw_data_path: str, output_path: str):
"""将原始数据转为Qwen微调格式"""
dataset = load_dataset("json", data_files=raw_data_path)
formatted = []
for item in dataset["train"]:
formatted.append({
"messages": [
{"role": "system", "content": "你是一个专业的领域专家"},
{"role": "user", "content": item["question"]},
{"role": "assistant", "content": item["answer"]}
]
})
with open(output_path, "w", encoding="utf-8") as f:
for item in formatted:
f.write(json.dumps(item, ensure_ascii=False) + "\n")
print(f"已生成 {len(formatted)} 条训练数据")
prepare_finetune_data("raw_qa.json", "train.jsonl")
9.2 使用LLaMA-Factory微调
# 安装LLaMA-Factory
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e .
# 使用Web UI微调
llamafactory-cli webui
命令行微调:
# qwen_sft.yaml
model_name_or_path: Qwen/Qwen2.5-7B-Instruct
stage: sft
do_train: true
finetuning_type: lora
lora_target: all
lora_rank: 16
lora_alpha: 32
dataset: my_custom_data
template: qwen
cutoff_len: 2048
max_samples: 10000
per_device_train_batch_size: 4
gradient_accumulation_steps: 4
learning_rate: 1e-4
num_train_epochs: 3
output_dir: ./output/qwen2.5-7b-sft
logging_steps: 10
save_steps: 500
warmup_ratio: 0.1
bf16: true
# 启动微调
llamafactory-cli train qwen_sft.yaml
9.3 使用transformers原生微调
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType
from trl import SFTTrainer
from datasets import load_dataset
# 加载模型
model_name = "Qwen/Qwen2.5-7B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype="bfloat16",
device_map="auto",
trust_remote_code=True
)
# LoRA配置
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# 输出: trainable params: 13,631,488 || all params: 7,628,000,000 || trainable%: 0.1787
# 加载数据
dataset = load_dataset("json", data_files="train.jsonl")
# 训练参数
training_args = TrainingArguments(
output_dir="./output",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4,
warmup_ratio=0.1,
bf16=True,
logging_steps=10,
save_strategy="epoch",
report_to="tensorboard",
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
tokenizer=tokenizer,
max_seq_length=2048,
)
trainer.train()
# 保存LoRA权重
model.save_pretrained("./output/lora_weights")
tokenizer.save_pretrained("./output/lora_weights")
9.4 合并与推理
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
# 加载基座模型和LoRA权重
base_model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen2.5-7B-Instruct",
torch_dtype="bfloat16",
device_map="auto"
)
model = PeftModel.from_pretrained(base_model, "./output/lora_weights")
# 合并LoRA到基座(可选,推理更快)
model = model.merge_and_unload()
model.save_pretrained("./merged_model")
# 推理
tokenizer = AutoTokenizer.from_pretrained("./output/lora_weights")
messages = [
{"role": "system", "content": "你是一个法律助手"},
{"role": "user", "content": "什么是合同违约?"}
]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tokenizer([text], return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=512)
print(tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True))
9.5 微调最佳实践
| 实践 | 建议 |
|---|---|
| 数据质量 | 高质量小数据集 > 低质量大数据集 |
| 数据量 | LoRA: 1000-10000条; 全量: 10000+ |
| 学习率 | LoRA: 1e-4 ~ 3e-4; 全量: 1e-5 ~ 5e-5 |
| LoRA rank | 一般任务r=8-16; 复杂任务r=32-64 |
| 训练轮数 | 1-3轮,过多容易过拟合 |
| 评估 | 保留10%数据做验证集 |
10. 与其他模型对比
10.1 主流模型横向对比
| 维度 | Qwen2.5-72B | GPT-4o | Claude 3.5 Sonnet | Llama 3.1 70B | DeepSeek-V2 |
|---|---|---|---|---|---|
| 中文能力 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐☆ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 英文能力 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 代码能力 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 数学推理 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 长文本 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 工具调用 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 开源 | ✅ | ❌ | ❌ | ✅ | ✅ |
| API价格(输入/百万token) | ¥2 | $2.5 | $3 | N/A | ¥1 |
10.2 不同场景模型选择建议
| 应用场景 | 推荐模型 | 理由 |
|---|---|---|
| 中文客服系统 | Qwen2.5-Plus/72B | 中文能力最强,成本可控 |
| 代码辅助 | Qwen2.5-Coder-32B | 代码专用,性价比高 |
| 数学教育 | Qwen2.5-Math-72B | 数学推理领先 |
| 超长文档分析 | Qwen2.5-Turbo | 1M上下文窗口 |
| 边缘设备部署 | Qwen2.5-3B/7B | 多种规格可选 |
| 英文创意写作 | Claude 3.5 Sonnet | 英文表达更自然 |
| 多语言翻译 | GPT-4o | 多语言覆盖面广 |
| 企业RAG系统 | Qwen2.5-Plus | 中文+长文本+性价比 |
10.3 成本效益分析
# 成本对比示例:处理100万次中文问答
# 假设每次问答:输入1000 tokens + 输出500 tokens
scenarios = {
"Qwen2.5-Plus": {
"input_price": 2.0, # 元/百万token
"output_price": 6.0,
"input_tokens": 1000,
"output_tokens": 500,
"calls": 1_000_000
},
"GPT-4o": {
"input_price": 18.0, # $2.5 ≈ ¥18
"output_price": 54.0,
"input_tokens": 1000,
"output_tokens": 500,
"calls": 1_000_000
},
"Claude-3.5-Sonnet": {
"input_price": 21.0,
"output_price": 105.0,
"input_tokens": 1000,
"output_tokens": 500,
"calls": 1_000_000
}
}
for model, params in scenarios.items():
cost = (
params["input_price"] * params["input_tokens"] * params["calls"] / 1_000_000 +
params["output_price"] * params["output_tokens"] * params["calls"] / 1_000_000
)
print(f"{model}: ¥{cost:,.0f}")
# 输出:
# Qwen2.5-Plus: ¥5,000,000
# GPT-4o: ¥45,000,000
# Claude-3.5-Sonnet: ¥73,500,000
10.4 本地部署vs API调用决策
| 考量因素 | 本地部署 | API调用 |
|---|---|---|
| 数据隐私 | ✅ 数据不出境 | ❌ 需信任第三方 |
| 初始成本 | ❌ 需GPU硬件投入 | ✅ 按量付费 |
| 运维成本 | ❌ 需专业团队 | ✅ 零运维 |
| 定制能力 | ✅ 可微调 | ⚠️ 部分支持微调API |
| 延迟 | ✅ 内网低延迟 | ❌ 受网络影响 |
| 扩展性 | ⚠️ 受硬件限制 | ✅ 弹性扩展 |
| 模型更新 | ❌ 需手动更新 | ✅ 自动更新 |
建议决策路径:
- 数据敏感 → 本地部署
- 快速验证 → API调用
- 大规模生产 → 混合方案(核心业务本地,边缘业务API)
- 预算有限 → Qwen2.5开源模型 + 自有GPU
总结
Qwen2.5系列已成为国内大模型应用开发的首选之一。核心建议:
- 从API开始——使用DashScope API快速验证想法,再决定是否本地部署
- 选对模型规格——不要盲目追求大模型,7B模型在很多场景下已经够用
- 善用专业模型——代码任务用Qwen-Coder,数学用Qwen-Math,多模态用Qwen-VL
- 微调提升效果——对垂直领域,LoRA微调几百条高质量数据就能显著提升
- 关注成本——Qwen API性价比极高,适合大规模生产应用
Qwen系列仍在快速迭代,建议关注通义实验室官方发布获取最新模型和特性。