一个有嘴没手的学霸,和一个会干活的项目经理——我终于搞懂 Agent 是啥了

一个有嘴没手的学霸,和一个会干活的项目经理------我终于搞懂 Agent 是啥了

最近系统读了两篇讲得极清楚的前置文章(下面统称「原文」),想把它们串成一篇完整的笔记发出来。两篇都是「零基础」向,不堆术语, 读完之后,我心里那句「Agent 不就是个大模型外面套个壳吗」的疑问,算是彻底解开了。

这篇文章分两大部分:先搞清楚 Agent 的大脑------大模型 到底是什么、又缺什么;再看 Agent 是怎么给它补上短板、真正动手干活的。文末还有一些我自己跑通代码之后的感想。


第一部分:大模型到底是个啥,它又缺了什么

大模型是个什么东西

它其实一直在玩「接龙」

先问你一个问题:你觉得大模型回答问题的时候,脑子里在干什么?

很多人第一反应是,它肯定跟人一样,先理解问题,再去翻知识,最后组织语言。其实没这么玄乎,它干的事说出来你可能不太信------就是在「猜下一个字」。

你给它一句「床前明月」,它根据以前读过的海量文字判断,后面最有可能跟着的是「光」。接上「光」之后,它再看「床前明月光」后面最可能是什么,就这样一个字一个字往下接,接到它觉得这句话该收尾了为止。

text 复制代码
床前明月 → 光 → 疑 → 地上霜 → ...

看到这估计有同学就问了:就这?光靠接龙,怎么能写代码、做翻译、回答各种专业问题?

关键在于它读过的东西实在太多了。互联网上的网页、书籍、论文、代码,它训练的时候几乎都「读」了一遍,从里面学会了人类说话的各种规律。所以同样是接龙,它接出来的不光通顺,还往往说得在理。

你可以把它想象成一个把整座图书馆都读完了的学霸,你起个头,它就能顺着接下去,还接得有模有样。这个学霸有个正式的名字,叫「大语言模型」,英文是 Large Language Model,简称「LLM」。我们平时用的 DeepSeek、ChatGPT、Claude、豆包,底层都是它。

在代码里,它就是一个接口

网页上聊天大家都会,那在代码里要怎么用它?

浏览器把你打的那句话打包好,通过网络发给一台远程服务器,大模型就跑在那台服务器上。它接完龙,把回答发回来,网页再把回答显示在你眼前。所以对你写的代码来说,大模型就是一个网络接口------你往这个接口发一段文字,它回你一段文字,跟你调一个查天气的接口,本质上是同一回事。

text 复制代码
你的代码 --发一段文字--> 大模型(远程服务器)
大模型   --回一段文字--> 你的代码

发过去的内容得按格式写,业内有一套大家都在用的格式,叫「Chat Completions」。DeepSeek、通义千问、智谱、MiniMax 这些国内模型都支持这套格式,学会它,市面上绝大部分模型你都能调。

对了,你以后在项目里会碰到 LangChain、LangGraph 这些框架,名字听着挺唬人。讲真,它们都是在这个接口外面包了一层又一层,帮你少写一些重复代码。把包装拆掉,最里面永远是这一发一收。

动手之前,先备好三样东西

第一样是 Python 3.10+。第二样是两个包:pip install openai python-dotenv。openai 是发请求用的官方工具包,别看名字叫 OpenAI,调 DeepSeek、MiniMax 这些兼容那套格式的模型也用它。python-dotenv 负责从配置文件里读密钥。

第三样是一个模型平台的密钥。推荐用 DeepSeek,注册后在「API keys」里新建一个,你会拿到一串 sk- 开头的字符。这串东西就相当于你的账号密码,谁拿到了都能花你的钱,所以别发到群里,也别提交进 git 仓库。充几块钱,足够把例子跑很多遍。

在根目录建一个 .env 文件,写上三行:模型服务的地址、你的密钥、要用哪个模型。换别家模型,只改这三行,代码一个字都不用动。

