跳到主要内容
Agent Memory 分离式协同

第4章:鲲鹏路线 1——基于 UB 内存池的上下文缓存系统

把"中间数据搬出 LLM 上下文"做成跨节点共享的工程底座——展开数据流、内存布局、典型负载下的延迟分布;和路线 D 单机上下文缓存做精确对照;给出可复现的最小工程骨架

鲲鹏 UB 内存池 上下文缓存 中间数据 跨节点共享 Prefix Cache

Ch3 结尾给出三处缝隙——这一章正面攻破第一条:跨节点共享的”中间数据池”。鲲鹏 2026 公开方案把这件事建在 UB(统一总线)共享域内存池上,目的是让多步工具链 / 多 Agent 协作时的中间结果不再走 LLM 上下文中转——而是落到一份所有 Agent 进程都能访问的高速共享内存里。这件事的工程红利不只是”省 token”——更深的是把 prefill TTFT 的平方代价直接砍掉。本章把这套系统的数据流、内存布局、延迟分布逐一拆开。

📑 目录


1. 鲲鹏路线 1 要解决的具体痛点

1.1 单机上下文缓存的三个工程缺口

Ch3 的路线 D(上下文缓存)方向是对的,但当前业内单机实现有三个具体缺口:

缺口表现真实代价
跨进程不可见Agent A 缓存的中间结果 Agent B 看不到多 Agent 协作必须在每个 Agent 重新算一遍
跨节点不可见推理服务做了 PD 解耦后,Prefill 节点的缓存 Decode 节点看不到KV cache / 工具结果都得跨网传
生命周期粗糙单机内存压力大就直接逐出,没有”按用户/按会话”的细粒度策略高频用户的会话 cache 频繁丢失

这三个缺口共有一个根本原因:当前上下文缓存被实现为”进程内 / 单机内”的数据结构——而 Agent Memory 真正的工作负载是跨进程、跨节点、跨会话的。

1.2 鲲鹏路线 1 的核心定位

把这件事放在系统架构图里:

        ┌─────────────────────────────────────┐
        │      用户 / 应用层                  │
        └──────────────┬──────────────────────┘

        ┌──────────────▼──────────────────────┐
        │   Agent Harness (LangGraph / OpenClaw 等) │
        │   - 工具调度                         │
        │   - 上下文组装                       │
        └─────────┬───────────────────────┬────┘
                  │                       │
        ┌─────────▼─────────┐    ┌────────▼─────────┐
        │  Prefill 节点 1   │    │  Prefill 节点 2  │
        │  Decode 节点 1    │    │  Decode 节点 2   │
        └─────────┬─────────┘    └────────┬─────────┘
                  │                       │
                  └───────────┬───────────┘

            ┌─────────────────────────────────────┐
            │   ⭐ UB 共享域内存池(鲲鹏路线 1) │
            │   - 跨节点 / 跨进程共享              │
            │   - 中间数据 / KV cache / 工具结果  │
            │   - 微秒级随机读                    │
            └─────────────────────────────────────┘

🌟 核心定位:把”上下文缓存”从单机数据结构升级为跨节点共享的系统服务——这是鲲鹏路线 1 的工程原创性。

2. UB 内存池:硬件底座的关键属性

2.1 UB 是什么

UB(Unified Bus,统一总线)是华为面向数据中心场景定义的高速互联协议。从 Agent Memory 系统的视角,它的关键属性可以归纳为四条:

属性数值范围工程含义
单次访问延迟微秒级(典型 1-3 µs)接近本地 DRAM 量级,比 SSD 快 50-100x
单链路带宽数十到上百 GB/s接近 PCIe 5.0 / DDR5 带宽
池容量跨节点合池单机 DIMM 装不下时仍能扩
协议特性load/store 语义 + RDMA 原语既能像内存一样访问,也能像 RDMA 一样原子操作

🍎 直觉比喻:本地 DRAM 是”你的座位旁边的小抽屉”,单机 SSD 是”办公室档案柜”——UB 内存池是部门所有人共享的高架资料柜,离每个人都很近,但是不在每个人面前

2.2 为什么 UB 适合做”上下文缓存”

把 Agent Memory 系统的访问模式画出来:

访问类型频率数据大小延迟敏感度
工具调用结果写入中(每秒数十次)KB-MB 级
工具调用结果读取中-高KB-MB 级
KV Cache 跨节点共享高(每 token)几十 MB极高
长会话历史读写低-中KB 级

