← All posts 此文章100% AI 生成,请读者放心阅读

六十行跑起来一个 agent,难在跑起来之后

周五晚上,他想给自己写个小东西:一个能自己查天气、读本地文件、必要时算两笔账的 AI 助手。听起来一个晚上能搞定。

他打开第一篇教程。第一段就让他装 LangChain。装完 LangChain,教程让他配一个向量数据库,说是给 agent 做「记忆」。配完向量库,下一节叫「Agent Executor」,里面又冒出 Tools、Toolkits、Memory、Planner、Callback Handler 五六个名词,每个都链到另一篇文档。他还没写一行属于自己的逻辑,浏览器已经开了十七个标签页。

到十一点,他关掉电脑,那个 AI 助手一个字都没跑起来。

这是绝大多数人第一次碰 agent 的经历。问题不在他不够聪明,而在他一上来就被推到了错误的起点——他以为「做一个 agent」等于「学会一个 agent 框架」。实际上,他那天晚上想要的东西,核心不到六十行代码,不需要向量库,不需要 planner,一个晚上跑起来绰绰有余。

「agent」这个词,哪些是必须的

在动手之前,把它的来历理一遍,你才知道哪些是必须的、哪些是后来被叠上去的。

2022 年 10 月,Yao 等人发了一篇叫 ReAct 的论文。在那之前,「让模型推理」(chain-of-thought)和「让模型行动」(调用外部工具)是两条分开研究的线。ReAct 把它们交错起来:模型先写一句想法(Thought),再决定一个动作(Action),执行后拿到结果(Observation),然后基于这个结果再想下一步。thought → action → observation,循环往复。今天你看到的每一个 agent,内核都是这个循环,没有例外。

2023 年 3 月,AutoGPT 出现,把这个循环推到了极端:你给一个目标,它自己拆任务、自己调工具、自己决定下一步,全程不用你管。GitHub 上几天就几万星。然后大家发现它不太能用——动不动陷进死循环,为了「搞清楚自己的目标」反复去 google,跑一会儿就开始幻觉,还因为每一步都在烧 GPT-4 的 API 而费用高得吓人。Wikipedia 给它的词条里专门有一句:以陷入循环、产生幻觉、成本高昂著称。AutoGPT 教会大家的,其实是一条反面经验:把控制权一股脑全交给模型,结果是不可控。

2024 年 12 月,Anthropic 发了一篇《Building effective agents》,等于给这场混乱定了调。他们跟几十个团队合作下来的结论是:最成功的实现都没在用复杂框架或专门的库,而是用简单、可组合的模式。这句话把「agent = 一套庞大框架」这个隐含假设直接否掉了。到 2025 年,Anthropic 的 Hannah Moran 在一次开发者活动上抛出一句被 Simon Willison 记下来的定义:agents are models using tools in a loop——agent 就是在循环里用工具的模型。一句话,没有向量库,没有 planner,没有框架。

一个让人意外的事实

你日常在用的那些最强的 agent,内核长得几乎一模一样。Braintrust 在 2025 年 8 月的一篇文章里把这个内核直接贴了出来。Claude Code、OpenAI 的 Agents SDK,说到底都是这么一段:

while (!done) {
  const response = await callLLM();
  messages.push(response);
  if (response.toolCalls) {
    messages.push(
      ...(await Promise.all(response.toolCalls.map((tc) => tool(tc.args)))),
    );
  } else {
    messages.push(getUserMessage());
  }
}

就这六行。一个循环,调一次模型,模型要是说「我要调工具」就去执行、把结果塞回去,要是没说就把话筒还给用户。Steve Kinney 把范围列得更全:Claude Code、Codex、Cursor、Vercel AI SDK、LangGraph、smolagents,他挨个看下来,发现它们收敛到的不是相似的架构,是同一个架构。

把这个事实和框架的体量摆在一起,张力就出来了。一个能编辑代码、能跑命令、能自己从报错里爬出来的 coding agent,Thorsten Ball 在 ampcode 上演示从零写,不到四百行,而且大部分是样板代码,他给文章起的副标题是「皇帝没穿衣服」。Hacker News 上有人说得更直接:你亲手拼一个这样的循环大约要三十分钟。而你为了「正确地」开始而去学的那个框架,光抽象层就是上千上万行。

