《AI Agent 高级编程》1.3 选型方法:按可观测/持久化/生态/锁定度打分

本节把框架选型从拍脑袋变成可计算:给出可观测、持久化、生态、锁定度四维权重表(含每项理由)与 1–5 分评分标准,配一个可运行的最小打分脚本,输入六个框架的分数、输出加权总分与排序,并做权重重排的敏感度分析,真跑贴输出,最后给出按场景调权的决策清单。

1.3 选型方法:按可观测/持久化/生态/锁定度打分

1.1 给了四层地图,1.2 给了统一抽象。但真到项目里,你还是要面对那个原始问题:「我该用哪个框架」。常见的回答是列一张特性表,然后靠感觉。

本节把这件事变成可计算的——四个维度、一组权重、一个能跑的脚本,让选型结论可复现、可讨论、可调参。

本节把「选型」推进到可量化:定义可观测 / 持久化 / 生态 / 锁定度四维及其权重(附理由)与 1–5 分标准,给六个候选框架打分,用一个最小脚本算出加权总分与排序并真跑,再做权重重排的敏感度分析,最后给出「不同场景怎么调权重」的决策清单。

1.3.1 为什么是这四个维度

维度不是越多越好。维度一多,权重就成了玄学,结论反而不可信。经过卷二《AI Agent 工程实战》的落地检验,真正会决定「这个框架能不能上线、上线后痛不痛」的,是这四件事:

维度含义高分的表现为什么它重要
可观测 observability能否看清每次模型/工具调用原生 OTel / trace 导出生产事故定位的唯一依据
持久化 durability崩溃/重启后能否续跑检查点、可恢复、确定性重放长任务能不能上线的硬门槛
生态 ecosystem集成、文档、人才、社区工具多、示例多、招得到人决定交付速度与维护成本
锁定度 lock-in迁移到别家的成本抽象清晰、无私有格式决定未来议价权(5 = 低锁定)

为什么不是「性能」「上手难度」「代码量」这些常见维度?因为:

  • 性能在 Agent 场景里几乎总是被模型延迟主导,框架自身的开销可忽略——区分度太低。
  • 上手难度是短期成本,且与「生态」高度相关,重复计分。
  • 代码量是过程指标,不是结果指标;卷二的工程经验告诉我们,少写的那几十行代码,往往在三个月后以「框架升级破坏兼容」的形式还回来。

四个维度覆盖了「上线前能不能用」「上线后痛不痛」「未来换不换得动」三条主线,且互相独立、不重复计分。

注意 锁定度是反向计分的:5 分表示「几乎不锁定、随便换」,1 分表示「深度绑定、换不动」。这样四个维度都是「分数越高越好」,加权求和才有统一方向——这是打分模型最容易搞错的地方,一旦方向反了,结论会完全颠倒。

权重及其理由(权重和为 1):

维度权重理由
可观测0.30生产环境里「不知道发生了什么」是最贵的故障,权重最高
持久化0.25长任务场景下这是 0 和 1 的区别,没有它连上线资格都没有
生态0.25直接换算成交付人天,和持久化同等重要
锁定度0.20重要但可延后——多数团队先上线再谈迁移,故略低

权重不是真理,是默认值。真正的方法论在 1.3.4:不同场景把权重调成不同形状。

1.3.2 1–5 分怎么定:评分标准

打分最容易「各打各的」,所以必须给锚点。每维 5 分对应「行业领先」,1 分对应「基本缺失」:

维度1 分3 分5 分
可观测无 trace,只能 print有日志,无结构化 trace原生 OTel,trace 可直接导出
持久化进程挂了从头来支持会话恢复检查点 + 确定性重放
生态几乎无集成有主流模型适配工具/示例/社区齐全,招得到人
锁定度深度绑定、换不动有抽象但仍有私有格式纯标准接口,随时可换

有了锚点,打分就从「我觉得」变成「对照标准」。锚点越具体,不同人打出的分越接近,这正是选型会议最需要的东西。