跟它说第一句话

发请求的核心就一行:client.chat.completions.create,里面放 model(用哪个模型)和 messages(你要说的话)。注意 messages 是个列表,列表里每一条是一个字典,role 表示这句话是谁说的,user 就是用户,content 是话的内容。

看到这你可能会嘀咕:我就说一句话,为什么要套一个列表?先别急,这个问题下一节自己就会冒出来。

回来的结果里,resp.choices[0].message.content 就是模型的回答。最后一行打印出来的 usage 是这一次的账单:模型收费不按字数,按「token」算。token 是模型处理文字的最小单位,粗略理解成一两个汉字算一个。prompt_tokens 是你发过去的,completion_tokens 是它回给你的,平台按这两个数收钱。

你可能会奇怪,我就发了一句八个字的话,怎么记了 182 个?这多出来的部分是模型平台自己加进去的一些固定内容,各家不一样,不用较真。账单这件事先记在心里,下一节它会变得很有意思。

跑到这一步,你已经在代码里调通大模型了。回头看看,所谓「接入大模型」,真就是发一个请求、收一段回答,没有任何魔法。


大模型的三个短板

把「接龙学霸」的画像立起来之后,原文很诚实地给它挑了三个毛病。这三个毛病,恰恰就是 Agent 要补的地方。

text 复制代码
大模型接龙学霸
├── 短板一:记不住,无状态
├── 短板二:不知道你家的事,幻觉
└── 短板三:只会一问一答,被动

短板一:它记不住你(无状态)

先做个小实验:先发一句「我叫喵喵」,再单独发一句「我叫什么?」,两次请求各发各的。结果上一秒刚跟你打完招呼,下一秒它就不认识你了。

问题出在服务器那边。模型服务不替你保存任何聊天记录,你的请求发过去,它接完龙把回答发回来,这件事就算结束了。这种特性叫**「无状态」**。你可以想象打客服热线,每次接起电话的都是一个刚上班的新客服,你上次跟别人说过什么,他一概不知道,除非你自己从头讲一遍。

那网页上的 ChatGPT 为什么记得住你?因为网页替你干了「从头讲一遍」这件事------你每说一句,网页都会把之前的聊天记录连同这句话一起发给模型。这就是为什么 messages 是个列表:它就是用来装聊天记录的。

解决办法也就出来了:用一个 history 列表把每一句都存下来,每次把整个列表发过去。用户说的话 role 标 user,模型回的话 role 标 assistant,连模型自己说过的话,也要你替它存回去。

但记性是补上了,账单也跟着涨了。 第一轮请求记了 179 个 token,第二轮记了 254 个------因为第二轮把第一轮的问和答也一起发过去了。聊得越久,列表越长,每一轮要发的东西就越多。还有一个更硬的限制:模型一次能读的内容有上限,叫上下文窗口,堆超过上限请求会直接报错。所以真实的客服系统不能无脑把所有记录都发过去,得挑着发、压缩着发。

短板二:它不知道你家的事(幻觉)

回头看第一个例子,「到手不喜欢能退吗」,模型答的是「大多数支持 7 天无理由退货」。这话挑不出错,可你要是喵购商城的老板,这回答基本没用------你家店到底几天能退、运费谁出,它一概不知道。原理很简单:模型的知识全来自训练时读过的资料,训练一结束,它脑子里的东西就定住了。

更麻烦的是:它会一本正经地编。 用「我的订单 SO20260901 发货了吗?」这句话,不给它任何数据,连着问两次。第二次它很老实,说查不了。第一次却自己演了一段「(查询订单系统...)」,编出了物流公司、单号、发货时间、转运中心、送达日期,没一样是真的。

text 复制代码
问订单发货了吗
        ↓
模型没数据,但目标是把话接通顺
        ↓
编造物流、单号、时间 = 幻觉

这种「一本正经胡说八道」,业内叫幻觉。而且同一句话问两次答案完全不一样------对聊天无所谓,放到客服身上就是事故。

