资讯详情

手写极简Agent:大模型如何通过工具调用实现自主任务

📅 2026/10/22 3:32:24 | 华诺云谱 👁 阅读
手写极简Agent:大模型如何通过工具调用实现自主任务
你是不是也遇到过这种情况看了很多讲Agent的文章收藏了一大堆等到自己想动手的时候还是不知道从哪儿开始。别急着自责这太正常了。Agent这个东西光看概念很容易被绕晕——又是规划、又是记忆、又是工具调用名词一套接一套没个清晰的骨架兜着看再多资料也是散的。我把Agent拆开揉碎讲一遍不堆术语不贴长篇代码吓人就用大白话讲清楚Agent到底是什么、它凭什么能“自主干活”、想动手做一个最简单的Agent需要准备什么东西、核心代码长什么样、以及我实际调试中踩过的那些坑。这篇内容的目标很简单——你看完这篇能对Agent有一个整体、不模糊的认识并且有能力动手搭出第一个能跑起来的Agent。适合完全零基础的小白也适合那些看了一堆概念但还没真正跑通一次的人。1. Agent到底是什么一个能“自己找活干”的智能助手1.1 先把“大模型”和“Agent”的关系掰扯清楚大模型本身是什么本质上是一个“超级接话员”。你给它一段话它帮你把下一段话接出来。不管是写文案、翻译、改代码本质上都是在“接话”——只不过它接得足够好以至于看起来像是真的在思考。但“接话”有一个致命的问题它只管说不管做。你让它帮你查一下明天的天气它只能告诉你“我无法实时获取天气数据”。你让它帮你订一张火车票它能给你写出一篇怎么订票的攻略但它自己订不了。它困在一个Dialogue Box里外面的世界什么都摸不到。Agent做的事情就是给这个“超级接话员”装上了手和脚。我常用的一个类比是这样的大模型像一个知识渊博但只会坐在办公室里的顾问你把问题抛给他他给你出主意。Agent呢是把这个顾问派到现场去给了他一堆工具——电话、电脑、账本——然后告诉他你自己看着办搞不定就问问完了继续干。所以别把Agent当成一个什么新的模型。Agent不是一个模型它是一种用大模型做“大脑”的软件架构。它的核心思路是把一个大模型放进一个循环里让模型自己决定下一步该调用什么工具、该查什么信息然后把结果拿回来继续推理直到任务完成。这句话是理解Agent的钥匙Agent 大模型大脑 规划能力思考 记忆经验 工具手脚 循环持续干活的机制。1.2 一个完整Agent的思考循环是怎样转起来的我们先抛开所有框架用最朴素的逻辑描述Agent干一件事情的完整过程。假设我现在要给Agent布置一个任务“帮我查一下最近一周AI行业的大新闻整理成三条摘要发给我。”Agent接到这个任务后它的“大脑”会开始运转大致经历五个阶段第一阶段拆解任务。大模型会想“要我整理新闻摘要我得先知道有哪些新闻那我得先去检索一下。” 第二阶段选择工具。Model看到自己的工具清单里有一个“网页搜索”工具于是它决定先调用这个工具。 第三阶段执行并观察。系统替它去调用搜索引擎拿到一堆搜索结果然后把这些结果塞回给模型。模型看完之后想“信息来源有了但都是标题我还得点进去看正文。” 第四阶段再行动。模型继续调用“网页正文抓取”工具把具体文章内容抓回来。 第五阶段总结输出。信息够了模型把内容整理成三条摘要输出结果。关键就在于循环。模型不是一次性回答完就结束了它会根据每一步的结果动态调整下一步动作。这种“思考-行动-观察-再思考”的循环在学术上有个名字叫ReAct你可以简单理解为让模型像人一样边干边想干一步看一步而不是闭着眼睛一口气冲到底。这玩意儿再往下发展还衍生出了Plan-and-Execute这类模式——就是让模型先把整个任务的步骤规划好再一步一步执行以及Multi-Agent模式——让多个Agent分工协作一个负责搜索一个负责写稿像一个小团队。不过这些都是后话新人先把单Agent的循环跑通就有了理解所有高级玩法的底子。2. 为什么Agent能实现“自主任务”拆开核心组件看门道要用好Agent你得先理解它的几个核心部件。我一直觉得搞清楚一个系统最笨也最有效的办法就是把它的组件一个一个拆开来看搞清楚每一块是干嘛的以及它们彼此怎么配合。2.1 大脑和记忆Agent凭什么“记得住”和“想得清”先说大脑也就是大模型本身。这是Agent唯一的“智力来源”所有推理、判断、规划、总结能力全从这儿来。模型选得怎么样直接决定了Agent的聪明程度。这里有个很现实的问题模型能力越强Agent表现越好但成本和延迟也越高。我自己调试的时候习惯先用轻量级模型跑逻辑等代码和控制逻辑稳定了再换更强的模型去做最终效果验证。这个习惯帮我省了不少调试验证的成本。然后是记忆。记忆分成两块短期记忆和长期记忆。短期记忆很好理解就是“当前对话的上下文”。模型记不住事情你得把所有相关的历史信息都塞到它的上下文窗口里它才能“记得”之前做了什么。有一个常见的误区是新手一看上下文窗口撑不住了就想着把历史对话截断结果Agent做到一半突然“失忆”忘了最初的任务目标是什么。这就是没处理好短期记忆的表现。长期记忆则复杂一些通常是把之前对话中的关键信息抽取出来向量化之后存到数据库里。等到下次需要时再检索出相关内容放回上下文。你可以简单理解为短期记忆是工作台面上的文件长期记忆是档案柜里的文件夹需要的时候再抽出来摊到桌面上。2.2 规划能力Agent是怎么把大任务拆成小步骤的规划能力是Agent看起来“智能”的关键。它做的核心事情就是把一个模糊的大目标拆成一系列清晰的、可执行的小步骤。我用一个生活化类比解释这件事。你让一个刚入职的实习生去“组织一次团建”。他如果直接冲到户外用品店买帐篷那就是没有规划。一个靠谱的实习生会先想清楚团建的目的是什么多少人参加预算多少大概什么时间然后逐项确定再去执行。Agent的规划能力本质上就是干这个活。它依靠大模型天生的语言理解能力把任务目标拆成子目标。主流实现方式有两种一种叫“一次性规划”。任务拿到的第一时间模型先输出一个完整的步骤清单之后按清单一步步执行中途不改。这种方案速度快适合任务边界清晰的场景但遇到意外情况容易翻车。另一种叫“动态规划”。模型每做一步都重新评估下一步该做什么。这种方式灵活适合开放式任务但开销更大而且要小心模型陷入死循环——这一点我后面会专门讲。这两种方式不是互斥的实际产品里经常混合使用。门外汉看Agent觉得神奇懂了这套机制就会发现它没你想的那么玄乎每个看起来“智能”的表现背后都是工程设计的取舍。2.3 工具调用Agent靠什么“触碰”真实世界没有工具Agent再聪明也只是一个会说话的脑袋。工具调用机制是Agent与现实世界交互的桥梁。我举个例子。你让Agent帮你查一下某款手机的参数。Agent自己并不具备这个知识也没有联网能力但它可以在自己的“工具清单”里发现一个名为“product_search”的API接口。于是它决定调用这个工具并把可能的参数条件比如手机品牌和型号作为入参传过去。工具执行完毕返回一份JSON格式的数据这个数据再传回给模型模型基于这份数据生成你最终看到的答案。工具可以是任何东西一个天气查询API、一个数据库查询接口、一段Python脚本、甚至另一个Agent。关键在于要让大模型知道“有哪些工具可用”“每个工具是干什么的”“该怎么调用”。这个过程在技术实现上叫Function Calling它是目前主流Agent框架的核心能力之一。这里有个实用性技巧可以分享工具的描述信息一定要写得极其直白。模型是通过文本描述来决定是否调用工具的你把工具名写成一个缩写或者描述得很含糊模型就会在“到底该不该用它”和“该怎么用它”上面反复纠结白白消耗时间和token。工具描述越具体、参数说明越详细模型选择的准确率就越高。这就好比你给实习生写工作手册流程写得越清楚他执行起来就越不容易跑偏。2.4 循环机制为什么Agent不会“说了不做”最后是循环机制这是把前面所有模块串起来的那根线。理解了这个你就理解Agent为什么能“自主”完成任务。常规的大模型调用是“一问一答”用户输入模型输出会话结束。Agent就不一样了它内部的运行逻辑是一个循环模型生成输出分析输出里是否包含工具调用请求有的话系统执行工具把结果返回给模型模型拿到新信息继续生成下一轮输出直到模型的输出里不再包含工具调用请求循环结束把最终结果呈现给用户。这个过程在技术上叫Agent Loop也是Agent区别于普通聊天应用最核心的机制——它赋予了模型“持续工作”的能力而不只是“回答单个问题”。你可能会问这不就是一个while循环吗有什么了不起的。从代码实现上看确实不复杂但它的意义在于模型可以在一次任务中反复试错、自我修正、获取外部信息直到任务完成。这让机器第一次有了“完成一个复杂任务”的可能性而不只是“回答一个问题”。有经验的开发者应该能体会到这两者的差别是天壤之别的。3. 动手前的准备工作框架怎么选、环境怎么搭理论基础差不多了接下来进入实操环节。先说清楚这篇文章里不推荐你从零手写Agent内核除非你是想搞研究或者自虐。业界的成熟框架已经帮你把记忆管理、工具调用、循环控制这些脏活儿累活儿都封装好了你直接用就行。3.1 主流Agent框架对比到底选哪个目前市面上主流的选择有三类我按使用场景帮你捋一下。第一类开发者型框架。代表是LangChain、LlamaIndex这类Python框架。优点是可定制程度最高、生态最丰富想怎么玩都行适合有编程基础、做技术验证或者做产品原型的人。缺点也很明显API变动频繁你会在网上看到大量已经跑不通的老教程学习成本不算低。我个人的建议是如果你是第一次接触Agent想跑通核心概念不要一上来就扎进LangChain的文档里去啃。因为它的抽象层次很多新手很容易迷失在各类概念里最后连“自己的逻辑被封装到了哪里”都搞不清楚。先用最基础的模型调用API手动实现一个二三十行的Agent循环体会一下那个感觉再上框架你会通透很多。第二类低代码平台型。就是扣子Coze、Dify这类可视化编排平台。优点是对小白极其友好拖拽节点就能搭出一个Agent内置了海量插件不用自己写代码。适合产品经理、运营人员或者想快速验证想法不想碰代码的人。缺点是部署和数据隐私方面限制比较多定制能力弱。第三类Agent即服务型。比如各类企业级Agent平台产品把Agent直接封装成服务对外输出你只需要调用API就行。适合业务方想要快速接入能力但不想亲自维护Agent系统的情况。给新手的建议很简单有编程基础从自写微型循环开始然后拥抱LangChain没编程基础直接上扣子或Dify把业务逻辑跑通比什么都重要。工具只是手段理解Agent的工作机制才是核心。3.2 环境准备一套最小可运行的基础设施不管选什么框架你的电脑上这一套东西最好还是准备好。首先是Python环境推荐3.10及以上版本别用老版本了。装好之后建议用venv或conda建一个虚拟环境别把依赖装到全局——这是我吃过亏的经验Agent相关的依赖库更新很频繁你同时维护两个项目时版本冲突会让你怀疑人生。其次是大模型的APIOpenAI、Anthropic、以及各类国产大模型平台都可以选一个你顺手的。要注意的是Agent框架通常支持通过环境变量来读取API密钥建议用系统环境变量或.env文件管理密钥不要把密钥硬编码在代码里原因不需要我多说。再次是必要的Python库。如果走LangChain路线核心就两个包langchain和langchain-openai。安装命令很简单但我不写在博文里你自己在终端执行就可以。安装完成后建议跑一个基础的模型调用测试确认API连通再继续往下走。还有一个容易被忽略的准备工作读通函数调用Function Calling的官方文档。不用读完只看你所用模型关于工具定义的格式规范就行。因为在Agent里你怎么定义工具决定了模型能否正确地调用它。这一步值得花半小时好好看比后面Debug一小时的效率高多了。4. 从零手写一个极简Agent把代码讲透前面那些内容如果你已经跟着想了一遍那现在我们就来搞一个真正能跑的Agent。我不带你用框架就用最裸的方式手写一个微型循环你会发现Agent的骨架代码少得惊人。为了照顾到零基础的朋友下面这段核心代码我刻意写得简单明了。4.1 先定义一个“工具”让Agent有一个技能Agent总得干点什么这里我们给它配两个工具一个查天气模拟一个算数学题。# 工具1模拟天气查询 def get_weather(city: str) - dict: 模拟查询城市天气 weather_data { 北京: {天气: 晴, 温度: 22℃, 风力: 3级}, 上海: {天气: 多云, 温度: 20℃, 风力: 2级}, 广州: {天气: 小雨, 温度: 25℃, 风力: 4级}, } return weather_data.get(city, {天气: 未知, 温度: 未知, 风力: 未知}) # 工具2计算器 def calculator(expression: str) - float: 计算数学表达式结果 try: return eval(expression) # 演示用生产环境请勿直接使用eval except Exception as e: return f计算错误{e}这两个函数本身没什么稀奇的就是一个普通Python函数。关键在后面我们要把它们“介绍”给大模型让模型知道有这两个工具并且知道怎么用。这一步在每个框架里的叫法不同有的叫Tools有的叫Actions有的叫Function本质都一样。4.2 组装“工具清册”教模型认识这些工具这一步非常重要要解释清楚。大模型本身不知道你有get_weather这个函数你需要用一种“规范化”的方式把这些函数的能力描述给它。OpenAI等主流通用模型的工具描述通常遵循JSON Schema格式。tools [ { type: function, function: { name: get_weather, description: 查询指定城市的当前天气情况。, parameters: { type: object, properties: { city: {type: string, description: 城市名称例如北京、上海} }, required: [city], }, }, }, { type: function, function: { name: calculator, description: 计算数学表达式的值例如 22*3。, parameters: { type: object, properties: { expression: {type: string, description: 数学表达式} }, required: [expression], }, }, }, ]你有没有发现工具描述就像我们在2.3节里说的要写得极其直白。这就告诉模型遇到天气问题找get_weather遇到计算找calculator。你要是不写description或者写得很含糊模型就会一头雾水或者错误地调用工具。4.3 写Agent循环真正的核心骨架现在我们写真正的核心骨架。这个函数的大概逻辑是这样把你的目标发给模型模型判断需要用到工具时返回“调用请求”你根据请求去执行对应的Python函数把结果回传给模型模型再继续思考。from openai import OpenAI client OpenAI(api_key你的API密钥) def run_agent(user_query: str, max_steps: int 8): # 初始化对话的历史消息 messages [{role: system, content: 你是一个能调用工具的智能助手。}, {role: user, content: user_query}] for step in range(max_steps): # 1. 让模型判断是直接回答还是调用工具 response client.chat.completions.create( modelgpt-4o-mini, # 换成你使用的模型 messagesmessages, toolstools, ) # 2. 拿到模型的当前回复 message response.choices[0].message messages.append(message) # 把这一轮回复加入历史 # 3. 如果模型没有请求调用工具说明任务已完成直接返回最终回答 if not message.tool_calls: return message.content # 4. 如果模型请求调用工具就去执行 for tool_call in message.tool_calls: func_name tool_call.function.name func_args json.loads(tool_call.function.arguments) if func_name get_weather: result get_weather(**func_args) elif func_name calculator: result calculator(**func_args) else: result 未知工具 # 5. 把工具执行结果作为一条“工具消息”塞回对话 messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse), }) # 然后进入下一轮循环 return 步骤超限未能完成任务这段代码只有二十多行但它完整体现了我们在2.4节里说的agent loop模型生成请求系统执行工具结果回传模型继续思考直到不再请求调用工具。就是这么简单。4.4 跑一个任务看看效果我们试着跑两个任务验证一下print(run_agent(北京今天天气怎么样)) print(run_agent(计算 (23 7) * 5 - 10 等于多少))第一个任务模型会经历这样的过程看到问题判断需要调用get_weather于是返回一个JSON格式的工具调用请求系统去执行get_weather(city北京)拿到天气数据再回传给模型模型最终生成一段自然语言回答“北京今天晴温度22℃风力3级。”第二个任务也类似模型直接调用calculator(expression(23 7) * 5 - 10)拿到结果140再输出答案。注意这两个任务涉及的推理、决策、格式化输出全部是模型自己完成的我们没有写一行if-else来判断该去哪里查天气这就是Agent和普通规则脚本的本质区别。如果你跑通了这两个任务恭喜你你对Agent的底层运行机制已经有了第一手的感知。后面再用LangChain之类框架你看到的无非就是把这套循环封装了起来加上了记忆、缓存、向量检索等外围能力。换汤不换药。5. 进阶一步给Agent加上记忆和规划能力核心循环跑通了我们再往这个极简Agent上扩展两个能力让它看起来更接近真正的产品级Agent。5.1 用“历史消息”实现记忆能力你可能会发现上面的Agent有交互但没记忆。它是一次对话任务式的任务结束就拉倒。实际使用中用户经常会追问“那上海呢”如果你不把“北京天气”那一段对话历史带上模型根本不知道用户说的“那”指的是什么。解决办法也很原始——把所有对话历史都塞进messages列表里让模型每次都能看到之前聊过什么。代码几乎不用改就是把用户接下来的问题也append进去。messages.append({role: user, content: 那上海呢})然后再次调用模型。因为messages里包含了之前查询北京的完整来龙去脉模型自然就知道用户想问的是上海的天气。这个机制看起来朴素但它就是短期记忆的全部秘密。现在你再去看LangChain里花样繁多的memory模块它们做的事本质上就是自动管理哪些历史消息该放进上下文、哪些该丢、哪些该压缩避免上下文窗口溢出。5.2 在循环里加入简单的“规划”逻辑如果你想在Agent里体现更明显的规划过程有个很简单的做法在循环最开始多让模型做一件事——输出它的下一步思考过程。比如在调用大模型之前我们在messages里加一条system指令“每次行动前请先输出你对当前阶段的思考格式为思考.../思考。”这样模型的输出中就会包含一段“推理过程”你要做的是把这部分文本解析出来塞回历史消息再判断是否调用工具。有了这个机制你可以在终端里很直观地看到Agent的思考链条用户提问模型思考模型决定调用工具工具返回结果模型继续思考最终输出回答。整个过程变得透明排查问题时你也能一眼看出模型在哪个环节犯了糊涂。这就是一个极简版的“带规划的Agent”。你去看那些宣称自己“有规划能力”的Agent产品核心逻辑大同小异给模型一个思考的入口让它在行动之前“多想过一步”。6. 实操中的常见坑与排查实录我踩过的那些雷光看代码顺利那是没遇到真实世界的毒打。这里把我在多次实操中遇到的高频坑整理出来每一个都是真实案例希望能让你少走点弯路。6.1 工具返回的数据格式不规范模型“看不懂”第一次做Agent的时候我写了个工具返回的是一个复杂的嵌套字典里面套了好几层数组。模型拿到这个返回值之后直接懵了回答开始胡言乱语。后来才想明白模型和人一样也是靠“读懂”信息来工作的。它擅长处理自然语言和结构清晰的数据你要是给它一坨混乱的、语义不明的JSON再聪明的模型也会犯迷糊。解决方案有两条一是让工具返回的数据尽量扁平化有嵌套结构的就提前展开二是在工具返回的content字段里加一段文字说明数据的结构和含义比如“下面JSON中results字段是最近一周的销售额数据每条包含日期和金额”。这相当于给模型递了一份带注释的说明书它能瞬间读懂。6.2 上下文太长Agent“读到后面忘了前面”在一次多轮任务中对话历史不断累积最后上下文窗口被撑满了结果前面的任务目标被挤出了上下文Agent开始做一些和目标无关的莫名其妙操作。这个问题在长任务Agent中非常常见。解决办法有很多截断早期的对话记录、对历史信息做摘要、用向量数据库检索最相关的记忆段落放回上下文。对于新手我建议先实现“历史摘要”策略每当历史消息超过一定长度就调用一次模型把前面的对话压缩成几十个字的摘要替换掉原文。这个办法简单有效代价仅是几次额外的模型调用。6.3 Agent陷入死循环一直调用工具这可能是最让人崩溃的问题了。Agent会无限循环地调用某个工具每次拿到结果又重新触发白白消耗API费用直到步骤上限被触发。我遇到过一次模型反复调用搜索工具搜索结果的标题里存在一个术语让模型误以为需要继续搜索才能理解结果就卡在那儿转圈了。解决思路有几个层面第一给循环设置最大步数上限比如我们就设了max_steps8这能保证即使失控也不会无限消耗下去第二在system提示词里明确要求“不要在拿到结果后重复调用同一工具除非结果不完整”第三检查工具返回的内容质量很多时候循环是因为工具返回的信息过于模糊让模型觉得“好像没查到什么”所以想再查一次。6.4 模型死活不调用工具只管自己瞎编相反方向的问题也有模型明明该查工具却自行脑补答案。这种情况出现的原因往往是工具的描述不够清晰。模型不知道存在这个工具或者工具的描述让模型觉得自己编一个答案更省事。教你一个排查步骤先用单个消息直接问模型比如“请列出你可以使用的工具”看它能不能正确列出全部工具。如果它列不出来一定是工具定义有误如果列出来了但仍不调用那多半是用户问题触发的意图不够明确这时候需要调整system提示词明确指示“当用户询问天气或需要实时信息时必须调用get_weather工具”。6.5 API超时和流式响应的坑Agent循环天然是多轮调用的在低延迟要求下每一轮模型调用都是几百毫秒到几秒的耗时如果中间还有工具调用整个流程轻松超过10秒。如果你在给自己的Agent加前端界面用户大概率会因为没有即时反馈而以为系统挂掉了。解决方案是使用流式输出把模型每一轮生成的内容实时推送到前端。但流式输出在处理工具调用时有个坑你要瞒着用户不让他看到那些中间的JSON结构化信息等工具执行完毕再给他看最终结果。所以在实际开发中我一般建议后端先跑完整Agent循环只把最终结果做流式输出中间的工具调用过程通过日志系统展示而不直接面向终端用户。7. 学习路径建议从小白到独立开发者的路线图文章写到这里核心知识已经全覆盖了。最后聊点学习方法的事。很多人学Agent最常见的误区是一上来就收集一大堆框架、插件、案例然后陷入资料海洋出不来。我更喜欢这种循序渐进的路子。第一步跑通原理。就用本文的方式手写一个二三十行的微型Agent搞清楚agent loop的运作机制。这一阶段不追求复杂功能核心目标是建立体感。第二步玩熟一个框架。推荐从LangChain或LlamaIndex选一个深入研究。不要求把所有模块都搞懂把Conversation、Tool、Agent这三个核心概念吃透能写一个带记忆、带工具的Multi-turn Agent就够用了。第三步实战一个真实小项目。给自己定一个具体的、有价值的小工具目标。比如做一个“自动整理周报的Agent”它读取你的工作记录生成周报。做一个“定时抓取某网站信息并总结的Agent”。真实项目会逼你在实战中处理各种边界情况和异常这些经验才是真正长在身上的能力。第四步接触多Agent系统和复杂记忆方案。等你对单Agent已经熟练了再去研究Multi-Agent框架和向量记忆。你会发现那些看起来高深的概念本质上都是在单Agent基础上做组合和封装。底子有了上层建筑怎么搭都不慌。学Agent的过程很像当年学写代码的过程——不是靠看会的是靠自己动手一点点调出来的。第一次把Agent调通、让它真的自主完成一个任务的时候那种感觉还是挺令人兴奋的。最后分享一个我的小习惯每次开发完一个Agent我都会用比较少的步骤上限强制跑一遍然后把完整日志看一遍观察模型在每个环节的思考语言和决策逻辑。这一步对理解模型行为习惯帮助极大比看十篇技术文章都管用。希望这篇文章能成为你学习Agent的第一块垫脚石。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