犀牛鸟 2026 研究笔记 estelledc.github.io

Agent 框架赛道 — 核心技术难点

基于 trpc-agent-go / trpc-agent-python / LangChain / LangGraph / CrewAI / Agno 源码调研 调研时间:2026-06-22


难点总览

# 难点 涉及框架 严重度
1 状态管理与一致性 LangGraph / tRPC-Agent-Go / Agno ★★★★★
2 Tool Calling 可靠性 全部六个 ★★★★
3 多 Agent 协作控制 tRPC-Agent-Go / CrewAI / LangGraph ★★★★★
4 记忆系统设计 tRPC-Agent-Go / Agno / LangGraph ★★★★
5 可观测性与调试 全部六个 ★★★
6 生产环境扩展性 tRPC-Agent-Go / LangGraph ★★★★★
7 规划与推理质量 tRPC-Agent-Go / LangGraph / CrewAI ★★★★
8 Human-in-the-Loop LangGraph / tRPC-Agent-Go ★★★

1. 状态管理与一致性(★★★★★)

核心矛盾:Agent 需要在多步推理中维护全局状态(对话历史、工具结果、计划进度),但 LLM 本身是无状态的——每次调用都从头开始。框架必须在 LLM 的”失忆”本质之上人工构建状态一致性。

日常类比:一个每天失忆的侦探在破案。他每天醒来忘记昨天做了什么,只能靠墙上的便利贴(State)回忆进度。如果有人在他睡觉时偷偷移动了便利贴(并发写入),第二天他会做出错误判断。

真实案例

LangGraph 的 Channel 冲突:当两个并行节点同时向同一个 LastValue Channel 写入不同的值时,最终状态取决于哪个节点先完成——这是非确定性的。

class State(TypedDict):
    answer: str  # LastValue——只保留最后写入

# 两个并行节点同时写 answer
def node_a(state):
    return {"answer": "A 的答案"}

def node_b(state):
    return {"answer": "B 的答案"}

# 最终 state["answer"] 是 A 还是 B?取决于执行顺序——非确定性!

解决方案:用 BinaryOperatorAggregate + operator.add 做累积,但这要求开发者预判哪些字段会被并发写入——设计时的认知负担。

tRPC-Agent-Go 的分布式状态:当 Agent 部署在多个实例上,Runner 的 Invocation.State 是实例本地的。如果一个请求被负载均衡到不同实例,状态会丢失。

请求 1 → 实例 A → State = {step: 3, plan: "research"}
请求 2 → 实例 B → State = {}  ← 丢失了!必须从 Session 后端重新加载

9 种 Session 后端的存在正是为了解决这个问题,但引入了新问题:Session 读写延迟、后端故障时的降级策略。

根本难点

状态管理的三难选择(类似 CAP 定理):

  1. 一致性(所有组件看到相同状态)
  2. 性能(状态读写不成为瓶颈)
  3. 简洁性(开发者不需要手动管理状态同步)

LangGraph 选择了一致性(Pregel 超步同步),代价是性能(不能跨超步流水线化)。tRPC-Agent 选择了性能(分布式部署),代价是需要额外的 Session 后端。Agno/CrewAI 选择了简洁性(状态就是对象字段),代价是一致性弱。

没有框架同时解决了三者。


2. Tool Calling 可靠性(★★★★)

核心矛盾:LLM 必须正确生成 tool call 的参数(JSON 格式、类型匹配、语义正确),但 LLM 本质是概率生成模型——它在”理解”和”瞎编”之间没有明确界限。

日常类比:你让一个从未用过计算器的孩子按计算器。他知道”要算加法”,但可能按错键(参数类型错)、按多了(多余参数)、或根本没按到正确的键(调错工具)。

真实案例

参数类型错误:LLM 经常把数字生成为字符串,或把列表生成为逗号分隔的字符串。

// LLM 生成的 tool call(错误)
{"name": "search", "arguments": {"limit": "10", "tags": "python, ai"}}