UB 内存池的”微秒级 + 几十 GB/s + 跨节点共享”这三个属性恰好同时命中这四类访问的最严格者(KV Cache 共享)。这是它作为”上下文缓存底座”的天然适配。

2.3 UB 不能解的事

公平地说,UB 也不是万能的:

  • 比 DRAM 仍慢 30-50x——HBM / DRAM 内的数据不应该被搬到 UB 池
  • 跨节点协议有头部开销——超小数据(几十字节)单次访问性价比低
  • 运维复杂度高——需要专用网络、专用驱动、专用协议栈

把这些限制翻译过来:UB 适合做KB-MB 量级、跨节点必需、可批量访问的中间数据 / KV cache;不适合做高频微小元数据 / 仍需 DRAM 速度的热数据

3. 上下文缓存的数据流与内存布局

3.1 一次”工具调用”的完整数据流

把 Agent 调用一个工具(比如 search 返回 5 篇文档)的完整数据流画出来:

   Step 1: Agent 决定调用 search


   Step 2: Harness 把 search 的请求参数组装好


   Step 3: 调 search 工具


   Step 4: search 返回 5 篇文档(~15K tokens)

       ├── 4a. ⭐ Harness 把文档原文写入 UB 内存池
       │       (key: ctx_42_search_step3, ttl: 1h)


   Step 5: Harness 给 LLM 上下文里只放:
       │   "<search_result id='ctx_42_search_step3' summary='5 papers about...'>"
       │   (~200 tokens, 不是 15K)


   Step 6: LLM 决定下一步——可能引用 step3 也可能不引用


   Step 7: 如果 LLM 决定 "summarize step3"

       ├── 7a. ⭐ Harness 从 UB 池读回原文
       │       (read by id, latency ~1-3 µs)

       ├── 7b. 把原文 chunked 后传给 summarize 工具


   Step 8: summarize 输出摘要(~1K tokens)

       ├── 8a. 摘要写入 UB 池 (key: ctx_42_summary_step7)

   Step 9: LLM 上下文里只保留 step3 + step7 的指针 + 摘要

关键观察:在这个流里,LLM 上下文从未直接持有 15K 原文——只持有”指针 + 短摘要”。原文只在工具间传递时被取出来用一次。

3.2 UB 内存池的内存布局

实现这个数据流,UB 内存池里至少要维护四类 region:

Region数据类型生命周期
ctx_<sess>_<step>工具调用中间结果会话级 / 步级
kv_<sess>_<layer>KV Cache 跨节点共享段推理生命周期
hist_<user>_<turn>长会话历史用户级(带时效衰减)
meta_<obj_id>上述各类的元数据 / 摘要 / 索引同源 region

每个 region 都有:

struct UBRegion {
    uint64_t  id;                  // 全局唯一
    uint32_t  size;                // 实际占用
    uint8_t   tier;                // 0=hot, 1=warm, 2=cold
    uint64_t  created_at;
    uint64_t  ttl_ms;
    uint32_t  ref_count;           // 跨节点引用计数
    char      content[];           // 实际数据
};

引用计数 ref_count 是关键——它让”跨节点共享”变得可显式管理

  • Prefill 节点 1 写入一段中间结果 → ref_count = 1
  • Decode 节点 2 读这段时持有引用 → ref_count = 2
  • 两端都释放后才被 GC

3.3 与 KV Cache 体系的耦合

不只是工具调用结果——KV Cache 本身也可以放进 UB 池。这件事在 PD(Prefill-Decode)解耦推理里特别有价值:

  • Prefill 节点把 KV cache 写到 UB 池
  • Decode 节点直接从 UB 池读取——不需要把 KV cache 通过网络再传一遍

这等价于把第十四模块《长记忆大模型系统》第 4 章讨论的 LMCache / AttentionStore / Mooncake 这一类工作的工业落地直接套进了同一份硬件底座。

🌟 关键判断:上下文缓存和 KV cache 跨节点共享是同一种系统能力的两个切片——它们都需要”跨节点 + 微秒级 + 大容量”的中间档介质。鲲鹏路线 1 把它们统一在同一份 UB 池里,这是它的工程经济学。

4. 典型负载下的延迟与成本分布

4.1 三类典型负载

