第12章 多模态与物理AI:让模型、工具和设备协同

本章技术主题: 多模态系统集成、设备端推理与安全接管。
本章技术实验: 先用回放材料连接图像、时序、语言说明和虚拟安全反馈。
家庭项目: 完成“打造一个AI阳台植物园”,再选择声音或手势互动、物品循环利用或“用AI改善一个自己的生活场景”。
跨章位置: 汇总第2、3、5章项目材料和全书测试方法,完成共同基线后才开展自主迁移。
技术主线: 多源感知 → 专用或多模态模型 → 协调程序 → 语言解释 → 安全动作 → 人工接管。

学习目标

完成本章学习后,你将能够:

  1. 为图像、声音和环境时序数据规定共同的时间、质量与结果接口,并解释它们如何形成多源证据。
  2. 区分原生多模态模型与多个专用模型串联的系统,说明语言模型、普通程序和人的不同责任。
  3. 根据数据、隐私、速度和设备条件选择云端、本地端或设备端运行位置,并完成H0、H1或H2路径中的一条。
  4. 沿完整链路测试输入失效、模型冲突、网络中断、输出编造和动作异常,设置安全动作与人的接管,并比较人工、规则、云端、本地端和不用AI的方案。

项目导入

本章的技术主题是多模态系统集成与物理AI。所有小组先完成共同基线“打造一个AI阳台植物园”,把任务从“识别一张叶片图像”扩展为“依据多源证据形成一份可核对的观察报告”。系统至少使用两种输入:植物图像,以及最近24小时的温度、空气湿度和土壤湿度记录;具备授权条件的小组还可加入一段短声音,由声音分类模型识别雨声、流水声或普通环境声。

图像模型描述可见外观,时序模型检查环境变化,声音模型提供可选事件线索,语言模型把已经结构化的证据组织成易读说明。系统只输出观察摘要和人工检查建议,不诊断植物问题,不自动浇水、施肥、开关高功率设备,也不把生成文字直接转换为控制指令。

本章的“应用中的AI”包括视觉、时序、声音和语言模型。它们各自处理规定输入,结果由普通协调程序检查时间、质量和权限。“开发与学习AI”协助学生设计接口、生成适配代码、分析日志和补写测试。学生决定数据是否可以采集、模型结果能否进入下一步、允许系统执行什么动作,并在模型冲突或证据不足时接管。

共同基线通过后,可任选“做一个会识别声音或手势的互动作品”或“建立家庭物品整理与循环利用助手”进行低风险迁移。前者只用短促非语音声音或不含人脸的手部动作切换虚拟页面、图标和提示;后者只对清洁、无危险的日常物品给出整理、再用或分类候选,并由人核对当地规则。两者都不进行身份识别,不自动操纵机械装置,也不把模型候选直接当作行动事实。

本章成果

考点提示

请重点区分:一个模型同时接收多种信息,称为模型层多模态;视觉、声音和时序专用模型由程序连接,属于系统层多模态;普通程序负责接口、规则和安全拦截;语言模型生成解释,不代表它拥有控制权限;物理AI的关键是感知、计算、行动与环境反馈的闭环,而不是给普通设备加上“智能”名称。

第一节 连接图像、声音、传感器和语言模型

一、先明确每种输入能证明什么

植物图像可以显示叶片颜色、斑点和形态,但一张照片不包含完整变化过程。环境时序记录可以显示温度和湿度何时变化,却不能单独确定叶片外观。声音能够提供雨声、流水等事件线索,但容易受到说话声、车辆声和距离影响。多源输入的价值在于相互补充,不是简单地让数据越多越好。

输入 主要模型或方法 输出示例 不能单独推出的结论
植物图像 视觉分类模型 发黄候选0.78 发黄的具体原因
24小时环境记录 时序异常模型或统计基线 土壤湿度持续下降 必须立即浇水
10秒声音片段 声音分类模型 雨声候选0.66 实际降雨量和土壤状态
文字问题与结构化证据 语言模型 观察摘要和待确认项 未出现在证据中的事实

采集前应明确最少输入。H0路径使用教师提供的样例图片和预录数据,不需要真实传感器。若增加声音,必须取得可能被录入人员的同意,限制录音时长,并在特征或分类结果生成后删除原始录音。不是完成任务所必需的数据就不采集。

