AI Agent 从技术原理到业务落地

📁 归档 · 学习日志📆 发布 · 2026-01-29🤯 作者 · PH 👀 35 次浏览

📖 参考文档: General Framework of AI Agents(字节 李航)

构建企业级RAG系统:从数据管道到智能客服的全链路架构演进

Introducing the Model Context Protocol

GitHub - anthropics/skills: Public repository for Agent Skills

Overview - Agent Skills

1. AI Agent 通用框架

1.1 核心观点

  • 设计 Agent 的目标是完成任务,它们以文本和多模态数据为输入和输出。对于硬件 Agent (机器人),它们还会生成物理动作数据。它们基于LLM进行“思考”,并通过强化学习构建,并在需要时利用工具和记忆模块。
  • 基于 LLM 是代理的核心,承担“思考”功能,其能力决定了 Agent 的智能水平。
  • Agent 框架与人类大脑的信息处理机制之间存在功能层次对应关系。
  • Agent 能够进行神经符号处理,并且应该为此类处理进行设计。
  • Agent 的未来研究方向包括:改进模型架构和训练方法、扩大数据量、开发自主连续学习技术,以及增强安全性和可控性。
  • 如果 Agent 强化学习的奖励函数范围超出任务完成的范畴,可能会带来重大风险,有必要为此设立研究和开发的底线。

1.2 Agent 具备的七大特征

  • Agent 是一个“理性行动的机器”,能够与环境(和其中的人类)交互从而完成任务,并且有指标来评估任务完成的质量
  • Agent 接受文本和多模态数据作为输入,并输出文本、多模态数据,以及物理动作数据。只有硬件 Agent (机器人)执行物理动作数据
  • Agent 的信息处理机制通过机器学习构建(特别是强化学习),当前强化学习是最有效的实现机器学习的方法。
  • Agent 使用 MLLM 作为其主要组成部分,这些模型通常需要进行预训练,然后用强化学习进一步 Fine-tuning。
  • LLM (MLLM的主要部分)是 Agent 的大脑,对其行为十分重要。在思考过程(规划、总结与反思)中,Agent 可以生成链式思维进行推理。
  • Agent 能够使用不同的工具与记忆,实现能力的扩展。工具可以是内置的,例如计算器,也可以是外部可访问的,例如搜索引擎。记忆可以包括长期记忆和工作记忆(短期记忆)。
  • 根据应用需求,Agent 拥有高或低自主权(独立作出决策和采取行动的能力),如自动驾驶和智能客服。
AI Agent 从技术原理到业务落地-BtoAI 波特埃

