← 跨产品 Agent 系统的参考架构
📚 读书笔记

《跨产品 Agent 参考架构》读书笔记

· 约 12 分钟 · 4200 字

这一页是给我自己用的工具页,不是给读者的阅读页。包含完整脉络、代码、架构图、面试话术。 如果你只想看精炼版,请回到 主文章

1. 主文章在讲什么(30 秒)

一句话主线:把五层 stack 拆成共享底座(Memory/Agents框架/Skill引擎/Rules+Hooks/协议适配器)+ 产品特定顶层(Personas/Specialists/Skills)。底座做成内部 SDK,每个产品 import 它,加自己的顶层。茶会、Amber、Mumu 都坐在同一个底座上。

反对什么观点

  • 反对”每个产品独立设计 agent 架构”——重复发明
  • 反对”所有产品共用同一个 Persona/Specialist”——不可能,每个产品视角不同
  • 反对”先做 SDK 再做产品”——抽象应该从实践中浮现

如果只能记一句话

共享底座 + 产品特定顶层 = 一个产品的架构变成所有未来产品的平台。


2. 关键概念词典

共享底座 vs 产品特定顶层

共享底座产品特定顶层
包含Memory架构、Agent框架、Skill引擎、Rules/Hooks机制、协议适配器Personas、Specialists、Skills
跨产品完全相同完全不同
改动频率低(架构级)高(产品迭代)
由谁维护平台团队(或一个人)各产品团队
实现npm package @teaparty/agent-sdk各产品代码库

“framework”和”实现”的区别

Persona/Specialist 框架(底座)具体的 Persona/Specialist(顶层)
例子class Persona { loadFromMarkdown(); enforceAntiSycophancy() }coach_persona.mdscoring_specialist.yaml
跨产品
改动框架升级 → 所有产品受益产品迭代 → 只本产品受影响

渐进迁移 vs Big Bang

渐进Big Bang
风险低(小步快跑)高(一次性巨变)
时间长(6-8 周)短(理论上)
学习实时反馈等到最后
回滚简单几乎不可能

我推荐渐进——不只是因为风险低,是因为抽象是迁移过程中浮现的,不是预先猜的


3. 完整脉络(主文章每节展开)

共享底座的五个部件,详细

1. Memory 架构(最重要,也最先做)

完整 6 子层。关键设计:作为 MCP server 暴露——任何 agent 系统都能消费。

┌─────────────────────┐
│  Memory MCP Server   │ ← 暴露统一接口
├─────────────────────┤
│  Conceptual layer    │
│  Graph               │
│  Temperature model   │
│  Episodic            │
│  Atomic facts        │
│  Type-aware storage  │
└─────────────────────┘
       ↑ MCP 协议

   各产品(Amber、Mumu)通过 MCP 调用

为什么是 MCP?因为 MCP 是标准协议,未来换 agent 框架时 Memory 不动

2. Persona/Specialist 框架

// 底座定义
abstract class Persona {
  abstract loadFromMarkdown(path: string): PersonaConfig
  abstract enforceAntiSycophancy(prompt: string): string
  abstract callWithTopic(topic: string, history: Statement[]): Promise<Statement>
}

abstract class Specialist {
  abstract loadFromYAML(path: string): SpecialistContract
  abstract checkQuality(artifact: any): QualityCheckResult
  abstract executeTask(task: Task): Promise<Artifact>
}

框架是抽象,不是实例。具体的 architect_persona、coach_persona 是产品/茶会自己定义的实例。

3. Skill 引擎

class SkillRunner {
  constructor(private graph: LangGraphInstance) {}
  
  async execute<T>(skill: Skill, input: T): Promise<SkillResult> {
    // 内部用 LangGraph
    // 但接口是稳定的——换框架不破坏调用方
    const checkpointer = new D1Checkpointer(env.DB)
    const tracer = new LangFuseTracer(env.LANGFUSE_KEY)
    return await this.graph.invoke(input, { checkpointer, tracer })
  }
}