声音或手势互动变体仍沿用“来源—采集时间—质量—候选—人工确认”接口。声音任务优先选择拍手、敲击等短促非语音类别,不采集对话,不做说话人识别或声音克隆;手势任务只裁取手部区域,不保存人脸和背景。识别结果只改变虚拟界面状态,误识别时可以立即撤销或改用键盘按钮。

二、给模型结果规定共同接口

不同模型不能只返回一句自然语言。每条结果至少包含来源、采集时间、标签或数值、分数、输入质量、模型版本和原始证据编号。例如视觉结果可写为“来源vision,标签yellow,分数0.78,质量ok,距当前3分钟”;时序结果可写为“来源environment,标签=soil_drop,分数0.82,质量ok,观察窗口24小时”。

统一接口使协调程序能够检查:必要来源是否齐全;证据是否过期;图像是否模糊;时序窗口是否缺记录;分数是否达到课堂设定的接受条件。模型版本也要记录,因为更新模型后,同一输入可能出现不同结果。

时间对齐非常重要。今天的叶片照片不能与一个月前的湿度记录拼成当前报告。声音事件也应有时间范围。若输入不同步,系统应并列展示而不是强行解释为同一原因。

三、区分两种多模态路线

原生多模态模型在同一个模型内部联合接收图像、文字、声音等输入,能够直接回答跨模态问题。多个专用模型串联系统则分别运行视觉、声音和时序模型,再由协调程序或语言模型组合结果。后者使用了多种模态,但不能因此宣称每个专用模型本身都是多模态模型。

比较项 原生多模态模型 多个专用模型串联
优点 跨模态提问自然、上下文统一 每个结果可单独测试、可替换、可离线
难点 内部推理较难分开核对 接口、时间对齐和错误传播更复杂
适用判断 需要联合理解且允许人工核验 需要明确分工、局部替换或设备端运行

本项目采用专用模型串联,便于复用前面章节成果。语言模型只能读取经过协调程序核验的结构化证据,并被要求区分“观察到”“模型候选”和“尚不能判断”。若它补写未提供的病因,输出必须被拒绝或重写。

第二节 完成云端、本地端与设备端的系统集成

一、把计算放在合适的位置

云端通常能提供较强的通用视觉和语言能力,但需要上传数据,受网络、费用和服务变化影响。本地端在普通计算机上运行协调程序和适合设备资源的模型,便于保护隐私、查看日志和离线工作。设备端靠近摄像头、麦克风或低压传感器,响应快、上传少,但算力、存储和电量有限,通常运行压缩后的小模型。

系统不必把所有模型放在同一位置。可以在设备端先计算声音类别和环境特征,只把结构化结果送到本地端;本地端完成时间对齐和安全检查;只有获得授权且确有必要时,才把最少证据交给云端语言模型生成说明。部署选择应记录原始数据去了哪里、保存多久、断网后怎样降级。

二、三级等价实践路径

路径 输入与运行条件 必做成果 动作边界
H0 仿真 样例图片、预录声音、环境数据文件 完成融合、虚拟动作—反馈、失败测试和判断 虚拟状态灯或屏幕显示,并回读显示状态
H1 共享设备 小组共享摄像头、麦克风或低压环境采集模块 比较实时输入与样例输入 只提示,不控制设备
H2 设备端拓展 把小型视觉、声音或时序模型放到边缘设备 测试延迟、断网、功耗和模型更新 仅低风险指示灯或显示器,保留物理停止

三条路径学习目标等价,没有硬件的学生使用H0也能完成本章。H0把“动作”限制为改变虚拟状态灯,并由程序回读实际状态;这样仍能观察“感知—计算—行动—环境反馈”的闭环及反馈失效。H1和H2增加的是采集与部署证据,不增加自动控制权限。设备端模型升级前要保留旧版本和固定回归样例,升级失败可以回退。

低风险迁移也使用三级路径。声音或手势互动的H0读取预录短声和裁剪后的手势图片,H1才读取经同意的实时片段;物品整理与循环利用助手的H0使用教师提供的清洁物品图片,H1可拍摄小组自带的安全物品。输出始终是虚拟分类卡和来源说明,破损电池、药品、化学品、尖锐物和其他危险废弃物不进入课堂采集,循环利用建议必须由人结合当地规定确认。

