首页
/ Learn Claude Code:从 0 到 1 构建 Nano 级 Claude Code 风格 Agent Harness 的完整工程指南

Learn Claude Code:从 0 到 1 构建 Nano 级 Claude Code 风格 Agent Harness 的完整工程指南

2026-09-05 17:52:45作者:龚格成

本文基于 learn-claude-code 仓库中文主文档(README-zh.md)整理并扩展,系统讲解该项目"模型 + Harness"的核心理念、最小 agent loop 的完整实现,以及从 s01 到 s17 共 17 个递进式课程如何逐个叠加 harness 机制。读完本文,你将掌握一套可运行的 Anthropic API 编码 agent 的搭建方法(含环境配置、快速开始命令),并理解每个 harness 机制在源码层面的落点,从而能够独立设计、调试和扩展属于自己的 agent harness。

一、Agency 来自模型,Agent 产品 = 模型 + Harness

仓库开篇先立了一个核心论点:Agency——感知、推理、行动的能力——来自模型训练,不是来自外部代码的编排。一个能干活的 agent 产品需要模型和 harness 缺一不可:模型是驾驶者,harness 是载具。这个仓库教你造载具。

1.1 Agency 从哪来:历史上的铁证

仓库用一串业界里程碑论证"agent 是训练出来的,不是编出来的":

  • 2013 — DeepMind DQN 玩 Atari:一个神经网络只接收原始像素和游戏分数,学会 7 款 Atari 2600 游戏并超越所有先前算法,其中 3 款击败人类专家;到 2015 年同一架构扩展到 49 款游戏、达到职业人类测试员水平(论文发表于 Nature)。没有游戏专属规则,没有决策树——一个模型,从经验中学习。
  • 2019 — OpenAI Five 征服 Dota 2:五个神经网络在 10 个月内与自己对战了约 45,000 年的 Dota 2,在旧金山直播赛 2-0 击败 TI8 世界冠军 OG;公开竞技场 42,729 场比赛胜率 99.4%。没有脚本化策略,模型完全通过自我对弈学会团队协作与实时适应。
  • 2019 — DeepMind AlphaStar 制霸星际争霸 II:闭门赛 10-1 击败职业选手,随后在欧洲服务器达到宗师段位(90,000 名玩家中的前 0.15%)。信息不完全、实时决策、组合动作空间远超棋类——Agent 是训练出来的模型。
  • 2019 — 腾讯绝悟统治王者荣耀:2019 年世冠杯半决赛 5v5 击败 KPL 职业选手;1v1 模式下职业选手 15 场只赢 1 场,训练强度一天等于人类 440 年。没有手工编写的英雄克制表,一个从零自我对弈学习整个游戏的模型。
  • 2024-2025 — LLM Agent 重塑软件工程:Claude、GPT、Gemini 在人类全部代码和推理上训练,被部署为编程 agent——阅读代码库、编写实现、调试故障、团队协作。架构与之前每一个 agent 完全相同:一个训练好的模型,放入一个环境,给予感知和行动的工具。

结论:每一个 agent 都需要一个环境才能工作——Atari 模拟器、Dota 2 客户端、星际引擎、IDE 和终端。模型提供智能,环境提供行动空间,两者合在一起才是一个完整的 agent。

1.2 Agent 不是什么:对"提示词水管工"的否定

仓库直言,"Agent"一词已被拖拽式工作流构建器、无代码 AI 平台、提示词链编排库所劫持。它们的共同幻觉是:把 LLM API 调用用 if-else 分支、节点图、硬编码路由逻辑串起来就算"构建 Agent"。仓库的判断是:那是鲁布·戈德堡机械——一个过度工程化的过程式规则流水线,LLM 被楔在里面当一个美化了的文本补全节点。这类系统脆弱、不可扩展、不具备泛化能力,是 GOFAI(经典符号 AI)的现代还魂。你不可能通过工程手段编码出 agency,agency 是学出来的,不是编出来的。

1.3 心智转换:从"开发 Agent"到开发 Harness

当一个人说"我在开发 Agent"时,只可能是两个意思之一:

  1. 训练模型——通过强化学习、微调、RLHF 等基于梯度的方法调整权重。这是 DeepMind、OpenAI、腾讯 AI Lab、Anthropic 在做的事,是最本义的 Agent 开发。
  2. 构建 Harness——编写代码,为模型提供一个可操作的环境。这是大多数人的工作,也是本仓库的核心。