// 期望的格式
{"name": "search", "arguments": {"limit": 10, "tags": ["python", "ai"]}}

每个框架都需要做参数修复(coercion),但修复策略不一致——有的默默修复(Agno),有的报错重试(LangChain),有的让开发者自定义(tRPC-Agent)。

工具选择错误:当可用工具超过 15 个时,LLM 选错工具的概率显著上升。CrewAI 的 allow_delegation=True 允许 Agent 把任务委派给其他 Agent,但委派决策本身也依赖 LLM 判断——形成了”用不可靠的系统做可靠性决策”的悖论。

循环调用:Agent 反复调用同一工具但参数略有不同,期望得到不同结果(类似”精神错乱的定义”)。

Step 1: search("agent framework comparison") → 没找到想要的
Step 2: search("agent framework comparison 2026") → 还是不满意
Step 3: search("best agent framework comparison 2026") → 继续...
Step 4: search("top agent framework comparison 2026 latest") → 死循环

tRPC-Agent-Go 的 MaxSteps 限制了总步数,但这是粗粒度保护——它不能阻止 Agent 在限制内浪费所有步数。

根本难点

Tool Calling 可靠性问题的本质是 LLM 没有”执行语义”的概念。它生成的是”看起来像正确 JSON 的文本”,不是”经过类型检查的函数调用”。框架能做的只有:

  1. Schema 验证 + 自动重试(所有框架都做了)
  2. 工具描述优化(减少歧义)
  3. 工具数量控制(保持在 LLM 可靠处理的范围内)
  4. Few-shot 示例注入(教 LLM 正确格式)

但这些都是”缓解”而非”解决”。真正的解决需要 LLM 架构层面的突破(如 constrained decoding / structured output 原生支持)。


3. 多 Agent 协作控制(★★★★★)

核心矛盾:多 Agent 系统需要在”自主性”和”可控性”之间找平衡。Agent 太自主则行为不可预测,太受控则失去协作的价值(直接写脚本更好)。

日常类比:公司管理。完全自主(每个人自己决定做什么)→ 混乱;完全受控(每一步都由经理审批)→ 效率极低。好的管理是”明确目标 + 适度授权 + 关键节点汇报”。

真实案例

CrewAI Hierarchical 模式的 Manager 失控:Manager Agent 本身也是 LLM 驱动的——它可能做出错误的任务分配。

# Manager 的"决策"是 LLM 生成的——不可靠
crew = Crew(
    agents=[researcher, writer, designer],
    process=Process.hierarchical  # Manager 自动分配任务
)
# 可能出现:Manager 把设计任务分给了 researcher
# 原因:LLM 对"谁擅长什么"的判断基于 Role/Backstory 的文本相似度

tRPC-Agent-Go Swarm 模式的死循环:Agent A 认为该转交给 B,B 处理后认为该转回 A——形成 ping-pong。

Agent A: "这个任务需要更多研究" → 转交 Agent B
Agent B: "研究完了,需要写成报告" → 转交 Agent A
Agent A: "报告需要更多数据支撑" → 转交 Agent B
... 无限循环

Coordinator 模式通过中心调度者避免了这个问题,但引入了单点瓶颈——所有任务都经过 Coordinator,Coordinator 本身的 LLM 调用成为延迟瓶颈。

LangGraph 子图嵌套的状态隔离:子图有自己的 State,父图无法直接观察子图内部状态。当子图执行出错时,父图只能看到”子图失败了”,不知道失败在哪一步。

# 父图只能看到子图的最终输出——内部执行过程是黑盒
parent_graph.add_node("sub_task", sub_graph.compile())
# 如果 sub_graph 内部第 5 步失败,parent_graph 只知道"sub_task failed"

根本难点

多 Agent 协作的根本难点是 涌现行为不可预测。单个 Agent 的行为已经难以完全预测(因为 LLM 是概率模型),多个 Agent 交互时,行为空间呈指数增长。

