
最近在和游戏团队聊 AI 工作流时经常听到一个非常类似的困惑AI 生成的对白、任务文本、技能描述确实让人眼前一亮但一旦进入正式制作流程问题就接踵而至——改到第三版时它忘了前面的数值规则让它计算奖励时输出一个明显不合理的数字换一个模型之后之前的“调教”全部失效。于是很多人得出一个结论AI 只能用来找灵感不能用来做交付。但我的判断不同。不是 AI 不能用于交付而是大多数游戏设计师还停留在和“裸模型”对话的阶段缺少一个把模型、工具、上下文、校验逻辑和文件落盘组装起来的“工程骨架”。这个骨架就是社区里越来越常被提到的 harness。从最近大家高频搜索的 deepseek harness、harness engineering、Agent 框架与编排、Agent 开发学习路线等词可以看到这个话题正在从 AI 工程师圈子扩散到更多岗位。这篇文章不打算复读某个现成项目的安装命令而是想先把一个更根本的问题讲清楚为什么游戏设计师需要搭建自己的 harness它到底是什么、解决了哪些具体问题、和你手上的 AI 聊天工具有什么区别以及怎么从零做出一个能嵌入游戏设计管线的最小版本。读完你会得到一个比“写提示词”可靠得多的做事方式。1. 游戏设计师正在面对的真实问题1.1 AI 生成内容很强但“交付”是另一回事很多人第一次接触 Agent 类工具时都会有一种“AI 好像真的懂游戏设计”的错觉。你让它写一个序章任务它能给出背景、目标、敌人、奖励你让它生成十个 NPC 的性格标签它也能很快列出来。这些内容放在灵感阶段完全够用但放进真正的制作管线时情况就变了。游戏设计和其他内容创作有一个本质区别游戏设计最终要产出的是“可被程序读取的数据结构”而不是一篇散文。一个任务在文档里写得再漂亮最终也要变成 Excel 配表、JSON 配置或数据库记录。这时AI 那些“语言上的精彩”反而成了风险它会写出一个结构不对的奖励表达式会把任务目标里的怪物 ID 写成名字甚至会自信地编造一个游戏里根本存在的物品。换句话说游戏设计师真正缺的不是“AI 生成能力”而是“把 AI 生成能力约束成合格工件的控制层”。如果没有这一层AI 就永远只能是一个昂贵的灵感机器。1.2 问题的根源缺少 harness 层为什么同一套提示词在一些人手里很稳定在另一些人手里一塌糊涂为什么优秀的 Agent 工作流看起来不只是“多轮对话”原因就在于稳定可用的 Agent 工作流一定会在模型外面加一层控制逻辑限定它能调用哪些工具规定它输出什么结构记录它每一步做了什么失败时让它重试偶尔还要把历史对话压缩成摘要。这个“控制层”就是近期社区热词里反复出现的 harness。放在游戏设计语境里harness 可以理解成一个“创作夹具”它把模型这颗相对通用的大脑固定在一个具体的设计工序上让它只做这一道工序并且按你的标准产出。没有夹具的自由手作很灵活但无法量产有了夹具之后灵活度下降但稳定性和交付效率大幅提升。这就是为什么我认为游戏设计师需要搭建自己的 harness而不是拿着通用聊天工具直接开工。因为你的工作场景本身就带有“结构化产出、多轮迭代、跨工具协作、需要回归验证”的工程属性这不是靠提示词堆叠能解决的。2. harness 是什么概念、误区与适用边界2.1 从马具到 Agent 工程骨架harness 的英文原意是马具、安全带或降落伞背带作用是“把力量和安全地连接起来”。在 Agent 开发里这个词被借用过来指的是围绕一个模型或一个 Agent 搭建的工程外壳。你可以它看作一个控制台模型是发动机harness 是驾驶舱、方向盘、仪表盘和安全带。具体来说一个典型的 harness 至少包含几类职责对接模型接口注册和调度工具管理对话历史保存运行状态控制最大步数校验模型输出记录日志和错误决定什么时候停止、重试、回退。它不是一个像 LangChain 那么庞大的框架也不是某个特定聊天软件而是你在项目里写下来的那层“胶水代码”。从近期搜索热词来看harness engineering 已经成为一个独立的话题。很多项目直接用 harness 命名比如社区里讨论度不低的 deepseek harness它的目标就是让用户能在地方面客搭建起一个可控的 Agent 运行环境。对这些项目来说harness 更像是产品的名字但从工程本质来看它们做的是同一件事把模型接入具体业务时的各种控制逻辑标准化。2.2 harness 与 Agent 框架、客户端的区别很多初学者会把 harness 和 Agent 框架混在一起。这样理解并非完全错误但容易导致一开始就陷入复杂抽象反而写不出可用的东西。这里我给出一个更朴素的区分层次代表职责模型GPT、Claude、DeepSeek 等完成文本生成、理解和推理客户端ChatGPT 网页、Claude Code、国产桌面工具提供人与模型的交互入口Agent 框架LangChain、AutoGen 等提供通用 Agent 循环、编排、记忆组件harness你自己项目里的控制层把模型和工具约束到你业务的验收标准里你可以不用任何 Agent 框架直接写一个 50 行的 harness你也可以在框架之上再包一层 harness。harness 不追求通用它追求的是“只有你的项目需要的规则”。比如“任务描述必须包含目标怪物 ID”“奖励公式必须经过校验脚本计算”“最终产出必须写进 JSON 文件”这些规则放到通用框架里往往要绕很多层但写在自己的 harness 里就是几行代码。2.3 适用边界哪些场景真的需要 harness不是所有 AI 使用场景都需要 harness。做头脑风暴、写世界观文档、整理灵感碎片时直接和模型对话反而效率更高。harness 的价值出现在“重复性生产”和“可验证产出”场景里你每隔几天就要生成一批任务文本你需要保证这批文本的格式和之前一致你要让 AI 在生成后自动校验奖励数值你希望同事也能跑同一个流程而不依赖某一个人的“玄学提示词”。一句话总结灵感阶段用聊天生产阶段用 harness。如果你发现自己总是在同一件事上反复“重建提示词”或者每次让 AI 跑同一个流程结果都不一样那就是到了搭 harness 的时候。3. 为什么现成的 Agent 客户端满足不了游戏设计3.1 上下文不设防现成的 Agent 客户端通常只给你一个很长的对话框。你可以把多次任务塞进同一个会话里但模型不会自动区分“这次讨论是设计文档”“这次讨论是生成配置数据”。一段美好的世界观设定可能就会干扰后面每一次 JSON 生成让它输出大量语气抒情、结构混乱的内容。游戏设计恰恰又特别依赖短期上下文的一致性一个任务改了 6 个版本第 6 版必须仍然知道第 1 版定下的怪物数值。通用客户端不会帮你维护这个“设计基线”它只会把全部历史拼在一起交给模型结果就是早期信息被稀释后期行为漂移越来越严重。3.2 工具调用难追溯当你需要 Agent 读写表格、跑数值脚本或更新配置时游戏设计工具链和通用 Agent 客户端往往是断开的。你能在聊天窗口里让模型“算一下”但它没有权限访问你的设计表即使你手动粘贴数据模型也只是在“假装计算”结果可能完全不可信。自己的 harness 可以注册真实工具validate_task_schema用来校验任务结构estimate_difficulty用来做数值粗算save_task_output用来把最终结果写进指定文件。工具是确定性函数模型只负责任选择参数真正计算的是代码。这样 Agent 的输出就从“听起来合理”变成“算过、验过、落盘过”。3.3 行为漂移同一个任务每次结果都不一样通用客户端默认追求对话的流畅和多样这对聊天是优点但对生产是灾难。你要的是同一套规则下生成 30 个支线任务它们的格式必须完全一致而不能“这次想到什么写什么”。通用工具不会自动记住上次的输出格式、字段顺序和术语偏好。harness 通过在系统提示词里固定任务模板再通过输出校验函数强制格式可以做到“每次生成的结果都符合同样的验收标准”。即使换一个底层模型只要 harness 的校验逻辑不变返回给设计系统的数据就是稳定的。对生产管线来说这个稳定比单次生成的惊艳重要得多。3.4 无法嵌入设计管线游戏设计团队通常有版本管理、配置仓库、测试计划。通用 Agent 客户端生成的文本需要人肉复制粘贴到配表、再提交、再通知策划复核。这个过程一旦涉及大量内容就会变成新的瓶颈。harrness 可以主动对接这些环节生成后直接按模板写 JSON触发本地的格式检查甚至把结果交给一个测试脚本跑一遍平衡性检查。它适合被放进 CI 或制作流程中成为真正的“设计工具”而不是一个聊天框。4. 游戏设计师最适合从哪些场景开始4.1 NPC 对白批量生成与一致性检查批量生成 NPC 对白时最头疼的不是“写不出”而是“风格不统一”。同一个酒馆里的十个 NPC有些说话像中世纪骑士有些像现代大学生。harrness 可以在生成前固定一份“角色语言规范”在生成后调用一个关键词/语气检查函数标记不符合规范的对白并让模型重写。更进阶的玩法是为每个 NPC 维护一个“性格状态”字段harrness 在调用模型前把状态拼进提示词模型只负责基于当前状态说一句话再把这句话影响的状态写入文件。这样即使进行一百轮对话NPC 也不会突然失忆。4.2 任务与支线文本的结构化生产任务配置涉及多个字段前置任务、过程目标、奖励、失败条件等。初级做法是让模型生成一段描述策划再手工拆字段harrness 的做法是定义好 JSON Schema要求模型直接按 Schema 生成生成后立即用校验函数检查。遗漏字段、类型错误、枚举值错误都会在模型重试阶段被拦截而不是等配置提交后被程序报错。这个场景特别适合第一个 harness 实践规则清晰、字段有限、马上能看到效果。4.3 关卡配置与数值假设验证游戏策划经常要在“感觉”上调整怪物数值。harrness 里可以挂一个简单的模拟器函数比如给定怪物数量和输出期望计算一场战斗的承伤风险。Agent 生成一版数值后不直接交付而是先调用模拟器把结果反馈给模型“当前配置下玩家可能在第三回合倒下请把怪物攻击系数调低 10%。”模型再基于反馈修改形成一个快速反馈闭环。这个能力比“让模型直接给出最终答案”可靠得多因为它把开放式的数值生成变成了一个有检验标准的迭代问题。4.4 自动化测试与回归评审当你的 harrness 生成了一批新任务怎么确认不是“看起来合理但同事用不了”可以让 harrness 自己跑回归用固定的测试输入检查所有生成的 JSON 是否能通过同一个校验函数是否包含禁用词是否满足基础规则。这个回归脚本不一定要多强但它能把“AI 换版本”带来的影响暴露出来避免上线前才发现无法读取配置。5. 最小可用的 harness核心模块与架构5.1 核心模块一个最小 harrness 不需要复杂分布式架构四个模块就够模型接入模块负责把系统提示词、历史消息和工具描述发给模型拿到回复。工具注册表维护“工具名 - 函数”的映射模型只负责指定工具名和参数。循环控制器核心 while 循环判断模型是调用工具还是输出最终结果控制最大步数。输出校验与落盘对最终结果执行校验函数通过后写文件失败则返回错误让模型重试。这里真正的难点不是写循环而是把“校验”放在“生成”后面。很多人只写提示词让模型“尽力而为”结果模型经常自作主张harrness 的做法是允许模型随便生成但生成后无条件过校验不通过就打回重写。5.2 最小目录结构game-harness/ ├── config.yaml ├── main.py ├── tools.py └── outputs/ └── task_latest.json我把代码分成两个文件就是为了让工具函数和主循环解耦。新手刚开始时也可以全写在一个文件里但建议还是按上面的结构来拆分。工具函数会有自己的 import 和数据格式拆出去后重新跑任务、加新工具都会容易很多。5.3 一次运行的生命周期一次典型的 harrness 运行流程如下读取配置文件初始化模型客户端注册工具把用户输入和系统提示词组装成初始消息进入循环把消息发给模型如果模型要求调用工具执行对应工具函数把结果作为新的工具消息追加到对话中继续循环如果模型给出最终文本则交给输出校验校验通过则保存并退出失败则构造一条错误消息让模型重试。整个循环最重要的变量是max_steps。模型陷入反复调用工具时这个值能保证进程不会跑到天荒地老。6. 完整示例游戏任务设计验证 Agent6.1 环境准备这个示例只依赖 Python 和一个兼容 OpenAI 接口的模型服务。无论你使用的是本地部署服务还是云端接口只要它支持chat.completions.create接口和工具调用协议代码都可以复用。版本请以实际项目为准本文重点演示通用思路。安装依赖pip install openai pyyaml如果你的模型服务不需要真实密钥可以把api_key填成任意占位符例如EMPTY。6.2 模型与服务配置新建config.yaml这个文件把模型、循环参数、目录和系统提示词集中管理。这样以后换模型、调步数不用改代码。model: provider: openai-compatible base_url: http://localhost:8080/v1 model_name: demo-model api_key: EMPTY agent: max_steps: 8 output_dir: ./outputs system_prompt: | 你是一名资深游戏任务设计师。 你的工作是为游戏生成任务定义 JSON。 任务 JSON 必须包含以下字段 - task_name: 字符串 - task_desc: 字符串 - targets: 数组每个元素包含 enemy_id 和 count - rewards: 数组每个元素包含 item_id 和 count 在输出最终 JSON 之前必须调用 validate_task_schema 进行校验。 如果校验失败根据返回的 errors 修改任务并重试最多重试 3 次。 不要解释过程只要在最终消息中输出合法的 JSON 对象。6.3 工具定义新建tools.py实现三个工具。第一个负责校验任务结构第二个负责估算战斗风险第三个负责把结果保存成文件。# tools.py import json from pathlib import Path def validate_task_schema(task: dict) - dict: errors [] if not isinstance(task, dict): return {pass: False, errors: [task must be a dict]} if not task.get(task_name): errors.append(task_name is required) if len(task.get(task_desc, )) 10: errors.append(task_desc is too short) if not isinstance(task.get(targets), list) or len(task[targets]) 0: errors.append(targets must be a non-empty list) else: for target in task[targets]: if not target.get(enemy_id) or target.get(count, 0) 0: errors.append(each target needs enemy_id and positive count) if not isinstance(task.get(rewards), list) or len(task[rewards]) 0: errors.append(rewards must be a non-empty list) return {pass: len(errors) 0, errors: errors} def estimate_difficulty(monster_count: int, base_atk: int, player_hp: int) - dict: risk_score round(monster_count * base_atk / max(player_hp, 1), 2) if risk_score 0.5: level easy elif risk_score 1.0: level medium else: level hard return {risk_score: risk_score, level: level} def save_task_output(task: dict, path: str ./outputs/task_latest.json) - dict: Path(path).parent.mkdir(parentsTrue, exist_okTrue) with open(path, w, encodingutf-8) as f: json.dump(task, f, ensure_asciiFalse, indent2) return {saved: True, path: path}这里值得注意的一点是工具函数必须返回“结构化结果”而不是人类印象。estimate_difficulty返回的是数字和等级模型拿到后才能精确地调整数值save_task_output返回文件路径模型就知道结果已经落盘不会在后续对话里重复犹豫。6.4 主循环实现新建main.py。我用一个GameDesignHarness类来封装配置、工具注册和主循环。为了让读者不陷入某个 SDK 的细节这里使用主流的 OpenAI 兼容协议写法。# main.py import json import yaml from openai import OpenAI import tools class GameDesignHarness: def __init__(self, config_path: str config.yaml): with open(config_path, r, encodingutf-8) as f: self.cfg yaml.safe_load(f) self.model_cfg self.cfg[model] self.client OpenAI( base_urlself.model_cfg[base_url], api_keyself.model_cfg.get(api_key, EMPTY), ) self.model_name self.model_cfg[model_name] self.max_steps self.cfg[agent][max_steps] self.output_dir self.cfg[agent][output_dir] self.system_prompt self.cfg[system_prompt] self.tools {} def register_tool(self, name, func, description, parameters): self.tools[name] { function: func, meta: { type: function, function: { name: name, description: description, parameters: parameters, }, }, } def _call_model(self, messages): return self.client.chat.completions.create( modelself.model_name, messagesmessages, tools[t[meta] for t in self.tools.values()] if self.tools else None, ) def run(self, user_input: str): messages [ {role: system, content: self.system_prompt}, {role: user, content: user_input}, ] for _ in range(self.max_steps): response self._call_model(messages) message response.choices[0].message if not message.tool_calls: content message.content or try: task json.loads(content) except json.JSONDecodeError as e: messages.append({role: assistant, content: content}) messages.append({ role: user, content: f最终输出必须是合法 JSON当前解析失败: {e}, }) continue saved tools.save_task_output(task, self.output_dir /task_latest.json) return {status: done, task: task, saved: saved} messages.append({role: assistant, content: message.content, tool_calls: message.tool_calls}) for tool_call in message.tool_calls: fn_name tool_call.function.name fn_args json.loads(tool_call.function.arguments) if fn_name not in self.tools: messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps({error: ftool {fn_name} not found}), }) continue result self.tools[fn_name][function](**fn_args) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse), }) return {status: max_steps_exceeded, messages: messages} def build_harness(): harness GameDesignHarness() harness.register_tool( validate_task_schema, tools.validate_task_schema, 校验任务 JSON 结构是否满足设计规范, { type: object, properties: {task: {type: object, description: 待校验的任务对象}}, required: [task], }, ) harness.register_tool( estimate_difficulty, tools.estimate_difficulty, 估算一场战斗的风险等级, { type: object, properties: { monster_count: {type: integer}, base_atk: {type: integer}, player_hp: {type: integer}, }, required: [monster_count, base_atk, player_hp], }, ) return harness if __name__ __main__: harness build_harness() prompt 生成一个 15 分钟的序章任务玩家需要击败 3 只森林狼奖励是 2 个治疗药水。战斗难度中等玩家初始生命 100。 result harness.run(prompt) print(json.dumps(result, ensure_asciiFalse, indent2))这段代码的主循环逻辑是模型如果返回tool_callsharness 就逐个执行工具并把结果追加到对话如果模型直接返回文本就尝试解析成 JSON成功则保存退出。真正值得学习的是那个异常分支——当模型输出的不是合法 JSON 时harness 不会默默接受而是把解析错误作为新消息发回给模型逼迫它输出合法结构。6.5 运行方式在项目目录下执行python main.py如果模型服务没有启动或接口不兼容大概率会在第一次_call_model时报连接错误如果服务正常且模型支持工具调用最终会在outputs/task_latest.json看到一个任务 JSON。7. 运行验证与效果评估7.1 预期输出一次成功运行会打印类似下面的结果{ status: done, task: { task_name: 狼群来袭, task_desc: 玩家需要在序章的森林区域击败一群森林狼, targets: [ { enemy_id: wolf_forest, count: 3 } ], rewards: [ { item_id: potion_hp_small, count: 2 } ] }, saved: { saved: true, path: ./outputs/task_latest.json } }和裸模型对话相比这个输出最重要的特征是稳定字段名固定、类型正确、奖励和任务目标都是可被程序读取的结构。7.2 如何判断成功判断成功的标准不是“AI 写的任务好不好”而是三条硬指标第一输出的 JSON 能被json.loads正确解析第二能通过validate_task_schema校验第三文件成功写入outputs/task_latest.json。设计质量当然也重要但它属于“后续人工评审”的范畴harness 首先要解决的是机器可读、格式稳定、过程可追。如果你把estimate_difficulty也放进提示词里还可以看到模型在最终输出前先调用工具再根据工具返回的risk_score调整自身结论。这说明 harrness 已经把“生成”和“真实计算”连接了起来模型不再靠感觉拍板。7.3 失败时的第一排查顺序如果运行失败先按顺序检查这几个位置模型服务地址是否可访问使用curl或浏览器确认接口返回正常配置里的model_name是否真的存在模型是否支持工具调用不支持就看不到tool_calls只会得到纯文本系统提示词是否强制要求调用校验工具如果提示词里没提模型很可能绕过工具直接输出。这些都是实际项目中最常见的失败点。8. 常见问题与排查思路8.1 高发问题速查表问题现象可能原因排查方式解决方案启动后直接连接失败base_url 或 api_key 配置错误打印配置并测试接口连通性修正 config.yaml确认模型服务已启动模型不调用任何工具系统提示词未强调工具或模型不支持工具调用打印tools列表检查响应是否包含 tool_calls在提示词中明确要求先调用工具并换支持工具调用的模型最终输出不是合法 JSON模型输出带解释文字或代码块标记查看最终的content原文增加 JSON 解析失败后的重试分支并提示“只需要 JSON”校验函数报错模型调用工具时传入参数类型错误查看工具调用的arguments原文在函数入口做参数类型转换并把校验错误返回给模型重试Agent 陷入死循环工具返回错误信息不够清晰模型无法修正打印每轮消息历史和步数计数设置合理的 max_steps工具返回结构化错误信息更换模型后行为漂移新模型对提示词的遵循度不同对比两个模型的工具调用次数和校验通过率固定模型版本升级前用测试集回归插件或扩展加载失败版本不匹配、依赖冲突、路径不对查看启动日志中插件条目确保插件与主版本兼容使用虚拟环境隔离依赖8.2 几个高发问题详解第一个值得展开的是“模型不调用工具”。很多本地小模型虽然兼容 OpenAI 接口但对工具调用协议的支持很弱拿到tools参数后仍然只会输出普通文本。这时先不要怀疑代码先换一个明确支持 function calling 的模型实测。如果模型支持但也不调用检查提示词里是否出现“直接给出答案就好”之类的暗号——模型会优先选择最省事的路径系统提示词必须把“必须调用工具”写得很直白。第二个是“输出校验一直失败”。最常见的原因是模型把task参数当作字符串而不是对象传给了validate_task_schema。可以在工具函数里加一层防御用json.loads尝试解析字符串参数解析失败再把具体错误返回给模型。这种“模型犯错 - harrness 反馈 - 模型修正”的模式本身就是 harness 的核心价值。第三个是社区里高频出现的“harness failed to load plugins”。这通常出现在一些命名里带 harness 的现成项目中原因大概率是插件版本与主程序版本不匹配或依赖没装完整。排查时不要只盯着报错最后一行要看日志里“完整未加载条目”的列表逐个核对版本。如果你的 harness 是自己写的建议从一开始就用虚拟环境固定依赖版本避免出现“在我们机器上可以跑”的经典现象。9. 最佳实践与下一步建议9.1 工程最佳实践先写验收标准再写提示词。很多设计师习惯先写一段华丽提示词结果很难验证。反过来做先定义“生成结果必须满足哪些条件”再把这些条件翻译成校验函数和提示词代码写起来反而更轻松。固定模型版本和提示词版本。AI 领域的更新速度快今天能跑通的提示词下周换一个模型 API 版本可能就失效。为每个模型版本和提示词版本都加上标识符在输出文件里记录版本号是成本最低的回滚手段。工具输出必须结构化。工具函数返回给模型的内容尽量用 JSON不要用“很好”“失败”这种模糊中文。模型需要数字、等级、错误列表才能据此进行下一步决策。日志记录要覆盖完整周期。记录每次模型响应、工具调用参数、校验结果、重试次数。出现问题时这些日志能让你快速还原“模型到底哪一步开始跑偏”。不要等出了问题再去猜。最小权限与合规风险。harrness 能够读写文件、调用脚本就必须警惕越权。指定明确的输出目录不要让 Agent 任意读取配置表或玩家数据涉及真实业务数据的场景先脱敏再交给模型。任何自动化操作都要在测试环境验证并通过备份、回滚机制保护关键数据。9.2 对游戏设计师的学习路径建议如果你是游戏设计师不用先啃完整的 Agent 框架文档。一个更高效的学习路径是先做出一个类似本文的 50 行 harness只解决“批量生成任务并校验格式”这一个问题再增加一个真实工具比如读取某个 Excel 导出成 JSON再增加“失败后自动重试”的逻辑最后尝试用一个测试集做回归。每一步都能直接作用于你的实际工作也自然离“把 AI 接入生产流程”更近一步。还可以多关注社区里关于 harness engineering、Agent 框架与编排的内容。这些内容表面上偏工程但底层思路对设计岗非常有帮助如何定义工具边界如何做上下文管理如何让 Agent 知道自己什么时候停下。9.3 最后提醒回到标题的问题游戏设计师为什么要搭建自己的 harness因为它能把 AI 的能力固定成你团队里可复用的“设计工具”而不是每次都要重新讨好一个随机应变的聊天对象。这个工作不需要你会写多复杂的算法只需要你把“写提示词”升级成“写校验规则 写工具 写闭环”。如果你已经受够了“AI 每次给的格式都不一样”那就拿一个最小的任务流程开始搭吧。第一版不需要多漂亮能把一次生成的 JSON 稳定校验、落盘就已经比大多数裸模型方案多走了一大步。