Harness 的组成公式(原文完整继承):

Harness = Tools + Knowledge + Observation + Action Interfaces + Permissions

    Tools:          文件读写、Shell、网络、数据库、浏览器
    Knowledge:      产品文档、领域资料、API 规范、风格指南
    Observation:    git diff、错误日志、浏览器状态、传感器数据
    Action:         CLI 命令、API 调用、UI 交互
    Permissions:    沙箱隔离、审批流程、信任边界

模型做决策,Harness 执行;模型做推理,Harness 提供上下文。编程 agent 的 harness 是它的 IDE、终端和文件系统;农业 agent 的 harness 是传感器阵列与灌溉控制;酒店 agent 的 harness 是预订系统与设施管理 API。Agent(智能、决策者)永远是模型,Harness 因领域而变。

1.4 Harness 工程师的日常工作

仓库给读者列出了五份具体工作清单,这份清单实际上就是课程 s01-s17 的"工种地图":

职责 说明 对应课程
实现工具 给 agent 一双手:文件读写、Shell、API 调用、浏览器、数据库查询;设计时原子化、可组合、描述清晰 s01、s02
策划知识 给 agent 领域专长:产品文档、架构决策记录、风格指南;按需加载,不前置塞入 s07
管理上下文 子 Agent 把明确的工作留在另一份 messages[];上下文压缩缩短早期历史;任务系统让目标持久化到单次对话之外 s06、s08、s10
控制权限 沙箱化文件访问、对破坏性操作要求审批、实施信任边界——安全工程与 harness 工程的交汇点 s03
收集任务过程数据 每条真实行动序列都是训练信号,你的 harness 不仅服务 agent,还可以帮助进化 agent

1.5 为什么拆解 Claude Code:Harness 工程的大师课

仓库选择 Claude Code 作为教学标本的理由:它是所见过的最优雅、最完整的 agent harness 实现——不是因为某个巧妙技巧,而是因为它没做的事:没有试图成为 agent 本身,没有强加僵化工作流,没有用决策树替模型做判断。把 Claude Code 剥到本质:

Claude Code = 一个 agent loop
            + 工具 (bash, read, write, edit, glob, grep, browser...)
            + 按需 skill 加载
            + 上下文压缩
            + 子 agent 派生
            + 带依赖图的任务系统
            + 异步邮箱的团队协调
            + 任务绑定的 worktree 并行执行
            + 权限治理

"就这些。这就是全部架构。"每一个组件都是 harness 机制;agent 本身是模型。Harness 没有让 Claude 变聪明,而是给了它双手、双眼和一个工作空间。启示不是"复制 Claude Code",而是:最好的 agent 产品,出自那些明白自己的工作是 harness 而非 intelligence 的工程师之手。

二、核心模式:THE AGENT PATTERN

整个课程的地基是最小 agent 循环(原文 ASCII 图完整继承):

                    THE AGENT PATTERN
                    =================

    User --> messages[] --> LLM --> response
                                      |
                            stop_reason == "tool_use"?
                           /                          \
                         yes                           no
                          |                             |
                    execute tools                    return text
                    append results
                    loop back -----------------> messages[]

    这是最小循环。每个 AI Agent 都需要这个循环。
    模型决定何时调用工具、何时停止。
    代码只是执行模型的要求。
    本仓库教你构建围绕这个循环的一切 --
    让 agent 在特定领域高效工作的 harness。

仓库 README 给出的核心代码骨架(完整继承):

def agent_loop(messages):
    while True:
        response = client.messages.create(
            model=MODEL, system=SYSTEM,
            messages=messages, tools=TOOLS,
        )
        messages.append({"role": "assistant",
                         "content": response.content})

        if response.stop_reason != "tool_use":
            return

        results = []
        for block in response.content:
            if block.type == "tool_use":
                output = TOOL_HANDLERSblock.name
                results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": output,
                })
        messages.append({"role": "user", "content": results})

2.1 源码级实现:s01 的最小循环