技术视野:MCP是一类让AI按统一描述连接外部工具的可选接口方法,本项目理解其用途即可,不把搭建协议基础设施作为学习要求。

三、用普通程序守住模型之间的边界

下面程序不训练模型,而是接收各专用模型已经生成的结果,检查必需来源、模型版本、采集时间、质量和时效,再形成允许交给语言模型的证据包。不同模型的分数含义不同,因此程序使用按来源设定并经过各自验证的阈值,不把视觉0.78与声音0.78当成可以直接比较的同一把尺子。程序还检查共同“是否需要复核”标志的冲突,并把动作限制为虚拟显示和状态回读。

from dataclasses import dataclass
from datetime import datetime
import json
import math


@dataclass(frozen=True)
class ModelResult:
    source: str
    label: str
    score: float
    score_kind: str
    quality: str
    captured_at: str
    evidence_id: str
    model_version: str


@dataclass(frozen=True)
class SourceRule:
    score_kind: str
    min_score: float
    max_age_minutes: int


# 这是课堂演示规则;正式阈值必须由各模型的封存数据分别验证。
SOURCE_RULES = {
    "vision": SourceRule("class_probability", 0.75, 15),
    "environment": SourceRule("anomaly_probability", 0.65, 60),
    "sound": SourceRule("class_probability", 0.65, 15),
}

# 协调程序只比较事先定义的共同任务标志,不凭标签名称猜含义。
REVIEW_FLAG = {
    ("vision", "normal"): "normal",
    ("vision", "yellow"): "review",
    ("vision", "spot"): "review",
    ("environment", "stable"): "normal",
    ("environment", "soil_drop"): "review",
}


def stop_packet(reason, details):
    return {
        "status": "stop",
        "reason": reason,
        "details": details,
        "allowed_action": "virtual_display_only",
    }


def build_evidence_packet(results, now):
    required_sources = {"vision", "environment"}
    sources = [result.source for result in results]
    duplicate_sources = sorted(
        {source for source in sources if sources.count(source) > 1})
    if duplicate_sources:
        return stop_packet("duplicate_source", duplicate_sources)

    evidence_ids = [result.evidence_id for result in results]
    duplicate_ids = sorted(
        {item for item in evidence_ids if evidence_ids.count(item) > 1})
    if duplicate_ids:
        return stop_packet("duplicate_evidence_id", duplicate_ids)

    unsupported = sorted(set(sources) - set(SOURCE_RULES))
    if unsupported:
        return stop_packet("unsupported_source", unsupported)

    by_source = {result.source: result for result in results}
    missing = sorted(required_sources - set(by_source))
    if missing:
        return stop_packet("missing_required_source", missing)

    validation_errors = []
    observed_times, ages = {}, {}
    for result in results:
        rule = SOURCE_RULES[result.source]
        if result.score_kind != rule.score_kind:
            validation_errors.append(
                f"{result.evidence_id}:score_kind_mismatch")
        if not math.isfinite(result.score) or not 0.0 <= result.score <= 1.0:
            validation_errors.append(f"{result.evidence_id}:invalid_score")
        if not result.model_version.strip():
            validation_errors.append(f"{result.evidence_id}:missing_model_version")
        if result.quality != "ok":
            validation_errors.append(f"{result.evidence_id}:invalid_quality")
        try:
            observed = datetime.fromisoformat(result.captured_at)
            if observed.tzinfo is None:
                raise ValueError("timezone required")
            age = (now - observed).total_seconds() / 60
            observed_times[result.evidence_id] = observed
            ages[result.evidence_id] = age
            if age < 0:
                validation_errors.append(f"{result.evidence_id}:future_time")
            elif age > rule.max_age_minutes:
                validation_errors.append(f"{result.evidence_id}:stale")
        except (TypeError, ValueError):
            validation_errors.append(f"{result.evidence_id}:invalid_time")
    if validation_errors:
        return stop_packet("invalid_evidence", validation_errors)

    uncertain = [
        result.evidence_id for result in results
        if result.score < SOURCE_RULES[result.source].min_score
    ]
    review_flags = {
        source: REVIEW_FLAG.get((source, by_source[source].label), "unknown")
        for source in required_sources
    }
    known_flags = {flag for flag in review_flags.values() if flag != "unknown"}
    conflicts = (
        ["vision_environment_review_flag_conflict"]
        if len(known_flags) > 1 else []
    )
    unknown_flags = [
        by_source[source].evidence_id
        for source, flag in review_flags.items() if flag == "unknown"
    ]
    alignment_minutes = (
        max(observed_times.values()) - min(observed_times.values())
    ).total_seconds() / 60

    facts = [
        {
            "source": result.source,
            "candidate": result.label,
            "score": round(result.score, 3),
            "score_kind": result.score_kind,
            "source_threshold": SOURCE_RULES[result.source].min_score,
            "captured_at": result.captured_at,
            "age_minutes": round(ages[result.evidence_id], 1),
            "evidence_id": result.evidence_id,
            "model_version": result.model_version,
        }
        for result in results
    ]
    review_reasons = []
    if uncertain:
        review_reasons.append("below_source_threshold")
    if conflicts:
        review_reasons.append("source_conflict")
    if unknown_flags:
        review_reasons.append("unmapped_review_flag")
    if alignment_minutes > 20:
        review_reasons.append("time_alignment_warning")
    return {
        "status": "needs_human_review" if review_reasons else "ready_for_summary",
        "facts": facts,
        "review_flags": review_flags,
        "time_alignment_minutes": round(alignment_minutes, 1),
        "uncertain_evidence": uncertain,
        "conflicts": conflicts,
        "unmapped_evidence": unknown_flags,
        "review_reasons": review_reasons,
        "language_instruction": (
            "只复述带证据编号的观察和候选结果;不得诊断原因,"
            "不得生成设备控制指令;列出需要人确认的项目。"
        ),
        "allowed_action": "virtual_display_only",
    }


