☰
AI Agent入门:先学底层原理,再碰框架
2026/10/22 20:02:46 网站建设 项目流程

1. 为什么一上来就啃框架是新手最大的坑

我带过不少想转行做 AI Agent 的朋友,也看过很多新手的学习路径,发现一个特别普遍的现象:打开某个主流 Agent 框架的官方文档,看到一堆概念——Chain、Tool、Memory、Retriever、Agent Executor——然后就开始照着示例代码一行行敲,敲完跑通了,觉得自己入门了。但一旦需求稍微变一下,比如换个模型、加个自定义工具、处理多轮对话里的上下文丢失问题,整个人就懵了。

这不是个别现象,而是学习路径本身出了问题。框架是别人对一类问题的抽象和封装,它默认你已经理解了被封装的那些底层概念。你直接跳到抽象层,相当于还没学会加减法就去解方程,能套公式算出答案,但不知道为什么要这样算。

我个人的判断是:AI Agent 入门阶段,最该先搞清楚的,是“一个 Agent 到底由哪些基本部件组成、每个部件解决什么问题”,而不是“某个框架怎么调用”。框架会过时、会换 API、会改设计哲学,但底层那套东西——模型怎么被调用、工具怎么被描述和选择、上下文怎么管理、循环怎么终止——这些是相对稳定的。

这篇文章就是想把这条学习路径讲清楚。适合两类人:一类是完全没有 AI 应用开发经验的新手,另一类是从传统开发(比如后端、前端、数据分析)想转到 AI Agent 方向的从业者。我会先讲清楚该学什么、按什么顺序学,再讲每个环节的实操要点和踩坑经验,最后给一套可以直接照着走的学习路线。全程不绑定任何具体框架,因为我想让你学的是“能力”,不是“某个工具的用法”。

2. 先建立认知地图:Agent 到底由什么组成

2.1 用生活类比理解 Agent 的本质

你可以把一个 AI Agent 想象成一个刚入职的助理。这个助理很聪明,但有几个特点:他只能通过文字和你沟通;他记性有限,聊太久会忘掉前面说过的内容;他不能直接操作电脑,需要你告诉他“你可以用哪些工具”;他有时候会自作主张,需要你给他划清边界。

对应到技术层面,一个 Agent 系统通常包含这几个核心部件:

  • 模型(大脑):负责理解意图、做决策、生成内容。它是整个系统的推理核心。
  • 工具(手脚):模型本身只能生成文字,要让它查数据、发请求、读写文件,必须给它提供可调用的函数。
  • 上下文/记忆(记事本):模型每次调用都是无状态的,你需要把历史对话、任务状态、中间结果组织好再喂给它。
  • 控制循环(工作流程):决定什么时候调用模型、什么时候调用工具、什么时候结束。这是 Agent 和普通“一问一答”最本质的区别。

新手最容易忽略的是最后一点。很多人以为 Agent 就是“模型加工具”,其实真正让它“动起来”的是那个循环:模型输出一个动作意图,系统执行这个动作,把结果再喂回模型,模型再决定下一步,直到任务完成。这个循环的设计,才是 Agent 开发的核心难点。

2.2 为什么底层概念比框架 API 更值得先学

我举个具体的例子。假设你要做一个“根据用户问题自动查数据库并回答”的 Agent。用框架的话,可能是几行配置的事。但如果你不理解底层,遇到下面这些问题就会卡住:

  • 模型总是选错工具,明明该查数据库却去调了计算器,为什么?——因为工具的描述(description)写得不够清晰,模型是靠这段文字来判断的。
  • 多轮对话后模型开始胡言乱语,为什么?——因为上下文窗口塞满了无关历史,或者关键信息被截断了。
  • 任务执行到一半死循环,为什么?——因为循环没有设置最大步数或终止条件。

这些问题,框架文档里往往一笔带过,但实际开发中天天遇到。你只有理解了“模型是怎么根据工具描述做选择的”“上下文是怎么被组织和截断的”“循环是怎么被控制的”,才能对症下药。

所以我的建议很明确:入门阶段,先用最原始的方式(直接调模型 API + 手写循环)把一个小 Agent 跑通,理解每个部件的作用,再去用框架提效。这样你学框架的时候,是在学“它帮我封装了什么”,而不是“它让我填什么参数”。