经典分布式系统用协议(如 Raft/Paxos)保证一致性,但 Agent 系统的”协议”是 LLM 生成的自然语言——它不具备协议的确定性保证。

当前的缓解手段

但这些都在牺牲灵活性换可控性——本质是把问题从”解决”降级为”约束”。


4. 记忆系统设计(★★★★)

核心矛盾:Agent 需要”记住”过去的交互以做出更好的决策,但 LLM 的 context window 是有限的。把所有历史都塞进 prompt 会超出 token 限制,选择性存储又可能遗漏关键信息。

日常类比:学生做笔记。全部逐字记录(全量记忆)→ 笔记本用完了也记不完;只记结论不记过程(压缩记忆)→ 考试时想不起推导过程;什么都不记(无记忆)→ 每次从零开始。

真实案例

tRPC-Agent-Go Fact vs Episode 的边界模糊:什么该存为 Fact(提炼后的知识),什么该存为 Episode(原始对话)?

// 这句话应该存为 Fact 还是 Episode?
"用户说他的项目用 React + TypeScript,但他考虑迁移到 Vue"

// 作为 Fact: "用户使用 React + TypeScript" — 丢失了"考虑迁移"的动态信息
// 作为 Episode: 保留原文 — 但 Episode 可能很长,检索时不好匹配

Agno LearningMachine 的知识漂移:Agent 从成功案例中学到的策略可能在场景变化后不再适用,但系统没有”遗忘”机制。

# Agent 学到:"用户问代码问题时,先搜 Stack Overflow"
# 存入 learning_db

# 3 个月后 Stack Overflow 改版,很多答案过时了
# 但 Agent 仍然优先搜 SO — 过时的学习策略变成了负资产

LangGraph Checkpoint 的存储膨胀:每个超步都保存完整 Channel 快照(不是增量 diff),长对话的 checkpoint 数据量线性增长。

对话 100 轮 × 每轮 State 约 5KB = 500KB checkpoint 数据
× 1000 并发用户 = 500MB
× 保留 30 天 = 15GB

PostgreSQL 后端可以处理,但 Redis(内存型)就吃不消了。

根本难点

记忆系统的根本难题是 相关性判断本身需要智能。”什么信息在未来有用”是一个需要预测能力的问题——而预测恰恰是 AI 最不确定的能力。

人类大脑通过睡眠时的”记忆固化”(memory consolidation)解决这个问题:重要记忆被反复激活,不重要的逐渐淡忘。当前没有 Agent 框架实现了类似的自适应遗忘机制。


5. 可观测性与调试(★★★)

核心矛盾:Agent 的执行路径是动态的(由 LLM 实时决定),传统的断点调试、日志追踪方法在面对非确定性系统时效果大减。

日常类比:调试一个”每次都走不同路”的迷宫机器人。你设置断点在某个路口,但机器人下次可能根本不经过那个路口。传统调试假设”相同输入→相同路径”,Agent 打破了这个假设。

真实案例

LangSmith trace 的信息过载:一个复杂的 LangGraph 执行可能产生 50+ 个 span,每个 span 包含完整的 prompt/response。人类审计者面对如此多的信息很难定位问题。

Trace:
├── graph.invoke (2.3s)
│   ├── node.research (0.8s)
│   │   ├── llm.call (0.6s) — 2000 token prompt, 500 token response
│   │   └── tool.search (0.2s)
│   ├── node.plan (0.5s)
│   │   └── llm.call (0.5s) — 3000 token prompt, 800 token response
│   ├── node.execute (0.7s)
│   │   ├── llm.call (0.4s)
│   │   ├── tool.code_run (0.2s)
│   │   └── llm.call (0.1s)
│   └── node.review (0.3s)
│       └── llm.call (0.3s)

问题出在哪一步?可能是 research 搜到了错误信息,可能是 plan 制定了错误策略,可能是 execute 的工具调用出错——需要人工逐步排查。