@dataclass
class VirtualIndicator:
    state: str = "blank"
    fail_to_update: bool = False

    def apply(self, command):
        if not self.fail_to_update:
            self.state = command

    def read(self):
        return self.state


def run_h0_cycle(results, now, indicator):
    packet = build_evidence_packet(results, now)
    command = {
        "ready_for_summary": "show_ready_for_review",
        "needs_human_review": "show_attention",
        "stop": "show_stop",
    }[packet["status"]]
    indicator.apply(command)
    observed_state = indicator.read()
    feedback_ok = observed_state == command
    if not feedback_ok:
        packet = {
            **packet,
            "status": "stop",
            "reason": "display_feedback_mismatch",
            "allowed_action": "virtual_display_only",
        }
    return {
        "evidence_packet": packet,
        "issued_command": command,
        "observed_display": observed_state,
        "feedback_ok": feedback_ok,
    }


sample_results = [
    ModelResult("vision", "yellow", 0.78, "class_probability", "ok",
                "2026-05-18T09:02:00+08:00", "IMG-021", "vision-demo-1.2"),
    ModelResult("environment", "soil_drop", 0.82, "anomaly_probability", "ok",
                "2026-05-18T08:57:00+08:00", "ENV-024", "timeseries-demo-1.1"),
    ModelResult("sound", "rain", 0.66, "class_probability", "ok",
                "2026-05-18T09:00:00+08:00", "AUD-006", "audio-demo-1.0"),
]

now = datetime.fromisoformat("2026-05-18T09:05:00+08:00")
normal_cycle = run_h0_cycle(sample_results, now, VirtualIndicator())
feedback_fault = run_h0_cycle(
    sample_results, now, VirtualIndicator(fail_to_update=True))
print("正常闭环:")
print(json.dumps(normal_cycle, ensure_ascii=False, indent=2))
print("显示反馈故障:")
print(json.dumps(feedback_fault, ensure_ascii=False, indent=2))

这段代码本身不是新的AI模型,而是普通确定性协调程序。它要求图像和环境两类必要证据齐全,拒绝重复来源或证据编号、未知接口、错误分数类型、越界数值、空版本、未来时间、过期或质量异常输入。年龄由带时区的采集时间和当前时间计算,不能由上游手填一个“看起来新鲜”的分钟数。各来源的分数类型、最低分和最长时效写在独立规则中;这里的数值只是课堂演示,正式项目必须由各模型的封存数据决定。若多源采集时间相差超过20分钟,系统也转人工确认。