实操建议:打分时每人独立打一遍再对表,分歧大的维度优先讨论——分歧点往往暴露了团队对「生产要求」的认知差异,比分数本身更有信息量。

1.3.3 六个候选的打分表

分数由本卷后续各章的真实体验给出(第 2 章 PydanticAI、第 3 章 Claude Agent SDK、第 4 章 OpenAI Agents SDK 与 smolagents、第 5 章 LangGraph 源码、第 6 章持久化)。这里是先验打分,后续章节会回头修正:

框架层可观测持久化生态锁定度说明
minagent(自研)引擎3225全可控、零锁定,但什么都得自己写
pydantic-aiSDK5344OTel 原生、类型强,检查点需自建
langgraph编排4552检查点最强,但 Graph 抽象绑定较深
claude-agent-sdkSDK3341内置能力多,深度绑定 Claude 生态
openai-agentsSDK5243tracing 一流,持久化弱
smolagentsSDK2134极简「代码即行动」,生产化最少

这张表本身就有信息量:没有全能冠军。langgraph 持久化/生态满分但锁定度高;claude-agent-sdk 锁定度只有 1;自研 minagent 锁定度满分却样样垫底。选型永远是取舍。

1.3.4 可运行的最小打分脚本

把上表变成代码。脚本的设计要点:权重与分数分离,改场景只动 WEIGHTS;排序函数与打印分离,方便复用。下面这段在本机真跑:

"""四维选型打分:可观测 / 持久化 / 生态 / 锁定度。每维 1–5 分,5 分最好。"""

WEIGHTS = {
    "observability": 0.30,   # 生产事故定位靠它,权重最高
    "durability":    0.25,   # 长任务/崩溃恢复,直接决定能不能上线
    "ecosystem":     0.25,   # 集成与人才供给,决定交付速度
    "lock_in":       0.20,   # 迁移成本,5 = 低锁定(易替换)
}
assert abs(sum(WEIGHTS.values()) - 1.0) < 1e-9

FRAMEWORKS = {
    "minagent(自研)":   {"observability": 3, "durability": 2, "ecosystem": 2, "lock_in": 5},
    "pydantic-ai":      {"observability": 5, "durability": 3, "ecosystem": 4, "lock_in": 4},
    "langgraph":        {"observability": 4, "durability": 5, "ecosystem": 5, "lock_in": 2},
    "claude-agent-sdk": {"observability": 3, "durability": 3, "ecosystem": 4, "lock_in": 1},
    "openai-agents":    {"observability": 5, "durability": 2, "ecosystem": 4, "lock_in": 3},
    "smolagents":       {"observability": 2, "durability": 1, "ecosystem": 3, "lock_in": 4},
}


def total(row: dict) -> float:
    return round(sum(WEIGHTS[k] * v for k, v in row.items()), 3)


def rank(frameworks: dict) -> list[tuple[float, str]]:
    return sorted(((total(r), n) for n, r in frameworks.items()), reverse=True)


def main() -> None:
    print(f"{'framework':18s} {'obs':>3s} {'dur':>3s} {'eco':>3s} {'lock':>4s}  total")
    for score, name in rank(FRAMEWORKS):
        r = FRAMEWORKS[name]
        print(f"{name:18s} {r['observability']:>3d} {r['durability']:>3d} "
              f"{r['ecosystem']:>3d} {r['lock_in']:>4d}  {score:>5.3f}")
    print("rank:", [n for _, n in rank(FRAMEWORKS)])


if __name__ == "__main__":
    main()

真跑输出(/tmp/agentbook/venv3/bin/python):

framework          obs dur eco lock  total
langgraph            4   5   5    2  4.100
pydantic-ai          5   3   4    4  4.050
openai-agents        5   2   4    3  3.600
minagent(自研)         3   2   2    5  2.900
claude-agent-sdk     3   3   4    1  2.850
smolagents           2   1   3    4  2.400
rank: ['langgraph', 'pydantic-ai', 'openai-agents', 'minagent(自研)', 'claude-agent-sdk', 'smolagents']

