两小时搭建AI Agent:LangChain+DeepSeek实战全记录
1. 两小时装了agent聊聊我干了点啥周末闲着没事想着最近大家都在聊AI agent我也花了两小时搭了一个。结果发现这东西比我想象中简单也比我想象中复杂。说它简单是因为框架和工具链已经很成熟了照着文档做基本能跑起来说它复杂是因为真要让它稳定干一件实事需要理解的东西远不止调一个API那么简单得搞清楚模型、工具、记忆这几层到底是怎么配合的。这篇文章就把这两小时里装的东西、踩的坑、想明白的道理一次性说清楚给同样准备入坑的朋友一个参考。不管你是后端开发、运维还是做企业信息化的同学这篇内容应该都能帮你省下不少试错时间。我会尽量用大白话讲代码示例用Python加LangChain加DeepSeek这套最常见、最容易上手的组合确保你照着敲一遍就能跑出自己的agent。先说结论装一个能跑的demo两小时确实够。但如果你想让agent稳定帮你干活比如自动查数据、回消息、写报表那还得在产品设计、工具定义、异常处理上多花功夫。这篇文章的核心目的就是帮你把能跑和能用之间那条鸿沟提前填一填。2. 先把概念捋清楚agent、LLM和AI模型的关系2.1 三层关系一张表看清新手最容易懵的地方就是agent、LLM、AI模型这几个词混在一起用。我刚接触的时候也绕了好久后来用一张表把它们的层级关系理清楚了。概念是什么类比举例AI模型一个完成了训练、具备某种能力的参数文件一个受过专业训练的大脑DeepSeek、Qwen、GLM以及各种开源权重模型LLM专指以语言为核心的AI模型能生成文字、理解语义一个会说话、会写字的大脑GPT系列、Claude、DeepSeek-V3/R1、Llama等Agent基于LLM搭建的一套完整系统能自主规划、调用工具、完成任务一个有大脑、有手有脚、会查资料干活的人LangChain应用、AutoGPT、各类智能助手产品这三者不是并列关系是包含关系。AI模型是最大的范围LLM是AI模型中擅长语言的那一类agent则是拿一个或多个LLM当大脑再配上工具、记忆、执行逻辑组装出来的一个能独立完成任务的系统。初学者最容易混淆的是LLM和agent你打开DeepSeek官网聊天那是LLM在直接回答你但如果你写了个程序让DeepSeek去判断用户想查天气然后自动调用天气接口再把结果整理成文字回复那这个程序就是一个agent。区别不在于模型本身而在于有没有感知-决策-行动这个闭环。2.2 DeepSeek属于哪一层很多人问DeepSeek是agent吗答案很清楚DeepSeek属于AI模型和LLM这一层人家是提供大脑的不是做手脚的。DeepSeek官方提供的产品无论是App还是网页版本质上就是一个聊天界面加上一个LLM。你给它一个提示词它给你一段文字并没有自主调用外部工具、长期规划的能力。真正把它变成agent的是开发者。我这次搭agent底层用的就是DeepSeek的API。之所以选它原因有三第一它对国内用户非常友好注册简单、充值方便调用成本也低第二它的API兼容OpenAI的消息格式这意味着市面上大部分现成框架都能无缝接入第三deepseek-chat和deepseek-reasoner两个模型一个偏快一个偏推理正好适合不同场景。2.3 为什么说agent是搭出来的不是训出来的理解了上面的层级关系你就会明白一个关键点用DeepSeek、GPT这类现成模型并不需要你去训练模型你要做的是搭。搭一个agent本质上是在组装四样东西模型大脑、工具手脚、记忆笔记本、调度逻辑决策流程。这四样东西里头模型是别人给你的你不用管工具是你自己写的比如查数据库、发HTTP请求、读写文件记忆可以是简单的对话历史也可以是用向量数据库存储的长期知识调度逻辑则是决定模型什么时候该调用工具、调完怎么处理结果的流程设计。把这四样想清楚agent的结构就通透了。这也是为什么我能在两小时内装出一个能跑的例子——因为不需要从零造轮子框架已经把调度逻辑封装好了。3. 动手之前方案选型和架构设计3.1 框架怎么选Python、Java还是直接调API市面上做agent的框架很多我简单分了三类大家根据自己的技术栈对号入座。第一类Python系代表是LangChain、LlamaIndex、CrewAI。这类框架生态最丰富文档和教程最多适合快速验证想法。如果你本来就会Python几乎没门槛。缺点是抽象层较多出了问题定位起来稍微费劲而且版本迭代快网上很多教程已经过时了看的时候要留意发布时间。第二类Java系代表是Spring AI。这算是新兴力量但势头很猛。如果你所在的公司是Java技术栈尤其是用了Spring Cloud的微服务架构那直接用Spring AI做agent是顺势而为跟现有系统的集成成本最低。我身边做企业级应用的朋友不少已经在看spring ai开发agent这条路了。第三类不依赖框架直接用模型的function calling能力手写循环。这种方式最透明也最能锻炼理解但代码量会多不少还得自己处理重试、超时、上下文管理等一堆细节。适合想深入理解原理的朋友不建议赶时间的人选这个。我这次选的是Python加LangChain原因很纯粹资料多、上手快、两小时能出活。框架选型不要纠结先跑通再优化这是我一直以来的习惯。3.2 模型怎么接以DeepSeek为例模型接入是agent搭建里最简单的一步但对新手来说反而容易出问题主要卡在到底怎么让LangChain调用DeepSeek上。LangChain的ChatOpenAI类本来就是为OpenAI接口设计的而DeepSeek的API兼容OpenAI协议所以只需要改两个环境变量就能把两者对接上把API Key换成DeepSeek的key把base_url指向DeepSeek的接口地址。这个技巧适用于几乎所有国产模型服务因为这些平台为了生态兼容普遍都做了OpenAI协议适配。还需要注意模型名称的填写。DeepSeek官方提供两个模型名deepseek-chat对应通用对话模型速度快deepseek-reasoner对应推理增强模型擅长数学、逻辑类任务但响应会慢一些。如果名称填错了程序会直接报错这个细节最容易坑到第一次接入的人。3.3 工具、记忆和技能agent的四肢和脑子模型选好之后真正决定agent有没有用的是工具和记忆的设计。工具就是一段段函数每个函数都带一个描述信息告诉模型我能干什么、什么时候用我、参数是什么格式。模型在对话过程中读到用户请求会先判断要不要调用某个工具如果需要就以约定的JSON格式生成调用指令。你的程序收到指令后执行对应函数把结果反馈给模型模型再基于结果组织最终回答。这就是最经典的ReAct模式思考、行动、观察循环往复直到任务完成。记忆则分两层。短期记忆就是当前会话的对话历史让模型记得上下文长期记忆是把重要信息存到向量数据库里下次会话还能检索出来常用方案有FAISS、Chroma这类轻量级向量库。MCPModel Context Protocol是最近很火的一个协议它把工具接口标准化了相当于给agent装了一个通用插槽接各种外部能力就像插U盘一样方便。如果你要做的agent涉及很多外部系统MCP是值得重点研究的方向。4. 实操从零搭一个能查时间、能算数的agent4.1 环境准备工欲善其事必先利其器。我这套示例只需要一个Python环境3.10以上版本就行。建议先建一个虚拟目录避免把依赖装到全局环境里。依赖就三个包langchain-openai负责对接大模型接口langchain-core提供工具和提示词的基础类langchain-agents提供agent的组装和执行器。安装命令很简单一条pip指令全搞定。安装好之后把DeepSeek的API Key配到环境变量里配置的时候建议用环境变量文件而不是直接写死在代码里这样代码传到Git仓库也不会泄露密钥。4.2 核心代码模型、工具、执行器三段式下面是我实测能跑通的核心代码逻辑不复杂就三大块初始化模型、定义工具、组装执行器。import os from langchain_openai import ChatOpenAI from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.tools import tool from langchain_core.prompts import ChatPromptTemplate # 1. 初始化模型通过OpenAI兼容协议对接DeepSeek os.environ[OPENAI_API_KEY] os.getenv(DEEPSEEK_API_KEY) os.environ[OPENAI_BASE_URL] https://api.deepseek.com/v1 llm ChatOpenAI( modeldeepseek-chat, temperature0.3, max_tokens2048 ) # 2. 定义两个工具时间查询和数学计算 tool def get_current_time() - str: 获取当前日期和时间当用户询问时间时使用。 from datetime import datetime return datetime.now().strftime(%Y-%m-%d %H:%M:%S) tool def calc(expression: str) - str: 计算数学表达式例如 1 2 * 3。注意表达式只能是数字和四则运算符号。 import ast import operator as op operators { ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.Pow: op.pow, ast.Mod: op.mod } def _eval(node): if isinstance(node, ast.Expression): return _eval(node.body) if isinstance(node, ast.Constant): if isinstance(node.value, (int, float)): return node.value raise TypeError(只支持数字) if isinstance(node, ast.BinOp): if type(node.op) not in operators: raise TypeError(不支持的运算符) left _eval(node.left) right _eval(node.right) if isinstance(node.op, ast.Pow): if abs(right) 10: raise ValueError(指数过大) return operators[type(node.op)](left, right) raise TypeError(不支持的表达式) try: result _eval(ast.parse(expression, modeeval)) return str(result) except Exception as e: return f计算失败{e} # 3. 组装agent执行器 tools [get_current_time, calc] prompt ChatPromptTemplate.from_messages([ (system, 你是智能助手能调用工具完成任务。先判断是否需要工具再决定是否调用。), (human, {input}), (placeholder, {agent_scratchpad}), ]) agent create_tool_calling_agent(llm, tools, prompt) executor AgentExecutor(agentagent, toolstools, verboseTrue) if __name__ __main__: result executor.invoke({input: 现在几点了顺便算一下 23 * 17 89 的结果}) print(result[output])这里有个特别值得说的细节就是工具描述的重要性。create_tool_calling_agent能不能正确选工具很大程度上依赖文档字符串写得好不好。模型不是人它只能靠描述文字来判断工具用途所以描述别写什么计算函数要写清楚什么时候用参数是什么格式。比如calc的描述我特意写了表达式只能是数字和四则运算符号就是为了降低模型传错参的概率。另外一个细节是我把calc的实现改成了基于AST解析而不是直接eval。网上很多教程图省事直接eval(expression)这在本地demo问题不大但如果agent要对接不可信的外部输入eval就成了严重的安全漏洞因为模型可能在这个参数里传入恶意代码。用ast库做白名单式解析只允许数字和指定运算符参与计算就能从根本上挡掉这类注入风险。这个习惯建议现在就养成。4.3 跑起来之后发生了什么代码写好之后python main.py跑一下你会看到执行器打印出一长串中间过程这正是理解agent内部机制的最佳窗口。模型收到现在几点了顺便算一下 23 * 17 89 的结果这个请求后自己会先做一轮判断第一个问题需要时间正好有get_current_time这个工具第二个问题需要数学计算calc正合适。于是模型返回一个结构化的调用请求LangChain解析后依次执行这两个工具拿到结果再交回给模型。最后一轮模型把2025-XX-XX XX:XX:XX和480这两个结果组织成自然语言回复比如当前时间是……计算结果是480。整个过程里模型本身的角色是调度员和发言人真正的计算和取数工作在工具里完成。这就是agent和普通聊天最本质的区别模型不再凭空生成答案而是通过工具拿到了事实依据再基于事实组织答案准确率一下子就不一样了。我建议你把这套示例改一改多定义几个工具比如查文件、发邮件、查数据库体验一下模型在不同工具之间选择的感觉。当你看到模型跳过不相关的工具、准确选中你期望的那个工具时对agent的理解会上一个台阶。5. 踩过的坑与排查实录5.1 常见问题速查表两小时体验下来我踩了不少坑很多是文档里不会明确写的。整理成一张速查表大家遇到同类问题可以直接对照。现象可能原因解决方案请求报401认证失败API Key填错或环境变量未生效检查key是否有空格确认环境变量已export重启终端报404或URL错误base_url拼写有误DeepSeek的地址结尾要带/v1不要漏掉模型名称不存在填了模型别名而未用官方名称确认使用deepseek-chat或deepseek-reasoneragent无限循环调工具缺少终止条件或工具总是返回错误给AgentExecutor加max_iterations限制最大轮数工具返回结果丢失工具内部异常被吞掉在工具里捕获异常并返回提示信息而不是让异常直接中断上下文被塞爆多轮工具调用结果累积超过模型窗口对工具返回内容做截断只保留关键部分或用摘要替代原文模型接了不存在的工具参数工具描述不清晰模型生成错误JSON优化工具描述明确参数类型和取值范围必要时做参数校验5.2 两个我印象最深的坑第一个坑跟DeepSeek的reasoner模型有关。我一开始图省事测试的时候把model改成了deepseek-reasoner结果发现工具调用的稳定性明显下降有些请求它不返回标准格式的function call而是直接在文本里写我来调用xxx工具导致LangChain解析失败报错。后来查了文档才知道推理模型的输出格式和通用模型有差异在做工具调用场景时deepseek-chat是更稳妥的选择。所以如果你也遇到工具调用不稳定先检查是不是模型选型的问题。第二个坑是关于verbose日志的。AgentExecutor开启verboseTrue后中间过程全打印出来非常直观但也暴露了一个问题模型在思考过程中偶尔会自言自语把用户提到的内容复述一遍再调用工具。这时候如果你只看输出会误以为它调了两次工具。其实这是模型的正常推理痕迹不影响最终结果。但如果你在排查问题一定要区分模型的思考文本和真正执行的工具调用否则容易被干扰。日志里Action和Observation这两个标记行才是关键Action是模型决定调用的工具Observation是工具返回的结果绕着这两个字段看定位问题会快很多。5.3 排查方法论前面都是具体问题的解法再说一个通用的排查思路这是我这次体验中最受用的一条。遇到agent行为不符合预期时第一件事不是改代码而是把verbose日志完整看一遍从用户的输入开始跟着模型的每一步Action走。看它选择了哪个工具、传入的参数是什么、工具返回了什么、模型最后怎么组织回答。大多数问题在这一步就能定位要么是模型没选对工具说明工具描述有问题要么是工具返回了错误结果说明工具实现有bug要么是模型看到了正确结果却说错话说明提示词需要强化。定位之后再动手改一次只改一个变量。比如想确认工具描述是不是有问题就改描述跑一次其他都不动。严格单变量验证才能避免改来改去最后不知道是哪个改动生效的尴尬。这个习惯放到任何调试场景都适用agent开发尤其需要因为中间隔着一层不可控的模型变量越多越难排查。6. 进阶方向与个人心得6.1 从单agent到多agent跑通了单agent的基础demo之后你可以往两个方向走。第一个方向是做深把单个agent的能力边界扩展接入更多工具、加上长期记忆、引入MCP标准化接口。第二个方向是做广搞多智能体协作。多智能体的思路是让多个各司其职的agent互相配合比如一个负责理解用户意图一个负责检索数据一个负责生成报告彼此之间传递消息、共享上下文。这种架构在处理复杂任务时很有效每agent只需要把一件事做到极致比硬塞给一个agent做所有事更稳定。我在实际体验中试过一个简化版一个研究员agent负责找资料一个写作agent负责整理成文效果确实比单agent好尤其在上下文组织上清晰很多。不过多智能体也有代价调用次数更多、成本更高、调试更复杂。我的建议是刚开始不要盲目上多agent先把单agent的体验做到位确认一个agent搞不定某个特定环节再把那个环节拆出去变成独立的agent。多智能体不是一个炫技噱头而是解决具体问题的手段。6.2 Spring AI与企业级落地如果你是Java技术栈Spring AI值得提前关注。Spring AI把大模型接入、提示词管理、向量存储这些能力都用Spring的风格封装好了让你可以用熟悉的依赖注入方式写agent。企业级场景里还有两个点值得注意。一个是Jenkins AI agent就是在CI/CD流水线里让agent帮忙做代码审查、生成变更说明、分析构建失败原因这是运维侧落地agent的一个很务实的方向。另一个是多智能体协同开发的规范当团队开始用agent辅助写代码时怎么定义agent的权限边界、怎么审计agent修改的代码、怎么防止agent未经确认就改动关键模块这些都需要在落地前明确下来。我个人的看法是企业落地agent最大的阻力从来不是技术而是流程和信任。demo跑通很简单但要让人放心地把agent接入生产环节需要大量的边界测试和审计机制。这个心理预期要提前有不然很容易在推广阶段碰壁。6.3 一些真心话两小时装完agent我最大的感受是工具链的成熟度已经远超大多数人的预期以前需要团队做几周的模型调度逻辑现在一个框架方法就搞定了。但这也意味着真正拉开差距的不再是谁更会用框架而是谁更会定义问题。你给agent定义的工具是否精准、描述是否清晰、边界是否合理直接决定了它的上限。最后分享一个小技巧调试agent时不要把模型当成聪明人要把它当成一个理解力正常但容易跑偏的新员工。你每写一个工具都花十秒钟想想如果这个工具的描述只有一行字新员工会不会用错。这个换位思考比任何调试技巧都管用。我自己在优化calc工具的整个过程里有一半时间不是在改代码而是在改描述文案改完之后调用准确率明显提升。