2.3 一张学习优先级清单

我把入门阶段该学的东西按优先级排一下,你可以对照自己的情况看:

优先级学习内容为什么重要建议投入时间
高模型 API 的基本调用(输入输出格式、参数)一切的基础,不理解这个后面都是空中楼阁1-2 天
高提示词的基本写法(角色、指令、格式约束)模型的行为高度依赖你怎么说3-5 天
高工具调用的原理(怎么描述工具、怎么解析调用)Agent 能“做事”的关键3-5 天
中上下文管理与简单记忆决定多轮任务能不能跑通2-3 天
中控制循环的设计(终止条件、错误处理)决定 Agent 稳不稳定3-5 天
低具体框架的使用提效工具,可后置按需

这张表的核心逻辑是:先学“不可变”的,再学“可变”的。模型 API 的调用方式、提示词的写法、工具调用的原理,这些是跨框架通用的;而某个框架的具体 API,换个框架就作废了。

3. 核心基础一:模型调用与提示词,别小看这两件事

3.1 模型 API 调用:先搞懂“输入什么、输出什么”

很多人觉得调模型 API 很简单,不就是发个请求拿个回复吗?但实际开发中,你需要搞清楚几个关键点:

第一,消息的角色(role)是怎么划分的。通常有 system、user、assistant 三种角色。system 用来设定模型的整体行为,user 是用户输入,assistant 是模型的回复。在 Agent 场景里,工具调用的结果通常也以特定角色(比如 tool 或 function)回传。理解角色划分,是理解上下文组织的第一步。

第二,输出格式的控制。普通对话你不需要管格式,但 Agent 场景里,你经常需要模型输出结构化的内容,比如一个 JSON,里面包含“要调用哪个工具、传什么参数”。这时候就要用到格式约束,比如要求模型输出 JSON,或者使用模型提供的结构化输出能力。

第三,参数的影响。温度(temperature)控制随机性,Agent 场景通常要调低,因为你需要稳定的决策;最大输出长度(max tokens)决定回复能有多长,设太小会导致工具调用参数被截断。

我建议你入门时,先不借助任何封装库,直接用 HTTP 请求或官方 SDK 调一次模型,把请求体和响应体完整打印出来看一遍。这一步很多人跳过,但它是建立直觉的关键。你会亲眼看到:哦,原来模型收到的是一串消息列表,返回的是一段文本加一些元信息。

3.2 提示词:Agent 的“岗位说明书”

提示词在 Agent 里的作用,比在普通对话里重要得多。普通对话里,提示词影响回复质量;Agent 里,提示词直接决定模型会不会正确调用工具、会不会跑偏、会不会死循环。

我踩过的一个坑是:早期写工具描述时,只写了“查询天气”,结果模型经常在不该查天气的时候也去查。后来我把描述改成“当用户明确询问某个城市的当前天气时使用此工具,其他情况不要调用”,误调用率立刻降下来了。

写 Agent 提示词,我总结了几条实操经验:

  • 角色要具体:不要写“你是一个助手”,要写“你是一个负责处理订单查询的客服 Agent,你只能通过提供的工具获取信息,不能编造”。
  • 工具描述要写清楚“什么时候用”和“什么时候不用”:模型是靠这段文字做选择的,模糊的描述会导致错误调用。
  • 输出格式要明确:如果需要模型输出工具调用,就明确告诉它格式,最好给一个例子。
  • 边界要划清:告诉模型遇到不确定的情况该怎么办,比如“如果工具返回错误,最多重试两次,然后告知用户”。

提示:提示词不是写一次就完事的,它需要根据实际运行效果反复调整。建议你把每次调整和对应的效果记录下来,慢慢就形成自己的“提示词手感”了。

3.3 一个最小可运行示例

下面这段代码展示了不借助任何 Agent 框架,直接调模型并手动处理工具调用的最小结构。语言用 Python,你可以照着改:

import json # 假设这是你的模型调用函数,返回模型输出的文本 def call_model(messages): # 实际项目中这里替换为真实的模型 API 调用 # 返回模型生成的文本 pass # 定义工具 tools = [ { "name": "get_weather", "description": "当用户明确询问某个城市的当前天气时使用。参数为城市名。", "parameters": {"city": "string"} } ] # 工具的实际执行函数 def execute_tool(name, params): if name == "get_weather": # 实际项目中这里调用天气 API return f"{params['city']}今天晴,25度" return "未知工具" # 手动控制循环 def run_agent(user_input, max_steps=5): messages = [ {"role": "system", "content": "你是一个助手,可以使用工具。需要工具时输出 JSON:{\"tool\": \"工具名\", \"params\": {...}}"}, {"role": "user", "content": user_input} ] for step in range(max_steps): response = call_model(messages) messages.append({"role": "assistant", "content": response}) # 判断模型是否要调用工具 try: action = json.loads(response) if "tool" in action: result = execute_tool(action["tool"], action.get("params", {})) messages.append({"role": "user", "content": f"工具返回:{result}"}) else: return response except json.JSONDecodeError: # 不是 JSON,说明是普通回复,任务结束 return response return "达到最大步数,任务未完成"

这段代码很粗糙,但它把 Agent 的核心结构完整暴露出来了:消息列表、工具定义、循环、终止条件。你把这个跑通,再去用框架,就会明白框架帮你省了哪些事。

4. 核心基础二:工具调用与上下文管理

4.1 工具调用:Agent 从“会说”到“会做”的关键

工具调用的本质,是让模型输出一段结构化的内容,告诉系统“我要调用哪个函数、传什么参数”,系统执行后把结果回传。这里面有几个容易出问题的地方:

工具描述的质量直接决定调用准确率。我见过太多新手把工具描述写成“查询数据”“处理请求”这种模糊表述,然后抱怨模型老选错。工具描述要像写给一个新员工的说明:这个工具做什么、什么时候用、参数是什么格式、返回什么。越具体越好。

参数校验不能省。模型输出的参数不一定符合你的预期,可能缺字段、类型不对、甚至编造不存在的参数。系统在执行工具前必须做校验,不合法就返回错误信息让模型重试,而不是直接崩溃。

工具数量要控制。一次性给模型几十个工具,它的选择准确率会明显下降。实践中,我通常把工具控制在 10 个以内,如果确实需要很多工具,就做分组或分层,让模型先选类别再选具体工具。

错误处理要设计好。工具执行失败是常态,网络超时、参数错误、权限不足都可能发生。你要决定:是让模型重试、换工具、还是直接告知用户失败。这个决策逻辑最好写在提示词里,让模型有章可循。

4.2 上下文管理:为什么你的 Agent 聊着聊着就“失忆”了

上下文管理是新手最容易低估的部分。模型每次调用都是无状态的,它看到的只有你这次传进去的消息列表。所以“记忆”这件事,完全是你自己实现的。

最简单的做法是把所有历史消息都带上。但这样很快会遇到问题:上下文窗口有限,聊久了就塞不下;而且无关历史会干扰模型判断。我实测下来,一个任务型 Agent 如果无脑带上全部历史,跑到十几轮之后,模型开始忽略最新的指令,反而去回应很早之前的内容。

我的做法是分层管理:

  • 系统提示词:始终保留,放在最前面。
  • 当前任务相关的上下文:比如用户最初的需求、已经确认的关键信息,这些要保留。
  • 近期对话:保留最近几轮,保证连贯性。
  • 远期历史:做摘要压缩,或者直接丢弃。

摘要压缩是个实用技巧:当历史消息超过一定长度,就调用模型把前面的内容总结成一段简短的话,替换掉原始消息。这样既保留了关键信息,又控制了长度。

注意:摘要会丢失细节,所以关键信息(比如用户明确给出的参数、已经确认的决策)不要依赖摘要,要单独结构化存储。

4.3 一个上下文管理的实操方案

下面这个结构是我在实际项目中常用的,你可以参考:

class ContextManager: def __init__(self, max_recent=6): self.system_prompt = "" self.key_facts = [] # 结构化存储的关键信息 self.recent_messages = [] # 近期对话 self.summary = "" # 远期历史的摘要 self.max_recent = max_recent def add_message(self, role, content): self.recent_messages.append({"role": role, "content": content}) if len(self.recent_messages) > self.max_recent: self._compress() def _compress(self): # 把最早的两条消息并入摘要 to_compress = self.recent_messages[:2] self.recent_messages = self.recent_messages[2:] # 实际项目中这里调用模型做摘要 new_text = " ".join([m["content"] for m in to_compress]) self.summary = (self.summary + " " + new_text).strip() def build_messages(self): messages = [{"role": "system", "content": self.system_prompt}] if self.summary: messages.append({"role": "system", "content": f"历史摘要:{self.summary}"}) if self.key_facts: facts = ";".join(self.key_facts) messages.append({"role": "system", "content": f"关键信息:{facts}"}) messages.extend(self.recent_messages) return messages