那把数据塞进问题里行不行?一两条数据完全可以这么干。可一家店几十万个订单,每个都在变,你不可能提前全塞进去,一次请求也装不下。所以更好的办法是反过来:别让模型「知道」,让它在需要的时候「开口要」------这就是下一篇要讲的「工具调用」。

短板三:它只会一问一答(被动)

换一个问法:「我那双鞋到哪了?几号能到?」

你要是客服,会先去订单系统里找到这一单,看到快递单号,再拿着单号去物流系统里查进度,最后才能回答。这是两步,而且第二步要用到第一步查出来的东西。可大模型做不到------它不会回完之后自己琢磨「我还差个物流信息,再去查一下」,因为它压根没有「接着干」这个能力,你不发下一次请求,它就一直停在那里。说白了,大模型是被动的。

三个短板里,第一个「记不住」我们已经亲手补上了(那个 history 列表)。剩下两个怎么补?下一篇就来干这件事。


第二部分:Agent 是怎么让大模型动手干活的

上一篇结尾,大模型给人一个印象:一个有嘴没手的学霸。它说得头头是道,可你家店的订单它查不到,硬问还会编,碰到要好几步才能办完的事,它回一句话就停在那里了。

怎么让它真正干点活?这一篇解决两件事:第一,给它装上一双手(工具调用);第二,给它套上一个循环(Agent 循环)。 两样凑在一起,就是 Agent。

text 复制代码
大模型(负责判断,接龙学霸)
        ↓
工具(碰到真实世界,查订单查物流)
        ↓
循环(自己想下一步,ReAct)
        ↓
Agent(会干活的智能体)

给它装上一双手:工具调用

换个思路,让它开口要

一家公司新来了一个前台,第一天上班,库存多少、订单到哪了,他一概不知道。那他怎么接待客户?工位墙上贴着一张内线电话表:查订单打 8001,查物流打 8002。客户问「我的订单发货没」,他听懂了意思,拨 8001,报上订单号,那边查完告诉他,他再用自己的话转述给客户。

前台自己没有任何数据,但他知道找谁要、要什么。大模型也可以这么用。

你提前给模型一份工具清单 ,告诉它手边有哪些工具、每个工具能干什么、要填什么参数。碰到需要数据的问题,它就不硬编了,改成回你一句「我要调用某某工具,参数是某某」。你的代码看到这句话,去真的查一下,把结果递给它,它再根据真实数据回答用户。这套机制在业内叫 Function Calling,中文一般叫「工具调用」。

工具清单长什么样? 它是一份写给模型看的说明书,核心就三样东西:name 是工具名字;parameters 说这个工具要填哪些参数、每个是什么类型、哪些必须填;最关键的是 description------模型判断「该不该用这个工具」「参数怎么填」,全靠读这几句描述。你写得含糊,它就调不准。所以描述要当成给新同事写的交接文档来写。

把工具清单带上,再问一次「我的订单 SO20260901 发货了吗?」。这次回来的不再是「编出来的物流」,而是一个「申请」------finish_reason 平时正常说完是 stop,这回变成了 tool_calls,意思是「我先不说了,我要用工具」,里面写得明明白白,要调 query_order,参数是 {"order_id":"SO20260901"}。

这一篇最重要的一句话

看到这估计有同学就问了:那它是不是已经去数据库里查过了?

其实它什么都没有执行。 它只是「说」了一句,我想调 query_order,订单号填 SO20260901。它碰不到你的数据库,也跑不了你的函数,真正去查数据的,是你接下来要写的那几行 Python。

这句话一定要记牢。以后你看到再复杂的 Agent,工具再多、功能再强,底层都是这个分工:模型负责判断该用哪个工具、参数怎么填,你的程序负责真正去执行。 这个分工还顺带划清了安全边界------你没给它删数据的工具,它说破天也删不了。

完整的工具调用流程长这样:

