1. 为什么我不建议新手一上来就啃框架
1.1 一个很常见的翻车现场
我带过几个想转行做 AI Agent 的朋友,几乎所有人第一周都会问我同一个问题:“LangChain 和 Spring AI 到底选哪个?”每次我都反问一句:“你能说清楚一个 Agent 从收到用户消息到给出回答,中间到底发生了哪几步吗?”十个人里有八个答不上来。
这就是最典型的翻车现场:还没搞懂 Agent 是什么,就先陷进框架的 API 里。结果就是照着官方文档抄了一个 Demo,跑通了,觉得自己会了;一旦需求稍微变一点,比如要加个工具调用、要接个本地模型、要做多轮记忆,立刻就懵了,因为根本不知道框架在背后替你做了什么。
我自己的经历也差不多。最早接触 AI Agent 的时候,我直接上手 LangChain,花了两天把文档里的 Chain、Agent、Tool 都跑了一遍,感觉挺爽。但等到我要做一个“根据用户问题自动查数据库再总结”的小工具时,我发现我完全不知道该把逻辑写在哪一层,最后写出来的东西又臭又长,调试起来极其痛苦。后来我退回去,用最原始的 Python 手写了一遍完整的 Agent 循环,才真正明白框架到底在解决什么问题。
所以这篇内容的核心观点很明确:新手和转行者学 AI Agent,第一步不是学框架,而是学“Agent 到底是怎么运转的”。框架是加速器,不是入门教材。你连发动机原理都不懂,给你一台涡轮增压你也开不明白。
1.2 这篇内容适合谁看
如果你符合下面任意一条,这篇内容就是写给你的:
- 完全没接触过 AI Agent,但听说这行有机会,想转行进来;
- 会一点 Python,但没做过任何 LLM 相关的项目;
- 用过 LangChain 或者 Spring AI 的 Demo,但说不清楚里面发生了什么;
- 想搭一个能真正干活的小 Agent,而不是只会跑官方示例。
如果你已经是能自己手写 ReAct 循环、能根据业务选型框架的老手,那这篇内容对你价值不大,可以直接跳过。
1.3 先给结论:学习路径应该是这样的
我把这条路径总结成一句话:先懂原理,再练手写,最后上框架。
具体拆成三个阶段:
| 阶段 | 目标 | 大概耗时 | 关键产出 |
|---|---|---|---|
| 第一阶段 | 搞懂 Agent 的核心循环和几个关键概念 | 3-5 天 | 能用大白话讲清楚 Agent 怎么工作 |
| 第二阶段 | 用纯 Python 手写一个最小可用 Agent | 1-2 周 | 一个不依赖任何框架、能调用工具的小 Agent |
| 第三阶段 | 引入框架,理解框架替你做了什么 | 2-3 周 | 能用 LangChain 或 Spring AI 重构第二阶段的成果 |
这个顺序不是拍脑袋定的。下面我逐个拆解为什么这么排。
2. 第一阶段:先把 Agent 的“五脏六腑”搞清楚
2.1 Agent 到底是什么,用生活化的类比讲
很多人把 AI Agent 想得很玄乎,其实你可以把它类比成一个刚入职的实习生。
这个实习生有几个特点:脑子还算好使(这是大模型),但记性差(没有长期记忆),不会用公司内部系统(没有工具),需要你给明确的指令(需要 Prompt),而且做完一步之后需要你告诉他下一步干嘛(需要循环控制)。
一个完整的 Agent,本质上就是把这个实习生包装成一个能自主干活的员工。它需要具备四个核心部件:
- 大脑:大语言模型,负责理解、推理、决策;
- 记忆:短期记忆(当前对话上下文)和长期记忆(历史信息、知识库);
- 工具:能调用的外部能力,比如查数据库、发请求、读文件;
- 循环控制:决定什么时候继续思考、什么时候调用工具、什么时候给出最终答案。
你把这四个部件想明白了,Agent 就没有神秘感了。框架做的事情,无非是把这四个部件封装得更顺手而已。
2.2 核心循环:ReAct 到底在循环什么
Agent 最经典的运转模式叫ReAct,全称是 Reasoning + Acting,也就是“推理 + 行动”。这个名字听起来学术,但逻辑特别朴素。
它的循环是这样的:
- Thought(思考):模型先想一下,当前这个问题该怎么解决,下一步该干嘛;
- Action(行动):根据思考结果,决定调用哪个工具,传什么参数;
- Observation(观察):拿到工具返回的结果;
- 把观察结果塞回上下文,回到第 1 步,继续思考。
一直循环到模型认为“我不需要再调工具了,可以直接回答用户了”,就输出最终答案。
我举个具体例子。用户问:“帮我查一下北京今天天气,然后告诉我适不适合跑步。”
第一轮:
- Thought:我需要先查北京今天的天气。
- Action:调用天气查询工具,参数是城市=北京。
- Observation:晴,气温 18 度,空气质量良。
第二轮:
- Thought:天气信息拿到了,18 度晴天,适合跑步,我可以回答了。
- Action:无(直接输出)。
- 最终答案:北京今天晴,18 度,空气质量良,很适合跑步。
你看,整个过程没有任何魔法,就是一个“想—做—看—再想”的循环。框架里的 AgentExecutor、Agent、Tool 这些概念,本质上都是在描述这个循环的不同部分。你把这个循环吃透了,再看框架文档就会觉得特别亲切。
2.3 几个必须搞懂的关键词
在进入实操之前,有几个词你必须能用自己的话解释清楚,不然看框架文档会一直卡壳。
Prompt(提示词):给模型的指令。在 Agent 里,Prompt 不只是“你是一个助手”这种角色设定,更重要的是要告诉模型“你可以用哪些工具、工具怎么调用、输出格式是什么”。这是 Agent 能不能正常工作的关键。
Tool(工具):Agent 能调用的外部函数。一个工具通常包含三部分:名字、描述、参数定义。描述特别重要,因为模型是靠描述来判断什么时候该用这个工具的。描述写得烂,模型就乱调或者不调。
Memory(记忆):Agent 记住历史信息的能力。短期记忆就是当前对话的消息列表,长期记忆通常要靠向量数据库或者外部存储来实现。
Token:模型处理文本的最小单位。你可以粗略理解为一个英文单词约等于 1 到 1.5 个 token,一个中文字约等于 1 到 2 个 token。这个概念重要是因为它直接关系到成本和上下文长度限制。很多人问“AI Agent token 是什么意思”,其实就是在问这个——你的 Agent 每循环一轮,上下文里的 token 就会增加,成本也会涨。
MCP:Model Context Protocol,可以理解成一套让模型和外部工具、数据源对接的标准协议。它的价值在于把“工具接入”这件事标准化了,不用每个框架自己造一套。新手不用急着深入 MCP,知道它是干嘛的就行。
2.4 这一阶段的实操建议
这一阶段不需要写代码,但要做两件事:
第一,找几个真实的 Agent 产品用一用,比如各种能自动完成任务的助手类工具,观察它在什么情况下会调用工具、什么情况下直接回答。带着“它现在处于 ReAct 的哪一步”这个视角去用,收获会完全不一样。
第二,用大白话把 ReAct 循环讲给一个不懂技术的人听。如果你能讲明白,说明你真懂了;如果讲着讲着自己卡住了,说明还有盲区。
提示:这一阶段千万别急着装环境、下框架。我见过太多人第一天就去 pip install langchain,结果被一堆依赖和版本问题劝退,连 Agent 是什么都没搞明白就放弃了。
3. 第二阶段:用纯 Python 手写一个最小 Agent
3.1 为什么一定要手写一遍
有人会问:“既然框架都封装好了,我为什么还要手写?这不是浪费时间吗?”
我的答案是:手写一遍,你才知道框架帮你省了什么,也才知道框架出问题时该往哪查。
我举个真实的例子。之前有个朋友用 LangChain 做 Agent,发现工具死活调不起来。他查了半天文档也没找到原因,最后我让他把框架的日志打开,发现是工具描述写得太模糊,模型根本没识别出来。如果他手写过 Agent,就会第一时间想到去检查工具描述,而不是在框架层面瞎找。
手写的另一个好处是建立信心。当你用一百多行 Python 跑通一个能查天气、能算数的 Agent 时,你会突然意识到:哦,原来这东西没那么玄。这种信心对转行者特别重要。
3.2 环境准备:别在这一步浪费时间
环境这块我只说最省事的方案,避免新手在配置上耗掉热情。
- Python 版本:直接用 3.10 或 3.11。3.8 太老,很多新库不支持;3.12 有些库还没跟上。3.10/3.11 是最稳的区间。
- 安装方式:去 Python 官网下载安装包,安装时记得勾选“Add Python to PATH”。Linux 用户用系统自带的包管理器装就行。
- 虚拟环境:强烈建议用 venv 建一个独立环境,别把全局环境搞乱。命令就三行:
python -m venv agent-env source agent-env/bin/activate # Windows 用 agent-env\Scripts\activate pip install openai- 依赖库:手写阶段只需要一个调用大模型的库。如果你用 OpenAI 兼容的接口,装 openai 就够了。不需要 numpy、cv2 这些,那些是别的场景用的。
注意:网上有很多“免费 Python 源码大全”之类的资源,新手容易一头扎进去下载一堆用不上的代码。我的建议是,手写阶段只装你真正要用的库,保持环境干净。
3.3 第一步:先跑通一次最简单的模型调用
在写 Agent 之前,先确认你能正常调用模型。这一步的目的是排除环境问题,别到时候 Agent 跑不通,你分不清是环境问题还是逻辑问题。
from openai import OpenAI client = OpenAI( api_key="你的key", base_url="你的接口地址" ) response = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "user", "content": "用一句话解释什么是 AI Agent"} ] ) print(response.choices[0].message.content)这段代码能跑通,说明你的环境和接口都没问题。跑不通就先解决这一步,别往下走。
3.4 第二步:定义你的第一个工具
工具本质上就是一个普通的 Python 函数,加上一段给模型看的描述。我以“查询天气”为例,用一个假的实现,重点是理解结构。
def get_weather(city: str) -> str: """查询指定城市的天气""" # 真实场景这里会调天气 API,这里用假数据演示 fake_data = { "北京": "晴,18度,空气质量良", "上海": "多云,22度,空气质量优", } return fake_data.get(city, "暂时查不到这个城市的天气")注意,函数本身很简单,关键是你要把这个函数包装成模型能理解的格式。在 OpenAI 的接口里,工具是这样描述的:
tools = [ { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市的天气情况,当用户询问天气时使用", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,比如北京、上海" } }, "required": ["city"] } } } ]这里有个新手最容易踩的坑:description 写得太随意。如果你只写“查天气”,模型可能在你问“今天适合出门吗”的时候不调用它。描述要写清楚“什么时候用”,而不是只写“这是什么”。
3.5 第三步:手写 ReAct 循环
现在到了最关键的部分。下面这段代码就是一个最小可用的 Agent 循环,我加了详细注释。
import json def run_agent(user_input, max_steps=5): messages = [ {"role": "system", "content": "你是一个助手,可以调用工具来回答问题。"}, {"role": "user", "content": user_input} ] for step in range(max_steps): response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools ) msg = response.choices[0].message # 如果模型没有调用工具,说明它准备直接回答 if not msg.tool_calls: return msg.content # 把模型的思考过程加入上下文 messages.append(msg) # 处理每一个工具调用 for tool_call in msg.tool_calls: func_name = tool_call.function.name args = json.loads(tool_call.function.arguments) if func_name == "get_weather": result = get_weather(args["city"]) else: result = "未知工具" # 把工具结果塞回上下文 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result }) return "达到最大步数,未能完成任务"这段代码不到 40 行,但它就是一个完整的 Agent。你可以拿它去问“北京今天天气怎么样”,它会自动调用工具、拿到结果、再组织语言回答你。
这就是 Agent 的本质。框架做的事情,无非是把这段代码封装得更通用、更健壮、支持更多模型和工具格式而已。
3.6 手写阶段必须搞懂的三个细节
第一个细节是消息列表的累积。每一轮循环,你都要把模型的输出和工具的结果追加到 messages 里,这样模型才能“看到”之前发生了什么。这就是最朴素的短期记忆。
第二个细节是循环终止条件。我用的是 max_steps 限制,防止模型陷入死循环。真实场景里还要考虑超时、异常处理等。很多人第一次写 Agent 忘了设终止条件,结果模型一直调工具,token 哗哗地烧。
第三个细节是工具结果的格式。工具返回的内容会作为一条 role 为 tool 的消息塞回上下文,模型会把它当成“观察结果”。所以工具返回的内容要尽量简洁清晰,别塞一大堆无关信息,否则会浪费 token 还干扰模型判断。
实操心得:手写阶段建议故意制造一些错误,比如让工具抛异常、让模型调用不存在的工具,看看会发生什么。这种“破坏性测试”能帮你提前理解框架里的异常处理机制。
4. 第三阶段:引入框架,理解它到底帮你做了什么
4.1 什么时候该上框架
我的判断标准很简单:当你手写的 Agent 开始出现重复代码、开始需要支持多种模型、开始需要管理复杂工具集的时候,就该上框架了。
如果你只是做个小工具,手写完全够用,甚至更可控。但如果你要做的是一个需要长期维护、要接很多工具、要支持多轮复杂对话的项目,框架的价值就体现出来了。
4.2 LangChain 和 Spring AI 到底怎么选
这是新手问得最多的问题。我直接给结论,再说理由。
| 维度 | LangChain | Spring AI |
|---|---|---|
| 语言生态 | Python 为主 | Java 为主 |
| 适合人群 | 数据、算法方向 | 后端、企业开发方向 |
| 上手难度 | 概念多,容易迷路 | 对 Java 开发者友好 |
| 生态丰富度 | 非常丰富,工具多 | 相对新,但在快速补齐 |
| 典型场景 | 快速实验、原型验证 | 企业级应用集成 |
选型的核心逻辑是跟着你的主语言走。你是 Python 背景,就选 LangChain;你是 Java 后端,就选 Spring AI。别为了追新去学一门不熟的语言,那样学习成本会翻倍。
至于 Dify、CrewAI 这些,Dify 更偏向低代码平台,适合快速搭原型;CrewAI 偏向多 Agent 协作场景。新手不用一上来就全都学,先把一个框架用透。
4.3 用 LangChain 重构你的手写 Agent
我把上面手写的逻辑用 LangChain 重写一遍,你可以对比着看,体会框架封装了什么。
from langchain_openai import ChatOpenAI from langchain.agents import tool, AgentExecutor, create_openai_tools_agent from langchain_core.prompts import ChatPromptTemplate @tool def get_weather(city: str) -> str: """查询指定城市的天气,当用户询问天气时使用""" fake_data = {"北京": "晴,18度", "上海": "多云,22度"} return fake_data.get(city, "查不到") llm = ChatOpenAI(model="gpt-4o-mini") tools = [get_weather] prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个可以调用工具的助手"), ("human", "{input}"), ("placeholder", "{agent_scratchpad}") ]) agent = create_openai_tools_agent(llm, tools, prompt) executor = AgentExecutor(agent=agent, tools=tools, verbose=True) result = executor.invoke({"input": "北京今天天气怎么样"}) print(result["output"])对比一下你会发现,框架帮你省掉了这些事:
- 工具描述的格式转换(@tool 装饰器自动生成 schema);
- ReAct 循环的编写(AgentExecutor 内部实现);
- 消息列表的管理(agent_scratchpad 自动处理);
- 多模型适配(换模型只改一行)。
但代价是你对细节的控制变弱了。比如你想自定义循环终止逻辑,就得去翻框架源码。这就是为什么我一直强调先手写——手写过的人,用框架时心里有底,出问题知道往哪查。
4.4 关于 MCP,新手该知道什么
MCP 这两年被提得很多,很多人一上来就想学 MCP。我的建议是:先别急。
MCP 解决的是“工具接入标准化”的问题。它的价值在于,当你有大量工具需要接入、而且希望这些工具能在不同框架、不同模型之间复用时,MCP 能省很多事。但如果你现在连一个工具都还没写过,学 MCP 就是空中楼阁。
正确的顺序是:先手写几个工具,理解工具的注册、描述、调用流程;然后再看 MCP 是怎么把这套流程标准化的。这样你才能理解 MCP 到底解决了什么痛点,而不是死记它的协议格式。
5. 新手最容易踩的坑和排查技巧
5.1 工具调不起来的排查思路
这是最高频的问题。模型明明应该调工具,但它就是直接回答了。排查顺序如下:
- 检查工具描述:描述里有没有写清楚“什么时候用”。这是最常见的原因。
- 检查参数定义:参数类型、必填项有没有写对。
- 检查 Prompt:系统提示里有没有告诉模型“你可以调用工具”。
- 检查模型能力:有些小模型对工具调用的支持不好,换个强一点的模型试试。
- 打开 verbose 日志:看模型实际输出了什么,很多时候答案就在日志里。
5.2 Token 消耗失控怎么办
Agent 循环最大的成本风险就是 token 爆炸。几个实用的控制手段:
- 限制最大循环步数:这是最基本的,别让模型无限循环。
- 精简工具返回内容:工具返回一大堆无关信息,每轮都塞进上下文,成本会飙升。
- 及时裁剪历史消息:多轮对话场景下,老消息该丢就丢,或者做摘要压缩。
- 监控每轮 token 数:养成看 usage 字段的习惯,心里有数。
5.3 常见问题速查表
| 现象 | 可能原因 | 解决方向 |
|---|---|---|
| 模型不调用工具 | 工具描述模糊 | 重写 description,写清使用场景 |
| 调用工具报参数错误 | 参数 schema 定义不对 | 检查类型和必填项 |
| 循环停不下来 | 没有终止条件 | 加 max_steps 和超时 |
| 回答质量差 | 上下文太乱 | 精简消息,优化 Prompt |
| 换模型后行为变了 | 模型对工具支持不同 | 换回验证过的模型或调整 Prompt |
5.4 几个我踩过的坑
第一个坑是过早追求多 Agent 协作。我一开始就想搞一个“规划 Agent + 执行 Agent + 审核 Agent”的系统,结果调试成本极高,最后发现单 Agent 加好工具就能解决大部分问题。新手别被“多 Agent 架构”这种词唬住。
第二个坑是迷信框架的默认配置。框架的默认 Prompt、默认循环逻辑不一定适合你的场景,该改就得改,别偷懒。
第三个坑是忽略错误处理。工具调用失败、模型返回格式异常、网络超时,这些在 Demo 里不会出现,但真实场景里天天发生。手写阶段就要养成加 try-except 的习惯。
6. 给转行者的学习节奏建议
6.1 别贪多,一次只学一个概念
AI Agent 涉及的知识点很多:Prompt 工程、工具调用、记忆管理、RAG、多 Agent、MCP……新手最容易犯的错就是全都想学,结果哪个都不精。
我的建议是按需学习。你当前的项目需要什么,就学什么。做单 Agent 就先别碰多 Agent,做工具调用就先别碰 RAG。知识是长在项目上的,脱离项目学概念,忘得特别快。
6.2 用项目驱动,别用教程驱动
看一百个教程,不如自己做一个能跑起来的小项目。我建议的第一个项目是“个人助手 Agent”,功能不用多,能查天气、能算数、能记点东西就行。做完这个,你对 Agent 的理解会超过看十篇教程。
第二个项目可以稍微复杂点,比如“自动整理笔记的 Agent”,涉及文件读写和简单的内容处理。做完这两个,你基本就有能力去看真实项目了。
6.3 关于框架学习的最后一点建议
框架更新很快,今天学的 API 明天可能就变了。所以学框架要学它的设计思想,而不是死记 API。比如 LangChain 的 Chain、Agent、Tool 这些抽象,理解了它们各自解决什么问题,就算 API 变了,你也能快速上手新版本。
我自己现在看一个新框架,第一件事是找它的核心抽象,第二件事是看它的 Agent 循环是怎么实现的,第三件事才是看具体 API。这个顺序能帮我快速抓住重点,不被细节淹没。
最后分享一个我自己的习惯:每学一个新东西,我都会尝试用最原始的方式实现一遍,再对比框架的实现。这个过程很慢,但学到的东西特别扎实。AI Agent 这个领域变化快,扎实的基础比追新更重要。