0Pricing
AI Agents · 课时

常见的代理循环故障

无限循环、重复进行相同的工具调用,以及始终无法得到最终答案。

常见的代理循环故障 是 CoddyKit 上的免费 AI Agents 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Agents 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Agents 课程共包含 4 节课。

代理循环及其失败模式

代理循环会反复执行:推理 → 调用工具 → 观察结果 → 再次推理。这个循环功能强大,但也很脆弱。多个广为人知的失败模式可能会困住代理、浪费令牌,并且无法产生有用的输出。

了解这些失败模式,是做好防范的第一步。

失败 1:无限循环

当代理反复使用相同参数调用同一工具,却没有取得进展时,就会发生无限循环。如果工具返回了无帮助的结果,而代理无法通过推理摆脱困境,就可能出现这种情况。

# Example of an agent in an infinite loop:
# Step 1: reasoning='Need to search for Python docs'
#         tool='search_web', args={'query': 'Python documentation'}
# Step 2: reasoning='Search result was unhelpful, try again'
#         tool='search_web', args={'query': 'Python documentation'}
# Step 3: reasoning='Search result was unhelpful, try again'
#         tool='search_web', args={'query': 'Python documentation'}
# ... repeats until max_iterations or token budget is exhausted

print('Symptom: same tool + same arguments appearing repeatedly in steps')
print('Fix: detect repeated (tool, args) pairs and break the loop')

失败 2:卡住状态

卡住状态是无限循环的一种更隐蔽的形式。代理会持续推理并调用不同的工具,却无法收敛到最终答案。它在不同方法之间来回切换,却没有取得进展。

# Example of a stuck agent:
# Step 1: tool='search_web', args={'query': 'topic A'}
# Step 2: tool='search_web', args={'query': 'topic B'}  # different args
# Step 3: tool='search_web', args={'query': 'topic A'}  # back to first
# Step 4: tool='read_document', args={'url': '...'}
# Step 5: tool='search_web', args={'query': 'topic A'}
# ... no FINAL_ANSWER ever produced

print('Symptom: agent takes many steps but never calls FINAL_ANSWER')
print('Fix: max_iterations guard + force final answer if limit is near')

失败 3:缺少最终答案

有些代理会一直循环,始终不判断任务是否已完成。它们收集信息,却从未停下来整合并返回结果。这会浪费令牌和时间。

# An agent that never concludes:
def run_agent_bad(query: str, max_steps: int = 20) -> str:
    for step in range(max_steps):
        action = llm_decide_action(query, history)

        if action['type'] == 'tool':
            result = execute_tool(action)
            history.append(result)
        # BUG: No check for 'final_answer' type!
        # The agent loops until max_steps, returning None

    return None  # never actually returns an answer

# Fix: explicitly check for final_answer signal
def run_agent_good(query: str, max_steps: int = 20) -> str:
    for step in range(max_steps):
        action = llm_decide_action(query, history)
        if action['type'] == 'final_answer':
            return action['answer']  # exit cleanly
        execute_tool(action)
    return 'Reached step limit without a conclusion.'

失败 4:工具调用解析错误

当 LLM 为函数调用生成格式错误的 JSON 时,工具执行器无法解析它。编写不佳的代理会崩溃,或静默地跳过该步骤。健壮的代理会捕获解析错误,并将错误反馈给 LLM。

import json

def safe_parse_tool_call(arguments_str: str) -> dict:
    try:
        return json.loads(arguments_str)
    except json.JSONDecodeError as e:
        print(f'Failed to parse tool arguments: {e}')
        print(f'Raw: {arguments_str}')
        return None

def execute_step(tool_call) -> str:
    args = safe_parse_tool_call(tool_call.function.arguments)
    if args is None:
        # Feed the error back to the LLM in the next step
        return f'ERROR: Could not parse tool arguments. Raw: {tool_call.function.arguments}'
    return run_tool(tool_call.function.name, args)

失败 5:工具未返回有用数据

工具在技术上可能执行成功(没有异常),却返回空数据或无用数据。代理必须处理这种情况,不能假定每次工具调用都会返回可供采取行动的信息。

def run_agent_with_empty_result_handling(query: str) -> str:
    for step in range(20):
        action = decide_next_action(query, history)

        if action['type'] == 'final_answer':
            return action['answer']

        result = execute_tool(action['tool'], action['args'])

        # Detect empty results and provide context
        if not result or result.strip() == '':
            observation = f'Tool {action["tool"]} returned no data. Try a different approach or different arguments.'
        elif 'error' in result.lower():
            observation = f'Tool error: {result}. Consider a different tool or query.'
        else:
            observation = result

        history.append({'tool': action['tool'], 'result': observation})

    return 'Could not complete task within step limit.'

失败 6:虚构的工具名称

LLM 有时会生成不存在的工具名称。尝试调用之前,务必根据已注册的工具验证工具名称。发生这种情况时,请向代理返回信息明确的错误。

REGISTERED_TOOLS = {
    'search_web': search_web_function,
    'get_weather': get_weather_function,
    'calculate': calculate_function
}

def dispatch_tool(tool_name: str, args: dict) -> str:
    if tool_name not in REGISTERED_TOOLS:
        available = ', '.join(REGISTERED_TOOLS.keys())
        return (
            f'ERROR: Unknown tool "{tool_name}". '
            f'Available tools: {available}. '
            f'Please use one of the available tools.'
        )

    tool_fn = REGISTERED_TOOLS[tool_name]
    return tool_fn(**args)

