架构9. 将错误信息压缩至上下文窗口
智能体的优势之一在于“自我修复”——对于短任务,大语言模型(LLM)可能会调用某个失败的工具。优秀的 LLM 有很大概率能够读取错误信息或堆栈跟踪,并在后续的工具调用中找出需要修改的地方。
大多数框架都实现了这一功能,但你也可以在不实现其他 11 个架构的情况下,仅实现这一条。下面是一个示例:
thread = {"events": [initial_message]}
while True:
next_step = await determine_next_step(thread_to_prompt(thread))
thread["events"].append({
"type": next_step.intent,
"data": next_step,
})
try:
result = await handle_next_step(thread, next_step) # our switch statement
except Exception as e:
# if we get an error, we can add it to the context window and try again
thread["events"].append({
"type": 'error',
"data": format_error(e),
})
# loop, or do whatever else here to try to recover
你可能需要为特定的工具调用实现一个错误计数器,以将单个工具的尝试次数限制在约 3 次,或者根据你的用例采用其他合理的逻辑。
consecutive_errors = 0
while True:
# ... existing code ...
try:
result = await handle_next_step(thread, next_step)
thread["events"].append({
"type": next_step.intent + '_result',
data: result,
})
# success! reset the error counter
consecutive_errors = 0
except Exception as e:
consecutive_errors += 1
if consecutive_errors < 3:
# do the loop and try again
thread["events"].append({
"type": 'error',
"data": format_error(e),
})
else:
# break the loop, reset parts of the context window, escalate to a human, or whatever else you want to do
break
}
}
达到一定的连续错误阈值可能是一个上报给人工处理的好时机,无论是通过模型决策还是通过确定性接管控制流。
好处:
- 自我修复 :LLM 可以读取错误信息,并在后续的工具调用中找出需要修改的地方。
- 持久性 :即使一个工具调用失败,智能体也可以继续运行。
我相信你会发现,如果过度使用这种方法,你的智能体可能会开始失控,并可能反复出现相同的错误。
这时就需要架构 8 - 掌控你的控制流和架构 3 - 掌控你的上下文构建了——你不需要只是将原始错误信息放回上下文,你可以完全重构其表示方式、从上下文窗口中移除先前的事件,或者采取任何你认为有效的确定性措施来让智能体重回正轨。
但防止错误失控的首要方法是采用架构 10 - 小型、专注的智能体。