注意 assert 那一行:它守住了权重和必须为 1。这类不变量在打分脚本里比结果本身更重要——一旦有人手改权重忘了配平,脚本立刻报错,而不是悄悄算出一个错的排序。

1.3.5 敏感度分析:换个权重,冠军会变吗

默认权重下 langgraph 险胜 pydantic-ai(4.100 vs 4.050)。但结论稳不稳,要看它对权重的敏感度。把权重按场景重排,再跑一遍:

SCENARIOS = {
    "默认":     {"observability": 0.30, "durability": 0.25, "ecosystem": 0.25, "lock_in": 0.20},
    "长任务":   {"observability": 0.20, "durability": 0.50, "ecosystem": 0.15, "lock_in": 0.15},
    "强合规":   {"observability": 0.50, "durability": 0.15, "ecosystem": 0.20, "lock_in": 0.15},
    "快速原型": {"observability": 0.15, "durability": 0.10, "ecosystem": 0.45, "lock_in": 0.30},
    "抗锁定":   {"observability": 0.20, "durability": 0.15, "ecosystem": 0.15, "lock_in": 0.50},
}

真跑输出:

默认       冠军=langgraph        4.100  前三=['langgraph', 'pydantic-ai', 'openai-agents']
长任务      冠军=langgraph        4.350  前三=['langgraph', 'pydantic-ai', 'openai-agents']
强合规      冠军=pydantic-ai      4.350  前三=['pydantic-ai', 'openai-agents', 'langgraph']
快速原型     冠军=pydantic-ai      4.050  前三=['pydantic-ai', 'langgraph', 'openai-agents']
抗锁定      冠军=pydantic-ai      4.050  前三=['pydantic-ai', 'minagent(自研)', 'openai-agents']

三条读得出来的结论:

  • 「长任务」场景 langgraph 优势扩大(4.100 → 4.350),因为它是唯一持久化 5 分的——这正是第 6 章要展开的能力。
  • 「强合规」场景冠军易主为 pydantic-ai,因为它可观测 5 分。冠军会变,说明选型必须先说清场景,再谈框架。
  • 「抗锁定」冠军不是 minagent 而是 pydantic-ai——反直觉但有道理:minagent 虽然锁定度满分,但生态/可观测太弱,总分仍不及「锁定度 4 分、其余均衡」的 pydantic-ai。单项满分救不了全面平庸。

这三条如果只靠感觉,是得不出来的。这就是把选型变成计算的意义。

还值得留意「默认」与「长任务」两行的前三名完全相同——说明当候选之间的差距大于权重扰动带来的变化时,结论是稳健的。反之,「快速原型」一行里 langgraph 掉到第二,说明它的领先是场景依赖的,不是普适的。判断一个排序稳不稳,就看它在几组权重下是否守住名次。

1.3.6 打分之外:三条硬否决项

打分模型有个陷阱:它会把「绝对不能选」的选项算出个中等分数,让你误以为可以接受。所以打分之前,先用三条硬否决过滤:

硬否决项判定为什么是「一票否决」而非扣分
许可证不合规与你的分发方式冲突法律风险无法用分数补偿
关键能力缺失场景必需项(如持久化)为 1 分缺的不是「一点」,是「能不能用」
已停止维护半年无提交、无安全更新供应链风险,越用越危险

举例:某框架若许可证不允许商用,它哪怕四维全 5 分也不能选——分数再高也过不了法务。同理,一个「持久化 1 分」的框架,在小时级长任务场景里直接出局,无论它生态多好。硬否决先于打分:先筛掉不能用的,再给能用的排序。

这条顺序不能反。现实中很多选型事故,正是「总分排第一的选项,其实踩了硬否决」——因为打分表里没有「许可证」这一行,也没人先做否决检查。

补充一点:硬否决项本身也要随场景变。对闭源 SaaS,许可证是硬否决;对内部工具,它可能完全不相关。所以「否决清单」和「权重」一样,属于场景,不属于框架。

