news 2026/10/26 20:34:27

AI Agent架构深度拆解:Planner与Reflection闭环如何让Agent稳定干活

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI Agent架构深度拆解:Planner与Reflection闭环如何让Agent稳定干活

1. 为什么现在聊 Agent 架构,绕不开 Planner 和 Reflection

过去一年我断断续续搭过七八个不同形态的 Agent,从最早那种"给个大模型套个 while 循环"的玩具,到后来接了工具、接了记忆、接了多智能体协作的完整系统,踩的坑基本都集中在同一个地方:架构没想清楚,模型再强也白搭。很多人一上来就问"用哪个模型""提示词怎么写",但真正决定一个 Agent 能不能稳定干活的,是它内部那条从"想"到"做"再到"复盘"的闭环链路。这条链路里最核心的两个角色,就是Planner(规划器)和Reflection(反思器)。

这篇文章我想把 AI Agent 的架构从头到尾拆一遍,重点讲清楚 Planner 到 Reflection 这个完整闭环是怎么转起来的,中间穿插Function Calling、MCP这些当下绕不开的关键词,也会聊到 token 消耗、部署选型、常见翻车点这些实操层面的东西。适合两类人看:一类是刚接触 Agent、想知道"这东西到底怎么搭"的新手;另一类是已经能跑通 demo、但发现一上真实任务就各种崩的老手。我会尽量用大白话把原理讲透,同时给出可以直接抄的架构方案和参数思路。

先说结论性的判断:一个没有 Reflection 的 Agent,本质上只是个"一次性执行器";一个没有 Planner 的 Agent,本质上只是个"高级 if-else"。这两句话是我搭了这么多系统之后最深的体会,后面会一点点展开为什么。

2. Agent 架构全景:从输入到输出的完整链路

2.1 一个 Agent 到底由哪几块拼起来

很多人对 Agent 的理解停留在"大模型 + 工具调用",这其实只覆盖了架构的一半。一个能真正干活的 Agent,我习惯把它拆成六个模块:

  • Perception(感知层):负责接收用户输入、环境状态、工具返回结果。听起来简单,但多轮对话里"哪些历史该带、哪些该丢"就是个大问题。
  • Planner(规划层):把一个大目标拆成可执行的子任务序列,决定先做什么、后做什么、什么时候该停。
  • Memory(记忆层):短期记忆(当前任务的上下文)和长期记忆(跨会话的知识沉淀),两者存储策略完全不同。
  • Tool / Action(执行层):通过 Function Calling 或 MCP 调用外部能力,比如查数据库、调 API、操作浏览器。
  • Reflection(反思层):对执行结果做评估,判断是否达成目标,没达成就要决定"重试、换方案还是放弃"。
  • Orchestration(编排层):把上面这些串起来的主循环,控制整个流程的节奏和终止条件。

这六块里,Planner 和 Reflection 是最容易被忽略、但最影响成败的两块。感知和执行是"体力活",规划和反思才是"脑力活"。

2.2 为什么是"闭环"而不是"流水线"

流水线思维是:输入 → 规划 → 执行 → 输出,一条直线走到底。这种结构在简单任务上没问题,但一旦任务复杂,比如"帮我分析这份财报并生成一份 PPT",直线结构几乎必崩。原因很简单:执行过程中一定会出现预期外的结果,可能是工具报错,可能是模型理解偏了,可能是数据格式不对。流水线没有回头路,只能硬着头皮往下走,最后输出一堆垃圾。

闭环思维是:规划 → 执行 → 反思 → 回到规划(或执行)。Reflection 层发现结果不对,就把信息反馈给 Planner,让它重新规划。这个"回头"的能力,才是 Agent 和普通脚本的本质区别。我实测下来,加了 Reflection 闭环之后,同一个任务的成功率能从 40% 左右拉到 75% 以上,代价是 token 消耗大概翻倍——这个 trade-off 后面细说。

2.3 主流架构的三种形态对比

市面上常见的 Agent 架构,我大致归成三类,各有各的适用场景:

架构形态核心特征适用场景主要缺点
ReAct 式思考-行动-观察循环单步工具调用为主的任务缺乏全局规划,容易迷路
Plan-and-Execute先规划完整计划再执行步骤明确的多步任务计划一旦出错难以及时调整
Plan-Execute-Reflect规划执行反思三段闭环复杂、结果不确定的任务token 消耗高,实现复杂