SkillRunner 是接口,LangGraph 是实现细节。这是”对原则写代码而非对框架写代码”的具体体现。

4. Rules + Hooks 机制

// 底座提供
class RuleEngine {
  registerRule(pattern: PathPattern, action: Action) { ... }
  trigger(event: Event) { ... }
}

class HookEngine {
  registerHook(lifecycle: LifecyclePoint, action: Action) { ... }
}

// 产品使用
ruleEngine.registerRule(
  'parties/*/roundtables/*.md',
  extractAtomicFacts
)

5. 协议适配器

// 底座提供 MCP server / A2A endpoint 模板
class MCPServer { ... }
class A2AEndpoint { ... }

// 任何产品都自动能:
// - 暴露自己的 memory 给其他 agent 消费(MCP)
// - 接收和发送 A2A 任务(跨系统)

产品特定顶层的具体形态

Amber 的完整顶层

amber/
├── personas/
│   ├── coach.md
│   ├── interviewer.md
│   └── realist.md
├── specialists/
│   ├── scoring.yaml
│   ├── question_generator.yaml
│   └── debrief.yaml
├── skills/                    ← LangGraph DAG 定义
│   ├── start_practice.ts
│   ├── run_mock.ts
│   └── give_debrief.ts
├── rules/
│   ├── after_mock_episodic.ts
│   └── pattern_extraction.ts
└── hooks/
    ├── session_start.ts
    └── session_end.ts

package.json 依赖:

{
  "dependencies": {
    "@teaparty/agent-sdk": "^1.0.0"
  }
}

Amber 的代码 = 顶层定义 + 业务逻辑。底座完全在 SDK 里,不重写

Mumu 的完整顶层

mumu/
├── personas/
│   └── director.md           ← 仅 1 个,可选用
├── specialists/
│   ├── video_generator.yaml
│   └── video_reviewer.yaml
├── skills/
│   ├── submit_video_task.ts  ← 用底座的 A2A 状态
│   └── review_video.ts
└── rules/
    └── episodic_on_complete.ts

Mumu 的顶层比 Amber 简单——这反映了 Mumu 是任务驱动产品。同一个底座支持不同复杂度的顶层

茶会作为验证场,详细

茶会是最复杂用例——multi-persona 圆桌 + multi-phase sprint。如果 SDK 能 host 茶会,简单产品(Mumu)必然能 host。

茶会的迁移不只是”自己变好”——更重要的是:

它强制把抽象从茶会特定代码里逼出来

举例:迁移 /sprint 时,会发现:

  • “并行 reviewer” 是茶会特有的吗?不,是 SkillRunner 的通用能力 → 抽到底座
  • “写 episodic 记录” 是茶会特有的吗?不,是 Rule 引擎的通用能力 → 抽到底座
  • “扫描 ateliers/dev/” 是茶会特有的吗?是 → 留在茶会顶层

抽象是迁移过程浮现的,不是预先猜的——这是为什么”先做 SDK 再用 SDK”是错的。

渐进迁移路径,详细

主文章给了 6 phase。这里加每 phase 的验证标准——什么算成功。

Phase验证标准
1 框架bun run skill --name=hello 跑通;LangFuse 看到 trace
2 /review新版输出和旧版一致
3 /roundtablepersona 反谄媚规则仍然生效;圆桌输出有真分歧
4 /sprint4 个 reviewer 真并行(trace 显示);checkpoint 能恢复
5 稳定1 周内零故障
6 抽 SDKAmber 能 import @teaparty/agent-sdk 并跑 hello-world

没通过验证不进下一 phase——这是渐进的核心纪律。


4. 真实代码 / 数据

底座目录结构

