最近半年,几乎每周都有人来问我同一个问题:想做AI Agent,该从哪开始学?我的回答往往让很多人意外——先别急着装那些现成的编排框架,也别一上来就啃各种Agent框架的源码。新手和转行做Agent的人,最该先搞懂的其实是一套循环、一个接口协议,以及几千行Python代码里最基本的几个库。这篇文章就按我真实的入门路径来写,把我踩过的坑、后来验证过有用的方法,一次性说清楚。
1. 先搞明白Agent的“循环”:它不是一个ChatGPT套壳
1.1 Agent = 模型 + 循环 + 工具,而不是一个更大的模型
很多人一听到AI Agent,第一反应是“这不就是ChatGPT加了个外壳吗”。这个理解不算错,但会害了你。因为一旦你抱着这种理解去学框架,会发现框架里的概念又多又绕,什么Chain、什么Planner、什么Memory,每个都认识,连起来就头晕。
我更愿意把Agent拆成三个部分来看:模型、循环、工具。
- 模型:负责“思考”的那部分,也就是大语言模型本身。
- 循环:一个反复执行的流程,通常是“观察→思考→行动→再观察”。
- 工具:模型可以调用的外部能力,比如计算器、搜索、数据库查询、发邮件。
三者的关系,用人来类比就很好懂了。模型是大脑,循环是工作流程,工具是手和脚。大脑不能直接搬砖,手和脚也不能自己决定搬哪块砖。Agent的价值,就是把这三者串起来,让大脑能指挥手脚去干活,而且干完一步能回头看结果、再决定下一步。
这个“回头看结果再决定下一步”的环节,就是循环的核心。它和普通聊天完全不同。普通聊天是“你问一句,模型答一句”,答完就结束了,模型不关心这句话之后发生什么。而Agent不是回答完就完事,它会根据你的问题,自己决定要调用什么工具,看到工具返回的结果,再判断下一步做什么,直到它认为任务完成了。
我见过不少新手,一上来就翻框架文档,看了一堆“AgentExecutor”“ToolNode”“Planner”这类名词,越看越混乱。原因很简单:框架把底层循环封装得太深了,你只看到表面接口,看不到背后的数据流。所以我的建议是,先不要碰任何框架,先自己在脑子里把“循环”这个概念扎稳。
1.2 三个必须理解的边界:工具、记忆、规划
理解了循环之后,还有三个边界必须清楚,否则后面写代码一定踩坑。
第一,工具边界。模型本身不执行任何真实操作,它只负责“决定”调用哪个工具,以及“生成”传给工具的参数。真正执行的是你那几千行代码。新手最容易犯的错,是把希望全寄托在模型身上,以为模型能自己神奇地访问数据库、操作文件。模型确实可以生成访问数据库的代码,但这些代码需要在我们自己的环境里跑起来,跑通了结果再传给模型去分析,它才能进一步处理。说白了,模型像是一个项目经理,它安排任务,真正搬砖的是你的代码。
第二,记忆边界。大模型本身没有记忆能力。它每轮对话都只接收你本次给它的全部上下文,上一次聊了什么,如果不主动带着,它不会自动记得。Agent系统里的记忆,通常有两种:一种是把历史对话拼进下一次请求里,这叫短期记忆,靠的是上下文窗口;另一种是把重要信息存到外部数据库,需要的时候检索回来,这叫长期记忆。新手很容易忽视一个问题:上下文窗口是有限的,而且塞得越多,响应越慢、成本越高。所以“记什么”和“怎么记”比“能记多少”更重要。
第三,规划边界。模型能生成看起来很合理的“步骤拆解”,但这不代表它真的能按计划执行到位。执行过程中遇到意外情况,它需要根据实时反馈调整计划。这种“边做边修正”的能力,靠的正是循环。很多新手设计的Agent,只会让模型输出一个完整的计划,然后傻乎乎地按计划执行,中间任何一步出了岔子,整个任务就断了。所以规划不是一次性的,它是循环里“思考”这个环节反复干的事。
把这三条边界想清楚,你再去看任何框架的文档,会发现思维清晰很多。因为你已经知道框架里的Memory模块是在解决记忆问题,ToolNode是在解决工具执行问题,Planner是在解决规划问题。你带着问题去学,而不是被名词牵着走。
2. 不碰框架,先用API把最小闭环跑起来
2.1 你真正要会的Python基础,比想象中少
转行者最担心的就是编程基础。我直接说结论:做AI Agent入门,你需要的最少Python技能就那么几条,不需要精通数据结构,更不需要会写复杂的算法。
- 字典和列表的读写(这是处理JSON的基础)。
- 函数的定义和调用(把工具封装成一个个函数)。
- 用requests或httpx发HTTP请求(调大模型API和外部服务的通用能力)。
- 用json.loads和json.dumps做序列化和反序列化。
- 用try-except做异常处理(工具调用一定会出错,不处理会直接崩)。
- 会读环境变量(API密钥这类敏感信息绝不写死在代码里,用os.getenv读取)。
就这些,没了。有人可能会问,那pandas、numpy要不要学?不用。至少入门阶段不需要,Agent的核心是“编排逻辑”,不是“数据处理算法”。你只要能把一个函数的返回结果交给模型,再把模型的决策传给另一个函数,这个骨架就撑得起来。
我见过有些转行者,花了三个月学Python基础语法,越学越心虚,觉得前面还有无数知识盲区,迟迟不敢动手。其实正确的做法是,先掌握上面这几条,然后立刻开始做一个小Agent,在做的过程中遇到不会的现查现学。真实的项目会逼着你快速掌握最常用的那几个库,效率远高于抱着教程空学。
2.2 调用大模型API的几个关键参数
先不讲复杂概念,单说调API这件事。所有大模型开放平台,基本都提供一个文字生成接口。你给它一段消息列表,它返回模型生成的文本。这一段调用,是所有Agent的地基。
地基里最需要搞懂的有几个参数,我一个个说:
temperature:控制随机性,取值范围通常是0到2。做Agent时我一般设很低,比如0.1甚至0。因为它需要稳定地输出符合格式的结果,而不是天马行空地创作。如果是写文案之类偏创意任务,才把温度调高。新手常犯的错是默认值凑合用,结果发现模型偶尔返回的JSON格式不规则,排查半天发现是温度太高导致输出飘了。
max_tokens:限制生成的最大长度。这个参数既能控制成本,也是防呆设计。不设的话,模型可能一个劲儿输出下去,钱哗哗地烧。Agent场景里,模型主要任务是输出“决策”,不会太长,一般给个几百就够。
stop:停止序列。可以指定一个字符串,模型一旦生成到这个字符串就停下来。比如你希望模型只输出一个JSON对象,可以把“}”作为结束标志之一,或者在更复杂的场景里用特定分隔符让模型在哪段停下来。这个技巧在Agent循环里非常实用,能有效地让模型输出“到点就停”。
stream:是否流式输出。入门阶段建议先不开,等响应再整体解析,逻辑更简单清晰。
这些参数原则上都值得亲手试一遍。我的习惯是,拿到一个新模型的API,先写个十行左右的脚本,把温度从0调到1.5,看看输出会有什么变化;把max_tokens调到10,看看截断长什么样。对这个“感觉”越熟悉,后面做Agent越稳。
2.3 结构化输出:JSON就是Agent内部的“接口协议”
做Agent时,模型输出可不是给人看的散文,而是要作为机器可以解析的指令去执行的。这里就引出了整个Agent系统里最关键的工程细节:结构化输出。
最常见的做法是,约定模型必须返回一个固定格式的JSON对象,里面包含“动作类型”和“动作参数”。比如:
{ "action": "calculator", "action_input": { "expression": "1 + 2" } }你的代码拿到这个JSON,解析后知道模型想调用calculator工具,参数是一个算式,于是执行对应函数,得到结果3,再把这个结果拼到消息里,回传给模型。这就是一次完整的“Agent思考→调用工具→获得结果→继续思考”的最小闭环。
这个结构化输出的约定,我习惯把它叫作Agent内部的“接口协议”。就像两个团队之间要对接,得先定好接口规范一样。模型和代码之间的接口,就是这份JSON约定。接口约定得越严格、越简单,系统就越不容易出错。
怎么让模型稳定输出JSON?有几个经验:
- 在系统提示词里写清楚格式要求,并给出一个JSON例子。模型的Few-shot能力很强,给一个好的示范比单纯描述格式更有效。
- 要求“仅输出JSON,不要任何解释或前后缀”。否则模型经常输出“好的,这是您需要的JSON:”之类的话,解析就会报错。
- 温度设低。随机性越高,越容易输出不合规内容。
- 一定要写解析兜底的逻辑。也就是模型偶尔给不出合法JSON时,你的代码要做异常处理,或者干脆把错误信息回传给它让它自我纠正。
3. 手写30行核心代码:从零搭一个会调用工具的Agent
3.1 用“动作字典”代替框架的Agent执行器
接下来是实战。我不准备贴一个完整的项目,那会让人有“看完还是不会”的挫败感。我只展示最核心的循环骨架,大概三四十行,但它是理解所有框架的一把万能钥匙。
思路很简单:把工具装进一个字典,字典的key是工具名,value是工具函数。模型输出的“action”字段,就是字典的key。代码查字典拿到函数,执行它,得到结果回传。这样一个极简的“Agent执行器”就出来了。
import json import os from openai import OpenAI client = OpenAI(api_key=os.getenv("LLM_API_KEY")) def calculator(expression: str) -> str: """安全的算术计算,仅支持加减乘除与括号""" allowed = set("0123456789+-*/(). ") for ch in expression: if ch not in allowed: return "错误:表达式包含不允许的字符" try: result = eval(expression) return str(result) except Exception as e: return f"计算失败:{e}" def get_weather(city: str) -> str: """模拟天气查询,真实场景换成API调用""" fake_weather = { "北京": "晴,25度", "上海": "多云,28度", } return fake_weather.get(city, "暂无该城市数据") tools = { "calculator": calculator, "get_weather": get_weather, } system_prompt = """ 你是一个智能助理。你可以调用以下工具: - calculator:算术计算,参数为expression,字符串类型 - get_weather:查询天气,参数为city,字符串类型 你需要根据用户问题,输出一个JSON对象,格式如下: {"action": "工具名", "action_input": {"参数名": "参数值"}} 仅输出JSON,不要任何其他内容。 """ def run_agent(user_input: str, max_steps: int = 5): messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_input}, ] for step in range(max_steps): response = client.chat.completions.create( model="your-model-name", messages=messages, temperature=0.1, ) content = response.choices[0].message.content.strip() print(f"第 {step + 1} 步,模型输出:{content}") try: decision = json.loads(content) except json.JSONDecodeError: messages.append({"role": "assistant", "content": content}) messages.append({ "role": "user", "content": "解析JSON失败,请只输出合法JSON,不要包含任何额外文字。" }) continue action = decision.get("action") action_input = decision.get("action_input", {}) tool_func = tools.get(action) if not tool_func: messages.append({ "role": "user", "content": f"未知工具:{action},请从可用工具中选择。" }) continue try: result = tool_func(**action_input) except Exception as e: result = f"工具执行出错:{e}" messages.append({"role": "assistant", "content": content}) messages.append({ "role": "user", "content": f"工具结果:{result}。如果任务已完成,请直接只输出以下固定格式:{{\"action\": \"final\", \"action_input\": \"最终答案\"}}。" }) if action == "final": return action_input return "达到最大步骤数,任务未完成。" print(run_agent("帮我算 3 * (4 + 5),然后看看北京天气"))这段代码,建议你亲手敲一遍,别复制。敲的过程里你会注意到很多细节,比如参数名对不上、忘记引入异常处理、模型偶尔返回非JSON时怎么办。这些细节,才是Agent开发真正的门道。
3.2 代码里的两个关键细节:循环上限和异常回传
这段代码看起来简单,但有两个细节,是新手最容易忽略的。
第一个是循环上限。我在run_agent里设置了一个max_steps参数,默认5步。这个设计极其重要。因为模型在实际运行中完全有可能陷入“反复调用工具、反复得到结果、但就是不收敛”的循环里,没有步数上限的话,你的程序会一直调API,钱花出去了,用户还在干等。我还见过一个极端案例,模型在一个错误参数上反复横跳,直到耗尽上下文窗口。所以,循环上限是Agent系统的“安全气囊”,必须有。
在真实项目里,我通常还会加一个超时机制。比如每轮工具调用最多等10秒,整个Agent任务最多等60秒,超时就直接向用户返回“任务超时,请稍后重试”。这些保护机制虽然不起眼,但决定了你的Agent能不能从demo变成可用的产品。
第二个是异常回传。注意我把工具执行包在了try-except里,并且把错误信息拼在回传消息中:“工具执行出错:xxx”。这招是我做了很久之后才意识到价值的。因为模型并不知道你的程序发生了什么,它只能看到你回传给它的文字。你如果把错误信息吞掉,回传一句“工具返回空”,模型就不知道是参数错了还是环境崩了,只能瞎猜。但你明明白白告诉它“除以零”、“键不存在”、“网络超时”,它就有机会在下一次决策中修正自己的参数选择。这个“把错误当作反馈喂回给模型”的模式,是Agent健壮性的核心。错误不是用来打断流程的,而是用来帮助模型纠错的。
3.3 从单轮工具调用走向多步任务:再加两步记忆
刚才那段代码,只能处理“一次思考、一次工具调用、再看结果”的单轮循环。但真实世界的任务往往是多步的。比如“帮我查北京天气,如果超过30度就提醒我带伞”。第一步要查天气,第二步根据结果做判断。这两步之间,模型需要记住第一步查到的结果。
好在这件事不用改循环结构,只要稍微改一下消息列表就行。你会发现,在我的代码里,messages列表一直是累加的。每轮模型的输出和工具的结果,都被追加进messages。这样一来,模型在下一次请求时,就能看到之前所有的交互记录,这就是最简单有效的短期记忆实现。
如果你想更靠近真实项目,可以再加一层简单的“工作记忆”,也就是把任务拆成子步骤。比如用一个列表记录每步的目标、状态和结果,最终汇总给模型做判断。我在很多项目里就是这么干的,不依赖任何框架,效果一样稳。
走到这一步,你已经具备了手写一个极简Agent的能力。这时候再回头看框架,你会发现它无非是把这些循环逻辑封装成了可复用的组件,再加上更多高级功能——重试机制、模型切换、多Agent协作,等等。但底层的骨架,就是上面这堆代码的增量扩展。
4. 什么时候才该碰框架:我的判断标准
4.1 框架解决的是效率问题,不是理解问题
写了三章“不要一上来就碰框架”,现在要公平地说说框架的价值。否则有些读者会误以为我彻底否定框架,那就走偏了。
框架解决的问题,是效率问题,不是理解问题。当你已经亲手写过一遍Agent循环,你对“Agent是怎么跑起来的”已经有了底层认知。这时再接触社区里那些常见的编排框架,你会有一种“原来它内部的某组件就是干这个用的”豁然开朗感。你学习框架的速度会快得多,而且一旦运行出问题,你能更快地定位到是框架配置问题,还是你自己的逻辑问题。
举个例子。框架里的“工具节点”模块,本质就是我上面那段代码里字典查表逻辑的工程化升级。它可能在内部处理了并发、重试、日志、并行调用等复杂需求,但核心思想没有变。你如果连手写循环都没有过,直接看这个模块的源码,大概率是云里雾里。
框架的第二个价值,是它帮你抽象掉了很多重复劳动。比如多轮对话管理、上下文截断策略、和向量数据库的对接、对多种模型厂商的统一封装。这些事情写起来不难,但繁琐。如果你已经懂原理,直接用框架是很划算的。
4.2 过早用框架的三个典型代价
很多新手有一个错觉:装了框架,就等于会做Agent了。实际上,框架只是提供了一套积木,怎么搭、搭成什么样,拼的还是你对底层原理的理解。过早用框架,通常会付出三个代价。
第一个代价是“黑盒焦虑”。你只管调方法传参数,但不知道背后发生了什么。如果一个环节报错,而你连循环的基本流程都讲不清,就只能上网搜解决方案,搜到什么都试试,运气好能试通,运气不好就卡死。有一次我帮一个朋友排查问题,他用的框架版本里改了API,旧的调用方式失效了,他一头雾水。我问他“你的数据在哪个环节断了”,他答不上来,因为他对框架内部的数据流完全没概念。这就是黑盒的代价。
第二个代价是“版本迁移成本”。编排框架的迭代速度极快,API经常变。如果你对底层原理不熟,框架一升级,你的代码就可能大面积报错,而且根本无从下手。反过来,如果你的核心逻辑是自己手写的,框架只是一个外层包装,升级成本就低很多。
第三个代价是“工程化错觉”。框架让你感觉系统很完整,但很多关键工程细节——比如上下文管理策略、工具调用的超时和重试、成本控制——仍然需要你自己去设计。这些细节恰恰是Agent能不能稳定运行的关键。框架不会替你思考这些。指望框架解决一切的人,最后往往会被框架的复杂抽象所累。
4.3 我给新手和转行者的进阶顺序表
说了这么多,最后给一张可以对照执行的进阶表。它是我自己带过好几个零基础转行的朋友,验证过比较顺畅的路径。
| 阶段 | 学习内容 | 目标 | 预计时间 |
|---|---|---|---|
| 第一阶段 | 熟练调用大模型API,理解参数 | 能写一个“输入用户问题→输出回答”的脚本,搞懂token和上下文 | 1周 |
| 第二阶段 | 手写一个工具调用循环 | 实现文章里的Agent骨架,至少接入2个工具,处理JSON解析和错误回传 | 1周 |
| 第三阶段 | 加入记忆和简单的任务拆解 | 能做多步任务,比如“查天气→提醒带伞” | 1周 |
| 第四阶段 | 主动看一个常见编排框架的核心概念 | 这次可以装了,用它重写第二阶段的Demo,体会框架帮你省了什么 | 1周 |
| 第五阶段 | 深入一个方向:RAG、多Agent协作、或生产化部署 | 做出一个自己真正想用的东西 | 依个人而定 |
这个顺序的核心思想是:先徒手,再上工具。徒手阶段能让你建立不可替代的直觉,工具阶段能让你提高效率。如果你直接跳到第五阶段,前四阶段欠下的“债”,总有一天会以“莫名其妙跑不通”的方式找上门来。
5. 新手与转行者最容易踩的5个坑
5.1 高频问题速查表
把项目里常见的坑整理成一个速查表,方便你直接对照。
| 问题 | 典型表现 | 排查思路与解决 |
|---|---|---|
| 上下文爆炸 | 消息列表越来越长,越到后面响应越慢、越贵 | 记录每轮消息数;超过阈值后,用摘要压缩旧消息,只保留最近几轮完整记录 |
| JSON输出不稳定 | 解析时报错,模型偶尔输出解释文字 | 温度降到0.1以下;提示词里给严格样例;解析失败时把错误消息回传给模型让它重试一次 |
| 工具参数名不匹配 | Python报“unexpected keyword argument” | 给每个工具写清晰参数说明;在提示词里列清参数名、类型和含义;必要时让模型输出JSON后靠代码自动转换字段名 |
| 循环不收敛 | 模型反复执行同一工具,结果原地踏步 | 设置最大步数上限;如果某一步的工具结果和上一步完全一样,可以强制终止并输出当前结论 |
| 成本失控 | 一个简单任务调了几十次API | 限制max_tokens、限制最大步数;开启流式但对用户展示结果的同时也行,但内部要控制;给所有调用加日志,统计单次任务成本 |
这里每一个问题,我都遇到过不止一次。前三个问题在入门阶段极其普遍,后两个则是在你开始做真实项目、要面向真实用户时一定会遇到的。建议把这张表存下来,做到对应问题时回来对照。
5.2 三个让我印象深刻的排查案例
记忆里有一个案例特别典型。一个自己学Agent的开发者,做了一个“自动整理邮箱并回复”的小工具。但是它总在某个固定步骤卡住:当邮件内容比较长时,模型的输出就不是纯JSON了,而是前面多了一段“根据邮件内容,我建议回复如下”。这段文字一加,他的代码就解析失败,整个流程中断。他当时的解决方法是:不断加大模型输出的长度限制,想让模型在足够长的地方再开始输出,结果是白烧了钱。正确的做法是什么?在提示词里用更强硬的约束,再加上一个“解析失败自动重试一次并回传错误信息”的兜底逻辑。我帮他把这两处改掉以后,问题再也没出现过。
第二个案例是关于工具参数的。那位开发者做了一个“查快递”的工具,模型经常把参数传成“快递单号:SF123”,而函数签名要求是单号字符串“SF123”。就因为提示词里没有说清楚“参数值只写单号,不要带字段名”,模型每次都在参数里多带几个字。这种案例,不是模型傻,而是你的接口协议定义得不够严格。解决方式很简单:在工具描述里写“参数city为城市名称,只写城市名本身,例如:北京”,然后做一个参数预处理函数,把常见干扰词剥掉。
第三个案例是关于循环不收敛的。有一次我们做一个自动竞标分析,模型反复调用同一工具查询同一条数据,但每次都因为“再确认一下”继续循环。原因在于,我们在提示词里告诉模型“为了确保准确,可以多次查询”这类模糊表述。模型“积极”地执行了这个指令。后来我把提示词改成“只有在数据不足或存在冲突时才允许再次查询,否则给出最终结论”,循环次数骤降,成本也明显降下来了。这事给我的教训是:给模型的自由度要精准,太多或太少都会出问题。
5.3 转行者如何稳定推进学习节奏
最后聊聊转行者最关心的“节奏”问题。见过太多转行学Agent的人,一开始热情高涨,学了几天就受挫,原因不外乎两种:一是目标定太大,比如“我要做一个能自动化处理所有邮件的系统”,结果第一次调试失败就泄气;二是反复犹豫“我是不是还缺什么基础”,迟迟不写代码。
我的建议是把目标切成特别小的粒度。比如第一个目标不是做Agent,而是“让Python程序成功调用一次模型API,并打印结果”。第二个目标是“让模型根据我的问题,输出一个表示动作的JSON”。第三个目标是“根据JSON去调用我写好的一个函数”。每完成一个小目标,就给自己一个明确的反馈。这种进度感,比任何学习计划都更管用。
转行者还有一个优势。你之前在其他领域的经验——无论是业务逻辑、沟通协调还是问题拆解——在做Agent时非常值钱。因为Agent本质上是在把一套业务规则自动化,你需要理解业务该怎么做,才能告诉模型要做什么、工具要提供什么。我认识一些背景完全不是编程出身的开发者,做起Agent来反而比纯技术的人更顺手,因为他们更擅长“把任务讲清楚”。而“把任务讲清楚”,恰恰是Agent开发中最稀缺的能力。
说实话,走到现在,我自己回头看,最值得庆幸的不是我熟练掌握哪个框架,而是第一周就逼着自己把那个最朴素的循环跑通了。那个手写的十几行代码,像一根定海神针,让我后来不管换什么工具、看什么新框架,都能一眼看出它到底在循环的哪个环节上做了增强。今天分享这套学习路径,如果能让你少走哪怕一点弯路,就值得了。