text 复制代码
用户:我的订单 SO20260901 发货了吗
              ↓
         (大模型)
              │
              │ tool_calls: query_order(order_id)
              ↓
         你的代码
              │
              │ 执行查询
              ↓
        数据库系统
              │
              │ 真实订单数据
              ↓
         你的代码
              │
              │ role=tool 放回 messages
              ↓
         (大模型)
              │
              │ 基于真实数据回答
              ↓
             用户

关键:模型只是"说",真正执行的是你的代码

模型提了申请,接下来轮到你的代码干活:先把那条「申请」原样放进聊天记录(漏了这一步,下一次请求多半会报错),接着挨个处理申请,把参数用 json.loads 解成字典,交给真正的函数去查,查出来的结果用一个新的角色 tool 放回聊天记录,tool_call_id 要跟申请里的 id 对上。结果放好,带着整个 messages 再请求一次,这回它才开口说人话。数一下,一次工具调用,你给模型发了两次请求:第一次它提申请,第二次它看结果说话。

不过跑通之后还有个小翻车:模型回答里写了「SF1234567890(顺丰)」,可假数据里只有快递单号,一个字没提快递公司。「顺丰」是它看到 SF 开头自己猜的。这就是上一篇讲的幻觉------工具调用并没有把幻觉治好,它只保证拿到的数据是真的,管不住模型在转述时自作主张往里加东西。 真实系统会用系统提示词给它立规矩,比如「数据里没有的一个字都不许说」。

让它自己往下走:Agent 循环

缺的其实只是一个循环

工具调用解决了「查不到」的问题。那上一篇的第三个短板(只会一问一答)呢?

换回那个要两步才能答的问题:「我的订单 SO20260901 那双鞋到哪了?几号能到?」这回多准备一个查物流的工具 query_logistics。问题来了,要回答用户,得先用订单号查出快递单号,再用快递单号查物流。刚才那段代码只处理一轮申请,模型拿到订单结果之后,就算它还想查物流,也没人帮它执行了。

缺的其实只是一个循环:只要模型还在申请工具,就继续帮它执行、继续把结果递回去、继续问它下一步,一直到它不再申请工具、直接开口回答为止。

外面一个 for,每走一轮就请求一次模型。模型的回复先存进聊天记录。然后看它有没有申请工具,没有申请,说明它觉得信息够了,直接把回答返回,循环结束;有申请的话,就挨个执行------FUNCS 是一个字典,把工具名对应到真正的函数,模型报哪个名字,就从字典里取出哪个函数来调。执行完照样把结果放回聊天记录,然后回到循环开头,带着新结果再问模型一次。

跑起来看重点:用户根本没提快递单号。第 1 步查完订单,结果里有一个 tracking_no,模型自己从里面把 SF1234567890 拿出来,自己决定下一步去调 query_logistics。第 2 步查完,它判断信息够了,不再申请工具,直接回答。先查什么、后查什么、查几次、什么时候停,这些你一行代码都没写,全是它自己决定的。

text 复制代码
用户问题
   ↓
Agent 循环(最多 MAX_STEPS 步)
   ↓
请求大模型
   ↓
还要用工具?
  ├─ 是 → 代码执行工具(try 兜底异常)→ 回到循环
  └─ 否 → 直接回答用户,循环结束

(顺带又是一个幻觉小彩蛋:最后那句「明天就能送到您手里啦」,物流数据里只有「9 月 18 日」,模型并不知道今天是几号,「明天」是它自己编的------这也是为什么正式系统要一层层加校验。)

所以 Agent 到底是什么

绕了这么一大圈,可以给 Agent 一个定义了:

Agent 就是以大模型为大脑,能调用工具,并且在一个循环里自己决定下一步做什么,直到把任务做完的程序。

这句话里有三个关键词。「大模型 」说明它的判断能力还是来自那个接龙学霸;「工具 」说明它能碰到外面的真实数据和系统;「循环 」说明它不会一问一答就收工,它会想一步、做一步、看结果、再想下一步。业内给这种「想一步做一步」的工作方式起了个名字,叫 ReAct(推理 Reasoning + 行动 Acting 两个词拼起来的)。