图像和环境标签先由明确映射转换为共同的review_flag;二者一方为normal、另一方为review时,程序只记录冲突并转人工,不让语言模型猜一个原因。这个共同标志是项目接口,不代表两类模型分数具有相同统计意义。声音是可选来源,因此声音缺失不阻断H0核心任务;一旦提供,也要接受自己的分数类型、质量、时效和阈值检查。

run_h0_cycle根据证据包发出虚拟显示命令,再回读状态。第二次运行故意让虚拟状态灯不更新,回读值与命令不一致时系统进入停止状态。这一小段补上了物理AI最基本的动作—反馈关系,同时没有把教材实验扩大为真实浇水或设备控制。学生还应把环境样例的标签改为stable,观察视觉review与环境normal怎样触发冲突路径。

程序生成的证据包可由语言模型整理,也可以在模型不可用时用固定模板直接显示。纸书不绑定具体服务;规划中的数字资源应为经过教师选择的模型提供独立适配器。适配器只能把证据包送入模型并取回文字,不能修改allowed_action。

第三节 测试失效链路、安全动作与人的接管

一、系统错误会沿链路传播

多模型系统的风险不仅是某个模型识别错误,还包括旧数据被当成新数据、字段含义不一致、网络重试产生重复结果、语言模型把候选写成事实,以及显示端隐藏停止状态。测试必须从输入一直追到最终输出。

故障注入 预期安全行为 不可接受行为
图像模糊或缺失 停止摘要,提示重新采集 沿用上次图像结果
环境记录超过时限 标记过期并停止融合 与当前照片强行组合
声音权限被拒绝 进入无声音的降级路径 反复请求或偷偷录音
两模型结果冲突 并列证据并转人工确认 由语言模型猜一个原因
网络中断 使用本地模板或只保存证据 重复发送、丢失原始记录
生成内容出现无证据病因 拒绝该段文字并保留日志 将文字转成控制动作

正常样例也要测试:图像、环境和声音时间一致、质量合格,系统能产生带证据编号的摘要。边界样例包括分数刚好接近阈值、短时缺一条记录和两个结果不一致。陌生样例包括非植物照片、训练外声音和超出数值范围的环境输入。故障样例包括模型不可用、字段改名、文件损坏和网络中断。

二、动作必须有权限分层

系统动作可分三层。第一层是保存证据和显示信息,可自动完成;第二层是生成提醒草稿,必须由人确认后发送;第三层是改变物理环境的动作,本项目一律禁止。语言模型无论文字多么肯定,都不能获得第三层权限。

普通程序维护动作白名单,语言模型只生成解释字段。H2拓展若连接低风险指示灯,也只允许显示“有待确认证据”,并提供物理关闭开关。水泵、加热器、门窗、电源和可能造成人身或财产风险的设备不在教材实验范围。

人的接管不能只写成一句“必要时人工处理”。界面要显示原始证据编号、各模型分数、采集时间、停止原因和可用按钮;接管者可以接受、驳回、重新采集或保持原状态。系统记录谁在何时确认了什么,但不记录与任务无关的个人信息。

三、形成系统级判断

判断系统是否可用,要分别检查组件和整体。组件测试回答视觉、声音、时序和语言模型各自表现怎样;接口测试回答字段、时间和错误状态能否正确传递;端到端测试回答从输入到显示是否保持来源和权限;恢复测试回答断网、重启和模型升级后能否回到安全状态。

还要比较云端、本地端和设备端方案。若结构化结果在本地模板中已经清楚,就没有必要为更流畅的表达上传原图。若设备资源不足,可降低采样频率或回到H0,不应删除安全检查换取速度。系统复杂度增加后,维护成本和失效点也会增加,多一个模型必须有可验证的收益。

最终判断卡至少写明:使用哪些输入;每个模型的边界;原始数据保存位置和删除方式;断网与模型失效时的降级路径;允许动作;人工接管者;模型或设备更新后的回归方法。只有当多源证据比单一输入稳定增加有用信息,并且隐私、安全和维护负担可以承担时,系统集成才有价值。

四、自主综合项目:用AI改善一个自己的生活场景

所有学生先用同一封存样例完成“打造一个AI阳台植物园”的H0基线,再开展自主项目。可直接选择“做一个会识别声音或手势的互动作品”“建立家庭物品整理与循环利用助手”,也可提出同等低风险的学习、兴趣或生活场景。健康咨询、用药、急症判断等健康场景不作为自由项目;涉及支付、门锁、交通控制、高功率设备或人身安全的自动动作也不在范围内。