失败 7:令牌预算耗尽

长时间运行且将完整工具结果存入上下文的代理,可能会达到 LLM 的上下文窗口上限。在将大型工具结果添加到历史记录之前,请先进行摘要或截断。

def truncate_tool_result(result: str, max_chars: int = 2000) -> str:
    if len(result) <= max_chars:
        return result
    truncated = result[:max_chars]
    return f'{truncated}\n... [result truncated to {max_chars} chars]'

def add_observation_to_history(history: list, tool_name: str, result: str):
    safe_result = truncate_tool_result(result, max_chars=2000)
    history.append({
        'role': 'tool',
        'content': safe_result,
        'tool_name': tool_name
    })
    print(f'[Step] Tool={tool_name}, Result length={len(result)} (stored {len(safe_result)})')

if __name__ == '__main__':
    demo_history = []
    add_observation_to_history(demo_history, 'search_web', 'x' * 3000)

通过程序检测失败模式

请编写一个诊断函数,分析代理的步骤历史,以识别发生了哪种失败模式。这在调试期间极其有价值。

def diagnose_agent_failure(steps: list) -> str:
    if not steps:
        return 'No steps recorded'

    # Check for infinite loop: same (tool, args) repeated
    seen = {}
    for s in steps:
        key = (s.get('tool'), str(s.get('args')))
        seen[key] = seen.get(key, 0) + 1
    repeated = {k: v for k, v in seen.items() if v > 2}
    if repeated:
        return f'INFINITE_LOOP: repeated actions: {repeated}'

    # Check for missing final answer
    has_answer = any(s.get('type') == 'final_answer' for s in steps)
    if not has_answer and len(steps) >= 15:
        return 'STUCK_STATE: many steps taken but no final answer'

    # Check for parse errors
    errors = [s for s in steps if 'ERROR' in str(s.get('result', ''))]
    if len(errors) > 2:
        return f'TOOL_ERROR: {len(errors)} tool errors in pipeline'

    return 'OK'

if __name__ == '__main__':
    demo_steps = [{'tool': 'search_web', 'args': {'q': 'weather'}} for _ in range(3)]
    print('Diagnosis:', diagnose_agent_failure(demo_steps))

实现简单的步骤预算

每个生产环境的代理循环都必须设置硬性步骤上限。这是最重要的安全机制——无论 LLM 作何决定,它都能保证循环终止。

def run_agent_with_budget(query: str, max_steps: int = 15) -> dict:
    history = []
    for step in range(1, max_steps + 1):
        print(f'[Step {step}/{max_steps}]')

        action = decide_next_action(query, history)

        if action['type'] == 'final_answer':
            return {
                'status': 'success',
                'answer': action['answer'],
                'steps_taken': step
            }

        result = execute_tool(action['tool'], action['args'])
        history.append({'step': step, 'tool': action['tool'], 'result': result})

        if step == max_steps - 1:
            # Warn the agent it must conclude
            history.append({'role': 'system',
                            'content': 'You must provide a FINAL_ANSWER on the next step.'})

    return {'status': 'timeout', 'answer': None, 'steps_taken': max_steps}

快速参考:失败模式及修复方法

以下是六种代理循环失败模式及其修复方法:

  • 无限循环:检测重复的(工具、参数)对;通过错误反馈中断循环
  • 卡住状态:设置最大迭代次数防护机制;接近上限时强制返回最终答案
  • 缺少最终答案:明确检查操作中是否存在最终答案信号
  • 解析错误:将 JSON 解析放入异常捕获结构中;将错误反馈给 LLM
  • 空工具结果:检测空字符串;提供“无数据”反馈
  • 虚构的工具名称:根据已注册的工具进行验证;返回错误消息

知识检查:代理循环失败模式

请测试您对常见代理循环失败模式的理解。

回顾:常见的代理循环失败模式

您现在可以识别并防范主要的代理循环失败模式:

  • 无限循环、卡住状态和缺少最终答案,都需要最大迭代次数防护机制
  • 工具调用解析错误需要在 JSON 解析外层加入异常捕获结构
  • 空工具结果需要进行检测,并向 LLM 提供信息明确的反馈
  • 虚构的工具名称需要根据已注册的工具列表进行验证
  • 令牌预算耗尽需要截断结果

健壮的代理循环会预先考虑所有这些失败模式,并以恰当的方式进行处理。

常见问题解答

「常见的代理循环故障」课时是免费的吗?

是的 — 「常见的代理循环故障」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Agents 课程的其余内容,请升级到 CoddyKit PRO。 AI Agents 课程共包含 4 节课。

「常见的代理循环故障」这节课中我会学到什么?

无限循环、重复进行相同的工具调用,以及始终无法得到最终答案。 你通过在浏览器中直接运行的动手代码来练习 AI Agents,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 AI Agents 需要有经验吗?

无需任何先前经验。CoddyKit 上的 AI Agents 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「常见的代理循环故障」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 AI Agents 课中编写并运行代码吗?

能。每节 AI Agents 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 常见的代理循环故障
  2. 代理步骤的跟踪日志
  3. 检测并打破无限循环
  4. 逐步调试技术
← 返回 AI Agents