打个比方。大模型像一个顾问,你问他「房子该怎么装修」,他能讲一大堆方案,但不会亲自动手。Agent 像一个项目经理,你说「帮我把房子装好」,他会自己去找装修队、买材料、盯进度,遇到问题再调整,直到房子装好了才来跟你汇报。

说实话,你手写的那二十来行循环,就是 Agent 的内核。后面正文用 LangGraph 搭的主力 Agent,功能多了很多,最底下跑的也是这个循环。

循环一定要有闸

让模型自己决定下一步,也带来了两个新麻烦,代码里已经提前防上了。

第一个麻烦是它可能停不下来------比如订单号打错了,查出来是空,它换个写法再查,还是空,再换,一直重复下去。所以循环外面用 MAX_STEPS 设了一个上限,走满八步还没结束,就跳出来转人工,不能让它无限地烧钱。第二个麻烦是工具本身会出错------数据库连不上、参数格式不对、下游接口超时,这些异常要是不管,整个程序直接崩掉。所以执行工具那里套了一个 try,出了错就把错误信息当成工具结果递回给模型,它一般读得懂报错,会试着换个参数,或者老实告诉用户查不到。

同一个问题,换一种写法:Workflow

Agent 很灵活,可你有没有觉得哪里有点不放心?先查什么、后查什么,全交给模型临场决定。

其实还有另一种写法。既然「查鞋到哪了」这件事就是先查订单、再查物流,那干脆把这个顺序直接写在代码里,模型只负责最后把查到的数据说成人话。这里面没有工具清单,也没有循环:先用正则从问题里抠出订单号,查订单,查不到就直接转人工,查到了再拿快递单号查物流,最后把两份数据一起交给模型,让它组织成一句回答。

这里的 system 是一个新角色,意思是开发者给模型定的规矩,用户看不到。我们在里面写了一句「数据里没有的不许编」------这就是前面说的立规矩。这种把步骤提前写好、按固定路线一步步走的写法,叫 Workflow(工作流)。

两种写法到底差在哪? 差别藏在「谁说了算」上。Agent 那边,下一步干什么由模型决定,代码只负责照着执行;Workflow 这边,下一步干什么由代码决定,模型只在最后说话的环节出场。

text 复制代码
用户问题
   ↓
下一步谁来决定?
  ├─ 模型决定(Agent)→ 模型自己拆步骤、自己决定查什么 → 代码照着执行
  └─ 代码决定(Workflow)→ 代码写死步骤:正则提取、查订单、查物流 → 模型只负责说人话

这个差别带来了实实在在的后果:

  • 花费:Agent 那边请求了三次模型(申请查订单、申请查物流、才回答),Workflow 只请求了一次,前面的查询都是代码直接做的。步骤一多,这个差距会越拉越大。
  • 稳定:Workflow 每次都走同一条路,结果可预期,出了问题一眼就能看出卡在哪一步。Agent 每次走的路可能不一样,调试起来要费劲得多。
  • 灵活 :Workflow 只能处理你提前想到的情况。用户要是没带订单号,只说「我昨天买的那双鞋」,re.search 直接找不到,整段代码就崩了。Agent 碰到这种情况,至少还有机会自己想办法,比如先问用户要订单号。

该选哪个? 一句话:看任务的步骤能不能提前定下来。步骤是固定的,或者对结果要求特别严、一步都不能出错(比如退款、扣款),就用 Workflow 把路线写死;步骤没法提前预料、要根据中间结果灵活应对,就用 Agent 让模型自己拿主意。真实的系统很少只用一种,大多是两种混着用。

为什么智能电商客服两种都要用

客服里有几类问题,是绝对不能赌模型自觉的:用户问退货政策,必须先去知识库里查到真实的规定再回答;用户要退款,必须先查订单、再查政策,才能下结论。这些环节要是交给 Agent 自己决定,它哪天一偷懒跳过了查询,就是一次客诉。所以这些环节的顺序,要用 Workflow 写死在代码里。