把鲲鹏路线 1 在三种典型 Agent 负载下的关键指标对照:

负载工具数中间数据规模多节点协作
轻负载客服5-10总计 ~5K tokens单节点
中负载工作助手30-60总计 ~50K tokens2-4 节点
重负载 BI / 多 Agent60+总计 ~200K+ tokens4-8 节点

4.2 延迟和成本对照

指标中负载工作助手重负载多 Agent
基线(单机内 LLM 上下文走全部中间数据)
单次 prefill TTFT~3 秒~15 秒
总 token 消耗 / 任务~50K~250K
任务总成本(GPT-4 价位)~$0.30~$1.50
+ 鲲鹏路线 1(UB 上下文缓存)
单次 prefill TTFT~0.8 秒~3.5 秒
总 token 消耗 / 任务~15K~70K
任务总成本~$0.09~$0.42
改善TTFT ↓ 70%, 成本 ↓ 70%TTFT ↓ 75%, 成本 ↓ 72%

观察改善并不是”线性叠加”——它在重负载下的相对收益反而更大。原因是 prefill 的 O(n2)O(n^2)——把 prompt 砍一半,prefill 时间砍 75%。

4.3 UB 池本身的延迟开销

加入 UB 内存池一层会引入额外的访问开销:

操作单次开销触发频率累计延迟
写中间结果到 UB~3-5 µs每工具一次工具调用占大头,~µs 不显著
从 UB 读回~1-3 µsLLM 引用时同上
跨节点引用建立~10-20 µs跨节点协作时显著但仍 < 1ms
GC / ref_count 维护异步周期性不在关键路径

总额外延迟 < 1 ms 量级——相比节省的几秒级 prefill 时间,完全可以接受

5. 与单机上下文缓存的精确对照

维度单机上下文缓存 (路线 D)鲲鹏路线 1 (UB 上下文缓存)
缓存位置进程内 / 单机内跨节点共享池
跨进程可见
跨节点可见
KV cache 共享
写入延迟< 1 µs(本地内存)~3-5 µs
读出延迟< 1 µs~1-3 µs
容量单机内存上限池容量(多机合池)
生命周期管理简单 LRU多 tier + ref_count
工程复杂度中-高(需要新硬件 / 协议栈)
适用场景单 Agent / 单机推理多 Agent 协作 / PD 解耦推理

🌟 关键判断:路线 D 没有错——它在单 Agent / 单机场景下完全够用。鲲鹏路线 1 是路线 D 的”超集”——它把同样的能力扩展到跨节点场景,但代价是引入新硬件和工程复杂度。这个取舍是否合算,取决于你的工作负载:

  • 单机轻负载 → 路线 D 就够
  • 多 Agent 协作或 PD 解耦推理 → 鲲鹏路线 1 的红利显著

6. 最小工程骨架

把鲲鹏路线 1 的核心机制用 Python 伪代码写出来,作为团队对照设计的起点:

import time
import uuid
from dataclasses import dataclass, field
from typing import Optional

# ═══════════════════════════════════════════════════════════
# UB 内存池抽象(实际实现在 C/Rust + 专用驱动)
# ═══════════════════════════════════════════════════════════

@dataclass
class UBRegion:
    rid: str
    content: bytes
    size: int
    tier: int = 0           # 0=hot, 1=warm, 2=cold
    created_at: float = field(default_factory=time.time)
    ttl_ms: int = 3600 * 1000
    ref_count: int = 1
    summary: str = ""       # 给 LLM 上下文用的短摘要

class UBPool:
    """跨节点共享内存池——伪实现"""
    def __init__(self):
        self.regions: dict[str, UBRegion] = {}

    def write(self, content: bytes, summary: str, ttl_ms: int = 3600*1000) -> str:
        rid = str(uuid.uuid4())
        self.regions[rid] = UBRegion(
            rid=rid, content=content, size=len(content),
            ttl_ms=ttl_ms, summary=summary,
        )
        return rid

    def read(self, rid: str) -> Optional[bytes]:
        r = self.regions.get(rid)
        return r.content if r else None

    def get_summary(self, rid: str) -> str:
        r = self.regions.get(rid)
        return r.summary if r else ""

    def acquire(self, rid: str):
        if rid in self.regions:
            self.regions[rid].ref_count += 1

    def release(self, rid: str):
        if rid in self.regions:
            self.regions[rid].ref_count -= 1
            if self.regions[rid].ref_count <= 0:
                del self.regions[rid]


