自动驾驶-第四阶段-VLA—当前最前沿方向

第四阶段:VLA——当前最前沿方向

用视觉语言大模型的"思考能力"让车学会像人一样开车

前置要求: 完成第三阶段(一段式端到端 + 扩散模型)
时间规划: 3周(每天3-4小时)
硬件要求: RTX 3090 24GB(VLA推理需要16-20GB显存)


先搞清楚:VLA到底是什么?

从V到VL到VLA——三代技术的演进

V(Vision)模型——第1-3阶段你学的:
  摄像头图像 → 神经网络 → 轨迹/控制
  特点:能看,但不会"想"。遇到没见过的场景就懵了。

VL(Vision-Language)模型——ChatGPT看图时代:
  图像 + 文字提问 → 大模型 → 文字回答
  特点:能看也能说,但只能动嘴不能动手。

VLA(Vision-Language-Action)模型——本阶段要学的:
  图像 + 语言指令 → 大模型 → 轨迹/控制动作
  特点:能看、能想、还能动手!是自动驾驶的"终极形态"。

类比理解:

V模型 = 一个只会条件反射的司机(看到红灯就停,但不知道为什么停)
VL模型 = 一个坐在副驾给你讲解的教练(能分析路况但自己不开车)
VLA模型 = 一个既能讲解又能亲自开车的老司机(知道为什么要这样开,并且真的去开)

为什么VLA这么热门?

VLA解决的核心问题:

1. 长尾场景泛化
   传统模型:训练数据里没见过施工路段+逆行电动车的组合 → 不知道怎么办
   VLA模型:从互联网文本学到了"施工要绕行""逆行车要让" → 能推理出应对策略

2. 可解释性
   传统模型:输出轨迹,但不知道为什么这么开
   VLA模型:先用文字说"前方有行人横穿,应减速让行",再输出减速轨迹

3. 指令跟随
   传统模型:只能按导航开,不理解"在前面那家星巴克停一下"
   VLA模型:理解自然语言指令,并转化为驾驶动作

当前行业格局:谁在用VLA?

小鹏 VLA 2.0:去掉Language中间层,Vision直接到Action
             720亿参数基座模型,阿里云3万卡训练

理想 MindVLA:快慢双系统,VLM辅助端到端决策
              用视觉语言模型做"慢思考"增强安全性

华为 ADS4.0:不叫VLA,叫WA(World Action)
             去掉Language,用世界模型直接控车

特斯拉 FSD:不公开叫VLA,但核心也是
            百亿参数端到端网络 + 数据闭环

Week 1:VLA基础——从Qwen2.5-VL到驾驶场景理解

Day 1-2:用Qwen2.5-VL理解驾驶场景

什么是VLM(Vision-Language Model)?

VLM是VLA的基础——先学会"看图说话",再学会"看图开车"。Qwen2.5-VL是目前最好的开源VLM之一,支持图像理解、视频理解和多语言。

VLM的工作原理:

                ┌──────────────┐
  图像 ─────→   │  视觉编码器   │──→ 图像Token
                │  (ViT)       │        ↓
                └──────────────┘   ┌──────────┐
                                   │  大语言   │──→ 文字回答
  文字提问 ──→  文字Token ────→    │  模型     │
                                   │  (LLM)   │
                                   └──────────┘

概念解释:Token(令牌)

Token是大模型处理信息的最小单位。对于文字,一个Token大约是一个汉字或半个英文单词。对于图像,视觉编码器会把图片切成小块(patch),每个patch变成一个Token。大语言模型把文字Token和图像Token放在一起处理,就能"看图说话"了。

实操:安装Qwen2.5-VL并分析驾驶场景

# 安装依赖
pip install transformers accelerate torch torchvision
pip install qwen-vl-utils

# 注意:Qwen2.5-VL-3B需要约8GB显存,7B需要约16GB
"""
driving_scene_understanding.py
用Qwen2.5-VL分析驾驶场景图片
"""
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info
import torch

# 加载模型(3B版本,适合RTX 3090)
model_name = "Qwen/Qwen2.5-VL-3B-Instruct"
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
    model_name,
    torch_dtype=torch.float16,  # 半精度节省显存
    device_map="auto"
)
processor = AutoProcessor.from_pretrained(model_name)