第一课 s01_agent_loop/code.py 把上述骨架落成了可直接运行的程序,其中几个实现细节值得注意:

  • 唯一工具是 bash。工具定义极简:名称 bash、描述 "Run a shell command."、输入 schema 只有一个必填的 command 字符串(s01_agent_loop/code.py)。这正是课程格言 "One loop & Bash is all you need" 的来源:一个工具 + 一个循环 = 一个 Agent。
  • 最小防护内置在工具里run_bash 在执行前检查危险命令黑名单(rm -rf /sudoshutdownreboot> /dev/),命中即返回 "Error: Dangerous command blocked";命令通过 subprocess.run(..., shell=True, timeout=120) 执行,120 秒超时返回错误;输出合并 stdout/stderr 后截断到 50,000 字符(s01_agent_loop/code.py)。
  • 循环控制参数:每轮调用 max_tokens=8000,assistant 回合整块追加进 messagesstop_reason != "tool_use" 时直接返回;工具结果以 role: "user" 的消息批量回喂(s01_agent_loop/code.py)。
  • 模型名来自环境变量MODEL = os.environ["MODEL_ID"],API key 与 base URL 通过 python-dotenvload_dotenv().env 加载,这决定了仓库所有课程统一的环境约定(下文"快速开始"详述)。
  • 交互入口python s01_agent_loop/code.py 启动后是一个 REPL(提示符 s01 >>),历史消息跨轮累积,输入 q 退出。

2.2 加工具只加 handler:s02 的 dispatch map

第二课 s02_tool_use/code.py 演示了"循环不用动,新工具注册进 dispatch map":在 bash 之外新增 read_file / write_file / edit_file / glob 四个工具,定义进 TOOLS 列表,并把实现函数注册进 TOOL_HANDLERS 字典(s02_tool_use/code.py)。循环里唯一的变化是一行:

# s01: output = run_bash(block.input["command"])
# s02: output = TOOL_HANDLERSblock.name

值得特别指出的是 safe_path 的实现:文件类工具先把路径 resolve() 到工作目录下,再用 path.is_relative_to(WORKDIR) 断言不能逃出工作区,越界直接抛 ValueErrors02_tool_use/code.py)。这是"harness 自带信任边界"这一设计哲学的第一个具体体现——权限不是靠模型自觉,而是靠工具实现强制。

三、17 个递进式课程总览

仓库的课程结构是"每个课程添加一个 harness 机制,每个机制有一句格言"(原文格言完整继承):

章节 格言 / 要点 关键概念(来自全部章节表)
s01 "One loop & Bash is all you need"——一个工具 + 一个循环 = 一个 Agent messages / while True / stop_reason
s02 "加一个工具, 只加一个 handler"——循环不用动,新工具注册进 dispatch map TOOL_HANDLERS / dispatch map / 并发
s03 "先划边界, 再给自由"——先判断操作能不能做,要不要问用户 PermissionRule / 审批管线
s04 "挂在循环上, 不写进循环里"——在工具前后留插口,不改主循环也能扩展 PreToolUse / PostToolUse / 扩展点
s05 "没有计划的 agent 走哪算哪"——先列步骤再动手 TodoItem / 先计划后执行
s06 给子任务全新的 messages[],最终文本作为一条工具结果返回 fresh messages[] / 上下文隔离
s07 "用到时再加载, 别全塞 prompt 里"——技能先列目录,用到时再展开 SkillLoader / 技能目录 / 按需注入
s08 "上下文总会满, 要有办法腾地方"——四步压缩,先整理工具结果,仍超限时再生成历史摘要 budget / snip / micro / summary
s09 "记住该记的, 忘掉该忘的"——三个子系统:筛选、提取、整理 selection / extraction / consolidation
s10 "大目标拆成小任务, 排好序, 持久化"——文件持久化的任务图 TaskRecord / blockedBy / 磁盘持久化
s11 "慢操作丢后台, agent 继续思考"——后台线程跑命令,完成后注入通知 线程执行 / 通知队列
s12 "定时触发, 不需要人推"——按时间自动触发任务 持久化调度 / 会话级触发
s13 "一个 Agent 顾不过来,就让队友分工协作"——持久队友、原子认领就绪任务、任务绑定的工作目录 持久队友 / 原子认领 / Worktree / 类型协议
s14 "能力不够? 插上 MCP"——把外部工具接进同一个工具池 工具发现 / 命名空间 / 工具池组装
s15 "多种机制,一个循环"——集成示例用到的机制归到同一个 harness 工具、运行时上下文、任务、团队、调度和 MCP 归到一个循环
s16 "编排形状固定时,就把它写进代码"——保存好的 workflow 使用 journal 续跑 脚本编排 / 生命周期事件 / journal 续跑
s17 "目标决定循环什么时候真正结束"——每次准备停止时由独立判断器审查;目标不可能、执行失败或超过续跑上限时把控制权交还用户 目标闸门 / 对话判断 / 自动续轮

