尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从零构建智能体:LangChain与LangGraph实战入门指南

从零构建智能体:LangChain与LangGraph实战入门指南 最近好几个做后端和算法的朋友都在问我 Agent 开发到底怎么入门说 LangChain 文档翻了好几遍、示例代码也能跑但一动手做自己的智能体还是发懵。这篇笔记是我自己从零啃 Agent 的踩坑记录核心目标就一个把“Agent 到底是什么、LangChain 怎么帮你把它跑起来”这两件事讲透。看完你至少能写出一个带工具调用的最小智能体也知道下一步该往哪个方向深挖。这篇笔记更适合两类人一类是写过 Python、但没系统接触过 Agent 的开发者另一类是已经在用 LangChain 拼 Prompt 调模型、但觉得“这不像智能体”的人。如果你已经能用 LangGraph 写出多 Agent 协作可以直接跳到第六节看框架边界。1. 先搞清楚一件事Agent 不等于“调一下大模型”这个点不说清后面全是在拿工具箱当创可贴。我见过太多所谓“Agent 项目”本质是脚本加 Prompt用户问一句程序把问题塞进模板扔给大模型返回一段文字。这种流程当然能用但它不是 Agent。真正的差距在“决策权”到底在谁手里。1.1 多数“智能体项目”其实是脚本加 Prompt普通的大模型调用流程是死的用户输入拼 Prompt调模型输出。所有分支逻辑都需要开发者在代码里写死模型没有机会根据中间结果改变自己的行动路径。举一个看得见摸得着的例子。你写一个客服机器人用户说“我想查一下订单状态”普通脚本的做法是写一个if 订单 in user_query去命中规则然后查数据库把结果拼进 Prompt 再丢给模型润色。规则多了以后你会发现这个if链条越来越长用户表达稍微换一种说法就漏接。而 Agent 的做法是直接把“查订单状态”封装成一个工具把用户问题交给模型让模型自己判断“这个问题需要调用订单查询工具”然后自动执行、拿结果、组织回答。模型在流程当中是有决策权的开发者不再需要把所有规则穷举出来。这两者没有绝对的高下之分普通脚本在某些简单场景下性能更好、成本更低但涉及复杂任务编排时Agent 的开发效率和泛化能力明显更强。1.2 Agent 的核心机制模型在循环里做决策Agent 的本质是一个循环很多人叫它 ReAct也就是 Reasoning推理加 Acting行动。整个循环是这样转的模型阅读用户问题先想“要回答这个问题我需要什么信息”。如果信息不够模型会提出“我打算调用某个工具”并给出参数。系统执行这个工具把结果返回给模型。模型看到工具结果后再判断“这些信息够不够还要不要继续调其他工具”。如果够了模型输出最终答案循环结束。这个循环最关键的改变在于每一步的“下一步做什么”是模型根据当前上下文动态决定的而不是开发者预先写死的。这也是为什么 Agent 能处理那些步骤不固定的开放任务——比如“帮我查一下北京和上海的天气温差再算算高铁两个小时能不能到”。我自己刚学的时候为了搞懂这个循环特意不去碰框架写了一个极简版 ReAct 循环核心代码大概长这样for step in range(max_steps): resp model.invoke(messages) action parse_action(resp.content) if action is None: return resp.content tool_result run_tool(action[name], action[input]) messages.append(resp) messages.append({role: tool, content: str(tool_result)}) return 超过最大循环步数主动停止这个代码很短但思路非常纯粹模型说调什么工具系统就调什么结果塞回去模型再决定下一步。max_steps是必须加的否则模型可能一直在“调用工具”和“继续思考”之间打转白白烧掉你的 Token。1.3 那为什么还要学 LangChain 和 LangGraph手写循环能帮你理解原理但到了真实项目里问题会变得很具体多个工具的注册和参数校验怎么做工具调用失败要不要重试几十轮对话历史怎么裁剪多个用户会话怎么隔离这些通用问题如果都自己造轮子项目还没开始就废了。LangChain 把模型封装、工具定义、输出解析这些组件标准化了LangGraph 则把循环、分支、多 Agent 协作这些流程编排问题做成了图结构你只需要关注业务本身。我建议的学习路线是先手写一个极简 ReAct 循环理解原理再用 LangChain 的组件把它们串起来。这样你后面遇到任何框架报错心里都有一个“底层发生了什么”的坐标系不至于完全懵。2. 认识 LangChain 里的智能体组件LangChain 不是某一个巨无霸库它是一堆组件的集合。做 Agent 开发你最先要认识的是四个角色模型、工具、记忆、编排器。理解这四个组件各自的职责和边界比背 API 重要得多。2.1 四个核心组件模型、工具、记忆、编排器先给一个直观的分工说明组件职责对应 LangChain 里的常见类型模型决策大脑理解意图并决定下一步动作ChatOpenAI、ChatOllama 等工具模型可调用的外部能力tool 装饰器定义的函数记忆保存对话上下文和中间状态MemorySaver、BaseStore编排器控制循环判断何时停止LangGraph 的状态图、AgentExecutor模型这块最容易踩坑。Agent 开发对模型有一个硬性要求必须支持工具调用也就是 Function Calling。你现在随便拿一个老模型或者不支持工具调用的本地小模型你会发现不管怎么调 Prompt模型都只会输出“我建议你手动去查”因为它在模型层面就没有输出结构化工具调用指令的能力。记忆也不是可选项。没有记忆的 Agent 就是一个失忆的客服用户上一秒说完需求下一秒它就忘。但记忆又不能无限堆上下文窗口总有上限所以需要记忆管理策略。编排器是灵魂。它决定你整个 Agent 的运行逻辑先调用哪个节点、工具返回后走哪条分支、失败后要不要重试、达到什么条件就终止输出。2.2 工具定义方式与规范LangChain 里面定义一个工具非常简单用tool装饰器就行。函数的文档字符串会自动变成模型的工具描述函数签名里的类型注解会生成参数 JSON Schema。from langchain_core.tools import tool tool def calculator(expression: str) - str: 计算简单数学表达式支持 - * / 和括号。传入表达式字符串返回计算结果。 allowed set(0123456789-*/(). ) if not set(expression).issubset(allowed): return 非法表达式请检查输入 return str(eval(expression, {__builtins__: {}}, {}))这里有个安全细节eval在真实项目里尽量不要直接面向用户输入开放我用白名单字符集和空__builtins__只是演示。生产环境更推荐用ast.literal_eval或者专门写一个表达式解析器避免注入风险。再看一个天气工具tool def get_weather(city: str) - str: 查询指定城市的当前天气。传入城市名返回天气描述。 weather_map {北京: 晴25°C, 上海: 多云28°C} return weather_map.get(city, 暂不支持该城市)定义工具最关键的不是代码本身而是函数名和描述。函数名要直观比如get_weather而不是fun1描述要写清楚“什么时候用、传什么、返回什么”因为模型是靠这段描述来判断该不该调这个工具的。描述写得含糊模型就会频繁误调用。2.3 为什么现在主流推荐 LangGraph 而不是 AgentExecutor如果你翻老教程会看到大量initialize_agent加AgentExecutor的写法。这套接口在 LangChain 0.3 之前很流行但现在已经被标记为 deprecated官方推荐用 LangGraph 的create_agent来创建 Agent。原因很简单AgentExecutor 是一条单行管道脚本从上往下执行最多套一个循环它对复杂分支、人工审核、多 Agent 协作基本无能为力。而 LangGraph 把整个流程画成一张有向图节点是操作边是跳转逻辑Agent 只是图里的一个节点。对比一下能力AgentExecutorLangGraph循环执行内置图结构自由编排分支跳转弱强支持条件边人工介入中断不支持支持多 Agent 协作基本不支持原生支持调试可视化日志状态快照、逐步回放所以你现在看到的新项目、新招聘需求基本都是 LangGraph 这套体系。我不是说老代码没用理解它的设计思路有帮助但新项目别再踩旧坑。3. 实操用代码跑通一个带工具调用的 Agent理论讲再多不如跑通一个实在的例子。这一节我会带你从环境准备开始搭一个能同时处理“查天气”和“算数学题”的智能体。3.1 环境准备与依赖安装建议用 Python 3.10 以上版本创建好虚拟环境后直接装这几个包pip install -U langchain langchain-openai langchain-community langgraph这里有两个细节。第一为什么不装langchain老版本因为新版框架结构和 API 变化很大你搜到的很多老教程会给你装一堆过时代码装最新版至少能保证和官方文档一致。第二langgraph是独立的包不要漏装create_agent在这个包里。模型我建议新手先用带工具调用能力且稳定的云端模型比如gpt-4o-mini等整个流程跑通以后再考虑换 Ollama 本地模型。设置 API Key 的方式很简单import os os.environ[OPENAI_API_KEY] sk-你的key from langchain_openai import ChatOpenAI model ChatOpenAI(modelgpt-4o-mini, temperature0)这里把temperature设成 0 是我个人的执念。Agent 场景里我们希望模型在“决定要不要调工具”这件事上尽量稳定随机性越低越好。温度拉高以后模型可能会在同一个问题上给出完全不同的行动路径调试起来会非常痛苦。3.2 定义工具并创建 Agent把上面两个工具函数拿过来然后用create_agent组装from langgraph.prebuilt import create_agent tools [calculator, get_weather] agent create_agent( modelmodel, toolstools, system_prompt( 你是智能助理。当问题涉及精确计算或实时天气时必须调用对应工具。 调用工具拿到结果后再组织最终回答。如果工具返回异常如实说明失败原因。 ), ) response agent.invoke( {messages: [(user, 北京今天多少度顺便算一下 (2517)*3 等于多少)]}, config{recursion_limit: 20}, ) print(response[messages])执行这段代码你会看到response里是一个消息列表最后一条消息就是 Agent 的最终回答。中间还有模型调用工具的记录、工具返回的结果这些都被存放在消息列表里。很多第一次用的人不知道去哪里找中间过程关键就在这个列表里。3.3 打开调试看它到底“思考”了什么为了让过程更透明创建 Agent 时可以开启调试agent create_agent( modelmodel, toolstools, system_promptSYSTEM_PROMPT, debugTrue, )开启以后控制台会输出模型每一步的工具调用请求和工具执行结果。你能清晰地看到模型先调用了get_weather返回“晴25°C”然后又调用了calculator返回计算数值最后把两个结果拼成一句完整回答。我一直觉得Agent 开发最大的心智门槛不是写代码而是习惯“模型的思考过程可见”。传统编程里程序怎么走完全由你控制但 Agent 里模型会在你控制之外决定调用什么工具。如果不能实时观察它的推理轨迹出问题基本没法排查。3.4 加记忆让 Agent 记住多轮对话默认情况下create_agent不保留多轮会话记忆每次invoke都是独立的。如果你需要 Agent 记住用户上一句话需要给它挂一个 Checkpointerfrom langgraph.checkpoint.memory import MemorySaver checkpointer MemorySaver() agent create_agent( modelmodel, tools[calculator], checkpointercheckpointer, ) thread_config {configurable: {thread_id: user-001}} agent.invoke({messages: [(user, 我叫小明)]}, configthread_config) agent.invoke({messages: [(user, 我叫什么名字)]}, configthread_config)这里最关键的是thread_id它就是会话 ID。同一个thread_id下的多轮调用来共享一套消息历史不同thread_id之间完全隔离。MemorySaver适合本地测试重启进程后记忆会丢生产环境一般用 PostgreSQL 或者 Redis 这类持久化存储。4. 深入理解几个关键机制跑通 Demo 只是第一步。如果只满足于“能跑”你会在后面对接真实业务时处处碰壁。这一节重点讲清楚三个机制Tool Calling 到底是怎么发生的、怎么让模型输出结构化结果、以及 Prompt 在 Agent 里的真实作用。4.1 Tool Calling 是怎么发生的很多人有一个误解觉得模型“会调用工具”是模型自己去执行了函数。实际上模型根本没执行任何东西模型做的是输出一个结构化的 JSON告诉你“我想调用calculator参数是(2517)*3”。真正执行函数的是你的代码、是 LangChain 框架。与普通文本生成不同支持 Tool Calling 的模型在训练时就接受了“输出结构化调用指令”的专门优化。当它判断需要查信息或执行计算时会在回复中带上一个特殊字段表示要发起的工具调用。这就解释了为什么工具描述那么重要。模型不是看到函数源码它看到的是你给它的 JSON Schema包括工具名、描述、参数格式。描述越清晰模型越容易在正确时机调用正确的工具。有些项目工具调用准确率特别低第一个该检查的就是工具描述写得够不够好。4.2 用结构化输出约束最终结果生产环境里Agent 的回答通常不是给人看一眼就完事而是要对接业务系统。比如客服助手判单你希望它返回的是一个结构化的 JSON包含处理状态、原因分类、回复文案而不是一大段散文。LangChain 支持with_structured_output配合 Pydantic 模型定义输出结构from pydantic import BaseModel, Field class TicketResult(BaseModel): category: str Field(description问题分类) confidence: float Field(description置信度0到1之间) reply: str Field(description给用户的回复文案) structured_model model.with_structured_output(TicketResult) result structured_model.invoke(我的订单三天了还没发货帮我问问) print(result.category)这样拿到的就是一个校验过的TicketResult对象字段缺失或类型不对会直接报错不用再手写正则去解析文本。把 Agent 的输出和业务系统对接这一层结构化是少不了的。4.3 Prompt 在 Agent 里的角色和开放心态传统大模型应用中Prompt 决定了回答质量。Agent 里 Prompt 依然重要但它的职责变了——重点不是让模型“说得好”而是让模型“知道什么时候该动、什么时候该停”。我常用的系统 Prompt 模板一般是这样的逻辑你是智能助理。 1. 面对实时信息、精确计算、数据查询类问题必须先调用对应工具禁止凭记忆编造。 2. 调用工具后先解释结果再给结论。 3. 工具返回错误时向用户说明失败原因不要假装成功。 4. 如果不需要工具就能回答直接回答。第四点很容易被忽略。有些人为了让 Agent“看起来智能”恨不得所有问题都走一遍工具调用。其实很多时候用户就是问一句常识你让模型调一个无关工具只会增加延迟和成本。5. 常见问题与排查技巧实录这一节整理的是我实际开发中踩过的坑不是从文档里抄来的。很多问题你早晚会遇到先存着省得到时候抓瞎。5.1 模型死活不调用工具症状你明明绑定了工具但不管怎么问模型都直接给出答案完全不碰工具。先按顺序排查模型本身是否支持 Tool Calling有些模型即使支持也要确认 LangChain 的集成包已经正确加载。工具描述里是否说清了“什么时候用”如果你只写“计算器”模型猜不透什么时候该用。temperature是不是太高温度高会导致模型行为不稳定工具调用指令可能被“随机掉”。系统 Prompt 有没有明确要求“必须调用工具”对于拿不准的问题模型倾向于保守你要主动给它授权。我见过最隐蔽的一个问题工具函数名取的太抽象比如func_a、process_data模型根本不知道这是干嘛的。工具名就是给模型看的接口名别省那几个字。5.2 上下文爆炸Token 消耗太大Agent 的每一轮循环都会把历史消息和工具结果重新发送给模型。假设一个工具调用循环要经历 8 轮每轮上下文 2000 Token一轮完整任务就是 16000 Token 起步这还不算多用户并发的成本。对策有三个控制历史消息长度只保留最近几轮对话。工具结果只保留关键信息不要把一个超大 JSON 整个塞回上下文。用摘要记忆把早期对话压缩成一段摘要而不是保留全部原文。Token 消耗不是算法问题是成本问题项目上线前一定要压测。5.3 工具返回解析失败或内容不可用工具返回的结果对模型来说就是一段文本。如果工具返回一段特别长的 JSON模型很可能被里面的次要字段带偏答非所问。我的习惯是工具返回前就做清理。比如数据库查询直接拼成“订单 xxx 的状态为已发货发货时间为 2025-06-01”而不是把整个记录对象原样返回。5.4 版本兼容问题速查LangChain 版本更新频繁你在网上搜教程时很容易遇到“这段代码跑不通”的情况。这里给一个新旧对照表方便排查功能旧写法新写法创建 Agentinitialize_agent(...)create_agent(...)执行 Agentagent.run(...)agent.invoke(...)对话记忆ConversationBufferWindowMemoryCheckpointer 消息历史持久化存储缺少标准方案BaseStore及相关实现我现在的建议很直接新项目就装最新版langchain和langgraph遇到文档里的 API 不存在优先去官方文档查最新签名不要硬套旧代码。还有一个经常出现的报错是GraphRecursionError: Recursion limit reached意思就是 Agent 循环次数超过了限制。你可以加大recursion_limit但我建议先想想为什么模型需要那么多步才能完成回答很多时候是工具结果不清晰导致模型反复调用。6. 下一步怎么走学习路线与框架边界第一篇笔记讲到这里已经覆盖了 Agent 最核心的工作原理和一个最小可运行项目。但我知道你肯定不满足于此所以我再给一条可执行的进阶路线。6.1 推荐的学习顺序我的建议按这个顺序推进不看框架手写一个 ReAct 循环理解模型决策和工具调用的闭环。用 LangChain 的组件重写一遍了解模型封装、工具定义、输出解析。换用 LangGraph从图结构角度理解编排。挑一个真实业务场景做项目比如客服工单分类、本地知识库问答。最后再研究 Agent 的评估体系也就是 Agent Evals。不要一上来就背 LangChain API背了也会忘关键是理解链路。框架更新太快理解原理比记函数名值钱。6.2 LangChain 和 LangGraph 到底是什么关系这个问题最近被问得太多了一句话总结LangChain 提供组件LangGraph 提供编排能力。LangChain 负责和模型打交道、定义工具、处理输入输出LangGraph 负责把这些组件连成一张可以循环、分支、暂停的图。从职责上看两者是组合关系不是竞品关系。新的 Agent 项目基本都是 LangChain 组件加 LangGraph 编排的搭配。现在很多低代码平台比如 Dify、Coze底层其实也在做类似的事情你理解了 LangGraph 的设计再去看这些平台就很容易看穿它们的套路。6.3 多 Agent 开发初探当你单 Agent 玩熟了会开始遇到一个现象任务复杂以后一个 Agent 既要规划、又要执行、还要自我检查Prompt 越写越长效果却越来越差。这时候就该拆多 Agent 了。常见的模式是一个“主管 Agent”负责任务分发下面挂多个“执行 Agent”每个执行 Agent 只负责一个窄领域。这种结构在 LangGraph 里很好实现本质上就是图里面再加几个节点和几条边。但我要泼一盆冷水多 Agent 不是越多越好。每多一个 Agent就多一层延迟、多一份 Token 成本、多一套失败逻辑。能单 Agent 解决的事就别硬拆成三个 Agent。生产环境里“架构简单”本身就是一个极大的优点多 Agent 是最后手段不是炫技工具。最后分享一点我个人的体会从手写 ReAct 再回过头用create_agent你会特别清楚地感受到框架到底替你干了什么。如果你也在入门我强烈建议你先花一晚手写那个极简循环再去用 LangGraph那种“原来如此”的感觉比看十篇教程都有效。后续我会继续更新 LangGraph 的状态管理、多 Agent 协作模式以及 Agent 上线前的评测方案。
返回列表