1.3 Agent 开源框架

  • AutoGPT:AutoGPT 是最早的一批基于 LLM 开发智能体的开源框架之一。给定一个任务,AutoGPT 尝试通过计划、执行和评估的迭代循环来完成目标。首先,它将任务分解为更小且可操作的子任务,然后依次使用外部工具(如网络搜索、文件输入输出和代码执行)来执行这些子任务。AutoGPT 保持一种形式的长期记忆,通常通过向量数据库实现,以存储中间结果和上下文信息。
  • LangChain:LangChain 是一个流行的软件开发框架,它使开发者能够构建完成复杂多步骤任务的系统和应用,如企业级问答、个人助手整合日历和电子邮件,或数据访问和分析工具。LangChain 提供了包括模型、提示、链、工具和记忆等功能。链允许将多个组件组合成管道或工作流,而 Agent 则会动态选择并调用搜索引擎、数据库、API 或代码执行等工具。记忆支持维护对话上下文和用户特定状态。
  • ReAct:ReAct 旨在通过将链式思考推理与与外部工具交互的动作交替进行来增强LLM。这种交替继续进行,直到任务得到解决。例如,在问答任务中,ReAct 通过与百科 API 的交互进行推理,减少了幻觉和错误传播,并且与之前的基线相比,生成了可解释的推理-行动步骤。
  • Reflexion:Reflexion 使 Agent 能够通过自我反思来提高性能。与静态执行计划不同,Reflexion 引入了一个迭代循环,在该循环中,执行者尝试完成一项任务,评估器确定任务的成功或失败(通常通过外部反馈),并且在失败时,反思者会生成关于任务失败原因及改进方法的文字洞察。这些反思被存储在记忆中,并被整合到未来的提示中,从而使代理能够避免重复过去的错误。
  • LATS:LATS 将蒙特卡洛树搜索适应于 LLM,并在此过程中集成推理、行动和反思。从初始任务开始,Agent 生成多个候选行动步骤,形成搜索树中的节点。这些节点通常会根据 LLM 进行自我反思来评估并产生一个标量值或批评。选择策略扩展高价值路径并剪枝低价值路径。该过程继续进行,直到达到计算预算为止,之后执行最高价值的路径。树搜索推理的结果可以存储在通用框架的记忆中。
  • Toolformer :Toolformer 是一种被训练来自主决定何时以及如何调用外部工具的 LLM,它通过在其生成的文本中直接发出API调用来实现这一目标。它能够访问一组固定的文本基础API,包括计算器、搜索引擎、问答系统、翻译系统和日历。Toolformer 的关键成分之一是其自我监督的训练程序。从一个文本数据集开始,模型被提示给出几例示例,以此来提议在可能受益于工具使用的位置的各种候选API调用。这些调用会在实际的工具上执行,只有那些在上下文中减少模型下个词预测损失的调用才会被保留。然后,模型在经过筛选和工具增强的数据集上进行微调,使其能够在没有手动标注的情况下学习有效的工具使用方法。
  • Voyager: Voyager 是为游戏 Minecraft 开发的一个 Agent,其最终目标是尽可能多地发现环境中的各种元素。Voyager 可以自主且持续地探索周围环境,获取新技能,并进行新颖的发现。它包含三个核心组件:用于开放式探索的自动课程、用于存储和调用技能的库,以及用于生成代码的迭代提示机制。Voyager 的高级规划和行动生成由其与 LLM 的交互驱动。工作流程如下:
    • 课程根据当前状态以及成功与失败的任务提出新任务,然后从技能库中搜索相关技能。
    • 如果没有找到适用技能,提示机制将利用 GPT-4 来生成可执行代码作为技能。
    • 如果执行失败,GPT-4 会根据错误反馈和环境观察再次进行提示,以迭代地完善代码。
    • 一旦任务成功完成,新的技能代码会被存档到技能库中。 总体而言,该 Agent 由用于规划(课程)和执行(提示)的 LLM 以及记忆(技能库)组成。
  • OS-Copilot: OS-Copilot 旨在作为个人电脑或智能手机的操作系统级别的用户助手。它的主要作用是帮助用户理解和控制整个系统中的任务,并自动化这些任务。它与操作系统内的文件、应用程序、设置、进程和服务进行交互。用户界面是自然语言,即用自然语言下达命令。OS-Copilot 框架由三个组件组成:一个计划者、一个配置器和一个执行者。
    • 计划者首先将用户的需求(任务)分解为一系列子任务,并从长期记忆和工作记忆中检索必要的工具和相关信息。
    • 然后创建一个计划并传递给配置器。配置器结合信息以创建执行指令。
    • 最后,执行者按照迭代执行者-批评者-改进者循环来执行这些行动:执行者执行行动,批评者评估结果并提供修复建议,改进者重写并重新执行失败的行动。 至关重要的是,整个框架支持持续的自我改进,因为成功的行动以及批评者的反馈会被存储在长期记忆中。
  • Gemini Robotics 1.5: Gemini Robotics 1.5 包含两个基础模型:一个具身推理(ER)模型和一个 VLA 模型。它们共同使机器人能够在现实世界环境中进行推理、规划和执行任务。ER 模型从 MLLM 微调而来的,作为系统的高层认知组件。它负责理解自然语言指令、推理物理空间,并将长周期任务分解为基本任务。它通过推断对象关系和随时间变化的因果关系进行空间和时间推理。在必要时,它也可以调用外部工具或函数。VLA 模型同样显然是从 MLLM 微调而来的,作为系统的低层感知和动作组件。它以视觉观察和语言指令为输入,将任务计划转化为机器人的运动和操作轨迹。该模型执行隐式多模态推理,以对齐感知、语言和控制。此外,VLA 模型展示了强大的跨具身泛化能力,使在一台机器人上学习的技能能够有效迁移到其他机器人上。

2. 企业 RAG Agent 搭建

