从最小循环讲清 Agent 的骨架,顺便打掉几个流行误解

这两年"Agent"变成了 AI 圈最被滥用的词。有人把 ChatGPT 串两轮 Prompt 叫 Agent,有人把 RPA 脚本套个 LLM 叫 Agent,有人把一个会调函数的模型也叫 Agent。概念一糊,写的代码就跟着糊——你以为在做 Agent,其实只是把 Function Calling 包了一层;你以为多 Agent 能干大事,其实只是让系统更慢、更贵、更难调。

这个系列从一个朴素的问题开始:Agent 到底是什么,它和已经有的东西有什么区别

一个干净的定义

Anthropic 在 2024 年底的 "Building effective agents" 里给了一个我很喜欢的定义:

An agent is an LLM dynamically directing its own processes and tool usage.

翻译过来:Agent 是一个自己决定下一步做什么、并能调用工具的 LLM

关键词两个——自己决定调用工具。少一个都不成立。只能调工具但由你决定调用顺序,那是 Workflow;能自己决定但没有工具(只是在脑子里推理),那是 Chain of Thought。两件事装进一个循环,才有了 Agent 的最小骨架:

while not done:
    response = llm.chat(messages, tools=tools)
    if response.tool_calls:
        results = [run_tool(tc) for tc in response.tool_calls]
        messages.append(response)
        messages.extend(results)
    else:
        done = True

这段代码不到 10 行,但它已经是一个真正的 Agent。剩下所有的复杂性——记忆、规划、反思、多 Agent 协作——都是在这个循环上加东西,而不是另起一个新范式。理解了这一点,后续所有"高级 Agent 架构图"看起来都不会那么吓人。

Workflow 和 Agent 的分界

这是最容易糊的地方,也最值得想清楚。

Workflow 是开发者在代码里写好流程,LLM 只是流程中的一个可调用节点:

summary = llm.summarize(doc)
tags = llm.tag(summary)
result = db.save(summary, tags)

Agent 是开发者只给目标和工具,流程由 LLM 自己生成:

agent.run("帮我整理这份文档,打好标签存到知识库")
# LLM 内部自己决定:先调 summarize,再 tag,再存 db

区别不是"用了多少个 LLM",而是谁在掌控控制流

这个分界有巨大的工程意义。Workflow 是可预测的——每次运行的路径都一样,好调试、好测试、好监控。Agent 是不可预测的——同一个输入,两次可能走完全不同的路径,某一步跑偏整个任务就偏了。

所以选 Workflow 还是 Agent,本质上是在问一个问题:这个任务的路径能不能事先枚举。能枚举就用 Workflow;不能枚举,或者分支多到枚举起来代码会爆炸,才用 Agent。

很多团队的第一个错误就是:不管任务是什么,上来就要做"多 Agent 系统"。结果是一个本来 20 行代码就能搞定的 Workflow,被做成了一个慢 10 倍、贵 10 倍、还经常跑偏的 Agent。

自主性是一条光谱,不是开关

Workflow 和 Agent 不是非黑即白。Anthropic 把中间划成五档,从左到右自主性递增:

  • Prompt chaining:LLM A 的输出喂给 LLM B,顺序固定
  • Routing:先让 LLM 判断任务类型,再路由到对应分支
  • Parallelization:把任务拆成可并行的子任务,LLM 并发跑,结果聚合
  • Orchestrator-Worker:一个 LLM 做协调者,动态分派子任务给 Worker
  • Evaluator-Optimizer:一个 LLM 出结果,另一个 LLM 评审,循环到满意

再加上"自由调用工具 + 自主决定何时结束",就到了完整意义上的 Agent。

这个光谱值得记下来,因为大多数真实任务只需要前三档。你以为需要 Agent,其实 Routing + Parallelization 就够了。Anthropic 内部的工程经验也是——先从能解决问题的最简单方案做起,只有在确实需要动态决策时才上 Agent。

Agent 的三要素

把 Agent 拆开看,永远是三件东西:

