1. 项目概述当AI智能体遇上学术研究最近在折腾一个挺有意思的东西我把它叫做“PaperClaw”。这个名字听起来有点中二但内核很实在一个利用AI智能体Agents来自动化处理学术研究流程并且巧妙地将人类专家也就是我们自己纳入循环进行关键环节精炼的系统。简单说就是让AI去干那些繁琐、重复的文献调研、信息整理和初步分析工作然后把最需要人类智慧和判断力的部分——比如核心观点的提炼、研究方向的评估、论文质量的判断——留给我们来把关和深化。这玩意儿诞生的背景其实是我们这些常年泡在实验室、图书馆或者对着电脑屏幕看论文的人共同面临的一个痛点信息过载。每天都有海量的新论文发布在arXiv、PubMed、ACL Anthology等预印本或学术期刊网站上。即使只关注自己细分的小领域想跟上最新进展也需要花费大量时间在搜索、筛选、阅读摘要、甚至快速浏览全文上。这个过程极其消耗精力而且容易遗漏关键信息。更头疼的是当你需要为一个新课题做全面的文献综述时那种面对成百上千篇相关文献的无力感相信很多人都体会过。PaperClaw想解决的就是这个问题。它不是一个简单的文献管理工具也不是一个只会总结单篇论文的聊天机器人。它的核心是“智能体”Agent你可以把它理解为一个具备一定自主目标、能调用工具、并能根据环境反馈调整策略的AI程序。在PaperClaw的架构里多个智能体各司其职协同工作模拟了一个小型“研究助理团队”的作业流程。而“Human-in-the-Loop”人机协同循环则是它的灵魂确保最终输出的不是冷冰冰、可能出错的机器摘要而是经过人类智慧“淬火”的高质量知识结晶。无论你是研究生、科研人员还是任何需要深度处理大量文本信息的从业者这套思路和工具链都能显著提升你的信息处理效率和研究起点的高度。2. 核心架构与智能体分工设计PaperClaw的整个系统可以看作是一个由多个“智能体”组成的流水线。每个智能体负责一个特定的子任务它们通过共享的工作区和明确的任务指令进行协作。这里的关键在于智能体不是大语言模型LLM的简单调用而是被赋予了“使用工具”和“进行思考”的能力。下面我拆解一下我们设计的主要智能体角色及其工作流。2.1 调度与任务解析智能体Orchestrator Agent这是整个系统的“大脑”或“项目经理”。它的输入是用户一个相对模糊的研究需求比如“帮我调研一下2023年以来在蛋白质结构预测方面有哪些结合了扩散模型和传统物理方法的新工作并比较它们的优劣。”这个智能体的核心工作有三步需求澄清与任务分解它首先会与用户进行一轮或多轮简单的对话将模糊的需求转化为具体、可操作的研究问题。例如它会确认“您关注的蛋白质结构预测是指从氨基酸序列到3D坐标的从头预测如AlphaFold解决的问题还是指对接、构象变化预测等特定场景”“扩散模型具体指去噪扩散概率模型DDPM还是分数匹配模型SGM”“需要涵盖哪些顶级会议或期刊如Nature, Science, ICLR, NeurIPS” 这个过程确保了后续搜索的精准性。生成结构化搜索策略基于澄清后的需求它会生成一套结构化的搜索指令。这包括关键词组合生成多组布尔逻辑关键词如(diffusion model) AND (protein structure prediction) AND (physics-based)。数据库指定确定搜索的学术数据库如 arXiv, PubMed, Semantic Scholar, Google Scholar。时间与数量限制设定时间范围如2023-至今和初步获取的文献数量上限如200篇。任务分发与监控它将生成的具体搜索指令、筛选条件等打包成一个任务包分发给下游的“信息搜集智能体”并监控其执行状态。注意这个智能体的Prompt设计至关重要。我们赋予它的“人设”是一个经验丰富的科研项目负责人指令中必须强调“分步思考”、“主动提问澄清模糊点”、“输出结构化、可执行的计划”。避免它直接生成一个笼统的答案。2.2 信息搜集与初筛智能体Collector Filter Agent这个智能体是“跑腿小哥”和“初级筛选员”。它接收来自调度智能体的具体任务包。工具调用它被授权调用外部工具。核心工具包括学术搜索引擎API如通过arxiv.py库直接查询arXiv或使用Semantic Scholar、PubMed的API。网络爬虫工具对于没有友好API的网站在遵守robots.txt的前提下使用如requests-html或Scrapy框架进行定向抓取。执行搜索与获取元数据它根据策略执行搜索获取第一批文献的元数据包括标题、作者、摘要、发表年份、期刊/会议、DOI、arXiv ID、引用数等。基于规则的初筛它并非简单地全盘接收。我们为其设定了一些简单的硬性过滤规则Heuristic Rules例如过滤掉非英语论文。过滤掉明显不相关领域的论文通过分类号如arXiv的cs.LG代表机器学习q-bio.BM代表生物大分子。可以根据引用数设置一个阈值进行初步排序。输出初筛列表它将过滤后的文献列表例如50篇连同元数据整理成一个结构化的列表通常是JSON或Markdown表格传递给下一个环节。实操心得在这一步我们曾尝试让智能体直接基于摘要内容做相关性判断但发现效果不稳定且消耗大量Token。后来改为“规则过滤为主摘要判断为辅”的策略。先通过领域、关键词匹配等硬规则快速缩小范围再对边界案例让智能体快速浏览摘要判断。效率提升非常明显。2.3 深度分析与内容提取智能体Analyzer Agent这是流水线上的“核心分析师”。它的任务是处理经过初筛的文献列表进行深度阅读和信息提取。这是整个系统计算成本最高也最体现“智能”的环节。获取全文对于有开放获取链接如arXiv PDF的论文智能体会自动下载PDF文件。文档解析与分割使用如PyPDF2,pdfplumber或专门的学术PDF解析器如ScienceParse将PDF转换为结构化文本。然后根据章节如摘要、引言、方法、实验、结论对文本进行智能分割。这一步的质量直接决定了后续分析的准确性。结构化信息提取智能体被要求以固定的模板从每篇论文中提取关键信息。我们设计的模板包括研究问题本文要解决的核心科学或技术问题是什么核心方法提出了什么新方法或对现有方法做了什么关键改进要求尽量精炼避免照抄关键结果在哪些数据集上取得了什么主要性能指标如蛋白质结构预测的TM-score, GDT-TS创新点与局限作者自称的主要贡献是什么文中是否提到了该方法的局限性与其他工作的关系文中重点对比或引用了哪些相关研究本文工作是延续、改进还是挑战了它们生成初步综述与对比在分析完一批如10-20篇相关论文后这个智能体会尝试自动生成一个迷你综述段落概括该小方向的研究脉络并制作一个对比表格将不同论文的方法、数据集、结果列在一起。这个智能体的Prompt工程极其复杂。我们需要引导它进行“批判性阅读”而不是简单复述。指令中会包含“避免直接引用长句子”、“用你自己的话总结方法的核心思想”、“如果文中没有明确说明请根据实验设置推断其可能存在的局限”。2.4 人类协同精炼环节Human-in-the-Loop Refinement这是PaperClaw区别于全自动系统的关键也是质量保证的阀门。上述智能体生成的所有内容——从初筛列表、单篇论文总结到对比表格和迷你综述——都不会被当作最终产品直接输出给用户。交互式审核界面系统会提供一个简洁的界面可以是Web应用或本地GUI向用户展示分析结果。例如文献列表视图展示初筛后的论文用户可以快速标记“相关”、“不相关”、“待定”。摘要卡片视图每篇论文以卡片形式呈现智能体提取的结构化信息。用户可以在每个字段如“核心方法”、“局限”上进行直接编辑、补充或批注。对比表格视图用户可以调整表格行列修改或确认智能体填入的信息。人类反馈作为强化信号用户的每一次编辑、批注、确认或拒绝都会被系统记录下来。这些反馈有两个重要作用即时修正直接修正当前任务输出的错误确保最终交付物的准确性。模型微调积累的高质量反馈数据可以用来对底层的大语言模型进行监督微调SFT或者用于训练一个奖励模型RM来进行强化学习RLHF从而让智能体在未来的任务中表现更好减少同类错误。这就是“闭环”的意义。迭代式深化分析用户可能在看完成果后产生新的问题。例如“这几篇论文都说自己解决了X问题但它们的方法本质上有何不同”用户可以将这个问题直接输入系统。调度智能体会根据当前上下文已分析的论文生成一个新的分析子任务如“进行方法论的深度对比分析”派发给分析智能体。系统在此基础上生成新的内容再次交由用户审阅。这个过程可以循环多次直到用户满意。3. 关键技术选型与实现细节要实现PaperClaw技术栈的选择至关重要。它不是一个单一模型的应用而是一个涉及多个组件集成的系统。3.1 智能体框架的选择目前基于大语言模型的智能体框架如雨后春笋。我们的选型主要考虑以下几点开发灵活性、工具调用能力、记忆管理、成本以及社区活跃度。LangChain / LangGraph这是我们最终选择的核心框架。LangChain提供了丰富的组件Models, Prompts, Chains, Agents, Tools, Memory将大语言模型的能力模块化。特别是它的“智能体”Agent概念完美契合我们的设计。而LangGraph是建立在LangChain之上的用于构建有状态、多智能体工作流的库它用图Graph来定义智能体之间的交互流程非常直观。我们可以用LangGraph清晰地定义出“调度 - 收集 - 分析 - 等待人工审核 - 根据审核结果决定下一步”的循环图。AutoGen微软推出的多智能体对话框架。它的优势在于智能体之间可以通过自然语言对话进行协作更接近人类团队的讨论模式。对于需要复杂辩论、头脑风暴的研究场景可能更有优势。但它的流程控制相对LangGraph不够直观且对编程定义工作流的要求更高。考虑到我们初期需要更确定性的流水线暂时没有采用。自定义框架我们也评估过完全用OpenAI的API或开源模型如Llama 3, Qwen的Function Calling能力自己搭建一个轻量级框架。这提供了最大的灵活性但需要从头实现任务规划、工具调用、记忆管理等所有功能开发成本太高。我们的实现采用LangChain LangGraph作为智能体编排层。底层模型根据任务选择对创造性要求高的任务如任务分解、总结提炼使用GPT-4对成本敏感、逻辑性强的任务如信息提取、格式转换使用Claude 3 Haiku或GPT-3.5-Turbo。工具Tool则用Python函数封装如search_arxiv(query, max_results)download_pdf(url)parse_pdf_to_sections(file_path)等通过LangChain的tool装饰器暴露给智能体。3.2 文档处理与向量检索智能体需要“阅读”论文全文但大语言模型有上下文长度限制。我们不可能把一篇50页的PDF全文喂给模型。分块Chunking策略简单的按固定字符数分割会切断完整的句子或段落破坏语义。我们采用基于语义的分块递归字符分割先按“\n\n”等自然段落分隔符分割。重叠窗口在块与块之间保留一定重叠如200个字符确保上下文连贯。优先章节边界利用PDF解析出的章节标题优先在章节边界处进行分割。向量化与检索当智能体需要回答关于论文细节的问题时例如“这篇论文在实验部分用了什么评估指标”它不需要重新阅读全文。我们为每篇论文的文本块创建向量嵌入Embedding存入向量数据库如Chroma, Pinecone或本地FAISS。当有具体查询时先将查询语句向量化然后从数据库中检索出最相关的几个文本块连同问题一起交给大语言模型生成答案。这就是RAG检索增强生成技术的应用。元数据过滤在检索时可以结合元数据如章节标题是“Experiment”还是“Introduction”进行过滤让检索结果更精准。我们的实现使用Unstructured库或pdfplumber进行PDF解析使用LangChain的RecursiveCharacterTextSplitter进行分块。嵌入模型选用text-embedding-3-small效果好成本低向量数据库使用轻量级的Chroma在本地运行。3.3 提示工程Prompt Engineering设计智能体的“智商”和“性格”很大程度上由Prompt决定。我们的Prompt设计遵循几个原则角色扮演Role-playing给智能体明确的角色如“你是一位严谨的计算机科学博士后研究员”。链式思考Chain-of-Thought要求智能体在输出最终答案前先输出其思考步骤。例如“首先我需要理解用户的问题是... 其次我应该搜索哪些关键词... 然后我需要从结果中筛选...”。结构化输出Structured Output要求智能体以指定的格式如JSON、Markdown表格输出便于后续程序化处理。我们大量使用LangChain的PydanticOutputParser来定义输出数据结构并让模型严格遵守。上下文管理在Prompt中提供清晰的上下文包括当前任务目标、之前步骤的结果、可用的工具列表及其描述。示例分析智能体的Prompt核心部分你是一位专注的领域专家。你的任务是从给定的学术论文文本中提取关键信息。 请严格按照以下JSON格式输出不要添加任何额外解释。 { research_problem: 用一两句话概括本文要解决的核心问题。, core_methodology: 总结提出的方法避免直接复制公式说明其核心思想。, key_results: [在数据集A上取得了指标X值1, 在数据集B上取得了指标Y值2], claimed_contributions: [贡献点1, 贡献点2], perceived_limitations: 根据实验设置和讨论部分推断该方法可能存在的局限如果文中明确提到则直接总结。 } 请按以下步骤思考 1. 快速浏览全文确定文章所属领域和基本脉络。 2. 精读引言部分明确研究动机和待解决的问题。 3. 重点阅读方法部分理解其技术路线。 4. 查看实验部分记录主要实验设置和结果。 5. 阅读结论和讨论部分了解作者的自评和未来工作。 现在开始处理以下论文文本 [论文分割后的文本内容...]4. 系统搭建实操与核心代码解析理论讲完了我们来点实际的。搭建PaperClaw的原型你可以从以下几个核心模块入手。这里我分享一些简化版的代码思路和关键配置。4.1 环境准备与依赖安装首先创建一个干净的Python环境推荐3.9。核心依赖如下pip install langchain langchain-community langgraph langchain-openai pip install chromadb pypdf2 pdfplumber unstructured pip install arxiv requests beautifulsoup4如果你使用OpenAI的模型需要设置API密钥import os os.environ[OPENAI_API_KEY] your-api-key-here # 或者使用其他模型如Anthropic os.environ[ANTHROPIC_API_KEY] your-key4.2 定义智能体工具Tools工具是智能体感知和操作世界的“手”。我们先定义几个最基础的工具。from langchain.tools import tool import arxiv import requests import pdfplumber tool def search_arxiv(query: str, max_results: int 20) - list: 在arXiv上搜索学术论文。 Args: query: 搜索查询字符串。 max_results: 返回的最大结果数。 Returns: 一个字典列表包含论文的标题、摘要、arXiv ID等信息。 client arxiv.Client() search arxiv.Search( queryquery, max_resultsmax_results, sort_byarxiv.SortCriterion.SubmittedDate ) results [] for paper in client.results(search): results.append({ title: paper.title, summary: paper.summary, arxiv_id: paper.entry_id, published: paper.published, pdf_url: paper.pdf_url, primary_category: paper.primary_category }) return results tool def download_and_parse_pdf(pdf_url: str) - dict: 下载PDF并解析其文本和元数据。 Args: pdf_url: PDF文件的URL。 Returns: 包含文本内容和元数据的字典。 response requests.get(pdf_url) local_path ftemp_{pdf_url.split(/)[-1]} with open(local_path, wb) as f: f.write(response.content) full_text with pdfplumber.open(local_path) as pdf: for page in pdf.pages: full_text page.extract_text() \n # 简单的章节分割实际应用需要更复杂的逻辑 sections {} # 这里可以加入基于正则表达式的章节标题识别 # 例如 sections[abstract] extract_abstract(full_text) sections[full_text] full_text os.remove(local_path) # 清理临时文件 return {url: pdf_url, sections: sections}4.3 构建智能体与工作流使用LangGraph我们以“调度 - 搜索 - 分析”的简单线性流程为例。from langgraph.graph import StateGraph, END from typing import TypedDict, List, Annotated import operator # 1. 定义状态State class ResearchState(TypedDict): user_query: str clarified_query: str search_results: List[dict] analysis_results: List[dict] # LangGraph的注解用于并行处理 analysis_results: Annotated[List[dict], operator.add] # 2. 定义节点函数Nodes def orchestrator_node(state: ResearchState): 调度智能体澄清需求生成搜索指令 from langchain.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI llm ChatOpenAI(modelgpt-4, temperature0.1) prompt ChatPromptTemplate.from_messages([ (system, 你是一个研究项目负责人。你的任务是澄清用户的研究需求并将其转化为具体的搜索指令。), (human, 用户的需求是{query}\n\n请通过提问来澄清模糊点然后输出一个明确的搜索查询字符串。) ]) chain prompt | llm # 这里简化了实际应该是多轮对话。我们假设一次澄清成功。 clarified chain.invoke({query: state[user_query]}) # 提取clarified.content中的搜索指令 search_query extract_search_query(clarified.content) # 假设的提取函数 return {clarified_query: search_query} def collector_node(state: ResearchState): 收集智能体执行搜索 # 调用我们之前定义的 search_arxiv 工具 results search_arxiv.invoke({query: state[clarified_query], max_results: 10}) return {search_results: results} def analyzer_node(state: ResearchState): 分析智能体处理一篇论文 from langchain.output_parsers import PydanticOutputParser from pydantic import BaseModel, Field from langchain.prompts import PromptTemplate # 定义输出结构 class PaperAnalysis(BaseModel): research_problem: str Field(description研究问题) core_methodology: str Field(description核心方法) key_results: List[str] Field(description关键结果) parser PydanticOutputParser(pydantic_objectPaperAnalysis) format_instructions parser.get_format_instructions() prompt_template PromptTemplate( template你是一位专家。请分析以下论文摘要\n{abstract}\n\n{format_instructions}, input_variables[abstract], partial_variables{format_instructions: format_instructions} ) llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) chain prompt_template | llm | parser analysis_list [] for paper in state[search_results][:3]: # 假设只分析前3篇 try: analysis chain.invoke({abstract: paper[summary]}) analysis_list.append({ title: paper[title], analysis: analysis.dict() }) except Exception as e: print(f分析论文 {paper[title]} 时出错: {e}) analysis_list.append({ title: paper[title], analysis: {error: str(e)} }) # 注意返回的是要添加到state中的部分 return {analysis_results: analysis_list} # 3. 构建图Graph workflow StateGraph(ResearchState) # 添加节点 workflow.add_node(orchestrator, orchestrator_node) workflow.add_node(collector, collector_node) workflow.add_node(analyzer, analyzer_node) # 设置边定义流程 workflow.set_entry_point(orchestrator) workflow.add_edge(orchestrator, collector) workflow.add_edge(collector, analyzer) workflow.add_edge(analyzer, END) # 编译图 app workflow.compile() # 4. 运行工作流 initial_state {user_query: 扩散模型在蛋白质结构预测中的应用, search_results: [], analysis_results: []} final_state app.invoke(initial_state) print(final_state[analysis_results])这个例子非常简化但展示了LangGraph构建工作流的核心逻辑定义状态、定义节点函数、用边连接节点形成图。在实际的PaperClaw中图会更复杂可能包含条件边根据分析结果决定是否下载全文、并行边同时分析多篇论文以及引入人工审核的循环边。4.4 前端界面与人工交互为了让人类专家方便地介入一个简单的前端是必要的。对于原型我们可以用Gradio或Streamlit快速搭建。import streamlit as st import json st.title(PaperClaw - 文献分析审核台) if papers not in st.session_state: # 这里应该调用之前构建的LangGraph工作流获取初始分析结果 # st.session_state.papers run_research_workflow(user_query) st.session_state.papers [] # 假设这是从工作流获取的数据 for i, paper in enumerate(st.session_state.papers): with st.expander(f{i1}. {paper[title]}): col1, col2 st.columns(2) with col1: st.subheader(AI分析结果) st.json(paper[analysis]) # 显示AI提取的结构化信息 with col2: st.subheader(人工审核与修正) # 为每个字段提供可编辑的文本框 corrected_problem st.text_area(研究问题, valuepaper[analysis][research_problem], keyfprob_{i}) corrected_method st.text_area(核心方法, valuepaper[analysis][core_methodology], keyfmeth_{i}) # ... 其他字段 if st.button(确认修正, keyfbtn_{i}): # 更新session_state中的数据 paper[analysis][research_problem] corrected_problem paper[analysis][core_methodology] corrected_method st.success(已更新) # 这里可以将修正后的数据发送回后端用于模型微调或生成最终报告 if st.button(生成最终报告): # 汇总所有审核后的paper信息生成Markdown或Word报告 final_report generate_report(st.session_state.papers) st.download_button(下载报告, final_report, file_nameliterature_review.md)这个Streamlit应用提供了一个最基本的交互界面让用户可以查看、编辑AI的分析结果并最终导出报告。在实际系统中交互会更丰富比如支持高亮、批注PDF原文进行论文间的拖拽对比等。5. 避坑指南与效能优化在开发和实际使用PaperClaw这类系统的过程中我们踩过不少坑也总结出一些提升效能的经验。5.1 常见问题与解决方案问题可能原因解决方案智能体“胡言乱语”或偏离任务Prompt指令不清晰模型温度temperature设置过高上下文混乱。1.细化Prompt使用更明确的指令、分步思考Chain-of-Thought和结构化输出要求。2.降低温度对于事实性任务将temperature设为0或0.1。3.清理上下文确保传入模型的上下文是干净、相关的避免无关历史对话干扰。文档解析质量差PDF格式复杂双栏、公式、图表解析库选择不当。1.使用专业解析器尝试unstructured、pdfplumber或商业API如Adobe PDF Extract。2.后处理对解析出的文本进行清洗如去除页眉页脚、连续换行。3.OCR备用对于扫描版PDF集成Tesseract等OCR引擎。信息提取不准确模型对专业术语理解有限文本块过大丢失细节。1.提供领域上下文在Prompt中加入领域术语表或背景知识。2.优化分块尝试更小的块大小和更大的重叠窗口。3.采用“摘要-细节”两步法先让模型通读后写摘要再针对摘要中的关键点去原文中检索细节。API调用成本失控处理大量文献时频繁调用GPT-4等昂贵模型。1.模型分层轻量任务用便宜模型GPT-3.5-Turbo, Claude Haiku核心分析任务用强模型。2.缓存结果对相同的查询和文档将AI分析结果缓存起来避免重复计算。3.限流与批处理控制调用频率并将多个小任务合并为一个批次请求如果API支持。人工审核成为瓶颈界面不友好审核效率低AI错误太多导致人工工作量巨大。1.设计高效UI支持键盘快捷键、批量操作、差异高亮。2.提升AI准确率用前期的人工反馈数据对模型进行微调SFT形成正向循环。3.设置置信度阈值只将AI低置信度的结果提交人工审核高置信度的自动通过。5.2 性能与成本优化技巧异步处理文献搜索、PDF下载、向量数据库写入等I/O密集型操作使用异步编程asyncio可以极大提升吞吐量避免智能体在等待网络响应时“空转”。流式输出与渐进式分析对于长篇文献的分析不要等AI读完所有内容再输出。可以设计成流式Streaming输出让AI边读边总结或者先输出一个粗略框架再逐步填充细节。这能让用户更早看到进展并可能提前中断不相关的分析。本地模型与混合架构对于敏感数据或需要控制成本的情况可以考虑使用开源模型如Llama 3、Qwen、DeepSeek。将文档解析、信息检索等对“智力”要求不高的任务放在本地只将最核心的总结、对比、推理任务交给云端大模型。LangChain很好地支持这种混合架构。智能体“短路”机制不是所有任务都需要走完全部流程。例如如果搜索智能体发现某篇论文的标题和摘要与需求完全无关它可以立即将其标记为“不相关”并跳过后续分析节省资源。5.3 安全与伦理考量虽然我们的系统专注于学术研究但仍需注意数据隐私如果处理未公开的论文草稿或私有数据确保数据流在可信环境中避免通过不安全的API泄露。版权与合理使用大规模下载PDF可能违反某些数据库的服务条款。务必遵守robots.txt控制请求频率并仅将获取的内容用于个人研究分析。学术诚信PaperClaw是研究辅助工具其输出不能直接作为学术成果如文献综述部分发表。用户必须亲自审核、理解和整合AI生成的内容并对其最终产出的学术诚信负责。系统应在显著位置提示这一点。构建PaperClaw的过程是一个不断在“自动化潜力”和“人类掌控必要性”之间寻找平衡点的过程。最大的体会是最强大的系统不是要取代研究者而是成为研究者思维的延伸和能力的放大器。当你能将繁琐的信息收集和初步整理交给一个可靠的智能体系统你便能把宝贵的时间和认知资源集中在真正需要创造力和深度思考的问题上——比如提出新的研究假设、设计更巧妙的实验、或是从看似不相关的发现中建立新的连接。这个“人机协同”的循环才是科研工作未来该有的样子。