多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

ponyc 的 libs 缓存架构:基于 GHCR OCI 工件的双缓存设计与 CI 编排实战

ponyc 的 libs 缓存架构:基于 GHCR OCI 工件的双缓存设计与 CI 编排实战 编程语言编译器语言运行时【免费下载链接】ponycPony is an open-source, actor-model, capabilities-secure, high performance programming language项目地址https://gitcode.com/gh_mirrors/po/ponyc点击查看免费下载ponyc 编译器内置vendor了 LLVM、LLD 与 clang从源码构建这些依赖动辄耗费数小时是 CI 中最昂贵的一环。本文基于仓库 .ci-scripts/libs-cache/README.md 及同目录下的全部实现脚本完整讲解 ponyc 如何用「主缓存 分支缓存」的双层 GHCR OCI 工件缓存体系消除重复构建包括包命名与内容哈希寻址、warmer 的三段式预热、从不冷构建的消费方策略、BSD VM 的缓存进出、保留清理策略以及双 token 权限拆分。读完本文你将能理解该缓存体系的每一个脚本、每一条工作流门控与每一次缓存命中的底层原理并可直接复用到其他「vendor 重型依赖」的 CI 场景。为什么需要一套独立的 libs 缓存ponyc 将 LLVM、LLD、clang 以源码形式 vendored 进仓库每次干净构建都需要从源码编译它们。由于构建耗时以小时计CI 必须缓存构建产物——具体而言是以下两条路径build/libsLLVM/LLD/clang 的构建产物树lib/llvm/src/compiler-rt/lib/builtinscompiler-rt 的内建库这两条路径在 .ci-scripts/libs-cache/registry.py 中被定义为CACHED_PATHS正是旧版actions/cache步骤曾经存储的内容。与 GitHub Actions 内置缓存不同ponyc 将工件以GHCR OCI artifact单个 targzip blob OCI manifest形式存放原因是该缓存需要跨工作流、跨平台、跨 fork 共享且要支持「先查存在性再决定是否构建」的廉价探测这些能力 GitHub Actions cache 无法满足。关键设计决策是缓存逻辑完全不进入构建本身。cmake -P lib/build-libs.cmake只知道如何构建 libs对缓存一无所知所有缓存原语与编排逻辑都收敛在.ci-scripts/libs-cache/目录的脚本里围绕这条构建命令做序列化。这套脚本全部使用 Python 标准库实现CI runner 上无需任何 pip 安装。双缓存架构总览main cache 与 branch cache体系内存在两个相互独立、职责分明的缓存缓存命名空间写入者读取者保留策略主缓存ponyc-libs-cache/仅 warmer预热工作流所有消费方工作流按包保留最新 N 个版本keep-N分支缓存ponyc-branch-libs-cache/PR 作业、weekly 消费方以及 tier2/tier3/stress 在 off-main 时PR 作业、tier 作业、warmer用于 promote按年龄两周主缓存只由 warmer 写入保证任何消费方「拉取或自建」都不会污染主缓存分支缓存则是 PR 与分支构建的「草稿区」让一次 LLVM 变更触发的构建只发生一次之后可被重复复用并在合入 main 后被**提升promote**进主缓存。脚本体系薄入口脚本 共享支持库整个.ci-scripts/libs-cache/目录由两类文件组成可直接运行的入口脚本和它们共同 import 的共享支持库。入口脚本oci_libs_cache.py— 主缓存的 push/pull/exists 原语registry v2 APIbranch_libs_cache.py— 分支缓存的同名原语promote_libs_cache.py— 将分支缓存工件以同一 tag 复制进主缓存registry.copyresolve_libs_cache.py— 非 PR 构建消费方、warmer、require-cache-hit的编排入口pr_libs_cache.py— PR 作业的编排入口prune_libs_cache.py/prune_branch_libs_cache.py/clear_libs_cache.py— 保留与清理共享支持库registry.py— registry-v2 客户端request、鉴权、blob、manifest、归档、copy、derive_platform、IMAGE_RE、repo_rootghpackages.py— GitHub Packages REST 管道gh_request、paginate、encodecache_arch.py— 架构名称规范化common.py—die/info打印器、编排辅助函数以及共享的入口脚本路径常量MAIN_CACHE、BRANCH_CACHE、PROMOTE正是这种分层让oci_libs_cache.py与branch_libs_cache.py退化为「一个命名空间 一个 cache_package 一个调用registry.dispatch的 main」promote_libs_cache.py则解析两个命名空间后调用registry.copy。修改构建镜像命名只需在registry.py中改一处——这正是共享库存在的意义参见 .ci-scripts/libs-cache/oci_libs_cache.py 与 .ci-scripts/libs-cache/branch_libs_cache.py。包命名与缓存身份完整包名只在一个地方组装——cache_package()ponyc-libs-cache/platform-arch ponyc-branch-libs-cache/platform-arch而 tag 是工作流中hashFiles(...)的内容哈希。package:tag与旧actions/cache的 key 基于同一组输入任何改变 LLVM 决定输入的改动都会得到不同 tag文件变化或不同 platform构建镜像变化因此绝不会服务到过期工件——结果只可能是精确命中或未命中。命名空间的隔离作用ponyc-libs-cache/这一路径命名空间把缓存包与可分发容器nightly/、releases/隔开同时为保留与清理脚本的 glob 匹配划定了边界ponyc-libs-cache/*永远不可能扫到无关容器。分支缓存的ponyc-branch-libs-cache/同理。platform 的两种来源platform要么由derive_platform从构建镜像引用推导要么是调用方显式传入的裸标签容器作业传--image镜像引用必须匹配IMAGE_RE正则^ghcr\.io/ponylang/ponyc-ci-(.):(\d{8})$.ci-scripts/libs-cache/registry.py。名称 日期YYYYMMDD共同构成 platform 字符串:被替换为_所以两个不同版本的构建镜像会落在不同的包中格式不符会立即失败并提示更新IMAGE_RE.ci-scripts/libs-cache/registry.py。非容器平台macOS/Windows/BSD传--platform裸标签如x86-macos-15-intel。脚本负责附加命名空间与 arch工作流只传标签本身。arch 规范化为什么是双重必需arch取自构建机上的platform.machine()经cache_arch.canonical归一为每种 ISA 的唯一拼写amd64→x86_64aarch64→arm64.ci-scripts/libs-cache/cache_arch.py。未识别架构是硬错误而非静默透传——新增 ISA 必须显式加入ARCH_ALIASES。规范化之所以必要有两个原因多架构镜像防冲突alpine 与 ubuntu26.04 构建镜像是多架构的同时在 x86-64 与 arm64 的 warmer 作业上构建。若 arch 不在包名里两个架构会推送到同一个package:tag互相覆盖arm64 消费方甚至会拉到 x86-64 的 libs。跨系统同名同一 ISA 在不同 OS 上拼写不同——Linux 写x86_64FreeBSD/OpenBSD 写amd64。BSD warmer 的宿主机侧存在性检查跑在 Linux runner 上而推送发生在 VM 内两者必须归一为同一名称否则宿主机永远看不到 VM 写入的工件。重命名即孤儿化改变某个 ISA 的规范拼写——或包名形状的任何部分——都会重命名包旧名的主缓存工件随即成为孤儿prune按包保留 N 个永远不会回收一个已停止接收新版本的包。此时需要手动运行一次clear-libs-cache.yml删除这些流浪包。分支缓存无此问题因为它的保留策略基于年龄能自我愈合主缓存则不能。主缓存warmer 与其三段式预热update-lib-cache.ymlwarmer是主缓存的唯一写入者在 push 到 main 时运行。未命中时它先尝试用promote_libs_cache.py提升一个匹配的分支缓存工件registry copy直接复用某个 PR 或临时 dispatch 已完成的构建只有两者皆无时才冷构建。由于其他所有工作流都只「拉取或构建」warmer 的作业必须覆盖每一个消费方会拉取的平台与标签若某个消费方的构建镜像或 runner 标签 warmer 不构建它每次运行都会未命中。因此新增 libs 消费方或给既有消费方加平台时必须同步在 warmer 的正确阶段补上对应平台。三阶段顺序与并发上限一次冷推送——比如 LLVM 输入变更导致所有平台同时冷构建——会瞬间占满整个组织的 runner 池用低频构建抢占最高频缓存的资源。因此预热分三个串行阶段进行PR 平台x86_64-linux-pr即 ubuntu26.04 x86-64arm64-macosx86_64-windows——pr.yml拉取的平台。无门控立即开始。Release 与 nightly 平台x86_64-linux-release、arm64-linux、x86_64-macos、arm64-windows——release.yml与nightlies.yml拉取的其余平台。其他所有平台x86_64-linux-other即 fedora 加交叉编译镜像freebsdopenbsddragonflybsd——tier2、tier3 与仅周更平台。第三阶段的后七个构建——四个x86_64-linux-other矩阵分支加三个 BSD VM——每个都要两到三个小时所以阶段 3 并发上限为 2x86_64-linux-other携带max-parallel: 2BSD 作业needs:x86_64-linux-other保证 VM 从不与容器分支重叠dragonflybsd还needs:freebsd。移除其中任何一个门控都会重新放开阶段并发。每个后一阶段只needs:前一阶段的快速作业Linux 与 macOS绝不等待 Windows——Windows 构建在其阶段内启动但因最慢而绝不能门控下一阶段。阶段作业携带if: ${{ !cancelled() }}使前一阶段构建失败只会推迟后续阶段而不会取消它们。新平台应放入最早会拉取它的阶段。x86-64 Linux 构建之所以拆成三个作业-pr、-release、-other是因为needs:是作业级而非矩阵条目级而这些构建镜像横跨全部三个阶段每个镜像必须且只能放在三个作业中的一个。从不冷构建的消费方stress-test 工作流stress-test-*.yml、ponyc-tier2.yml与ponyc-tier3.yml依据被测代码是否为 main 来选择模式。步骤的分支检查为github.event_name workflow_dispatch ref ! main其中ref是检出 reftier2/tier3 用inputs.refstress 用github.event.inputs.sha。两者默认都是main定时运行两者皆无因此按 on-main 处理。On main定时运行或留在 main 上的 dispatch时它们传--require-cache-hit --skip-on-miss永不冷构建。未命中时写入.libs-cache-miss标记并以 0 退出后续每个构建/运行步骤都以if: hashFiles(.libs-cache-miss) 门控于是作业在这些步骤被跳过的情况下保持绿色stress 作业的Send alert on failureZulip 步骤以failure() github.event_name schedule门控保持静默。这是刻意为之warmer 独占 main而持续 stress 循环的运行时间交错可能与空缓存或回填中的缓存重叠因此定时未命中是预期现象而非覆盖缺陷。Off main对某个分支的手动workflow_dispatch时它们以消费方模式运行--branch-cache -- cmake … -P lib/build-libs.cmake。先拉主缓存再拉分支缓存全部未命中才构建 LLVM 并推送分支缓存——与 PR 行为完全一致使 LLVM 变更的手动测试不被阻塞且同一分支的再次 dispatch 会复用该构建。这正是这些工作流持有packages: write而非packages: read的原因。模式的拼写方式bash 与 sh 站点用两个环境变量——LIBS_MODE承载--image之前的旗标LIBS_BUILD承载末尾的-- cmake … -P lib/build-libs.cmake该段仅 off-main 存在on-main 时不添加多余参数。PowerShell 无法对变量值做词分割所以 Windows 站点在字面if ($env:LIBS_OFF_MAIN -eq true)下把两种模式完整展开。未命中标记写入GITHUB_WORKSPACE——回退到工作目录即 arm64-linux docker-in-docker 作业的工作区挂载点——使宿主机侧hashFiles门控可见实现见 .ci-scripts/libs-cache/resolve_libs_cache.py。已接受的权衡warmer 覆盖上的永久缺口不再被这些 on-main 作业大声暴露定时未命中只是跳过。它仍会通过拉取同平台的非 stress 消费方浮现。tier2/tier3 的Send alert on failure保持普通failure()而非像 stress 那样以schedule门控——on-main 跳过永不失败所以保持静默但手动运行的构建或测试失败仍会告警。构建镜像与 BSD VM容器平台名由IMAGE_RE经derive_platform从构建镜像引用推导契约是ghcr.io/ponylang/ponyc-ci-name:YYYYMMDD。名称或 tag 破坏该格式的构建镜像会立即失败命名约定变化时更新IMAGE_RE即可。BSD VM 没有构建镜像因此使用显式的按版本标签freebsd-15.1、openbsd-7.9、dragonfly-6.4.2等。warmer 启动这些 VM 构建并推送ponyc-tier3.yml的 BSD 作业拉取。两者都将GITHUB_TOKEN通过 ssh 传入 VM与其他消费方一致。VM 供给是共享的而非复制的两个工作流都从单一Provision VM步骤调用.ci-scripts/bsd/{freebsd,openbsd,dragonfly}-provision.bash。这些脚本释放磁盘、安装 QEMU、下载镜像、启动 VM、安装依赖并将检出 rsync 进去。DragonFly 的脚本再调用.ci-scripts/bsd/dfly_configure_vm.pyQEMUsendkey控制台自动化从PUB_KEY读取 ssh 公钥。修改 VM 配置应改脚本而非两份 YAML。freebsd-provision.bash接受FREEBSD_VERSION并无条件安装doas与doas.conf——对 warmer 无害且简化任何需要 VM 内 root 的操作。VM 内的 libs 处理按平台共享方式与供给相同两个工作流都调用.ci-scripts/bsd/{freebsd,openbsd,dragonfly}-libs-cache.bash operation完成恢复与构建/推送步骤而不是各作业内嵌自己的ssh远程执行。每个脚本持有该平台的 ssh 选项、VM 用户、仓库目录、构建环境、编译器旗标与构建树清理逻辑。operation是restore、build-push-branch、build-push-main之一分别对应分支缓存恢复、分支缓存构建与推送tier3 off-main、主缓存构建与推送warmer。两套脚本都是基于文件的因此 Super-Linter 的 shellcheck 可以覆盖它们——这是内嵌run:块做不到的。dfly_configure_vm_test.py守护KEYMAP反转义、DFLY_MONITOR_SOCK监视器套接字路径契约与dragonfly-provision.bash一致以及让重新键入的配置尝试从干净提示符开始的控制台重置。两个调用方仅在对脚本的调用方式上不同warmer先做宿主机侧oci_libs_cache.py exists检查再尝试宿主机侧 promote 步骤branch_libs_cache.py exists然后promote_libs_cache.py不启动 VM复用已存在的分支工件。它用if: steps.check.outputs.hit ! true steps.promote.outputs.promoted ! true门控Provision VM步骤与终端的构建推送步骤因此主缓存命中或成功 promote 会完全跳过 QEMU 启动。promote 失败非致命promotedfalse会落入 VM 构建。作业在这些步骤被跳过时仍成功而非失败从而满足prune的needs:。tier3同样以宿主机侧缓存检查门控 QEMU 启动并与容器分支一致地按 main/off-main 分流。宿主机侧Check libs cache步骤id: check设置hit输出并且仅在 on-main 时于未命中处写.libs-cache-miss标记使Provision VM及其后所有步骤跳过——定时未命中完全跳过 VM 而非冷构建。Off-main 时它从不写标记主缓存命中或分支缓存命中都设hittrue完全 off-main 未命中设hitfalseVM 内步骤按该输出门控。Restore libshit true用--require-cache-hit --branch-cache拉取且不构建Build libshit false在 VM 内构建 LLVM 并用branch_libs_cache.py push推送分支缓存镜像 warmer 的 VM 内构建但写分支而非主缓存。因此 off-main 时 tier3 确实会把 BSD 构建捕获进分支缓存同一分支的再次 dispatch 可复用——这正是 tier3 持有packages: write的原因。保留与清理主缓存保留按包 keep-Nwarmer 的prune作业运行prune_libs_cache.py --keep 2每个包保留最新的两个版本.ci-scripts/libs-cache/prune_libs_cache.py。平台在包名中而非 tag 中因此 keep-N 按平台计数若把平台移入 tagkeep-N 就会删除属于其他平台的活跃工件。clear唯一的失效手段clear-libs-cache.yml与clear_libs_cache.py是逃生舱。它们整包删除所有ponyc-libs-cache/*包REST API/编码为%2F并重新 dispatch warmer。由于 tag 是内容哈希不存在「触碰以续期」——删除是唯一的失效方式。clear 工作流还需要actions: write权限用于重新预热 dispatch。为什么删除需要两个 token每个 token 只能完成其作用域允许的一半组织级PONYLANG_MAIN_READ_PACKAGE_TOKEN经典 PATread:packages是唯一能枚举组织包的 token——仓库作用域的GITHUB_TOKEN在组织包列表端点会得到 400。但只有GITHUB_TOKENpackages: write能删除这些包因为它们是仓库作用域的组织 PAT 无论 scopes 如何删除时都会得到 404。因此clear_libs_cache.py与prune_libs_cache.py用PONYLANG_MAIN_READ_PACKAGE_TOKEN枚举、用GITHUB_TOKEN删除两个工作流都传入两个 secret。这个拆分也正是保留逻辑写成自定义脚本而非snok/container-retention-policy的原因——后者只拿一个 token在此场景无法「枚举并删除」。分支缓存跨 PR 去重的关键分支缓存是独立缓存拥有自己的命名空间ponyc-branch-libs-cache/platform-arch、自己的 push/pull 脚本branch_libs_cache.py与自己的保留prune_branch_libs_cache.py。它是tag 可寻址的包名只是平台与架构版本是同一个hashFiles内容哈希因此一个分支包正是主缓存的名字换了命名空间前缀。没有-prN组件——早期那个分区设计因不做正确性工作而被移除移除后换来的是跨 PR、跨 tier 的免费去重共享同一 tag 的两个构建内容必然相同。同时这也意味着 warmer 可以手工构造名字用一次existsHEAD 请求找到可提升工件无需枚举。这个缓存存在的意义改变了 LLVM 决定输入的构建——非 fork 的 PR或对分支的 ad-hocworkflow_dispatch如 weekly——只需构建一次 LLVM后续运行直接复用warmer 在合入后可将该构建提升进主缓存而非重建。写入者PR 作业pr_libs_cache.py仅非 fork与 weekly 消费方resolve_libs_cache.py --branch-cache总是推送tier2、tier3 与 stress 也推送但仅 off-main对分支的手动workflow_dispatch。这些工作流没有pull_request触发器所以推送者总是仓库授权的。warmer 只读分支缓存用于提升从不推送分支包提升只写主缓存从而保持 warmer 是主缓存的唯一写入者。分支脚本不 import 主缓存脚本主缓存ponyc-libs-cache始终是事实来源。pr_libs_cache.py消费方模式与 ensure 模式pr_libs_cache.py拥有 PR 作业流程resolve_libs_cache.py的--branch-cache消费方模式为 tier 作业做同样的事。两者都只是围绕工作流在--之后交给它们的构建命令序列化既有缓存原语split_build_command见 .ci-scripts/libs-cache/common.py。两种模式消费方模式默认先查主缓存再带--branch-cache时经pull查分支缓存——命中即下载 blob未命中则运行构建然后带--branch-cache时尽力推送分支缓存。推送失败仅记录警告并降级为「下次运行重建」不失败作业。ensure 模式--ensure相同序列但用exists子命令检查——不下载 blob因为该作业只需知道是否要构建——且分支推送失败会硬失败作业使 registry 写入问题在此暴露而非让每个消费方各自冷构建。--ensure要求--branch-cache。exists子命令同时存在于oci_libs_cache.py与branch_libs_cache.py.ci-scripts/libs-cache/registry.py。它只检查 manifest、不下载 blob存在时退出 0、缺失时退出 1。任何 HTTP 或网络错误都经die以退出 1 结束从而失败安全地退化为「构建」。主缓存命中在任何推送之前短路warmer 因此保持为ponyc-libs-cache的唯一推送者。pr.yml 如何驱动分支缓存只有一个工作流驱动分支缓存pr.yml——合并后的 PR 工作流取代了pr-ponyc.yml、pr-pony-compiler.yml与pr-tools.yml。合并正是跨工作流去重的前提三个套件此前是三个并发工作流各自在缓存未命中时冷构建同一个共享 LLVM 平台而needs:只在工作流内有效。现在对于被两个或更多套件共享的每个平台ubuntu glibc、macOS、Windows一个maybe-build-plat作业运行一次pr_libs_cache.py --ensure消费方作业needs:它并拉取。消费方门控为!cancelled() needs.changes.outputs.suite true needs.maybe-build-plat.result ! failure!cancelled()允许消费方在 maybe-build 被跳过时运行——这是 fork 路径消费方随后不带--branch-cache地拉取或构建。result ! failure在共享构建确实失败时跳过消费方使 LLVM 构建失败只报告一次而非三次。Fork 安全--branch-cache在工作流表达式本身就被门控为非 fork。消费方的LIBS_BRANCH_CACHE环境变量是${{ head.repo.full_name github.repository --branch-cache || }}——非 fork 得旗标fork 得空串从而抑制分支拉取与推送。bash 站点上run:行不加引号地引用它$LIBS_BRANCH_CACHE使 fork 的空值消失而非作为多余空参数传入。加引号会破坏 forkargparse 会看到一个空位置参数并退出 2。PowerShell 不会那样丢弃空变量——它把作为真实参数传入——所以 Windows 站点把旗标构建成数组$bc if ($env:LIBS_BRANCH_CACHE) { ($env:LIBS_BRANCH_CACHE) } else { () }空数组不贡献任何东西。maybe-build 作业的if:已经要求非 fork所以它们字面传递--branch-cache。--branch-cache是布尔值也是脚本读取的唯一非 fork 信号它不携带 PR 号因为缓存是 tag 可寻址的。pr.yml为非 fork 分支推送携带permissions: packages: write。fork 的pull_requesttoken 无论如何都是只读的。绝不要把它切换为pull_request_target——那会把写 token 交给 fork 代码。分支缓存的保留基于年龄保留基于年龄刻意区别于主缓存的 keep-N。prune-branch-libs-cache.yml每日schedule加workflow_dispatch运行prune_branch_libs_cache.py删除超过两周的分支缓存工件并在一个包的所有版本都过期后丢弃该包——例如退役构建镜像的平台。现在按平台的包是长期存在的而非按 PRkeep-N 永远不会删除闲置包因此需要独立脚本。它使用与主缓存保留相同的双 token 拆分用PONYLANG_MAIN_READ_PACKAGE_TOKEN枚举、GITHUB_TOKEN删除。它只在自己的命名空间内枚举与删除碰不到主缓存主缓存的prune_libs_cache.py同样过滤ponyc-libs-cache/永远看不到分支包——两个 prune 不会交叉。分支缓存没有clear 或逃生舱工作流基于年龄的 prune 是唯一的回收手段。实践要点速览新增消费平台先确认 warmer 在正确阶段覆盖了该平台否则每次运行必然未命中。新增 ISA必须显式加入 .ci-scripts/libs-cache/cache_arch.py 的ARCH_ALIASES否则硬失败。变更镜像命名同步更新IMAGE_RE否则所有容器作业立即失败。仓库外复用的最小入口消费方模式一条命令即可——resolve_libs_cache.py [--branch-cache] (--image ref | --platform label) --tag hash -- build command...构建命令示例为cmake -DJOBS4 -P lib/build-libs.cmakeWindows 上为cmake -DPRESETlibs-windows-x86-64 -P lib/build-libs.cmake。关注点分离构建命令lib/build-libs.cmake只负责构建所有缓存决策都在.ci-scripts/libs-cache/的编排脚本中这套分层让缓存逻辑的演进如本文中的 promote、ensure、skip-on-miss 模式无需触碰构建本身。整个体系的可运行验证不仅存在于工作流中也沉淀为脚本同目录的单元测试如pr_libs_cache_test.py、resolve_libs_cache_test.py、promote_libs_cache_test.py、cache_arch_test.py、package_name_test.py、repo_root_test.py以及 BSD 侧的dfly_configure_vm_test.py它们守护着包命名、repo 根路径推导与编排序列等最易出错的环节。赞分享编程语言编译器语言运行时【免费下载链接】ponycPony is an open-source, actor-model, capabilities-secure, high performance programming language项目地址https://gitcode.com/gh_mirrors/po/ponyc点击查看免费下载相关推荐ponyc CI 辅助脚本工程化指南.ci-scripts 的代码约定、自包含测试与 libs 缓存实战ponyc CI 辅助脚本工程化指南 .ci scripts 的代码约定、自包含测试与 libs 缓存实战 .ci scripts 是 ponyc 仓库中供编程语言编译器语言运行时BAML 发布 CI 的 GCP 容器镜像缓存基于 Artifact Registry 远程仓库的 GHCR 拉取缓存实践BAML 发布 CI 的 GCP 容器镜像缓存基于 Artifact Registry 远程仓库的 GHCR 拉取缓存实践 本指南系统讲解 BAML Lang编程语言AI Agent编译器CLI人工智能Bisheng缓存优化多级缓存架构的设计实现Bisheng缓存优化多级缓存架构的设计实现 引言企业级LLM应用的缓存挑战 在大规模语言模型LLM应用的企业场景中缓存系统面临着前所未有的挑战。Bi人工智能大模型AI 应用LLMOpsRAGAI Agent工作流自动化后端前端上一篇oam-tools 中的 HCCL Test昇腾 NPU 集合通信性能与正确性测试工具的架构与实战下一篇Imposm3与Docker集成容器化部署OpenStreetMap数据管道的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表