2.1 数据管道

  • 观点:
    • 必须根治“垃圾进,垃圾出”。
    • 文档解析是首要挑战,不能简单粗暴地处理。
  • 实践与案例:使用LayoutLM等版面分析模型智能解析PDF,保留表格、章节等逻辑结构。为应对企业内SVN、Confluence等异构数据源,需定制适配器框架统一处理,并实现基于事件的增量更新,将索引构建时间从小时级降至分钟级。

2.2 分块策略

  • 观点:
    • 简单的“固定长度切分”是灾难,会破坏语义。
    • 分块这事儿没有银弹。我们试过按标题分、按段落分、按语义分,最后发现得看文档类型。
  • 实践与案例:采用语义切分(通过句子嵌入相似度判断边界)和父子索引(父块保上下文,子块做精准匹配)等策略。分块需根据文档类型(手册、博客、法规)灵活配置,甚至动态调整大小,以提升检索命中率。
  • 语义切分:先按句子做 Embedding,然后计算相邻句子的相似度。相似度高的说明在说同一件事,应该放在一起;相似度陡降的地方,就是话题切换的边界。这种方法听起来挺玄乎,但实际效果特别好。例如,同样是重置密码的文档,语义切分能完整保留 “找回密码→验证身份→重置成功” 这个流程,不会被拦腰砍断。
  • 父子索引:父块是大的语义单元,比如一个完整的章节;子块是细粒度的段落。检索的时候先用子块做精准匹配,找到相关段落后再把对应的父块拉进来补充上下文。这样既保证了召回率,又不失完整性。例如,用户问 “API 调用的鉴权方式”,可能只匹配到一个小段落讲 OAuth,但通过父子索引能把整个 “鉴权机制” 章节的背景信息都带进来,回答就更全面。

2.3 向量化与索引

  • 观点:通用嵌入模型在处理专业术语时可能不足,需权衡效果与实施成本。
  • 实践与案例:有条件的可以用领域数据微调专属Embedding模型以提升专业术语区分度。
    • 在向量数据库选型(如Milvus(数据大选)、Pinecone)
    • 索引构建上,可采用分层索引(热数据用HNSW求快,冷数据用IVF_FLAT省钱)
    • 量化压缩技术,把 Float32 改成 Float16,甚至 Int8,体积能小一半多,精度损失却不到 1

2.4 元数据治理

  • 观点:没有元数据的RAG系统如同没有标签的图书馆。这份文档从哪儿来、谁写的、最后修改时间是什么时候。
  • 实践与案例:必须为数据块建立包含来源、时效性、权威性分级、主题标签的元数据体系。这能实现问题追溯、自动过滤过期内容,并通过标签系统在检索时预先圈定范围,提升精度与可控性。
  • 权威性:可以把知识源分三级:一级是官方产品文档,绝对权威;二级是技术博客和最佳实践,仅供参考;三级是社区讨论,可信度最低。查询时优先从一级数据源里找,找不到再逐级往下。这样既保证了答案的可靠性,又不会错过有价值的补充信息。

2.5 检索层优化

  • 观点:单一的向量检索不够用,需结合传统方法,并让机器先“读懂”问题。
  • 实践与案例:
    • 混合检索:结合向量检索(擅长语义匹配)和BM25关键词检索(擅长精确匹配),并根据查询类型动态调整权重,兼顾灵活与准确。要动态维护别名词典。
    • 查询理解:在检索前增加查询改写与扩展层,使用轻量级LLM将口语化、指代不清的问题规范化,并扩展同义词,大幅提升检索输入质量。
    • “假设性文档嵌入”(HyDE):就是让模型先根据问题生成一个假设性的答案,然后用这个答案去做向量检索。这种方法在长尾问题上效果特别明显,因为生成的答案包含了更多可能的关键词和语义信息。不过代价是每次查询都要多花一次 LLM 调用的成本,我们会根据问题的复杂度动态决定是否启用这个策略,简单问题没必要,复杂问题才值得。
    • 重排序:在第一次检索后,用更精确的交叉编码器(Cross-Encoder)对 Top-N 结果重新打分。
    • 图增强检索(Graph RAG):向量检索再怎么优化,也有个天生的局限:它只能捕捉语义相似性,理解不了实体之间的复杂关系。GraphRAG 把知识库构建成一张图,节点是实体(人、项目、模块),边是关系(负责、属于、依赖)。检索的时候先解析问题里的实体,然后在图里做路径搜索。听起来很像传统的知识图谱,但不一样的是,GraphRAG 把图谱和大模型结合起来了,图谱负责精确的关系推理,模型负责理解自然语言和生成答案。