我个人的经验是:别一上来就上最复杂的。如果你的任务就是"查个天气再告诉我",ReAct 足够了,硬套闭环纯属浪费。但如果是"帮我把这个项目的所有 TODO 整理成周报并发送",那 Plan-Execute-Reflect 几乎是唯一能稳定跑通的方案。

3. Planner 深度拆解:Agent 的"大脑"怎么规划

3.1 Planner 的核心职责与三种实现思路

Planner 要解决的核心问题是:给定一个模糊的目标,怎么产出一个可执行的步骤序列。这里有个关键认知——规划不是一次性的,好的 Planner 是"边做边规划"的。

实现思路上我见过三种:

第一种是纯提示词规划,直接让大模型输出一个 JSON 格式的任务列表。优点是实现简单,缺点是模型对任务复杂度的判断经常失准,要么拆得太粗(一步干不完),要么拆得太细(几十步根本跑不完)。

第二种是结构化规划 + 校验,让模型输出计划后,再用一层逻辑校验步骤的合理性,比如检查是否有循环依赖、是否每步都有明确的完成标准。这层校验可以用规则做,也可以再调一次模型做 critic。

第三种是动态规划,不预先产出完整计划,而是每执行一步就重新规划下一步。这种方式最灵活,但 token 消耗也最高,因为每次都要把完整上下文喂进去重新推理。

我一般推荐第二种,在可控性和灵活性之间平衡得比较好。

3.2 任务分解的粒度控制:一个被低估的难点

粒度控制是 Planner 最考验功力的地方。拆得太粗,执行层不知道从哪下手;拆得太细,步骤数量爆炸,token 直接烧穿。

我的经验法则是:每个子任务应该对应一次明确的工具调用或一次明确的模型推理。比如"查询用户订单"是一个合适的粒度,"打开系统"就太粗,"点击登录按钮"又太细。

具体怎么控制?我通常会在 Planner 的提示词里加几条硬约束:

  • 每个步骤必须能用一个动词开头描述(查询、计算、生成、发送)
  • 每个步骤必须说明输入是什么、输出是什么
  • 步骤总数控制在 3 到 10 步之间,超过 10 步说明任务本身需要再拆分
  • 每个步骤要有明确的"完成判据",否则 Reflection 层没法判断对错

这几条约束看起来简单,但实测能显著降低规划跑偏的概率。

3.3 Planner 提示词的关键结构

一个能用的 Planner 提示词,我一般会包含这几块:角色定义、可用工具清单、任务分解规则、输出格式约束、以及几个 few-shot 示例。这里给一个简化版的结构参考:

你是任务规划器。给定用户目标,你需要输出一个 JSON 格式的步骤列表。 可用工具: - search(query): 搜索信息 - calculate(expr): 计算表达式 - write_file(path, content): 写文件 规划规则: 1. 每步对应一次工具调用或一次推理 2. 步骤数控制在 3-10 步 3. 每步必须包含 step_id, action, input, expected_output 输出格式: {"steps": [{"step_id": 1, "action": "...", "input": "...", "expected_output": "..."}]}

注意最后那个expected_output字段,这是给 Reflection 层用的。没有它,反思层就失去了判断依据,只能靠模型"感觉"结果对不对,可靠性大打折扣。

3.4 规划失败的典型信号与应对

Planner 出问题通常有几个信号:步骤之间逻辑不连贯、出现重复步骤、步骤描述含糊("处理数据"这种)、或者步骤数明显不合理。遇到这些情况,我的处理方式是加一层"规划校验",让模型自己 review 一遍计划,或者用规则做基础检查。

还有一种更隐蔽的失败:计划看起来合理,但和实际工具能力不匹配。比如计划里写了"调用支付接口",但你的工具清单里根本没有这个能力。这种问题必须在规划阶段就拦住,否则执行到一半才发现,整个流程就废了。

4. Function Calling 与 MCP:Agent 的"手脚"怎么接

4.1 Function Calling 的本质与调用流程