这个方案的核心思想是:把“记忆”拆成不同层次,每层用不同的策略处理。关键信息结构化存储,近期对话原样保留,远期历史压缩成摘要。这样既控制了长度,又尽量不丢信息。

5. 核心基础三:控制循环与错误处理

5.1 循环设计:Agent 的“心跳”

控制循环决定了 Agent 怎么一步步推进任务。最简单的循环是:调用模型 → 如果有工具调用就执行 → 把结果回传 → 再调用模型 → 直到模型不再调用工具或达到最大步数。

但实际场景里,你需要考虑更多:

终止条件要明确。除了“模型不再调用工具”,还要设置最大步数、最大耗时、最大 token 消耗。我踩过的坑是:有一次模型陷入了一个“调用工具 → 结果不满意 → 再调用同一个工具”的死循环,因为没有设最大步数,跑了几十轮才被我发现。

中间状态要可观测。每一步模型输出了什么、调用了什么工具、返回了什么结果,都要记录下来。不然出了问题你根本不知道是哪一步错的。我通常会把每一步的完整信息写到日志里,调试的时候一目了然。

异常要能恢复。工具调用失败、模型返回格式错误、网络超时,这些都要有对应的处理逻辑。我的做法是:把错误信息作为工具结果回传给模型,让模型决定下一步。大多数情况下,模型看到错误信息后会调整策略。

5.2 错误处理:让 Agent 在出错时“优雅地失败”

新手写的 Agent,一出错就整个崩掉。但实际生产环境里,出错是常态,关键是怎么处理。

我把错误分成三类:

  • 可重试错误:网络超时、临时限流。这类错误直接重试,通常重试一两次就好了。
  • 可恢复错误:参数格式不对、工具返回空结果。这类错误把信息回传给模型,让它调整。
  • 不可恢复错误:权限不足、工具不存在。这类错误直接终止任务,告知用户。

对应到代码里,就是给工具调用包一层错误处理:

def safe_execute_tool(name, params, max_retry=2): for attempt in range(max_retry): try: result = execute_tool(name, params) if result is None: return {"error": "工具返回空结果,请检查参数"} return {"result": result} except TimeoutError: if attempt == max_retry - 1: return {"error": "工具调用超时,请稍后重试"} continue except Exception as e: return {"error": f"工具执行失败:{str(e)}"}

这个结构把错误信息结构化后回传给模型,模型看到error字段就知道这次调用失败了,可以选择重试、换工具或告知用户。

5.3 循环步数的经验值

最大步数设多少合适?这个没有标准答案,但根据我的经验:

  • 简单任务(单次工具调用):3-5 步足够。
  • 中等任务(多步推理 + 多次工具调用):10-15 步。
  • 复杂任务(需要反复调整策略):20-30 步。

设太小会导致任务没完成就中断,设太大又浪费资源。我的做法是先设一个保守值(比如 15),观察实际运行时的步数分布,再调整。如果发现大部分任务都在 5 步内完成,那 15 就够用了;如果经常撞到上限,说明要么任务确实复杂,要么提示词有问题导致模型绕弯路。

6. 常见问题与排查技巧实录

6.1 模型不调用工具怎么办

这是新手最常遇到的问题。模型明明有能力调用工具,但它就是直接回复文字,不输出工具调用。

排查思路:

  • 检查工具描述是否清晰:模型是靠描述判断的,描述模糊它就不敢调。
  • 检查提示词是否明确要求使用工具:有时候需要在系统提示词里明确写“你必须通过工具获取信息,不能凭记忆回答”。
  • 检查输出格式约束:如果要求模型输出 JSON,但没给例子,模型可能不知道怎么输出。
  • 检查模型能力:不是所有模型都支持工具调用,确认你用的模型有这个能力。

我的经验是,90% 的情况是工具描述或提示词的问题,不是模型的问题。

6.2 模型选错工具怎么办