2.6 结构化提示词

  • CO-2W2H1R结构: C 是 Context,O 是 Objective,两个 W 分别是 What 和 Why,两个 H 是 How 和 How Good,R 是 Restriction。每个部分都有明确的作用,Context 给背景,Objective 定目标,What 讲要做什么,Why 解释原因,How 给方法,How Good 设标准,Restriction 加约束。
  • 拿金融客服场景来说,一个典型的 Prompt 可能是这样:Context 是用户问信用卡分期利息,检索回来的文档里有三条相关信息;Objective 是准确计算并解释利息规则;What 是给出具体数值和公式;Why 是让用户明白费用构成;How 是分步骤说明;How Good 是要求计算误差小于 0.01 元;Restriction 是严禁推荐具体产品、不能透露内部政策、遇到不确定要明确表示不知道。
  • 让模型 “显式思考”:在 Prompt 里加一句 “请一步一步思考,把推理过程写出来”,能极大提升复杂问题的准确率。
  • 安全护栏:比如 “如果问题涉及个人账户信息,请拒绝回答并引导用户联系客服”;”如果问题超出知识库范围,请明确表示不知道”。这些看似简单的约束,实际上构成了企业级应用的安全底线。没有这些,系统就是个定时炸弹,随时可能泄露敏感信息或给出越界建议。

2.7 上下文管理

通过“相关性+多样性”筛选、结构化组织、动态窗口等方法,在有限上下文窗口内实现信息效用最大化。

  • “相关性 + 多样性”:先从重排序结果里取 Top-K,尽量让来源分散。比如选 3 条来自官方文档,2 条来自最佳实践,1 条来自社区讨论。这样既保证了权威性,又提供了多角度参考。
  • 上下文组织:要给每块内容加上来源标注。格式一般是 “【来源:某某文档】内容…”。这样模型生成答案时,知道每句话的依据是什么,也方便后面做来源追溯。而且如果同一段内容在多个文档里出现,需要做合并,避免重复干扰。
  • 对于多轮对话上下文:只在当前问题依赖历史的时候才带。比如用户追问 “那它的性能怎么样”,这里的 “它” 指代上一轮的产品,这时候就需要把上一轮的上下文带进来。但如果用户问了个全新的问题,就清空历史,避免干扰。
  • 上下文压缩:有些研究用 LLM 把长文本摘要成短文本再放进去,或者提取关键句子,但发现效果不稳定,有时候会把关键细节压缩掉。所以现在用的是基于规则的压缩,比如去掉停用词、合并重复表述。虽然简单,但胜在可控。
  • “动态上下文窗口”:简单问题用 2K 窗口,复杂问题自动扩展到 8K 甚至 16K。判断标准是检索结果的相关性分布,如果 Top-5 的分数都很高且接近,说明问题复杂,需要更多上下文。这个策略能在效果和成本间动态平衡,简单问题不浪费 Token,复杂问题不缺信息。

2.8 风控与合规

风控体系可以分三层:生成前过滤、生成中约束、生成后审查。

  • 生成前过滤:比如发现包含银行卡号、身份证号就自动脱敏,用星号替换中间几位。敏感信息脱敏是个技术活儿。不能简单替换,要保证语义连贯。比如 “张三的卡号是 6222021234″,脱敏后用户知道这是卡号,但看不到完整信息。可以建敏感词库,正则表达式匹配,发现就处理。不过这个库需要持续更新,新类型的敏感信息不断出现,比如现在人脸信息、指纹信息也要脱敏。
  • 生成中约束就是前面说的 Prompt 限制,明确告诉模型什么能说什么不能说。(第6部分)
  • 生成后审查是用规则引擎和轻量级模型对输出再做一轮检查。规则引擎主要检查格式和关键词。比如金融行业要求收益类表述必须加 “历史业绩不代表未来表现” 的免责声明,如果模型生成的回答里忘了,规则引擎会自动补上。再比如检测到 “保证”、”承诺” 这类绝对化词汇,系统会自动替换成更谨慎的表达。这些规则看似死板,但在合规面前,死板比灵活重要。
  • 事实性核查是目前最难的部分。模型幻觉防不胜防,有时候看起来很有条理的回答,某个细节却是错的。推荐的做法是,对关键数据做二次验证。比如模型回答里提到 “利息是 3.5
  • 拒答机制:对于不确定的问题,模型应该说 “我不知道”,而不是瞎猜。但什么时候说 “不知道”,这个度很难把握。推荐的策略是,如果检索召回的相关性分数都低于某个阈值,或者 Top-3 结果差异很大,就触发拒答。同时 Prompt 里也会反复强调 “不确定就说不知道”,让模型养成 “保守” 的习惯。
  • 答案的可追溯性:每条回答下面都附带来源链接,用户可以自己点击查看原始文档。这不仅增加了可信度,也给了用户自主判断的空间。万一系统答错了,用户能快速发现。这个设计其实挺反常识的,好像暴露了自己的 “参考资料” 会降低权威性,但实际上用户更喜欢这种透明的方式,感觉更踏实。

