
1. 为什么我不建议新手一上来就啃框架1.1 框架是“果”不是“因”我带过不少想转行做 AI Agent 的朋友十个里面有八个第一句话就是“我该学 LangChain 还是 AutoGen还是直接上 CrewAI”每次听到这个问题我就知道这人大概率要走一段弯路了。不是说这些框架不好它们都是非常优秀的工程产物。问题在于框架是对底层能力的封装而不是底层能力本身。你连大模型怎么调用、上下文怎么管理、工具怎么描述都还没搞明白直接跳进框架里就像还没学会走路就去研究跑鞋的碳板角度——不是说不行而是你根本感受不到那些设计决策背后的取舍。我见过太多人跟着教程跑通了一个“多智能体协作写文章”的 Demo兴奋得不行觉得自己入门了。结果一换需求比如要让 Agent 去查数据库、要处理多轮工具调用失败、要控制 token 成本立马就懵了。因为他们学的是“怎么用这个框架”而不是“Agent 到底是怎么运转的”。所以我的核心观点很明确先建立对 AI Agent 最小可用闭环的直觉再去挑框架。这个闭环包括四件事——模型调用、提示词组织、工具调用、循环控制。这四件事你用手写代码跑通一遍哪怕代码很丑你对 Agent 的理解也会比跑十个框架 Demo 要扎实得多。1.2 新手和转行者的真实痛点在哪转行者的痛点其实很集中。第一是概念迷雾市面上名词太多Agent、RAG、Function Calling、MCP、Workflow每个词都好像懂一点但连起来就不知道谁是谁。第二是路径焦虑不知道先学哪个后学哪个怕学错了浪费时间。第三是动手恐惧看别人代码觉得能看懂自己一写就卡在环境配置和 API 报错上。而新手比如刚入门的在校同学的痛点又不太一样他们往往编程基础还在建立中对异步、HTTP 请求、JSON 处理这些工程概念不熟直接上框架会被大量“与 Agent 无关的工程细节”淹没最后误以为自己不适合做这个方向。这两类人其实有一个共同的解法把学习路径切成两层第一层只碰“裸模型 手写循环”第二层再引入框架。第一层的目标是建立心智模型第二层的目标是提升工程效率。顺序反了效率极低。1.3 一个判断标准你能不能不用框架说清楚 Agent 的运转我给你一个很实用的自测标准。如果你能用大白话不用任何框架名词把下面这个问题讲清楚你就具备学框架的基础了用户问了一个需要查天气再决定穿什么衣服的问题你的程序从收到问题到给出答案中间经历了哪几步每一步的输入输出分别是什么能讲清楚的人说明他脑子里有“模型输出 → 解析 → 执行工具 → 把结果塞回上下文 → 再问模型”这个循环。讲不清楚的人去学框架只会是背 API。这个标准我自己用了很多年也用它来判断一个转行者是不是真的“入门”了。框架会变LangChain 的 API 一年改好几版但这个循环的本质不会变。2. 先搞懂 AI Agent 的最小构成2.1 剥掉所有包装Agent 就是“模型 循环 工具”我们把 Agent 这个词拆到最干净。一个最原始的 Agent本质上就是三样东西的组合一个语言模型负责理解、推理、生成决策一个循环负责反复调用模型直到任务完成一组工具负责让模型能对外部世界产生动作或获取信息就这么简单。所谓“智能体”智能来自模型体来自循环和工具。没有循环那就是一次普通的模型调用没有工具那模型只能空谈没法查数据、没法写文件、没法调接口。我经常用一个类比模型是大脑工具是手脚循环是“想一步做一步再想一步”的思考节奏。你光有大脑那叫聊天光有手脚没大脑那叫脚本只有三者凑齐才叫 Agent。理解这一点之后你会发现很多框架宣传的“高级特性”其实都是在这三样东西上做优化——更好的循环控制、更丰富的工具生态、更省 token 的上下文管理。你先把原始版本跑通再看这些优化就能看懂它们在解决什么问题。2.2 模型调用你要理解的第一件事模型调用是所有一切的起点。新手最容易犯的错是把模型当成一个“输入问题输出答案”的黑盒。实际上你要关注的是它的输入结构和输出结构。输入侧现在主流的对话模型都是“消息列表”结构每条消息有角色system、user、assistant和内容。system 消息用来设定人设和规则user 是用户输入assistant 是模型之前的回复。这个结构决定了你怎么把历史对话、工具结果塞回给模型。输出侧关键是要理解模型可以输出“结构化的意图”而不只是自然语言。比如它可以输出一段 JSON告诉你“我要调用 get_weather 这个工具参数是 city北京”。这就是后面工具调用的基础。我建议新手第一件事就是手写一段代码把 system、user、assistant 三种消息拼成一个列表发给模型看看返回什么。然后再手动构造一段“假装是工具返回结果”的 assistant 消息再发一次观察模型怎么接着往下说。这个练习花不了半小时但能让你对“上下文”有肌肉记忆。注意不同模型对消息角色的支持略有差异有的模型对 system 消息的遵循度更高有的对多轮工具结果的处理更稳。选模型时不要只看跑分要拿你的真实任务去试。2.3 工具调用Agent 的“手脚”是怎么长出来的工具调用是新手第一个真正的门槛。很多人卡在这里是因为把它想复杂了。其实工具调用的本质是你用自然语言向模型描述“有哪些工具可用、每个工具要什么参数”模型决定要不要用、用哪个、参数填什么。所以你要做两件事。第一把工具描述写清楚。一个工具描述通常包括名字、功能说明、参数列表和每个参数的类型与含义。描述写得越清楚模型选错工具、填错参数的概率越低。第二解析模型的输出。如果模型决定调用工具它会返回一个结构化的调用请求你要把它解析出来去执行真正的函数再把结果包装成消息塞回上下文。这里有个特别容易被忽略的点工具执行失败也是信息。很多人工具报错了就直接抛异常中断其实更好的做法是把错误信息也塞回给模型让它自己决定是重试、换参数还是换工具。这才是 Agent 该有的“韧性”。我自己的经验是工具描述里一定要写清楚“什么时候不该用这个工具”。比如一个查订单的工具要注明“仅用于查询已有订单不用于创建订单”。这种负向说明能显著降低误调用。2.4 循环控制决定 Agent 是“聪明”还是“死循环”循环控制是最能体现工程功力的地方。最朴素的循环就是调用模型 → 如果有工具调用就执行 → 把结果塞回去 → 再调用模型 → 直到模型不再调用工具为止。但真实场景里这个循环会出各种问题。模型可能反复调用同一个工具、可能陷入无效推理、可能一直不给出最终答案。所以你需要设置终止条件最大循环次数、超时时间、连续无进展检测等。我一般会给循环加三个保险最大步数比如 10 步、单步超时比如 30 秒、以及一个“如果连续两步工具调用完全相同就强制中断”的检测。这三个保险能挡掉绝大多数失控情况。还有一个进阶技巧把中间步骤的思考过程显式记录下来。不是让模型输出思维链给用户看而是你自己在程序里维护一个“已做了什么”的摘要在上下文变长时用它来压缩历史。这对控制 token 成本非常关键。3. 手写一个最小 Agent 的完整实操3.1 环境准备与依赖选择这一节我带你从零手写一个最小 Agent不依赖任何 Agent 框架只用最基础的模型 SDK 和标准库。目的是让你把上一节讲的四件事亲手串一遍。环境上你需要一个能调用对话模型的方式官方 SDK 或兼容接口都行、Python 3.9 以上、以及 requests 这类基础库。我不建议一上来就装一堆东西依赖越少你越能看清哪些是 Agent 逻辑、哪些是工程噪音。目录结构我建议就三个文件tools.py放工具函数agent.py放主循环main.py做入口。别小看这个结构它逼你把“工具”和“循环”分开想这个习惯后面用框架时你会感谢自己。提示API Key 一定要用环境变量管理不要硬编码在代码里。这是最基本的工程习惯也是很多新手第一个踩的坑。3.2 定义工具与工具描述我们先定义两个最简单的工具一个查天气一个算加法。查天气用假数据模拟重点是让你看清工具描述的结构。# tools.py import json def get_weather(city: str) - str: fake_data {北京: 晴25度, 上海: 多云28度} return fake_data.get(city, 暂无该城市数据) def add(a: float, b: float) - float: return a b # 工具描述这是给模型看的 TOOLS_SPEC [ { name: get_weather, description: 查询指定城市的当前天气。仅用于查询天气不用于其他用途。, parameters: { type: object, properties: { city: {type: string, description: 城市名称如 北京} }, required: [city] } }, { name: add, description: 计算两个数字的和。, parameters: { type: object, properties: { a: {type: number}, b: {type: number} }, required: [a, b] } } ] TOOL_MAP {get_weather: get_weather, add: add}注意description里我特意写了“仅用于查询天气”。这就是前面说的负向说明。工具描述不是写给人看的文档是写给模型看的“使用说明书”措辞要精确。3.3 组装消息与调用模型接下来是核心。你要把工具描述、system 提示、用户问题组装成一次请求。不同模型的工具调用格式不一样但思路一致把工具描述作为参数传给模型模型返回时如果要用工具会给你一个结构化的调用请求。# agent.py import json from tools import TOOLS_SPEC, TOOL_MAP SYSTEM_PROMPT 你是一个助手可以调用工具来回答问题。 需要天气或计算时请调用对应工具。 拿到工具结果后用自然语言回答用户。 def build_messages(user_input, historyNone): messages [{role: system, content: SYSTEM_PROMPT}] if history: messages.extend(history) messages.append({role: user, content: user_input}) return messages这里的关键是history。Agent 的多轮能力全靠它。每次循环产生的 assistant 消息和工具结果消息都要追加进 history下一次调用才能“记得”。3.4 解析工具调用并执行模型返回工具调用请求后你要解析它、执行对应函数、把结果包装成消息。这一步是新手最容易写乱的地方我建议单独抽一个函数。def execute_tool_call(tool_call): name tool_call[name] args tool_call[arguments] if isinstance(args, str): args json.loads(args) func TOOL_MAP.get(name) if not func: return f错误未知工具 {name} try: result func(**args) return str(result) except Exception as e: return f工具执行失败{e}注意异常处理。工具失败不要中断整个流程而是把错误信息返回给模型。这就是前面说的“韧性”。模型看到错误后往往会自己调整参数重试或者换一种方式回答。3.5 主循环与终止条件最后把所有东西串起来。主循环的逻辑是调用模型 → 检查是否有工具调用 → 有就执行并追加结果 → 没有就输出最终答案。MAX_STEPS 10 def run_agent(user_input, call_model): history [] messages build_messages(user_input, history) for step in range(MAX_STEPS): response call_model(messages, toolsTOOLS_SPEC) if not response.get(tool_calls): return response[content] messages.append(response[raw_message]) for tc in response[tool_calls]: result execute_tool_call(tc) messages.append({ role: tool, tool_call_id: tc[id], content: result }) return 达到最大步数任务未完成。call_model我故意做成参数传进来这样你可以换成任何模型逻辑不变。MAX_STEPS就是那个保险。跑通这段代码你就拥有了一个不依赖任何框架的 Agent。实操心得第一次跑的时候故意让工具报错观察模型怎么处理。这个练习比跑通正常流程更有价值因为真实场景里工具失败是常态。4. 从手写版过渡到框架的正确姿势4.1 什么时候该引入框架手写版跑通之后你会自然遇到一些痛点工具多了管理麻烦、上下文长了要手动压缩、多轮对话状态要自己维护、想加流式输出要改一堆代码。这些痛点出现的时候才是引入框架的时机。判断标准很简单当你发现自己在重复写与业务无关的样板代码时就该考虑框架了。框架的价值就是把这些样板代码标准化、可复用化。但如果你连样板代码在干什么都不知道框架对你就是个黑盒。我一般建议手写版至少完整做过两个不同场景比如一个查询类、一个计算类再去看框架。这时候你看框架文档会有一种“哦它是在帮我做这件事”的顿悟感而不是“这都啥跟啥”。4.2 看框架时该重点看什么带着手写版的经验去看框架你的关注点会完全不同。你不再关心“怎么调用模型”而是关心这几个问题关注点手写版对应框架里看什么工具管理TOOL_MAP 字典工具注册机制、装饰器写法循环控制for MAX_STEPSAgent Executor、终止策略配置上下文管理手动 append historyMemory 组件、自动摘要多智能体无角色定义、消息传递机制这张表你可以当成看框架文档的“检查清单”。每看一个框架就对照着找它对应的实现。找齐了你对这个框架的理解就到位了。4.3 转行者最容易踩的三个坑第一个坑是过早追求多智能体。很多人一上来就想搞“一个规划 Agent 一个执行 Agent 一个审核 Agent”的架构结果连单个 Agent 的工具调用都没调稳。多智能体是复杂度放大器单 Agent 都控制不住多 Agent 只会更乱。第二个坑是迷信框架的“自动”能力。框架说“自动管理记忆”你就真不管了结果 token 爆了、上下文串了都不知道为什么。记住框架的“自动”都是有一套默认策略的你得知道那套策略是什么才能判断它适不适合你的场景。第三个坑是只跑 Demo 不做真实任务。Demo 都是精心设计过的顺利路径真实任务全是边界情况。我建议你学完框架后立刻拿一个自己真实的小需求去做比如“帮我整理一个文件夹里的文档摘要”这种任务会逼你处理各种意外。4.4 一个可复用的学习路线最后给你一条我自己验证过的路线按顺序走别跳第一周手写模型调用理解消息结构能手动构造多轮对话第二周手写工具调用理解工具描述和结果回填跑通最小 Agent第三周给手写 Agent 加终止条件、错误处理、简单记忆第四周选一个主流框架对照手写版理解它的每个组件第五周起用框架做一个真实小项目遇到问题回看手写版原理这条路线的好处是每一步都有明确的产出而且后面的学习都建立在前面理解的基础上。转行最怕的就是学了一堆名词但串不起来这条路线能帮你把知识串成一条线。5. 常见问题与排查技巧实录5.1 模型不调用工具怎么办这是最高频的问题。模型该调工具的时候不调通常有三个原因。第一工具描述不清楚模型没看懂这个工具是干嘛的。第二system 提示没强调“需要外部信息时要用工具”。第三模型本身对工具调用的支持较弱。排查顺序我建议从提示词开始。先强化 system 提示明确写“涉及天气、计算等问题必须调用工具不要凭记忆回答”。如果还不行检查工具描述把功能、参数、使用场景写得更具体。最后再考虑换模型。避坑技巧有些模型在工具描述里加一两个“示例调用”会显著提升调用率。比如在 description 里写“例如查询北京天气时参数为 city北京”。5.2 工具调用参数总是填错参数填错多半是参数描述不够精确。比如一个参数叫date你只写“日期”模型可能填“明天”“下周一”这种自然语言。你要写清楚格式比如“日期格式为 YYYY-MM-DD”。另一个技巧是给参数加枚举约束。如果某个参数只能是几个固定值就在描述里列出来。模型看到枚举填错的概率会大幅下降。5.3 循环停不下来或提前结束停不下来通常是终止条件没设好或者模型陷入了“调用工具 → 结果不满意 → 再调用”的循环。加最大步数和连续重复检测能解决大部分情况。提前结束则往往是模型在拿到工具结果后误以为任务完成了。这时候你要在 system 提示里强调“拿到工具结果后要基于结果回答用户不要直接结束”。有时候也需要检查工具结果是不是为空或格式异常导致模型判断失误。5.4 上下文越来越长、成本越来越高这是所有 Agent 都会遇到的问题。最直接的办法是只保留最近 N 轮对话更早的用摘要替代。摘要可以让模型自己生成也可以你自己写规则压缩。另一个技巧是工具结果只保留关键字段。比如查天气返回一大段 JSON你只把“城市、天气、温度”三个字段塞回上下文而不是整个 JSON。这个优化能省下大量 token。问题常见原因优先排查不调用工具描述不清、提示不足system 提示 → 工具描述参数填错参数描述模糊加格式说明、枚举约束循环不停无终止条件加最大步数、重复检测成本过高上下文膨胀截断历史、精简工具结果这张表你可以贴在显示器边上遇到问题先对照排查能省不少时间。6. 我个人的一些体会学 AI Agent 这件事我最大的体会是慢就是快。那些一上来就啃框架的人看起来起步快但遇到问题就卡死因为他们没有可以回退的“底层理解”。而先手写一遍的人起步慢一两周但后面学任何框架都是降维打击。还有一个体会是Agent 的难点从来不在模型而在工程。模型能力是给定的你能控制的是提示词、工具设计、循环策略、上下文管理。这些全是工程问题而工程能力只能靠动手练看再多文章都没用。最后分享一个小技巧每次学一个新概念都问自己“如果不用任何框架我怎么用最笨的代码实现它”。能回答上来你就是真懂了回答不上来那就回去补课。这个方法我用它判断自己是不是真的掌握了一个东西屡试不爽。