tRPC-Agent-Go 跨服务 trace 的因果链断裂:Agent A 调用 Agent B,B 调用 Agent C。当 C 的结果有误时,trace 能告诉你”C 返回了什么”,但不能告诉你”为什么 A 会选择调用 B 而不是直接调用 C”——决策推理链在 trace 中不可见。

复现困难:由于 LLM 的温度参数(temperature > 0),同样的输入可能产生不同的输出。一个生产环境中偶尔出现的 bug 可能在调试环境中无法复现。

根本难点

Agent 系统的可观测性难题源于 非确定性 + 高维状态空间。传统可观测性三支柱(Metrics/Logs/Traces)假设系统行为是确定性的——相同条件下可复现。Agent 打破了这个假设。

需要新的可观测性范式:


6. 生产环境扩展性(★★★★★)

核心矛盾:Agent 的单次执行涉及多次 LLM 调用 + 工具调用 + 状态读写,延迟高、资源占用重。高并发场景下,传统 Web 服务的扩展模式(无状态 + 负载均衡)不直接适用于有状态的 Agent。

日常类比:餐厅服务。普通菜品(无状态 API)→ 任何服务员都能上菜;定制大餐(有状态 Agent)→ 同一个厨师必须从头跟到尾(因为他记得你的口味偏好和之前做了哪些菜)。后者很难通过”多招几个厨师”来线性扩展。

真实案例

LangGraph Cloud 的冷启动延迟:每次新对话开始时,需要初始化 Graph + 加载 Checkpoint + 预热连接。

冷启动:Graph 编译 (50ms) + Checkpoint 加载 (100ms) + LLM 连接 (200ms) = 350ms
热路径:LLM 调用 (500-3000ms/步) × 5-10 步 = 2.5-30s 总延迟

对于实时交互场景(如客服 chatbot),350ms 冷启动已经可感知。

tRPC-Agent-Go 的 Session 后端瓶颈:9 种 Session 后端中,Redis 最快但容量有限,PostgreSQL 容量大但每次状态读写有 2-5ms 网络延迟。在 ReAct 循环的每一步都需要读写 Session 时,延迟累积显著。

5 步 ReAct 循环 × 每步 2 次 Session 读写 × 3ms/次 = 30ms 额外延迟
看起来不多,但在 1000 QPS 下,Session 后端承受 10000 次/秒读写

LLM API 的 rate limit:所有框架共同面临的瓶颈——上游 LLM API 有 TPM(tokens per minute)和 RPM(requests per minute)限制。多 Agent 系统的 LLM 调用量是单 Agent 的 N 倍。

Coordinator + 3 Worker Agents × 5 步/Agent = 20 次 LLM 调用/请求
× 100 并发请求 = 2000 RPM
GPT-4 Tier 1 限制 = 500 RPM → 必须排队

根本难点

生产扩展性的根本挑战是 有状态 + 长执行时间 + 外部依赖三重叠加:

  1. 有状态:不能简单水平扩展(Session Affinity 或分布式状态)
  2. 长执行:一次 Agent 执行可能持续 30+ 秒,占用连接和内存
  3. 外部依赖:LLM API rate limit 是不可控的外部瓶颈

tRPC-Agent-Go 通过微服务框架继承了负载均衡和熔断限流,但本质上只是把问题推迟到了 Session 后端——后端本身的扩展性仍需要工程投入。


7. 规划与推理质量(★★★★)

核心矛盾:Agent 需要在执行前规划(先想后做),但规划本身依赖 LLM——而 LLM 在长链推理中的可靠性会随步数增加而下降。

日常类比:让一个五年级学生规划一场公司年会。他可能列出”订酒店、请嘉宾、准备节目”等合理步骤,但细节(预算分配、时间冲突处理、Plan B)往往不够周全。更致命的是,计划写得头头是道,执行时才发现很多步骤不可行。

真实案例

