1. 先搞清楚:AI Agent 到底是个什么东西
1.1 别被术语吓到,它就是个“会自己干活的程序”
很多人第一次听到 AI Agent 这个词,脑子里浮现的是科幻电影里那种有自我意识的机器人。其实完全不是那么回事。你把它理解成一个“能自己判断下一步该干什么的程序”就行了。
传统的程序是什么样?你写死逻辑:第一步调A接口,第二步判断B条件,第三步写C数据库。每一步都是你提前规定好的,程序自己不会变通。AI Agent 不一样的地方在于,它中间有一个“大脑”——通常是大语言模型——会根据当前的情况自己决定下一步做什么。你给它一个目标,它自己拆解步骤、自己选工具、自己判断有没有做完。
举个例子。你让传统程序去“帮我查一下明天北京的天气然后决定要不要带伞”,你得写:调天气API、解析返回结果、判断降水概率是否大于某个阈值、输出结论。每一步都是硬编码。而 AI Agent 的做法是:你把“查天气”和“判断是否带伞”这两个能力以工具的形式给它,然后告诉它“帮我看看明天北京要不要带伞”,它自己会决定先调天气工具,拿到结果后自己推理,最后告诉你结论。
这就是本质区别:传统程序是“你告诉它怎么做”,AI Agent 是“你告诉它做什么”。
那为什么现在 AI Agent 突然火起来了?因为大语言模型的能力到了一个新的临界点。2023年之前,语言模型的理解和推理能力还不够稳定,你让它自己规划步骤,它经常跑偏。但现在的主流模型在指令遵循、工具调用、多步推理这几个维度上已经相当可靠了,这才让 Agent 从论文里的概念变成了能实际跑起来的东西。
1.2 一个 Agent 的最小构成:四个零件
不管多复杂的 Agent 系统,拆到最底层,核心就四个部分:
第一,大脑(LLM)。这是整个 Agent 的决策中心。它负责理解用户意图、规划步骤、选择工具、判断结果是否满足要求。你可以用 OpenAI 的接口、Claude 的接口、也可以用本地部署的开源模型。选哪个模型直接决定了 Agent 的“智商上限”。
第二,工具(Tools)。Agent 不能只靠嘴说,它得能干活。工具就是它跟外部世界交互的手段。查数据库是一个工具,发邮件是一个工具,执行一段代码是一个工具,甚至调用另一个 Agent 也是一个工具。工具的定义通常包括:名称、描述、参数列表、执行逻辑。描述写得清不清楚,直接影响到模型能不能正确选用这个工具。
第三,记忆(Memory)。包括短期记忆和长期记忆。短期记忆就是当前对话的上下文,让 Agent 知道刚才发生了什么。长期记忆通常是外挂一个向量数据库,让 Agent 能记住几天前甚至几个月前跟用户的交互内容。没有记忆的 Agent 就像金鱼,每次对话都从零开始。
第四,规划(Planning)。这是 Agent 最核心也最难做好的部分。简单任务一步就完了,但复杂任务需要拆解。比如“帮我策划一场团建活动”,Agent 得自己拆成:确定人数、选场地、定预算、安排交通、发通知。怎么拆、按什么顺序拆、拆到什么粒度,这些都是规划要解决的问题。
把这四个零件拼起来,一个最简版的 Agent 循环就是:接收用户输入 → LLM 思考该做什么 → 调用工具 → 拿到结果 → LLM 再思考 → 再调工具 → 直到任务完成 → 输出最终结果。
1.3 为什么新手容易走弯路:一上来就啃框架的陷阱
我见过太多人,听说 LangChain 火,上来就 pip install langchain,然后对着文档里那一堆 Chain、Agent、Tool、Memory 的类发呆。折腾了两天,跑通了一个 demo,但问他“这个 Agent 为什么这么决策”,完全答不上来。
问题出在哪?框架帮你封装了太多东西,导致你看不到底层发生了什么。
LangChain 确实好用,它把工具调用、提示词模板、输出解析这些常见模式都封装成了现成的类。但这也意味着,当 Agent 行为不符合预期的时候,你根本不知道是提示词的问题、工具描述的问题、还是模型本身能力不够。你面对的是一个黑盒,而调试黑盒是最痛苦的。
我的建议很明确:先用最原始的方式手写一个 Agent 循环,跑通了、理解了,再去用框架。手写一个最简 Agent 大概只需要 50 行 Python 代码,不依赖任何框架,直接调模型的 API。这个过程会让你真正理解 Agent 的工作原理,之后再用 LangChain 或者 Spring AI 的时候,你就知道框架在帮你做什么,出了问题也知道去哪里找原因。
2. 新手和转行者到底该先学什么
2.1 第一优先级:Python 基础,但不用学到能写爬虫的程度
AI Agent 开发目前最主流的语言就是 Python。原因很简单:几乎所有大模型的官方 SDK 都是 Python 优先,LangChain、CrewAI、AutoGen 这些主流框架也都是 Python 写的。你用 Java 也能做,Spring AI 就是干这个的,但生态丰富度确实差一截。
那 Python 要学到什么程度?我的标准是:能看懂函数定义和调用、会用列表和字典、知道怎么装第三方库、能写 if-else 和 for 循环、会处理 JSON 数据。就这些,足够了。
你不需要会写装饰器、不需要理解元类、不需要搞懂 GIL。那些东西等你真正遇到性能问题或者需要读框架源码的时候再补。一开始就抱着《流畅的Python》啃,大概率是啃到一半就放弃了。
具体来说,你需要掌握的知识点:
- 变量和基本数据类型(字符串、数字、布尔值)
- 列表和字典的增删改查
- for 循环和 while 循环
- if-elif-else 条件判断
- 函数的定义和调用,理解参数传递
- 导入模块和使用 pip 安装包
- 读写文件(尤其是 JSON 文件)
- 异常处理(try-except)
- 虚拟环境的使用(venv 或 conda)
这些内容,如果每天投入两小时,零基础大概两周就能达到“够用”的水平。有编程基础的人,两三天就能捡起来。
注意:不要花时间去学 Python 的面向对象编程高级特性。Agent 开发中你更多是在写函数和调 API,类继承、多态这些概念等你需要读框架源码的时候再学也不迟。
2.2 第二优先级:理解大模型 API 的基本用法
Agent 的大脑是 LLM,所以你必须知道怎么跟 LLM 打交道。现在主流的方式就是通过 API 调用。不管你是用哪家的模型,基本流程都是一样的:
- 注册账号,拿到 API Key
- 安装对应厂商的 SDK(或者直接用 HTTP 请求)
- 构造请求:把提示词和参数传进去
- 解析响应:拿到模型返回的文本
以 OpenAI 的接口为例,最核心的参数就几个:
model:用哪个模型,比如 gpt-4o、gpt-4o-minimessages:对话历史,是一个列表,每条消息有 role 和 contenttemperature:控制随机性,0 最确定,1 最随机max_tokens:限制返回的最大长度tools:可调用的工具列表(这是 Agent 的关键)
你需要理解messages的结构。它通常包含三种角色:
system:系统提示词,设定 Agent 的身份和行为规则user:用户输入assistant:模型之前的回复
多轮对话就是把历史消息都塞进messages列表里,模型会根据整个上下文来生成回复。这个机制看起来简单,但它是 Agent 记忆功能的基础。
还有一个关键概念是Function Calling(或者叫 Tool Use)。这是 Agent 能干活的核心机制。你可以在请求里定义一组工具,模型在回复的时候如果觉得需要调用某个工具,它不会直接返回文本,而是返回一个“工具调用请求”,告诉你它想调哪个工具、传什么参数。你的代码拿到这个请求后,执行对应的函数,把结果再塞回对话历史,让模型继续处理。
这个循环就是 Agent 的核心循环。手写一遍,你就彻底懂了。
2.3 第三优先级:手写一个最简 Agent,不依赖任何框架
现在到了最关键的一步。我下面给出一段最简 Agent 的伪代码逻辑,你用任何语言都能实现:
# 定义工具 def get_weather(city): # 实际调用天气API return "晴,25度" # 工具描述,告诉模型这个工具是干什么的 tools = [ { "name": "get_weather", "description": "查询指定城市的天气", "parameters": { "city": "城市名称" } } ] # 主循环 messages = [ {"role": "system", "content": "你是一个助手,可以查天气"}, {"role": "user", "content": "北京今天天气怎么样?"} ] while True: # 调模型 response = call_llm(messages, tools) # 如果模型返回的是工具调用 if response.has_tool_call(): tool_name = response.tool_name tool_args = response.tool_args # 执行工具 result = execute_tool(tool_name, tool_args) # 把工具结果塞回对话 messages.append(response.message) messages.append({ "role": "tool", "content": result }) else: # 模型返回了最终文本 print(response.content) break这段代码的核心逻辑就是:调模型 → 看它要不要调工具 → 要就执行工具并把结果喂回去 → 不要就输出结果结束。就这么简单。
你把这个逻辑手写一遍,用真实的 API 跑通,你就已经跨过了 AI Agent 开发的门槛。后面再学 LangChain、LangGraph、Spring AI,你就是在学“怎么把这个循环写得更优雅、更可扩展”,而不是在学“Agent 是什么”。
2.4 第四优先级:再学框架,而且要有选择地学
等你手写跑通了,再来看框架,你的视角就完全不一样了。你看到 LangChain 的AgentExecutor,你会想“哦,这就是把我刚才那个 while 循环封装了一下”。你看到Tool类,你会想“这就是我刚才那个 tools 列表的面向对象版本”。
那框架怎么选?我的建议是:
LangChain / LangGraph:生态最全,文档最多,社区最大。LangGraph 是 LangChain 团队后来推出的,专门做有状态的、多步骤的 Agent 编排。如果你要做复杂的、有分支和循环的 Agent 流程,LangGraph 比原始的 LangChain Agent 更合适。缺点是抽象层多,学习曲线陡。
CrewAI:主打多 Agent 协作。你可以定义多个角色(比如“研究员”、“写手”、“审核员”),让它们互相配合完成任务。适合做内容生产、数据分析这类需要多角色协作的场景。API 设计比较直观,上手快。
AutoGen:微软出的,也是多 Agent 对话框架。特点是 Agent 之间可以自动对话来解决问题。适合做需要多轮讨论和辩论的场景。
Spring AI:Java 生态的选择。如果你本身是 Java 开发者,不想转 Python,Spring AI 提供了跟 LangChain 类似的能力。但说实话,目前 Java 生态在 Agent 开发这块的成熟度还是不如 Python。
Dify:低代码平台,可视化编排 Agent 流程。适合不写代码或者代码能力较弱的产品经理、运营人员快速搭建原型。但灵活性受限,复杂逻辑还是得写代码。
我的建议是:先深入学一个,别贪多。如果你主要做单 Agent 加工具调用的场景,LangChain 就够了。如果你要做多 Agent 协作,看 CrewAI 或 AutoGen。如果你要精细控制 Agent 的状态流转,看 LangGraph。
2.5 关于 MCP:它解决的是什么问题
MCP 最近热度很高,但很多人搞不清楚它到底是什么。我用一句话解释:MCP 是一个让 Agent 跟外部工具对接的标准协议。
在没有 MCP 之前,你每接一个工具,都要自己写适配代码。比如你要让 Agent 能查数据库,你得写一个函数,定义参数,处理返回结果。你要让它能操作文件系统,又得写一套。每个工具的接入方式都不一样,复用性很差。
MCP 的思路是:定义一套标准接口,工具提供方按照这个标准来实现,Agent 这边也按照这个标准来调用。这样工具就能即插即用。你可以把它类比成 USB 接口——以前每个设备都有自己的接口,现在统一成 USB,插上就能用。
MCP 的核心概念包括:
- MCP Server:工具提供方,暴露一组能力(比如读文件、查数据库、调 API)
- MCP Client:Agent 这边,负责连接 Server 并调用能力
- Resources:Server 暴露的数据资源
- Tools:Server 暴露的可执行操作
- Prompts:预定义的提示词模板
现在很多工具已经开始支持 MCP 了,比如 Playwright MCP 可以让 Agent 操作浏览器,百度地图 MCP 可以让 Agent 查地理位置。如果你要做的 Agent 需要跟大量外部工具对接,花点时间了解 MCP 是值得的。但如果你只是做一个小 demo,手写几个工具函数就够了,不用急着上 MCP。
3. 实操:从零手写一个能查天气和算数的 Agent
3.1 环境准备:Python 安装和虚拟环境
先说 Python 安装。Windows 用户去 python.org 下载安装包,安装的时候记得勾选“Add Python to PATH”。Mac 用户可以用 Homebrew 装:brew install python。Linux 用户一般系统自带,但版本可能比较老,建议用 pyenv 装一个新版本。
装完之后验证一下:
python --version pip --version然后建一个虚拟环境,这是好习惯,避免不同项目的依赖打架:
python -m venv agent-env # Windows agent-env\Scripts\activate # Mac/Linux source agent-env/bin/activate虚拟环境激活后,命令行前面会出现(agent-env)的标识。接下来装依赖:
pip install openai requests如果你用的是其他厂商的模型,把openai换成对应的 SDK 就行。
3.2 定义工具函数:查天气和做计算
我们定义两个工具:一个查天气,一个做数学计算。查天气我们用一个模拟函数,实际项目中你可以接真实 API。
import json import math def get_weather(city: str) -> str: """模拟查天气,实际项目中替换为真实API调用""" weather_data = { "北京": "晴,气温25度,湿度40%", "上海": "多云,气温28度,湿度65%", "广州": "雷阵雨,气温30度,湿度80%", } return weather_data.get(city, f"未找到{city}的天气数据") def calculate(expression: str) -> str: """计算数学表达式""" try: # 只允许基本数学运算,避免安全问题 allowed = set("0123456789+-*/.() ") if not all(c in allowed for c in expression): return "表达式包含不允许的字符" result = eval(expression) return str(result) except Exception as e: return f"计算错误:{str(e)}"注意calculate函数里我做了字符白名单校验。直接用eval是有安全风险的,虽然这只是个 demo,但养成好习惯很重要。
3.3 构造工具描述:让模型知道有什么工具可用
工具描述是 Agent 能不能正确选用工具的关键。描述要清晰、准确、包含参数说明。
tools = [ { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市的当前天气情况", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名称,例如:北京、上海" } }, "required": ["city"] } } }, { "type": "function", "function": { "name": "calculate", "description": "计算数学表达式,支持加减乘除和括号", "parameters": { "type": "object", "properties": { "expression": { "type": "string", "description": "数学表达式,例如:(3+5)*2" } }, "required": ["expression"] } } } ]工具描述有几个经验:第一,description 要写清楚这个工具是干什么的,什么时候该用。比如“查询指定城市的当前天气情况”就比“查天气”好。第二,参数的 description 要给出示例。模型看到示例更容易传对参数。第三,required 要准确。必填参数没标 required,模型可能不传。
3.4 主循环实现:调模型、执行工具、喂回结果
from openai import OpenAI client = OpenAI(api_key="你的API_KEY") def run_agent(user_input: str): messages = [ {"role": "system", "content": "你是一个助手,可以查天气和做数学计算。需要时调用工具。"}, {"role": "user", "content": user_input} ] max_iterations = 10 # 防止无限循环 for i in range(max_iterations): response = client.chat.completions.create( model="gpt-4o-mini", messages=messages, tools=tools, tool_choice="auto" ) msg = response.choices[0].message # 没有工具调用,直接返回文本 if not msg.tool_calls: return msg.content # 有工具调用,把 assistant 消息加入历史 messages.append(msg) # 逐个执行工具 for tool_call in msg.tool_calls: func_name = tool_call.function.name func_args = json.loads(tool_call.function.arguments) if func_name == "get_weather": result = get_weather(func_args["city"]) elif func_name == "calculate": result = calculate(func_args["expression"]) else: result = f"未知工具:{func_name}" # 把工具结果加入历史 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result }) return "达到最大迭代次数,任务未完成"这段代码就是 Agent 的核心。max_iterations是必须的,防止模型陷入死循环一直调工具。tool_call_id也很关键,模型靠这个 ID 来匹配哪个结果对应哪个工具调用。
3.5 跑起来看看效果
# 测试 print(run_agent("北京今天天气怎么样?")) print(run_agent("帮我算一下 (15 + 27) * 3 等于多少")) print(run_agent("上海和广州的天气分别怎么样?然后算一下两个城市温度的平均值"))第三个测试用例比较有意思,它需要 Agent 先调两次天气工具,拿到结果后再调计算工具。这就是多步推理和工具编排。如果你的 Agent 能正确处理这个 case,说明基本逻辑没问题了。
实操心得:调试 Agent 的时候,把每一步的
messages打印出来看。你会清楚地看到模型什么时候决定调工具、传了什么参数、拿到结果后怎么继续推理。这个习惯能帮你快速定位问题。
4. 常见问题与排查技巧实录
4.1 模型不调工具怎么办
这是最常见的问题。你明明定义了工具,用户的问题也明显需要工具,但模型就是直接返回文本,不调工具。
原因通常有三个:
第一,工具描述不够清晰。模型不知道这个工具是干什么的,自然就不会用。解决办法是把 description 写得更具体,明确说明“什么时候应该使用这个工具”。
第二,系统提示词没有引导。在 system message 里加一句“当需要查询实时信息或进行计算时,请调用相应的工具”,能显著提高工具调用率。
第三,模型能力不够。一些小模型或者老模型对 Function Calling 的支持不好。换个更强的模型试试。
还有一个技巧是设置tool_choice="required",强制模型必须调用工具。但这只适合你确定每次都需要调工具的场景,一般还是用"auto"。
4.2 工具参数传错怎么排查
模型传错参数也很常见。比如该传城市名,它传了个省份名;该传数字,它传了个字符串。
排查方法:在json.loads(tool_call.function.arguments)之后打印一下参数,看看模型到底传了什么。如果参数格式不对,在工具定义的 parameters 里把类型和描述写得更严格。比如"type": "string"加上"enum": ["北京", "上海", "广州"]限定取值范围。
另外,在工具函数内部做参数校验也很重要。不要假设模型传的参数一定是对的,该做的校验都要做。
4.3 Agent 陷入死循环怎么处理
死循环的表现是:Agent 反复调同一个工具,或者在不同工具之间来回跳,就是不输出最终结果。
原因通常是:工具返回的结果模型不满意,或者模型不知道下一步该干什么。
解决办法:第一,设置最大迭代次数。我上面代码里的max_iterations就是干这个的。第二,在工具返回结果里加入引导信息。比如查不到天气的时候,返回“未找到该城市数据,请尝试其他城市或告知用户无法查询”,而不是简单返回一个空字符串。第三,在系统提示词里明确“如果工具无法提供有效信息,请直接告知用户”。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 模型不调工具 | 描述不清/提示词没引导/模型能力不足 | 检查工具 description 和 system prompt | 完善描述、加引导语、换模型 |
| 参数传错 | 参数定义不明确/模型理解偏差 | 打印实际传入参数 | 加 enum 限定、加参数校验 |
| 死循环 | 工具结果不满足/无终止条件 | 打印每轮 messages | 设最大迭代、优化工具返回值 |
| 返回结果不符合预期 | 提示词不够具体 | 检查 system prompt | 细化角色设定和输出格式要求 |
| API 调用报错 | Key 无效/额度用完/网络问题 | 看错误码和错误信息 | 检查 Key、充值、重试 |
| 响应太慢 | 模型本身慢/工具执行慢 | 分别计时 | 换更快的模型、优化工具逻辑 |
4.5 几个我踩过的坑
坑一:工具函数抛异常导致整个 Agent 崩溃。工具函数一定要用 try-except 包起来,返回错误信息而不是抛异常。模型拿到错误信息后通常会自己调整策略。
坑二:对话历史太长导致 token 超限。多轮对话后,messages 列表会越来越长。解决办法是定期截断历史,只保留最近 N 轮,或者用摘要的方式压缩历史。
坑三:工具描述里写了太多技术细节。工具描述是给模型看的,不是给开发者看的。用自然语言写清楚“这个工具做什么、什么时候用、参数是什么”就够了,不要写实现细节。
坑四:忽略了 tool_call_id 的匹配。多个工具调用时,每个 tool_call 有自己的 id,返回结果时必须带上对应的 id。不匹配的话模型会混乱。
5. 学完基础之后往哪走
5.1 下一步:给 Agent 加上记忆
你现在写的 Agent 每次对话都是独立的,没有记忆。用户说“北京天气怎么样”,Agent 查完告诉你。然后用户说“那上海呢”,Agent 不知道“那”指的是天气,因为它不记得上一轮对话。
加记忆最简单的方式就是把历史消息都保留在 messages 列表里。但这样 token 消耗会越来越大。更好的做法是用向量数据库做长期记忆:把历史对话存进向量库,每次新对话时检索最相关的几条历史记录塞进上下文。
LangChain 提供了ConversationBufferMemory、ConversationSummaryMemory等现成的记忆组件,但建议你先手写一个最简单的版本,理解原理后再用框架的。
5.2 再下一步:多 Agent 协作
单个 Agent 能做的事情有限。当你需要完成一个复杂任务时,可以拆成多个 Agent 各司其职。比如做一个“市场调研报告生成”系统:
- 研究员 Agent:负责搜索和收集信息
- 分析师 Agent:负责分析数据、提炼观点
- 写手 Agent:负责撰写报告
- 审核员 Agent:负责检查事实和逻辑
每个 Agent 有自己的系统提示词和工具集,它们之间通过消息传递来协作。CrewAI 和 AutoGen 就是专门做这个的框架。
但我要提醒一句:多 Agent 系统的复杂度是指数级上升的。两个 Agent 协作还好,五个 Agent 协作的时候,调试会变得非常困难。建议先把单 Agent 玩透,再考虑多 Agent。
5.3 关于框架学习的最终建议
回到标题那句话:别一上来就啃框架。我见过太多人,LangChain 的文档翻了一遍,各种概念背得滚瓜烂熟,但让他从零写一个 Agent 循环,写不出来。这就是本末倒置了。
正确的学习路径是:
- Python 基础(两周)
- 大模型 API 基本用法(三天)
- 手写最简 Agent 循环(一天)
- 手写带记忆和多工具的 Agent(三天)
- 选一个框架深入学习(一周)
- 用框架重构你之前手写的 Agent(两天)
这个路径走下来,大概一个月左右,你就能独立开发一个可用的 AI Agent 了。比上来就啃框架快得多,也扎实得多。
框架是工具,不是知识。工具会过时,LangChain 可能明年就被别的框架取代了,但 Agent 的核心原理——LLM 决策、工具调用、循环执行——这些是不会变的。把原理吃透,换什么框架你都能快速上手。
我在实际带新人的过程中发现,那些先手写再学框架的人,遇到问题时的排查能力强很多。因为他们知道底层发生了什么,框架报错的时候能判断是框架的问题还是自己代码的问题。而直接学框架的人,遇到报错往往一脸懵,只能去社区提问等回答。
最后分享一个小技巧:每次学一个新框架的时候,先别急着看它的文档,先自己想“如果让我设计这个框架,我会怎么设计”,然后再去看它的 API。这样你学起来会快很多,因为你是在验证自己的想法,而不是被动接受信息。