Function Calling 说白了就是让模型输出一个结构化的"我要调用某个函数"的意图,然后由外部代码真正执行这个函数,再把结果喂回给模型。模型本身不执行任何东西,它只负责"决定调什么、传什么参数"。

完整流程是这样的:你把工具的定义(函数名、参数 schema、描述)一起发给模型 → 模型判断需要调用某个工具 → 返回一个结构化的调用请求 → 你的代码解析并执行 → 把执行结果作为一条新消息发回给模型 → 模型基于结果继续推理。

这里有个容易踩的坑:工具描述写得好不好,直接决定模型调得对不对。我见过太多人工具描述就写一句"查询数据",结果模型根本不知道该传什么参数。好的工具描述应该包含:这个工具干什么、什么场景下用、每个参数的含义和格式、返回什么。

4.2 MCP 是什么,为什么它正在成为标配

MCP(Model Context Protocol)是这两年火起来的一个协议标准,核心价值是把工具的定义和调用标准化。在 MCP 出现之前,每个 Agent 框架都有自己的工具接入方式,你为 A 框架写的工具,换到 B 框架就得重写。MCP 相当于给工具接入定了一套通用接口,工具提供方实现一次,所有支持 MCP 的客户端都能用。

从架构角度看,MCP 把系统分成了 MCP Server(提供工具能力)和 MCP Client(Agent 侧,负责调用)。这种解耦带来的好处很实在:工具可以独立部署、独立升级,Agent 侧只需要知道"有这么个工具"就行。

我实测下来,MCP 最大的价值不是技术上的,而是生态上的。现在各种现成的 MCP Server 越来越多,从浏览器自动化到数据库操作到设计软件接口,你不需要自己从零写工具了,接上就能用。这对快速搭原型帮助巨大。

4.3 没有 MCP 能不能开发 Agent

这个问题被问得很多,答案是:当然能,MCP 不是必需品。MCP 解决的是"工具复用和标准化"的问题,如果你的 Agent 只用两三个自己写的工具,完全没必要上 MCP,直接 Function Calling 就够了。

什么时候该上 MCP?我的判断标准是:工具数量超过 5 个、或者需要跨项目复用工具、或者团队里有人专门维护工具能力。这时候 MCP 的解耦优势才体现出来。小项目硬上 MCP,纯属给自己找麻烦,多一层协议就多一层调试成本。

4.4 工具选型的几个实操原则

选工具的时候我一般看三点:幂等性、可观测性、失败可恢复性。幂等的工具(比如查询)可以放心重试,非幂等的(比如发送消息、扣款)必须加去重逻辑。可观测性指的是工具执行要有日志,出问题能查。失败可恢复性指的是工具报错后,Agent 能不能拿到足够的信息去调整策略。

举个具体的例子:浏览器自动化工具(比如基于 Playwright 的那类)在 Agent 里用得特别多,但它的失败率也高——页面加载慢、元素找不到、弹窗干扰。我的做法是给这类工具加超时和重试,并且把失败原因结构化返回,让 Reflection 层能判断是"重试就行"还是"得换方案"。

5. Reflection 闭环:让 Agent 学会"自我纠错"

5.1 Reflection 到底在反思什么

Reflection 层要回答三个问题:做完了吗?做对了吗?没做对怎么办?

第一个问题是终止判断,判断当前任务是否达成目标。第二个问题是质量评估,判断结果是否符合预期。第三个问题是策略调整,决定下一步是重试、换方法还是上报失败。

这三个问题看起来简单,但实现起来每个都有坑。终止判断最容易出问题的是"假完成"——模型觉得做完了,其实没做完。质量评估最难的是"标准从哪来",没有明确的判据,模型只能瞎猜。策略调整最怕的是"死循环"——一直重试同一个失败的操作。

5.2 反思的三种触发时机

Reflection 不是每步都要做,那样 token 消耗扛不住。我一般设三种触发时机:

  • 步骤级反思:每个关键步骤执行完,快速判断结果是否合理。轻量,主要看格式和明显错误。
  • 阶段级反思:一组相关步骤做完,评估阶段性目标是否达成。中等重量,会重新审视计划。
  • 任务级反思:整个任务结束前,做最终质量检查。重量级,可能触发整体重规划。

这种分层设计的好处是,大部分时候只跑轻量的步骤级反思,只有真正出问题时才升级到重量级,token 消耗可控。

