ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Function Calling实战:从零搭建多步交互AI Agent

Function Calling实战:从零搭建多步交互AI Agent 开场当传统API开发遇到会“自己思考”的接口如果你是个写了三五年业务代码的Web开发者最近一定被AI Agent刷屏了。GitHub趋势榜上全是Agent项目招聘JD里开始出现“Agent开发经验”连面试官都开始问“你怎么理解Function Calling”。说实话两年前我听到这个概念的第一反应是这不就是让模型调API吗有什么好吹的。但真的动手把第一个带多步交互的Agent跑通之后我才意识到事情没那么简单——Function Calling确实是在调API但它是让模型自己决定“调哪个API、按什么顺序调、参数从哪里来”这就完全是另一套思维方式了。这篇文章就是写给Web开发者的实战笔记。我会从零拆解Function Calling的运行逻辑用真实代码演示如何搭建一个能完成多步任务的Agent重点讲提示词怎么优化才能让模型“听话”以及那些官方文档里不会写的坑——比如模型突然不调工具了、参数传错了它还在硬编、死循环怎么防。内容面向有基本HTTP/API经验的开发者即使你完全没碰过大模型只要懂JSON、懂请求响应就能跟上节奏。1. 为什么Web开发者要关注Function Calling它到底解决了什么问题1.1 先搞懂大模型为什么“不会算账”用过ChatGPT的人都有体会你问它“23乘以47等于多少”它可能在大部分时候答对但一旦数字变大、步骤变多它就很容易一本正经地胡说八道。原因在于大模型的本质是“下一个词预测器”它不是在计算而是在根据海量训练数据推测“这道题最可能的答案是什么”。它没有真正的计算器也没有执行环境。所以你会发现一个很尴尬的局面模型能写出漂亮的代码片段但你不能让它直接操作你的数据库它知道天气App应该返回什么格式但它不知道北京的实时温度。这就是大模型的能力边界——它擅长“理解”和“生成”不擅长“计算”和“执行”。这几个月的AI Agent热潮本质上就是在解决这个边界问题。Agent不是一个神秘的系统它的核心思路特别朴素让大模型只负责“思考”和“决策”把“执行”外包给外部工具。模型说“我要查一下上海的天气”然后代码帮它真实地调一次天气API把结果再喂回给模型。模型再基于真实数据继续推理和回答。这一步一思考、一步一执行的循环就是Agent最底层的形态。1.2 Function Calling在中间扮演什么角色很多人刚接触Function Calling会有一个误解以为它是让模型变得更强的魔法。其实Function Calling只是一个协议——约定好了模型输出什么格式的结构化数据由你的代码去解析、执行、返回结果。用Web开发的老话来说这就像是前端表单和后端接口之间的契约。你给大模型一份“接口文档”tools参数大模型看完后回你一个“我要调用哪个接口、传什么参数”的JSON你的后端代码负责真正执行这个请求。区别在于传统接口的调用方是有明确业务逻辑的前端而Function Calling的调用方是一个能理解自然语言的模型它会根据用户的不同表达动态决定调哪个函数。我打个比方你就明白了。传统API开发里前端页面是个固定的表单用户点击按钮就触发固定请求。而Function Calling相当于你做了一个智能中台用户说一句“帮我看看明天去杭州合适吗”这个中台自己去查天气API、查高铁票API、查酒店API然后把结果汇总成建议。中台本身不生产数据但它知道该问谁要数据以及按什么顺序问。对于Web开发者来说这是个巨大的机会**你不需要学习复杂的机器学习算法不需要微调模型。你只需要把你熟悉的API按照模型能理解的JSON Schema格式描述清楚。你现有的后端服务、数据库、第三方接口都可以无缝变成Agent的“手和脚”。这也是我强烈建议Web开发者从Function Calling切入Agent的原因——它把你已有的技能直接迁移到了AI时代而不是让你从零开始。2. 搭建第一个Function Calling Agent从选模型到完整代码2.1 模型选型与API协议准备动手之前先解决选型问题。市面上支持Function Calling的模型不少OpenAI系的GPT-4o、GPT-4o-miniAnthropic的Claude系列Google的Gemini国内的通义千问、DeepSeek、智谱GLM都支持。对于学习目的我建议选性价比高的模型比如GPT-4o-mini或者DeepSeek因为Agent的调试过程往往会产生大量请求烧钱不是目的跑通逻辑才是。所有主流模型的Function Calling API都有一个共同的抽象逻辑只是字段名略有不同你发送请求时带上用户消息user message和可用工具定义tools。模型判断需要调用工具时在响应中返回一个tool_calls字段里面是提议的工具名称和参数。你的代码执行工具把工具的执行结果作为一个新角色通常是tool角色的消息追加到对话里再次请求模型。模型看到工具返回的真实数据后生成最终回复或者继续发起下一轮工具调用。这里我强烈建议你先用OpenAI兼容协议来学习因为目前它几乎成了行业标准接口。你甚至不需要OpenAI官方的SDK直接用HTTP请求或者Python的openai库就能完成实验。下面的示例都基于这个协议。2.2 从零写一个能查天气、算计算器的Agent直接上代码。我先用一个最小可运行的Python示例展示单轮Function Calling的完整流程。这个Agent具备两个能力查实时天气和做数学运算。import json from openai import OpenAI client OpenAI() # 根据你的服务商配置 base_url 和 api_key # 1. 定义工具清单——这是给模型看的“接口文档” tools [ { type: function, function: { name: get_weather, description: 查询指定城市的实时天气, parameters: { type: object, properties: { city: { type: string, description: 城市名称例如北京、上海 } }, required: [city] } } }, { type: function, function: { name: calculate, description: 进行数学运算支持加、减、乘、除, parameters: { type: object, properties: { expression: { type: string, description: 数学表达式例如12*75 } }, required: [expression] } } } ] # 2. 这是你的“工具实现”也就是真正执行的那段代码 def execute_tool(name: str, arguments: dict) - str: if name get_weather: # 这里接真实的天气API这里用模拟数据代替 return json.dumps({city: arguments[city], temperature: 26, condition: 晴}) elif name calculate: # 注意eval有安全风险生产环境请用表达式解析库 result eval(arguments[expression]) return json.dumps({result: result}) else: return json.dumps({error: 未知工具}) # 3. 单轮对话让模型决定是否调用工具 messages [ {role: system, content: 你是一个智能助手可以调用工具来回答用户问题。}, {role: user, content: 北京的天气怎么样如果气温超过25度顺便帮我算一下32*18} ] response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools, tool_choiceauto # 让模型自己决定要不要调、调哪个 ) # 4. 根据模型返回结果判断是否需要执行工具 msg response.choices[0].message if msg.tool_calls: print(模型发起工具调用, msg.tool_calls[0].function.name) tool_result execute_tool( msg.tool_calls[0].function.name, json.loads(msg.tool_calls[0].function.arguments) ) # 把工具结果追加到消息历史中 messages.append(msg) # 先把完整的助手消息加入历史 messages.append({ role: tool, tool_call_id: msg.tool_calls[0].id, content: tool_result }) # 再次请求模型 second_response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools ) print(最终回复, second_response.choices[0].message.content) else: print(直接回复, msg.content)看到这里你可能会嘀咕这不就是一个if-else分发器吗确实最小实现就是这么朴素。但请注意两个关键细节第一工具描述description是写给模型看的不是写给用户看的。它写得越清晰模型选错工具的概率越低。这跟写API文档时把功能讲清楚是一个道理只是你的读者变成了模型。第二整个调用过程是无状态的。模型记不住上一次对话的状态你需要把所有的历史消息都带在请求里。上面的代码里我把助手消息和工具结果都append到messages里这一步是必须的——如果丢了模型就不知道刚才自己调了什么工具、拿到了什么结果。2.3 为什么说tools的JSON Schema就是Agent的“技术债”写工具定义的时候Web开发者最常见的错误是把它当成给自己看的后端接口定义来写从接口命名到参数说明都非常随意。但你要明白这份JSON Schema是模型唯一能看到的“文档”模型对工具的理解完全取决于这里面的描述。我举个例子假设你有一个发送短信的工具如果你把description写成“发送短信”模型在用户说“帮我把验证码发给这个手机号”的时候可能并不会调用它。但如果写成“发送短信到指定手机号message参数为短信内容仅用于给用户发送验证码”模型的调用准确率会明显提高。原因很简单——模型是通过文本相似度来匹配用户意图和工具描述的描述越具体、越贴近用户的自然表达匹配越精准。另外参数名和类型定义也直接影响模型输出。比如你定义手机号字段时用了phone_number模型能理解但如果你用了一堆没有语义的缩写比如pn模型猜错的概率就大增。参数必填项务必标清楚否则模型会自作主张跳过它认为“不重要”的参数。这块做得好不好决定了你后面所有提示词优化的空间。工具定义本身就是一种“提示词”而且是结构性最强的提示词。后文我还会专门讲怎么优化描述。3. 多步交互的实现逻辑与提示词优化实战3.1 多步Agent的“思考-行动-观察”循环上面单轮示例只能实现“用户一问模型一调Agent一答”的简单场景。真实的Agent诉求远不止此用户可能说“帮我安排好这周末去上海的高铁票”这时候Agent可能需要先查高铁班次、再选推荐班次、再查酒店、最后生成行程单。整个过程中涉及多次工具调用且后一次调用依赖前一次的结果。这个循环在技术上有个经典名字ReActReason Act。翻译成大白话就是模型阅读当前对话推理出下一步需要的工具Reason。模型输出工具调用请求代码执行工具Act。工具执行结果返回给模型模型观察结果决定是否继续Observation。如果任务没结束回到第1步否则生成最终回复。实现多步循环的代码并不复杂核心就是加一个while循环同时设置最大轮数上限def run_agent(user_input, max_iterations5): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_input} ] for i in range(max_iterations): response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools ) msg response.choices[0].message if not msg.tool_calls: return msg.content # 没有工具调用任务结束返回最终回答 messages.append(msg) # 记录模型的决定 for tool_call in msg.tool_calls: result execute_tool(tool_call.function.name, json.loads(tool_call.function.arguments)) messages.append({ role: tool, tool_call_id: tool_call.id, content: result }) print(f第{i1}轮调用了{tool_call.function.name}结果{result}) return 已达最大迭代次数任务终止这个循环看起来简单但真正决定Agent质量的不在循环本身而在两处一个是系统提示词System Prompt怎么写另一个是每轮工具结果和上下文怎么组织。接下来重点讲这两个。3.2 系统提示词的设计给Agent立规矩写系统提示词这事很多从传统开发转过来的人特别不习惯。传统开发的代码是确定性的逻辑而提示词是概率性的引导。你需要用文字清晰表达Agent的角色是什么、行为边界在哪里、如何处理异常情况。我自己的系统提示词模板长期迭代下来沉淀了一套比较稳定的版本分享出来给你参考你是“智能生活助手”一个通过调用工具解决用户实际问题的AI助理。 你拥有以下能力 - 查询天气、计算数学公式使用工具 - 回答通用知识问题直接回答无需调用工具 工作时必须遵守以下规则 1. 先判断用户意图。如果用户请求涉及实时数据或精确计算必须调用对应工具严禁依靠训练数据中的记忆作答。 2. 调用工具前先向用户简述你将要执行的操作。 3. 工具结果返回后用通俗易懂的语言向用户解释结果必要时给出建议。 4. 如果工具调用失败或返回异常告诉用户暂时无法处理并提出替代方案不要编造结果。 5. 多步骤任务要逐步推进每完成一步向用户汇报进度全部完成后输出完整结论。 6. 禁止执行超出工具能力范围的操作。如果用户请求无法满足直接说明原因。有个很微妙的点是第1条。很多新手Agent最常见的问题就是模型“偷懒”——用户问天气它凭记忆回答“北京夏天很热”而不是去调工具。把这条规则写得既严格又带说明能显著降低这种偷懒调用的概率。还有一个易被忽略的细节系统提示词也占用模型的上下文长度。别写成一部长篇小说控制在几百字以内规则分条目关键信息前置。你的工具描述、历史消息、工具结果都需要空间系统提示词太长会挤占这些内容的注意力。3.3 工具描述该怎么写让模型一次选对工具描述是我做提示词优化时投入产出比最高的部分。一个写得好与坏的工具描述可能让模型调用的准确率相差30%以上。这里我把打磨工具描述的checklist列出来描述包含动词对象场景。比如“get_user_score”不要只写“获取用户分数”写成“根据用户ID获取用户在指定比赛中的积分分数用户可能称为积分、得分、分数”就清晰很多。明确参数边界和取值来源。如果参数是可枚举的在description里列出所有允许值如果参数值来自上一轮对话或其它工具结果要写清楚来源。比如“dept_id参数必须来自get_departments工具返回结果用户提到的部门名需要先转换为部门ID”。在description里给出一个示例用法。模型非常擅长模仿示例一个短小的“例如get_weather(city‘北京市’)”比大段参数说明更有效。相似工具之间要刻意制造区分度。如果你的Agent同时有“获取当日订单”和“获取历史订单”两个工具描述里一定要明确时间边界否则模型很容易混淆。表达负面规则。比如“此工具只能用于查询已支付的订单未支付订单请使用get_pending_orders”。补充一个我踩过的坑工具描述里有些词看起来没问题但在模型的语义空间里会和其它词混淆。比如有个工具“send_notification”我原本写的是“推送通知给用户”结果模型在用户说“发个短信提醒我”的时候总是调错把“推送通知”和“短信”当成一回事了。后来我把描述改为“应用内发送系统通知App Push不是短信、不是邮件”错误率立刻降下来了。写工具描述时多想想“用户换一种说法模型还认不认识这个意思”。3.4 多轮上下文管理避免Agent“失忆”和“串台”多步交互还有一个容易翻车的细节上下文管理。模型对前面的对话是“一念之间”的记忆每一轮都在读全部历史做预测。问题有几个层面第一是信息过载。比如第1步查天气返回了一大段JSON第2步模型需要做算数这段JSON又占空间又干扰决策。解决方案是控制工具返回结果的长度——能精简的字段就精简能只返回结论就只返回结论。比如“resolve_arithmetic”工具返回的不是“表达式值为108”而是直接“108”减少模型二次解析的负担。第二是多次工具调用的结果混淆。我一开始写多步循环时把每轮的所有工具结果都全部塞进消息历史。当工具数量多了之后模型经常出现“张冠李戴”把上一个工具的结果当作当前工具的结果来推理。后来我养成了一个习惯每轮工具调用前输出一个简短的执行摘要把关键信息从大JSON里提炼出来重新组织。比如“上一轮查询到杭州市气温32度适合出行接下来需要查杭州东站到上海虹桥的高铁票”。第三是冗余消息累计。对于长流程你不需要把每一轮的所有中间结果都永久保留。有些框架的做法是定期做“记忆压缩”把已经完成步骤的原始JSON替换成一句摘要。这个优化在早期不太必要但当你的Agent流程超过5步、每步返回几百字JSON时它就成了刚需。4. 一个完整的多步交互实战旅行行程规划Agent4.1 需求拆解与工具组合设计前面讲了一堆理论现在来一个完整的实战项目。目标做一个“周末旅行规划Agent”用户只需说“帮我规划一下这周末从北京去杭州的两日游”Agent自主完成以下步骤查询北京周六的天气评估是否适合出行。查询杭州周六到周日的天气判断天气对行程的影响。查询北京到杭州的高铁班次挑选合适时间的车次。查询杭州当地的热门景点生成两天行程。计算预估交通费用和基础门票费用。这个任务需要4个工具get_weather、query_train、get_hot_attractions、calculate。工具定义的关键部分如下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] } } }, { type: function, function: { name: query_train, description: 查询两个城市之间某一天的高铁班次返回出发时间、到达时间、二等座票价。注意日期必须是中国标准日期, parameters: { type: object, properties: { from_city: {type: string, description: 出发城市}, to_city: {type: string, description: 到达城市}, date: {type: string, description: 乘车日期格式YYYY-MM-DD} }, required: [from_city, to_city, date] } } }, # get_hot_attractions 和 calculate 定义略 ]需要特别注意的是query_train的date参数。模型在处理“这周末”这种模糊时间词时常常不转换成具体日期就直接调用工具。我见过很多次模型直接传“date: 这周末”的情况然后工具解析失败。这个问题的解决办法除了在工具描述里反复强调“必须是YYYY-MM-DD格式”更稳妥的做法是在代码层面做一层日期转换——在发送给模型前先让另一个工具或代码逻辑把用户输入里的相对时间解析成绝对日期。这是工程上“不要把鸡蛋放在模型一个篮子里”的思路。4.2 一步步跟踪Agent的执行过程实际跑起来之后我记录了Agent的一次完整执行过程非常有意思。第一轮用户说“帮我规划一下这周末从北京去杭州的两日游”。模型没有急着调工具而是先回复“我来帮你规划先确认一下天气和交通信息”然后发起了两个工具调用get_weather(city“北京”, date“本周末”)和get_weather(city“杭州”, date“本周末”)。注意我并没有在工具描述里明确“本周末”需要转换但模型在这里返回的date参数格式不规范。幸好我在execute_tool里做了容错处理把相对时间翻译成了具体日期周六和周日。执行结果返回了北京周六晴23度、杭州周六周日多云26到30度。第二轮模型看到天气结果后调用query_train(from_city“北京”, to_city“杭州”, date“2026-04-18”)。我设计的工具逻辑里默认接受date参数为空时自动取周六。返回结果模拟了几趟车次模型选择了一趟G字头高铁上午8点出发、中午11点30到达并把车次信息展示给用户。第三轮模型接着调用get_hot_attractions(city“杭州”)拿到了西湖、灵隐寺、西溪湿地等景点列表。这一轮模型没有立即返回最终计划而是继续调用calculate。第四轮calculate(expression“553*21200”)这其实是模型在算”两人往返高铁费门票基础费用“。这里有个有趣的现象模型把估算逻辑内化成了数学表达式这比让它用自然语言计算靠谱得多。第五轮所有信息齐了模型组织了一份完整的行程规划包含每天的时间安排、景点路线、天气提醒、总预算估算并在结尾处加了一句“我是基于实时天气和高铁数据做的规划如果需要我帮你预订可以告诉我”。整个流程跑完只用了40多秒五轮交互一次都没走错。你能明显感觉到模型不是在背答案而是真的在“按流程办事”。这种体验传统的规则代码很难实现——因为你没法预先把所有用户表达方式都match到固定流程而模型天然能理解语义差异。4.3 多步交互的异常处理与兜底策略上面的执行过程是理想情况。实际运行中多步交互的异常简直防不胜防。我总结了几类高发问题模型跳过必要步骤比如用户明明要两日游模型查完天气直接给建议压根没查高铁。这种情况系统提示词里的“多步骤任务要逐步推进”约束只能降低概率不能完全杜绝。兜底方案是代码层面做流程校验比如检查最终回复中是否包含车次、是否包含景点如果缺失就强制再开一轮让模型补充。工具调用参数错误但没有报错模型把城市参数传成了“北京市”你的代码做了模糊匹配没报错但结果可能是错误的更隐蔽的是模型把两个相似参数传反了比如from_city和to_city对调。这类问题没有银弹只能在工具函数内部做参数合理性校验比如from和to不能相同、日期必须在当前日期之后等校验不过就抛错误信息给模型让它自查重试。工具结果导致模型“编造”工具返回的数据如果字段名含义不清比如返回了一个“score”字段但模型不知道它代表好评率还是热度就可能误解。工具返回的内容也应该做“结构化可解释化”处理必要时附带一个简短说明字段。我的经验是多步Agent的健壮性不是靠模型而是靠工程兜底。模型负责“聪明”代码负责“稳定”两者缺一不可。Web开发者在这一点上有天然的优势因为传统开发中对异常处理、参数校验的理解可以直接迁移过来。5. 常见问题与排查技巧实录5.1 工具调用潜规则模型不调工具怎么办这是被问得最多的一个问题“我的工具明明定义好了模型就是不调用直接编了个答案给我”。排查方向按优先级排序检查工具描述是否清晰。这是第一大嫌疑。如果你的description写得含糊让模型觉得“直接答也行”它就会偷懒。把description改成“必须调用此工具才能获取答案”的语气会有明显改善。检查请求里是否正确传递了tools参数。很多人在多轮对话的后续请求里忘了带tools模型马上就变回“纯对话模式”。检查tool_choice参数。如果你希望模型强制调用某个工具可以设置tool_choice{type: function, function: {name: xxx}}。但这个选项适合已明确知道下一步该调什么工具的场景日常对话还是用“auto”更灵活。升级模型或换同类型不同厂商的模型。不同模型对Function Calling的支持质量差异很大有的模型对复杂多参工具定义就是“理解能力有限”。核对上下文长度。如果消息历史过长模型的注意力会被稀释可能“忘记”工具的存在。考虑截断早期消息或做摘要压缩。5.2 模型“幻觉式”调用调了一个不存在的工具模型返回的tool_calls里出现了你没有定义过的工具名或者参数集合完全不符合定义。这通常不是模型的恶意行为而是它在长文本生成时的“幻觉”。这类问题高发于工具数量多、功能重叠的场景。我在排查时最常用的办法是加一个工具白名单校验。模型返回tool_calls之后代码先校验工具名是否在已注册列表里参数是否符合JSON Schema不符合就直接构造一个错误结果返回给模型“调用失败工具名不存在或参数不合法”。模型看到错误信息后通常会自动纠正发起新的正确调用。这个白名单校验的成本极低但对稳定性的提升非常大。很多生产级框架会在底层默认加上这一层防护你如果自己手写Agent一定不要省。5.3 死循环与任务不收敛Agent最常见的“翻车现场”就是陷入循环调A工具 - 返回结果 - 调B工具 - 返回结果 - 又调A工具……反复横跳几十轮既消耗token又不出结果。我的经验是三个防线第一设置最大迭代次数上限比如5到8轮超出后强制终止并让模型输出“当前获取的信息已经足够我基于现有结果给出建议”。第二在系统提示词里明确终止条件。比如写“当工具返回结果已经能回答用户问题时立即输出最终回答不要再调用其它无关工具”。第三在代码里检测重复调用。如果同一工具在最近N轮里被调用超过X次主动中断并向模型注入一条提示“你陷入了重复调用请根据已有信息直接回答用户”。第一道防线是硬性的必须加第二、三道防线的效果取决于模型的理解能力和你的提示词水平。三层叠加能让大多数循环问题被拦截住。5.4 常用排查工具与方法这里分享一套我在调试Agent时常用的“望闻问切”流程打印每一轮消息的完整JSON。不要嫌日志长Agent的bug往往隐藏在某一条消息的角色或格式错误里。重点检查tool_call_id是否一一对应、does消息的role是否和消息类型匹配。用单步调试法定位问题。如果5步流程在第3步出错就别再从头跑整个Agent了。直接把前2步的messages固定下来单独调试第3步的请求和响应。构建回归测试集。准备10到20条典型的用户输入每次改动提示词或工具定义后批量跑一遍对比前后输出的正确率。这听起来土但确实是防止“改一个描述结果弄坏了另一个场景”的最有效手段。善用模型的响应日志。OpenAI的API响应里会带usage信息看token消耗能帮你判断是否发生了无意义的重复调用。6. AI Agent开发的技术生态与进阶方向6.1 从手写循环到框架LangGraph、AutoGen等该怎么选如果你只是学习或者做小Demo手写上面的循环足够。但到了生产环境手写Agent会出现大量重复工作并发工具调用、状态持久化、人机交互确认、错误恢复机制、可视化追踪……这些需求催生了一批Agent开发框架。LangGraph把Agent流程定义成一张图节点是“工具调用”或“人机交互”边是条件跳转。适合复杂流程编排对熟悉状态机的后端开发者比较友好但需要花时间理解它的事件循环和状态管理模型。AutoGen微软出的多Agent对话框架擅长“多个Agent互相协作”的场景。你可以定义一个用户Agent、一个助理Agent、一个审查Agent它们之间通过消息对话协作。优点是理念先进缺点是调试复杂度成倍上升。字节的Coze / Dify降低门槛的工作流平台适合快速验证和内部工具开发。如果你不想写大量代码可以先把流程在这些平台上拖出来看看效果再决定是否用代码实现。我给Web开发者的建议是先手写一两遍循环彻底理解Agent的运行逻辑然后再上框架。直接上手框架容易被抽象概念绕晕出了问题也难排查——因为你不知道底层发生了什么。6.2 与Web技术栈的深度结合Next.js、Spring Boot与Agent现在很多Web开发者关心的是Agent怎么和自己的Web应用集成。实际上Agent服务完全可以当做一个常规的“智能后端服务”来设计。你的前端发送用户消息到后端后端调用大模型API执行工具调用最终把结果返回前端。整个过程对前端完全透明。我在实践中发现几个集成要点用流式输出提升体验。Agent的多轮工具调用会产生延迟如果前端干等着用户会觉得卡顿。解决方案是用SSEServer-Sent Events把“正在调用天气工具…”、“正在查询高铁…”这些中间状态实时推给前端让用户看到进度。这也是为什么很多聊天式Agent的UI上有“打字机”效果的原因。在后端维护会话状态。每个用户应该有自己的对话历史和工具调用上下文。你可以用Redis存每个会话的messages列表也可以在数据库里按会话ID存JSON。把工具调用设计成可观测的操作。对Web开发者来说这就像给接口加日志和监控。Agent每次调用工具、每次生成回复都应该有记录。这样无论是排查问题还是做费用优化都有据可查。如果你在Spring Boot项目里集成底层的HTTP调用逻辑和你调任何第三方API没有本质区别。用RestTemplate或WebClient请求大模型接口解析JSON执行本地服务逻辑再返回响应。如果你在Next.js项目里集成可以把Agent逻辑封装成Server Action或API Route前端组件用SWR或React Query管理流式响应。6.3 给Web开发者的Agent学习路线图最后聊一下学习路径这是我带过好几个转AI方向的Web开发者后总结出来的顺序先把Function Calling的API协议吃透。找一家模型服务商用Python或Node.js写一个最小调用例程理解消息、工具、响应三者的关系。这一周左右就能上手。实现一个单工具Agent再实现多工具Agent。重点练习工具描述优化——尝试用不同的描述词观察模型调用效果的变化逐步建立对“模型怎么理解描述”的直觉。实现一个多步交互场景。选一个你熟悉的Web业务比如订单售后、客服问答、数据报表查询把它拆成多步流程用Agent串联起来。学习主流框架的核心概念。这时候再看LangGraph的图模型、AutoGen的多Agent协作就会觉得很多设计“你早该想到”。关注人机协同机制。生产级Agent一定要有“人工确认”环节。比如Agent准备执行扣款操作前应该返回一个确认请求给用户用户点击确认后再继续。这个机制的设计非常考验工程能力。我对2026年的Agent趋势判断比较乐观随着多模态模型成熟Agent能处理的场景会越来越复杂但底层的Function Calling协议和“思考-行动-观察”循环不会变。Web开发者现在入场学的每一个原理和踩的每一个坑都还能在未来很长一段时间内复用。说到这儿我把这几年摸索下来的核心心得再拿出来晒一晒Agent开发最难的从来不是写代码而是“理解模型的行为模式”。模型是个概率系统它会偷懒、会幻觉、会钻提示词的空子。你得像带新人一样给它清晰的边界、明确的反馈、兜底的机制它才能稳定地把活干好。这对习惯了确定性逻辑的Web开发者来说是一个不小的思维转变但一旦适应了你会发现构建那些“几乎什么都能干”的应用真的很有成就感。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进