# ===== 场景1:基础场景描述 =====
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": "path/to/driving_scene.jpg"},
            {"type": "text", "text": 
             "You are an autonomous driving AI. "
             "Describe this driving scene in detail: "
             "1. What objects are visible? "
             "2. What is the road condition? "
             "3. What should the ego vehicle do next?"}
        ]
    }
]

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)

output_ids = model.generate(**inputs, max_new_tokens=256)
response = processor.batch_decode(output_ids, skip_special_tokens=True)[0]
print(f"场景分析:\n{response}")
# ===== 场景2:多层次CoT驾驶推理 =====
# 这就是VLA中最关键的"链式思维"(Chain-of-Thought)
cot_prompt = """You are an expert autonomous driving system.
Analyze this driving scene step by step:

Step 1 - PERCEPTION: List all important objects and their positions
(e.g., "car ahead at 20m", "pedestrian on right sidewalk")

Step 2 - PREDICTION: Predict what each object will do in the next 3 seconds
(e.g., "the car ahead is slowing down", "pedestrian may cross")

Step 3 - DECISION: Based on steps 1 and 2, what should the ego vehicle do?
(e.g., "slow down and prepare to stop")

Step 4 - TRAJECTORY: Output 6 waypoints for the next 3 seconds as coordinates
Format: [(x1,y1), (x2,y2), ..., (x6,y6)]
where x is forward distance (meters), y is lateral offset (positive=left)
"""

messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": "path/to/driving_scene.jpg"},
            {"type": "text", "text": cot_prompt}
        ]
    }
]
# ... (同样的推理代码)

概念解释:CoT(Chain-of-Thought,链式思维)

CoT是让大模型"一步步思考"而不是直接给答案。就像你考数学题时,老师要求写出解题过程——这不仅让答案更准确,还让你的思路可以被检查。

在VLA中,CoT的典型流程是:
感知(看到了什么)→ 预测(它们会怎么动)→ 决策(我应该怎么做)→ 动作(输出轨迹)

这个流程和人类开车时的思考过程完全一致。

Day 3-4:用nuScenes图片做批量驾驶场景分析

"""
batch_scene_analysis.py
批量分析nuScenes中的驾驶场景,生成训练VLA的CoT标注数据
"""
from nuscenes.nuscenes import NuScenes
import json
from pathlib import Path

nusc = NuScenes(version='v1.0-mini', dataroot='./data/nuscenes')

# 为每个关键帧生成多层次CoT标注
cot_annotations = []

for sample in nusc.sample[:50]:  # 先处理50帧
    # 获取前视摄像头图像
    cam_token = sample['data']['CAM_FRONT']
    cam_data = nusc.get('sample_data', cam_token)
    img_path = f"./data/nuscenes/{cam_data['filename']}"

    # 获取真实标注信息
    anns = []
    for ann_token in sample['anns']:
        ann = nusc.get('sample_annotation', ann_token)
        anns.append({
            'category': ann['category_name'],
            'distance': round(ann['translation'][0], 1),  # 前方距离
            'lateral': round(ann['translation'][1], 1),    # 横向偏移
        })

    # 获取自车未来轨迹(作为GT)
    ego_pose = nusc.get('ego_pose', cam_data['ego_pose_token'])

    # 构造CoT标注
    cot_annotations.append({
        'image_path': img_path,
        'perception': anns,  # 感知结果
        'prediction': 'auto_generated',  # 后续用VLM生成
        'decision': 'auto_generated',
        'trajectory': ego_pose['translation']  # 真实轨迹
    })

# 保存标注
with open('cot_annotations.json', 'w') as f:
    json.dump(cot_annotations, f, indent=2)

print(f"生成了 {len(cot_annotations)} 条CoT标注")

Week 2:ORION——小米的开源VLA方案

Day 5-6:理解ORION架构

ORION是什么?

ORION是小米汽车和华中科技大学联合发表的VLA框架(ICCV 2025),它的核心创新是用生成式规划器打通VLM的"推理空间"和轨迹的"动作空间"。

ORION的整体架构:

┌─────────────────────────────────────────────────────────┐
│                     ORION Framework                      │
│                                                          │
│  ┌──────────┐                                            │
│  │ 多视角    │──→ 视觉编码器 ──→ 视觉Token               │
│  │ 摄像头图像 │                      ↓                    │
│  └──────────┘     ┌───────────────────────┐              │
│                   │     QT-Former          │              │
│  ┌──────────┐     │  (时序Query聚合器)      │              │
│  │ 历史帧    │──→  │  压缩多帧视觉信息      │──→ 历史Token  │
│  │ 记忆库    │     │  解决VLM输入长度限制    │              │
│  └──────────┘     └───────────────────────┘              │
│                              ↓                           │
│                   ┌───────────────────────┐              │
│  ┌──────────┐     │     VLM (大语言模型)    │              │
│  │ 文字指令  │──→  │  推理空间:场景描述     │              │
│  │"直行到路口"│     │  + 行为分析 + 决策     │              │
│  └──────────┘     │  输出:规划Token         │              │
│                   └──────────┬────────────┘              │
│                              ↓                           │
│                   ┌───────────────────────┐              │
│                   │   生成式规划器          │              │
│                   │  (VAE / 扩散模型)       │              │
│                   │  规划Token → 多条轨迹   │              │
│                   │  对齐推理空间和动作空间  │              │
│                   └──────────┬────────────┘              │
│                              ↓                           │
│                     最优驾驶轨迹 (waypoints)              │
└─────────────────────────────────────────────────────────┘

ORION的三大核心创新

创新1:QT-Former——解决VLM的"短期记忆"问题

VLM一次只能处理有限长度的Token。如果把过去10帧的6个摄像头图像都塞进去,Token数量会爆炸。QT-Former用类似Q-Former的方法,把多帧视觉信息"压缩"成少量Token。

没有QT-Former:
  第1帧6张图(500token) + 第2帧6张图(500token) + ... + 第10帧(500token)
  = 5000 token → 超过VLM的输入限制!

有QT-Former:
  10帧历史信息 → QT-Former压缩 → 64个Token
  = 大幅降低计算量,同时保留关键时序信息

概念解释:Q-Former

Q-Former来自BLIP-2论文,它的核心思想是:用一组可学习的"查询向量"(Query)去"询问"图像特征,只提取最重要的信息。就像你让实习生看一段很长的视频,然后只用3句话总结要点。QT-Former在此基础上加入了时序(Temporal)维度,能跨越多帧总结历史信息。

创新2:VLM推理→规划Token

ORION让VLM做完场景分析后,除了输出文字,还额外输出一组"规划Token"。这些Token不是人类可读的文字,而是一种隐含的"驾驶意图表示"——类似于一种"驾驶密码"。

# VLM的输出(伪代码)
vlm_output = {
    # 人类可读的文字输出
    'text': "前方20米有行人正在横穿马路,应减速让行",

    # 机器可用的规划Token(不是文字,是向量)
    'planning_tokens': tensor(shape=[1, 8, 256])  # 8个256维的Token
}

创新3:生成式规划器——打通推理和动作

规划Token通过一个VAE(变分自编码器)或扩散模型,被转化为具体的驾驶轨迹。关键在于:这个转化过程是可微分的——意味着轨迹的误差可以反向传播到VLM,让VLM学会输出更好的规划Token。

概念解释:VAE(变分自编码器)

VAE是一种生成模型。它做两件事:

  • 编码器:把复杂数据(轨迹)压缩成一个简短的"编码"(潜在向量)
  • 解码器:从"编码"恢复出原始数据(轨迹)

在ORION中,VAE把VLM输出的规划Token当作"条件",控制轨迹的生成方向。

Day 7-8:跑通ORION推理

# 克隆ORION
git clone https://github.com/xiaomi-mlab/Orion.git
cd Orion

# 安装依赖(参考README.md)
pip install -r requirements.txt

# 下载预训练权重(从GitHub Releases或HuggingFace)
# ORION使用Vicuna 1.5作为LLM backbone

# 在Bench2Drive数据上运行推理
python inference.py \
    --config configs/orion_base.py \
    --checkpoint ckpts/orion_base.pth \
    --visualize