@teaparty/agent-sdk/
├── src/
│   ├── memory/
│   │   ├── mcp-server.ts      ← Memory 作为 MCP server 暴露
│   │   ├── episodic.ts
│   │   ├── atomic-facts.ts
│   │   ├── temperature.ts
│   │   └── graph.ts
│   ├── agents/
│   │   ├── persona.ts          ← Persona 抽象类
│   │   ├── specialist.ts       ← Specialist 抽象类
│   │   └── anti-sycophancy.ts  ← 反谄媚规则强制
│   ├── skills/
│   │   ├── skill-runner.ts     ← LangGraph 包装
│   │   ├── checkpointer-d1.ts  ← D1 持久化
│   │   └── tracer-langfuse.ts
│   ├── rules/
│   │   ├── rule-engine.ts
│   │   └── hook-engine.ts
│   └── protocols/
│       ├── mcp.ts              ← MCP server 模板
│       └── a2a.ts              ← A2A endpoint 模板
├── package.json
└── README.md

一个产品如何 import

Amber 的 apps/coach/index.ts

import {
  Persona,
  Specialist,
  SkillRunner,
  RuleEngine,
  HookEngine,
  createMemoryClient,
} from '@teaparty/agent-sdk'

// 加载产品特定的 persona/specialist
const coachPersona = await Persona.loadFromMarkdown('./personas/coach.md')
const scoringSpecialist = await Specialist.loadFromYAML('./specialists/scoring.yaml')

// 定义产品特定的 skill(用底座的 SkillRunner)
const startPractice = new SkillRunner({
  nodes: {
    diagnose: diagnoseWeakSpot,
    generate: questionGenerator(scoringSpecialist),
    score: scoreAnswer(scoringSpecialist),
    feedback: coachPersona.callWithContext,
  },
  edges: [
    ['START', 'diagnose'],
    ['diagnose', 'generate'],
    ['generate', 'score'],
    ['score', 'feedback'],
    ['feedback', 'END'],
  ],
})

// 触发 Amber 启动
const memory = await createMemoryClient(env.MEMORY_MCP_URL)
const result = await startPractice.execute({
  userId: '...',
  topic: 'estimation',
  memory,
})

Amber 不写 Memory 实现、不写 LangGraph 集成、不写反谄媚规则——这些都来自 SDK

数据:迁移到底省多少

假设当前每个新产品花 3 周搭基建(memory + agent loop + retry + 重试 + episodic)。

迁移完成后:

  • 第 2 个产品(Amber 重构):省 3 周
  • 第 3 个产品(Mumu 重构):省 3 周
  • 第 4 个产品(未来 X):省 3 周
  • 持续:每个新产品都省 3 周

迁移成本:6-8 周(茶会改造)。

ROI 平衡点:第 3 个产品。之后每个产品净赚 3 周


5. 架构图

图 1:底座 + 顶层的二分

   Amber 顶层          Mumu 顶层          TeaParty 顶层
   ─────────         ─────────          ───────────
   coach_persona     director_persona   architect_persona
   scoring_spec      video_gen_spec     dev_team_spec
   start_practice    submit_video       /sprint
        │                  │                  │
        └──────────┬───────┴──────────┬──────┘
                   ↓ all import       ↓
            ┌─────────────────────────────┐
            │  @teaparty/agent-sdk        │
            │                              │
            │  Memory (MCP server)         │
            │  Persona / Specialist 框架   │
            │  Skill 引擎 (LangGraph 包装) │
            │  Rules + Hooks 机制          │
            │  MCP / A2A 协议适配器        │
            └─────────────────────────────┘
所有产品共享底座,顶层各自定义

图 2:迁移的 6 phase 时序

   时间 →
   
   Week 1  ┌─────────────────┐
           │ Phase 1: 框架     │  搭 SDK 骨架
           └─────────────────┘
   
   Week 1.5 ┌────────────┐
            │ Phase 2:    │   /review PoC
            │ /review     │
            └────────────┘
   
   Week 2  ┌──────────────────┐
           │ Phase 3:           │  /roundtable
           │ /roundtable        │
           └──────────────────┘
   
   Week 3-4 ┌─────────────────────┐
            │ Phase 4: /sprint     │  最复杂
            └─────────────────────┘
   
   Week 5-6 ┌──────────────────────┐
            │ Phase 5: 稳定化        │  并行运行
            └──────────────────────┘
   
   Week 7+ ┌─────────────────────────┐
           │ Phase 6: 抽 SDK + Amber  │  其他产品 import
           │ 采用                      │
           └─────────────────────────┘
   
   每 phase 必须通过验证才进下一个。