每章目录结构统一(README-zh.md 项目结构一节原文继承):

learn-claude-code/
  s01_agent_loop/          # 每章一个文件夹
    README.md              #   默认英文文档(完整叙事)
    README.zh.md           #   中文译本
    README.ja.md           #   日文译本
    code.py                #   独立可运行代码
    images/                #   SVG 流程图
  s02_tool_use/
  ...
  s14_mcp_plugin/
  s15_integrated_harness/
  s16_workflow_runtime/
  s17_goal_loop/           # 终点章
  agents/                  # 旧 12 章可运行副本 + s_full.py
  skills/                  # s07 使用的 skill 文件
  docs/                    # 旧 12 章文档,过渡期保留
  web/                     # 从根目录课程生成
  tests/

其中 skills/ 目录真实存放了 s07 课程用到的四个 skill(agent-buildercode-reviewmcp-builderpdf,各自带 SKILL.md);agents/ 保留旧 12 章的可运行副本(s01_agent_loop.pys12_worktree_task_isolation.py 及全集成版 s_full.py);tests/ 下的 pytest 用例对各个机制做了回归验证(如 tests/test_s06_subagent.pytests/test_task_system.pytests/test_goal_loop.py)。

四、版本说明:两条教程线并存

本仓库现在同时保留两条教程线(原文完整继承):

  • 新版主线:根目录 s01-s17。根目录下的 s01_*s17_* 是新的主版本,也是当前推荐阅读路径。每章包含默认英文 README、中文/日文译本、可运行的 code.py,以及必要的图示。
  • 旧版过渡:docs/agents/。这些仍保留旧 12 章体系,暂时用于已有读者和旧链接过渡。

新读者请从 s01_agent_loop/ 读到 s17_goal_loop/。旧版章节号和新版不完全一致,不要混用章节号。旧版到新版的对应关系(原文表格完整继承):

旧 12 章版本 新 17 章版本 主题
旧 s01 新 s01 Agent Loop
旧 s02 新 s02 Tool Use
旧 s03 新 s05 TodoWrite
旧 s04 新 s06 Subagent
旧 s05 新 s07 Skill Loading
旧 s06 新 s08 Context Compact
旧 s07 新 s10 Task System
旧 s08 新 s11 Background Tasks
旧 s09 新 s13 Agent Teams
旧 s10 新 s13 Team Protocols
旧 s11 新 s13 自主认领任务
旧 s12 新 s13 任务绑定的 Worktree
新版新增 s03、s04、s09、s12、s14、s15、s16、s17 Permission、Hooks、Memory、Cron、MCP、Agent Harness 集成、Workflow Runtime、Goal Loop

课程边界(原文继承):这是一个从 0 到 1 的 harness 工程课程。每章先单独展开一个机制,s15 再把累积的运行时接回完整的 Agent 循环;s16 在这个循环上加入 workflow 编排;s17 用更小的工具池单独讲目标控制的续跑,不是又一个累积式运行时。

五、快速开始

5.1 依赖与环境(以仓库实际文件为准)

requirements.txt 只有三个依赖,门槛极低:

anthropic>=0.25.0
python-dotenv>=1.0.0
pyyaml>=6.0

环境变量约定来自 .env.example(仓库内可直接查看),核心项:

变量 必填 默认值 / 示例 说明
ANTHROPIC_API_KEY sk-ant-xxx Anthropic API Key
MODEL_ID claude-sonnet-4-6 模型 ID,所有课程统一读取此变量
ANTHROPIC_BASE_URL 默认官方端点 用于接入 Anthropic 兼容的第三方提供商