5.3 反思提示词的设计要点

反思提示词和规划提示词的设计思路完全不同。规划是"发散",反思是"收敛"。我一般会这样组织:

你是结果评估器。给定任务目标和实际执行结果,判断是否达成目标。 任务目标:{goal} 预期输出:{expected} 实际结果:{actual} 请输出: - 是否达成:是/否/部分达成 - 判断理由:具体说明 - 若未达成,问题出在:规划问题/执行问题/工具问题/信息不足 - 建议下一步:重试/换方案/补充信息/放弃

关键是最后那个"问题归类",它直接决定了后续怎么处理。规划问题就回 Planner,执行问题就重试当前步,工具问题就换工具,信息不足就去补信息。没有这个归类,反思就变成了"感觉不对",没法指导行动。

5.4 防止反思陷入死循环

死循环是 Reflection 最危险的失败模式。Agent 一直觉得没做对,一直重试,token 烧光也没结果。防死循环我一般设三道闸:

第一道是最大迭代次数,硬性限制整个任务的重试次数,比如 5 次。第二道是重复检测,如果连续两次反思给出的建议完全一样,强制跳出。第三道是降级策略,重试超过阈值后,不再追求完美,输出当前最好的结果并标注"未完全达成"。

这三道闸缺一不可。我早期有个项目就是因为没设迭代上限,一个任务跑了上百次调用,账单出来的时候人都傻了。

6. 完整闭环的实操搭建:从零到能跑

6.1 整体流程编排

把前面几块拼起来,一个完整的闭环流程是这样的:

  1. 接收用户目标,进入 Planner
  2. Planner 产出步骤列表
  3. 取第一个未完成步骤,进入执行层
  4. 执行层通过 Function Calling 或 MCP 调用工具
  5. 结果进入 Reflection 做步骤级评估
  6. 评估通过则标记完成,取下一步;不通过则根据问题类型处理
  7. 所有步骤完成后,进入任务级反思
  8. 任务级反思通过则输出结果,不通过则回到 Planner 重规划
  9. 达到迭代上限则强制输出

这个流程的核心是两个循环:内层是步骤循环,外层是任务循环。内层处理单步问题,外层处理整体问题。

6.2 状态管理:闭环的"记忆"

闭环能转起来的前提是状态管理做得好。每一步的执行结果、反思结论、当前进度,都得存下来,否则反思层拿不到上下文,规划层也不知道做到哪了。

我一般用一个结构化的状态对象来管理,大致长这样:

{ "goal": "用户原始目标", "plan": [{"step_id": 1, "action": "...", "status": "done"}], "current_step": 2, "history": [{"step_id": 1, "result": "...", "reflection": "..."}], "iteration": 1, "max_iteration": 5 }

这个状态对象在每一轮循环里被读取和更新,是整个闭环的"中枢神经"。设计得好,调试起来一目了然;设计得烂,出了问题根本不知道哪一步错了。

6.3 关键参数的选择与计算

几个关键参数我一般这么定:

最大迭代次数:根据任务复杂度和成本容忍度定。简单任务 3 次,复杂任务 5-8 次。超过 8 次基本说明任务本身有问题,该拆分了。

上下文窗口分配:这是最容易被忽略的。一个闭环 Agent 的上下文里塞着系统提示、工具定义、历史步骤、反思记录,很容易爆。我的分配原则是:系统提示和工具定义占 20%,最近 3 步的详细历史占 40%,更早的历史做摘要压缩占 20%,留 20% 给当前推理。

token 预算估算:假设单次调用平均消耗 3000 token,一个 5 步任务加上反思,大概要 15-20 次调用,总消耗 5 万 token 左右。如果用了多轮反思,翻倍很正常。这个量级心里要有数,不然容易超预算。

6.4 一个最小可运行示例的骨架

下面是一个极简的闭环骨架,用伪代码展示核心逻辑:

def run_agent(goal, max_iter=5): state = {"goal": goal, "iteration": 0} plan = planner(goal) while state["iteration"] < max_iter: for step in plan: result = execute(step) reflection = reflect_step(step, result) if not reflection["passed"]: plan = replan(goal, state, reflection) break state["history"].append({"step": step, "result": result}) else: final = reflect_task(goal, state) if final["passed"]: return final["output"] plan = replan(goal, state, final) state["iteration"] += 1 return {"status": "max_iter_reached", "partial": state["history"]}