渐进迁移,每 phase 有明确验证

图 3:抽象不是预先猜的,是迁移浮现的

   预先设计 SDK              迁移浮现 SDK
   
   "我猜 Memory 应该          "迁移 /sprint 时发现:
    有 X、Y、Z 接口"           - 并行 reviewer 是通用 → 抽
                              - episodic 写入是通用 → 抽
                              - 扫 ateliers/ 是茶会特定 → 不抽
   
   ↓                          ↓
   
   猜对一半                    抽出真正用得上的
   过度设计                    刚好够用
   半年后大改                  迭代稳定
预先猜的抽象 vs 迁移中浮现的抽象

6. 我的批注

我和我以前的想法的冲突

以前:我以为”做平台”是大公司才能做的事。 现在单人 + 6 周可以做出 MVP 平台——只要承诺做共享底座。做不出来的原因不是规模,是没有”为未来产品想”的纪律

以前:我把”SDK 抽象”和”产品代码”当成两件事——SDK 团队做 SDK,产品团队做产品。 现在它们应该是同一个人/团队做抽象是从产品中浮现的,分开做就是猜抽象——必然过度设计。

以前:我倾向”重构 = 一次性大改”。 现在渐进迁移的真正价值不是降低风险,是让抽象有机会浮现。Big Bang 必然过度设计。

反复想过的部分

为什么 Memory 暴露成 MCP server 而不是直接 import——因为 Memory 是最稳定的层,应该是协议化的服务而不是 import。这样:

  • 未来换 agent 框架,Memory 不动
  • 多个产品同时消费同一个 Memory(如 Amber + Mumu 共享同一个用户记忆?)
  • Memory 可以独立 deploy + scale

为什么 SkillRunner 包 LangGraph 而不是直接用 LangGraph——因为 LangGraph 是最不稳定的层(框架更新、商业化变化)。SkillRunner 接口稳定,未来换框架时业务代码不动

为什么 Persona / Specialist 是抽象类而不是具体框架——因为这两个概念很稳,实现可能演进。抽象类强制接口,让具体实现可以替换(比如未来 Persona 可能从 markdown 改成 GraphQL schema,接口不变)。

下次会改的

  • MCP server 的多租户——目前茶会的 Memory 是单租户(K 自己)。Amber/Mumu 上线后需要按 user_id 隔离。MCP server 接口要预留 tenant_id 参数
  • Skill 之间的 composition——目前每个 skill 是独立 graph。应该支持 skill 嵌套(一个 skill 调用另一个 skill)——LangGraph 的 sub-graph 能做。
  • 顶层定义的版本化——Amber 的 coach_persona.md 改了之后,旧的 episodic 记录是不是还有效?需要 persona 的版本字段——否则记忆和当前 persona 错位。

7. 面试话术(按时长背三档)

30 秒电梯版

30 秒电梯版 在走廊里被截住时

做多个 AI 产品时最容易犯的错:每个产品独立设计 agent 架构。结果是每个产品花 3 周搭基建,架构学习不在产品间转移。我的方案:把五层 stack 拆成共享底座(Memory/Agents 框架/Skill 引擎/Rules+Hooks/协议适配器)+ 产品特定顶层(Personas/Specialists/Skills)。底座做成 SDK,每个产品 import。Amber、Mumu、茶会都坐在同一个底座上——新产品 90% 时间花在让它不同的事上,不是重建 agent loop。

2 分钟白板版

2 分钟白板版 会议室开场

关键 insight:五层 agent stack 干净地拆成两块——