tRPC-Agent-Go Planner 的规划脆弱性:Planner 生成的 Plan 可能在执行第 3 步时发现前提不成立,需要 Replan。但 Replan 依赖 LLM 对”哪里出了问题”的正确诊断——而这个诊断本身也可能出错。

// 原始计划
Plan: [
    Step 1: 搜索用户的历史订单   成功
    Step 2: 分析消费趋势       成功
    Step 3: 生成推荐方案        失败数据不足
]

// Replan
// LLM 诊断:"数据不足是因为搜索范围太窄"  ← 可能是错误诊断
// 实际原因:用户是新用户,根本没有历史订单

CrewAI Sequential 的计划刚性:任务执行顺序在定义时固定,无法根据运行时情况动态调整。

# 定义时:research → write → review
# 运行时:research 发现"这个话题不值得写"
# 问题:仍然会继续执行 write 和 review——浪费 token

LangGraph 的条件边爆炸:为了处理各种异常情况,条件边会越加越多,最终图的复杂度超出人类理解能力。

# 开始:2 个条件边,清晰易懂
graph.add_conditional_edges("check", route, {"pass": "next", "fail": "retry"})

# 6 个月后:12 个条件边,没人敢改
graph.add_conditional_edges("check", route, {
    "pass": "next", "fail": "retry", "timeout": "fallback",
    "rate_limit": "wait", "auth_error": "reauth", "partial": "supplement",
    "ambiguous": "clarify", "duplicate": "dedupe", "stale": "refresh",
    "forbidden": "escalate", "not_found": "search_alt", "error": "log_and_skip"
})

根本难点

规划质量的根本问题是 LLM 不真正”理解”因果关系。它生成的计划是基于训练数据中”看起来像合理计划”的模式匹配,不是基于对任务的深层理解。

这意味着:


8. Human-in-the-Loop(★★★)

核心矛盾:把人类引入 Agent 循环可以提升可靠性(人审批关键操作),但同时破坏了自动化的核心价值(效率)。找到”什么时候该问人”的平衡点极其困难。

日常类比:自动驾驶的 L3 级别。系统处理 95% 的路况,但偶尔让你”接管方向盘”。问题是:你不知道什么时候会被要求接管,必须时刻保持注意力——这比自己开还累。

真实案例

LangGraph GraphInterrupt 的时机判断:什么操作需要人审批?框架无法自动判断——必须开发者手动在代码中埋入 raise GraphInterrupt()

def execute_action(state):
    if state["action"] == "delete_all_data":
        raise GraphInterrupt(value="确认删除所有数据?")  # 开发者手动判断
    if state["action"] == "send_email":
        raise GraphInterrupt(value="确认发送邮件?")  # 开发者手动判断
    # 忘记在 "transfer_money" 加 interrupt → 直接执行 → 出事了

中断恢复的状态一致性:人类可能在中断后数小时甚至数天才恢复——这期间系统状态可能已经变化。

# T=0: Agent 查询库存 = 100,触发 GraphInterrupt("确认下单 50 件?")
# T=2h: 人类点击"确认"
# 但 T=1h 时另一个订单已经消耗了 80 件库存 → 实际库存 = 20
# 恢复执行时下单 50 件 → 超卖!

审批疲劳:如果 interrupt 太频繁,人类会形成”无脑点确认”的习惯——失去了 human-in-the-loop 的意义。

Agent 执行 1000 个任务/天,每个任务 2 次 interrupt = 2000 次审批
人类平均 3 秒/次 = 100 分钟/天花在"点确认"上
第一个月:认真看每个审批请求
第三个月:条件反射式点"approve"
→ Human-in-the-loop 退化为 Human-rubber-stamp

根本难点

Human-in-the-loop 的根本困境是 信任校准

理想状态是”系统在不确定时自动请求人审批,确定时自动执行”——但”确定/不确定”的判断本身就是最难的 AI 问题之一。


难度分层总结

第一层:工程可解(★★★)— 有成熟方案,投入人力即可