这段代码不长,但把闭环的核心逻辑都包含了:规划、执行、反思、重规划、迭代控制。实际项目里每一块都会复杂得多,但骨架就是这个。

7. 常见问题与排查技巧实录

7.1 规划跑偏:Agent 做着做着就忘了目标

这是最高频的问题。表现是 Agent 执行了几步之后,做的事情和原始目标越来越远。根因通常是上下文里目标信息被稀释了。

我的解法是目标锚定:每一轮规划或反思时,都把原始目标放在提示词最显眼的位置,并且明确要求"检查当前计划是否仍然服务于原始目标"。另外,历史步骤做摘要时,一定要保留和目标相关的关键信息,别一股脑压缩掉。

7.2 工具调用失败:参数格式总是不对

模型生成的参数格式不对,是 Function Calling 的经典问题。解法有几个层次:一是把参数 schema 写清楚,类型、格式、示例都给全;二是在工具执行前加一层参数校验,格式不对就返回明确的错误信息让模型重试;三是给几个 few-shot 示例,让模型照着学。

我实测下来,给示例比讲规则管用得多。与其写一堆"参数必须是 ISO 8601 格式"的说明,不如直接给一个正确调用的例子。

7.3 反思失效:模型总说"做对了"但其实没做对

反思失效的根因通常是判据不明确。模型没有客观标准,只能凭感觉判断,自然倾向于说"对"。解法是把判据显式化:预期输出是什么、验收标准是什么、哪些情况算失败。判据越具体,反思越可靠。

另一个技巧是让反思层看到"反例"。在提示词里说明"以下情况应判定为失败",能显著提升反思的准确率。

7.4 token 消耗失控:账单比预期高好几倍

token 失控一般有三个来源:上下文太长、迭代次数太多、反思太频繁。对应的解法是:做上下文压缩、设迭代上限、反思分层。我一般会加一个 token 计数器,实时监控消耗,超过预算就触发降级。

7.5 常见问题速查表

问题现象可能根因排查方向解决思路
规划跑偏目标信息稀释检查上下文中的目标权重目标锚定 + 摘要保留关键信息
参数格式错schema 不清检查工具定义补示例 + 加参数校验
反思失效判据不明确检查反思提示词显式判据 + 反例说明
token 失控上下文/迭代过多统计各环节消耗压缩上下文 + 设上限 + 分层反思
死循环无终止条件检查迭代控制迭代上限 + 重复检测 + 降级

8. 部署与选型:把 Agent 跑起来

8.1 部署形态的选择

Agent 的部署形态主要看使用场景。个人用或者做原型,本地跑就行,简单直接。团队用或者要对外提供服务,就得上服务化部署,考虑并发、限流、日志这些。

服务化部署时有个坑要注意:Agent 的执行是长任务,不是普通的请求-响应。一个任务可能跑几十秒甚至几分钟,普通的 HTTP 超时根本扛不住。我的做法是把任务提交和结果获取拆开,提交后返回一个任务 ID,客户端轮询或者用长连接拿结果。

8.2 模型选型:不是越强越好

模型选型上,我的原则是按环节选模型。规划层和反思层需要强推理能力,用强模型;执行层的工具调用和简单推理,用轻量模型就够。这种混合策略能显著降成本,实测下来总成本能降一半左右,效果几乎没损失。

8.3 可观测性:没有日志的 Agent 等于黑盒

Agent 的可观测性比普通应用重要得多,因为它的决策过程是不透明的。我一般会记录:每一轮的输入输出、规划结果、反思结论、工具调用详情、token 消耗。这些日志在排查问题时是救命的。

有条件的话,把整个执行链路可视化出来,每一步的状态一目了然,调试效率能提升好几倍。

9. 我踩过的几个坑和一点个人体会

搭了这么多 Agent,有几个坑我印象特别深,分享出来给后来人省点时间。

第一个坑是过早追求架构完整。我最早搭 Agent 的时候,一上来就想把 Planner、Reflection、Memory 全做齐,结果每个模块都半成品,整体跑起来一塌糊涂。后来学乖了,先用最简单的 ReAct 跑通核心流程,再逐步加模块,每加一块都验证效果。架构是长出来的,不是设计出来的。