共享底座(跨产品相同)

  • Memory 架构(6 子层)— 暴露成 MCP server
  • Persona/Specialist 框架(抽象类)
  • Skill 引擎(LangGraph + LangFuse 包装)
  • Rules + Hooks 机制
  • MCP/A2A 协议适配器

产品特定顶层(各自不同)

  • 具体的 Personas
  • 具体的 Specialists
  • 具体的 Skills(DAG 定义)

举例:Amber 的顶层是 coach_persona.md + scoring_specialist.yaml + start_practice.ts。Mumu 的顶层是 video_generator_specialist.yaml + submit_video_task.ts。两个产品底座完全相同,顶层完全不同

为什么先迁茶会

  1. 最复杂用例——能 host 茶会就能 host 简单产品
  2. 失败成本最低——没付费用户
  3. 迁移过程强制把抽象逼出来——抽象是浮现的,不是猜的

ROI:迁移 6-8 周。第 3 个产品采用时回本,之后每个产品净赚 3 周。

结果:从”跑多个 AI 产品”到”跑一个 AI 产品平台”。

10 分钟深入版

10 分钟深入版 完整论证

先讲为什么这是个真问题。我做了茶会、Amber、Mumu 三个产品。每个都有 agent 系统。如果按传统方式做——每个产品独立设计——结果是:

  • 每个产品花 2-4 周搭基建(memory、agent loop、retry、episodic)
  • 同一个改进(更好的 trace)要在每个产品里重做
  • 架构学习不在产品间转移

所以我提出:把五层 agent stack 拆成两块——共享底座 + 产品特定顶层。

共享底座包含什么

第一,Memory 架构。完整 6 子层(Memory as Foundation)。关键设计:暴露成 MCP server——任何 agent 系统都能消费。为什么是 MCP?因为它是标准协议,未来换 agent 框架时 Memory 不动。

第二,Persona/Specialist 框架。提供抽象类 PersonaSpecialist,强制接口(loadFromMarkdown、enforceAntiSycophancy、checkQuality 等)。框架是抽象,具体实例是产品定义

第三,Skill 引擎。LangGraph 包在 SkillRunner 类里。SkillRunner 接口稳定,LangGraph 是实现细节——未来换框架业务代码不动。

第四,Rules + Hooks 机制。RuleEngine、HookEngine 提供注册接口。具体规则各产品定义。

第五,协议适配器。MCP server / A2A endpoint 作为底座的内置能力。任何产品免费拿到跨系统通信

产品特定顶层是什么:每个产品在底座之上加自己的 personas/specialists/skills/ 目录。

举具体例子

Amber 的顶层——coach_persona.md(教练视角)+ scoring_specialist.yaml(评分契约)+ start_practice.ts(练习流程的 LangGraph DAG)。

Mumu 的顶层——director_persona.md(仅 1 个)+ video_generator_specialist.yaml + submit_video_task.ts(提交+轮询)。

茶会的顶层——7 个 personas(架构师/PM/…)+ 7 个 specialists(dev/qa/…)+ 3 个 skills(/sprint, /roundtable, /review)。

三个产品底座完全相同,顶层完全不同

为什么先迁茶会而不是直接做 SDK

  1. 茶会是最复杂用例——multi-persona 圆桌 + 多 phase sprint。能 host 茶会就能 host 简单产品。
  2. 茶会失败成本最低——只个人使用。
  3. 关键迁移过程强制把抽象从茶会特定代码里逼出来。抽象是浮现的,不是预先猜的——这是渐进迁移的核心价值。

预先猜的抽象一定过度设计只有从真实代码里浮现的抽象才刚好够用

渐进迁移路径——6 phase:

  1. Week 1:搭 SDK 骨架,hello-world
  2. Week 1.5:/review PoC,验证并行 + state reducer + LangFuse trace
  3. Week 2:/roundtable,验证 persona 反谄媚规则保留
  4. Week 3-4:/sprint,验证并行 reviewer + checkpoint + interrupt
  5. Week 5-6:稳定化,新旧并行跑
  6. Week 7+:抽 SDK,Amber/Mumu 采用

