
1. 這篇文章真正要解決的問題如果你正在開發一個需要復雜物理模擬或機器人控制的游戲或仿真項目那么“如何讓一個虛擬的機器人在崎嶇地形上穩定行走”這個問題很可能讓你頭疼不已。傳統的解決方案無論是手寫狀態機、基于規則的控制器還是簡單的PID調節在面對復雜、動態的環境時往往顯得笨拙且脆弱。代碼越寫越復雜調試成本呈指數級上升最終項目可能陷入“調參地獄”。這正是《齒輪盛宴》系列特別是其第四集“重新開始再下地獄進化吧我的機器”所聚焦的核心挑戰。它不是一個簡單的游戲實況而是一個深度技術實踐項目其本質是探索并實戰如何利用現代機器學習方法特別是強化學習來自動化地解決復雜的運動控制問題。本文要解決的就是為你拆解這個項目背后的技術棧、實現思路以及其中蘊含的工程哲學讓你不僅能看懂這個“機器進化”的過程更能將類似的方法論應用到自己的項目中。很多人可能會誤以為這只是個“用AI玩游戲的視頻”。但真正的價值在于它演示了一條從零構建、不斷試錯、最終讓智能體Agent在仿真環境中“學會”行走的完整路徑。這背后涉及的關鍵問題包括仿真環境如何搭建狀態和動作空間如何設計獎勵函數Reward Function——這個強化學習的“指揮棒”——如何制定才能引導智能體做出我們期望的行為以及當智能體表現不佳時我們是應該“重新開始”優化算法還是深入“地獄”般的調試過程去改進環境本文將帶你深入這個“齒輪盛宴”不僅解釋概念更會提供可復現的實踐框架、代碼示例和避坑指南。無論你是對強化學習感興趣但不知如何入手的新手還是正在尋找更優雅方案來解決運動控制問題的資深開發者都能從中獲得直接的啟發和可操作的方案。2. 基礎概念與核心原理在深入項目細節前我們需要統一幾個核心概念。理解這些是看懂后續所有操作的基礎。1. 強化學習 (Reinforcement Learning, RL)你可以把它想象成訓練一只小狗。小狗智能體在一個環境比如客廳里它會嘗試各種動作坐下、趴下、叫。每當它做出一個動作你會根據這個動作的好壞給予獎勵或懲罰給零食或輕聲呵斥。小狗的目標是學會一套行為策略使得長期獲得的零食累計獎勵最多。在《齒輪盛宴》中“機器”就是這只小狗虛擬的物理世界就是客廳而開發者的任務就是設計一套合理的“零食發放規則”獎勵函數。2. 智能體 (Agent)、環境 (Environment) 與交互循環這是強化學習的三個核心要素智能體 (Agent)做出決策的實體。在本項目中就是那個需要學會走路的機器模型。它接收環境的狀態 (State)輸出一個動作 (Action)。環境 (Environment)智能體所處的外部世界。它接收智能體的動作更新內部狀態并反饋給智能體一個新的狀態和一個獎勵 (Reward)。交互循環智能體觀察狀態 → 智能體執行動作 → 環境反饋獎勵和新狀態 → 循環繼續。項目視頻中機器一次次嘗試、跌倒、再嘗試的過程就是這個循環的直觀體現。3. 獎勵函數 (Reward Function)RL項目的靈魂這是整個項目成功與否最關鍵的設計。獎勵函數定義了“什么是好什么是壞”。一個糟糕的獎勵函數會讓智能體學會“作弊”或陷入局部最優。例如目標導向獎勵機器向前移動了1米10分。生存懲罰機器跌倒軀干觸地-50分并結束本次嘗試Episode。能耗懲罰關節電機用力過大每一步-0.1分鼓勵高效行走。姿態獎勵軀干保持直立0.1分/步。《齒輪盛宴》EP.4 中提到的“再下地獄”很大程度上就是在反復調整和優化這個獎勵函數因為初期設計的獎勵函數很可能導致機器學會一些詭異但能“刷分”的步態比如瘋狂抽搐前進。4. 仿真環境 (Simulation Environment)在真實機器人上訓練既危險又昂貴。因此我們首先在物理仿真引擎中構建一個虛擬環境。常用的引擎有PyBullet: 輕量級易于集成Python接口友好非常適合RL研究和快速原型開發。《齒輪盛宴》項目極有可能基于此。MuJoCo: 精度高在機器人領域被廣泛認可但新版需要許可證。Isaac Gym: NVIDIA出品支持大規模并行仿真速度極快但對硬件要求高。仿真環境負責計算物理碰撞、關節力矩、傳感器數據等為智能體提供一個安全、可重復、可加速的訓練場。3. 環境準備與前置條件要復現或借鑒《齒輪盛宴》項目的思路你需要搭建以下開發環境。以下配置以最通用的 PyBullet 為例。操作系統: Ubuntu 20.04/22.04 LTS 或 Windows 10/11 (WSL2 推薦)。macOS 也可行但可能在某些依賴上需要額外處理。編程語言: Python 3.8 或 3.9 (與主要機器學習庫兼容性最好)。核心依賴庫:pybullet: 物理仿真引擎。gym或gymnasium: OpenAI 的強化學習環境標準接口。numpy: 數值計算。torch或tensorflow: 深度學習框架用于構建神經網絡策略。本文示例將使用 PyTorch。stable-baselines3或ray[rllib]: 高級強化學習算法庫讓我們不必從零實現PPO、SAC等復雜算法。環境搭建步驟:創建并激活虛擬環境(強烈推薦避免包沖突):# 使用 conda conda create -n gear_feast python3.9 conda activate gear_feast # 或使用 venv python -m venv gear_feast_env # Linux/macOS source gear_feast_env/bin/activate # Windows .\gear_feast_env\Scripts\activate安裝核心依賴:pip install pybullet gymnasium numpy torch stable-baselines3 # 如果需要可視化訓練過程可以安裝 tensorboard pip install tensorboard驗證安裝: 創建一個簡單的Python腳本test_env.py:import pybullet as p import pybullet_data import time # 連接物理服務器直接GUI模式 physicsClient p.connect(p.GUI) # 使用 p.DIRECT 則不顯示圖形界面 p.setAdditionalSearchPath(pybullet_data.getDataPath()) p.setGravity(0, 0, -9.8) # 加載地面 planeId p.loadURDF(plane.urdf) # 加載一個簡單物體例如立方體 cubeStartPos [0, 0, 1] cubeStartOrientation p.getQuaternionFromEuler([0, 0, 0]) boxId p.loadURDF(r2d2.urdf, cubeStartPos, cubeStartOrientation) # 模擬幾步 for i in range(1000): p.stepSimulation() time.sleep(1./240.) # 模擬實時 p.disconnect()運行python test_env.py如果彈出一個窗口并看到R2D2機器人站在地面上說明PyBullet環境配置成功。4. 核心流程拆解從零構建一個“學走路”的智能體整個項目的開發流程可以拆解為以下六個關鍵步驟這構成了強化學習應用的標準范式。步驟一定義仿真環境 (Environment)這是我們的“訓練場”。我們需要創建一個繼承自gym.Env的類。這個類需要實現幾個核心方法__init__: 初始化物理引擎、機器人模型、狀態和動作空間的維度。reset: 將環境重置到初始狀態例如讓機器人重新站在起點并返回初始觀察值。step: 接收智能體的動作在物理引擎中前進一步計算新的狀態、獎勵、以及是否結束done。render: 可選用于可視化。步驟二設計狀態和動作空間 (State/Action Space)狀態空間: 告訴智能體“你看到了什么”。通常包括機器人的關節角度、關節角速度、軀干姿態歐拉角或四元數、軀干線速度和角速度、足端接觸傳感器等。這是一個高維連續向量。動作空間: 智能體“可以做什么”。對于行走機器人通常是給每個關節電機施加的目標位置或扭矩也是一個連續向量。在PyBullet中我們使用p.setJointMotorControl2來執行這些動作。步驟三精心設計獎勵函數 (Reward Function)這是最需要“藝術”和“科學”結合的部分。獎勵函數R(s, a)的設計直接決定了學習的方向。一個基礎的行走獎勵函數可能包含 python def compute_reward(self): # 假設 self.state 包含所需信息 forward_reward self.forward_velocity * self.dt # 向前速度獎勵 survival_reward 0.1 # 存活獎勵鼓勵堅持更久 energy_penalty -0.001 * sum(abs(joint_torques)) # 能量懲罰 orientation_penalty -abs(self.torso_pitch) # 姿態懲罰防止前傾后仰total_reward (forward_reward * 10.0 survival_reward energy_penalty orientation_penalty * 0.5) return total_reward “再下地獄”往往就是在這里反復調整權重系數如 10.0, 0.5。步驟四選擇并配置強化學習算法對于連續控制問題PPO (Proximal Policy Optimization) 和 SAC (Soft Actor-Critic) 是當前最流行且穩定的選擇。我們使用stable-baselines3庫它可以極大簡化訓練流程。 python from stable_baselines3 import PPO from stable_baselines3.common.env_checker import check_envenv YourCustomRobotEnv() # 你的自定義環境 check_env(env) # 檢查環境是否符合 gym 規范 model PPO(MlpPolicy, env, verbose1, tensorboard_log./ppo_robot_tensorboard/, learning_rate3e-4, n_steps2048, batch_size64, n_epochs10) 關鍵參數如 learning_rate學習率、n_steps每次更新前收集的步數都需要根據實際情況調整。步驟五啟動訓練與監控訓練是一個漫長的過程需要耐心和監控。 python # 訓練指定步數 model.learn(total_timesteps1_000_000, reset_num_timestepsTrue)# 保存模型 model.save(ppo_robot_walker_v1) # 使用 Tensorboard 監控訓練曲線 # 在命令行運行tensorboard --logdir ./ppo_robot_tensorboard/ 你需要密切關注 tensorboard 中的曲線episode_reward單次嘗試總獎勵是否在上升episode_length單次嘗試步數是否在變長這能直觀反映智能體是否在進步。步驟六評估與部署訓練完成后加載模型并觀察其表現。 python # 加載模型 model PPO.load(ppo_robot_walker_v1)obs env.reset() for i in range(1000): action, _states model.predict(obs, deterministicTrue) # 使用確定性策略 obs, reward, done, info env.step(action) env.render() # 可視化 if done: obs env.reset() 如果效果滿意這個訓練好的策略網絡就可以被“部署”到仿真環境中作為機器人的大腦。理論上經過適當轉換它也可以部署到真實的機器人硬件上但這涉及 sim-to-real 遷移是另一個挑戰。5. 完整示例構建一個簡易雙足機器人環境讓我們將上述流程具體化創建一個極簡的雙足機器人學習環境。為了聚焦核心邏輯我們使用PyBullet自帶的簡單人形模型。文件結構:bipedal_walker/ ├── envs/ │ └── bipedal_env.py # 自定義環境 ├── train.py # 訓練腳本 ├── evaluate.py # 評估腳本 └── requirements.txt1. 自定義環境 (envs/bipedal_env.py)import gymnasium as gym from gymnasium import spaces import numpy as np import pybullet as p import pybullet_data import math class SimpleBipedalEnv(gym.Env): 一個簡單的雙足機器人行走環境 metadata {render.modes: [human, rgb_array]} def __init__(self, render_modeNone): super(SimpleBipedalEnv, self).__init__() self.render_mode render_mode self.physicsClient None # 動作空間控制髖部和膝部關節共4個關節的角度范圍[-1, 1]映射到實際弧度 self.action_space spaces.Box(low-1.0, high1.0, shape(4,), dtypenp.float32) # 狀態空間關節角、角速度、軀干姿態等這里簡化定義 # 假設有4個關節加上軀干的姿態俯仰角和線速度共7個值 self.observation_space spaces.Box(low-np.inf, highnp.inf, shape(7,), dtypenp.float32) self.robot None self.joint_indices [] self.step_counter 0 self.max_steps 1000 def reset(self, seedNone, optionsNone): # 重置環境狀態 if self.physicsClient is not None: p.disconnect() self.physicsClient p.connect(p.DIRECT) # 訓練時用DIRECT更快 if self.render_mode human: p.disconnect() self.physicsClient p.connect(p.GUI) p.setAdditionalSearchPath(pybullet_data.getDataPath()) p.setGravity(0, 0, -9.8) p.resetDebugVisualizerCamera(cameraDistance2, cameraYaw0, cameraPitch-30, cameraTargetPosition[0,0,0.5]) # 加載地面和機器人 planeId p.loadURDF(plane.urdf) startPos [0, 0, 0.5] startOrientation p.getQuaternionFromEuler([0, 0, 0]) self.robot p.loadURDF(legged_spider.urdf, startPos, startOrientation) # 使用一個簡單的多足模型替代 # 獲取關節信息假設前4個是可驅動的 num_joints p.getNumJoints(self.robot) self.joint_indices [i for i in range(num_joints) if p.getJointInfo(self.robot, i)[2] p.JOINT_REVOLUTE] self.joint_indices self.joint_indices[:4] # 只取前4個旋轉關節 # 禁用默認電機控制由我們接管 for i in self.joint_indices: p.setJointMotorControl2(self.robot, i, p.VELOCITY_CONTROL, force0) self.step_counter 0 return self._get_obs(), {} def _get_obs(self): # 獲取觀察值關節角 關節角速度 軀干俯仰角 joint_states p.getJointStates(self.robot, self.joint_indices) joint_angles [state[0] for state in joint_states] joint_velocities [state[1] for state in joint_states] # 獲取軀干base的姿態和速度 base_pos, base_orn p.getBasePositionAndOrientation(self.robot) base_euler p.getEulerFromQuaternion(base_orn) # 俯仰角在 index 1 torso_pitch base_euler[1] lin_vel, ang_vel p.getBaseVelocity(self.robot) forward_vel lin_vel[0] # x方向速度 # 簡化狀態4個關節角 軀干俯仰角 向前速度 可選一個角速度 obs np.array(joint_angles [torso_pitch, forward_vel], dtypenp.float32) return obs def step(self, action): # 執行動作 # 將歸一化的動作[-1,1]映射到實際的關節角度范圍例如[-0.5, 0.5]弧度 target_positions action * 0.5 for i, joint_idx in enumerate(self.joint_indices): p.setJointMotorControl2( bodyUniqueIdself.robot, jointIndexjoint_idx, controlModep.POSITION_CONTROL, targetPositiontarget_positions[i], force50, # 最大力 positionGain0.5, velocityGain0.5 ) p.stepSimulation() self.step_counter 1 # 獲取新狀態 obs self._get_obs() # 計算獎勵 forward_vel obs[-2] # 倒數第二個是 forward_vel torso_pitch obs[-3] # 倒數第三個是 torso_pitch forward_reward forward_vel * 0.1 # 速度獎勵 alive_reward 0.5 # 存活獎勵 pitch_penalty -abs(torso_pitch) * 0.3 # 姿態懲罰 energy_penalty -0.01 * np.sum(np.square(action)) # 動作幅度懲罰模擬能耗 reward forward_reward alive_reward pitch_penalty energy_penalty # 檢查是否結束 base_pos, _ p.getBasePositionAndOrientation(self.robot) height base_pos[2] done bool(height 0.2 or self.step_counter self.max_steps) # 摔倒或超時 truncated False # Gymnasium 新增表示因非終止條件結束如超時 if self.step_counter self.max_steps: truncated True info {} return obs, reward, done, truncated, info def render(self): # 渲染邏輯如果初始化時是GUI模式step里已經自動渲染 pass def close(self): if self.physicsClient is not None: p.disconnect() self.physicsClient None2. 訓練腳本 (train.py)import os from envs.bipedal_env import SimpleBipedalEnv from stable_baselines3 import PPO from stable_baselines3.common.callbacks import CheckpointCallback, EvalCallback from stable_baselines3.common.monitor import Monitor from stable_baselines3.common.vec_env import DummyVecEnv # 創建環境 env SimpleBipedalEnv(render_modeNone) # 訓練時不渲染 env Monitor(env) # 包裝以記錄數據 env DummyVecEnv([lambda: env]) # 向量化環境單環境 # 配置模型 model PPO( MlpPolicy, env, verbose1, tensorboard_log./tensorboard_logs/, learning_rate3e-4, n_steps1024, # 每次更新前收集的步數 batch_size64, # 小批量大小 n_epochs10, # 每次更新時優化epoch數 gamma0.99, # 折扣因子 gae_lambda0.95, # GAE參數 clip_range0.2, # PPO裁剪范圍 ent_coef0.01, # 熵系數鼓勵探索 ) # 設置回調定期保存模型并在獨立環境評估 checkpoint_callback CheckpointCallback(save_freq50000, save_path./models/, name_prefixppo_bipedal) # 評估環境渲染模式可選 eval_env SimpleBipedalEnv(render_modeNone) eval_env Monitor(eval_env) eval_callback EvalCallback(eval_env, best_model_save_path./best_model/, log_path./logs/, eval_freq10000, deterministicTrue, renderFalse) print(開始訓練...) model.learn(total_timesteps500_000, callback[checkpoint_callback, eval_callback]) print(訓練完成) # 保存最終模型 model.save(ppo_bipedal_final) env.close()3. 評估與可視化腳本 (evaluate.py)from envs.bipedal_env import SimpleBipedalEnv from stable_baselines3 import PPO # 加載訓練好的模型 model PPO.load(./models/ppo_bipedal_final.zip) # 或 best_model 路徑 # 創建帶渲染的環境 env SimpleBipedalEnv(render_modehuman) obs, _ env.reset() total_reward 0 episode_count 0 while episode_count 5: # 演示5次 action, _states model.predict(obs, deterministicTrue) obs, reward, terminated, truncated, info env.step(action) total_reward reward if terminated or truncated: print(fEpisode {episode_count 1} finished. Total reward: {total_reward:.2f}) obs, _ env.reset() total_reward 0 episode_count 1 env.close()6. 運行結果與效果驗證運行上述代碼你會經歷以下階段啟動訓練在命令行執行python train.py。控制臺會輸出類似以下信息顯示訓練進度、平均獎勵等。| rollout/ | | | ep_len_mean | 23.4 | | ep_rew_mean | 8.56 | | time/ | | | fps | 1256 | | iterations | 1 | | total_timesteps | 2048 | | train/ | | | entropy_loss | -1.38 | | explained_variance | 0.123 | | learning_rate | 0.0003 | | policy_loss | -0.0456 | | value_loss | 0.123 |關鍵指標是ep_rew_mean平均單次嘗試獎勵它應該隨著訓練逐步上升。監控訓練曲線在另一個終端運行tensorboard --logdir ./tensorboard_logs/然后在瀏覽器打開http://localhost:6006。你將看到episode_reward、episode_length等曲線。一個成功的訓練過程其獎勵曲線整體呈上升趨勢盡管會有波動。驗證智能體行為訓練一段時間后例如10萬步運行python evaluate.py。此時你應該能在PyBullet的GUI窗口中看到機器人模型。一個訓練有素的智能體應該能夠保持站立平衡不會立即摔倒。嘗試邁步即使步伐可能很滑稽。向前移動盡管可能不穩定。單次嘗試的生存時間ep_len_mean顯著增長。如何判斷成功初級成功智能體能穩定站立超過100步。中級成功智能體能協調腿部做出明顯的邁步動作并持續向前移動。高級成功智能體能以穩定、高效的步態在平坦地面上持續行走甚至能應對輕微擾動。如果智能體一直摔倒獎勵曲線不升反降說明獎勵函數設計、算法參數或環境本身存在問題需要進入“調試地獄”。7. 常見問題與排查思路在復現此類項目時你幾乎一定會遇到以下問題。下表提供了系統的排查思路問題現象可能原因排查方式解決方案訓練獎勵不上升智能體原地不動或立即摔倒1. 獎勵函數設計不合理正向獎勵太難獲取。2. 學習率過高或過低。3. 神經網絡策略初始化權重導致輸出動作全為零。4. 動作空間范圍過大智能體探索不到有效區域。1. 打印每一步的獎勵構成看哪個分量占主導。2. 觀察初始動作輸出值。3. 使用Tensorboard查看explained_variance解釋方差如果接近0說明價值函數沒學好。1.重塑獎勵增加密集獎勵如存活獎勵或簡化任務如先學站立。2.調整超參嘗試經典參數組合如PPO的learning_rate3e-4。3.修改網絡在策略網絡最后一層使用小權重初始化。4.縮放動作將動作輸出范圍縮小如從[-1,1]映射到[-0.1,0.1]。智能體學會“作弊”行為如瘋狂抖動前進獎勵函數存在漏洞鼓勵了非期望行為。例如僅獎勵向前速度不懲罰高頻抖動。錄制并回放智能體的行為視頻分析其“刷分”策略。完善獎勵函數增加能量消耗懲罰、關節角速度懲罰、動作平滑性懲罰。引入“存活”的基礎獎勵并讓向前速度的獎勵與之相乘如forward_reward * alive_bonus這樣摔倒后向前獎勵也為零。訓練不穩定獎勵曲線劇烈震蕩1. 批次大小 (batch_size) 太小。2. 梯度裁剪 (max_grad_norm) 沒設置或設置不當。3. 環境隨機性太大如重置狀態方差大。1. 檢查Tensorboard中的train/policy_grad_loss是否爆炸。2. 檢查每次迭代的clip_fraction如果持續很高說明裁剪頻繁。1.增大批次大小。2.設置梯度裁剪在PPO中設置max_grad_norm0.5。3.降低環境隨機性在訓練初期使用更確定的初始狀態。仿真速度極慢1. 使用了GUI模式 (p.GUI) 進行訓練。2. 物理引擎步長 (p.stepSimulation) 太精細。3. 渲染調用過于頻繁。1. 檢查訓練腳本中環境初始化模式。2. 使用性能分析工具。1.訓練時務必使用p.DIRECT模式僅在評估時使用GUI。2.適當增大仿真步長但需注意物理穩定性。3.考慮并行化使用SubprocVecEnv或Ray進行多環境并行采樣。PyBullet無法找到URDF模型文件pybullet_data路徑未正確設置。檢查p.setAdditionalSearchPath(pybullet_data.getDataPath())是否在reset方法中調用。確保已安裝pybullet并正確導入pybullet_data。可以手動指定模型絕對路徑。stable-baselines3報錯AssertionError: The observation is not within the observation space自定義環境返回的obs形狀或數據類型與observation_space定義不符。在reset和step方法中打印obs.shape和obs.dtype與observation_space對比。確保obs是np.ndarray且形狀、數據類型、數值范圍與observation_space完全一致。使用env.check_env(env)進行驗證。8. 最佳實踐與工程建議基于《齒輪盛宴》項目所體現的迭代精神和大量實踐經驗以下建議能幫助你更高效地開展類似項目迭代式獎勵設計不要試圖一次性設計出完美的獎勵函數。采用“課程學習”思想先讓智能體學會簡單的子任務如站立不倒獎勵函數只包含存活獎勵和姿態懲罰。訓練穩定后再逐步引入向前移動的獎勵。每次只改變一個變量觀察影響。充分的監控與可視化除了獎勵曲線還要監控關鍵狀態量的分布如關節角度、軀干傾斜角、動作值的分布、價值函數估計等。錄制智能體行為的視頻回放是發現異常行為最直觀的方式。使用版本控制與環境封裝為每次重要的獎勵函數修改、超參數調整創建獨立的代碼分支或實驗目錄。將環境配置、獎勵函數、算法參數打包成一個可復現的“實驗配置”。這能讓你在“重新開始”和“深入地獄”之間從容切換和回溯。從簡單環境開始在讓智能體學習復雜地形行走前先在平坦地面上訓練。甚至可以先在二維平面簡化模型中驗證算法和獎勵函數的有效性再遷移到三維全模型。這能極大降低調試復雜度。超參數調優有優先級對于PPO這類算法影響最大的通常是learning_rate、n_steps或batch_size和gamma。建議先使用社區驗證的默認值如SB3的PPO默認值只有在獎勵函數設計相對合理后再進行小范圍網格搜索或使用Optuna等工具優化。理解算法假設PPO是一種同策略算法它利用當前策略收集的數據來更新自己。這意味著如果策略變得很差它收集的數據質量也會變差可能導致性能崩潰。如果遇到這種情況可以考慮保存歷史最佳策略或切換到SAC這類異策略算法。生產化考量如果目標是部署到真實機器人在仿真階段就要考慮“Sim-to-Real”鴻溝。在訓練中引入域隨機化如隨機化地面摩擦系數、機器人質量、傳感器噪聲等可以增強策略的魯棒性使其更容易遷移到現實世界。《齒輪盛宴EP.4》所展示的“重新開始”與“再下地獄”正是強化學習項目開發的真實寫照。它不是一個線性過程而是一個螺旋上升的調試循環。每一次對獎勵函數的微調每一次對超參數的嘗試甚至每一次推倒重來都是讓“機器”向期望行為進化的一小步。通過本文提供的框架、代碼和避坑指南希望你能親手啟動屬于自己的“機器進化”項目在解決復雜控制問題的道路上少一些迷茫多一些篤定。