LangChain Agent 入门实战:从报错到跑通带记忆的交互式智能体(初学者保姆级教程)
LangChain Agent 入门实战:从报错到跑通带记忆的交互式智能体(初学者保姆级教程)
作者:风吹夏回
适合人群:零基础接触 LangChain Agent 的初学者,全程附可运行代码 + 踩坑解决方案
写在前面
大家好,我是风吹夏回。今天正式开始学习 LangChain 中的 Agent 智能体,从最开始的配置报错、无输出,一步步踩坑调试,最终跑通了带记忆能力的交互式对话 Agent。
这篇文章完全以初学者视角记录整个学习过程,所有代码都经过实测可直接运行,同时把我踩过的坑全部标注了出来,大家跟着抄代码就能复现效果,不用再走弯路。
本次学习使用的技术栈:
- 大模型:火山方舟豆包
doubao-seed-2.0-lite - 框架:LangChain + LangGraph
- 运行环境:Python 虚拟环境 + Windows 系统
一、前置准备:环境与依赖
先把基础环境搭好,建议全程用虚拟环境,避免依赖冲突。
1. 安装核心依赖包
pipinstalllangchain langchain-openai langchain-core langgraph python-dotenv2. 配置 .env 文件
在项目根目录新建.env文件,填入你的模型配置:
# 你的火山方舟API密钥 DEEPSEEK_API_KEY=ark-你的密钥 # 注意!必须是标准大模型接口,不能用coding接口 DEEPSEEK_BASE_URL=https://ark.cn-beijing.volces.com/api/v3⚠️ 第一个坑预警:火山方舟的
api/coding/v3是代码专属接口,不支持工具调用(Function Calling),一定要用/api/v3标准路径,否则Agent会没有任何输出。
二、第一阶段:第一个Agent的诞生
最开始我直接照着教程写,一运行就报错,先带大家把坑踩完,再跑通最简版本。
踩坑1:TavilySearch 密钥缺失报错
最开始的代码里加了 Tavily 搜索工具,运行直接报 Pydantic 校验错误:
ValidationError: Did not find tavily_api_key, please add an environment variable `TAVILY_API_KEY`原因:Tavily 是第三方联网搜索工具,必须单独注册申请密钥。
初学者解决方案:先不用第三方工具,用自定义的本地工具先把 Agent 主流程跑通,获得正反馈最重要。
最简可运行 Agent 完整代码
我们先实现一个「天气查询工具」,让 Agent 自主判断什么时候调用它。
fromlangchain.agentsimportcreate_agentfromlangchain_openaiimportChatOpenAIfromlangchain_core.toolsimporttoolfromdotenvimportload_dotenv,find_dotenvimportos# 加载环境变量dotenv_path=find_dotenv()load_dotenv(dotenv_path,override=True)api_key=os.getenv("DEEPSEEK_API_KEY")base_url=os.getenv("DEEPSEEK_BASE_URL")# 1. 初始化大模型llm=ChatOpenAI(model="doubao-seed-2.0-lite",api_key=api_key,base_url=base_url,temperature=0.7,)# 2. 定义自定义工具:天气查询@tooldefget_weather(city:str)->str:"""查询指定城市的实时天气情况,输入为城市名称,如北京、上海"""returnf"{city}今日天气:晴转多云,24-31℃,东南风2级"# 工具列表tools=[get_weather]# 3. 创建 Agentagent=create_agent(model=llm,tools=tools,system_prompt="你是一个智能助手,请根据用户的需求调用合适的工具来帮助他们。",)if__name__=="__main__":print("开始测试Agent...")# 一次性调用,查看完整执行链路result=agent.invoke({"messages":[{"role":"user","content":"北京今天天气怎么样?"}]})print("\n=== 完整执行链路 ===")formsginresult["messages"]:print(f"[{msg.type}]:{msg.content}")ifhasattr(msg,"tool_calls")andmsg.tool_calls:print(f" 工具调用:{msg.tool_calls}")运行后你会看到
输出会清晰展示 Agent 的完整工作循环:
user:用户提问ai:模型推理,决定调用get_weather工具,参数为北京tool:工具执行,返回天气结果ai:模型根据工具结果,生成自然语言最终回答
这就是 Agent 最核心的「感知→推理→行动→回复」循环,全程没有我们手动控制流程,完全是模型自主决策。
三、第二阶段:给Agent加上记忆
跑通基础版后你会发现:每次调用都是“失忆”的,上一轮说过的话下一轮就忘了。这显然不符合真实使用场景,接下来我们给 Agent 加上记忆能力。
核心概念
- Checkpointer:记忆存储器,自动保存每一轮的对话消息
- Thread ID:会话标识,同一个ID对应同一份记忆,不同ID完全隔离,用来区分不同用户
带记忆的 Agent 完整代码
只需要在之前的代码上新增3行核心代码即可:
fromlangchain.agentsimportcreate_agentfromlangchain_openaiimportChatOpenAIfromlangchain_core.toolsimporttoolfromdotenvimportload_dotenv,find_dotenvimportos# 新增:导入内存存储器fromlanggraph.checkpoint.memoryimportInMemorySaver dotenv_path=find_dotenv()load_dotenv(dotenv_path,override=True)api_key=os.getenv("DEEPSEEK_API_KEY")base_url=os.getenv("DEEPSEEK_BASE_URL")llm=ChatOpenAI(model="doubao-seed-2.0-lite",api_key=api_key,base_url=base_url,temperature=0.7,)@tooldefget_weather(city:str)->str:"""查询指定城市的实时天气情况,输入为城市名称,如北京、上海"""returnf"{city}今日天气:晴转多云,24-31℃,东南风2级"tools=[get_weather]# 新增:创建记忆存储器checkpointer=InMemorySaver()agent=create_agent(model=llm,tools=tools,system_prompt="你是一个智能助手,请根据用户的需求调用合适的工具来帮助他们。",# 新增:传入记忆存储器checkpointer=checkpointer,)if__name__=="__main__":# 同一个 thread_id 代表同一场对话config={"configurable":{"thread_id":"user_001"}}print("="*50)print("第1轮对话")print("="*50)result1=agent.invoke({"messages":[{"role":"user","content":"你好,我叫小明,在北京"}]},config=config)print("AI回复:",result1["messages"][-1].content)print("\n"+"="*50)print("第2轮对话(相同thread_id,有记忆)")print("="*50)result2=agent.invoke({"messages":[{"role":"user","content":"我叫什么名字?我所在的城市今天天气怎么样?"}]},config=config)print("AI回复:",result2["messages"][-1].content)print("\n"+"="*50)print("第3轮对话(换thread_id,无记忆)")print("="*50)result3=agent.invoke({"messages":[{"role":"user","content":"我叫什么名字?"}]},config={"configurable":{"thread_id":"user_002"}})print("AI回复:",result3["messages"][-1].content)效果验证
- 第2轮:Agent能准确说出你的名字,并且自动调用天气工具查询北京天气 → 记忆生效
- 第3轮:更换 Thread ID 后,Agent表示不知道你的名字 → 会话完全隔离
💡 小提示:
InMemorySaver是内存存储,程序重启后记忆会清空,适合开发调试。生产环境可以换成SqliteSaver、RedisSaver做持久化存储。
四、第三阶段:升级交互式对话
到这里功能都跑通了,但每次都要改代码输入问题太麻烦。我们把它改造成实时聊天模式,像跟微信聊天一样和 Agent 对话,体验感直接拉满。
交互式对话完整代码
输入退出、exit即可结束程序,全程保留记忆,还能看到 Agent 的思考和工具调用过程。
fromlangchain.agentsimportcreate_agentfromlangchain_openaiimportChatOpenAIfromlangchain_core.toolsimporttoolfromdotenvimportload_dotenv,find_dotenvimportosfromlanggraph.checkpoint.memoryimportInMemorySaver# 加载环境变量dotenv_path=find_dotenv()load_dotenv(dotenv_path,override=True)api_key=os.getenv("DEEPSEEK_API_KEY")base_url=os.getenv("DEEPSEEK_BASE_URL")# 初始化大模型llm=ChatOpenAI(model="doubao-seed-2.0-lite",api_key=api_key,base_url=base_url,temperature=0.7,)# 自定义工具@tooldefget_weather(city:str)->str:"""查询指定城市的实时天气情况,输入为城市名称,如北京、上海"""returnf"{city}今日天气:晴转多云,24-31℃,东南风2级"tools=[get_weather]# 记忆配置:固定会话ID,全程保留记忆checkpointer=InMemorySaver()config={"configurable":{"thread_id":"chat_session_001"}}# 创建 Agentagent=create_agent(model=llm,tools=tools,system_prompt="你是一个智能助手,请根据用户的需求调用合适的工具来帮助他们。",checkpointer=checkpointer,)# 交互式对话主程序if__name__=="__main__":print("="*60)print("🤖 Agent 交互式对话已启动")print("💡 输入问题即可对话,输入 退出/exit/quit 结束")print("="*60+"\n")whileTrue:# 获取用户输入user_input=input("👤 你:").strip()# 退出判断ifuser_input.lower()in["退出","exit","quit"]:print("\n👋 对话已结束,再见!")break# 空输入跳过ifnotuser_input:continueprint("-"*60)# 流式执行,展示完整过程forstep_index,stepinenumerate(agent.stream({"messages":[{"role":"user","content":user_input}]},config=config),start=1):# 兼容不同版本的返回结构messages=step.get("messages",[])ifnotmessages:forkeyinstep:ifisinstance(step[key],dict)and"messages"instep[key]:messages=step[key]["messages"]breakifnotmessages:continuelast_msg=messages[-1]# 模型决定调用工具iflast_msg.type=="ai"andlast_msg.tool_calls:print(f"🧠 [思考中] 决定调用工具:")fortool_callinlast_msg.tool_calls:print(f" └─ 工具:{tool_call['name']},参数:{tool_call['args']}")# 工具执行返回结果eliflast_msg.type=="tool":print(f"🔧 [工具执行] 返回结果:{last_msg.content}")# 最终回复eliflast_msg.type=="ai"andnotlast_msg.tool_calls:print(f"\n🤖 Agent:{last_msg.content}")print("-"*60+"\n")推荐体验流程
大家可以按这个顺序测试,完整感受记忆 + 工具调用的能力:
- 第一轮输入:
我叫小明,我在长沙 - 第二轮输入:
我叫什么名字? - 第三轮输入:
我所在的城市今天天气怎么样? - 第四轮输入:
刚才我们聊了什么?
五、今天踩过的坑总结
作为初学者,这几个坑非常容易踩,特意整理出来帮大家避坑:
| 报错/问题 | 原因 | 解决方案 |
|---|---|---|
| TavilySearch 报 value_error 缺少密钥 | 没有配置 Tavily 的 API Key | 初学者先移除第三方工具,用自定义工具先跑通主流程 |
| 程序正常退出但没有任何输出 | 用了 coding 专属接口,不支持工具调用 | 把 base_url 改成标准路径/api/v3 |
| 记忆不生效 | 调用时没传 config 和 thread_id | 每次 invoke/stream 都必须传入带 thread_id 的 config |
| 流式输出什么都不打印 | 返回结构和判断条件不匹配 | 先打印原始 step 的键名,再适配结构 |
六、下一步学习规划
今天把 Agent 的核心基础都跑通了,接下来的学习路线:
- 消息压缩中间件:解决长对话 Token 膨胀的问题
- 人工审核中间件:给高风险操作加上人类确认环节
- MCP 协议:标准化接入第三方工具服务
- 综合项目:做一个完整的智能客服 Agent
后续我会继续更新学习笔记,把每一步的实战代码和踩坑记录都分享出来。
最后
作为初学者,学习 Agent 不用一开始就堆很多功能,先跑通最小 Demo,理解核心的「自主决策循环」,再一步步加能力,是最稳妥的学习方式。
如果这篇文章对你有帮助,欢迎点赞收藏~ 有问题也可以在评论区交流,我们一起进步!