.env.example 中还以注释形式列出了若干兼容提供商的配置样例(国际与大陆分别给出),包括 MiniMax(MiniMax-M3 等)、GLM 智谱(glm-5.2)、Kimi Moonshot(kimi-k2.7-code 等)、DeepSeek(deepseek-v4-pro / deepseek-v4-flash),各自对应的 ANTHROPIC_BASE_URL 均在注释中给出,复制注释、替换 MODEL_ID 即可切换后端。这一点也与 s01 源码中的行为一致:Anthropic(base_url=os.getenv("ANTHROPIC_BASE_URL")) 显式支持自定义 base URL(s01_agent_loop/code.py)。

5.2 新版 17 章主线运行方式

原文快速开始命令完整继承(clone 地址仅在此处给出一次):

git clone https://gitcode.com/GitHub_Trending/an/learn-claude-code
cd learn-claude-code
pip install -r requirements.txt
cp .env.example .env   # 编辑 .env 填入你的 ANTHROPIC_API_KEY

python s01_agent_loop/code.py        # 起点 — 一个循环 + bash
python s08_context_compact/code.py    # 上下文压缩(复杂章)
python s17_goal_loop/code.py          # 终点章:用目标闭合循环

旧版 12 章过渡线:

python agents/s01_agent_loop.py
python agents/s12_worktree_task_isolation.py
python agents/s_full.py

Web 平台从根目录课程生成内容,s16、s17 提供阅读、源码、模拟和架构视图:

cd web && npm install && npm run dev   # http://localhost:3000

5.3 各章 code.py 的统一运行约定

从各章源码头部注释可以确认统一的运行方式与依赖约定:

  • 所有课程均为 python <章节目录>/code.py 直接运行,交互式 REPL 输入任务、输入 q 退出;
  • s17 支持命令行直接给定目标:python s17_goal_loop/code.py "/goal pytest tests exits with code 0"
  • s16 支持 demo / resume 子命令演示 workflow 编排与 journal 续跑(s16_workflow_runtime/code.py 头部注释)。

六、学习路径:从"能动手"到"编排与目标闭环"

原文学习路径主线是:能动手 → 能做复杂任务 → 能记住和恢复 → 能长期运行 → 能协作 → 能扩展并合体。仓库 README 中用 mermaid 流程图组织为七个阶段,这里将其压缩为等价的阶段视图(内容一一对应原图):

阶段 名称 包含课程
1 让 Agent 能动手 s01 Agent Loop(一个循环 + bash)、s02 Tool Use(单个到多个工具)、s03 Permission(判断能不能做)、s04 Hooks(工具前后留扩展插口)
2 做复杂任务 s05 TodoWrite(先列计划再执行)、s06 Subagent(全新消息,返回最终文本)、s08 Context Compact(长上下文腾空间)
3 跨会话记忆 s09 Memory(保存并召回可复用知识)
4 让任务长期运行 s10 Task System(任务落盘记依赖)、s11 Background Tasks(慢操作丢后台)、s12 Cron Scheduler(按时自动触发)
5 让多个 Agent 协作 s13 Agent Teams(队友 + 消息投递 + 协作协议、原子认领就绪任务、任务绑定的 Worktree)
6 接外部能力合体 s07 Skill Loading(技能按需展开)、s14 MCP Plugin(外部接进工具池)、s15 Agent Harness 集成(课程机制回到同一循环)
7 编排并完成 s16 Workflow Runtime(脚本拥有固定编排)、s17 Goal Loop(独立判断决定何时停止)

七、关键机制的源码级实现证据

以下选取与 README 声明逐一对应的源码证据,帮助读者验证"每章一个机制"不是口号而是可运行的实现。

7.1 s03 权限:三道闸门串成审批管线

README 把 s03 的关键概念标为 PermissionRule / 审批管线。在 s03_permission/code.py 中可以看到管线由三个函数串联:

  1. Deny-list 闸门:对 bash 命令先查危险命令列表,命中直接返回 False(不执行、不打扰用户);
  2. 规则闸门 check_rules:遍历 PERMISSION_RULES,每条规则声明适用工具与检查函数,命中则给出原因;
  3. 用户审批闸门 ask_user:打印工具名与参数,交互询问 Allow? [y/N],默认拒绝。

管线函数 check_permission(block) 在 agent loop 中作为工具执行前的一步插入,被拒的工具会收到一条 Permission denied.tool_result 而不是崩溃——权限结果也是对话的一部分,模型可以据此换路。这与 README"先划边界, 再给自由"的格言严格对应。

