首页 / 资讯中心 / 文章详情

程序员零基础搭建AI Agent框架:从API调用到完整智能体

程序员零基础搭建AI Agent框架:从API调用到完整智能体 ★ FEATURED ARTICLE
一个程序员朋友跑来问我“我看网上都在聊AI Agent也想搞一个但是不是得先读个硕士我现在只会写CRUD有机会吗”我说有机会而且机会比你想的大得多。标题里那句“程序员零基础搭建AI Agent框架”真正缺的不是编程能力而是对Agent工作方式的理解。只要弄明白“模型—工具—记忆—编排”这四块拼图你甚至不需要精通算法就能在几天内搭出一个能干活的原型。这篇文章就围绕“零基础”这三个字展开。我会把我自己从只会调接口到做出一个能调用工具、带记忆、能执行多步任务的Agent的完整过程拆开给你看。适合谁看写过一点Python、用过或没用过大模型API、想亲手做一个Agent而不是只停留在概念层的人。看完你能获得一条清晰的路径从调用一次大模型API到拥有一个具备完整Agents能力的框架原型。1. 为什么说零基础入局不是痴人说梦1.1 Agent到底是个什么东西先说人话。Agent不是一个神秘的科技产物你可以把它想象成一个“会自己安排工作的实习生”。普通程序是一套固定的流程你输入A它执行B输出C。Agent不一样它接收一个目标然后自己决定先做什么、后做什么过程中还能去查资料、算数据、调用别的系统最后把结果整理给你。我自己的理解是大模型提供了“大脑”而Agent让这个大脑长出了手和脚。大模型本身很聪明但它只会“说话”不会“做事”。你问它“明天天气怎么样”它能告诉你很多关于天气的常识但给不出你所在城市的明日温度。Agent则不同它会把这个问题拆解成“调用天气查询工具→读取返回结果→组织语言回答”每一步都由模型决策但动作由程序执行。这就引出一个关键点搭建Agent框架真正难的不是写代码而是理解“决策循环”。这个大模型会思考那个程序负责执行中间还有记忆在保存状态。把这个心法想通了代码只是照着画葫芦的事。1.2 框架帮我们兜底了什么如果从零手搓一个Agent你要面对的问题会非常多模型返回的文本怎么解析工具调用的参数怎么从自然语言里抽出来多轮对话的历史怎么存上下文超长了怎么办模型陷入死循环怎么让它停下来这些问题每一个单拎出来都够写几千行代码。而主流的Agent编排框架本质上就是提前把这些问题解决好了暴露给你的是几个简单概念模型、工具、记忆、状态图。你用它们组合出工作流而不是从第一行代码开始造轮子。我自己早期犯过一个错误想自己实现“函数调用”那一套协议结果光解析模型返回的参数JSON就折腾了两天格式稍微一变就崩溃。后来换了思路——先理解框架的约定而不是去发明约定。这就像你想做一个新的网站没必要先去做一台服务器直接在现成的服务上盖楼就行。选框架新手第一原则选社区活跃、文档有中文、示例多的。另外别贪多一开始只需要一个“能跑的玩具”不要去看那些复杂的企业级架构图。2. 搭建前先把这4个概念吃透2.1 模型一个会接话的“大脑”Agent的一切决策都来自大模型输出所以第一步是把模型接入搞明白。这里说的“接入”不是部署模型而是调用API。你只需要知道三个参数model模型标识、messages对话消息列表、temperature随机性。在代码里这就对应着一次HTTP请求把消息发给服务端拿到返回的文本。有一个概念特别重要叫System Prompt系统提示词。它是你给模型设定的“人设”和“行为准则”。比如你可以写“你是一个日程助手回答要简洁并调用日历工具来安排会议”。这个角色设定对Agent的行为影响极大后续我们让模型做工具选型靠的就是它。另一个概念是Output Token也就是模型一次能输出的最大字数。零基础最容易忽略它结果模型回答到一半被截断看起来像程序出Bug了。实际上是你没告诉它“话不能太长”。我把这理解成给实习生一张答题纸不限制篇幅他可能写不完限制了反而能给你要点式的答案。2.2 工具给大脑装上手和脚工具是Agent区别于聊天机器人的根本。所谓工具不过就是你写一个普通函数然后告诉大模型“有这个函数什么时候调用参数是什么”。模型自己不会执行函数它只会发出一个调用请求真正执行还是你的Python代码。这一块有两个实现层次。简单的是“文本约定”你在提示词里写“如果你想查天气请输出weather(query城市名)”然后程序解析这句话。高级一点的是“函数调用协议”模型原生支持结构化返回函数名和参数你直接把函数Schema告诉它它就能按JSON返回。零基础建议先从高级协议入手。为什么解析自然语言会出现无穷无尽的格式变体而结构化返回是模型厂商训练好的能力稳得多。我在做的过程中发现一个工具函数关键在于描述写得好不好模型就靠这段描述来判断何时调用它。比如我写“get_weather(location: str, date: str): 查询某地某日天气”模型就知道当用户问天气时应该调用它。2.3 记忆短期与长期记忆是Agent最容易被忽略的部件。一个没有记忆的Agent就像金鱼每轮对话都忘了前一轮说了什么。技术上你要维护一个messages数组把用户的问题和模型的回答都追加进去再一起发给模型。但这里有一个巨大的坑大模型输入Token是计费的而且有长度上限。把历史全部塞进去不光变慢还会爆掉上下文窗口。所以实际开发需要一种叫“滑动窗口”的策略只保留最近N轮对话更早的内容可以总结成一段摘要或者直接丢弃。长期记忆则更复杂一点通常需要向量数据库把历史记录转成向量存起来需要时按相似度召回。零基础阶段不急着上向量库先用一个JSON文件把关键信息存下来就够了。记忆的目标不是“全都记住”而是“记住有用的”。2.4 编排循环是Agent的呼吸编排是Agent的大脑回路。现在最流行的模式叫ReAct即“思考—行动—观察”的循环模型先思考下一步做什么调用一个工具看到工具返回结果再思考下一步直到它认为可以给出最终答案。用代码表示就是一个while循环。听起来是不是没多高级但难就难在循环的控制上。你要设计终止条件否则Agent可能陷入死循环。常见手段有三个最大轮数限制比如最多执行10步、停止信号判断模型返回意图为“结束”、时间限制。每一个都很必要我在没有做终止条件的时候见过Agent反复调用同一个工具把API配额跑光了才反应过来。理解了这个循环你就理解了90%的Agent框架底层。一些复杂框架比如多Agent协作、子Agent递归也都是在这个基础上长出来的。3. 从零搭一个能跑起来的Agent实操3.1 准备环境与依赖我建议你用Python 3.10原因是有更好的类型提示调试更方便。整个项目我们只依赖标准库再加一个dotenv用来读配置。你不需要装任何深度学习库也不用本地GPU。环境准备三步走创建虚拟环境避免污染全局。安装依赖pip install python-dotenv requests。在大模型服务商那边申请一个API Key配置到项目根目录的.env文件里。有些人一听调API就觉得要写一堆网络代码。其实不用第三方库把HTTP请求封装好了你只需要传一个URL和一段JSON。我自己的习惯是在最开始就搭建“配置模块”把所有可变的东西都放在.env文件里比如模型名、API地址、密钥。这样一来后续想从某厂商切换到另一家只需要改几行配置不用动业务代码。3.2 只调用模型写出你的第一个Agent雏形先写一个最基础的功能向大模型发送一句“你好”拿到回复。这一段代码虽然简单但它是所有Agent的地基。import os import requests from dotenv import load_dotenv load_dotenv() API_KEY os.getenv(LLM_API_KEY) BASE_URL os.getenv(LLM_BASE_URL) MODEL_NAME os.getenv(MODEL_NAME, default-chat-model) def chat(messages): response requests.post( f{BASE_URL}/chat/completions, headers{ Authorization: fBearer {API_KEY}, Content-Type: application/json, }, json{ model: MODEL_NAME, messages: messages, temperature: 0.7, }, timeout60, ) response.raise_for_status() data response.json() return data[choices][0][message][content] if __name__ __main__: messages [ {role: system, content: 你是一个乐于助人的助手。}, {role: user, content: 请用一句话介绍你自己。}, ] print(chat(messages))这段代码做了什么其实就三步把对话列表发送出去、等待响应、取出回答文本。你运行它就能体会到所谓“接入大模型”并没有任何魔法。这里有个细节messages里分system和user两种角色。System角色的内容在逻辑上是“导演指令”对Agent行为影响很大建议所有Agent项目都从这里开始定义人设和目标。3.3 加入工具让Agent能查天气、能算日期这是最关键的一步。我们来实现“工具调用”。目标用户问“明天北京会下雨吗”Agent不能靠模型瞎编而是调用一个本地函数拿到数据再回答。共分四步定义真实函数。用JSON Schema描述这个函数告诉模型“有这个工具”。在对话里附上描述。模型返回调用意图后真正执行函数并把结果发回模型。先定义工具描述tools [ { type: function, function: { name: get_weather, description: 查询某城市在某日期的天气情况返回温度、降水概率和天气状况。, parameters: { type: object, properties: { city: {type: string, description: 城市名称比如北京}, date: {type: string, description: 日期格式YYYY-MM-DD} }, required: [city, date] } } } ]这段描述不是给人看的是给模型“理解工具能力边界”用的。你想让模型准确选工具描述就得精确到“参数是什么含义”和“什么时候该调用”。我见过不少人把描述写得模棱两可结果模型在不需要调用工具时也去调用乱做一团。接下来实现本地函数def get_weather(city: str, date: str) - str: # 这里接入真实天气服务为了演示返回一条固定数据 return f{city} 在 {date} 的天气为多云温度18-25℃降水概率20%。然后写主循环。为了让你看清楚我用一个极简版本def agent_with_tool(user_query: str): messages [ {role: system, content: 你是一个能调用工具的助手。需要查天气时使用get_weather工具。}, {role: user, content: user_query}, ] for step in range(5): # 最多5轮 response requests.post( f{BASE_URL}/chat/completions, headers{Authorization: fBearer {API_KEY}}, json{model: MODEL_NAME, messages: messages, tools: tools, tool_choice: auto}, timeout60, ) message response.json()[choices][0][message] # 如果模型返回了工具调用请求 if message.get(tool_calls): messages.append(message) for tool_call in message[tool_calls]: func_name tool_call[function][name] args json.loads(tool_call[function][arguments]) if func_name get_weather: result get_weather(**args) # 无论工具执行成功与否都要把结果通过 roletool 发回给模型 messages.append({ role: tool, tool_call_id: tool_call[id], content: result, }) continue # 继续循环让模型看到工具结果后做判断 # 如果没有工具调用说明Agent已经准备好回答 return message[content]这段代码是整个Agent的核心骨架。为什么工具调用之后要continue因为工具返回的数据模型还没见到它必须“思考”完这些数据后才能组织最终答案。这跟人办事一样你打听完了信息不能说“我问完了没下文了”得把结论汇报出来。我用自己的天气Agent测试过一句话“明天杭州适合户外跑步吗”它会先查天气如果拿到降水概率高还会接着提示“建议改成室内运动”。这背后就是循环推理的效果不是模板规则能实现的。3.4 加上轻量记忆让Agent记住你说过的话目前上面的代码是无状态的你问完一句下一句它全忘了。这在实际中没法用因为用户一定会追问上下文。最简单有效的方案是维护messages列表但只保留最近的对话片段MAX_HISTORY 6 # 最多保留6条消息3轮左右 def append_and_trim(history, new_msg): history.append(new_msg) if len(history) MAX_HISTORY: return history[-MAX_HISTORY:] return history这里有个容易被忽视的问题系统提示词system不应该被挤出去。你在做截断的时候要把role为system的消息单独拎出来剩下的才参与滑动窗口。再往后你会面临“上下文摘要记忆”和“向量记忆”但入门阶段先别贪。你有两个体感收获就够历史需要管理、token要省钱。我用一个真实例子算给你看假设一条历史消息平均200字约合150个token中文一个字大概对应1.5个token保留20轮就是3000 token。3000听起来不多但加上工具定义、系统提示、工具返回一轮流量可能直接飙到8000 token以上。生产环境这么玩成本一下就上去了。所以零基础阶段的目标不是“做一个完美产品”而是“做一个能跑通逻辑的Demo”。记忆管理做到“不爆上下文、记住最近关键信息”就够了。4. 常见问题与排查技巧实录4.1 工具存在模型就是不调用这是我被问得最多的问题。现象是你明明把工具描述传上去了模型也读到了但它就是凭自己的知识胡编一个答案。排查思路按优先级走看System Prompt。你是不是写了“尽量直接回答”如果是模型自然会绕过工具你得分明告诉它“涉及实时信息时必须使用工具”。看工具描述是否具体。描述越抽象模型越不会用。比如“获取数据”就不如“获取指定城市的当前温度与风速”好用。看参数名是否让模型好填。参数名如果叫arg1模型很可能不知道填什么调用就失败了。给工具描述加少量示例是另一招不过别堆太多会让Token账单变难看。我处理的绝大多数“不调用”问题最后都出在描述上而不是代码上。4.2 模型一直重复调用同一个工具遇到最多的场景是你让Agent查天气它查完一遍发现下雨又查了一遍再查一遍就是不给最终结论。这是陷入了“观察—再行动”的循环里出不来。解决办法设置max_steps用轮数止损。在系统提示里写明“拿到工具结果后如果信息足够回答用户必须直接给出最终答复不再调用工具”。检查工具返回格式是否不明确比如返回的是一个空字符串模型看不懂只能再查一次。技术上说工具返回的内容最好是“人话”不要只返回一个数字0。我有个教训某个函数返回了JSON嵌套模型解析不清楚就反复用另一个角度去调用后来我把返回内容改成了一句话描述循环立刻消失了。4.3 上下文长度爆掉这是Agent上线后会遇到的硬仗。你的提示词、工具定义、历史记录、工具返回都在抢上下文窗口。我有一个常用的成本估算公式单次请求Token ≈ 系统提示词Token 工具定义Token 历史消息Token 本次用户输入Token如果工具定义有800 Token、历史有4000 Token那么哪怕用户只输入了10个字请求也差不多消耗5000 Token。那怎么降精简工具描述能把1000 Token压缩到400就已经省了一半。限制历史轮数需要长记忆用“摘要”代替原文。工具返回内容只截取关键字段别把整份数据塞回来。举个例子你的工具返回了一个1000行日志模型根本不需要那1000行只关心里面的错误码那你应该在函数内部先过滤再返回“错误码401说明认证失败”。这既是省Token也是帮模型减轻注意力负担。4.4 回答质量忽好忽坏如果你发现同样的输入Agent有时答得很好、有时答得离谱这多半是temperature参数搞的鬼。温度越高随机性越大0.2以下几乎稳定0.8以上就开始发挥不定了。工具调用和逻辑推理类任务我建议把temperature在0到0.3之间创意写作或头脑风暴才用0.7以上。这个参数值不是玄学它直接影响模型选择Token时拿概率分布还是偏重高概率项。另一个变量是模型自身版本调整哪天厂商偷偷改了模型行为你的Agent效果就会漂移。做Agent需要养成记录版本的习惯每次更换模型版本把关键测试用例重跑一遍。我在实践中准备了一组“冒烟测试”十个固定问题只要能稳定通过我就认为模型切换没有破坏基本能力。5. 再往前走一步框架与未来扩展5.1 从手写循环到编排框架当你把上面的手工代码跑通你已经理解Agent最核心的原理了。下一步可以去看开源编排框架但此时心态完全不一样你是带着问题去看的不是带着迷茫去看的。框架能帮你的是状态流转管理、并发调度、长期记忆插拔、可视化追踪。自己在脚本里写while True没问题一旦Agent要跑“多分支流程”比如先写一个总结再发邮件再录入数据库你就需要一个能表达“先A后B失败走C”的编排层。我用过的其中一种框架核心思路是基于有向图状态机每个节点是一个处理函数边是流转条件。Debug时能看到当前Agent在哪个节点这对排查复杂度帮助很大。5.2 增加长期记忆和评估体系如果想把Agent做成产品有两件事逃不掉评估和可观测性。评估是什么就是你得有一批测试用例每次改动后自动跑一遍看看Agent的综合表现是变好了还是变差了。没有评估你面对的就是一个“薛定谔的Agent”——你说它好用但说不清哪里好。可观测性则要求你记录每次请求的输入输出、token消耗、调用链。我所有的生产级Agent都会打日志输出的格式是这样的[Agent Step 1] Tool Call: get_weather(args{city: 杭州, ...}) [Agent Step 2] Tool Result: 多云25℃ [Agent Step 3] Final Answer: 杭州今天多云适合跑步。有了这种日志你才能定位“它是哪一步想歪的”而不是对着最终结果猜。5.3 零基础要避开的几个误区最后给准备开干的人几个我总结出来的避坑方向第一别一上来就堆框架。先用标准库写一个最小原型把“模型-工具-循环”的体感拿到。不然框架里全是不理解的抽象概念出问题你根本不知道从哪查起。第二别迷信“一个Agent包打天下”。你的第一个Agent最好只做一件事比如“查天气”“归档文件”“生成周报”。范围收窄成功率会成倍提升。等到把流程跑顺再加新工具、新能力。第三别忽略成本控制。开发阶段每天反复调接口一个不稳定提示词可能烧掉大量额度。我习惯把日志里每次请求的Token数都记下来定期看永远知道钱花哪儿了。第四别怕试错。你第一次写出来的Agent大概率是笨的很正常。我的第一个Agent连“你好请帮我查天气”这样直白的问题都分不清后来靠迭代提示词和工具描述才逐渐变得能分清“今天”和“明天”。Agent工程本质上是“调教”和“校准”的过程不是一蹴而就的代码交付。写代码之外的几点体会说实话这段从零搭Agent的经历最让我有收获的不是代码本身而是理解了一种新的编程思维方式你不再写死执行路径而是在给一个智能体提供决策所需的环境和边界。你给工具描述其实是给它“说明书”你给系统提示词是给它“工作守则”你设最大轮数是给它“下班时间”。编程的核心从“告诉计算机每一步做什么”变成了“让模型自己找出每一步做什么同时我们确保它不会跑偏”。我强烈建议每个被标题里“零基础”劝退的程序员都试一次。不用等什么基础都学好了直接开始。就用这篇文章里的最小骨架换成你自己的业务场景比如“把招聘JD转成面试题”“把会议纪要整理成待办清单”“自动归档下载目录里的文件”。你会发现编程的门槛从来没这么低过难的也不再是写代码而是想清楚“你要让Agent替你做一件什么样的事”。跑起来一个能对话的小程序只要十分钟但理解Agent的工作方式、学会给它配工具、学会控制它的运行边界才是能长期受用的能力。我也不藏着掖着入门Agent并没那么难难的是别在起点就选错方向。这篇文章里每一个坑我都踩过希望你是下一个轻松绕过去的人。
阅读完成 · 觉得有帮助?
咨询建站