这不是说框架没用,是说它把「构建 agent」这件事的门槛人为抬高了——让一个三十分钟、六十行的东西,看起来像一个需要先啃完一整套文档才能动手的工程。那天晚上挡在他和「跑起来」之间的,不是 agent 难,是框架的学习曲线。绕过它的办法很简单:先不学框架,直接写那六十行。

从零到跑起来:那六十行到底是什么

先把心智模型立住,后面写代码就不会迷路。一个 agent 由三样东西构成:一个会说话的模型,一个不停转的循环,几个模型能调的工具。模型负责想,工具负责做,循环负责把想和做接起来,直到事情办完。

打个比方,模型是一个隔着墙的专家,他很会出主意但手脚被绑着;工具是墙这边几个能干活的助手;循环是你们之间传纸条的过程。专家写下「帮我查一下这个目录有多少文件」,你照做,把数字写回纸条递进去,他看到数字再决定下一步。agent 跑起来,就是这叠纸条来回传的过程。

环境你只需要两样:一个 Python,一个能调模型的 key。

pip install openai
export OPENAI_API_KEY="你的 key"

messages 就是那叠纸条本身——一个列表,记着到目前为止谁说了什么。先不加工具,跑个最素的版本:

from openai import OpenAI

client = OpenAI()
messages = [{"role": "user", "content": "用一句话介绍你自己"}]

response = client.chat.completions.create(
    model="gpt-4o",
    messages=messages,
)
print(response.choices[0].message.content)

这还只是个聊天机器人,因为它只能「想」,不能「做」。要让它变成 agent,得给它工具,并且把它放进循环。

工具就是一个普通的 Python 函数,外加一份给模型看的说明书。说明书用 JSON schema 写,告诉模型这个工具叫什么、干什么、要什么参数。Anthropic 在《Writing effective tools for agents》里反复强调一件事:工具描述写得好不好,直接决定 agent 调得准不准。所以 description 别偷懒。

import json, os

def list_files(directory):
    return json.dumps(os.listdir(directory))

tools = [{
    "type": "function",
    "function": {
        "name": "list_files",
        "description": "列出某个目录下的所有文件和子目录名称",
        "parameters": {
            "type": "object",
            "properties": {
                "directory": {"type": "string", "description": "要查看的目录路径"}
            },
            "required": ["directory"],
        },
    },
}]

现在是关键的一步:调模型,如果模型说要调工具,就执行对应的函数,把结果以 role=tool 的身份塞回 messages,然后再调一次模型。模型拿到工具结果,要么接着调下一个,要么直接给你最终答案。

messages = [{"role": "user", "content": "当前目录下有哪些文件?挑出其中的 Python 文件。"}]

for step in range(10):  # 停机条件:最多转 10 圈
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
    )
    msg = response.choices[0].message
    messages.append(msg)

    if not msg.tool_calls:
        print(msg.content)   # 没有工具要调,说明它给出了最终回答
        break

    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = list_files(**args)        # 真正去执行
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": result,
        })

跑起来你会看到这样一条轨迹:模型先决定调 list_files,参数是当前目录;程序执行,把文件名列表塞回去;模型看到列表,自己挑出 .py 结尾的,给你一句话答案。thought → action → observation,那个 2022 年的循环,此刻就在你终端里转。

有两个细节别省。第一是那行 for step in range(10),它不是凑数的。模型有时会卡住,反复调同一个工具或者绕圈子,一个写死的最大步数是最便宜也最有效的保险(IBM 讲 ReAct agent、Haystack 设 max_agent_steps,做的都是同一件事:给循环一个尽头)。第二是异常:真实环境里工具会失败,别让一次失败把整个 agent 打挂,把工具执行包进 try,把错误信息当成一条普通的 observation 塞回去:

try:
    result = list_files(**args)
except Exception as e:
    result = f"工具执行失败:{e}"

模型读得懂错误信息,下一圈它会自己改参数、换路径,相当于让 agent 具备了从自己的错误里爬出来的能力。到这里,你手上已经有一个会查目录、会挑文件、出错了还能自我修正的 agent 了。它不到一百行,没用任何框架。

demo 之外:墙会一堵接一堵出现