可也有一类问题,步骤是说不准的。有的用户报订单号,有的只报手机号,问完物流又接着问售后,你很难提前把所有路线都写出来。这种问题就交给 Agent,让它自己决定查什么。

所以这套客服系统的骨架,是 Workflow 加 Agent 的混合架构:一条用户消息进来,先经过一段写死的流程------请模型识别出用户想干什么,再由代码按识别结果把它分到固定的路线上,只有需要灵活处理的那条路线,才交给中间的 Agent。

text 复制代码
用户消息
   ↓
代码识别意图并分流(写死的 Workflow)
  ├─ 退货政策:先查知识库再答(Workflow)
  ├─ 退款:先查订单再查政策(Workflow)
  └─ 灵活问题:交给 Agent(自己决定查什么)
          ├─ 工具:查订单
          └─ 工具:查物流

你手写的这些东西,正文里都会换成更工程化的做法:发请求 → ChatOpenAI;history 列表 → 上下文裁剪与摘要;手写工具清单 → @tool 装饰器;那个循环 → LangGraph 搭的主力 Agent;写死的步骤 → 节点和分支;try 与步数上限 → 工具系统的超时、重试和审计。框架并不神秘,它替你做的就是这些重复劳动。


一点感想

读完这两篇,我最大的收获是把「框架光环」给摘掉了。我们平时听到 LangChain、LangGraph 觉得高深,但原文里点破了一件事:这些框架不过是在那「一发一收」的接口外面套了一层又一层的包装。最里面永远是「你发一段文字,它回一段文字」。

而 Agent 之所以「能干活」,靠的也不是什么黑科技,就是补上了大模型那三个朴素的短板:记不住 → 用 history 列表把聊过的话每次重发一遍;不知道你家的事 → 用工具调用,让它开口要数据、你的代码替它去查;只会一问一答 → 用一个循环,让它想一步、做一步、看结果、再想下一步。

我手写过的那段二十来行的 run_agent 循环,就是 Agent 的内核;那串 TOOLS 工具清单,就是它伸出的一双手。等真正去读 LangGraph 的代码时,我不会再被那些节点、分支、状态图吓到,因为我知道,它们不过是把我手写的循环和清单,换了一种更结构化、更工程化的写法而已。

最后用原文那句话收尾,也作为我这次复习的总结:

大模型负责判断,工具负责碰到真实世界,循环负责一步步把事做完。

如果你想从零搭一个能真正干活的智能体,强烈推荐先把这两篇前置文章读透、把那几个小例子亲手跑一遍。跑通的那一刻,比读十遍定义都管用。

相关推荐
海带紫菜菠萝汤1 小时前
欧洲也开源了「78B 只激活 3.46B」:主权叙事变了,技术选型没变
人工智能·深度学习·ai·开源·大模型
进击的雷神1 小时前
OpenClaw 太重、启动太慢?我试了试这个 Rust 重写的轻量版 AI 助手网关
开发语言·人工智能·rust·zeroclaw
微软技术分享1 小时前
BinSentry 1.0 二进制哨兵测试版发布
人工智能
蒲公英eric1 小时前
Python工具链与LaTeX排版:把兵器配齐
人工智能·python·算法·数学建模·数学建模工具
海盗12341 小时前
AI 新闻日报 2026-10-03:编排写进代码、领域知识打包成技能、具身智能回到班次与价格
人工智能·机器人·人工智能aigc
沐言人生1 小时前
牛逼!Github上有人开源了,让AI帮你生成数学物理解题视频
人工智能
liulilittle1 小时前
短期内不存在通用 AI 工作流魔法
大数据·开发语言·c++·人工智能·llm·agent·tools
别动我齐刘海1 小时前
简历技术栈全面复习总结
c++·人工智能·深度学习·学习·tcp/ip·算法·rpc
AIUCE1 小时前
都说Muse开源了,其实开源的是 gadget SDK,不是 Muse
人工智能