从ChatBot到大模型Agent:工具调用与自主规划进阶指南

发布时间:2026/10/20 5:03:12
从ChatBot到大模型Agent:工具调用与自主规划进阶指南 你是不是也刷到过那种酷炫的Agent演示——问一句“帮我写份周报顺便发给老板”屏幕上的大模型就开始自己调工具、查数据、生成文档整个过程跟个真人员工一样。再看看自己手里只会一问一答的ChatBot顿时觉得差距有点大。别慌这差距没有想象中那么远。所谓大模型Agent说白了就是给会说话的模型再装上“脑子”和“手脚”让它不仅能聊天还能自己规划任务、调用外部工具、根据结果不断修正下一步动作。而从一个只会“你一句我一句”的ChatBot进化到能够自主完成多步任务的Autonomous Agent中间有一条非常清晰的进阶路径——今天这篇就把这条路上的关键节点全部拆开揉碎从零开始讲清楚。这篇内容适合准备入坑大模型应用开发的程序员也适合做技术选型时需要快速理解Agent边界的产品和技术负责人。文章会避开那些绕口的概念定义直接用代码、流程图逻辑和真实场景把“Agent是怎么跑起来的”讲明白。你不需要有深厚的机器学习背景只需要懂常规的Python开发和HTTP调用就能照着一步步走完。1. 先搞清楚一件事ChatBot和Agent差在哪很多教程一上来就抛“ReAct”“规划器”“记忆管理”这类术语结果新手听了个寂寞代码也没跑通。我建议第一步先把地基打牢——搞清楚ChatBot和Agent的本质差异。1.1 为什么ChatBot只是“单轮问答机器”ChatBot的工作模式可以用一句话概括有问就有答答完就结束。用户输入“今天天气怎么样”大模型内部走一遍推理把“北京晴21度”这段文字吐出来一次调用完成。哪怕你实现了多轮对话把历史消息一起拼进Prompt里发过去它本质上依然是“每次独立问答只是问题里带了聊天记录”。这种模式解决的是信息生成和问答交互比如客服机器人、文档问答、知识库检索增强生成RAG都归在这一类。它的问题很明显模型只能动嘴不能动手。你说“帮我订个明天下午三点的会议室”模型再聪明也只能回你一段“好的建议您使用XX系统进行预订”——因为它没有访问你企业内部预订系统的入口也没有在对话过程中触发“查询→确认→预订→反馈”这条行为链的能力。1.2 Agent的核心特征感知、决策、行动闭环Agent和ChatBot最大的分水岭在于Agent不再是“回答你”而是“替你做”。它的工作模式更像一个真人实习生感知Perception接收你的指令同时能主动拉取外部信息比如调用搜索引擎查资料、读取数据库里的一份表格。决策Decision基于当前信息和最终目标拆解出下一步该做什么可能需要想好几步。行动Action实际去执行比如调用API发一封邮件、把结果写进一个文件、点击页面上的某个按钮。观察Observation拿到行动之后的结果再回去修正判断循环往复直到目标达成。这四步串在一起就是Agent的核心循环。我做过一个很粗浅的类比ChatBot是“键盘侠”嘴上能百科全书式地回答一切问题Agent是“跑腿工”接到一个活自己拆成几步每一步都真的把事办了跑完还会回来汇报。1.3 从L1到L5Agent成熟度的五个层级把“进阶之路”说清楚有个很实用的分层模型我在团队内部做技术分享时用它比划过很多次层级名称特征描述典型表现L1基础ChatBot单轮或多轮对话无外部工具只会回复文本无法操作外部系统L2工具增强ChatBot能调用预设API但由用户一步步触发用户说“查天气”它调用天气API返回结果L3任务型Agent能理解目标自动选择并组合多个工具完成任务“安排会议”它自动查日程、选时间、发邀约L4自主规划Agent能自己分解复杂目标规划步骤并执行“帮我调研竞品”它自动列出搜索计划并逐项执行L5多智能体协作系统多个Agent协同各司其职互相校验一个写方案一个查数据一个做质检后面正文里的代码示例会逐步覆盖到L2和L3让你亲手感受“从只会回答到开始做事”这一层质的跨越。2. 动手前先选好你的“施工材料”真正开始写代码之前有几样东西得先定下来用什么大模型、用什么Agent框架、跑在哪里。很多人死在这一步——不是代码写不对是选型没选对后面越写越别扭。2.1 大模型选型API优先还是本地部署对新手来说我不推荐一上来就本地部署大模型。那玩意光显卡显存就够你折腾一周的。更务实的路线是直接调用成熟的大模型API。国内可直连的通用大模型API比如各种开放平台的对话接口上手最快SDK几行代码就能发起对话成本也低调试方便。国际主流大模型API能力全面工具调用和推理表现优秀但需要考虑网络环境与合规问题。我的建议是第一版Agent优先选择工具调用Function Calling能力稳定、文档齐全的大模型API。因为Agent的核心不是“模型多聪明”而是“模型能不能按照约定格式输出工具调用请求”。这个能力不行后面全白搭。2.2 框架选型从零手写还是站在轮子上市面上有不少Agent开发框架比如开源的LangChain、LlamaIndex以及国内一些新锐的Agent框架。但截至我写这篇文章时的经验新手我建议先别碰大而全的重框架。原因很实际重框架抽象级别高封装太厚出了问题你根本不知道是哪一层出的排查起来像大海捞针。框架自带的概念很多什么Chain、Retriever、Tool、Memory、AgentExecutor……新手的注意力会被“学框架”带走而不是“理解Agent本质”。其实Agent的最小实现非常朴素无非是“大模型对话接口 工具函数集合 一个循环判断”用原生代码三四百行就能写出来。所以这篇里的示例代码我会用最原始的方式——直接调大模型API自己写循环逻辑。这套逻辑跑通了你再去看框架会发现框架里的每个名词都是你见过的东西。2.3 环境准备你需要装什么假定你用Python 3.10核心依赖其实只有两个openai客户端库不管接哪家模型很多API都兼容这套调用协议一个HTTP请求库比如requests如果你本地还没有Python环境建议用conda或venv先建一个干净的环境。我比较倾向如下配置mkdir agent-demo cd agent-demo python -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate pip install openai requests python-dotenv加一个python-dotenv是为了把API密钥放进.env文件里管理避免把密钥直接写在代码里然后手一抖推到Git仓库那画面太美我不敢看。另外我自己习惯在项目根目录创建一个.envLLM_API_KEY你的密钥 LLM_BASE_URLhttps://你的API服务地址 LLM_MODEL你的模型名不同平台的配置项名略有差异不过思路都是“环境变量里存密钥代码里读配置”。这样不管以后换哪家API代码主体基本不用动。3. 第一款Agent给大模型配上“计算器”现在进入正题。我不会一开始就让你做个全知全能的大Agent而是先做一个极简但能说明问题的Demo一个会调用计算工具的对话机器人。这中间那个核心机制就是前面提到的Function Calling函数调用。理解它等于拿到了Agent世界的入场券。3.1 什么是Function Calling为什么它是关键大模型的知识在训练完成那一刻就冰冻了。你问它“127乘以321等于多少”它可能算个大概但你要让它精确算出结果它大概率会翻车。更别说“今天上海的天气”“我数据库里有多少条记录”这种压根不在它记忆里的信息。Function Calling的破解思路非常朴素让模型在需要外部能力时不是“回答”而是“请求”。它输出一个格式化的指令——比如“我要调用名为calculate的函数参数是{expression: 127*321}”——然后你的代码截获这个请求真正去执行函数把计算结果塞回给模型模型再基于这个结果组织最终回答。这样一来模型不再是孤岛它拥有了“调用工具的四肢”。3.2 定义一个工具从函数到Schema我们需要先定义一个普通Python函数然后写一份描述这个函数的JSON Schema。先看函数本体import math def calculate(expression: str) - str: 安全执行基础的数学运算表达式。 # 仅允许对常见数学表达式求值避免任意代码执行 allowed set(0123456789-*/()., ) for ch in expression: if ch not in allowed: return f表达式中包含非法字符: {ch} try: # 替换math中的函数名如 sin, cos, sqrt safe_expr expression.replace(sin, math.sin).replace(cos, math.cos).replace(sqrt, math.sqrt) result eval(safe_expr, {math: math}, {}) return f计算结果是: {result} except Exception as e: return f计算出错: {e}注意这里我要特别提个醒裸用eval执行用户拼出的表达式是危险的。在实际项目里我一般建议用专门的表达式解析库或者用ast模块做语法树白名单校验。Demo里我也做了字符白名单限制但生产环境请务必换掉这套写法。接着是描述这个函数的Schema这个格式是大模型API约定俗成的标准tools [ { type: function, function: { name: calculate, description: 计算数学表达式的结果支持加减乘除、括号、三角函数等, parameters: { type: object, properties: { expression: { type: string, description: 要计算的数学表达式例如 127*321 } }, required: [expression] } } } ]这份Schema就是“说明书”把它随请求一起发给大模型模型读完就知道原来你能帮我做这个事参数得按这个格式给。3.3 主循环大模型、工具、Agent三方的“击鼓传花”现在写Agent的核心循环。逻辑上分成三步把用户消息 工具定义发给大模型。看模型返回什么——如果返回的是“普通回答”就直接展示给用户如果返回的是“工具调用请求”就执行对应工具把结果再传给模型。重复步骤2直到模型不再请求工具。用代码实现大概是下面这个结构import os from openai import OpenAI client OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL), ) def chat_loop(user_input: str, max_rounds: int 5): messages [ {role: system, content: 你是一个乐于助人的助手。如果需要精确计算务必使用calculate工具。}, {role: user, content: user_input}, ] for _ in range(max_rounds): response client.chat.completions.create( modelos.getenv(LLM_MODEL), messagesmessages, toolstools, ) msg response.choices[0].message # 情况一模型想要调用工具 if msg.tool_calls: messages.append(msg) # 把带工具调用请求的消息放进历史 for tool_call in msg.tool_calls: fn_name tool_call.function.name args eval(tool_call.function.arguments) # 参数是JSON字符串 print(f [Agent] 调用工具 {fn_name} 参数 {args}) if fn_name calculate: result calculate(args[expression]) else: result 未知工具 # 把工具结果追加到历史里 messages.append({ role: tool, tool_call_id: tool_call.id, content: str(result), }) continue # 继续下一轮对话 # 情况二模型给出最终回答 print(f [助手] {msg.content}) return msg.content print( [Agent] 达到最大循环轮数强制结束。) if __name__ __main__: while True: user_input input(你: ) if user_input.lower() in [quit, exit]: break chat_loop(user_input)跑起来你试一下你: 帮我算一下 127乘以321 [Agent] 调用工具 calculate 参数 {expression: 127*321} [助手] 计算结果是: 40767看到那行“[Agent] 调用工具”恭喜你已经亲手完成了从ChatBot到Agent的第一步跨越。此时你手里的东西就是一个标准的L2级别“工具增强ChatBot”。这里有个重要的细节模型每次请求工具工具执行结果必须回到对话历史里而且要有对应关系。tool_call_id就是把“模型请求”和“工具结果”绑在一起的凭证。一旦漏掉这个关联后续模型会“失忆”不知道刚才那个工具结果是给谁的循环就会乱掉。3.4 实操心得为什么工具结果一定要“喂回去”我刚开始写Agent时犯过一个很蠢的错误工具执行完结果我直接拿最终结果去回复用户完全没把中间过程再发给模型。结果模型面对一个莫名其妙的数字根本组织不出像样的回答。后来我理解了大模型不是一个“能接收任意程序调用结果的函数”它是一个“需要完整上下文才能生成合理回复的语言引擎”。你给它看整个推理链条——问题、工具请求、工具结果——它才能在这个链条末端把话说明白。所以在Agent代码里看到“把中间过程拼进messages”这类操作不要嫌麻烦这正是Agent和普通程序最大的区别它需要上下文流式的信息输入而不是一次性给定参数。你后续做更复杂的Agent时会无数次用到这个模式。4. 让Agent拥有“动手能力”一个真实的信息查询Agent计算器Demo太小了很多人会觉得“就这”。别急这一节我们把工具集扩大做一个更像回事的Agent它能根据你的问题决定是查数据库、查天气还是搜索网页。这属于L3任务型Agent入口的雏形。4.1 工具集设计不同需求不同武器假设我们的Agent手头有三个工具查本地用户信息从一份JSON文件里查询用户数据。查当前城市天气模拟调用一个天气API。执行计算沿用上面的计算器。每个工具本质上就是“一个函数 一份Schema”。工具之间互相独立Agent根据用户意图自己决定用哪个。import json # 本地“数据库” USERS_DB { 张三: {city: 北京, vip_level: 黄金会员, last_order: 2025-01-15}, 李四: {city: 上海, vip_level: 白银会员, last_order: 2025-02-01}, } def get_user_info(name: str) - str: 查询用户基本信息返回所在地、会员等级和最近下单时间。 user USERS_DB.get(name) if user is None: return 未找到该用户信息 return json.dumps(user, ensure_asciiFalse) def get_weather(city: str) - str: 查询城市当前的天气情况。 # 真实环境中这里会调用外部天气预报API mockweather { 北京: 晴-4℃~6℃西北风3级, 上海: 阴3℃~10℃东北风2级, 广州: 小雨14℃~20℃东风2级, } return mockweather.get(city, 暂无该城市天气数据)每个函数上方那一行说明不是摆着好看的——大模型的工具调用意图识别很大程度上靠这份描述。描述写得越清楚模型选工具越准。比如get_user_info的描述里一定要有“用户”这个词get_weather的描述里一定要有“城市”和“天气”。4.2 多工具路由模型如何“看菜下碟”现在把工具的Schema列表扩展主循环逻辑基本不变只是工具函数多了路由判断时加个分发def dispatch_tool(name: str, args: dict) - str: if name calculate: return calculate(args[expression]) elif name get_user_info: return get_user_info(args[name]) elif name get_weather: return get_weather(args[city]) return 未知工具Agent的运行逻辑就变成了用户: 我想知道张三在哪个城市顺便看看那边天气怎么样 [Agent] 调用工具 get_user_info 参数 {name: 张三} [Agent] 调用工具 get_weather 参数 {city: 北京} [助手] 张三的用户信息显示他在北京目前北京的天气是晴-4℃~6℃。这个例子看着简单但它揭示了任务型Agent的雏形面对一个复合问题模型自主决定先拿用户信息再拿城市天气然后综合两边结果做回答。中间没有任何人为编排的步骤——模型自己规划了。这就是“智能体”的味道。这里我再补充一个常见误区有人会把“Agent”理解成一定要有很复杂的图结构或状态机。其实在日常交互场景下一个while循环工具分发字典已经能覆盖相当大比例的实用需求。复杂编排是后话先把这条路走通比什么都重要。4.3 揭秘大模型工具调用的实现机制很多新手会好奇大模型到底是怎么知道该调哪个工具的内部原理不复杂可以粗浅理解为三步工具描述随系统Prompt一起进入模型上下文模型“看到”了你给它的几份工具说明书。模型根据用户问题在内部推理出“这个需求需要调用某个工具来获取数据”然后按照预设的JSON Schema格式输出一个结构化请求。你的代码截获这个结构化请求在本地执行工具将结果返回给模型模型再用自然语言组织回复。所以本质上工具调用是模型推理结果的一种特殊表达形式。它不是模型真的“操作”了你的代码而是模型“告诉你的代码该去操作什么”。这也解释了为什么我们经常说Agent的运行依赖“模型质量”——模型如果连该调哪个工具都判断不出来那后续再精巧的编排逻辑也是空中楼阁。5. 进阶核心让Agent学会“反思”与“迭代”能调用工具的Agent已经能做不少事了但还不够“Agent”——因为它的动作完全由用户的一句话触发执行完就结束。真正的Autonomous Agent至少要具备一个能力遇到挫折会自己调整目标没完成就继续想下一步。这一节我们来补齐这块拼图。5.1 ReAct模式把推理过程写进循环ReAct这个名字看起来很高级实际拆开就是 Reasoning Acting推理行动。它的核心操作是在每一轮循环里先让模型输出“我现在的想法Thought”再让它输出“我要做的动作Action/动作参数Action Input”然后观察结果Observation想下一步。反映在代码上和之前的工具调用循环高度相似——区别在于我们要主动引导模型先把思路说出来。具体做法是给系统提示词加一句约束请逐步思考并执行任务。每当你需要调用工具请先简短解释为什么调用然后调用工具。这样对话历史里就保留了一条“想法链”。模型看到之前的想法链之后会顺着逻辑继续推导而不是每次都从零开始。完整例子让Agent写一段数据报告帮用户整理用户表里有几个人是黄金会员。执行过程中模型大概会这样走[Thought] 用户想统计黄金会员人数。我需要先获取全部用户信息然后筛选出黄金会员。 [Action] 调用工具 get_user_info参数 name张三 [Observation] {city:北京,vip_level:黄金会员,...} [Thought] 张三确实是黄金会员继续查下一个用户。 [Action] 调用工具 get_user_info参数 name李四 [Observation] {city:上海,vip_level:白银会员,...} [Thought] 李四不是黄金会员。现在我已经检查了两位用户统计结果1人是黄金会员。 [Answer] 用户表中黄金会员共1人是张三。这已经不是一个“有问必答”的机器人了而是一个“带着目标自己走完流程”的小助理。这就是从ChatBot到Autonomous Agent的质变点之一。5.2 进阶加入“尝试-纠正”机制光会一步步走还不够真正的Agent还得会“走错了退回去换个方向”。业界常用的一种策略是设置最大尝试轮数限制循环内每轮检查“模型是否产生了工具调用”如果没有工具调用且没有给出最终回答就强制插入一条提醒消息例如“你还没完成任务请继续使用工具获取足够信息”。还有一种常见的自我纠错思路向模型中追加一个新的工具比如finish_reason让模型在认为目标已完成时主动调用它而不是懒洋洋地直接输出结论。这样你就能够显式地区分“Agent干完了活”和“Agent中途卡壳了”。def finish(conclusion: str) - str: 任务结束时调用请传入对用户最终问题的总结。 return f任务已完成结论{conclusion}看到没有连“结束”这件事都要用工具来完成。这就是Agent和普通程序很不一样的地方Agent的终止条件不是代码里的某个状态而是模型在上下文流转中做出的“元决策”。你通过“是否调用了finish工具”这个信号就能判断任务走到了哪一步方便做日志记录、计费和流程控制。5.3 实操心得反复调不到工具怎么办如果你跑上面的例子发现模型老是直接输出结论而不是调用工具通常有四个排查方向系统提示词写得不够强制。试一下把它改硬“你无法直接访问外部数据源所有查询必须通过工具完成不调用工具就得不到正确结果。”工具描述里缺少“什么时候用我”的说明。在description里把触发场景写细比如“当用户询问用户信息时必须调用此工具”。模型本身工具调用能力偏弱。市面上各家的函数调用水平差异不小遇到那种千呼万唤就是不调的果断换个模型试试。上下文里历史消息太乱模型被前几轮的无效信息带偏了。可以考虑清理一下历史只保留最近的几轮关键对话。我个人经验中第二点和第四点最容易被忽略表面上看是模型“不配合”实际是你在提示词工程上欠了债。6. 再进一步给Agent装上“记忆”之后才能真正“自主”到这里你的Agent已经能感知、决策、行动了但从L3迈向L4还差一个关键能力——记忆。没有记忆的Agent就是金鱼聊完就忘更别提完成那种需要跨多轮、跨会话的复杂任务。6.1 短期记忆与长期记忆怎么理解短期记忆就是当前对话上下文。模型每次调用你塞进messages里的内容就是它的“工作记忆”。这部分容量受模型上下文窗口限制长了会爆。长期记忆则需要你在外部存储。比如用户的关键信息、业务数据、历史偏好存进数据库或向量库会话开始时通过检索塞回上下文。这就是RAG检索增强生成和Agent记忆管理经常交叉的原因。实际做Agent应用时我见过一个非常实用的“记忆三层架构”层级存储位置保存内容策略短期记忆对话上下文本任务内的中间步骤、历史问答保留最近N轮超出则摘要压缩中期记忆会话级存储用户偏好、任务状态会话结束后持久化长期记忆业务数据库/向量库用户画像、历史事实按需检索注入新手入门先用最简单的“在会话里拼历史消息”实现短期记忆再考虑把总结写进文件或数据库做长期记忆。6.2 做一个会“记住偏好”的Agent来看一个连贯的实操例子。我们给Agent增加“记住用户偏好”的能力PREFERENCE_FILE preferences.json def save_preference(key: str, value: str) - str: 保存用户的个人信息或偏好设置。 prefs {} if os.path.exists(PREFERENCE_FILE): with open(PREFERENCE_FILE, r, encodingutf-8) as f: prefs json.load(f) prefs[key] value with open(PREFERENCE_FILE, w, encodingutf-8) as f: json.dump(prefs, f, ensure_asciiFalse, indent2) return f已保存偏好: {key}{value} def get_preference(key: str) - str: 读取用户保存的偏好信息。 if os.path.exists(PREFERENCE_FILE): with open(PREFERENCE_FILE, r, encodingutf-8) as f: prefs json.load(f) return prefs.get(key, 未找到偏好设置) return 未找到偏好设置当用户说“以后都称呼我王工”Agent就能调用save_preference把“称呼王工”存到文件里。下一次会话开始时我们把偏好文件里的内容塞进系统提示词def load_preferences_as_prompt(): if os.path.exists(PREFERENCE_FILE): with open(PREFERENCE_FILE, r, encodingutf-8) as f: prefs json.load(f) return 用户偏好记录如下 json.dumps(prefs, ensure_asciiFalse) return 暂无用户偏好记录就这么一个简单的“偏好文件读写”模式已经能支撑相当多的个性化Agent场景了记住用户的书写风格、记住用户常用的查询对象、记住用户上次的决策习惯。6.3 记忆不是存了就完事上下文窗口管理不知道你有没有触碰到“上下文爆了”的体验——任务跑着跑着模型突然开始答非所问。大多数情况就是历史消息太长了生成的结果被淹没在旧信息里。这个问题我能给的经验是别一口气全塞用摘要替换法。当messages加起来超过一定token预算就把前面的对话交给模型概括成一段摘要保留摘要 最近几轮完整消息一起作为新上下文继续跑。这里有个小技巧每轮的摘要里务必保留“已经完成的目标”“已获取的关键信息”“遗留下来的待办”这样后面模型才知道自己走到哪了。我自己写过一个粗版实现先数token按字符数估算超过3000字符就触发摘要把旧对话交给一个“压缩函数”用一行Prompt让它输出要点。这个方法很糙但对绝大多数日常场景够用。7. 迈向Autonomous Agent从“一步一步走”到“自己拆解目标”记忆和反思加进来之后Agent终于距离“Autonomous”又近了一步。那什么是真正的自主Agent呢最明显的一个特征拿到一个模糊的大目标自己把它拆成若干个清晰的小任务再逐一执行。7.1 用一个“调研报告Agent”讲透自主规划设想用户说帮我调研一下市面上主流大模型Agent开发框架的现状写一份500字摘要。如果只有工具调用能力Agent会直接卡住——因为它不知道“调研”的具体步骤是什么。但一个Autonomous Agent会这样思考先判断需要的信息种类框架名称、各自特点、GitHub Star数量、适用场景。拆解子任务搜索结果获取、逐个框架信息整理、汇总对比、生成摘要。按顺序执行每个子任务在中间步骤中记录观察结果。子任务全部完成后统一组织为最终报告。在代码层面做这件事需要一个“任务清单”结构让模型先生成一个JSON数组包含子任务和每个子任务的描述然后主循环依次执行。当然更精致的做法是用子Agent去分别执行各子任务但这对新手来说还为时过早——先把“清单顺序执行”跑通你已经走在正确的路上了。7.2 再进一步让多个Agent协作当你完成了一个单Agent自主执行全部任务的能力后自然就会遇到性能与准确性问题一个Agent又要规划、又要执行、又要反思容易累死还容易被单个失败的步骤拖垮。这时就可以考虑引入“多Agent协作”架构规划Agent负责拆解任务执行Agent负责干活审计Agent负责检查和纠正。三者相互配合每个Agent只负责自己最擅长的部分。当然多智能体最大的代价是成本成倍增加——token消耗、上下文管理复杂度、故障排查难度都会显著上升新手在第一阶段我认为不必急于做多智能体架构先把单Agent练扎实。7.3 Autonomous Agent的安全边界最后我必须认真提醒你自主性越强安全约束越重要。一个L4的Agent如果被恶意Prompt利用可能调用对外接口执行危险操作。所以实际开发中请务必做好这几道安全线工具权限最小化比如让Agent能查数据库但只授权只读账号。关键操作人工审批删除数据、发送消息、转账等动作必须设计审批确认流程。设置执行上限最大循环轮数、最大token消耗、最大API调用次数。输出审计对Agent的所有工具调用日志做审计追踪。Prompt注入防护对外部输入一律做脱敏和隔离防止诱导模型执行“隐藏指令”。这不是套话是我实际见过踩坑后的肺腑之言。网络上出现过好多次Agent被诱导读取用户私密文件、越权操作的事件。自主性是双刃剑能力越大责任边界越要画清楚。8. 常见问题与排查技巧实录文章最后一部分我把这些年给团队和读者做Agent开发交流时大家最常踩的坑整理成一个速查表。按这个表排查能省掉很多试错时间。问题现象可能原因解决思路模型从不调用工具工具描述不清晰 / 系统提示词不够强制把描述写得更具体提示词里明确“必须通过工具获取数据”工具调用了但结果没生效没把tool结果拼回messages / tool_call_id不对检查循环里是否正确追加tool role消息Agent进入死循环工具结果与预期不符 / 没有设置max_rounds设置轮数上限增加自省机制检查工具是否返回了误导信息上下文太长模型答非所问历史消息无限堆积引入摘要机制压缩旧会话工具参数格式报错模型生成的JSON参数不符合预期用json.loads时包一层try/except给模型在提示词中提供参数示例模型被外部输入误导缺少Prompt注入防护对外部内容隔离、脱敏关键操作增加人工审批这里挑两个高发问题展开说一下。第一个是死循环。新手跑Agent时最常见一个现象模型不停调用工具但每次的结果都没有让任务状态前进反而原地打转。比如查询工具一直查不到目标结果模型就一直重试同一个工具。解决办法首先是设置轮数和时间上限其次我习惯在系统提示词里加一句“如果同一工具重复调用超过两次仍无结果请用finish工具结束并如实说明现状”。把“止损”能力交给模型基本能杜绝那种无意义空转。第二个是工具参数格式不服。有些模型在输出工具参数时会把value写成字符串而不是数组、把布尔值写反等等。我处理的方式是在Schema的description里给出一个完整的参数示例比如“参数name的类型是string例如‘张三’”。这种小细节对提高参数生成准确率有奇效。再分享一个我每次都会跟人提的“规则”任何生产级Agent工具调用日志一定要完整保留。哪一步调了哪个工具、参数是什么、结果是什么全部落到日志里。否则出了问题你根本无从定位。这句话我复制粘贴给过很多人也算一个血泪教训。最后关于学习路径我再给一条实在的建议先手写一两百行原生的Agent循环跑通之后再去看那些框架的文档。框架帮你省掉的是工程化复杂度而不是帮你理解Agent原理。你自己写过一个循环之后框架里那些抽象名词——Tool、AgentExecutor、Memory——在你眼里立刻就有了具体形象。我最早从ChatBot开始接到第一个Agent需求时也是一脸懵结果认认真真从“给模型配一个计算器”这一步开始练起而后把工具扩展到数据库、搜索、发送消息一步步走到了能自主完成完整业务链路的多步Agent。回头看真正卡人的不是模型智商而是你能不能把那个“感知—决策—行动—观察”的循环在心里扎稳。那棵根扎下去了树上长什么枝叶只是时间问题。如果你按这篇的顺序把示例代码都跑过一遍现在手里应该已经有了一个“能调工具、能记偏好、能做简单任务拆解”的Agent雏形。后面再往上走无论是加RAG、接工作流、上多智能体协作都是在这个骨架上添砖加瓦。祝所有从ChatBot起步的同学都能稳稳走到自己心中的那个Autonomous Agent。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询