阅读ORION代码的重点

Orion/
├── configs/
│   └── orion_base.py           # ← 第1个读:模型配置
├── models/
│   ├── orion.py                # ← 第2个读:主模型forward
│   ├── qt_former.py            # ← 第3个读:QT-Former实现
│   ├── vlm_wrapper.py          # ← 第4个读:VLM封装
│   └── generative_planner.py   # ← 第5个读:生成式规划器
├── datasets/
│   └── bench2drive_dataset.py  # 数据加载
└── inference.py                # 推理脚本

Week 3:构建你自己的轻量VLA + 模型部署

Day 9-11:构建简化版VLA

设计思路

我们要在NAVSIM上构建一个轻量VLA。核心思想:用Qwen2.5-VL-3B做场景理解,输出CoT文字描述,然后用一个MLP把VLM的隐藏层特征映射为轨迹。

"""
mini_vla.py
简化版VLA:Qwen2.5-VL + MLP轨迹预测头
"""
import torch
import torch.nn as nn
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor

class MiniVLA(nn.Module):
    """
    最简化的VLA架构:
    1. 用Qwen2.5-VL编码图像+指令
    2. 取VLM最后一层隐藏状态
    3. 用MLP映射到轨迹
    """
    def __init__(self, vlm_name="Qwen/Qwen2.5-VL-3B-Instruct", 
                 num_waypoints=6, freeze_vlm=True):
        super().__init__()

        # 加载预训练VLM
        self.vlm = Qwen2_5_VLForConditionalGeneration.from_pretrained(
            vlm_name, torch_dtype=torch.float16
        )
        self.processor = AutoProcessor.from_pretrained(vlm_name)

        # 冻结VLM参数(先不微调,只训练轨迹头)
        if freeze_vlm:
            for param in self.vlm.parameters():
                param.requires_grad = False

        # 轨迹预测头:VLM隐藏维度 → waypoints
        hidden_dim = self.vlm.config.hidden_size  # 通常是2048或3584
        self.trajectory_head = nn.Sequential(
            nn.Linear(hidden_dim, 512),
            nn.ReLU(),
            nn.Dropout(0.1),
            nn.Linear(512, 256),
            nn.ReLU(),
            nn.Linear(256, num_waypoints * 2)  # 6个点 × (x, y)
        )
        self.num_waypoints = num_waypoints

    def forward(self, images, driving_command, ego_status):
        """
        images: 前视摄像头图像
        driving_command: "go straight" / "turn left" / "turn right"
        ego_status: 自车速度等
        """
        # 构造VLM输入
        prompt = f"Driving command: {driving_command}. " \
                 f"Current speed: {ego_status['speed']:.1f} m/s. " \
                 f"Analyze the scene and plan the trajectory."

        # VLM前向传播(只取隐藏状态,不生成文字)
        inputs = self.processor(
            text=prompt,
            images=images,
            return_tensors="pt"
        ).to(self.vlm.device)

        with torch.no_grad():
            vlm_output = self.vlm(**inputs, output_hidden_states=True)

        # 取最后一层隐藏状态的最后一个Token
        # 这个Token聚合了图像+文字的全部信息
        hidden = vlm_output.hidden_states[-1][:, -1, :]  # (B, hidden_dim)
        hidden = hidden.float()  # 转回FP32做MLP

        # 通过轨迹预测头输出waypoints
        traj = self.trajectory_head(hidden)  # (B, 12)
        traj = traj.view(-1, self.num_waypoints, 2)  # (B, 6, 2)

        return traj

训练这个MiniVLA

"""
train_mini_vla.py
训练简化版VLA的轨迹预测头
"""
import torch
from torch.utils.data import DataLoader
from mini_vla import MiniVLA

# 配置
EPOCHS = 20
LR = 1e-3  # 只训练MLP头,可以用较大学习率
DEVICE = 'cuda'

# 加载模型(VLM冻结,只训练trajectory_head)
model = MiniVLA(freeze_vlm=True).to(DEVICE)

# 只优化轨迹预测头的参数
optimizer = torch.optim.Adam(
    model.trajectory_head.parameters(), lr=LR
)
loss_fn = torch.nn.SmoothL1Loss()  # 比MSE更鲁棒

