背景
当前 LocalAgentRunner(src/langbot/pkg/provider/runners/localagent.py)的 Agent 循环(while pending_tool_calls:)缺乏必要的保护机制,存在上下文溢出风险。
现状分析
1. 无循环迭代上限
while pending_tool_calls: # 没有迭代次数限制
for tool_call in pending_tool_calls:
...
# 再次调用 LLM
pending_tool_calls = final_msg.tool_calls
如果 LLM 持续返回 tool_calls(模型幻觉、工具返回异常结果导致模型反复重试等),循环不会终止。每轮迭代至少新增 2 条消息(工具结果 + LLM 响应),上下文会无限膨胀。
2. 工具返回结果无长度限制
func_ret = await self.ap.tool_mgr.execute_func_call(func.name, parameters, query=query)
# 结果直接序列化后加入消息,无截断
req_messages.append(Message(role='tool', content=json.dumps(func_ret), ...))
如果工具返回了大量内容(例如爬取整个网页、查询返回大量数据),整个内容会原样塞入上下文,可能单次就接近或超出模型 context window。
3. 无发送前的 token 预估
在调用 LLM API 之前,没有对 req_messages 的总 token 量进行估算和检查。当前唯一的失败点是 LLM API 返回 context length exceeded 错误,这是被动失败而非主动保护。
4. 轮次截断不覆盖当前轮
现有的 RoundTruncator(max-round 默认 10)只截断历史对话轮次,对当前这一轮 Agent loop 内部不断累积的工具调用消息不起作用,因为这些都属于"当前轮"。
建议
a) 增加 Agent Loop 最大迭代次数
max_iterations = config.get('max-tool-iterations', 16)
iteration_count = 0
while pending_tool_calls and iteration_count < max_iterations:
iteration_count += 1
...
if iteration_count >= max_iterations:
# 强制终止,返回当前已有的回复或提示信息
b) 工具返回结果截断
对工具返回的内容设置最大长度,超出部分截断并附加提示:
MAX_TOOL_RESULT_LENGTH = 8000 # 字符数,可配置
result_str = json.dumps(func_ret, ensure_ascii=False)
if len(result_str) > MAX_TOOL_RESULT_LENGTH:
result_str = result_str[:MAX_TOOL_RESULT_LENGTH] + "\n...[结果已截断]"
c) 发送前 token 预估(可选)
在每次调用 LLM 之前,用 tiktoken 或粗略估算(字符数 / 比例系数)检查总 token 量,如果接近模型上限,主动裁剪较早的工具调用结果或进行摘要。
影响
缺乏这些保护机制可能导致:
- 成本失控:无限循环持续消耗 API token
- 请求失败:上下文超出模型窗口限制时 API 报错,用户得到错误而非回复
- 服务稳定性:大量 token 的请求可能导致响应超时
主流框架的做法参考:
- LangChain
AgentExecutor:有 max_iterations 参数(默认 15)
- OpenAI Assistants API:有
max_prompt_tokens 限制
- AutoGPT / CrewAI:均有迭代上限和 token budget 控制
背景
当前
LocalAgentRunner(src/langbot/pkg/provider/runners/localagent.py)的 Agent 循环(while pending_tool_calls:)缺乏必要的保护机制,存在上下文溢出风险。现状分析
1. 无循环迭代上限
如果 LLM 持续返回 tool_calls(模型幻觉、工具返回异常结果导致模型反复重试等),循环不会终止。每轮迭代至少新增 2 条消息(工具结果 + LLM 响应),上下文会无限膨胀。
2. 工具返回结果无长度限制
如果工具返回了大量内容(例如爬取整个网页、查询返回大量数据),整个内容会原样塞入上下文,可能单次就接近或超出模型 context window。
3. 无发送前的 token 预估
在调用 LLM API 之前,没有对
req_messages的总 token 量进行估算和检查。当前唯一的失败点是 LLM API 返回 context length exceeded 错误,这是被动失败而非主动保护。4. 轮次截断不覆盖当前轮
现有的
RoundTruncator(max-round默认 10)只截断历史对话轮次,对当前这一轮 Agent loop 内部不断累积的工具调用消息不起作用,因为这些都属于"当前轮"。建议
a) 增加 Agent Loop 最大迭代次数
b) 工具返回结果截断
对工具返回的内容设置最大长度,超出部分截断并附加提示:
c) 发送前 token 预估(可选)
在每次调用 LLM 之前,用 tiktoken 或粗略估算(字符数 / 比例系数)检查总 token 量,如果接近模型上限,主动裁剪较早的工具调用结果或进行摘要。
影响
缺乏这些保护机制可能导致:
主流框架的做法参考:
AgentExecutor:有max_iterations参数(默认 15)max_prompt_tokens限制