文章

Agent 不是会聊天的机器人:理解它的执行循环

判断一个系统是否称得上 Agent,可以看它有没有真实的工具调用、任务状态和明确的停止条件。

判断一个产品是不是真有 Agent,我会看一个很土的细节:模型说“我要查一下订单”之后,后台有没有发生一次能追踪的工具调用。如果没有,它多半只是在聊天框里描述行动。

普通问答是一问一答。Agent 多走几步:它读当前任务,决定下一步,调用工具,再根据结果继续。听上去简单,麻烦全在“继续”这两个字里。谁保存进度,谁限制权限,什么时候算完成,都得由程序说清楚。

先看这个循环

最小版本不需要复杂框架,大概是这样:

state = initialize(user_request)

while not state.finished and state.steps < MAX_STEPS:
    decision = model.decide(state, available_tools)

    if decision.type == "answer":
        state.finish(decision.content)
    elif decision.type == "tool_call":
        result = runtime.execute(decision.tool, decision.arguments)
        state.observe(result)
    elif decision.type == "clarify":
        state.ask_user(decision.question)
    else:
        state.fail("invalid decision")

return state.output

代码不长,真正要花时间的是 runtime.executestate。模型可以提出“调用退款接口”,运行时还要检查用户身份、金额、参数、超时和确认状态。模型的提议不能直接变成生产动作。

模型、工具和运行时

我倾向于把这三块分开。

模型读自然语言,选择工具,整理答案。它很会处理模糊表达,但不该拿数据库密码,也不该自己拼一段 Shell 命令去生产机执行。

工具把外部能力收窄成几个具体动作,比如 search_ordersget_weathercreate_ticket。每个动作都有固定参数、返回结构和权限范围。名字取得直白一点也没关系,模型需要知道它究竟会做什么。

运行时负责剩下那些不太显眼、出问题却很要命的事:循环次数、状态持久化、重试、幂等、日志和人工确认。以后换模型,通常不用把这些逻辑跟着重写。

别把状态藏在聊天记录里

Agent 每走一步,都要知道刚才做了什么。把整段聊天原样塞回模型当然省事,跑到十几轮后就开始混乱。至少应该单独保存这些内容:

  • 用户目标和硬性约束,例如时间范围、预算、输出格式。
  • 已经确认的事实,以及它们的来源。
  • 已调用的工具、参数、结果和错误。
  • 待完成的子任务和当前步骤预算。

状态必须有上限。最大步数、token、工具调用次数和总耗时都交给运行时控制。预算用完就停,并把已完成的部分和缺口交代清楚。让模型自己决定“再试最后一次”,很容易变成第五个最后一次。

停下来也是一次正确动作

搜索、查询、计算这些只读动作,可以让它自己跑。创建草稿要保留撤销办法。退款、删除数据、对外发信之类的动作,到了那一步就停下来等人确认。

这会牺牲一点“全自动”的观感,我觉得值得。Agent 的权限应该跟动作风险走,跟模型说话有多像人没关系。

从一个具体任务开始

第一版可以只做一件事:“根据内部文档回答售后政策,资料不够时列出缺少的信息。”给它搜索和生成待补清单两个工具就够了。答案要有出处,找不到政策就明说,不能拿常识补。

跑十几次之后再看轨迹:它搜了什么,为什么又搜一次,引用能不能回到原文,什么时候停。如果这几个问题还答不上来,先别急着加第三个工具。