# ═══════════════════════════════════════════════════════════
# Harness 端:把"中间数据搬出 LLM 上下文"
# ═══════════════════════════════════════════════════════════

class ContextCachingHarness:
    def __init__(self, ub_pool: UBPool):
        self.pool = ub_pool

    def call_tool_with_caching(self, tool_func, *args, **kwargs):
        """调用一个工具,把结果写入 UB 池,返回指针 + 摘要"""
        result = tool_func(*args, **kwargs)
        # 1. 把完整结果序列化
        payload = serialize(result)
        # 2. 生成简短摘要(让 LLM 在上下文里能"看见"这件事)
        summary = make_summary(result, max_tokens=100)
        # 3. 写入 UB 池
        rid = self.pool.write(payload, summary=summary)
        # 4. 返回 LLM 上下文用的"指针 + 摘要"
        return f"<cached id='{rid}' summary='{summary}'/>"

    def materialize_for_step(self, rids: list[str], target_tool):
        """LLM 决定要把某些缓存的中间数据传给下一步工具时使用"""
        actual_payloads = []
        for rid in rids:
            self.pool.acquire(rid)
            actual_payloads.append(self.pool.read(rid))
        try:
            return target_tool(*actual_payloads)
        finally:
            for rid in rids:
                self.pool.release(rid)


# ═══════════════════════════════════════════════════════════
# 用法示例
# ═══════════════════════════════════════════════════════════

pool = UBPool()
harness = ContextCachingHarness(pool)

# Agent 第一步:调 search
search_pointer = harness.call_tool_with_caching(
    search_tool, query="best SSD for AI training")
# search_pointer 是 "<cached id='abc-123' summary='5 papers, ranked by ...'/>"
# 它进入 LLM 上下文——只占 ~50 tokens 而不是 ~15K

# LLM 决定 summarize 这条 search 结果
search_rid = parse_id(search_pointer)
summary_result = harness.materialize_for_step(
    rids=[search_rid], target_tool=summarize_tool)
# summarize_tool 拿到完整原文,但 LLM 上下文里只看到指针

这份代码不到 80 行,但它体现了鲲鹏路线 1 的核心机制:

  1. 写入时给 LLM 留摘要 + 指针——LLM 上下文只看到 <cached id summary/>
  2. 真正引用时由 Harness 物化——把 UB 池的内容传给下一步工具
  3. 引用计数 + ref_count 自动 GC——跨节点协作不会泄漏

🍎 直觉比喻:这套机制好比把”会议室的所有文件”搬到”档案柜”——会议室里只放”文件号清单”,谁要用到具体文件就去柜子里取一下。这样会议室空气清新,prefill 也快。

🎯 自我检验清单

  • 单机上下文缓存(路线 D)和鲲鹏路线 1 的核心区别是什么?跨节点协作场景下哪一类性价比更高?
  • UB 内存池的”微秒级 + 几十 GB/s + 跨节点共享”这三个属性各自命中哪些 Agent Memory 访问模式?
  • 解释”prefill TTFT 是 O(n2)O(n^2)“——为什么把上下文砍一半能让 TTFT 快 4 倍而不是 2 倍?
  • 在第 6 节最小骨架里,acquire / release 引用计数解决的是什么具体的工程问题?
  • 如果你的项目目前是单机推理 + 单 Agent,路线 D 就够吗?什么时候才值得迁移到鲲鹏路线 1?

📚 参考资料

  • 鲲鹏 Agent Memory 创新方案(华为鲲鹏团队 2026 公开发表)—— 路线 1 详细技术披露
  • 本系列模块十三 第 6 章 RDMA verbs 实战
  • 本系列模块十四 第 4 章 KV Cache 跨层级管理论文精读(LMCache / AttentionStore / Mooncake 等)
  • CXL 3.0 Specification(2024)
  • Mooncake(KAIST + Moonshot 2024)—— PD 解耦推理 KV cache 跨节点共享代表作
  • NVIDIA NIXL(2025)—— 推理框架的 KV cache 抽象层

下一章预告:Ch5 进入鲲鹏路线 2——基于 UB 内存池的全局向量检索——用同一份共享底座装下千亿级 HNSW 整图,避开 Ch3 路线 E(HNSW 分片)的召回质量损失。