LangChain+LangGraph从零搭建AI智能体,踩坑完整教程
文章目录
P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。
前言
2026年你要是没写过AI Agent,出门都不好意思跟同行打招呼。就像2018年没买过比特币,2020年没炒过NFT,2022年没玩过AIGC——咱们程序员圈子的焦虑,永远比技术更新快三个版本。
所以今天咱们就来手搓一个Agent。不是那种"调个API就敢说自己是AI工程师"的Hello World,而是一个真正能动手、能思考、能记仇——不对,能记上下文——的完整Agent。全程TypeScript,全程LangChain,全程踩坑。
第一章:项目初始化,或者叫"npm install地狱"
搭建项目的第一步永远是创建文件夹。我给它起名叫"lingshi",灵感来源于我写完这个项目后可能剩下的头发数量——零星的几根,简称"零拾"。
然后安装依赖。看到这一串包名了吗?langchain、@langchain/anthropic、@langchain/core、@langchain/langgraph、deepagents、zod、dotenv……这阵仗,比我女朋友的购物车还长。最离谱的是那个叫"deepagents"的包,听起来像是某种深海特工组织,实际上它只是帮我们少写几行样板代码的贴心小棉袄。
冷知识: pnpm的安装速度比npm快,不是因为技术更先进,而是因为npm在下载依赖的时候,会顺便帮你把前世今生的所有版本都下载一遍,生怕你错过任何一个历史时刻。
tsconfig.json的配置也有讲究。module要设成ESNext,moduleResolution要设成bundler,noEmit要设成true。翻译成人类语言就是:“我用tsx直接跑,tsc你别多管闲事,编译产物这玩意,生出来也是占硬盘空间的电子垃圾。”
环境变量文件.env里藏着一个骚操作:ANTHROPIC_BASE_URL指向一个代理服务器,底层实际跑的是qwen3.7-plus。这就好比你去米其林餐厅点餐,后厨实际给你炒的是楼下沙县小吃——但摆盘用的是米其林标准,所以吃起来感觉特别高级。
第二章:Agent到底是个啥?
很多人搞不清Agent和普通LLM的区别。我打个比方:普通LLM就是你那个只会动嘴的室友。你跟他说"帮我算一下128乘47",他回你:"根据我的训练数据,128和47都是正整数,乘法是一种基本的算术运算……"说了八百字,答案没给一个。
Agent不一样。Agent是你那个不仅会动嘴,还会动手翻计算器的室友。你问他128乘47,他二话不说掏出手机打开计算器,啪啪啪按完,告诉你"6016"。如果算错了,他甚至还会再按一遍——这就是Agent的核心竞争力:有手。
Agent的本质公式: Agent = LLM + 工具 + 一个死循环。LLM负责思考"我要不要用工具",工具负责执行"我真的去做了",循环负责保证"没做完就继续干,直到LLM说收工为止"。
这个循环的逻辑大概是这样的:LLM看着用户的提问,陷入沉思——"这题我会吗?不会。那我有工具吗?有。用哪个?计算器。参数是什么?a=128, b=47, operation=multiply。"然后工具执行完,把结果"6016"喂回去,LLM一看:“哦,原来答案是6016,那我包装一下,用人类语言说出来。”
整个过程就像你让实习生去打印文件。你不会自己去打印,你告诉实习生"去打印三份合同",实习生跑到打印机前操作,拿回来给你。你(LLM)是老板,实习生(工具)是执行者,打印机(外部系统)是最终干活的。唯一不同的是,LLM这个老板不会给实习生发工资,也不会在实习生做错的时候骂它——因为LLM骂了也没用,工具听不懂人话,它只认JSON参数。
第三章:定义工具,或者叫"给LLM装上义肢"
工具是Agent的手。没有工具的Agent,就像没有手的奥特曼——光会摆pose,打不了怪兽。咱们给Agent装两只手:一只叫calculator,负责算术;一只叫get_current_time,负责看表。
定义工具要用Zod写schema。Zod这玩意,本质上就是一个"参数说明书生成器"。你写z.number().describe(‘第一个数字’),框架就会把它翻译成JSON Schema发给LLM。LLM看到这份说明书,就知道:“哦,这个参数得是数字,而且它是第一个数字。”
重要警告: describe()里的描述一定要写清楚。如果你写z.number().describe(‘一个数字’),LLM就会一脸懵逼:"什么数字?干嘛用的?是我生日吗?"最后它可能会把温度当参数传过去,或者把股价当参数传过去——总之,LLM的想象力比你丰富得多,你得把它锁死在正确的理解轨道上。
计算器工具的代码看起来有点长,但核心逻辑就两行:switch判断operation,然后return结果。除法的时候加了个防零判断,因为除以零在数学上是不被允许的,在编程上会让你的程序直接原地爆炸,在情感上会让你的用户直接原地爆炸。
获取当前时间的工具更有意思。它的schema是z.object({}),一个空对象。这就好比你去餐厅点餐,服务员问你"要什么",你说"随便"——但这里的"随便"是字面意思,因为时间工具真的不需要任何参数。LLM看到空schema,就知道:“这个工具我直接调用就行,不用传参,比我的前任还省心。”
第四章:创建Agent,把大脑和义肢缝在一起
创建Agent用的是createDeepAgent。这个函数名听起来很深沉,像是某个哲学家的笔名,实际上它只是LangGraph的一个封装。LangGraph是LangChain的图结构引擎,专门用来管理Agent的决策流程——“先干什么,再干什么,如果出错怎么办,如果成功又怎么办”。
配置ChatModel的时候有两个骚操作。第一个是streaming: true,开启流式输出。这很重要,因为如果你用invoke,用户发完问题后要等好几秒才能看到回复。这几秒里用户在干嘛?在盯着空白屏幕发呆,在怀疑自己的网络是不是断了,在思考人生是不是就是这么虚无。而streaming能让用户看到AI在"打字"——虽然它实际上是在"吐token",但视觉效果上就是"它在思考,它在组织语言",用户的心理体验从"焦虑等待"变成了"沉浸式观看"。
streaming的心理学原理: 人类对"渐进式反馈"的容忍度远高于"一次性结果"。这就是为什么你等外卖的时候,App显示"骑手正在赶往商家"比直接显示"预计30分钟后送达"让你更安心——虽然实际上都是30分钟,但前者给了你"事情正在推进"的幻觉。
第二个骚操作是thinking参数。type: ‘enabled’, budget_tokens: 5000。这意思是:"模型啊,你在给出最终答案之前,可以先花5000个token进行内部推理。"就像考试的时候,老师允许你先打草稿。只不过这个草稿是透明的,用户能看到——当然你也可以选择不看,但既然都开了,为什么不看呢?看AI思考的过程,比看AI给出答案的过程有趣多了。
Agent的四个参数各司其职:model是大脑,tools是双手,systemPrompt是入职培训手册,checkpointer是记忆存储器。MemorySaver是内存版的记忆存储,特点是快,但重启就丢。生产环境建议换成PostgresSaver,虽然慢点,但至少你的Agent不会一觉醒来忘记自己是谁——这剧情太科幻了,不适合用在生产环境。
第五章:流式输出,或者叫"别让用户干瞪眼"
流式输出是Agent体验的分水岭。没有流式的Agent,就像没有进度条的下载——你根本不知道它是在努力工作,还是已经死机了。用户盯着空白屏幕的那几秒,足够他在心里把你的产品骂十八遍。
stream()配合streamMode: ‘messages’,每次yield出来的是一个[message, metadata]元组。message的类型有三种:'ai’是LLM的输出,'tool’是工具执行后的返回,'human’是用户消息——不过stream里一般不会出现human,除非你的用户是个话痨,在AI回答的过程中疯狂插嘴。
这里有个巨坑:AI消息的content字段有两种形态。没调用工具的时候,它是字符串,直接输出就行。调用了工具的时候,它变成了数组,里面可能有text块、tool_use块、thinking块。如果你只处理了字符串形态,那调用工具的时候输出就会一片空白——就像你准备了雨伞但只带了伞柄,下雨的时候才发现自己拿的是根棍子。
踩坑实录: 我最初只处理了string类型的content,结果调用计算器工具时输出为空。调试了半小时,最后发现content变成了数组。那一刻我的心情,就像花了半小时找手机,最后发现手机一直在自己手里——既愚蠢又无奈。
正确的处理方式是:先判断_getType()是不是’ai’,再看content是string还是Array。如果是数组,就遍历每个block,找到type为’text’的块,把它的text字段输出。如果是thinking块,就额外处理一下——后面会讲。
第六章:多轮对话,或者叫"给金鱼装上硬盘"
普通LLM的记忆能力,大概跟金鱼差不多——七秒,最多七秒。你问它"我叫什么名字",它说"我不知道"。你告诉它"我叫张三",它说"好的张三"。你紧接着问"我叫什么",它说"我不知道"。这不是AI,这是某种行为艺术。
Agent通过checkpointer解决了这个问题。核心机制是thread_id:你给每次对话分配一个唯一的thread_id,MemorySaver就会按这个ID把所有消息存起来。下次再调用的时候,只要thread_id不变,Agent就能看到之前的完整对话历史。
thread_id的哲学意义: thread_id就是Agent的"身份证"。同一个ID代表同一个"灵魂",不同ID代表不同的"转世"。你可以理解为:thread_id='session-1’的Agent记得你,thread_id='session-2’的Agent是个陌生人。这设定是不是很像某些玄幻小说的设定?
实际效果很惊艳。第一轮你问"128乘47等于多少",Agent回答"6016"。第二轮你直接说"算的不对吧"——注意,这句话里没有数字,没有运算,没有任何上下文信息。但Agent因为记得上一轮的内容,能理解你是在质疑之前的计算结果。它会重新审视,然后告诉你"我重新检查了一遍,128乘47确实是6016,不信你自己按计算器"。
这种"记得上下文"的能力,让Agent从"问答机器人"升级成了"对话伙伴"。虽然这个伙伴偶尔还是会算错,但至少它不会每次都问你"你是谁"——这已经比大部分人类客服强了。
第七章:Extended Thinking,或者叫"偷看AI的草稿纸"
Extended Thinking是Anthropic提供的一个能力,让模型在给出最终答案之前,先进行一段"内心独白"。你可以把它理解为:AI在考试的时候,允许你站在旁边看它打草稿。这草稿里可能写着"这题看起来是乘法,让我想想用哪个工具……哦对,calculator,参数是a=128, b=47, operation=multiply……"
开启thinking需要两个条件:一是模型本身支持,二是配置里显式设置maxTokens和thinking参数。maxTokens必须显式设置,这是Anthropic API的硬性要求——大概是因为他们怕AI思考得太投入,忘了还有最终答案要输出,最后把token全花在思考上,留给答案的就只剩一个"嗯……"
thinking的预算管理: budget_tokens: 5000的意思是"思考最多花5000个token"。如果AI是个哲学家,它可能会把5000个token全用来思考"生命的意义是什么",最后告诉你"128乘47等于一个关于存在的深刻问题"。所以预算管理很重要,不能让AI想太多。
处理thinking block的时候,我给它加了ANSI灰色转义码。在终端里,thinking内容会显示成灰色,和最终答案区分开。这就像你偷看学霸的草稿纸,草稿纸上的涂涂画画是灰色的,正式答题卡上的字迹是黑色的——虽然都是同一个人写的,但重要性不一样。
运行效果是这样的:用户问"128乘47等于多少",终端先输出一行灰色的"[思考] 用户想要计算128乘以47,这是一个乘法运算,我应该使用calculator工具……“,然后输出正常颜色的"128 × 47 = 6016”。整个过程就像看一场魔术表演:先让你看到幕后准备,再让你看到台前效果。
如果底层模型不支持thinking,这个block不会出现,输出行为和之前完全一致。这属于"优雅降级"——就像你买了辆带天窗的车,但天窗坏了,车照样能开,只是少了个看星星的功能。
第八章:回顾与展望,或者叫"终于写完了"
咱们从一个空文件夹开始,一步步搭了:TypeScript骨架、两个工具、一个Agent、流式输出、多轮对话、Extended Thinking。整个过程就像拼乐高:一开始只有一堆散件,最后拼出了一个能跑能跳还能思考的小机器人。
当然,这只是一个起点。后续你可以加更多工具——搜索、数据库查询、API调用、文件操作。你可以把MemorySaver换成持久化存储,让Agent的记忆跨越服务器重启。你可以给Agent加错误处理和重试机制,让它在工具调用失败的时候不会直接躺平。你可以构建一个Web界面,把流式输出通过SSE推到前端,让用户在浏览器里就能和Agent聊天。
最后的忠告: Agent的世界很大,但坑也很多。每当你觉得"这个功能应该很简单"的时候,LangChain就会跳出来给你上一课。保持耐心,保持幽默,保持随时能回滚代码的心态——这是Agent开发者的三大生存法则。
运行命令很简单:pnpm dev。然后你会看到三个测试场景依次输出:计算器工具调用、多轮对话上下文记忆、时间工具调用。如果一切正常,恭喜你,你现在已经是一个拥有AI Agent的程序员了——虽然这个Agent目前只会算数和看表,但至少它不会在你问"现在几点"的时候回答"我不知道,因为我没有工具"。
Agent的世界刚刚打开。这个项目只是一个起点,就像你学会骑自行车之后,接下来可以骑摩托车、开汽车、甚至开飞机——虽然开飞机需要驾照,但梦想总是要有的。万一实现了呢?
P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。
更多推荐


所有评论(0)