
1. 项目概述当AI学会“指哪打哪”最近在折腾AI智能体Agent开发的朋友估计没少为两件事头疼一是让Agent能稳定、准确地调用外部工具和API二是设计一个足够灵活、能适应各种未知新任务的系统架构。我自己在尝试将大语言模型LLM接入实际业务流时就经常遇到“幻觉调用”——模型凭空编造一个不存在的API参数或者面对一个稍微复杂点的组合任务就直接“摆烂”的情况。这背后的核心痛点其实就是传统方法在“开放性”上的不足模型被训练在固定的工具集和任务范式上一旦环境变化或需求超出预设性能就急剧下降。这正是“PLATO: Pointer Learner for Agent and Task Openness”这个项目试图破局的方向。PLATO直译过来是“指针学习器”它的核心思想不是教模型死记硬背成千上万个具体的API签名和任务流程而是赋予它一种更底层的“指向”能力。你可以把它想象成教一个实习生与其让他背熟公司所有部门的每一条规章制度这不可能且低效不如教会他如何快速查阅公司手册、理解组织架构图并能根据当前问题的关键词精准地“指向”手册中相关的章节或联系到正确的负责人。PLATO让AI智能体学会的正是这种“按图索骥”和“动态链接”的元能力。简单来说PLATO的目标是实现智能体Agent与任务Task的双重开放性Openness。对于智能体开放意味着它能自主发现、学习并使用未曾见过的新工具对于任务开放意味着它能理解并执行超出训练数据范围的、由基础原子操作组合而成的复杂新任务。这直接回应了当前AI应用落地中最迫切的诉求如何让AI系统像人一样具备在陌生环境中快速学习和适应的能力而不是一个只能重复预设动作的精致木偶。接下来我们就深入拆解PLATO是如何设计来实现这一野心的。2. 核心架构与“指针学习”原理拆解要理解PLATO得先抛开那些复杂的数学公式从它解决的根本矛盾入手。传统基于微调或提示工程Prompt Engineering的智能体其能力边界严重受限于训练数据。你喂给它100个工具的使用例子它最多能较好地处理第101个相似工具但面对一个原理迥异的新工具或者需要将已知工具以全新方式串联的任务时它就无能为力了。这就像只学过四则运算计算器突然丢给它一个需要解微积分的问题一样。PLATO的解法颇具巧思它引入了一个核心中间件指针网络Pointer Network。这个“指针”是理解其所有机制的关键。2.1 指针网络从“生成”到“指向”的范式转换在自然语言处理中常见的序列到序列Seq2Seq模型是“生成式”的。比如翻译模型它看到“apple”会在自己的词库里“生成”出“苹果”这个词。但指针网络不同它的输出不是从自己的词汇表生成一个新词而是“指向”输入序列中的某个位置。例如在文本摘要任务中指针网络不是自己编造句子而是从原文中“指出”哪些词句应该被摘录出来组成摘要。PLATO将这一思想创造性地应用于智能体决策。它不再要求大语言模型直接“幻想”出工具调用的具体参数如{“city”: “Beijing”}而是让模型学会“指向”一个外部的、动态更新的工具与任务知识库中的特定条目。这个知识库包含了所有可用工具的标准化描述包括功能、输入输出格式、约束条件等以及基础任务模板。这个过程可以类比为传统方法生成式你问助手“查一下北京天气。”助手可能直接回答“北京晴25度。”这个回答完全来自助手自己的知识可能对可能错且无法执行后续操作。PLATO方法指向式同样的问题PLATO驱动的助手会先“看向”一个工具手册知识库手册里有一条记录“工具名get_weather功能查询城市天气输入格式{“location”: “城市名”}输出格式{“weather”: “...”, “temp”: ...}”。然后助手“指向”这条记录并基于它生成符合格式的调用指令get_weather({“location”: “北京”})。这个转变至关重要。模型的学习目标从“无中生有地创造正确调用”变成了“在给定上下文中找到正确的参考点”。这大大降低了学习的难度和产生“幻觉”的风险因为模型只需要学会匹配和关联而不是凭空编造细节。2.2 双重开放性的实现机制基于指针网络这个核心PLATO构建了实现Agent开放性和Task开放性的具体机制。2.2.1 Agent开放性工具的动态发现与集成PLATO为每个工具维护一个结构化的描述文件通常采用一种标准化的描述语言如类似于OpenAPI的规范或一种特定的描述性文本。这个描述不仅包括工具名称和参数更重要的是用自然语言阐明其功能、适用场景和副作用。当遇到一个新工具时PLATO不会重新训练整个模型。而是将这个新工具的描述添加到外部的工具知识库中。在运行时当模型接收到用户请求它会检索Retrieve将用户请求与知识库中所有工具的描述进行语义相似度匹配找出最相关的几个候选工具。指向与推理Point Reason指针网络结合用户请求的上下文和候选工具的描述决定“指向”哪一个或哪几个工具是最合适的。参数实例化Instantiate根据被指向的工具描述中定义的输入格式模型从用户请求和对话历史中提取或推理出具体的参数值。这样一来增加新工具就像在图书馆的目录里新增一张卡片而不需要重写整个图书馆的索引系统。只要工具的描述是清晰、结构化的PLATO就有能力去尝试使用它。2.2.2 Task开放性任务的组合与分解对于复杂的新任务PLATO将其视为一系列已知原子操作对应基础工具或子任务的组合。它通过一个分层任务规划器来实现这一点。高层目标解析模型首先将用户的复杂指令如“为我策划一个周末北京胡同文化之旅并预订合适的酒店”解析成一个抽象的高层目标序列。子任务匹配与指向对于每个高层目标如“查找胡同文化景点”、“筛选酒店”PLATO再次动用指针网络去指向任务知识库中已有的、可完成类似目标的原子任务模板或工作流片段。工作流编排将这些被指向的原子任务按照逻辑顺序和依赖关系组合起来形成一个可执行的工作流图。在这个过程中模型需要处理任务之间的数据传递上一个任务的输出如何作为下一个任务的输入和条件判断。这里的“开放性”体现在只要原子任务库足够丰富并且模型学会了如何正确地组合它们理论上它就能应对无数种由这些原子任务排列组合而成的新颖复杂任务。这类似于人类用有限的词汇和语法规则可以创造出无限多的句子。2.3 训练策略如何教会模型“指”PLATO的训练数据不是简单的输入输出对而是用户指令工具知识库正确工具调用序列或任务规划序列这样的三元组。训练过程主要聚焦于两点指针准确性训练让模型学会在给定的工具描述集合中准确地将用户意图指向最相关的工具描述。这通常通过最大化指向正确工具的概率来实现。参数填充与逻辑推理训练在指向正确工具后模型需要根据工具描述的要求从对话历史和指令中提取或推理出正确的参数。这部分训练让模型理解工具描述语义与具体数据之间的映射关系。训练通常采用两阶段或联合训练的方式。首先可能在大量的指令工具集正确调用数据上进行预训练让模型建立初步的指向和参数化能力。然后可以通过强化学习或人类反馈RLHF进行微调优化其在实际交互中的成功率和效率。注意指针网络的一个关键优势是它对工具知识库的大小不敏感。无论库中有10个还是10000个工具模型的“指向”操作在计算上都是高效的因为它本质上是在做检索和选择而不是在庞大的参数空间中进行生成。这为构建大规模、可扩展的工具生态奠定了基础。3. 实操构建从零搭建一个PLATO风格智能体理解了原理我们动手实现一个简化版的PLATO核心流程。这里我们使用Python和流行的LangChain框架来演示因为它提供了良好的工具抽象和链式调用能力方便我们模拟“指向”和“组合”的逻辑。请注意这是一个高度简化的概念验证实现真实的PLATO系统要复杂得多。3.1 环境准备与工具知识库定义首先我们定义我们的“工具宇宙”。我们将创建一个小型的工具知识库每个工具都有结构化的描述。# 定义工具描述知识库 tool_knowledge_base [ { name: get_weather, description: 获取指定城市的当前天气情况。, parameters: { location: {type: string, description: 城市名称例如北京、上海} }, returns: {type: object, description: 包含天气状况和温度的字典}, example: 用户输入北京天气怎么样 - 调用: get_weather({location: 北京}) }, { name: search_restaurants, description: 在指定城市和区域附近搜索特定类型的餐厅。, parameters: { city: {type: string, description: 城市名}, district: {type: string, description: 区域或商圈例如朝阳区、王府井}, cuisine: {type: string, description: 菜系例如川菜、意大利菜} }, returns: {type: list, description: 餐厅信息列表}, example: 用户输入帮我找找国贸附近的川菜馆 - 调用: search_restaurants({city:北京, district:国贸, cuisine:川菜}) }, { name: book_flight, description: 查询并预订航班。, parameters: { departure: {type: string, description: 出发城市}, destination: {type: string, description: 到达城市}, date: {type: string, description: 出发日期格式YYYY-MM-DD} }, returns: {type: object, description: 航班选项和预订状态}, example: 用户输入我想订下周五从上海飞广州的机票 - 调用: book_flight({departure:上海, destination:广州, date:2023-10-27}) } ] # 模拟的工具函数实现实际中会调用真实API def mock_get_weather(location): return {weather: 晴朗, temperature: 22, location: location} def mock_search_restaurants(city, district, cuisine): return [{name: f好吃的{cuisine}馆1, address: f{city}{district}路1号}, {name: f地道的{cuisine}馆2, address: f{city}{district}路2号}] def mock_book_flight(departure, destination, date): return {status: 查询成功, flights: [{airline: 模拟航空, time: 10:00}]}3.2 实现核心指针学习器简化版我们将实现一个简化的“指针”逻辑它使用文本嵌入Embedding来计算用户查询与工具描述的相似度从而进行“指向”。from sentence_transformers import SentenceTransformer import numpy as np class SimplePointerLearner: def __init__(self, tool_base): self.tool_base tool_base # 加载一个轻量级的句子编码模型来计算语义相似度 self.encoder SentenceTransformer(paraphrase-multilingual-MiniLM-L12-v2) # 预计算所有工具描述的嵌入向量 self._index_tool_descriptions() def _index_tool_descriptions(self): 为知识库中的每个工具创建描述文本并编码。 self.tool_descriptions [] self.tool_embeddings [] for tool in self.tool_base: # 将工具信息组合成一段描述性文本 desc_text f工具名称{tool[name]}。功能{tool[description]}。参数{, .join(tool[parameters].keys())}。示例{tool[example]} self.tool_descriptions.append(desc_text) # 批量编码提高效率 if self.tool_descriptions: self.tool_embeddings self.encoder.encode(self.tool_descriptions, convert_to_tensorTrue) def point_to_tool(self, user_query, top_k2): 核心指向函数根据用户查询返回最相关的工具。 Args: user_query: 用户输入的自然语言指令。 top_k: 返回最相关的K个工具候选。 Returns: list: 最相关的工具字典列表。 if not self.tool_descriptions: return [] # 编码用户查询 query_embedding self.encoder.encode(user_query, convert_to_tensorTrue) # 计算余弦相似度 # 使用PyTorch在GPU/CPU上高效计算 cos_scores np.dot(self.tool_embeddings, query_embedding) / (np.linalg.norm(self.tool_embeddings, axis1) * np.linalg.norm(query_embedding)) # 获取相似度最高的top_k个索引 top_results np.argsort(cos_scores)[-top_k:][::-1] pointed_tools [] for idx in top_results: pointed_tools.append({ tool_info: self.tool_base[idx], # 原始工具定义 similarity_score: float(cos_scores[idx]) # 相似度得分可用于后续排序或阈值过滤 }) return pointed_tools # 初始化指针学习器 pointer_learner SimplePointerLearner(tool_knowledge_base)3.3 参数提取与任务执行指向工具后我们需要另一个模块通常也是一个小型语言模型或解析器来从用户查询中提取具体参数并执行调用。# 这里我们使用一个规则关键词提取的简化方法。在实际的PLATO中这部分通常由另一个微调过的LLM或语义解析器完成。 import re def extract_parameters_simple(tool_info, user_query): 一个简化的参数提取函数。实际应用需要更复杂的NLP模型。 params {} required_params tool_info[parameters] # 非常简单的关键词匹配仅为演示 for param_name, param_config in required_params.items(): # 这里可以根据param_config的‘description’进行更智能的匹配 # 例如对于‘location’我们查找城市名 if param_name location or param_name city or param_name departure or param_name destination: # 一个简单的城市名列表实际中应使用更全的地理库 city_pattern r(北京|上海|广州|深圳|杭州|成都) match re.search(city_pattern, user_query) if match: params[param_name] match.group(1) elif param_name date: date_pattern r(\d{4}年\d{1,2}月\d{1,2}日|下周一|下周五|明天) match re.search(date_pattern, user_query) if match: # 转换日期格式简化处理 params[param_name] 2023-10-27 # 假设一个固定日期 elif param_name district: district_pattern r(国贸|朝阳区|王府井|浦东) match re.search(district_pattern, user_query) if match: params[param_name] match.group(1) elif param_name cuisine: cuisine_pattern r(川菜|意大利菜|日料|火锅) match re.search(cuisine_pattern, user_query) if match: params[param_name] match.group(1) # 检查必填参数是否都已提取 for p in required_params: if p not in params: params[p] None # 或触发澄清对话 return params def execute_pointed_tool(point_result, user_query): 执行被指向的工具。 tool_info point_result[tool_info] tool_name tool_info[name] # 1. 提取参数 extracted_params extract_parameters_simple(tool_info, user_query) print(f 指向工具{tool_name}) print(f 提取参数{extracted_params}) # 2. 映射到实际的工具函数 tool_mapping { get_weather: mock_get_weather, search_restaurants: mock_search_restaurants, book_flight: mock_book_flight } if tool_name in tool_mapping: # 3. 执行调用这里传入提取的参数 # 注意需要处理参数缺失的情况实际应用中应有更完善的校验和交互 callable_params {k: v for k, v in extracted_params.items() if v is not None} result tool_mapping[tool_name](**callable_params) return result else: return {error: f工具 {tool_name} 未找到对应的执行函数。}3.4 组合任务规划器工作流引擎对于复杂任务我们需要一个简单的规划器来分解和排序子任务。class SimpleTaskPlanner: def __init__(self, pointer_learner): self.pointer pointer_learner def plan_and_execute(self, complex_query): 对复杂查询进行规划并执行。 print(f处理复杂查询{complex_query}) # 第一步尝试将复杂查询分解这里用简单的分句模拟实际应用需要LLM进行意图分解 # 例如“帮我查一下北京天气然后找找国贸附近的餐厅” sub_tasks self._decompose_query(complex_query) results [] context {} # 用于在子任务间传递上下文信息 for sub_query in sub_tasks: print(f\n规划子任务{sub_query}) # 第二步为每个子任务指向工具 pointed_tools self.pointer.point_to_tool(sub_query, top_k1) if not pointed_tools: print(f 警告未找到处理‘{sub_query}’的合适工具。) results.append({sub_task: sub_query, status: no_tool_found}) continue # 第三步执行子任务 # 这里可以加入更复杂的逻辑比如根据上一个任务的结果修改当前查询或参数 enriched_query self._enrich_query_with_context(sub_query, context) task_result execute_pointed_tool(pointed_tools[0], enriched_query) # 第四步保存结果并更新上下文例如将天气结果中的城市名传递给后续任务 results.append({sub_task: sub_query, result: task_result}) # 简单的上下文更新规则将结果中的关键信息存入context if isinstance(task_result, dict): context.update(task_result) return results def _decompose_query(self, query): 一个极其简单的查询分解器。真实系统需要基于LLM的意图识别。 # 用“然后”、“并且”、“还有”等词简单分割仅为演示 separators [然后, 并且, 还有, 再] for sep in separators: if sep in query: return [q.strip() for q in query.split(sep) if q.strip()] # 如果找不到分隔符则整个查询作为一个任务 return [query] def _enrich_query_with_context(self, query, context): 用之前任务的上下文信息丰富当前查询。 # 例如如果上一个任务查询了天气context里有‘location’:‘北京’ # 当前查询是“找找附近的餐厅”可以自动补充为“找找北京附近的餐厅” if location in context and 附近 in query: # 这是一个非常启发式的规则 return query.replace(附近, f{context[location]}附近) return query # 初始化并运行 planner SimpleTaskPlanner(pointer_learner) # 测试简单查询 print( 测试简单查询 ) user_input 北京今天天气如何 pointed pointer_learner.point_to_tool(user_input, top_k1) if pointed: result execute_pointed_tool(pointed[0], user_input) print(f最终结果{result}) # 测试复杂查询 print(\n\n 测试复杂查询任务规划) complex_input 帮我查一下北京天气然后找找国贸附近的川菜馆 final_results planner.plan_and_execute(complex_input) print(f\n所有子任务执行完毕汇总结果{final_results})通过以上代码我们搭建了一个具备PLATO核心思想——基于指针的工具指向与任务组合——的简易智能体原型。它展示了如何将开放性设计落地为可运行的代码。4. 关键挑战与实战避坑指南在实际项目中应用PLATO或类似架构时你会遇到一系列理论论文中不会提及的“坑”。以下是我从多个项目实践中总结出的核心挑战和应对策略。4.1 工具描述的“对齐”难题问题工具描述的质量直接决定了指针网络的性能。描述过于简略如“获取天气”模型无法区分get_weather和get_historical_weather描述过于冗长或使用内部术语模型又难以理解。更棘手的是不同开发者编写的工具描述风格迥异导致知识库“方言”混杂。解决方案制定严格的描述规范强制要求所有工具描述必须包含固定字段如功能一句简洁的自然语言、输入每个参数的名称、类型、描述、示例、是否必填、输出数据结构描述、错误码、使用场景示例。可以借鉴OpenAPI Specification的思路。使用描述模板提供标准化的模板让开发者填空而不是自由发挥。例如“本工具用于[功能]。需要提供[参数1]描述、[参数2]描述等参数。调用后将返回[输出描述]。典型用法是当用户想[场景]时。”引入描述质量评估与优化可以训练一个小型模型或设计一组规则对提交的工具描述进行自动评分提示开发者修改模糊、不完整或有歧义的地方。甚至可以利用LLM自动将简陋的描述扩写为更规范的版本。4.2 长尾工具与“冷启动”问题问题知识库中大部分调用集中在少数热门工具如搜索、计算器大量工具很少被用到。当用户请求涉及这些长尾工具时由于训练数据中相关样本极少指针网络可能无法准确指向它们。解决方案分层检索与重排序不要只依赖单一的语义相似度检索。可以采用“召回-重排”两阶段策略。第一阶段用快速的向量检索召回Top-N如50个相关工具第二阶段用一个更精细的、经过针对性训练的交叉编码器Cross-Encoder对召回结果进行重排序这个重排模型可以在少量长尾工具的正负例样本上微调从而提升其辨别能力。数据增强与合成为长尾工具人工构造或使用LLM合成高质量的查询工具配对数据。例如根据工具描述让GPT-4等模型生成多样化的、可能使用该工具的用户查询语句用于补充训练。元学习Meta-Learning思路在训练中引入“少样本学习”任务让模型学会从工具描述中快速学习如何使用一个新工具而不是仅仅记忆训练集中工具的使用模式。4.3 复杂任务分解的“规划幻觉”问题让模型自主分解复杂任务时它可能产生逻辑上可行但实际无法执行的“幻觉规划”。例如规划出一个需要工具A的输出作为工具B的输入但两个工具的数据格式根本不兼容的流程。解决方案强类型约束与接口验证在工具描述中明确输入输出的数据类型和结构如JSON Schema。在规划阶段或执行前加入一个“接口兼容性检查”步骤。规划器在组合任务时必须验证上游任务的输出模式是否匹配下游任务的输入模式要求。可执行性验证与回滚设计一个轻量级的模拟执行环境。在正式执行前先让规划器输出工作流然后由验证模块模拟运行一遍检查数据流是否通畅关键参数是否可能缺失。如果验证失败则触发规划修正或向用户请求澄清。人类在环Human-in-the-loop验证对于高风险或非常复杂的任务可以将模型生成的规划展示给用户确认后再执行。“这是我将为您执行的步骤1. 查询A2. 用A的结果查询B3. 整合结果。确认执行吗”这能有效防止灾难性错误。4.4 错误处理与鲁棒性问题工具调用可能失败网络超时、API限流、参数错误指针可能指错工具参数提取可能不完整。一个环节出错整个智能体流程就会崩溃。解决方案结构化错误码与重试策略要求所有工具返回结构化的错误信息。智能体需要根据错误类型如网络错误、参数无效、权限不足采取不同策略网络错误可指数退避重试参数无效则尝试重新提取或向用户澄清。指针置信度与备选方案指针网络应输出其选择的置信度分数。当Top-1工具的置信度低于某个阈值时不直接执行而是可以考虑1) 同时执行Top-2和Top-3工具对比结果2) 生成一个澄清问题向用户确认“您是想查询天气还是查询空气质量”。参数提取的交互式补全参数提取模块应能明确识别出缺失或模糊的参数。不要简单地赋默认值或静默失败而是生成一个自然语言问题向用户询问。例如用户说“订一张机票”模型应追问“请问您的出发城市和目的地是哪里以及出行日期是”5. 性能优化与进阶技巧当你的PLATO风格智能体基本跑通后下一步就是提升其性能和实用性。以下是一些进阶优化点。5.1 提升指向速度与精度向量数据库的选用对于大规模工具库1000使用专业的向量数据库如Milvus, Pinecone, Weaviate来存储和检索工具描述的嵌入向量比内存计算快几个数量级。它们支持高效的近似最近邻搜索ANN。混合检索策略结合语义向量检索和关键词BM25检索。有些工具的名称或关键参数是专有名词如内部系统函数名calculate_roi_2024_v2关键词检索可能更准。将两种检索结果融合如加权平均能有效提升召回率。查询重写Query Rewriting在将用户查询送入指针网络前先对其进行优化。例如利用LLM对模糊查询进行扩写或澄清。“帮我订票” - “请帮我查询并预订从用户所在城市到目的地的航班机票”。这能显著提升语义匹配的准确性。5.2 记忆与上下文管理真正的开放性智能体需要记忆。它应该记住本次对话中已经执行过的操作、获得的结果甚至在多次交互中了解用户的偏好。短期会话记忆在对话上下文中显式维护一个“已执行动作列表”和“已知事实列表”。例如[已调用get_weather(北京)结果为晴朗22度用户偏好川菜]。这能避免重复提问“您要查询哪个城市”和实现指代消解“那里的餐厅呢” - “北京的餐厅”。长期记忆与用户画像将跨对话的信息如用户常驻城市、常用服务存储到外部数据库或向量存储中形成简单的用户画像。在每次对话开始时将相关的长期记忆作为上下文注入让智能体更个性化。工具调用历史学习记录成功和失败的工具调用历史。这些数据可以用于持续优化指针网络和参数提取模型形成一个自我改进的闭环。5.3 与现有Agent框架的集成你不需要从头造轮子。可以将PLATO的核心思想集成到LangChain、AutoGen、Camel等流行框架中。在LangChain中实现你可以自定义一个PLATOToolkit类继承自BaseToolkit。它的get_tools方法不是返回固定的工具列表而是动态地根据当前查询通过你的指针学习器从知识库中检索并实例化出最相关的几个Tool对象。这样你就把一个静态的工具箱变成了一个动态的、开放的工具发现系统。作为Meta-Agent的规划模块在AutoGen这类多智能体框架中你可以将PLATO作为一个顶层的“规划智能体”Planner Agent。它负责接收用户请求通过指针学习分解任务、指向工具这些工具可能由其他专门的智能体封装然后协调其他智能体如代码执行智能体、API调用智能体去完成子任务。5.4 评估体系构建如何衡量你的开放智能体的好坏不能只看端到端任务成功率。指向准确率Pointing Accuracy在已知答案的测试集上评估模型将查询指向正确工具的比例。参数填充准确率Parameter Filling Accuracy在指向正确的前提下评估提取或生成的参数完全正确的比例。任务分解合理性Task Decomposition Rationality请人类评估员对模型生成的复杂任务分解计划进行评分判断其步骤是否逻辑连贯、可执行。新颖任务泛化能力Novel Task Generalization设计一组在训练集中完全未出现过的、由已知工具组合而成的新任务测试智能体能否成功完成。这是衡量“开放性”的黄金指标。构建一个具备真正开放性的智能体是一条充满挑战但回报巨大的道路。PLATO的“指针学习”范式为我们提供了一个清晰而有力的起点。它告诉我们与其追求一个无所不能的巨型模型不如精心设计一个善于“查找手册”和“组装乐高”的智能系统。从定义清晰的结构化工具描述开始到实现稳健的检索与指向机制再到处理复杂的任务流和异常情况每一步都需要将严谨的工程实践与灵活的AI能力相结合。我自己的体会是最大的难点往往不在算法本身而在于如何构建高质量、一致性的工具生态以及设计出能够优雅处理失败和不确定性的系统流程。这更像是在设计一种新的编程范式而不仅仅是调优一个模型。