# 训练循环
for epoch in range(EPOCHS):
    model.train()
    for batch in dataloader:
        images = batch['image'].to(DEVICE)
        commands = batch['driving_command']
        ego_status = batch['ego_status']
        gt_traj = batch['trajectory'].to(DEVICE)  # (B, 6, 2)

        # 前向传播
        pred_traj = model(images, commands, ego_status)

        # 计算损失
        loss = loss_fn(pred_traj, gt_traj)

        # 反向传播(只更新trajectory_head)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")

torch.save(model.trajectory_head.state_dict(), 'vla_traj_head.pth')

Day 12-13:GRPO强化学习微调

什么是GRPO?为什么需要它?

SFT(监督微调)让模型学会了"模仿人类开车",但模仿有一个致命问题:人类的开车数据本身就包含不好的习惯(急刹车、犹豫不决等)。强化学习(RL)可以让模型学到比人类数据更好的策略。

SFT的问题:
  人类数据中:70%正常驾驶 + 20%犹豫不决 + 10%危险操作
  SFT学到的:一个"平均"策略,包含犹豫和危险的成分

GRPO的解决:
  让模型自己生成多条轨迹 → 用奖励函数评分 → 强化好的、抑制差的

概念解释:GRPO(Group Relative Policy Optimization)

GRPO是DeepSeek提出的强化学习方法,比PPO(OpenAI用的)更简单高效。核心思想:

  1. 对同一个场景,让模型生成K条候选轨迹
  2. 用奖励函数给每条轨迹打分(有没有碰撞?偏离车道多少?)
  3. 好的轨迹 → 增加概率;差的轨迹 → 降低概率
  4. 不需要单独训练Critic网络(PPO需要),直接用组内相对排名

为什么叫"Group Relative"? 因为它不看绝对分数,只看"这条轨迹在这一组里排第几"。第一名奖励最大,最后一名惩罚最大。

"""
grpo_driving.py
简化版GRPO驾驶策略优化

注意:这是概念性代码,帮助你理解GRPO的核心流程
实际应用中需要配合完整的VLA模型和数据pipeline
"""
import torch
import torch.nn.functional as F

def compute_driving_reward(trajectory, gt_trajectory, obstacles):
    """
    驾驶奖励函数:评估一条轨迹的质量

    奖励 = 进度奖励 - 碰撞惩罚 - 偏离惩罚 - 不舒适惩罚
    """
    reward = 0.0

    # 1. 进度奖励:你到底往前开了多少?
    forward_progress = trajectory[-1, 0]  # 最后一个waypoint的x坐标
    reward += forward_progress * 0.5

    # 2. 碰撞惩罚
    for obs in obstacles:
        min_dist = torch.min(torch.norm(trajectory - obs['position'], dim=1))
        if min_dist < obs['radius']:
            reward -= 10.0  # 碰撞了,严重惩罚

    # 3. 偏离车道中心的惩罚
    lateral_deviation = torch.mean(torch.abs(trajectory[:, 1]))  # y方向偏差
    reward -= lateral_deviation * 2.0

    # 4. 不舒适惩罚(急转弯、急加速)
    acceleration = torch.diff(trajectory, dim=0)
    jerk = torch.diff(acceleration, dim=0)
    comfort_penalty = torch.mean(torch.norm(jerk, dim=1))
    reward -= comfort_penalty * 0.5

    return reward

def grpo_step(model, scene_input, gt_trajectory, obstacles,
              num_samples=8, temperature=1.0):
    """
    GRPO的一个训练步骤

    1. 生成K条候选轨迹
    2. 用奖励函数打分
    3. 计算GRPO loss
    """
    # Step 1: 生成K条候选轨迹
    trajectories = []
    log_probs = []

    for _ in range(num_samples):
        with torch.no_grad():
            traj = model.sample_trajectory(scene_input, temperature=temperature)
        trajectories.append(traj)

        # 计算每条轨迹的对数概率
        log_prob = model.log_probability(scene_input, traj)
        log_probs.append(log_prob)

    trajectories = torch.stack(trajectories)  # (K, 6, 2)
    log_probs = torch.stack(log_probs)        # (K,)

    # Step 2: 计算每条轨迹的奖励
    rewards = torch.tensor([
        compute_driving_reward(traj, gt_trajectory, obstacles)
        for traj in trajectories
    ])

    # Step 3: 组内标准化(Group Relative的关键)
    # 不看绝对分数,只看相对排名
    rewards_normalized = (rewards - rewards.mean()) / (rewards.std() + 1e-8)

    # Step 4: 计算GRPO loss
    # 好的轨迹(正奖励)→ 增加概率;差的轨迹(负奖励)→ 降低概率
    loss = -(log_probs * rewards_normalized).mean()

    return loss