每 phase 必须通过验证才进下一个——这是渐进的纪律。

ROI

  • 假设每个新产品独立搭基建花 3 周
  • 迁移成本:6-8 周
  • 平衡点:第 3 个产品采用时回本
  • 之后:每个新产品净赚 3 周
  • 持续效应:架构改进同时让所有产品受益

结果:从”跑多个 AI 产品”到”跑一个 AI 产品平台”。这是平台思维和产品思维的差别

最后一个 caveat——这套架构的局限我在另一篇专门评估了(Honest Evaluation)。不要把它当永恒真理——它是当前最优归纳,不是教条。


8. 可能被问到的 5 个问题 + 回应

问题 1:你怎么避免 SDK 变成 Amber 的”包装”?

回应

这是真风险。SDK 应该比 Amber 更通用

防止机制:

  1. Mumu 是 SDK 的另一个测试场——任何只在 Amber 用得上的功能,Mumu 用不上,就不能进 SDK
  2. 底座代码不 import 任何产品的代码——单向依赖
  3. 每个 SDK 接口必须有 2 个以上产品验证用例——不只 Amber

问题 2:单人维护 SDK 怎么避免它变陈旧?

回应

SDK 维护工作量比想象中小,因为:

  • 大部分依赖(LangGraph、LangFuse 等)是 well-maintained 的开源项目,自动跟进
  • 我自己每周用 SDK(茶会就是 SDK 的 first user),bug 第一时间发现
  • Amber、Mumu 反向贡献——他们用 SDK 时发现的问题修在 SDK 里

真正的风险是 paradigm shift——5 层架构如果过时,SDK 整个要重做。这是 Honest Evaluation 那篇的话题

问题 3:为什么不用现成的 LangChain / Mastra 等框架?

回应

LangChain 是工具集合,不是 5 层架构。它给你 Memory / Agent 工具,但不强制 Persona/Specialist 拆分不内置反谄媚规则不显式分 Rules/Hooks

我的 SDK = LangChain/LangGraph 等的架构层封装——强制了我认为重要的设计选择用户用我的 SDK 就自动得到这些设计——这是 SDK 的价值。

类比:用 React 不等于做了好 UI;用 LangChain 不等于做了好 agent 系统。架构层的强制是 SDK 真正的价值

问题 4:Memory 暴露成 MCP server 不会有性能问题吗?

回应

在同一个 Cloudflare Worker 内调用,几乎零开销——MCP 接口本质就是 RPC,序列化/反序列化在 Worker 里 sub-millisecond。

跨 Worker 调用(如 Amber Worker 调茶会的 Memory MCP server)有真实延迟——几十毫秒。

应对:关键 hot path 把 Memory 共置在产品 Worker 里——MCP server 是默认接口,但需要时可以 inline。

协议化的好处大于性能损失——除非你的产品是延迟敏感型(实时游戏、HFT),否则 MCP 是值得的。

问题 5:你说”6-8 周迁移”——这是单人吗?团队呢?

回应

单人。茶会是我个人项目,所以是单人估算。

团队估算会短一些

  • Phase 1-2(搭骨架 + PoC):1 人 1 周
  • Phase 3-4(/roundtable + /sprint):2 人 1.5 周
  • Phase 5(稳定化):1 人 1 周(可以兼其他事)
  • Phase 6(抽 SDK):2 人 1 周

总团队工作量:约 4-5 人周。日历时间约 4 周(如果团队专注)。


9. 相关链接

内部(其他主文章)

外部参考

相关概念

  • 平台 vs 应用 ≈ 共享底座 vs 产品特定顶层
  • Framework + Plugins ≈ 类似设计模式(如 VSCode、Webpack)
  • Microservices vs Monolith ≈ 不完全类比但有启发