Model——大脑。决定下一步干什么、解析工具返回的结果、判断任务是否完成。 Tools——手脚。能调用的外部能力:搜索、文件读写、代码执行、API、数据库。 Loop——心跳。一个不断"思考 → 行动 → 观察"的循环,直到任务完成或触发停止条件。

这三件事都离不开,也都是这个系列后续每一篇要深挖的方向。Model 侧讨论 Prompt 设计、推理模型、上下文管理;Tools 侧讨论粒度、命名、错误反馈、工具数量膨胀;Loop 侧讨论最大步数、停止条件、反思与重规划。

为什么 Agent 到 2024 才真正能用

有个有意思的问题:ReAct 这个 Agent 模式 2022 年的论文就提出来了,但大规模能用的 Agent 产品要到 2024 年才看到。中间缺了什么?

缺的不是某一个东西,是一堆能力同时到位:

工具调用能力的成熟。GPT-3.5 时代的 Function Calling 不稳定,经常调错参数、忘记调、重复调。直到 GPT-4 Turbo、Claude 3.5 Sonnet 这一代,工具调用才从"能用"变成"能靠"。

上下文长度的爆炸。Agent 在循环里每一步都往 messages 里堆东西,几步就几千 token。上下文只有 4K 的年代,Agent 跑三轮就爆。到了 100K+、200K 的时代,Agent 才有了做长任务的空间。

推理模型的出现。o 系列、R 系列、Claude 的 extended thinking,让模型在动作前真的能规划,而不是凭直觉瞎跳。多步任务的成功率因此跃了一个数量级。

成本的下降。Agent 很费钱——一次任务可能调 LLM 二十次。当每百万 token 从 60 美元降到 3 美元、0.3 美元,Agent 才从"实验室玩具"变成"敢放上线"。

协议的统一。OpenAI 的 tools、Anthropic 的 tool_use、Hermes 的 XML tool_call,三家格式不同,但"模型能以结构化方式声明要调什么工具"这件事成了行业共识,工具生态才有了基础。

这五件事少一件,Agent 都还停在"demo 能跑、生产没法用"的阶段。

Function Calling 不等于 Agent

这是最常见的混淆。Function Calling 是**模型能以结构化方式说"我想调用这个函数"**的能力。它是 Agent 的一个必要零件,但不是 Agent 本身。

一个只做单次 Function Calling 的系统:

用户:北京天气怎么样?
模型:[tool_call: get_weather(city="北京")]
你:执行函数,拿到 "15 度晴"
模型:北京现在 15 度晴朗。

没有循环,模型调完一次工具就把结果抛给用户了。

一个 Agent 长这样:

用户:整理我上周的日历,把所有会议标签化并存到 Notion
模型:[tool_call: list_calendar(start=..., end=...)]
你:执行,返回 20 个事件
模型:[tool_call: classify_event(event=1)] ... [tool_call: classify_event(event=20)]
你:并行执行,返回 20 个分类
模型:[tool_call: notion_create(...)]
你:执行,创建成功
模型:已经整理完 20 个会议并存入 Notion。

多轮工具调用 + 自己决定调哪个 + 自己决定何时结束。一个简单的识别法:如果你的代码里控制了"下一步调什么",那就是 Workflow 或 Function Calling,不是 Agent。

一个能跑的最小 Agent

把前面的所有概念落到代码上,一个有工具、有循环、有终止条件的 Agent,不依赖任何框架:

import json
from openai import OpenAI

client = OpenAI()

def get_weather(city: str) -> str:
    return f"{city} 现在 15 度,晴"

def calculate(expression: str) -> str:
    return str(eval(expression))

TOOLS = {"get_weather": get_weather, "calculate": calculate}

TOOL_SCHEMAS = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的天气",
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "计算一个数学表达式",
            "parameters": {
                "type": "object",
                "properties": {"expression": {"type": "string"}},
                "required": ["expression"],
            },
        },
    },
]


