Agent 协议:意图、执行与观察必须成对
一个最小 Agent 回合包含三件事:模型提出动作,执行器决定是否允许并运行,系统把带来源的观察回填到下一轮上下文。模型输出工具名不等于工具已经执行;工具返回结果也不等于业务已经完成。内部协议应保存 run_id、step_id、call_id 和工具版本,才能重放、排障和防止迟到结果污染新任务。
第一个可运行实验:按 call ID 配对观察
保存为 protocol.py,用 Python 3.12 运行。
python
def attach_observations(calls, results):
by_id = {r['call_id']: r for r in results}
if len(by_id) != len(results):
raise ValueError('duplicate call id')
out = []
for call in calls:
if call['id'] not in by_id:
raise ValueError('missing tool result')
out.append({'call': call, 'observation': by_id[call['id']]})
return out
calls = [{'id': 'a', 'name': 'search'}, {'id': 'b', 'name': 'weather'}]
results = [{'call_id': 'b', 'ok': True}, {'call_id': 'a', 'ok': True}]
paired = attach_observations(calls, results)
assert [item['observation']['call_id'] for item in paired] == ['a', 'b']
try:
attach_observations(calls, [{'call_id': 'a', 'ok': True}])
except ValueError:
print('protocol pairing passed')
else:
raise AssertionError('missing result accepted')结果返回顺序可以和调用顺序不同,协议仍按 ID 配对。并行工具还要记录开始时间、结束时间、超时和取消状态;不能把“没有结果”静默转换成空字符串。跨供应商适配时保留原始事件,内部事件只负责稳定业务语义。
变体实验
加入一个未知 call_id 的结果,要求显式记录为孤儿事件并拒绝回填。再让同一个 call_id 返回两次,说明为什么重试需要新的传输事件 ID,但业务幂等仍应依赖任务意图。
练习
- 为配对记录增加
run_id和step_id,拒绝跨任务结果。 - 设计并行工具中“部分成功、部分失败、整体取消”的状态。
- 说明为什么 call ID 不能单独充当支付或写库的幂等键。