青岛网站建设服务公司自由贸易区的建设网站
青岛网站建设服务公司,自由贸易区的建设网站,网站建设费用英文,鹿泉区城乡建设局网站智能体被定义为任何能够通过传感器#xff08;Sensors#xff09;感知其所处环境#xff08;Environment#xff09;#xff0c;并自主地通过执行器#xff08;Actuators#xff09;采取行动#xff08;Action#xff09;以达成特定目标的实体。Workflow 是让 AI 按部…智能体被定义为任何能够通过传感器Sensors感知其所处环境Environment并自主地通过执行器Actuators采取行动Action以达成特定目标的实体。Workflow 是让 AI 按部就班地执行指令而 Agent 则是赋予 AI 自由度去自主达成目标。智能体工作流程LM驱动的智能体通过一个由多个模块协同工作的、持续迭代的闭环流程来完成任务。感知 (Perception)流程始于感知模块 (Perception Module)。它通过传感器从外部环境 (Environment)接收原始输入形成观察 (Observation)。这些观察信息如用户指令、API返回的数据或环境状态的变化是智能体决策的起点处理后将被传递给思考阶段。思考 (Thought)这是智能体的认知核心对应图中的规划模块 (Planning Module)和大型语言模型 (LLM)的协同工作。规划与分解首先规划模块接收观察信息进行高级策略制定。它通过反思 (Reflection)和自我批判 (Self-criticism)等机制将宏观目标分解为更具体、可执行的步骤。推理与决策随后作为中枢的LLM接收来自规划模块的指令并与记忆模块 (Memory)交互以整合历史信息。LLM进行深度推理最终决策出下一步要执行的具体操作这通常表现为一个工具调用 (Tool Call)。行动 (Action)决策完成后便进入行动阶段由执行模块 (Execution Module)负责。LLM生成的工具调用指令被发送到执行模块。该模块解析指令从工具箱 (Tool Use)中选择并调用合适的工具如代码执行器、搜索引擎、API等来与环境交互或执行任务。这个与环境的实际交互就是智能体的行动 (Action)。观察 (Observation)与循环 行动会改变环境的状态并产生结果。工具执行后会返回一个工具结果 (Tool Result)给LLM这构成了对行动效果的直接反馈。同时智能体的行动改变了环境从而产生了一个全新的环境状态。这个“工具结果”和“新的环境状态”共同构成了一轮全新的观察 (Observation)。这个新的观察会被感知模块再次捕获同时LLM会根据行动结果更新记忆 (Memory Update)从而启动下一轮“感知-思考-行动”的循环。这种模块化的协同机制与持续的迭代循环构成了LLM驱动智能体解决复杂问题的核心工作流。智能体经典范式构建ReActReAct的巧妙之处在于它认识到思考与行动是相辅相成的。思考指导行动而行动的结果又反过来修正思考。为此ReAct范式通过一种特殊的提示工程来引导模型使其每一步的输出都遵循一个固定的轨迹Thought (思考)这是智能体的“内心独白”。它会分析当前情况、分解任务、制定下一步计划或者反思上一步的结果。Action (行动)这是智能体决定采取的具体动作通常是调用一个外部工具例如Search[华为最新款手机]。Observation (观察)这是执行Action后从外部工具返回的结果例如搜索结果的摘要或API的返回值。智能体将不断重复这个Thought - Action - Observation的循环将新的观察结果追加到历史记录中形成一个不断增长的上下文直到它在Thought中认为已经找到了最终答案然后输出结果。这个过程形成了一个强大的协同效应推理使得行动更具目的性而行动则为推理提供了事实依据。适用场景需要外部知识的任务如查询实时信息天气、新闻、股价、搜索专业领域的知识等。需要精确计算的任务将数学问题交给计算器工具避免LLM的计算错误。需要与API交互的任务如操作数据库、调用某个服务的API来完成特定功能。ReAct 的特点、局限性与调试技巧1ReAct 的主要特点高可解释性ReAct 最大的优点之一就是透明。通过Thought链我们可以清晰地看到智能体每一步的“心路历程”——它为什么会选择这个工具下一步又打算做什么。这对于理解、信任和调试智能体的行为至关重要。动态规划与纠错能力与一次性生成完整计划的范式不同ReAct 是“走一步看一步”。它根据每一步从外部世界获得的Observation来动态调整后续的Thought和Action。如果上一步的搜索结果不理想它可以在下一步中修正搜索词重新尝试。工具协同能力ReAct 范式天然地将大语言模型的推理能力与外部工具的执行能力结合起来。LLM 负责运筹帷幄规划和推理工具负责解决具体问题搜索、计算二者协同工作突破了单一 LLM 在知识时效性、计算准确性等方面的固有局限。2ReAct 的固有局限性对LLM自身能力的强依赖ReAct 流程的成功与否高度依赖于底层 LLM 的综合能力。如果 LLM 的逻辑推理能力、指令遵循能力或格式化输出能力不足就很容易在Thought环节产生错误的规划或者在Action环节生成不符合格式的指令导致整个流程中断。执行效率问题由于其循序渐进的特性完成一个任务通常需要多次调用 LLM。每一次调用都伴随着网络延迟和计算成本。对于需要很多步骤的复杂任务这种串行的“思考-行动”循环可能会导致较高的总耗时和费用。提示词的脆弱性整个机制的稳定运行建立在一个精心设计的提示词模板之上。模板中的任何微小变动甚至是用词的差异都可能影响 LLM 的行为。此外并非所有模型都能持续稳定地遵循预设的格式这增加了在实际应用中的不确定性。可能陷入局部最优步进式的决策模式意味着智能体缺乏一个全局的、长远的规划。它可能会因为眼前的Observation而选择一个看似正确但长远来看并非最优的路径甚至在某些情况下陷入“原地打转”的循环中。3调试技巧当你构建的 ReAct 智能体行为不符合预期时可以从以下几个方面入手进行调试检查完整的提示词在每次调用 LLM 之前将最终格式化好的、包含所有历史记录的完整提示词打印出来。这是追溯 LLM 决策源头的最直接方式。分析原始输出当输出解析失败时例如正则表达式没有匹配到Action务必将 LLM 返回的原始、未经处理的文本打印出来。这能帮助你判断是 LLM 没有遵循格式还是你的解析逻辑有误。验证工具的输入与输出检查智能体生成的tool_input是否是工具函数所期望的格式同时也要确保工具返回的observation格式是智能体可以理解和处理的。调整提示词中的示例 (Few-shot Prompting)如果模型频繁出错可以在提示词中加入一两个完整的“Thought-Action-Observation”成功案例通过示例来引导模型更好地遵循你的指令。尝试不同的模型或参数更换一个能力更强的模型或者调整temperature参数通常设为0以保证输出的确定性有时能直接解决问题。ReAct 智能体的编码实现(1)系统提示词设计提示词是整个 ReAct 机制的基石它为大语言模型提供了行动的操作指令。我们需要精心设计一个模板它将动态地插入可用工具、用户问题以及中间步骤的交互历史。# ReAct 提示词模板 REACT_PROMPT_TEMPLATE 请注意你是一个有能力调用外部工具的智能助手。 可用工具如下: {tools} 请严格按照以下格式进行回应: Thought: 你的思考过程用于分析问题、拆解任务和规划下一步行动。 Action: 你决定采取的行动必须是以下格式之一: - {{tool_name}}[{{tool_input}}]:调用一个可用工具。 - Finish[最终答案]:当你认为已经获得最终答案时。 - 当你收集到足够的信息能够回答用户的最终问题时你必须在Action:字段后使用 Finish[最终答案] 来输出最终答案。 现在请开始解决以下问题: Question: {question} History: {history} 这个模板定义了智能体与LLM之间交互的规范角色定义 “你是一个有能力调用外部工具的智能助手”设定了LLM的角色。工具清单 ({tools}) 告知LLM它有哪些可用的“手脚”。格式规约 (Thought/Action) 这是最重要的部分它强制LLM的输出具有结构性使我们能通过代码精确解析其意图。动态上下文 ({question}/{history}) 将用户的原始问题和不断累积的交互历史注入让LLM基于完整的上下文进行决策。(2)核心循环的实现ReActAgent的核心是一个循环它不断地“格式化提示词 - 调用LLM - 执行动作 - 整合结果”直到任务完成或达到最大步数限制。class ReActAgent: def __init__(self, llm_client: HelloAgentsLLM, tool_executor: ToolExecutor, max_steps: int 5): self.llm_client llm_client self.tool_executor tool_executor self.max_steps max_steps self.history [] def run(self, question: str): 运行ReAct智能体来回答一个问题。 self.history [] # 每次运行时重置历史记录 current_step 0 while current_step self.max_steps: current_step 1 print(f--- 第 {current_step} 步 ---) # 1. 格式化提示词 tools_desc self.tool_executor.getAvailableTools() history_str \n.join(self.history) prompt REACT_PROMPT_TEMPLATE.format( toolstools_desc, questionquestion, historyhistory_str ) # 2. 调用LLM进行思考 messages [{role: user, content: prompt}] response_text self.llm_client.think(messagesmessages) if not response_text: print(错误:LLM未能返回有效响应。) break # ... (后续的解析、执行、整合步骤)3输出解析器的实现LLM 返回的是纯文本我们需要从中精确地提取出Thought和Action。这是通过几个辅助解析函数完成的它们通常使用正则表达式来实现。# (这些方法是 ReActAgent 类的一部分) def _parse_output(self, text: str): 解析LLM的输出提取Thought和Action。 # Thought: 匹配到 Action: 或文本末尾 thought_match re.search(rThought:\s*(.*?)(?\nAction:|$), text, re.DOTALL) # Action: 匹配到文本末尾 action_match re.search(rAction:\s*(.*?)$, text, re.DOTALL) thought thought_match.group(1).strip() if thought_match else None action action_match.group(1).strip() if action_match else None return thought, action def _parse_action(self, action_text: str): 解析Action字符串提取工具名称和输入。 match re.match(r(\w)\[(.*)\], action_text, re.DOTALL) if match: return match.group(1), match.group(2) return None, None_parse_output 负责从LLM的完整响应中分离出Thought和Action两个主要部分。_parse_action 负责进一步解析Action字符串例如从Search[华为最新手机]中提取出工具名Search和工具输入华为最新手机。(4) 工具调用与执行# (这段逻辑在 run 方法的 while 循环内) # 3. 解析LLM的输出 thought, action self._parse_output(response_text) if thought: print(f思考: {thought}) if not action: print(警告:未能解析出有效的Action流程终止。) break # 4. 执行Action if action.startswith(Finish): # 如果是Finish指令提取最终答案并结束 final_answer re.match(rFinish\[(.*)\], action).group(1) print(f 最终答案: {final_answer}) return final_answer tool_name, tool_input self._parse_action(action) if not tool_name or not tool_input: # ... 处理无效Action格式 ... continue print(f 行动: {tool_name}[{tool_input}]) tool_function self.tool_executor.getTool(tool_name) if not tool_function: observation f错误:未找到名为 {tool_name} 的工具。 else: observation tool_function(tool_input) # 调用真实工具这段代码是Action的执行中心。它首先检查是否为Finish指令如果是则流程结束。否则它会通过tool_executor获取对应的工具函数并执行得到observation。(5观测结果的整合最后一步也是形成闭环的关键是将Action本身和工具执行后的Observation添加回历史记录中为下一轮循环提供新的上下文。# (这段逻辑紧随工具调用之后在 while 循环的末尾) print(f 观察: {observation}) # 将本轮的Action和Observation添加到历史记录中 self.history.append(fAction: {action}) self.history.append(fObservation: {observation}) # 循环结束 print(已达到最大步数流程终止。) return None通过将Observation追加到self.history智能体在下一轮生成提示词时就能“看到”上一步行动的结果并据此进行新一轮的思考和规划。plan-and-Solve与 ReAct 将思考和行动融合在每一步不同Plan-and-Solve 将整个流程解耦为两个核心阶段。规划阶段 (Planning Phase) 首先智能体会接收用户的完整问题。它的第一个任务不是直接去解决问题或调用工具而是将问题分解并制定出一个清晰、分步骤的行动计划。这个计划本身就是一次大语言模型的调用产物。执行阶段 (Solving Phase) 在获得完整的计划后智能体进入执行阶段。它会严格按照计划中的步骤逐一执行。每一步的执行都可能是一次独立的 LLM 调用或者是对上一步结果的加工处理直到计划中的所有步骤都完成最终得出答案。这种“先谋后动”的策略使得智能体在处理需要长远规划的复杂任务时能够保持更高的目标一致性避免在中间步骤中迷失方向。适用场景Plan-and-Solve 尤其适用于那些结构性强、可以被清晰分解的复杂任务例如多步数学应用题需要先列出计算步骤再逐一求解。需要整合多个信息源的报告撰写需要先规划好报告结构引言、数据来源A、数据来源B、总结再逐一填充内容。代码生成任务需要先构思好函数、类和模块的结构再逐一实现。Reflection基于低代码平台构建智能体应用快速原型验证、非技术用户: 优先选择 Coze企业级应用、复杂业务逻辑: 优先选择 Dify深度业务集成、自动化流程: 优先选择 n8n框架开发实践AutoGenAgentScopeLangGraph构建自己的Agent框架记忆与检索记忆系统让智能体拥有记忆为何智能体需要记忆与RAG对于基于LLM的智能体而言通常面临两个根本性局限对话状态的遗忘和内置知识的局限。1局限一无状态导致的对话遗忘当前的大语言模型虽然强大但设计上是无状态的。这意味着每一次用户请求或API调用都是一次独立的、无关联的计算。模型本身不会自动“记住”上一次对话的内容。这带来了几个问题上下文丢失在长对话中早期的重要信息可能会因为上下文窗口限制而丢失个性化缺失Agent无法记住用户的偏好、习惯或特定需求学习能力受限无法从过往的成功或失败经验中学习改进一致性问题在多轮对话中可能出现前后矛盾的回答2局限二模型内置知识的局限性除了遗忘对话历史LLM 的另一个核心局限在于其知识是静态的、有限的。这些知识完全来自于它的训练数据并因此带来一系列问题知识时效性大模型的训练数据有时间截止点无法获取最新信息专业领域知识通用模型在特定领域的深度知识可能不足事实准确性通过检索验证减少模型的幻觉问题可解释性提供信息来源增强回答的可信度四种记忆类型1工作记忆WorkingMemory工作记忆是记忆系统中最活跃的部分它负责存储当前对话会话中的临时信息。工作记忆的设计重点在于快速访问和自动清理这种设计确保了系统的响应速度和资源效率。工作记忆采用了纯内存存储方案配合TTLTime To Live机制进行自动清理。这种设计的优势在于访问速度极快但也意味着工作记忆的内容在系统重启后会丢失。这种特性正好符合工作记忆的定位存储临时的、易变的信息。工作记忆的检索采用了混合检索策略首先尝试使用TF-IDF向量化进行语义检索如果失败则回退到关键词匹配。这种设计确保了在各种环境下都能提供可靠的检索服务。评分算法结合了语义相似度、时间衰减和重要性权重最终得分公式为(相似度 × 时间衰减) × (0.8 重要性 × 0.4)。2情景记忆EpisodicMemory情景记忆负责存储具体的事件和经历它的设计重点在于保持事件的完整性和时间序列关系。情景记忆采用了SQLiteQdrant的混合存储方案SQLite负责结构化数据的存储和复杂查询Qdrant负责高效的向量检索。情景记忆的检索实现展现了复杂的多因素评分机制。它不仅考虑了语义相似度还加入了时间近因性的考量最终通过重要性权重进行调节。评分公式为(向量相似度 × 0.8 时间近因性 × 0.2) × (0.8 重要性 × 0.4)确保检索结果既语义相关又时间相关。3语义记忆SemanticMemory语义记忆是记忆系统中最复杂的部分它负责存储抽象的概念、规则和知识。语义记忆的设计重点在于知识的结构化表示和智能推理能力。语义记忆采用了Neo4j图数据库和Qdrant向量数据库的混合架构这种设计让系统既能进行快速的语义检索又能利用知识图谱进行复杂的关系推理。如何理解使用图数据库存抽象知识要理解 “语义记忆存储到图数据库Neo4j”首先要打破 “抽象知识” 和 “数据库存储结构” 的壁垒 ——语义记忆的 “抽象概念、规则、知识”本质上可以拆解为 “概念 概念间的关系 概念 / 关系的特征”而这正好完美匹配图数据库Neo4j的 “节点Node 关系Relationship 属性Property” 核心模型。举个最通俗的例子语义记忆中的知识“SQLite 是嵌入式关系型数据库支持 ACID 事务常用于移动端本地存储”映射到 Neo4j 中节点SQLite概念、嵌入式关系型数据库概念、ACID事务概念、移动端本地存储场景关系SQLite -[属于]- 嵌入式关系型数据库、SQLite -[支持]- ACID事务、SQLite -[应用于]- 移动端本地存储属性给SQLite节点加属性{体积:1MB, 部署方式:无服务, 合规性:ACID}。简单说图数据库把语义记忆中 “看不见的抽象知识”变成了 “可计算、可推理的结构化图结构”。语义记忆的评分公式为(向量相似度 × 0.7 图相似度 × 0.3) × (0.8 重要性 × 0.4)。这种设计的核心思想是向量检索权重0.7语义相似度是主要因素确保检索结果与查询语义相关图检索权重0.3关系推理作为补充发现概念间的隐含关联重要性权重范围[0.8, 1.2]避免重要性过度影响相似度排序保持检索的准确性4感知记忆PerceptualMemory感知记忆支持文本、图像、音频等多种模态的数据存储和检索。它采用了模态分离的存储策略为不同模态的数据创建独立的向量集合这种设计避免了维度不匹配的问题同时保证了检索的准确性。感知记忆的评分公式为(向量相似度 × 0.8 时间近因性 × 0.2) × (0.8 重要性 × 0.4)。感知记忆的评分机制还支持跨模态检索通过统一的向量空间实现文本、图像、音频等不同模态数据的语义对齐。当进行跨模态检索时系统会自动调整评分权重确保检索结果的多样性和准确性。此外感知记忆中的时间近因性计算采用了指数衰减模型RAG系统知识检索增强RAG的基础知识1什么是RAG检索增强生成Retrieval-Augmented GenerationRAG是一种结合了信息检索和文本生成的技术。它的核心思想是在生成回答之前先从外部知识库中检索相关信息然后将检索到的信息作为上下文提供给大语言模型从而生成更准确、更可靠的回答。因此检索增强生成可以拆分为三个词汇。检索是指从知识库中查询相关内容增强是将检索结果融入提示词辅助模型生成生成则输出兼具准确性与透明度的答案。2基本工作流程一个完整的RAG应用流程主要分为两大核心环节。在数据准备阶段系统通过数据提取、文本分割和向量化将外部知识构建成一个可检索的数据库。随后在应用阶段系统会响应用户的提问从数据库中检索相关信息将其注入Prompt并最终驱动大语言模型生成答案。3发展历程第一阶段朴素RAGNaive RAG, 2020-2021。这是RAG技术的萌芽阶段其流程直接而简单通常被称为“检索-读取”Retrieve-Read模式。检索方式主要依赖传统的关键词匹配算法如TF-IDF或BM25。这些方法计算词频和文档频率来评估相关性对字面匹配效果好但难以理解语义上的相似性。生成模式将检索到的文档内容不加处理地直接拼接到提示词的上下文中然后送给生成模型。第二阶段高级RAGAdvanced RAG, 2022-2023。随着向量数据库和文本嵌入技术的成熟RAG进入了快速发展阶段。研究者和开发者们在“检索”和“生成”的各个环节引入了大量优化技术。检索方式转向基于稠密嵌入Dense Embedding的语义检索。通过将文本转换为高维向量模型能够理解和匹配语义上的相似性而不仅仅是关键词。生成模式引入了很多优化技术例如查询重写文档分块重排序等。第三阶段模块化RAGModular RAG, 2023-至今。在高级RAG的基础上现代RAG系统进一步向着模块化、自动化和智能化的方向发展。系统的各个部分被设计成可插拔、可组合的独立模块以适应更多样化和复杂的应用场景。检索方式如混合检索多查询扩展假设性文档嵌入等。生成模式思维链推理自我反思与修正等。RAG系统工作原理数据处理流程处理和存储知识文档在这里我们采取工具Markitdown设计思路是将传入的一切外部知识源统一转化为Markdown格式进行处理。查询与生成流程根据查询检索相关信息并生成回答。RAG系统架构设计用户层RAGTool统一接口 ↓ 应用层智能问答、搜索、管理 ↓ 处理层文档解析、分块、向量化 ↓ 存储层向量数据库、文档存储 ↓ 基础层嵌入模型、LLM、数据库任意格式文档 → MarkItDown转换 → Markdown文本 → 智能分块 → 向量化 → 存储检索1多模态文档载入RAG系统的核心优势之一是其强大的多模态文档处理能力。系统使用MarkItDown作为统一的文档转换引擎支持几乎所有常见的文档格式。MarkItDown是微软开源的通用文档转换工具它是HelloAgents RAG系统的核心组件负责将任意格式的文档统一转换为结构化的Markdown文本。无论输入是PDF、Word、Excel、图片还是音频最终都会转换为标准的Markdown格式然后进入统一的分块、向量化和存储流程。2智能分块策略经过MarkItDown转换后所有文档都统一为标准的Markdown格式。这为后续的智能分块提供了结构化的基础。HelloAgents实现了专门针对Markdown格式的智能分块策略充分利用Markdown的结构化特性进行精确分割。Markdown结构感知的分块流程标准Markdown文本 → 标题层次解析 → 段落语义分割 → Token计算分块 → 重叠策略优化 → 向量化准备 ↓ ↓ ↓ ↓ ↓ ↓ 统一格式 #/##/### 语义边界 大小控制 信息连续性 嵌入向量 结构清晰 层次识别 完整性保证 检索优化 上下文保持 相似度匹配由于所有文档都已转换为Markdown格式系统可以利用Markdown的标题结构#、##、###等进行精确的语义分割。在Markdown段落分割的基础上系统进一步根据Token数量进行智能分块。由于输入已经是结构化的Markdown文本系统可以更精确地控制分块边界确保每个分块既适合向量化处理又保持Markdown结构的完整性。3统一嵌入与向量存储嵌入模型是RAG系统的核心它负责将文本转换为高维向量使得计算机能够理解和比较文本的语义相似性。RAG系统的检索能力很大程度上取决于嵌入模型的质量和向量存储的效率。高级检索策略RAG系统的检索能力是其核心竞争力。在实际应用中用户的查询表述与文档中的实际内容可能存在用词差异导致相关文档无法被检索到。为了解决这个问题HelloAgents实现了三种互补的高级检索策略多查询扩展MQE、假设文档嵌入HyDE和统一的扩展检索框架。1多查询扩展MQE多查询扩展Multi-Query Expansion是一种通过生成语义等价的多样化查询来提高检索召回率的技术。这种方法的核心洞察是同一个问题可以有多种不同的表述方式而不同的表述可能匹配到不同的相关文档。例如如何学习Python可以扩展为Python入门教程、Python学习方法、Python编程指南等多个查询。通过并行执行这些扩展查询并合并结果系统能够覆盖更广泛的相关文档避免因用词差异而遗漏重要信息。MQE的优势在于它能够自动理解用户查询的多种可能含义特别是对于模糊查询或专业术语查询效果显著。系统使用LLM生成扩展查询确保扩展的多样性和语义相关性2假设文档嵌入HyDE假设文档嵌入Hypothetical Document EmbeddingsHyDE是一种创新的检索技术它的核心思想是用答案找答案。传统的检索方法是用问题去匹配文档但问题和答案在语义空间中的分布往往存在差异——问题通常是疑问句而文档内容是陈述句。HyDE通过让LLM先生成一个假设性的答案段落然后用这个答案段落去检索真实文档从而缩小了查询和文档之间的语义鸿沟。这种方法的优势在于假设答案与真实答案在语义空间中更加接近因此能够更准确地匹配到相关文档。即使假设答案的内容不完全正确它所包含的关键术语、概念和表述风格也能有效引导检索系统找到正确的文档。特别是对于专业领域的查询HyDE能够生成包含领域术语的假设文档显著提升检索精度。3扩展检索框架HelloAgents将MQE和HyDE两种策略整合到统一的扩展检索框架中。系统通过enable_mqe和enable_hyde参数让用户可以根据具体场景选择启用哪些策略对于需要高召回率的场景可以同时启用两种策略对于性能敏感的场景可以只使用基础检索。扩展检索的核心机制是扩展-检索-合并三步流程。首先系统根据原始查询生成多个扩展查询包括MQE生成的多样化查询和HyDE生成的假设文档然后对每个扩展查询并行执行向量检索获取候选文档池最后通过去重和分数排序合并所有结果返回最相关的top-k文档。这种设计的巧妙之处在于它通过candidate_pool_multiplier参数默认为4扩大候选池确保有足够的候选文档进行筛选同时通过智能去重避免返回重复内容。