第二个坑是忽视失败路径。新手搭 Agent 只想着"成功路径怎么走",但真实场景里失败才是常态。工具会报错、模型会跑偏、数据会缺失。一个健壮的 Agent,失败路径的处理代码量往往比成功路径还多。我现在搭任何 Agent,第一件事就是设计失败处理。

第三个坑是反思层做太重。我一度把反思做得特别复杂,每步都深度评估,结果 token 消耗爆炸,速度还慢。后来改成分层反思,轻量为主、重量为辅,效果好多了。反思的目的是纠错,不是炫技。

最后一个体会是关于 MCP 的。MCP 确实好用,但别为了用而用。我见过有人为了"架构先进",把本来三个函数就能搞定的事情硬拆成 MCP Server,结果调试成本翻了好几倍。工具选型永远服务于目标,不是反过来。

如果你现在正准备搭自己的第一个 Agent,我的建议是:从 ReAct 起步,跑通一个真实任务,然后逐步加 Planner 和 Reflection,每加一块都对比效果。别急着上全套架构,先把闭环跑起来,剩下的都是优化。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 20:34:23

Flutter应用ITMS-91053报错解决:隐私清单声明与依赖链排查

1. 问题定位&#xff1a;ITMS-91053 到底在拦什么 第一次在提交构建版本时看到 ITMS-91053 这串报错&#xff0c;很多人的第一反应是“代码是不是写错了”。实际上这条邮件跟业务代码几乎没关系&#xff0c;它属于苹果在隐私合规层面的一道硬门槛。报错原文大意是&#xff1a;你…

作者头像 李华
网站建设 2026/10/26 20:33:36

校园跑腿系统开发:微信小程序与SpringBoot全栈实践

1. 项目概述&#xff1a;校园跑腿系统的现实意义与技术选型校园跑腿系统是近年来在高校场景中快速普及的O2O服务应用。作为计算机专业毕业设计的经典选题&#xff0c;它完美融合了微信生态的便捷性与校园生活的实际需求。我去年指导过三个类似项目&#xff0c;发现这类系统最能…

作者头像 李华
网站建设 2026/10/26 20:33:31

微信小程序+SpringBoot校园跑腿系统设计与实现

1. 项目概述校园跑腿系统是近年来在高校中兴起的一种便捷服务模式&#xff0c;它通过移动互联网技术连接有需求的同学和可以提供服务的同学。基于微信小程序的校园跑腿系统设计&#xff0c;主要解决了以下几个实际问题&#xff1a;校园内短距离物品代取、快递代拿的需求紧急文件…

作者头像 李华
网站建设 2026/10/26 20:32:53

从仿真到上板验收:FPGA数字钟的时钟使能与工程化实现

简介&#xff1a;面向FPGA初学者与数字逻辑课程学习者的数字钟工程&#xff0c;以Verilog HDL实现计时、跑表、闹钟与时间调整等常见功能&#xff0c;可在Quartus II环境中完成编译、仿真与下载验证。压缩包共145个文件&#xff0c;约7.82MB&#xff0c;包含Verilog/VHDL源码、…

作者头像 李华
网站建设 2026/10/26 20:31:58

石油领域知识图谱构建与NLP技术实践

1. 石油领域知识图谱构建概述石油行业作为典型的数据密集型领域&#xff0c;每天产生海量的勘探报告、钻井日志、科研论文和工程文档。这些非结构化文本中蕴含着丰富的专业知识和行业经验&#xff0c;但传统的关键词检索和人工整理方式已经难以满足知识管理的需求。我们团队基于…

作者头像 李华
网站建设 2026/10/26 20:29:38

Python短视频内容理解与推荐系统开题与工程落地指南

简介&#xff1a;《Python短视频内容理解与推荐系统》开题报告是一份面向计算机、软件工程等专业毕业设计阶段的免费文档&#xff0c;适合选择推荐系统、深度学习与Web全栈方向、需要快速搭建开题框架的读者。文档围绕Python、Hadoop、Flask与Vue技术栈&#xff0c;梳理短视频内…

作者头像 李华