2026年10月2日
今天的学习主线其实非常集中:一个 Agent 能不能稳定完成任务,真正决定因素并不只是 LLM 会不会选工具,而是整个执行系统能不能把模型一次次“不稳定的决策”,约束成一个可控、可恢复、可终止的工程流程。
从“工具选择准确率为什么不等于任务完成率”,一路延伸到了 Timeout、Retry、Idempotency,再到 ReAct、Plan-and-Execute,最后真正落到了Runtime(运行时)和 Harness(工程控制框架)。
我今天真正形成的一个认知是:
LLM 负责提出下一步应该做什么,但生产系统不能把“任务是否继续执行”这件事完全交给 LLM。
一、工具选择准确率高,不代表 Agent 的任务完成率高
我之前比较容易关注一个指标:
模型有没有选择正确的 Tool?
但对真实 Agent 来说,这个指标远远不够。
假设一个任务需要连续执行 5 个步骤,每一步成功率都是 $p$。在非常理想化地假设每一步相互独立、成功率相同的情况下,完整任务成功率可以粗略理解为:
$$P(\text{complete})=p^n$$
其中:
$p$:单个步骤的成功概率
$n$:任务需要连续完成的步骤数
$P(\text{complete})$:整个任务最终成功的概率
例如每一步成功率已经有 90%:
$$0.9^5\approx0.59$$
也就是说,一个看起来“每一步都挺准”的 Agent,连续执行多个步骤以后,端到端成功率可能迅速下降。
当然,真实 Agent 的步骤并不是完全独立的,所以这个公式不能直接拿来计算线上成功率。它更重要的价值是帮助理解:
Agent 是一个 trajectory(执行轨迹)系统,而不是一次分类任务。
一次工具选择正确,并不代表:
参数一定正确
API 一定成功
网络不会超时
Observation 能被正确理解
下一步决策不会出错
Agent 不会进入死循环
最终状态真的满足用户目标
所以在生产系统中,应该关注End-to-End Task Success Rate(端到端任务完成率),而不能只关注 Tool Selection Accuracy(工具选择准确率)。
二、Timeout、Retry 和 Idempotency 本质上是一个问题链
今天我比较重要的一次认知修正,是不应该把 Timeout、Retry、Idempotency 看成三个互相独立的功能。
它们实际上是一条连续的工程因果链。
假设 Agent 调用一个支付接口:
Agent ↓ 扣款 API ↓ 等待响应…… ↓ TimeoutTimeout 只说明:
客户端在规定时间内没有收到结果。
它并不能说明:
服务端一定没有执行成功。
最危险的情况是:
第一次请求: 服务端已经扣款成功 ↓ 响应在网络中丢失 ↓ 客户端 Timeout ↓ Agent Retry ↓ 再次扣款如果只实现 Retry,没有实现幂等,就可能把一次任务执行两次。
所以完整链路应该是:
Timeout ↓ 状态未知 ↓ 需要 Retry ↓ Retry 可能重复执行 ↓ 需要 Idempotency这就是为什么我今天更准确地理解成:
Retry 解决“请求可能失败”的问题,Idempotency 解决“Retry 可能重复成功”的问题。
一个简化的 Python 示例:
processed = {} def charge(order_id: str, amount: float): if order_id in processed: return processed[order_id] result = {"order_id": order_id, "amount": amount, "status": "success"} processed[order_id] = result return result这里order_id就承担了类似Idempotency Key(幂等键)的作用。
同一个order_id即使重复执行:
charge("order_001", 100) charge("order_001", 100)第二次也不会再次执行真实扣款逻辑,而是返回第一次执行结果。
真实生产系统当然不会只使用 Python 字典,而通常需要数据库唯一约束、持久化状态或者分布式一致性机制。
但底层思想没有变:
任何带副作用的 Tool,只要允许 Retry,就必须认真考虑幂等性。
三、Plan-and-Execute 到底解决了 ReAct 的什么问题?
我之前容易把两者理解成两种不同的 Agent“写法”。
今天更准确地理解是:
它们本质上是在解决决策粒度(decision granularity)不同的问题。
ReAct:边观察,边决定下一步
典型流程:
Thought ↓ Action ↓ Observation ↓ Thought ↓ Action它的优势非常明显:
能快速根据环境反馈调整
Tool 失败以后可以立即修改策略
适合开放环境
不需要提前生成完整计划
问题是,它非常容易产生一种Local Decision(局部决策):
模型每一次只考虑:
“我现在下一步做什么?”
而不是始终维护:
“距离最终目标还差哪几步?”
任务一旦变长,就容易出现:
重复调用工具
忘记前面的目标
在局部信息中反复试错
路径越来越长
Goal Drift(目标漂移)
Plan-and-Execute:先规划,再执行
它会先生成类似:
Goal ↓ Plan ├─ Step 1 ├─ Step 2 ├─ Step 3 └─ Step 4Executor 再逐步执行。
它解决的核心问题不是“ReAct 不会调用工具”,而是:
给复杂多步骤任务建立一个全局任务结构。
例如用户要求:
查找订单 → 判断是否超时 → 查询退款规则 → 创建退款工单 → 返回结果。
ReAct 可能一步一步临时决定。
Plan-and-Execute 则先形成任务分解:
1. 查询订单 2. 判断当前状态 3. 查询退款规则 4. 判断是否符合退款条件 5. 创建工单 6. 汇总结果这种架构更适合 Long-Horizon Task(长程任务)。
但它也引入了新的问题。
1. Planning Overhead
规划本身需要一次甚至多次模型调用,会增加:
Token
延迟
成本
2. Error Propagation
如果第一版计划错了,后续 Executor 可能只是非常认真地执行一个错误计划。
3. Plan Staleness
真实世界会变化。
例如原计划:
查询库存 → 创建订单 → 支付执行过程中发现库存已经没有了。
如果 Agent 仍然机械执行旧 Plan,就会失败。
所以生产系统更合理的方式不是:
Plan Once, Execute Forever。
而是:
Plan → Execute → Observe → Replan
这也是为什么现代 Agent 架构经常不是纯 ReAct 或纯 Plan-and-Execute,而是混合设计。
四、LLM 可以决定“任务完成了”,但 Runtime 必须拥有最终停止权
这是今天我认为最值得保留的一点。
Agent 执行过程中,LLM 完全可以输出:
任务已经完成,可以结束。这属于一种Semantic Stop(语义终止)。
问题是:
LLM 本身并不是一个可靠的程序控制器。
它可能:
一直认为任务还没完成
重复调用同一个 Tool
Tool 连续失败以后仍然重试
在 Observation 中来回循环
消耗大量 Token
因错误状态永远无法结束
所以生产系统必须提供Hard Stop Conditions(硬终止条件)。
典型包括:
max_stepstimeoutmax_retriestoken_budgetcost_budgetrepeated-action detection
permission / safety boundary
一个极简 Runtime 循环可以写成:
MAX_STEPS = 10 for step in range(MAX_STEPS): action = agent.decide() if action.type == "finish": break result = execute_tool(action) else: raise RuntimeError("Agent exceeded max steps")这里有两个终止层级。
第一层:
action.type == "finish"这是模型提出:
我觉得完成了。
第二层:
MAX_STEPS这是系统规定:
无论你觉得完没完成,到这里都必须停。
这让我真正理解了生产级 Agent 的一个核心原则:
LLM 可以拥有决策权,但不能拥有无限执行权。
五、Agent、Runtime、Harness 和 MCP,不应该混成一层
这几个概念之前很容易混在一起。
今天我重新建立了一套更清晰的边界。
Agent
Agent 更偏向:
决策逻辑。
它根据:
Goal + Context + State + Observation决定:
下一步做什么?例如:
搜索知识库
查询订单
调用计算器
创建工单
返回答案
Runtime
Runtime 是Execution and Control Layer(执行与控制层)。
它真正负责的是:
Agent 决定调用 Tool ↓ 参数校验 ↓ 权限检查 ↓ 执行 Tool ↓ Timeout ↓ Retry ↓ 状态更新 ↓ 日志 / Trace ↓ Observation ↓ 重新交给 Agent所以 Runtime 解决的是:
Agent 的决定到底怎样安全、稳定地执行。
Harness
Harness 的范围通常比 Runtime 更大。
我现在更倾向于把它理解成:
围绕 LLM 搭建的一整套工程控制框架。
它可能包含:
Agent Harness ├─ Prompt / Context ├─ Model ├─ Tool Registry ├─ Memory / State ├─ Planner ├─ Runtime ├─ Guardrails ├─ Retry / Timeout └─ Observability因此:
一个完整 Agent 系统可以看成一个 Harness,但不能简单地说 Harness = Agent。
Agent 更多代表智能决策部分,Harness 则是把模型包装成可运行软件系统的整体工程结构。
MCP
MCP 今天也顺带和 Runtime 的边界更加清楚了。
MCP 主要解决:
工具和数据到底以什么标准方式暴露给 AI 应用。
例如原来:
Agent → GitHub SDK Agent → Database SDK Agent → Slack SDK Agent → File SDK每一个系统都需要不同 Adapter。
MCP 希望把它统一为标准协议。
但 MCP 并不负责决定:
“现在为什么调用 GitHub?”
也不负责:
“调用失败以后重试几次?”
更不负责:
“Agent 循环多少次以后必须终止?”
因此可以简单区分:
MCP 解决:怎么接 Agent / Planner 解决:为什么调用、下一步调用什么 Runtime 解决:调用以后怎么可靠地执行这个边界非常重要。
六、今天最需要纠正的几个理解
我原来以为:Timeout 就等于操作失败
实际上:
Timeout 只能说明客户端没有及时拿到结果,服务端状态可能是成功、失败,甚至仍在执行。
因此才会引出 Retry 和 Idempotency。
我原来以为:Plan-and-Execute 比 ReAct 更高级
更准确地说:
两者解决的是不同类型任务的问题,没有简单的高级和低级。
ReAct 更强调实时反馈。
Plan-and-Execute 更强调长任务的全局结构。
生产系统中往往会组合使用。
我原来以为:Agent 判断完成以后,系统就可以结束
实际上:
模型的
finish只是语义上的终止信号。
真正的生产系统还必须拥有 Runtime 级别的硬终止条件。
我原来以为:MCP 已经负责了 Agent 的工具调用系统
实际上:
MCP 更接近Tool Connectivity Standard(工具连接标准)。
真正负责:
Retry
Timeout
Permission
State
Loop Control
Failure Recovery
的是 Agent Runtime / Harness 这一层。
七、和真实 Agent 项目的关系
如果以后自己设计一个企业级 Agent,我现在会把系统拆成:
User Request ↓ Agent / Planner ↓ Tool Selection ↓ Runtime ↓ Validation ↓ Permission ↓ Tool / MCP Server ↓ Timeout / Retry / Idempotency ↓ Observation ↓ State Update ↓ Agent并在 Runtime 外层加入:
max_steps max_retry timeout token_budget cost_budget repeat_detection这样设计以后,我才真正开始把 Agent 从:
“LLM 会调用几个工具”
理解成:
一个由概率模型负责决策、确定性 Runtime 负责约束和执行的软件系统。
这两者缺一不可。