数学的数学——用对象和箭头统一描述一切结构,在 AI Agent 工程中落地为”如何安全组合带副作用的计算”。

Definition / Explanation

范畴论由 Samuel Eilenberg 和 Saunders Mac Lane 于 1945 年创立,最初用于代数拓扑学。核心思想:不关心对象内部是什么,只关心对象之间的关系(箭头)。

三个层次的递进

普通函数    f: A → B                     点 → 点
函子        F: C → D(范畴到范畴)        世界 → 世界(保结构翻译)
单子        M + return + bind            世界 → 世界 + 链式组合能力

1. 范畴(Category)

由两样东西组成:

  • 对象(Objects):可以是任何东西(类型、集合、Agent、状态…)
  • 态射(Morphisms):对象之间的”箭头”,代表变换/关系

必须满足两条规则:

  1. 结合律:(f ∘ g) ∘ h = f ∘ (g ∘ h)
  2. 恒等态射:每个对象 A 都有 id_A,使得 f ∘ id = id ∘ f = f
% 态射 = 函数
double(X) -> X * 2.
inc(X) -> X + 1.
 
% 组合(结合律自动满足)
double_then_inc(X) -> inc(double(X)).
 
% 恒等态射
id(X) -> X.

2. 函子(Functor):整个小世界的翻译

函子是两个范畴之间保持结构的映射,做两件事:

  • 把 C 中的对象映射到 D 中的对象
  • 把 C 中的态射映射到 D 中的态射
  • 且保持组合关系:F(f ∘ g) = F(f) ∘ F(g)
范畴 C (普通类型)          范畴 D (List类型)
    Integer    ---F--->    [Integer]
       |                      |
    double                 map(double)
       |                      |
    Integer    ---F--->    [Integer]
% List 函子:map 把 f: A->B 提升为 [A]->[B]
lists:map(fun double/1, [1, 2, 3]).  % [2, 4, 6]
 
% Maybe 函子
fmap(_F, nothing)  -> nothing;
fmap(F, {just, X}) -> {just, F(X)}.

判断口诀:只要你写了一个”对容器里每个元素做变换、不改变容器结构”的函数,你就在实现函子。


3. 单子(Monad):带上下文的链式计算

函子和单子的分界线只有一条:

函子单子
核心操作map(变形内部值)bind(扁平化组合)
操作后结构仍是一层壳不会出现两层壳
串联能力无(不能依赖前面结果决定后面结构)有(前一个结果决定下一个世界)

为什么函子不够?

safe_div(_, 0) -> nothing;
safe_div(X, Y) -> {just, X / Y}.
 
% map:函数本身返回 Maybe,结果双层壳
maybe_map(fun(X) -> safe_div(10, X) end, {just, 2}).
% => {just, {just, 5.0}}   ← 坏了,没法继续链式调用
 
% bind:自动扁平化,一层壳
maybe_bind({just, 2}, fun(X) -> safe_div(10, X) end).
% => {just, 5.0}           ← 干净

铁路比喻:

成功轨道: [step1] ---> [step2] ---> [step3] ---> 结果
失败轨道: =========================> 错误(一旦失败,后续全跳过)

bind 就是铺设这两条轨道的连接器

单子 = 自函子 + return + bind,其中:

  • return:把普通值包装进 Monad 上下文
  • bind:解决”函子嵌套”问题,让带效果的计算可以链式组合

4. 六种常用单子

每个 Monad 对应一种”计算效果”,bind 负责让这种效果自动传播:

 Either:带原因的失败
either_bind({error, E}, _F) -> {error, E};
either_bind({ok, X}, F)     -> F(X).
 
 State:隐式传递状态(本质:S -> {A, S})
state_bind(M, F) -> fun(S0) ->
    {A, S1} = M(S0),
    (F(A))(S1)
end.
 
 (a -> M b) -> (b -> M c) -> (a -> M c)
kleisli(F, G) -> fun(X) -> either_bind(F(X), G) end.
 
Pipeline = kleisli(
    kleisli(fun call_llm/1, fun parse_response/1),
    fun execute_tool/1
),
Result = Pipeline("What's the weather?").

7. Monad Transformer Stack:效果叠加

真实系统同时需要多种效果,Transformer 把它们叠成一座塔:

┌─────────────────────────────────────┐
│  StateT AppState   ← 记忆/上下文     │  隐式传递状态
├─────────────────────────────────────┤
│  EitherT Error     ← 可能失败        │  自动短路错误
├─────────────────────────────────────┤
│  IO                ← 副作用          │  隔离不纯操作
└─────────────────────────────────────┘

类型签名:AppState → IO(Either(Error, (Result, AppState)))
读法:接受初始状态,执行 IO,返回"要么错误,要么(结果+新状态)"

8. 其他核心概念

自然变换(Natural Transformation):函子之间的态射,描述”容器类型之间的转换”,且转换方式与容器里的内容无关。

% 自然变换:List A -> Maybe A(取第一个元素)
head([])    -> nothing;
head([H|_]) -> {just, H}.
% 自然性:head(map(f, list)) = fmap(f, head(list))

Yoneda 引理:对象可以通过它与所有其他对象的关系完全刻画。直觉:你不需要知道一个对象”内部是什么”,只需要知道它”能做什么”。Transformer 注意力机制的范畴论解释——Token 的语义由它与其他 Token 的关系决定。

伴随函子(Adjoint Functors):函子 F 和 G 互为伴随(F ⊣ G),是一对”最优的互逆操作”。编码/解码、压缩/解压、抽象/具体化都是伴随关系的体现。


Current State of Knowledge

范畴论在 AI/Agent 领域的应用正在快速发展:

  • MCE(Monadic Context Engineering):Princeton 大学论文,用 Functor/Applicative/Monad 三层抽象解决 Agent 架构脆弱性,开源于 github.com/yifanzhang-pro/monadic-context-engineering
  • Token Space:2024 年论文(arXiv 2404.11624),用范畴论框架在 Token 级别建立范畴结构,分析 Transformer 注意力机制
  • UMass COMPSCI 692CT:2026 年春季研究生课程,系统讲授范畴论在 AGI 中的应用,配套 FunctorFlow 框架
  • ArchAgents 范畴:arXiv 2603.28906,用范畴论统一描述 AGI 架构模式

Open Questions or Debates

  • 范畴论对 Agent 工程师的实际价值边界在哪?对只写 prompt 的用户暂无直接价值;对构建 Agent 框架/runtime 的工程师价值显著
  • Monad Transformer Stack 的性能开销与工程复杂度是否值得?LangChain/AutoGen 等主流框架仍采用命令式方法
  • Topos 理论(范畴论高级分支)是否真的对 AGI 意识建模有帮助?UMass 课程持肯定态度,但学界尚无定论

  • agent-client-protocol — ACP 协议的 EitherT 层与 MCP 规范中工具结果必须显式标明成功/失败的要求对齐
  • openclaw-acp-protocol — Agent 工具调用链是 Kleisli 组合的直接工程实现
  • llm-wiki-pattern — 知识库构建本身可用 State Monad 建模(状态 = 知识库快照)