
1. 入门前最重要的一课Agent不是会聊天的API我一直觉得很多人在大模型Agent开发上栽跟头不是因为代码写不出来而是因为脑子里对Agent的画像从一开始就是错的。他们以为Agent就是调用大模型API多轮对话然后返回一段文本这其实是把Agent当成了一台自动回复机器。打个比方单纯的大模型API调用像一个知识渊博但只能动嘴的顾问——你说什么他答什么全程坐在椅子上一步不动而Agent是这个顾问被装上了手脚、配上了工具箱你告诉他帮我把书房收拾一下他会自己规划先干什么后干什么自己决定用抹布还是用吸尘器碰到扫不干净的地方还会换一种工具再试一次。这就是Agent最核心的本质**它不是一个会说话的模型而是一个能自主完成任务的执行系统。**大模型是它的大脑而工具调用、规划、记忆、反馈循环是它的手脚和神经。开发Agent本质上不是在写提示词而是在搭建一套大脑工具流程的协作体系。所以入门前你不需要急着看LangChain文档也不需要急着研究各种花哨的Agent框架。你需要先把下面这五件套想清楚它们可以说是一切Agent系统的地基模型Model决定Agent想不想得明白。目前主流的做法是直接用具备Function Calling能力的商用或开源大模型比如OpenAI的GPT系列、Claude或者国内的开源模型Qwen等。Function Calling是Agent的入场券后面会专门讲。规划Planning决定Agent先干什么后干什么。最简单的规划就是让模型自己写步骤清单复杂一点的用ReAct框架Reason Act思考再行动再往上还有Plan-and-Execute这种把规划和执行拆开的架构。工具Tools决定Agent能干什么活。查天气、操作数据库、发邮件、控制浏览器这些能力全部来自工具。没有工具的Agent再聪明也只是一个聊天窗口。记忆Memory决定Agent记不记得事。短期记忆是当前任务里的上下文长期记忆是跨会话的用户偏好和历史经验。动作与反馈Action Feedback决定Agent能不能根据结果调整自己。调用工具拿到结果之后模型需要判断结果是不是符合预期不符合就换方案再试。我刚入门的时候踩过一个大坑花了两周时间研究Agent框架的配置文件、各种抽象类结果自己连一个最简单的让Agent调用计算器都没跑通。后来我才悟到Agent开发的核心从来不是框架而是流程。你只要把一个模型思考-调用工具-拿到结果-再思考的循环跑通框架上的花活都是锦上添花。这篇文章我打算按一条程序员最容易上手的路径来讲先拆清楚Agent收到一个任务后到底经历什么再用最少的代码手写一个真正的Agent然后带你评估到底要不要用框架最后把我实战里遇到的高频问题全部倒出来。目标只有一个让你读完这篇文章自己能从零写出一个能干活、能排错、能继续升级的Agent应用。2. 最小技术栈与Agent的工作链路2.1 技术栈怎么选能省则省能简单绝不复杂很多初学者问我第一个Agent项目用什么技术栈我通常给一套非常抠门的清单语言Python 3.10。不是说其他语言不行而是大模型生态的工具链、示例代码、社区答疑几乎都优先支持Python你踩坑时搜到的答案大概率也是Python写的。模型API首选支持Function Calling的模型这是能让你用最简单方式实现模型决定调用哪个工具的关键能力。如果没有Function Calling你就得靠提示词逼模型输出特定格式的JSON然后自己解析费事且不稳定。HTTP请求库requests或httpx就够了甚至不需要引任何Agent框架。向量数据库暂时不需要入门阶段先把记忆放内存里后面再上chromadb这类轻量级方案。这个技术栈的思路很简单**尽量少引入中间层先把链路跑通。**你亲手用几行代码控制模型输出-工具调用-结果塞回模型这个循环之后再看任何框架都会觉得它们只是把你手写的这些代码封装得更漂亮了这时候你才具备评估框架的能力。2.2 一次Agent任务的完整执行链路我画不出流程图但可以用文字把这个循环讲清楚。假设你给Agent的任务是帮我查一下今天北京和上海的温差如果超过5度就记到备忘录里。这段任务背后Agent经历的是这样一个循环任务理解与规划模型读入你的指令结合系统提示词心里产生一个计划先查北京天气再查上海天气算温差然后决定要不要写入备忘录。模型输出工具调用请求模型自己决定需要查天气于是输出一个结构化的调用意图比如函数名get_weather和参数{city: 北京}。这个过程在OpenAI的API里叫tool_calls这个结构化输出不是靠运气是模型专门训练出来的能力。程序执行工具你的代码收到这个调用意图后去执行真实的函数比如调用天气API拿到返回结果。结果回填你把这个工具的执行结果天气数据作为一个tool消息返回给模型。模型继续决策模型看到天气结果后判断还需要查上海于是又输出一次工具调用。循环执行步骤3到5直到模型认为任务目标达到输出最终答案。最终回复模型生成一个自然语言回复告诉你结论比如北京12度上海19度温差7度我已记录到备忘录。这个循环行业里称为ReAct范式Reasoning Acting其实就是想一下-做一下-看结果-再想。核心在于每一次工具调用的结果都会成为模型下一步思考的输入所以Agent不是一次性算好所有步骤而是动态调整的。2.3 工具调用Function Calling是Agent的灵魂为什么要单开一个小节讲Function Calling因为我见过太多人在这里绕远路。所谓Function Calling简单说就是你提前定义好一批工具清单给模型模型在需要时不是自己算答案而是输出一个我要调用哪个工具、传什么参数的结构化指令由你的代码去真正执行这个工具。注意工具的执行者是你写的代码不是模型。模型只负责选工具和定参数。这个分工极其重要。因为大模型不擅长精确计算但它非常擅长理解意图和决策。比如帮我算一下3乘7等于多少你与其让模型直接口算不如定义一个calculator工具让模型调用它由真实的Python代码算出结果。把模型不擅长的事交给工具把模型擅长的事留给模型这是Agent设计的第一原则。我在最初写Agent时就犯过一个典型错误把一堆工具的逻辑硬塞进提示词希望模型直接输出最终结果。比如让模型自己算搜索结果的摘要、自己执行数学公式结果模型开始一本正经地胡说八道。后来我把这些工作全部拆成工具调用准确率立刻上来了。所以记住一句话判断一个设计是不是好的Agent设计就看它是否把任务拆给了合适的工具去处理。3. 从零手写一个能自己调工具办事的Agent3.1 场景设定一个能查天气和写备忘录的Agent理论讲太多容易飘这里直接写一个最小可运行的Agent实例。需求是Agent能调用两个工具——查城市天气、写备忘录。用户提问北京的天气适合跑步吗如果想跑帮我记到今天的备忘录里。Agent需要自己决定调用天气工具然后根据天气决定是否调用备忘录工具。这个例子虽然小但五脏俱全有工具注册、有模型决策循环、有最终回复。3.2 先定义工具在OpenAI的Function Calling机制里工具的定义分两部分一份是给模型看的JSON Schema描述另一份是给代码执行的Python函数。# tools.py import json from datetime import datetime def get_weather(city: str) - str: 返回城市的天气情况这里是模拟数据实际项目可替换成真实天气API weather_data { 北京: {温度: 12, 天气: 晴, 风力: 3级}, 上海: {温度: 19, 天气: 小雨, 风力: 2级}, } data weather_data.get(city, {温度: 20, 天气: 未知, 风力: 未知}) return json.dumps({城市: city, **data}, ensure_asciiFalse) def write_memo(content: str) - str: 将内容追加写入当日备忘录文件 filename fmemo-{datetime.now().strftime(%Y-%m-%d)}.md with open(filename, a, encodingutf-8) as f: f.write(f- {content}\n) return f已写入备忘录{content}注意get_weather返回的是JSON字符串这是为了让模型读取结构化数据更稳定。在实际开发里天气数据可以换成真实API请求比如和风天气、高德的天气接口这里先用模拟数据跑通流程。然后是要给模型看的工具描述# tool_schemas.py weather_tool_schema { type: function, function: { name: get_weather, description: 查询指定城市的当前天气情况包含温度、天气状况和风力。, parameters: { type: object, properties: { city: {type: string, description: 城市名称如北京、上海} }, required: [city] } } } memo_tool_schema { type: function, function: { name: write_memo, description: 将一条内容写入当天的备忘录文件中通常用于记录待办事项或重要信息。, parameters: { type: object, properties: { content: {type: string, description: 要写入备忘录的内容} }, required: [content] } } }这里描述写得好不好直接影响模型会不会正确调工具。我见过很多新手把description写得太空泛比如写查询天气函数模型什么时候该调用它、该传什么参数全凭猜。建议每个工具的description都写清楚三件事工具是干嘛的、什么场景下使用、参数分别是什么意思。3.3 写Agent主循环接下来是核心部分一次对话中的while循环处理逻辑。# agent.py import json from openai import OpenAI client OpenAI(api_keyyour-api-key, base_urlhttps://api.openai.com/v1) # 工具映射表模型的作用就是选出key程序执行对应的value TOOLS_MAP { get_weather: get_weather, write_memo: write_memo, } SYSTEM_PROMPT 你是一个智能助理。你可以使用工具来获取信息或执行操作。 当用户的问题需要具体数据或需要执行动作时请先调用相应工具 当你认为任务已经完成时用自然语言回复用户最终结果。 def run_agent(user_input: str, max_iterations: int 5): messages [{role: system, content: SYSTEM_PROMPT}] messages.append({role: user, content: user_input}) for _ in range(max_iterations): response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, tools[weather_tool_schema, memo_tool_schema], tool_choiceauto, ) choice response.choices[0] message choice.message # 打印模型思考过程方便调试 if message.content: print(f[模型回复] {message.content}) # 模型决定调用工具 if message.tool_calls: messages.append(message) # 把带有tool_calls的消息加入历史必须否则模型会失去调用记录 for tool_call in message.tool_calls: func_name tool_call.function.name args json.loads(tool_call.function.arguments) print(f[调用工具] {func_name}({args})) result TOOLS_MAP[func_name](**args) # 工具结果以tool身份回传给模型 messages.append({ role: tool, tool_call_id: tool_call.id, content: result, }) continue # 继续循环让模型基于工具结果产生下一步决策 # 没有tool_calls说明模型认为任务完成 if message.content: return message.content return 超过最大迭代次数任务未完成。 if __name__ __main__: result run_agent(北京今天适合跑步吗如果适合帮我记到备忘录里。) print(f\n最终回答{result})跑一下输出大致会是[模型回复] None [调用工具] get_weather({city: 北京}) [模型回复] None [调用工具] write_memo({content: 北京今日天气晴朗气温12度风力3级适合跑步。}) [模型回复] None [最终回答] 北京今天天气晴朗、气温12度、风力3级体感比较适合跑步。我已经帮你记到今天的备忘录里了随时可以查看。注意一个关键点messages.append(message)这一步很多初学者会漏掉。模型返回的tool_calls消息本身必须加入对话历史否则下一次请求模型就不知道自己刚才调了什么工具会出现调了工具但回头不认账的诡异行为。3.4 为什么故意不用框架有读者可能会问这个轮子LangChain一行就能搞定我为什么还硬写一遍我的回答是你手写过一次循环才能理解框架在你背后做了什么。LangChain的AgentExecutor也好OpenAI的Assistants API也好本质上就是这个循环的封装。如果你没手写过直接上手框架遇到一个模型不停调同一个工具停不下来的bug你会完全不知道问题出在哪个环节。而你自己写过一遍你一眼就能看出哦这可能是工具结果回传后模型认为还需要继续调得加一个停止条件。这是我强烈建议所有入门者做的一件事至少手写一个Agent循环哪怕极其简陋。这段经历带来的框架理解力比你读十篇框架源码分析都有用。3.5 第一次测试时会遇到哪些预期内怪象第一次跑通这个Agent的人我敢打赌会遇到下面这些正常现象提前给你打预防针模型不调用工具直接编天气数据这通常是prompt里没有说明必须用工具或者工具的description写得模糊模型觉得可以自己回答。把系统提示词改成当涉及具体数据时必须先调用工具再回答情况立刻好转。模型连续调用同一个工具两次比如查了北京还查一次上海这是正常的说明模型在按计划执行。如果它在无意义地重复调用同一个参数那就需要在提示词里约束如果已经获取到该数据不要重复获取。模型调用工具时参数解析失败json.loads报错多半是模型输出的arguments不是合法JSON。不管多强壮的模型偶尔都会抽风稳健做法是加一个异常捕获尝试修复JSON比如去掉多余换行符。这个在实际生产里很重要。4. 框架选型LangChain、LlamaIndex还是自己拼4.1 三套方案的定位差异手写循环跑通之后你会开始面临一个现实问题要不要上框架目前市面上主流的方案我按抽象程度从低到高排了个序并做了对比方案抽象层级适合人群最大优势主要槽点手写循环最低贴近API刚入门、想彻底理解原理完全可控出bug好排查功能简陋要自己处理很多细节LangChain中高抽象出链、代理、记忆已理解原理、开发速度优先组件丰富生态大社交问答多学习曲线陡版本升级频繁抽象过深时调试困难LlamaIndex中高偏数据/检索方向做RAG、知识库类Agent数据连接器极丰富偏重检索增强通用业务逻辑仍需自己搭自研极简Layer自定义业务逻辑复杂、要长期维护完全贴合业务无脏依赖需要一定设计能力值得注意的一点是LangChain的版本更迭一直是老用户吐槽的重灾区——类名和导入路径说变就变网上教程基于旧版直接粘贴就跑不动。我自己经历过LangChain 0.1时代写好的代码升到0.2后一夜之间好几个类被废弃。于是我的建议是入门阶段先手写核心循环然后如果真要引入框架从工具辅助层面逐步引入而不是一上来就把整个AgentExecutor抱进怀里。4.2 我推荐的入门路径如果你目的很明确就是要尽快做出一个能用的Agent应用而不是成为框架源码专家这条路我个人觉得最平滑第一步用原生API手写一遍ReAct循环就是我上面第3节那个例子。这一步帮你建立一次Agent运行到底发生了什么的心智模型大概花一晚上。第二步把工具数量增加比如从2个扩到5个在同一个循环结构里测一测。等你发现循环逻辑本身没变变的是工具清单的时候你其实已经在心里完成了抽象这一步——你已经具备了评估框架的资格。第三步根据需求挑框架。如果你的核心痛点是接入的数据源太多、要做问答知识库毫不犹豫选LlamaIndex如果你的核心痛点是要编排复杂的自然语言任务流程、要各种现成的工具集成选LangChain。如果你不想被框架的抽象束缚自己用Pydantic定义一个工具注册器其实也就一百行代码的事完全可控。4.3 从手写版本迁移到框架版本的正确姿势很多人迁移到框架后反而觉得更痛苦原因是他们试图把所有东西都塞进框架的规范里结果被框架的抽象牵着鼻子走。我从手写迁移到LangChain时只做了一件最小的事把手写的四个部分拆出来保留逻辑替换掉传输层。具体来说我的工具函数定义不变只在外面套一层tool装饰器并补上docstring我的主循环不再手写改用create_agent或AgentExecutor我的记忆从列表换成了框架提供的ConversationBufferMemory。这样迁移的好处是工具逻辑完全保留框架只是替我把调用循环和历史管理这些劳动密集型的部分自动化了。5. 实战中的五个拦路虎上下文、工具、提示词、记忆、评测5.1 上下文爆掉这是人人都要面对的墙Agent一旦跑起来每一轮都要把之前的对话历史全部发给模型尤其是每次工具调用结果也要回传。一个复杂任务跑5轮、每轮有几百token的工具返回几轮下来上下文可能就翻倍了。我做过一个自动写周报的Agent工具里有个读取本周Git提交记录每次返回光一个仓库就能塞几千token。任务执行到第3次循环单次请求就超过了普通模型的上下文窗口上限。处理策略从粗到细有三层裁剪早期日志只保留系统提示词、用户原始目标、最近的几轮交互。大多数情况下模型规划其实只依赖最近的状态早期寒暄完全可以丢弃。摘要压缩把超过阈值的对话历史交给模型生成摘要用摘要替换原内容。代价是模型要额外消耗一次请求。结构化记忆把工具结果摘要化比如本周提交42次涉及模块登录、支付而不是把完整git log塞进去。这条最有效也最推荐。5.2 工具调用失灵最常见的五种翻车现场工具调用是Agent项目里最脆弱的环节。我整理了我在实战里遇到最多、也最容易被初学者误判的五种情况现象根因解决方案该调工具时不调模型硬编结果工具description不清晰或系统提示词没约束强化description的场景说明提示词写明涉及实时数据必须先用工具不该调时偏偏调description里没写限制条件在description里写清楚仅当用户问X时调用参数总传错参数描述不够精确比如日期格式、单位在参数的描述里给示例如格式为YYYY-MM-DD同一工具反复调用不结束工具结果没有给模型足够信息做完成判断在系统提示词里加如果已获得答案直接输出最终回复并发调用乱套模型一次输出多个tool_calls结果互相依赖要么串行执行依赖型工具要么在多个调用里给每个结果带上关联标记这里尤其要提一下并发调用Parallel Function Calling。OpenAI的模型支持一次返回多个工具调用请求比如查北京和上海的天气还要订餐厅模型可能一口气输出三个tool_calls。如果你的工具之间有依赖关系比如先查天气才能决定是室内还是户外千万别顺手并发了老老实实串行执行把上一步结果喂回去。5.3 提示词在Agent里和普通聊天不一样给Agent写提示词和给聊天机器人写提示词完全不是一个打法。聊天机器人只要说得好Agent必须想得对、调得准、收得住。我在Agent项目里固定用三段式提示词结构角色与目标告诉模型你是谁、你在帮用户达成什么目标。工作流程约束告诉模型遇到哪类问题先调什么工具、调完之后下一步怎么判断、什么条件下结束任务。红线条款告诉模型绝对不要做什么比如不要编造工具返回的数据如果工具返回错误直接把错误信息反馈给用户而不是假装成功。举一个例子一个查快递单号的Agent提示词里我写了这样一段当用户提供一个快递单号时你必须调用query_express工具查询物流信息如果工具返回单号不存在请直接告知用户查无此单禁止自行编造物流记录。就是这种带场景、带动作、带兜底的提示词能让Agent的稳定性上一个台阶。5.4 记忆系统内存里到底该存什么入门阶段的Agent可以完全不做记忆但随着项目变复杂你会发现每个任务都是无状态的用户上次的偏好、之前的结论全都想不起来体验像失忆的人。这就是记忆系统存在的意义。我用下来的经验是长期记忆千万别把原始对话塞进去而是存结构化结论。比如用户说我每周二下午开会帮我提前订会议室记忆里存的应该是{recurring_event: 每周二14:00预订会议室}而不是那三句闲聊。这个结论可以由模型在每次对话结束后自动抽取存进向量数据库或普通的JSON文件里。下次对话开始前把相关记忆检索出来作为系统提示词的一部分。5.5 一个低调但关键的环节Agent评测做Agent到一定阶段你就会发现它不像传统函数输入一样输出一定一样。同样的工具、同样的提示词模型这次决策和上次决策可能完全不同。这就是Agent评测难的地方。我最常用的评测方式是场景回放把真实用户的一批历史任务收集成测试集每次修改代码后回放这批任务对比任务的完成率、工具调用正确率、最终回复可接受度。评测不需要多复杂——就是自动跑一遍然后人工抽检几十条。但这件事一定要做否则你的Agent会越改越薛定谔的可用。我在实操中发现完成率最高的Agent往往不是提示词写得最华丽的那个而是失败兜底写得最稳的那个。所以写评测用例时多花一点时间设计边界输入和异常场景比堆正常用例有价值得多。6. 进阶方向与两步扩展建议6.1 进阶方向一把Agent从一个循环变成一个图当你的Agent工具数量超过10个、任务链路越来越长时靠模型自由发挥的风险会增大——模型可能一直在工具之间绕来绕去。这时我建议你接触一下流程编排思路把标准动作抽象成流程节点模型只负责在节点之间做选择而不是每一步都临时发明。举个例子一个电商客服Agent固定的流程是识别意图→查订单→查物流→售后处理你把这些节点固化成流程模板模型的任务变成在模板节点里填参数而不是凭空生成行为。这个做法极大提升了确定性代价是灵活性下降。确定性和灵活性通常不可兼得你要根据业务场景主动选择天平偏向哪边。6.2 进阶方向二多Agent协作单个Agent往往身兼数职又要理解用户意图又要决策又要干活。当任务复杂到一定程度把一个全能Agent拆成多个专职Agent协作完成一个大任务往往是更优解。比如一个简历分析助手可以拆成三个Agent一个负责解析简历文本、一个负责对比JD匹配度、一个负责生成面试问题。三个Agent各管一摊比一个大而全的Agent效果稳定得多。多Agent的协调方式入门阶段不用搞得太复杂用一个导演Agent负责决策调度就够了导演Agent根据任务状态决定交给哪个子Agent处理这在工程上实现起来本质上还是你上面学的那套循环只是工具变成了其他Agent而已。6.3 两步扩展建议如果你看完这篇文章决定亲手动手试一下我建议你给自己设计一个两周计划第一周把手写的ReAct循环跑通然后增加三个小工具比如计算器、获取当前时间、写文件测试不同用户指令下模型的选择是否合理。第二周把其中一个工具换成真实API比如免费天气API然后引入一个轻量级记忆让它记住用户的偏好比如每天查一次北京天气。这两周走完你对Agent的理解会比读三个月源码收获更大。最后想分享一个我自己的体会Agent开发最大的魅力在于它没有一个正确的架构但有一大堆错误的架构。每个团队最终都会磨出最适合自己业务的形态。入门阶段最重要的不是追求用最牛的框架、最新的架构而是建立模型决策循环这层心智模型然后在这个模型之上不断做实验。等你的Agent开始自己规划任务、自己调用工具、自己从错误里纠正的时候那种它在替我干活的感觉会让你觉得前面的所有折腾都是值得的。