2.9 系统与组件选型

推荐系统分成五个独立服务:数据摄入服务、索引构建服务、检索服务、生成服务、API 网关。 服务之间用消息队列通信,每个服务都可以独立升级、扩缩容。

  • 推理框架的选择也很重要。
    • vLLM 吞吐量最高,适合高并发场景;
    • TensorRT-LLM 延迟最低,但对模型格式有要求;
    • HuggingFace 最灵活,但性能一般。
    • 可以混合部署,简单查询用 vLLM,复杂任务用 TensorRT-LLM,动态路由。这种异构部署虽然复杂,但能把资源利用率最大化。
  • 缓存组件用 Redis,但缓存策略很有讲究:不仅缓存最终结果,还缓存中间过程的检索结果。比如用户问 “如何重置密码”,系统会先查向量数据库,这个结果可以缓存 15 分钟,因为知识库不会频繁变化。不过缓存失效策略要做好,一旦知识库更新,相关缓存要立即清除,否则就返回旧数据了。

2.10 性能与成本优化

除了缓存外,还有一些方式也可以节省成本同时提升体验。

  • 预生成答案池与知识自更新:把 Top 1000 个高频问题提前生成好答案,缓存起来。用户提问时,先用轻量级模型做语义匹配,如果在预生成池里找到了相似问题,直接返回缓存答案,不走完整 RAG 流程。需要定期更新。也可以让系统自动把高频问题汇总,生成文档改进建议,推送给技术写作团队。这样一来,知识库越用越完善,形成了正向循环。
  • 流式输出(Streaming)对用户体验的提升是革命性的。没做流式之前,用户点击查询后要等好几秒才能看到完整答案,体验很差。改成流式后,首 Token 响应时间降到 500ms 以内,用户感觉系统 “反应很快”,其实整体生成时间没变。实现流式不难,难的是怎么在前端优雅地展示,怎么处理 Markdown 格式的实时渲染。例如在前端实现虚拟打字机效果,一个字一个字往外蹦,实际用户反馈特别好。
  • 模型分级是最省钱的优化。发现 70
  • 批量处理(Batching)也能显著提升吞吐量。vLLM 本身就是动态批处理,但我们的检索服务也做了批量化改造。把多个用户的查询合并成一个批次,一次性做向量检索。因为向量数据库的 GPU 计算一次能处理多条 Query,批处理能把 GPU 利用率从 30
  • Token 压缩。我们让模型在输出时尽量简洁,Prompt 里明确要求 “简洁回答,避免冗余”。同时在后处理阶段,用规则去掉 “首先、其次、总之” 这类可有无的词。平均每个答案能节省 20