Day 14:模型部署基础——TensorRT加速

为什么需要TensorRT?

VLA模型很大(3-7B参数),推理慢。车端部署需要实时性(至少10Hz)。TensorRT是NVIDIA的推理加速工具,能把PyTorch模型转换为高度优化的推理引擎。

"""
model_export.py
将训练好的轨迹预测头导出为ONNX → TensorRT
"""
import torch
import onnx

# 1. 导出ONNX
model = MiniVLA(freeze_vlm=True)
model.trajectory_head.load_state_dict(torch.load('vla_traj_head.pth'))
model.eval()

# 只导出轨迹预测头(VLM部分用其他方式优化)
dummy_input = torch.randn(1, 2048)  # 模拟VLM的隐藏层输出
torch.onnx.export(
    model.trajectory_head,
    dummy_input,
    "trajectory_head.onnx",
    input_names=['vlm_features'],
    output_names=['trajectory'],
    dynamic_axes={'vlm_features': {0: 'batch'}, 'trajectory': {0: 'batch'}}
)
print("ONNX模型已导出!")

# 2. 用TensorRT优化
# trtexec --onnx=trajectory_head.onnx \
#          --saveEngine=trajectory_head.trt \
#          --fp16  # 使用半精度加速

# 3. TensorRT推理
import tensorrt as trt
import numpy as np

# 加载TensorRT引擎
with open('trajectory_head.trt', 'rb') as f:
    engine = trt.Runtime(trt.Logger()).deserialize_cuda_engine(f.read())

# 推理速度对比
# PyTorch FP32: ~5ms
# PyTorch FP16: ~3ms  
# TensorRT FP16: ~0.5ms  ← 10倍加速!

总结:你的完整技术能力树

第一阶段 ✅  CARLA仿真 + 简单模仿学习 + 闭环测试
第二阶段 ✅  BEV感知(BEVFormer) + 端到端(VAD) + nuScenes评测
第三阶段 ✅  一段式端到端(SparseDrive) + 扩散模型(DiffusionDrive) + NAVSIM
第四阶段 ✅  VLA(ORION) + 强化学习(GRPO) + 模型部署(TensorRT)

面试时你的"故事线"

"我从CARLA仿真入手建立了端到端自动驾驶的闭环实验能力,然后在nuScenes上复现了BEVFormer和VAD。接着研究了一段式端到端方案SparseDrive和基于扩散模型的DiffusionDrive,在NAVSIM上做了标准化评测。最后进入VLA方向,跑通了小米的ORION框架,自己实现了一个基于Qwen2.5-VL的轻量VLA,并用GRPO做了强化学习微调。整个过程覆盖了从感知到规划的完整技术栈,也掌握了TensorRT模型部署的基础。"

求职目标岗位

岗位 匹配的技术栈 你的竞争力
端到端算法工程师 BEV + VAD + SparseDrive 有完整的开环+闭环复现经验
规划算法工程师 DiffusionDrive + NAVSIM 理解扩散模型和多模态规划
VLA/大模型算法工程师 ORION + Qwen2.5-VL + GRPO 掌握最前沿的VLA技术栈
数据闭环工程师 CARLA + nuScenes + 工程化 10年工程经验 + 算法理解
模型部署工程师 TensorRT + ONNX + 量化 工程化背景 + 算法知识

你的差异化优势: 有10年Java/Python工程经验的候选人学VLA算法,比纯学术背景的候选人更懂工程化落地,在车企非常稀缺。

为者常成,行者常至