def run_agent(user_input: str, max_steps: int = 10):
    messages = [
        {"role": "system", "content": "你是一个能用工具的助手。"},
        {"role": "user", "content": user_input},
    ]
    for _ in range(max_steps):
        resp = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages,
            tools=TOOL_SCHEMAS,
        )
        msg = resp.choices[0].message
        messages.append(msg)

        if not msg.tool_calls:
            return msg.content

        for tc in msg.tool_calls:
            fn = TOOLS[tc.function.name]
            args = json.loads(tc.function.arguments)
            result = fn(**args)
            messages.append({
                "role": "tool",
                "tool_call_id": tc.id,
                "content": result,
            })

    return "达到最大步数限制,任务未完成。"


print(run_agent("北京今天天气怎么样,顺便算一下 (15+20)*3 等于多少"))

不到 60 行,做到了什么:三要素齐全(gpt-4o-mini 是 Model、两个函数是 Tools、for 是 Loop);自主决定(模型看到用户问了两件事,会自己先调 get_weather 再调 calculate,或并行调用);终止条件(模型不再发起 tool_calls 或达到 max_steps 退出);状态累积(messages 列表在循环里追加,保留完整对话和工具历史)。

这就是 Agent 的内核。后面整个系列的复杂机制——ReAct 的思考显式化、Reflection 的自我批评、Plan-Execute 的分层规划、Hermes 协议在开源模型上的落地、Multi-Agent 的分工协作——都是在这 60 行之上加东西,本质上没变。记住这个骨架,后面不会迷路。

不要上来就做"多 Agent"

最后想在第一篇就打掉的流行误解:多 Agent 不是更强,反而经常更弱

你会看到很多项目一上来就摆七八个 Agent,PM Agent、Coder Agent、Tester Agent、Reviewer Agent 云云。看着像"团队分工",实际上踩两个大坑。

上下文碎片化。Agent A 做了一半,把结果交给 Agent B,中间必然需要压缩上下文。压缩过程必然丢信息,B 经常在 A 已经做过的事情上兜圈子。

错误沿链路放大。A 略微偏了,B 基于 A 的输出继续偏,到 D 那里已经完全跑偏。单 Agent 的错误会被自己在下一步看到并纠正,多 Agent 看不到彼此的思考。

Cognition 的 Devin 团队 2024 年底发了一篇 "Don't Build Multi-Agents",观点非常直接:在你没把单 Agent 做到极限之前,不要碰多 Agent。Anthropic 的立场也类似——先试 Workflow,不行试单 Agent,真不行再考虑 Orchestrator-Worker 这种受控的多 Agent 结构。这个系列会单独有一篇讲多 Agent,但重点不是"怎么做得多"而是"怎么做得对",以及"什么时候根本不该做"。

这个系列会带你走到哪里

从这一篇开始,我会带你把 Agent 这件事从最基础的循环,一步步推到生产可用的程度。不会停在 demo,也不会陷进某个框架的黑盒。每一篇解决一类问题:

怎么让 Agent 思考得更清楚——ReAct、Plan-Execute、Reflection、Tree of Thoughts。怎么设计好的工具——粒度、命名、错误反馈、工具爆炸。怎么管理记忆和上下文,这是 Agent 最难的地方。怎么让本地开源模型也能做 Agent——Hermes 协议、Qwen-Agent、全本地方案。怎么做真正有用的复杂形态——Code Agent、Browser Agent、Multi-Agent。最后怎么把它变成生产系统——评测、监控、成本、安全。

每一篇都会给你可以直接跑的代码,不会用"留给读者练习"这种偷懒写法。

下一篇从 ReAct 开始——手写一个把"思考过程"显式化的 Agent,看看为什么让模型先说出它在想什么,会让整个系统的表现跃一个台阶。

相关阅读

版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:01. Agent 是什么:从一次性 Function Call 到自主循环

本文链接:https://www.sshipanoo.com/blog/ai/ai-agent/01-Agent是什么/

本文最后一次更新为 天前,文章中的某些内容可能已过时!