简介:一份对标大模型应用开发工程师岗位的AI Agent学习资料,系统梳理LangChain、LangGraph、Coze、Dify、MCP、RAG与提示词工程等主流技术栈,从LLM基础原理、智能体核心组件到企业级部署与微调全链路展开,适合从零入门、求职冲刺或项目落地的开发者。资源包共2000个文件,包含1588张图解说明、127个Python示例脚本、83篇Markdown笔记、13个实操视频以及多格式文档与数据集,整体约513MB,按学习阶段与项目模块分类存放,便于快速定位。目前已有223人学习下载。内容覆盖金融投研、医疗问诊、电商客服、工业运维、政务解读等真实场景实战项目,并附带面试题库、调参建议和故障排查方案,可作为从学习到上线的完整参考资料。
1. 2026 年 AI Agent 速成指南:不是要不要学,而是从哪条路切入
2026 年聊 AI Agent,已经不是要不要学的问题,而是从哪条路切入的问题。市面上的速成材料有两个毛病:要么从小白科普讲起,绕半天没见到 LangChain 一行代码;要么直接丢出 LangGraph,连 function calling 都没说明白就让你上生产。这篇指南按大模型应用开发工程师的真实岗位技能来拆:先立认知,讲清 Agent 为什么不是 Chatbot;再给完整学习路径,用 LangChain 跑通最小闭环;接着用 LangGraph 把单轮 Agent 改造成可维护的工作流;最后落到面试题库和自检掌握度的验证方法。适合准备转岗、面试,或手上有业务但想系统补一遍框架边界的工程师。目标是让你用四到六周,能对着真实场景把方案画出来、写出来、上线验证。
2. 先搭认知再选框架:LLM 调用、工具调用与 Agent 主流架构
2.1 从 LLM 到 Agent:中间差了一个「工具调用」
很多人对着 chatbox 调了几个接口,就以为自己在做 Agent。实际上,一个裸的 LLM 本质上只是一个「按概率接下文」的模型,你给它一段文本,它回你一段文本。它没有数据库连接,不能读订单系统的接口,也不能执行代码。所谓 Agent,就是在 LLM 外面包一层循环:理解用户输入、决定要不要调用工具、拿到工具结果、再决定下一步动作。
这个循环里最关键的咬合点就是工具调用(Tool Calling / Function Calling)。模型本身不会去访问任何系统,它只是输出一个结构化 JSON,里面包含你要调用的工具名和参数。真正执行工具的是你写的 Python 代码。执行完,你把结果以一条 ToolMessage 追加回对话历史,再让模型基于这个结果继续推理。网上常有人问「AI Agent token 是什么意思」——这里的 token 就是你每次循环里来回传递的文本计量单位,也是 Agent 成本和时间的主要来源,后面讲上下文膨胀时会再回到它。
我把这套机制称为 Agent 的「四段式循环」:意图输入、模型决策、工具执行、结果回填。无论你用 LangChain、LangGraph 还是 Dify,底层都逃不开这四步。区别只在于:谁来编排循环,状态放哪里,异常怎么恢复。
2.2 LangChain、LangGraph、Dify、CrewAI:2026 年怎么选
2026 年聊 Agent 框架,最常被拿来对比的就是 LangChain、LangGraph、Dify 和 CrewAI。我的判断是:学习顺序先 LangChain 后 LangGraph,Dify 和 CrewAI 按团队形态决定要不要碰。LangChain 解决的是「把 LLM 和工具粘起来」的组件化问题,适合快速原型和 RAG;LangGraph 解决的是「状态怎么流转、任务怎么恢复」的工程化问题,适合生产级工作流;Dify 是低代码可视化平台,适合产品同学或非纯代码团队快速验证;CrewAI 主打多角色协作,在需要模拟团队分工的场景有存在感,但企业里落地占比不高。
| 框架 | 核心抽象 | 适合场景 | 学习优先级 |
|---|---|---|---|
| LangChain | Chain / Tool / Memory | RAG、快速原型、工具封装 | 先学 |
| LangGraph | StateGraph / Node / Edge / Checkpoint | 生产级工作流、多轮状态、人机协同 | 重点补 |
| Dify | 可视化编排、工作流画布 | 低代码验证、非技术团队 | 按需 |
| CrewAI | Role / Task / Process | 多角色协作仿真 | 了解 |
我见过不少团队一上来就选 LangGraph,结果被状态图绕晕;也见过一直停在 LangChain AgentExecutor 的项目,跑到上线后被「不可观测、不可打断、不可恢复」折磨。务实的路线是:先用 LangChain 把单个 Agent 跑通,理解工具调用和 prompt 的作用方式;再把循环迁到 LangGraph,用图结构把每一步变成可检查的节点。
2.3 岗位对标:大模型应用开发工程师到底在写什么
企业里的大模型应用开发工程师,岗位描述写得天花乱坠,拆开看核心就几条:能设计 prompt 和 few-shot 样例,能定义工具 JSON Schema,能用框架把模型接到业务系统上,能处理多轮上下文,能做基础的效果评测。面试题库也是围绕这些能力展开的。很多人背了一堆「什么是 RAG」「什么是微调」的名词,可真到现场被问「工具调用失败时你从哪一层排查」,立刻露馅。
这个岗位的工作更像传统后端开发的变体:接口从「第三方 HTTP」变成了「LLM API」,业务逻辑里多了一层「模型可能输出错误格式」的不可控性。所以后面所有章节,我都会围绕「把不可控的模型行为变成可控的工程行为」来讲——这才是四到六周速成真正要练的东西。
3. 完整学习路径:从 LLM 基础到 LangChain 最小闭环
3.1 四周学习路径表与阶段产出
完整学习路径的核心不是「看多少教程」,而是「每个阶段有没有拿得出手的产出物」。我给一个可执行的四周拆分,每周末你手里应该有一个能跑的代码片段和一张能讲清楚的设计图。
| 周次 | 主题 | 必会产出 | 对应面试考点 |
|---|---|---|---|
| 第 1 周 | LLM 基础、prompt、temperature、上下文长度 | 一个温度和 system prompt 对照实验脚本 | temperature 对输出影响、上下文长度限制 |
| 第 2 周 | function calling 原理 + LangChain 组件 | bind_tools 跑通一个订单查询工具 | Tool Schema 怎么设计、pydantic 作用 |
| 第 3 周 | AgentExecutor 循环 + 工具封装 | 一个能回答业务问题的客服 Agent | ReAct 与原生 Tool Calling 区别 |
| 第 4 周 | LangGraph 重构 + 多轮持久化 | 带状态和 checkpoint 的工作流 | StateGraph 和 AgentExecutor 区别 |
第 1 周别急着碰框架。先用你最顺手的模型 API 写脚本,分别测 temperature=0 和 temperature=0.9 下同一段 prompt 的输出,再故意不写 system prompt 跑一轮,你会切身体会「为什么企业里几乎没人把温度调高」。第 2 周开始接触 LangChain,重点是工具定义和模型绑定。到了第 3 周,才真正让模型进入 Agent 循环。
3.2 第一行可运行代码:bind_tools 触发工具调用
第 2 周的第一个脚本,我一般会让新人从 bind_tools 写起。这一步不用管 AgentExecutor,只需要让模型输出一个「我要调用工具」的结构化结果:
from langchain_openai import ChatOpenAI from pydantic import BaseModel, Field # 如果你接的是本地 vLLM/Ollama 等 OpenAI 兼容端点,替换 base_url 即可 llm = ChatOpenAI( model="qwen-plus", # 换成你手头有 function calling 能力的模型 base_url="http://localhost:8000/v1", temperature=0, ) class GetOrderStatus(BaseModel): """查询订单状态""" order_id: str = Field(description="订单号,形如 2026001") llm_with_tools = llm.bind_tools([GetOrderStatus]) resp = llm_with_tools.invoke("订单 2026001 现在什么状态?") print(resp.tool_calls)这段代码的逻辑是:用 Pydantic 类声明工具参数结构,bind_tools 把这个结构转换成模型能理解的 JSON Schema 注入请求。模型如果判断需要查询订单,就会在返回结果里带上 tool_calls 字段。这里有两个参数值得盯住:temperature 设为 0,是为了避免采样随机性破坏结构化输出的格式;base_url 指向本地端点,是因为开发阶段用本地模型调试能省不少成本,生产再切商业化 API,代码不用改。
常见的翻车点是工具描述写得含糊。pydantic 里类的 docstring 和 Field 的 description 会原样进入模型提示,描述不清,模型就不知道该不该调用这个工具。你多写几个工具后会发现:模型参数的准确性,一半靠模型能力,一半靠你的 Schema 表达得清不清楚。
3.3 在 LangChain 里组装 AgentExecutor 跑通 ReAct
第 3 周的核心产出是让 Agent 完整跑完一个循环。下面这个例子是客服 Agent 的最小可运行版本,我用的姿态是「先跑通,再优化」:
import json from langchain_openai import ChatOpenAI from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain.tools import tool from langchain_core.prompts import ChatPromptTemplate llm = ChatOpenAI(model="qwen-plus", temperature=0) @tool def get_order_status(order_id: str) -> str: """查询订单状态,返回 JSON 字符串。""" return json.dumps({"order_id": order_id, "status": "shipped"}, ensure_ascii=False) @tool def calculate_shipping(address: str, weight_kg: float) -> str: """根据收货地地址和包裹重量估算运费,单位元。""" return "15.0" tools = [get_order_status, calculate_shipping] prompt = ChatPromptTemplate.from_messages([ ("system", "你是客服助手,只能使用工具获取真实信息,禁止编造订单状态和运费。"), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), ]) agent = create_tool_calling_agent(llm, tools, prompt) executor = AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=5) result = executor.invoke({"input": "订单 2026001 发货了没?运费多少?"}) print(result["output"])这段代码的逻辑是:create_tool_calling_agent 依赖模型原生的工具调用能力,模型内部完成「该不该调工具」的判断;prompt 里的 agent_scratchpad 是占位符,运行时会把已经发生的推理和工具结果填进去,保证模型看到完整历史。max_iterations=5 是安全阀,防止模型在工具结果里死循环出不来的情况,我在生产环境一般压到 3 到 6。
需要特别说明一点:传统 ReAct 走的是「Thought / Action / Observation」文本推理,而 create_tool_calling_agent 走的是原生 Tool Calling,两者在工程上差别很大。原生 Tool Calling 的结构化程度更高,解析更稳定,2026 年的一线项目几乎都倾向用它。面试若被问到这个区别,能说清楚「一个靠解析文本,一个靠解析 JSON 字段」,会比单纯背概念得分高很多。
4. LangGraph 实战:把 Agent 从「对话玩具」改成「可控工作流」
4.1 StateGraph 的最小认知:状态、节点、边、条件路由
LangChain 的 AgentExecutor 跑通 demo 很快,但真正到生产,你会发现它像一个黑匣子:循环走到哪一步了,状态里积压了多少条消息,中途能不能插入人工审批,出了问题怎么从某一轮恢复,这些它统统不给你抓手。LangGraph 解决的就是这件事。它的核心抽象是状态图:所有信息集中在 state 里,处理逻辑拆成节点,节点之间用边连接,边走,边就是决策条件。
你要先接受一个观念转换:在 AgentExecutor 里,循环是框架替你维护的;在 LangGraph 里,循环是你自己画出来的。代价是要多写几行胶水代码,收益是每一步都可打断、可检查、可恢复。这个取舍,在只做一个周末 demo 时感知不强,但一旦 Agent 要处理真实订单、真实转账,它就是生死线。
4.2 LangGraph 实现订单查询 Agent:代码与参数说明
沿用第 3.3 节的两个 @tool 函数,我们把同一个客服 Agent 迁到 LangGraph 上。先定义状态和节点:
from typing import TypedDict, Annotated, Literal from langgraph.graph import StateGraph, START, END from langgraph.graph.message import add_messages from langchain_core.messages import ToolMessage class AgentState(TypedDict): # add_messages 是 reducer,新消息追加进列表,而不是覆盖旧列表 messages: Annotated[list, add_messages] def run_agent(state: AgentState): response = llm_with_tools.invoke(state["messages"]) return {"messages": [response]} def run_tools(state: AgentState): last_message = state["messages"][-1] tool_outputs = [] for call in last_message.tool_calls: tool_map = {"get_order_status": get_order_status, "calculate_shipping": calculate_shipping} result = tool_map[call["name"]].invoke(call["args"]) tool_outputs.append(ToolMessage(content=result, tool_call_id=call["id"])) return {"messages": tool_outputs} def route_after_agent(state: AgentState) -> Literal["tools", "__end__"]: last_message = state["messages"][-1] if last_message.tool_calls: return "tools" return END graph = StateGraph(AgentState) graph.add_node("agent", run_agent) graph.add_node("tools", run_tools) graph.add_edge(START, "agent") graph.add_conditional_edges("agent", route_after_agent, {"tools": "tools", END: END}) graph.add_edge("tools", "agent") app = graph.compile()构图完成后,运行时调用方式和 AgentExecutor 很像:
result = app.invoke({"messages": [{"type": "human", "content": "订单 2026001 发货了没?"}]}) print(result["messages"][-1].content)这段代码有三个参数细节要讲清楚。第一,AgentState 的 messages 字段用 Annotated[list, add_messages] 标注,add_messages 是 reducer,它决定「节点返回的 messages 和原有 messages 是合并而不是覆盖」,没有这个标注,每一轮都会把历史消息丢掉,Agent 会瞬间失忆。第二,run_tools 里构造 ToolMessage 时必须带上 tool_call_id,这个 id 必须和 AIMessage 返回的 tool_calls 里那个 id 严格一致,模型靠它把工具结果和之前的调用请求对应起来,对不上就报错。第三,add_conditional_edges 的第三个参数是映射表,route_after_agent 返回 "tools" 就走工具节点,返回 END 就结束整个图——这就是「条件路由」的落点。
4.3 进阶:Checkpointer 做多轮持久化,interrupt 做人工审批
LangGraph 相比 AgentExecutor 最实用的两个进阶能力,一个是多轮持久化,一个是人工打断。多轮持久化用 Checkpointer:把编译前的 MemorySaver 传入 compile,invoke 时携带一个 thread_id,同一线程下的多轮对话就会自动共享历史。这个机制解决的是「用户关掉页面再回来,Agent 还认不认得这件事」的问题,在客服场景几乎必用。
from langgraph.checkpoint.memory import MemorySaver config = {"configurable": {"thread_id": "order-2026001"}} app = graph.compile(checkpointer=MemorySaver()) result = app.invoke( {"messages": [{"type": "human", "content": "刚才我问的订单运费是多少?"}]}, config, )人工审批适合用在转账、发消息、删除数据这类敏感动作上。通过 interrupt 节点,图执行到这里会暂停,把审批请求抛给外部系统,等人点完「同意」再恢复执行。很多团队上生产时会把「所有写操作都过一遍 interrupt」,听起来麻烦,实际上是在给模型行为兜底——模型可以出错,但错误不能直接落到业务数据上。
5. 避坑清单:Agent 实战最容易翻车的 4 类问题
5.1 温度设置与 system prompt 玄学:工具参数为什么会乱
现象:模型明明声明了工具,却把 order_id 填成数字而非字符串,或者漏掉必填参数,甚至自己拼出一个不存在的工具名。排查到最后,问题往往出在 temperature 和 prompt 的相对关系上。
原因:temperature 大于 0 时,模型采样会引入随机性。你把它调到 0.7,对话生成确实更「有创造力」,但结构化输出也一起被污染了。工具调用的本质是让模型在约束空间里做选择,随机性对这种任务是有害的。
解决:凡是涉及工具调用的节点,temperature 一律设 0;需要多样性的文本生成单独开一个节点、单独配一个模型实例。system prompt 里明确写「必须通过工具获取数据,禁止编造」,同时工具描述尽量带上业务上常见的别名。这不是玄学,是概率问题——你把随机性降到最低,再用 prompt 把选择空间收窄,翻车概率自然下来。
5.2 工具返回格式不统一:LLM 拿到非字符串直接崩
现象:Agent 第一轮调用工具后,报错信息指向 tool_calls processing failure,或者模型把工具返回的 None、dict 当成了「查询不到结果」,然后自己编一个答案。
原因:工具函数返回了 Python 对象而不是字符串。LangChain 虽然会尝试把非字符串结果做序列化,但只要遇到异常情况,返回给模型的内容就不可控。模型侧要求的是干净的文本输入,任何反序列化残留都会干扰后续推理。
解决:所有 @tool 函数的返回类型强制写成 str,内部用 try/except 包住真实调用:
@tool def get_order_status(order_id: str) -> str: """查询订单状态,永远返回字符串。""" try: data = upstream_api.get(order_id) return json.dumps(data, ensure_ascii=False) except Exception as exc: return f"查询失败:{exc}"这个写法保证了两点:模型拿到的永远是合法文本;即使上游接口挂了,模型也能拿到一个明确的错误状态,而不是异常堆栈。把异常吞进工具内部,是 Agent 工程里最基本的后悔药。
5.3 上下文无限膨胀:多轮对话后 Agent 开始「失忆」
现象:单轮查询表现完美,跑到第 10 轮、第 15 轮,模型开始重复调用同一个工具,或者把用户最早提到的订单号忘掉,甚至答非所问。
原因:messages 列表只增不减,很快逼近上下文长度上限。超过模型的有效工作窗口后,最早的关键信息(比如订单号)被截断,模型只剩最近几轮的内容,看起来就像「失忆」。
解决:在 LangGraph 的工作流里,用 trim_messages 对传入模型的 messages 做裁剪,保留 system 和最近几轮,而不是一股脑全塞:
from langchain_core.messages import trim_messages trimmer = trim_messages( max_tokens=4000, strategy="last", start_on="human", include_system=True, ) trimmed_messages = trimmer.invoke(state["messages"])另一个更彻底的做法是把关键业务字段(订单号、用户 id)单独放 state 字段,不走 messages 列表,每次模型需要时从 state 里直接取。我倾向于两者结合:state 管关键数据,trim 管对话历史。只做裁剪不做关键字段沉淀,历史一长照样丢信息。
5.4 本地小模型跑 LangGraph:路由不准与超时边界
现象:把 Qwen 7B 这类本地模型接进 LangGraph,agent 节点经常不输出 tool_calls,或者 route_after_agent 把它误判成结束;偶尔调用成功了,又因为推理太慢触发 HTTP 超时。
原因:小模型的 instruction following 能力和工具调用格式稳定性都比大模型弱,工具 Schema 稍微复杂一点,它就不知道该怎么输出。另一个坑是本地推理速度慢,LangChain 侧默认的请求超时撑不住 Agent 循环的多轮往返。
解决:本地小模型优先选择专门做过 tool calling 微调的版本,或者直接换 70B 级别的模型;工具描述写得更直白,减少嵌套参数。超时方面,在 ChatOpenAI 里显式设置 timeout 参数,并把 max_iterations 调小,避免模型卡在某轮循环里反复重试。记住一条边界:小模型能跑通 demo,不代表能扛住生产;路由不准的问题,不是你 prompt 写得不够好,而是模型能力天花板摆在那里。
6. 面试自检:5 道高频题加一条命令验证 Agent 掌握度
面试题库要背的东西很多,但如果只能押五道题,我会押下面这些。它们分别卡住了架构认知、底层原理、框架理解和实战排查四个维度:
| 高频面试题 | 考察点 |
|---|---|
| Agent 和 Chatbot 的本质区别是什么 | 是否理解工具调用与循环 |
| function calling 的原理,为什么模型不是「会搜索」 | 是否理解结构化输出与外部执行分离 |
| ReAct 文本推理和原生 Tool Calling 的差别 | 是否真正写过 Agent 而非只背概念 |
| LangGraph 的 state 为什么要用 add_messages 做 reducer | 是否理解状态合并机制 |
| 多轮对话 20 轮后质量下降怎么排查 | 是否有上下文管理实战经验 |
这五题全答上来,面试基本能过技术面。但要验证自己真学会了,不是靠背题,我习惯用一个 20 轮成功率脚本:准备一组「必须调用工具才能回答」的问题,跑 20 轮,统计工具调用命中率和最终答案正确率。
from your_project.agent import build_agent cases = [ "查询订单 2026001 的状态", "计算到杭州 3kg 的运费", "先查询订单,再根据结果计算运费", "你好", # 此条不应触发工具调用 ] def main(): agent = build_agent() passed = 0 for question in cases: result = agent.invoke({"input": question}) hit_tool = "tool_calls" in str(result) and len(result.get("tool_calls", [])) > 0 expected = question.startswith("查询") or question.startswith("计算") if hit_tool == expected: passed += 1 print(f"success_rate={passed / len(cases):.0%}") if __name__ == "__main__": main()成功率在 90% 以下,回头检查工具描述、temperature 和上下文裁剪策略;达到 90% 以上,再考虑加并发、加人工审批这类生产特性。我每接手一个 Agent 项目,第一件事就是把这类脚本丢进去跑一遍,这算不上什么聪明技巧,只是被坑过太多次换来的习惯。希望帮到你。
本文还有配套的精品资源,点击获取