2.11 全链路监控

  • 性能监控包括响应延迟、吞吐量、错误率、Token 消耗这些常规指标。
  • 质量监控更复杂,因为不能直接量化 “答得好不好”。可以建套 “黄金数据集”,包含 500 个典型问题和人工标注的标准答案。每天凌晨自动跑一次回归测试,对比系统答案和标准答案的差异。这个数据集持续更新,用户反馈不好的问题定期补充进去。它能及时发现性能退化。
  • 用户反馈机制:在每个答案下面都放了 “点赞” 和 “点踩” 按钮,它构建了 “使用 – 反馈 – 优化” 的数据飞轮。点踩的数据会进入人工审核队列,确认是系统问题后,会触发知识库修正或模型调优。连续一周点赞率低于某个阈值,就会触发架构 review。这个闭环让系统能持续迭代,越用越聪明。
  • 用户满意度预测:是用轻量级模型根据答案长度、来源可信度、格式规范性等特征,预测用户会不会满意。这个预测值和实际反馈做对比,能发现系统的潜在问题。比如预测满意度高但实际点踩多,说明模型可能过于自信,需要调整。案例:因为技术支持的场景很特殊,答案对错直接影响客户能否解决问题。Synology 让资深工程师标注了一批 “高质量答案” 和 “低质量答案”,训练了个小模型来预测生成答案的质量。如果预测分数低,自动转人工处理。这个设计相当于给系统装上了一个 “自知之明” 模块,知道什么时候该自己答,什么时候该交给人。
  • 日志的埋点要足够细,每个环节都要记录。用户问了一个问题,日志里能看到:原始 Query 是什么、改写后的 Query 是什么、检索到了哪些文档、每篇文档的相关性分数、最终生成的答案、耗时多少、消耗多少 Token。这样一旦出问题,能快速定位是解析环节、检索环节还是生成环节的问题。

3. MCP 模型上下文协议

MCP((Model Context Protocol,模型上下文协议)是一种用于将AI连接到外部系统的开源标准。使用 MCP,像 Claude 或 ChatGPT 这样的 AI 应用程序可以连接到数据源(例如本地文件、数据库)、工具(例如搜索引擎、计算器)和工作流程(例如专业提示)——使它们能够访问关键信息并执行任务。可以把 MCP 想象成 AI 应用程序的 USB-C 接口。就像 USB-C 提供了一种标准化的方式来连接电子设备,MCP 提供了一种标准化的方式来将 AI 应用程序连接到外部系统。

AI Agent 从技术原理到业务落地-BtoAI 波特埃
AI Agent 从技术原理到业务落地-BtoAI 波特埃

4. Function Calling

AI Agent 从技术原理到业务落地-BtoAI 波特埃
  • 第一步:开发者定义和提供工具(Functions) 在最开始,你需要告诉大模型它有哪些“工具”可用。这就像你给一个助手一个工具箱,并告诉他每个工具的作用。
  • 第二步:大模型响应,返回函数调用指令 当用户提出一个请求(例如:“北京现在多少度?”),你的应用程序将用户的问题和上述工具列表一起发送给大模型。大模型在处理请求后,会识别出它需要调用一个外部工具来获取信息。它的响应不会是常规的文本回复,而是一个结构化的函数调用参数。
  • 第三步:应用程序执行函数并再次调用大模型 这是整个流程中最关键的步骤。你的应用程序代码接收到大模型的响应后,需要完成检查响应、解析指令、执行函数、再次调用大模型等工作。
  • 最后一步,大模型接收到所有这些信息后,会利用函数执行的结果,生成一个自然流畅的最终回复给用户:“背景现在晴朗,气温是34°C。”

FC与MCP两者区别:

维度 Function Calling MCP
性质 模型内置能力(API 功能) 外部通信协议(开源标准)
依赖 特定 LLM 平台(如 OpenAI) 任何支持文本输入的 LLM
上下文管理 需手动拼接历史 自动维护会话上下文
安全性 依赖平台沙箱 显式权限配置(YAML/JSON)
扩展性 限于平台支持的工具类型 任意可执行程序均可接入
标准化程度 各厂商私有实现 社区驱动的开放协议

5. Skills

Agent Skills 是包含指令、脚本和资源的文件夹,代理可以发现并使用它们来更准确、更高效地完成任务。

my-skill/
├── SKILL.md          # Required: instructions + metadata
├── scripts/          # Optional: executable code
├── references/       # Optional: documentation
└── assets/           # Optional: templates, resources
## SIKILL.md
---
name: pdf-processing (小写字母、数字、连字符)
description: Extract text and tables from PDF files, fill forms, merge documents.
license: Apache-2.0
metadata:
  author: example-org
  version: "1.0"

---

# PDF Processing

## When to use this skill
Use this skill when the user needs to work with PDF files...

## How to extract text
1. Use pdfplumber for text extraction...

## How to fill forms
...
## 引用方式
See [the reference guide](references/REFERENCE.md) for details.

Run the extraction script:
scripts/extract.py

更多文章

回到顶部