7.2 s08 上下文压缩:四步压缩管线在类方法中落地

README 将 s08 描述为 budget / snip / micro / summary 四步压缩。s08_context_compact/code.py 中这些步骤一一对应到 CompactManager 的方法:

该章配套多张 SVG 流程图(四步管线、大结果转存、自动压缩时序),见 s08_context_compact/images/

7.3 s16 与 s17:运行时护栏常量直接可读

  • s16 Workflow Runtimes16_workflow_runtime/code.py 顶部定义了显式的运行时护栏:AGENT_CAP = 1000(单次运行内 agent() 调用硬上限)、CONCURRENCY = 8(信号量并發上限)、快照与 journal 存放在章节目录下的 .runtime,以及 workflow 名称的合法性正则 ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$。"编排形状固定时,就把它写进代码"的具体含义就是这些可审计的常量与 journal 文件。
  • s17 Goal Loop 的头部常量(s17_goal_loop/code.py)精确刻画了"目标闸门"的边界:DEFAULT_MAX_TOKENS = 8000(worker 模型)、DEFAULT_EVALUATOR_MAX_TOKENS = 512(判断器用更小预算)、DEFAULT_STOP_HOOK_BLOCK_CAP = 8(续跑拦截上限)、MAX_GOAL_LENGTH = 4000(目标描述长度上限),另有 DENY_LISTDESTRUCTIVE 两组命令名单。其架构注释与 README 格言一致:目标是会话级 Stop hook,独立 evaluator 读对话、判定完成条件,不满足就把未完成的工作送回同一个 agent loop。

7.4 s15 集成:把课程机制归到一个循环

s15_integrated_harness/code.py 从源码结构看是"合体章"的实据:同一文件内可见任务存储(create_task / claim_task / complete_task,依赖检查函数 can_start_incomplete_dependencies)、git worktree 的创建与校验(validate_worktree_name / task_worktree_cwd / _registered_worktrees)、队友任务分配(advance_assignment_version / assignment_cwd / release_teammate_assignment)与内存运行时加载(load_memory_runtime)等组件并存于一个 runtime 中。运行 s15 需要额外安装 pyyaml(其头部注释已注明),用于读取任务/工作树相关的 YAML 配置。

八、愿景:Harness 模式是可跨领域泛化的基础设施

仓库把视野从编程 agent 推得更远,用一组公式说明"循环不变,工具/知识/权限在变":

庄园管理 agent  = 模型 + 物业传感器 + 维护工具 + 租户通信
农业 agent      = 模型 + 土壤/气象数据 + 灌溉控制 + 作物知识
酒店运营 agent  = 模型 + 预订系统 + 客户渠道 + 设施 API
医学研究 agent  = 模型 + 文献检索 + 实验仪器 + 协议文档
制造业 agent    = 模型 + 产线传感器 + 质量控制 + 物流系统
教育 agent      = 模型 + 课程知识 + 学生进度 + 评估工具

"Agent = 模型(LLM) + 泛化的操作环境(Harness)"。每一个部署在真实领域的好 harness,都是 agent 能够感知、推理、行动的又一个阵地。这是仓库的收束宣言:Agency 来自模型。Harness 让 agency 落地。造好 Harness,模型会完成剩下的。Bash is all you need. Real agents are all the universe needs.

九、小结:如何继续深入本仓库

  • 想理解某章机制的完整叙事,读对应章节的双语文档,如 s01_agent_loop/README.zh.mds13_agent_teams/README.zh.md
  • 想对照验证实现,直接运行或阅读各章 code.py(每章均可独立运行,仅需 .env);
  • 想看机制的回归验证,查阅 tests/ 目录下的 pytest 用例;
  • 想浏览交互化内容(模拟、架构图、版本对比),运行 web/ 平台(cd web && npm install && npm run dev)。

本文所有事实均取自仓库当前实际内容:章节结构与格言来自 README-zh.md,运行命令与依赖来自 requirements.txt.env.example,机制细节引自各章 code.py 源码。适用前提:Python 环境 + 可用的 MODEL_ID(默认 claude-sonnet-4-6)API 凭据;课程间除 s15 的 pyyaml 外无额外依赖。

登录后查看全文
热门项目推荐
相关项目推荐