第一步填写任务画布,而不是先让模型生成整套程序。画布至少写明:要改善的具体问题;使用者;最小输入和输出;哪些内容由人确认;哪些用普通规则;是否需要模型;云端、本地端或设备端位置;数据授权与删除;允许动作和停止条件;一个最小成功样例。开发与学习AI可以追问缺失条件并分段生成代码,学生必须逐段说明输入、输出、失败行为和自己作出的决定。

第二步只实现最小系统。系统图中的每个方框必须对应真实文件或明确组件,不能画一张与作品无关的理想流程图。例如:input/sample.jpg对应采集输入,src/vision_adapter.py对应模型适配,evidence/vision.json对应结构化候选,src/coordinator.py对应规则与权限,output/report.md对应界面输出,tests/cases.json和evidence/regression.md对应固定测试与结果。学生应从一次输入沿编号追到最终输出,证明图、文件和实际运行一致。

第三步比较五种路线:完全由人完成、普通规则程序、云端模型、本地模型以及不用AI。比较项至少包括效果证据、隐私、响应速度、费用、维护、断网行为和错误后果。若人工或规则已经稳定完成任务,模型没有带来可验证收益,就应缩小模型责任或不用AI;“最后没有采用AI”可以是合格结论,但必须有比较记录。

第四步封存正常、边界、陌生和故障四类固定样例。声音或手势作品应测试背景噪声、相似手势、无目标输入和模型缺失;物品助手应测试常见清洁物品、遮挡、训练外物品和规则文件损坏。每类测试写明输入、预期输出、停止位置、界面提示和日志,修改后用相同样例回归。最终提交最小系统、真实文件对应图、路线比较表、测试记录和采用、限用或不采用判断。

本章小结

多模态系统把图像、声音、时序和语言等不同信息连接起来。原生多模态模型在一个模型内联合处理多种输入,多个专用模型串联则依靠统一接口和协调程序组合结果。云端、本地端和设备端各有数据、能力与成本取舍,H0、H1、H2提供等价学习路径。全班以“打造一个AI阳台植物园”为共同基线,再把接口和测试方法迁移到声音或手势互动、家庭物品整理与循环利用等低风险场景。物理AI强调感知、计算、行动和环境反馈;H0用虚拟显示和状态回读建立低风险闭环,H1、H2也只允许提示与人工确认。可靠系统必须让真实文件对应系统图,比较人工、规则、云端、本地端与不用AI的路线,测试整条失效链路,并允许最终决定不采用AI。

关键术语

目标测试

一、单项选择题

  1. 下列哪一项属于系统层多模态? A. 单一视觉模型只处理图片 B. 视觉、声音和时序专用模型由协调程序连接 C. 普通表格求平均 D. 只显示固定文字
  2. 为什么模型结果需要采集时间和质量字段? A. 便于更换颜色 B. 检查证据是否过期或不可用 C. 增加模型参数 D. 代替人工授权
  3. H0路径的主要特点是什么? A. 必须购买设备 B. 使用样例和预录数据完成全部核心学习 C. 自动控制水泵 D. 跳过失效测试
  4. 语言模型在本章系统中可以执行哪一项? A. 根据结构化证据生成待核对摘要 B. 绕过动作白名单 C. 自动控制高功率设备 D. 修改原始采集时间

二、判断并改错

  1. 判断并改错:“连接了视觉、声音和时序三个专用模型,就说明其中每个模型都是原生多模态模型。”
  2. 判断并改错:“语言模型生成的解释很肯定时,可以直接把它转换成物理控制指令。”

三、简答与操作题

  1. 说明视觉、环境时序和声音输入在AI阳台植物园中分别能提供什么证据,以及各自不能单独证明什么。
  2. 比较云端、本地端和设备端,分别写出一项优势、一项限制和适合放置的组件。
  3. 设计一个“环境数据过期”的端到端故障测试,写出输入、预期停止位置、界面提示和需要保留的日志。
  4. 从“做一个会识别声音或手势的互动作品”或“建立家庭物品整理与循环利用助手”中选择一个,写出最小任务画布、至少四个真实文件或组件的对应关系、人工/规则/云端/本地端/不用AI的比较重点,以及四类固定测试。说明在什么证据下可以最终不采用AI。