模型在多个工具之间选错了。常见原因和解决方法:

现象可能原因解决方法
总是选某个不相关的工具该工具描述太宽泛收窄描述,明确使用场景
该用 A 却用了 BA 和 B 描述太相似在描述里写清楚两者的区别
该调用工具却直接回答提示词没强调必须用工具在系统提示词里明确要求
参数传错参数说明不清晰给出参数格式示例

6.3 Agent 陷入死循环怎么办

死循环的表现是:模型反复调用同一个工具,或者反复输出相同的内容。

排查思路:

  • 检查工具返回结果:如果工具一直返回错误或空结果,模型可能会一直重试。确保工具在正常情况下能返回有效结果。
  • 检查提示词里的重试逻辑:如果提示词说“失败就重试”,但没说重试上限,模型可能无限重试。明确写“最多重试两次”。
  • 设置硬性最大步数:这是最后的防线,不管什么原因,到了步数上限就强制终止。

6.4 上下文太长导致模型“失忆”

表现是:聊到后面,模型忘记了前面说过的关键信息,或者开始重复之前的内容。

解决方法:

  • 结构化存储关键信息:不要依赖模型自己记住,把关键参数、已确认的决策单独存起来,每次调用时放在系统提示词里。
  • 压缩历史:用摘要替换远期历史。
  • 控制单次输入长度:如果单条消息特别长(比如工具返回了一大段数据),考虑截断或摘要后再喂给模型。

6.5 我的避坑清单

最后整理一份我踩过的坑,你可以直接对照检查:

  • 工具描述写得太简单,导致模型误调用。
  • 没有设置最大步数,导致死循环消耗大量资源。
  • 上下文无脑全带,导致模型被无关信息干扰。
  • 工具执行没有错误处理,一出错整个流程崩溃。
  • 提示词里没有明确输出格式,导致解析失败。
  • 没有记录中间步骤,出问题无法定位。
  • 一次性给太多工具,模型选择困难。
  • 忽略了模型的输出长度限制,导致工具调用参数被截断。

7. 一套可以直接照着走的学习路线

7.1 第一周:打地基

目标:理解模型调用的基本流程,能写出稳定的提示词。

  • 第一天到第二天:直接调模型 API,打印请求和响应,理解消息角色和参数。
  • 第三天到第五天:练习写提示词,从简单角色设定到复杂的格式约束,观察不同写法对输出的影响。
  • 第六天到第七天:写一个不涉及工具调用的多轮对话程序,手动管理上下文。

这一周的关键是“动手”,不要只看文档。每改一次提示词,就跑一次看效果,记录差异。

7.2 第二周:让 Agent 动起来

目标:理解工具调用原理,能写出一个能调用工具的最小 Agent。

  • 第一天到第三天:定义两三个简单工具(比如查时间、做计算),手动实现工具调用循环。
  • 第四天到第五天:加入错误处理和最大步数限制,测试各种异常情况。
  • 第六天到第七天:加入简单的上下文管理,测试多轮任务。

这一周你会遇到大量问题,这正是价值所在。每解决一个问题,你对 Agent 的理解就深一层。

7.3 第三周:引入框架提效

目标:在理解底层的基础上,用框架重写之前的 Agent,体会框架的便利和局限。

  • 选一个主流框架,用它重写第二周的最小 Agent。
  • 对比手写版本和框架版本,理解框架封装了什么、牺牲了什么。
  • 尝试框架的高级功能,比如多 Agent 协作、复杂记忆管理。

这时候你学框架,是在“验证自己的理解”,而不是“从零猜测”。效率完全不一样。

7.4 后续方向

基础打牢之后,你可以往几个方向深入:

  • 多 Agent 协作:多个 Agent 分工合作完成复杂任务。
  • RAG 结合:让 Agent 能检索外部知识库。
  • 评估与优化:建立评估体系,持续优化 Agent 的表现。
  • 生产化:日志、监控、限流、成本控制。

我个人在实际操作中的体会是,入门阶段最忌讳的就是“贪快”。我见过太多人一周换一个框架,每个都只跑通了示例,但遇到实际问题就束手无策。反而是那些愿意花两周时间手写最小 Agent 的人,后面学什么都快。因为底层那套东西是相通的,框架只是换了个壳。你把壳下面的东西搞明白了,换什么壳都不慌。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询