身边一个做运维的朋友A同学,年初决定转行做AI应用开发。他的第一步和大部分人一样:收集了各个Agent编排框架的官方文档、翻译版电子书、付费视频课,笔记记了两大本,还跟着教程敲了好几个Demo。结果呢?学了一个多月,面对一个简单的报错依然毫无头绪——不知道为什么上下文超限,不知道为什么工具调用结果没被模型读到,更不知道日志里那一串调用栈在说什么。A同学的困惑很有代表性,因为“AI Agent入门”这件事,很多人一开始就走反了方向。
这篇内容就是写给A同学这样的人:刚接触AI Agent的新人、想从其他岗位转过来的开发者。我会直接告诉你,AI Agent入门阶段最应该先学的是什么,为什么不要一上来就啃框架,以及如何在一个月左右建立起真正能用的底层认知。核心观点就一句话:框架是给会用的人提高效率的工具,不是给新手当教材用的。
1. 先搞清楚一件事:框架是工具,不是知识本体
1.1 大多数新手的“框架焦虑”从哪里来
打开技术社区,满屏都是“基于某某框架搭建智能助手”“用某某框架十分钟做出一个Agent”,再一看招聘需求,也几乎都写着要熟悉各类Agent开发框架。这种环境下,新人很容易产生一种错觉:不会框架就等于不会Agent开发,学得越早,转行越快。
但事实恰恰相反。我见过太多人把框架文档当教科书从头到尾翻,结果学会的是“怎么调用某个框架的API”,而不是“Agent是怎么工作的”。一旦框架升级改版,或者公司里换了一套技术栈,之前学的百分之七八十都要作废。更麻烦的是,框架把最关键的底层逻辑都封装好了,你根本看不到模型和工具之间是如何配合的,一旦出问题,排查起来就像医生只会看化验单却不懂人体结构。
1.2 框架替你做了什么,你就少了什么
市面上主流的Agent编排框架,说白了做的事情无非这五类:
- 封装大语言模型API的调用:请求、重试、流式输出、超时处理。
- 管理对话状态:把多轮消息按会话存储、读取、清理。
- 注册和调度工具:让你写一个Python函数,然后告诉模型“有这个工具可用”。
- 执行Agent主循环:判断模型要不要调工具、调完之后把结果喂回去、再让模型继续生成。
- 提供记忆方案:对接向量检索、摘要压缩等。
这些功能,对一个已经理解原理的开发者来说,是省时省力的脚手架。但对一个新手来说,它们就是一层厚厚的帘子——你把帘子掀开之前,根本不知道幕后发生了什么。
我打个比方:框架像一台自动挡汽车,它确实让驾驶变简单了,但你连油门刹车离合的关系都没搞明白就坐进驾驶座,仪表盘亮一个故障灯你就傻眼。反过来,如果你先开一阵手动挡,把换挡的逻辑刻进肌肉记忆,回头再开自动挡,几乎不需要学。AI Agent入门的正确顺序,恰恰应该是先用最笨的方式手写一遍Agent的核心循环,再去看框架怎么帮你省事。
所以,第一阶段真正要学的不是某个框架,而是大语言模型API本身怎么用、提示词怎么组织、工具调用机制是怎么回事、记忆和上下文怎么管理。这些东西,换任何框架都跑不掉。
2. 第一课不是写代码,是学会“把需求说清楚”
2.1 模型是不懂潜台词的实习生
很多人第一次调用大模型API,只写一句“帮我查天气”,然后抱怨模型答非所问。问题不在模型,而在你给的信息太少。大语言模型本质上是一个读完海量文本、学会文字接龙的系统,它并不天然知道你到底要什么格式的回答、要什么粒度的信息、要什么风格。它像一个特别聪明但完全没有行业常识的实习生,你交代任务时少说一个前提,它就自由发挥。
这也是AI Agent开发者和普通用户最大的区别:普通用户可以用聊天式的方式和模型互动,但Agent开发者必须把需求“结构化”地表达出来。一个标准的提示词,至少要包含三件事:
- 角色:你是谁?你是一个生活助手/数据分析师/客服……
- 任务:你具体要做什么?查天气、写摘要、还是从文本中抽取信息?
- 约束:输出格式是什么?长度多少?不能出现什么?
举个例子,新手可能会写:“杭州天气怎么样?”模型可能回一大段散文,也可能教你带伞,信息是散的。但如果你这样写:
你是我的生活助手。查询杭州今天的天气,并回答两个问题: 1. 现在的气温是多少? 2. 相比昨天是变热还是变冷? 要求:用两句话以内回答,不要输出多余内容。模型答非所问的概率立刻小一半。Agent项目里,这种“把需求说清楚”的能力,直接影响后续所有环节——因为模型判断要不要调用工具,靠的也是你对工具描述的清晰程度。
2.2 结构化输出:让模型讲“机器听得懂的话”
聊天式输出最大的问题是:结果不稳定。同一句话,这次输出“26摄氏度”,下次可能变成“气温26度,体感舒适,微风”。对人类来说都能看懂,但程序不好解析。
Agent场景里,代码必须按固定字段去读模型的结果。所以入门第二天就应该学会一件事:**让模型输出JSON,而不是散文。**做法很简单,在提示词里写清楚目标数据结构,最好再给一个例子。
请从用户输入中提取以下字段,以JSON格式输出: { "city": "城市名称", "intent": "用户意图,取值只能是weather/reminder/other", "keywords": "关键词列表" } 示例输出:{"city": "杭州", "intent": "weather", "keywords": ["天气", "杭州"]}如果模型API支持结构化输出参数,最好连这个参数也打开。这一步不学,后面做工具调用几乎寸步难行,因为函数调用的参数本质上就是一种强约束的结构化输出。
2.3 上下文窗口:你给多少信息,决定它干多少活
上下文窗口,可以简单理解成模型在回答问题时“眼前能看到的文字总量”。Token是它的计量单位,一个Token大致相当于半个到四分之三个汉字。窗口越大,模型能参考的内容越多,但代价也很直接:更慢、更贵、注意力更容易被稀释。
我见过很多新手犯的错:把整个对话历史从第一句开始全部塞给模型,每轮都越积越长,直到某天窗口爆掉,或者模型速度肉眼可见地变慢。这里有一个很朴素的指导思想——最小上下文原则:只给模型完成当前这一步任务所需的信息。
比如做客服问答,历史消息里有200条,但用户当前问题只需要最近3轮上下文,那就截取最近3轮;如果你还想让模型知道用户身份,把用户画像摘要拼进去就够了。做Agent开发时,上下文管理是一项核心技能,因为工具调用的中间结果、模型的思考过程、历史对话,全都在跟你抢窗口空间。这个道理懂了,后面看框架里的各种记忆组件,你一眼就能看明白它们到底在解决什么问题。
3. Agent的四个骨架零件,缺一个都不是Agent
很多人对“Agent”的理解停留在“能聊天、会写文案”的层面,这也导致他们看框架文档时,目光全落在炫酷的Demo上,却忽略了Agent真正区别于普通聊天机器人的地方:它是能自己决定调用什么工具、按什么顺序完成任务、并且能记忆和规划的系统。
拆开来看,一个再复杂的Agent也离不开四个零件:模型、工具调用、记忆、规划。入门阶段的重点,是先认识工具调用和记忆,规划可以往后放一点。
3.1 工具调用:模型不会动手,但它会摇人
一个关键认知:大模型本身不会执行任何操作,它只会生成文本。所谓“工具调用”,其实是模型在输出里生成一段特殊指令,告诉宿主程序:“我需要调用某个工具,参数是什么。”宿主程序收到指令后,自己去执行真正的代码,再把结果作为一条新消息塞回给模型。
这个过程可以用一个类比来理解:模型像一个项目经理,它不会自己搬砖、不会自己查数据库,但它知道什么时候该叫电工、什么时候该叫水管工。它开会时说“现在联系施工队,进场时间定在明天上午9点”,这句话就是一次工具调用。真正给施工队打电话的,是旁边的助理——也就是你的宿主程序。
所以工具调用里最值得研究的是两件事:一是工具描述怎么写,二是工具返回结果怎么处理。工具描述写得好,模型才能准确判断“什么时候该调用这个工具、参数怎么填”;工具结果处理得好,模型才能基于真实数据继续回答,而不是自己编。
3.2 记忆:短期工作记忆和长期档案
对话场景里的记忆,拆开就是两块。短期记忆是当前会话的上下文,也就是我们前面说的消息队列;长期记忆是把重要信息存到外部系统,比如文件、数据库、或者向量检索。短期记忆相当于一个人脑子里正在想着的事,长期记忆相当于记在笔记本里的档案。
入门阶段,先把短期记忆玩明白就足够了:你会越来越熟练地管理消息列表,知道什么时候该把历史截断,什么时候该把工具结果追加进去。至于长期记忆和向量检索,我建议把它放到第二个月再研究。原因是向量检索涉及文本嵌入、相似度计算、召回质量评估,这是一个独立且不浅的领域,上来就搞,容易把Agent开发和向量数据库两件事混在一起,哪个都没学透。
3.3 规划:把大任务拆成小步骤
规划能力听起来很高级,但最朴素的实现方式就是循环:让模型看完当前状态,决定下一步做什么;执行完,再让它看结果,决定再做什么。经典的模式叫“思考-行动-观察”循环,翻译成大白话就是:模型先想一步,然后调一个工具,看看返回结果,再想下一步。
新手往往把这个想得太玄学,总觉得规划必须用什么复杂的算法、专门的推理框架。其实你手写一个while循环就能实现最基础的规划:只要模型连续几次判断“任务还没完成,我还得继续调用工具”,循环就一直往下走。等你能跑通这个循环,再回来看框架里的各种规划组件,就只是一层更精细的调度罢了。
3.4 一个类比:Agent像外包团队的项目经理
把四个零件串起来,最贴切的比喻就是“外包团队的项目经理”。你(用户)向项目经理(模型)提需求;项目经理手头有一份团队成员通讯录(工具列表),它知道谁负责什么、该怎么联系;接到需求后,它开始规划:先问设计部要方案,再让开发部评估成本,最后汇总成一份报告交给你。整个过程中,项目文档(记忆)一直被更新,项目经理每一步的决定都基于当前掌握的信息。
这个比喻能帮你理清很多模糊概念:比如为什么工具描述要写得像“团队成员的技能标签”?因为项目经理只能通过这些标签决定该叫谁。为什么上下文窗口很宝贵?因为项目经理的桌面就那么大,文件摊太多,关键材料反而找不到了。
4. 不装任何框架,手写一个“能查天气”的最小Agent
4.1 场景定义:一个能查天气并回答的助手
说了这么多理论,现在动手做一个不需要任何框架、只用Python标准库加一个HTTP请求库就能跑通的最小Agent。目标很朴素:用户问“杭州今天天气怎么样,适合穿什么?”Agent先调用天气工具拿到真实数据,再基于数据生成穿衣建议。
你可能会问,不就查个天气吗,直接写个函数然后手动调用不就行了?关键是这里多了一个“模型自主决策”的环节——**不是你在代码里显式指定调用get_weather,而是模型阅读用户问题后自己决定“该调用天气工具了”。**这一步到位,Agent和普通函数的区别就出来了。
4.2 从API裸调开始:模型本身不会调用工具
先把大模型API调用封装成一个函数,注意这里的地址和密钥都是模拟值,实际使用时替换成你自己对接的模型服务即可:
import json import requests def call_llm(messages, tools=None): """极简的大模型API封装,仅用于演示""" url = "https://api.llm-example.dev/v1/chat/completions" headers = { "Authorization": "Bearer sk-demo-key", "Content-Type": "application/json", } payload = { "model": "demo-chat", "messages": messages, "tools": tools or [], "tool_choice": "auto", "temperature": 0.2, } resp = requests.post(url, json=payload, headers=headers, timeout=30) resp.raise_for_status() return resp.json()这里有个容易被忽略的点:tools参数是在每次请求的时候都传给模型的。模型并不会“记住”你有这个工具,它每次判断时都要靠你在请求里把工具描述完整地带给它。这也是后续上下文变大的原因之一,做好心理准备。
再写一个模拟的天气查询函数,真实项目里改成对服务商API的请求就行:
def get_weather(city: str) -> str: """模拟天气查询,实际项目替换为真实服务""" if city == "杭州": return json.dumps( {"city": "杭州", "temp": 22, "weather": "多云"}, ensure_ascii=False, ) return json.dumps( {"city": city, "temp": 20, "weather": "晴"}, ensure_ascii=False, )4.3 主循环:决策、执行、回答
现在写Agent的核心循环。先定义工具清单,这个清单会随每次请求一起发给模型,模型根据它决定要不要调用工具:
TOOLS = [ { "type": "function", "function": { "name": "get_weather", "description": "查询某个城市的当前天气和气温,返回JSON字符串", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市中文名称,例如:杭州", } }, "required": ["city"], }, }, } ]注意工具描述里的这句话:“查询某个城市的当前天气和气温”。模型不知道你的函数内部逻辑,它只能靠这句话来猜“什么时候该调用、参数该怎么填”。所以描述写得越清楚,模型瞎调用的概率越低。
然后是Agent主循环。逻辑分成两步:第一次调用模型,看看它有没有在返回里带tool_calls字段;如果有,就执行对应的工具函数,把结果追加到对话里,再调用一次模型,让模型基于结果生成最终回答。
def agent_loop(user_input: str) -> str: messages = [ { "role": "system", "content": "你是一个生活助手。需要天气信息时,调用get_weather获取数据,再基于数据回答。回答控制在两句话以内。", }, {"role": "user", "content": user_input}, ] # 第一次调用:让模型决定是否调用工具 first_resp = call_llm(messages, TOOLS) first_msg = first_resp["choices"][0]["message"] messages.append(first_msg) # 如果模型产生了工具调用请求,就执行它 if first_msg.get("tool_calls"): for tool_call in first_msg["tool_calls"]: args = json.loads(tool_call["function"]["arguments"]) result = get_weather(args["city"]) messages.append( { "role": "tool", "tool_call_id": tool_call["id"], "content": result, } ) # 第二次调用:让模型基于工具结果生成回答 second_resp = call_llm(messages, TOOLS) return second_resp["choices"][0]["message"]["content"] return first_msg["content"]如果一切正常,运行agent_loop("杭州今天天气怎么样,适合穿什么?"),会得到类似“杭州今天22度,多云。建议穿长袖或薄外套,早晚可以加一件。”的输出。
4.4 这个Demo告诉你三件事
第一,Agent的本质不是什么神秘机制,就是一个循环:模型决策,宿主程序执行,结果回灌,模型再决策。你把这个循环写熟,后面学任何框架都会觉得“原来是这么一回事”。
第二,工具执行永远发生在宿主进程,不在模型内部。模型能做的只是“提出调用请求”,真正干活的函数是你的代码。理解这一点,你就不会再问“模型怎么自己调用数据库”这种问题。
第三,tool_call_id必须正确回传。把工具结果追加进messages时,每条结果都要关联到对应的工具调用ID。如果漏了这个ID,很多模型会直接报错或忽略工具结果。这也是新手第一次手写时最容易踩的坑。
我自己当时写完这个Demo,最大的感受是:以前看框架文档里的“AgentExecutor”“ToolNode”这些概念,每个字都认识,但不知道在干什么。手写完这个循环之后再看,一下就通透了。这就是静态看文档和亲手跑流程的差距。
5. 什么时候才应该碰框架,以及怎么挑
5.1 重复劳动超过三次,再考虑框架
手写了最小Agent之后,你会有一种“代码掌控感”:每一行都知道为什么存在。但继续做下去,很快会遇到重复劳动:每次都要写消息拼接、循环控制、超时重试、历史截断……这时候再考虑引入框架,才是正确的时机。
我建议给自己设一个信号:如果同一个功能你手写了三次以上,或者你开始要对多个工具做并发的调度管理,那就可以打开框架文档了。因为框架能帮你把繁琐部分抽象掉,让你集中精力写业务。而在那之前,手写永远是更好的学习方式——学习阶段追求快,反而学不到东西。
5.2 选框架的标准:不是看谁火,是看抽象层合不合你的场景
市面上的Agent编排框架各有各的抽象方式。有的偏重图形化编排,适合产品快速验证;有的偏重代码配置,适合工程团队深度定制;还有的极端贴近底层API,几乎就是帮你去掉了重复代码,把控制权完全交给你。
选择标准其实特别朴素:**打开快速开始文档,看它让你写的第一个Hello World是什么。**如果我在三步之内就理解了“用户请求进来之后,Agent是怎么被创建的、模型是怎么被调用的、工具是怎么被注册的”,那这个框架的设计对我来说就是透明的。反之,如果文档前两页全是概念名词,干了半天也看不到一个能跑通的例子,那它对新手来说就是黑盒,再火也先别用。
5.3 一个被很多人忽略的问题:可观测性
Agent项目最大的调试难题是:你很难知道模型“为什么这么回答”。它可能基于错误的工具结果乱编了一个答案,也可能因为上下文里混入了无关信息而跑偏。这时候框架的日志、追踪、中间状态输出能力,比任何花哨功能都重要。
我见过有人在框架里搭了一个看起来很复杂的Agent,一问“如果用户问的问题不在你定义的规划流程里会怎样”,答不上来。原因就是框架把他所有的中间步骤都吞掉了,他只能看到最终输出,完全无法定位。所以选框架时,先看看它能不能把“模型输入、工具调用参数、工具结果、模型最终输出”这四个阶段的日志打出来。能,就是好框架;不能,后期有你受的。
5.4 自己写轮子的边界在哪
强调别一上来就啃框架,不代表要永远拒绝框架,也不代表所有东西都要手写。我个人的平衡法则是这样:把核心的Agent循环保留在自己手里——模型调用、工具决策、结果回灌这三步,我的代码里必须看得见、改得动。至于记忆压缩、向量检索、流式输出、队列调度,这些外围能力,框架怎么方便怎么来。
这个边界的意思很简单:**一个随时可以拆开重新组装的东西,不怕出错。**如果哪天框架升级导致行为变了,你至少知道自己的核心逻辑在哪,不至于把整个项目推倒重来。
6. 一个月的学习路线,附老手才会提的避坑清单
6.1 分阶段路线规划
目标是让一个没有任何大模型开发经验的普通开发者,在一个月内具备独立搭建简单Agent应用的能力。路线按周划分,不用贪多,每周完成一个里程碑就够了。
第一周的任务是纯粹打地基:注册并配置任意一个大模型API服务,学会用代码发起一次对话请求;调整temperature、max_tokens等参数,观察输出的变化;练习写结构化输出提示词,让模型稳定输出JSON。这个阶段的验收标准是:能不看文档,凭记忆写出一段把用户输入转成JSON的API调用代码。
第二周进入Agent核心:手写一遍上面那个天气查询的最小Agent;把工具数量扩展到两到三个,比如加一个“查询城市景点”的工具,让模型自主决定先查天气还是先查景点;在循环里加一个错误处理逻辑,比如工具调用参数缺失时让模型重新生成参数。这个阶段的验收标准是:你能对着自己的代码,讲清楚每一轮循环里消息列表的内容变化。
第三周学习记忆和上下文管理:给Agent加上“最近5轮对话截断”策略;尝试把早期对话做成摘要存入系统提示词;如果还有余力,了解文本嵌入和向量检索的基本概念。这个阶段不要求你自己实现向量库,但要知道它解决的“长期记忆”问题大概是什么链路。
第四周挑战框架:选一个自己感兴趣但适合新手的框架,跑通官方快速开始;把你手写的天气Agent用框架重写一遍,做一份对比笔记:哪些代码被框架接管了,哪些逻辑必须自己写。这周结束,你已经不是“啃框架”的新手,而是“评估框架”的开发者了。
6.2 新手最容易踩的几个细节坑
下面这几个问题是带过的人几乎都会遇到的,提前知道能省很多时间。
一是temperature参数没调好。工具调用场景建议设低一点,0.2左右,让模型输出更稳定。如果设成0.8甚至更高,模型会变得“有创造力”,工具参数格式错误、意外输出散文的情况会明显增多。入门阶段,先追求可控,再追求灵活。
二是工具描述里的参数含义没写清楚。模型是通过描述来理解“这个参数该填什么”的,你写“city: 城市名称”和写“city: 城市中文名称,不带省份后缀,例如杭州、上海”效果完全不同。描述越具体,模型填错参数的概率越低。这不是玄学,是每次请求时模型真的在靠这些文字做决策。
三是上下文里塞了太多无关历史。新手容易把用户三个月前的闲聊记录一直留着,结果导致模型判断工具调用时被干扰。定期截断、定期把旧对话压缩成摘要,是Agent开发中最常见也最实用的优化手段。
四是JSON解析失败时不处理。模型偶尔会输出不合法JSON,前后有额外文字、逗号放错位置,都可能让json.loads崩溃。写代码时务必对解析失败做好兜底,比如让模型重新输出一次,或者从文本里用正则把JSON片段先抠出来。这个处理能直接决定你的Agent是“稳定服务”还是“偶尔罢工”。
五是外部工具调用必须设超时。你的天气API、数据库、搜索引擎,任何一个挂了都可能彻底拖垮Agent主循环。所有真实的外部请求,都要加超时和重试策略,同时把这个错误信息作为工具结果回传给模型,让它决定下一步怎么办——这本身就是Agent“自主决策”的一部分。
6.3 最后的个人体会
从我自己带新人的经验来看,“AI Agent入门”这件事,卡住十个人里七个人的,从来不是技术难,而是学错顺序。框架文档背得再多,代码敲得再快,如果不知道模型怎么决策、工具怎么被调用、上下文怎么管理,项目一复杂,心里必然发虚。
而我见过学得最快的路线,几乎都是从这个朴素顺序开始的:先学会和模型对话,再手写一个最简单的Agent循环,理解四个骨架零件,最后才回头看框架。等你亲手把那几十行代码跑通,再打开框架文档,你会发现那些曾经像天书一样的术语,不过是这个循环的工程化包装而已。放心,你的手写Demo会写的比任何框架都简单,但它是你的,你懂它,它也懂你——这才是转行的第一块真正意义上的地基。