难点 当前最佳实践 成熟度
可观测性 OpenTelemetry + LangSmith + Langfuse 80%(缺决策推理可视化)
Human-in-the-Loop GraphInterrupt + Checkpoint 70%(缺自动置信度评估)

这一层的问题本质上是”已知解法但实现不完善”。给够工程资源就能解决。

第二层:设计权衡(★★★★)— 没有完美解,只有适合场景的取舍

难点 核心 trade-off 为什么无法同时满足
Tool Calling 可靠性 灵活性 vs 类型安全 LLM 概率生成本质
记忆系统 完整性 vs context window 信息量 vs 有限注意力
规划质量 规划深度 vs 执行速度 规划本身消耗推理资源

这一层的问题需要根据具体场景做取舍决策——没有通用最优解。

第三层:基础研究(★★★★★)— 当前技术栈无法根本解决

难点 为什么是基础问题 突破方向
状态管理与一致性 Agent 有状态 + LLM 无状态的根本矛盾 新型状态机模型(不依赖 LLM 做一致性保证)
多 Agent 协作控制 涌现行为 + 非确定性 = 不可预测 形式化验证 + 协议约束(但会牺牲灵活性)
生产环境扩展性 有状态 + 长执行 + 外部限制三重约束 需要新的 Agent 原生调度范式

这一层的问题不是”工程做得不够好”,而是”当前的技术基础有结构性限制”。解决它们可能需要:新的 LLM 架构(如原生支持状态持久化的模型)、新的分布式计算范式(为 Agent 设计而非为请求-响应设计)、新的形式化方法(证明多 Agent 系统的安全性属性)。


商业级产品的应对策略:Codex 与 Claude Code

上述 8 大挑战在商业级 coding agent 中有了实战解法。以下对照表展示 OpenAI Codex 和 Claude Code 如何应对:

挑战 Codex 解法 Claude Code 解法
状态管理 Rollout JSONL + SQLite 持久化;auto-compaction 压缩长对话 推测:conversation state + checkpoint
Tool Calling 可靠性 ExecPolicy 规则引擎预过滤 + Sandbox 物理隔离 + Escalation 重试 ToolUseBlock 标准化 + 权限分类器
多 Agent 协作 子进程 spawn + Guardian 审查(弱多 Agent) Subagent → Coordinator → Swarm 四层递进
记忆系统 两阶段 pipeline(并行提取 + git-baseline 串行合并)→ MEMORY.md 推测:conversation memory + project indexing
可观测性 App-Server JSON-RPC 事件流 + 客户端 UI 实时展示 推测:内部遥测 + CLI 输出
生产扩展性 本地执行(无分布式);Cloud Tasks 异步卸载 推测:单进程 + batch mode
规划能力 Plan tool(显式规划步骤)+ 模型自由循环 推测:模型自由规划
Human-in-the-Loop 5 级审批(UnlessTrusted→Never)+ Hooks 自定义 四层权限(Allow/PowerUser/Normal/Deny)

详见:Codex 工具循环 / Codex 沙箱 / Codex 记忆


对犀牛鸟参与者的启示

理解这些难点的价值不在于”解决它们”——大部分是开放研究问题。价值在于:

  1. 选择贡献方向时有判断力:第一层问题适合工程贡献(PR),第三层适合研究贡献(论文/设计文档)
  2. 阅读源码时知道在看什么:StateGraph 的 6192 行为什么那么长?因为状态管理本身就是这个难度
  3. 设计自己的 Agent 时少踩坑:知道 trade-off 就不会追求”完美方案”,而是根据场景做最合理的妥协
  4. 和 mentor 讨论时有深度:能聊”为什么 Coordinator 模式有单点瓶颈但仍然是主流选择”,比”Coordinator 模式是怎么工作的”高一个层次
  5. 有商业级参考:对照 Codex/Claude Code 的实战解法,理解”工业界选了什么 trade-off”