1.3.7 怎么用这张表做决策

默认权重下的结论是「langgraph ≈ pydantic-ai 领先」,但真正的用法是调权。把 WEIGHTS 改成你的场景,排序可能完全翻盘:

场景该调高的维度调整后倾向
快速原型 / Demo生态↑、锁定度↑pydantic-ai、openai-agents
长任务(小时级)持久化↑↑langgraph(唯一 5 分)
强合规 / 可审计可观测↑↑pydantic-ai、openai-agents
深度绑定某云 / 某模型锁定度↓(不介意)claude-agent-sdk
教学 / 最小依赖锁定度↑、生态↓smolagents、自研 minagent

三个使用原则:

  1. 分数要来自实测,不是宣传。本节的分是后续章节真跑后的体验值,你换成自己的项目时,也应在小规模试跑后再填。
  2. 权重必须团队共识。权重之争其实是「我们最怕什么」之争,吵清楚权重比吵清楚分数更有价值。
  3. 不要追总分最高。第 4 名可能恰好是「锁定度最高」的那个——如果迁移能力对你是硬需求,它才是对的。
  4. 分层选型,不要选「一个」。1.1 的四层图提醒你:编排层选 langgraph、SDK 层选 pydantic-ai 是完全合理的组合,你不需要在同一个框架里找齐所有能力。本卷后续每一章都会回到这个组合视角。

这套方法替你做了什么:把「选型」从主观争论变成可复现的计算,让不同人用同一张表得出可比的结论。你让渡了什么:打分简化了真实世界的复杂性——有些框架的杀手级能力(比如某家的内置 subagent)无法被四个数字概括。打分是决策的起点,不是终点;第 11.3 节全景回顾时,我们会用真实项目数据回头检验这张表。

1.3.8 把结论固化:一份可复现的选型记录

打分的价值只有在被记录下来时才可持续。建议每次选型产出一段简短记录,格式如下:

选型记录 · <日期>
场景:        小时级研究任务,可中断可恢复
硬否决检查:  许可证✓ 关键能力(持久化≥3)✓ 维护中✓
权重:        可观测0.20 / 持久化0.50 / 生态0.15 / 锁定度0.15
候选与得分:  langgraph 4.350 | pydantic-ai 4.050 | openai-agents 3.150
结论:        选 langgraph(编排层),SDK 层用 pydantic-ai 配合
被否理由:    openai-agents 持久化 2 分,不满足关键能力门槛
复评时间:    3 个月后(若 langgraph 锁定度问题暴露则重评)

这份记录回答了三件事:为什么选、为什么没选别的、什么时候该重评。三个月后有人问「当初为什么用 langgraph」,翻出这段就够了;框架升级或场景变化时,「复评时间」会提醒你重跑脚本。

把它和 1.2 的统一抽象接起来,一个完整的选型闭环就成型了:打分选框架 → Protocol 包住它 → 记录留痕 → 场景变了重评。这也是本卷后续所有章节的元方法——每一章你都会看到「某框架替你做了什么」,而决定用不用它,回到这张四维表就够了。

最后提醒一句:这张表是活文档。第 2–6 章跑完后,某些分数一定会被修正(比如你可能会发现某框架的持久化比预想的更弱)。届时不要改历史记录,而是**追加一行「修订」**并注明依据——这样三个月后回看,你能看到的不只是结论,还有结论是怎么演化的。这比一张「看起来永远正确」的表有价值得多。

阅读导航:上一节:1.2 统一抽象:一个 Protocol 适配多家并写适配层 · 下一节:2.1 核心模型:Agent/RunContext/依赖注入重写问答路径 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「agent」更多文章

  1. 《AI Agent 高级编程》目录
  2. 《AI Agent 高级编程》11.3 全景回顾:从零到框架的完整路径与展望
  3. 《AI Agent 高级编程》11.2 真实 API 冒烟:假模型 vs 真模型量化差距