现在把这个小东西从你的终端挪到真实场景里。Steve Kinney 那句话的后半段才是重点:六行的版本很简单,难的是 production-hardened 的版本——上下文压缩、死循环检测、成本预算、优雅停机。这些恰恰是你的六十行里没有的东西。

第一堵墙是上下文。你的循环每转一圈,messages 就长一截,工具返回的内容也全堆在里面。一个真实任务跑上几十步,上下文很快撑爆模型窗口,或者就算没爆,里面塞满无关内容,信号被噪声淹没,模型开始忘事、开始幻觉出「我之前决定过」的步骤。有人专门写过:加大上下文窗口大多只是推迟失败,而不是解决它。

第二堵墙是钱。上下文每长一截,每一步的 API 费用都跟着涨。生产里一个 agent 单次跑动烧掉二三十美元不稀奇。你只剩三个选择:发最小上下文、结果变差;发全部上下文、成本破产;或者老老实实建一套上下文管理系统,决定每一步该带什么进去。能用的只有第三个,而第三个不在你的六十行里。

第三堵墙是循环本身。AutoGPT 当年最出名的故障,就是陷进「do nothing」的死循环,或者为了搞清楚自己的目标反复 google。Simon Willison 转述过一个更黑色幽默的例子:一个 agent 意识到自己卡在了无限循环里,干脆用 pkill 把自己进程杀了。你那行 max steps 能挡住最蠢的一种,但挡不住它在十步之内来回兜圈子。

把这些墙加起来,就是行业里那个不太好看的数字。Fiddler 整理的数据显示,生产环境里 agent 的任务失败率在 70% 到 95% 之间;WebArena 这个基准上,最好的 GPT-4 agent 端到端成功率只有 14.41%,而人类是 78.24%;CMU 发现 agent 在常见办公任务上大约 70% 会失败。

这些数字不是要劝你别写。恰恰相反,它们解释了为什么 MVP 值得写:那六十行最大的价值,不是替你干活,是用最快的速度、最低的成本,把这几堵墙一次性暴露在你面前。你亲手撞过上下文爆炸、撞过工具超时、撞过死循环,才知道框架里那些 Memory、Executor、Callback 到底在解决什么问题。HumanLayer 的 Dexter Horthy 把这套生产经验整理成了 12-factor agents:很多团队开个新项目、上 agent 框架,用开箱工具怎么都过不了 70%-80% 的可靠性线;真正做成的,反而是把 agent 里那些小而专的概念,一点点融进自己已有的产品。

你接下来该做什么

先别管框架。今晚就把上面那六十行敲进去,接上你自己的一个真实任务——读你电脑上某个目录、查个接口、算笔账,随便什么,只要是你真想要的。让它在终端里跑起来,看着 thought → action → observation 那叠纸条来回传。这一步给你的,是任何文档都给不了的东西:你终于知道 agent 到底是什么了。

跑通之后,撞墙之前,先用四个问题判断你到底需不需要再加东西。这套问法 Anthropic 和 OpenAI 的实践指南里都讲过。第一,这个任务的路径是固定的,还是开放的?路径固定就别上 agent,写个普通的流程脚本(workflow)更稳、更便宜。第二,要几个工具?一两个工具的事,手搭版完全够。第三,要不要多步推理、要不要根据中间结果改主意?要,才轮到 agent 这个循环真正发挥作用。第四,可靠性要求多高?给自己用,七成成功率能忍;交给客户,那是另一个量级的工程,前面那几堵墙一堵都躲不过。

什么时候该上框架?等你撞墙之后,按墙的形状去挑。上下文撑爆了,再去看上下文管理;要编排好几个 agent 协作,再去看编排层;要可观测、要追踪每一步,再去接相应的工具。12-factor agents 的经验是,成功的团队很少从零堆一整套框架,而是把需要的小模块挑出来,嵌进自己已经跑通的那六十行里。框架是用来填墙的,不是用来开工的。

那个周五晚上被十七个标签页劝退的人,如果换个顺序——先写六十行,再撞墙,再按需补——他那个会查天气、读文件、算账的小助手,本来真的一个晚上就能跑起来。你今晚的终端里,要不要也跑一个?

Comments

Select any text to comment on a specific part. Existing inline comments appear as small numbered bubbles. Powered by GitHub Discussions.