《跨产品 Agent 参考架构》读书笔记
这一页是给我自己用的工具页,不是给读者的阅读页。包含完整脉络、代码、架构图、面试话术。 如果你只想看精炼版,请回到 主文章。
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.md、scoring_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 /roundtable | persona 反谄媚规则仍然生效;圆桌输出有真分歧 |
4 /sprint | 4 个 reviewer 真并行(trace 显示);checkpoint 能恢复 |
| 5 稳定 | 1 周内零故障 |
| 6 抽 SDK | Amber 能 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 必须通过验证才进下一个。 图 3:抽象不是预先猜的,是迁移浮现的
预先设计 SDK 迁移浮现 SDK
"我猜 Memory 应该 "迁移 /sprint 时发现:
有 X、Y、Z 接口" - 并行 reviewer 是通用 → 抽
- episodic 写入是通用 → 抽
- 扫 ateliers/ 是茶会特定 → 不抽
↓ ↓
猜对一半 抽出真正用得上的
过度设计 刚好够用
半年后大改 迭代稳定 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 秒电梯版
做多个 AI 产品时最容易犯的错:每个产品独立设计 agent 架构。结果是每个产品花 3 周搭基建,架构学习不在产品间转移。我的方案:把五层 stack 拆成共享底座(Memory/Agents 框架/Skill 引擎/Rules+Hooks/协议适配器)+ 产品特定顶层(Personas/Specialists/Skills)。底座做成 SDK,每个产品 import。Amber、Mumu、茶会都坐在同一个底座上——新产品 90% 时间花在让它不同的事上,不是重建 agent loop。
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。两个产品底座完全相同,顶层完全不同。为什么先迁茶会:
- 最复杂用例——能 host 茶会就能 host 简单产品
- 失败成本最低——没付费用户
- 迁移过程强制把抽象逼出来——抽象是浮现的,不是猜的
ROI:迁移 6-8 周。第 3 个产品采用时回本,之后每个产品净赚 3 周。
结果:从”跑多个 AI 产品”到”跑一个 AI 产品平台”。
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 框架。提供抽象类
Persona和Specialist,强制接口(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:
- 茶会是最复杂用例——multi-persona 圆桌 + 多 phase sprint。能 host 茶会就能 host 简单产品。
- 茶会失败成本最低——只个人使用。
- 关键:迁移过程强制把抽象从茶会特定代码里逼出来。抽象是浮现的,不是预先猜的——这是渐进迁移的核心价值。
预先猜的抽象一定过度设计。只有从真实代码里浮现的抽象才刚好够用。
渐进迁移路径——6 phase:
- Week 1:搭 SDK 骨架,hello-world
- Week 1.5:
/reviewPoC,验证并行 + state reducer + LangFuse trace- Week 2:
/roundtable,验证 persona 反谄媚规则保留- Week 3-4:
/sprint,验证并行 reviewer + checkpoint + interrupt- Week 5-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 更通用。
防止机制:
- Mumu 是 SDK 的另一个测试场——任何只在 Amber 用得上的功能,Mumu 用不上,就不能进 SDK
- 底座代码不 import 任何产品的代码——单向依赖
- 每个 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. 相关链接
内部(其他主文章)
- Five Layers of an Agent System — 这套架构基于的栈
- Persona vs Specialist Split — Agent 框架的核心抽象
- Memory as Foundation — 共享底座的最重要部分
- Anti-Sycophancy Rule — Persona 框架强制的规则
- Honest Evaluation — 这套架构的局限评估
- Agent Framework Landscape — 业界框架对比
外部参考
- LangGraph 文档 — Skill 引擎实现
- LangFuse — Trace 实现
- Model Context Protocol — Memory 接口标准
- A2A Protocol — 跨 agent 通信
相关概念
- 平台 vs 应用 ≈ 共享底座 vs 产品特定顶层
- Framework + Plugins ≈ 类似设计模式(如 VSCode、Webpack)
- Microservices vs Monolith ≈ 不完全类比但有启发