1. 先说清楚Agent到底是什么
做开发这些年,你会发现一个特别有意思的现象:三年前大家见面聊的是“你的系统用了什么框架”,两年前聊的是“你的模型推理速度多少”,现在见面聊的基本都是“你的Agent能干活了没”。
大模型Agent开发,说白了就是让大模型不再停留在“你问我答”的聊天阶段,而是变成一个能自己拆任务、调工具、跑流程、交付结果的数字员工。我见过不少朋友第一次接触这个概念时,以为Agent就是写个prompt套壳,实测下来发现完全不是这么回事。一个合格的Agent背后至少牵扯到模型选择、工具注册、任务编排、上下文管理、结果校验这几个环节,任何一个环节掉链子,整个流程就卡住。
这篇文章适合谁看?如果你已经用过ChatGPT或国内的大模型API,会写Python基础语法,但对“Agent怎么架构”“工具调用怎么实现”“多步任务怎么拆解”还没什么概念——那这篇文章就是给你准备的。我会用自己踩过的坑和跑通的代码,把整个链路掰开揉碎讲一遍。不夸张地说,跟着走一遍,你就能搭出第一个真正能干活的Agent,而不是一个只会背prompt的玩具。
2. 设计思路:Agent的本质是把“思考”和“行动”连起来
2.1 为什么单单靠Prompt不够用
很多人以为Agent就是把Prompt写长一点、写详细一点,模型就能自动完成任务。早期我也这么干过,结果发现模型答得挺好,但它不干活。
举个例子,你让大模型“帮我把这个文件夹里的图片都压缩一下”,如果只是Prompt对话,模型会给你输出一段Python代码,然后告诉你“你把这个代码跑一下就行”。看起来没问题,但这不是Agent,这是只会动嘴的方案顾问。真正的Agent需要自己去遍历文件夹、调用压缩工具、检查输出结果、失败自动重试——这些动作必须通过代码来执行,Prompt只是大脑,手脚得另外接上。
所以Agent开发的核心思路就一句话:把大模型当作“指挥官”,给它配备一堆“工具”,再把“指挥官”的决策循环跑起来。这个循环通常是:观察任务 -> 思考拆解 -> 调用工具 -> 观察结果 -> 继续决策,直到任务完成或达到终止条件。
2.2 工具调用到底是怎么回事
工具调用的机制值得多说两句。你要让模型调用工具,不是把函数文档一股脑塞给模型就行。大模型的API里有一个专门的机制,叫“函数描述”(Function Calling)或“工具定义”(Tools Definition),你需要把每个工具的名字、参数、用途、返回格式,用结构化的JSON描述出来,随消息一起发给模型。
模型收到这些描述后,在回答时不会直接说“我去调用工具了”,而是返回一个结构化的指令,比如“我想调用search_web这个工具,参数是keyword: 北京天气”。你的代码收到这个指令后,去真正执行搜索,再把搜索结果作为一条消息返回给模型。模型看到结果后,继续思考下一步。
这个“模型决策 -> 代码执行 -> 结果回传”的循环,就是Agent区别于普通对话的核心机制。一开始你可能觉得绕,习惯了之后你会发现这个设计特别优雅——模型的思考和你的代码各管一摊,模型负责判断,代码负责干活。
2.3 框架选型:从零手写还是用现成框架
关于框架,我的建议是先别急着上LangChain这种重框架,先用原生方式手写一个最小可用的Agent,把调用循环吃透了再说。因为框架虽然省事,但把太多细节藏了起来,一旦出现问题,光排查框架的封装逻辑就能折腾你一整天。
等你搞明白了底层原理,再用LangChain、Dify、Coze这类框架或平台提效,就是锦上添花的事。我自己就是先手写了个两百多行的Agent跑通全流程,后来切到LangChain时,看它的文档跟看老朋友似的,一点不费劲。你如果一上来就用框架,很容易陷入“会用但不懂”的尴尬境地。后面遇到复杂需求需要定制改造时,你会发现自己完全没有头绪。
3. 实操准备:环境、API选型与模型选择
3.1 开发环境搭建
开发Agent不需要太复杂的环境,一个Python版本管理器、一个虚拟环境、一个API密钥就够了。我目前用的配置供你参考:
- Python 3.10+,太老的版本有些新库装不上
- 使用 venv 创建独立虚拟环境,避免依赖冲突
- 在根目录建
.env文件存放API密钥,绝不硬编码在代码里 - 开发调试阶段使用
requests库直接调HTTP接口,暂时不需要引入SDK
这里有一条实操心得很重要:不要把API密钥提交到Git仓库。我见过不少同事把密钥写在代码里直接push上去,结果被爬虫扫到,一夜之间被刷了几百块费用。最稳妥的做法是.env文件加入.gitignore,加载环境变量用python-dotenv这个库,非常方便。
3.2 模型怎么选:大小结合才是正经路数
大模型选型这块,新手最容易犯的病是“只用最强的模型”。GPT-4级别的Token价格摆在那,你让Agent做一次网页搜索加分析,一个任务来回十几轮调用,成本嗖嗖往上蹿。我的建议是大小模型搭配使用:
- 规划、决策、复杂推理阶段,用强模型(比如GPT-4级别或Claude系列的中高端版本),因为这一步错了后面全错,值得花高价
- 提取、总结、格式化输出这类机械性环节,用小模型或低成本模型完全够用,速度快、价格只有大模型的十分之一甚至更低
模型选择的另一个关键指标是“上下文长度”。上下文长,能喂进去的历史消息就多,Agent翻车率会明显降低。目前主流模型已经支持几十万Token级别的上下文,但Token越长、每次请求的延迟和价格就越高,建议你把系统提示词压到500Token以内,日常工作消息控制在2000Token左右就足够了。
3.3 API网关:别把鸡蛋放在一个篮子里
做Agent开发一段时间后你就会发现,任何单一模型的API都可能出现限流、故障、响应变慢的情况。我的建议是搭一个轻量级的API网关,把不同厂商的接口统一封装,可以随时切换,避免被单一供应商绑死。
特别是国内环境,不同厂商的模型各有所长,有的在中文理解上更强,有的在代码生成上更胜一筹。我用Python写了个简单的封装层,核心逻辑是给每个模型接口配置一个统一的数据格式,再接一个路由函数,专门用来做模型切换和异常回退。实测下来,一套接口适配了全系模型,再也不用针对每个厂商单独写一套代码。
4. 手写一个最小可用Agent:完整跑通全流程
4.1 最基础的消息循环
我们直接上手写代码。第一步是让模型具备基本的对话能力,构建一个“说话——听话——回话”的循环。
import os from dotenv import load_dotenv import requests load_dotenv() API_KEY = os.getenv("API_KEY") API_URL = os.getenv("API_URL") # 比如 OpenAI / 国内大厂的兼容接口地址 def call_model(messages, tools=None): payload = { "model": "gpt-4o-mini", "messages": messages, "tools": tools, "tool_choice": "auto", } resp = requests.post(API_URL, headers={"Authorization": f"Bearer {API_KEY}"}, json=payload) resp.raise_for_status() return resp.json()["choices"][0]["message"] def run_agent(user_input, max_iterations=10): messages = [{"role": "system", "content": "你是一个可调用工具的智能助理。"}] messages.append({"role": "user", "content": user_input}) for _ in range(max_iterations): assistant_msg = call_model(messages) messages.append(assistant_msg) # 如果没有工具调用请求,说明任务完成,直接返回 if not assistant_msg.get("tool_calls"): return assistant_msg["content"] return "超出最大迭代次数,任务未完成。" if __name__ == "__main__": result = run_agent("你好,介绍一下你自己") print(result)这段代码虽然简单,但已经具备了Agent最核心的循环骨架。注意迭代次数的限制很关键,这是用来防止Agent陷入死循环的安全阀。我曾经没设这个上限,结果有一次模型反复调用同一个工具,连续跑了二十多轮,不仅慢,还烧了不少Token。从那次之后,我所有的Agent工程都会强制加上迭代上限。
4.2 把工具接进来:让Agent真正开始干活
光有对话能力远远不够。我们给Agent接入一个计算工具,让它能做数学运算。
def calculate(expression): """安全计算器:只处理数字和四则运算,防止代码注入""" allowed_chars = set("0123456789+-*/(). ") if any(c not in allowed_chars for c in expression): return "错误:表达式包含非法字符" return str(eval(expression)) TOOLS = [ { "type": "function", "function": { "name": "calculate", "description": "计算四则运算表达式的结果,只支持+ - * / 和括号", "parameters": { "type": "object", "properties": { "expression": {"type": "string", "description": "要计算的数学表达式"} }, "required": ["expression"] } } } ]有了工具定义之后,在run_agent函数里把tools=TOOLS传进去,然后需要处理模型返回的tool_calls字段。
def execute_tool_call(tool_call): if tool_call["function"]["name"] == "calculate": args = json.loads(tool_call["function"]["arguments"]) return calculate(args["expression"]) return "未知工具" def run_agent_with_tools(user_input): messages = [{"role": "system", "content": "你是一个可调用工具的计算助理。"}] messages.append({"role": "user", "content": user_input}) for _ in range(10): assistant_msg = call_model(messages, tools=TOOLS) messages.append(assistant_msg) if not assistant_msg.get("tool_calls"): return assistant_msg["content"] for tool_call in assistant_msg["tool_calls"]: result = execute_tool_call(tool_call) messages.append({ "role": "tool", "tool_call_id": tool_call["id"], "content": result }) if __name__ == "__main__": result = run_agent_with_tools("帮我计算 (123 + 456) * 78 的结果") print(result)这一步非常关键,你把工具结果用role: "tool"回传给模型,模型才能“看到”工具执行的结果,并基于结果进行下一步决策。这个来回如果格式不对,模型会直接报错,所以常见错误里我会详细讲怎么排查。
4.3 工具箱扩展:AI能力百宝箱思路
当你把计算器接好之后,后续要扩展其他工具,思路是完全一样的。接下来是我在项目里用到的高频工具,供你参考:
- 网络搜索工具:调用搜索API,让Agent能查实时资讯和网页内容
- 网页抓取工具:输入URL,返回网页正文文本,方便Agent做内容分析
- 数据库查询工具:让Agent能查自己的数据表,做数据分析
- 文件读写工具:实现文件的操作能力,方便输出报告或读取本地配置
- 图片生成工具:接入绘图API,让Agent具备多模态能力
- 定时提醒工具:让Agent跟日历和消息推送联动起来
每加一个工具,只需要写一个普通Python函数,再加一段JSON描述,然后写一个分支让模型调过来就完事了。所以Agent的开发工作量,真正核心不是代码量,而是“你想让Agent具备哪些能力”的需求设计。
4.4 让Agent能“规划”:拆解复杂任务必须走的一步
再往上走一步,是给Agent加上任务规划能力。所谓规划,本质是把复杂任务拆解为多个子步骤,然后按顺序执行。实现思路有几种,有的是用提示词要求模型“先列计划再执行”,有的是用ReAct框架,让模型交替进行“推理”和“行动”。
我推荐一个轻量级的方案:先做“规划器”,再做“执行器”。两个角色共用同一个模型,但消息上下文各不相同。
PLANNER_SYSTEM = "你是一个任务规划器,请把用户的任务拆解成最多5个具体步骤,每个步骤一句话描述,用编号列表输出。" EXECUTOR_SYSTEM = "你是一个任务执行器,你只能执行当前这一步,执行完成后如实汇报结果。"这种拆法,就是经典的“规划器——执行器”架构(Planner-Executor)。好处是任务拆解和执行互不干扰,规划做得不好时也不用把执行上下文全部推倒重来。更复杂的任务还可以引入“反思”模块,让模型在执行完一轮之后,回看一下前面的步骤有没有问题,再决定是继续还是调整方案。这就是OpenAI在相关技术报告里展示过的类似设计思路,许多企业级Agent已经把这类机制发展得挺成熟了。
5. 开发过程常见的坑与经验排查
5.1 工具描述写得太含糊导致调度失误
这一个大坑相信每个做过Agent的人都会踩到。模型面对多个工具时,如果工具描述写得不清楚,它根本不知道该选哪个。比如你写了“search”工具,描述是“搜索一下”,模型可能不知道它是搜网页还是搜数据库,调度就乱了。
后来我的做法是,每个工具的描述必须包含以下三块信息:
- 这个工具“做什么”,说得越具体越好
- 什么场景下“应该用”或“不应该用”
- 关键参数的含义和限制
举个直观对比:
- 差的描述:
获取天气信息 - 好的描述:
获取指定城市当前和未来的天气信息,适用于用户询问天气、出行建议、活动安排等场景。如果不确定城市名,先向用户确认。城市参数使用中文全称。
同样的工具函数,描述写清楚了,模型的准确率能提升很大一截。这成本很低,但效果是立竿见影的。
5.2 上下文越聊越长:管理策略从清理开始
Agent每走一步,多轮对话的上下文就会越来越长。消息太多之后,Token成本上升,模型响应变慢,还会导致模型被一些无关历史干扰,出现“幻觉”式的错误决策。
我常用的策略有几种:
- 只保留最近N轮对话的工作记忆区存储,更早的历史做摘要
- 对于工具执行结果,只保留结论和重要数据,不保留完整原始返回
- 对系统提示词,每隔一段时间就重新发送关键的指令,避免模型在长对话中“遗忘”系统设定
这就像你平时整理工作台,桌子堆满了就难找东西,但你不能把文件全扔了,只能把不常用的归档、常用的放桌面。Agent的上下文管理,逻辑完全一样。
5.3 Token消耗过高的问题排查与优化
Token烧钱的问题其实不太难解决,关键是找出钱都花在哪了。每次调用如果传入了完整的工具定义,这些描述本身就要消耗Token。你定义了几十个工具,每次请求都带上,消耗是很大的。
我的优化方案是“分组动态加载”,把工具按功能分成几组,根据用户的请求让模型先判断走哪个场景,再只加载对应组里的工具。做法是先用轻量级的收分类接口识别用户意图,经过这样一次预筛,再根据意图拼接对应的工具子集传给模型。
这种方式在做了工具数量大于10个的场景后,Token消耗能明显降下来,响应速度也快了不少。如果你手上的Agent特别重,这个思路可以优先考虑。
5.4 排查问题:从Log驱动到流程追踪
Agent开发最难的环节是问题排查。因为Agent的每一步决策、工具调用、反馈回传都是动态的,中间任何一环出错,结果是多样的。有几次模型没按预期行动,我盯着终端看了半天也看不出毛病。
后来我做了个决定,给Agent开发加上完整日志记录功能,每轮消息、工具调用参数、返回结果、Token消耗全部落盘。这样做的好处是,Agent出了问题之后,回看日志基本上能秒定位。日志记录看起来不复杂,但它是Agent开发里的隐形基础设施,强烈建议从第一天就做起来。
我记得有个同事跑Agent任务时遇到连续失败的诡异情况,排查了整整一天没头绪。后来看了日志,发现是在某次工具调用返回时多了一个空字符串,导致模型在后续步骤里把空结果当成有效数据,一路推理到错误方向去了。这就是日志的价值——它不直接告诉你答案,但能把你的排查范围缩到很小。
为了让日志更有用,我一般还会在每条工具信息里加一个调用耗时,方便判断瓶颈到底在模型侧还是在API请求侧。
6. 进阶方向:从单Agent到多Agent与安全思考
6.1 多Agent架构是怎么一回事
单Agent能解决很多问题,但遇到复杂业务场景时,把多个Agent组合在一起会更灵活。我的经验是用“主控Agent + 若干专业Agent”的分工模式,主控Agent只负责理解用户意图,拆解任务,然后分发给背后的专业Agent去执行。
比如说一个企业知识库客服系统,可以拆成:
- 意图识别Agent:快速判断用户问的是技术问题、售后问题还是售前咨询
- 技术答疑Agent:对接产品文档,回答远程配置、系统报错等具体问题
- 订单处理Agent:查订单状态、处理退款、对接售后流程
- 情绪安抚Agent:升级突发事件,用共情的话术稳住客户,并及时转人工处理
不同Agent之间通过消息队列或共享状态通信。消息传递的协议设计如果做得好,整个系统会特别稳。多Agent之间有时也会“吵架”——两个Agent的意见不一致,这时候就需要一个仲裁机制,或者干脆让主控Agent重新判断。
6.2 Agent安全怎么考虑
Agent安全是最近行业里讨论非常多的话题。Agent拥有了工具调用能力之后,权限边界如果控制不好,风险比普通对话应用大得多。核心坏例子就是Prompt注入攻击,外来的恶意内容伪装成了系统指令,诱导Agent去执行高危操作,比如发邮件、转账、删除数据。
我在自己的项目里养成了一个习惯:重要操作一律走“二次确认”机制。Agent要执行高危动作时,先停下来向用户确认,用户点头了才继续。除此之外,敏感操作的执行权限要与模型决策权限分离——Agent能调用的API密钥,必须是最小权限的那一个。不能让一个客服Agent拿着服务平台的全部API权限。这些安全基操,是保证Agent能真正投入生产环境的前提。
6.3 我的实操体会与选择思路
如果让我说一条最想给新手分享的心得,那就是:先定义清楚“边界”,再动手写Agent。有很多人上来就堆功能、堆框架、堆模型,结果做出来的东西在外人眼里很高级,实际大家都看到了——工作不稳定、结果不可控、上线之后根本不敢让用户随便用。
Agent开发最本质的思维方式,就是“把大模型放对位置”。大模型是发动机,不是整车。你要给它配好方向盘、刹车、仪表盘,它才能安全地跑起来。想清楚这一点之后,你跟大模型配合的每一次决策,都会变成尽可能清晰、可控、可追溯的执行链路。
有几次我凌晨还在改代码,就是因为模型在某个边界条件下做了我没预料到的操作。后来我把所有“兜底逻辑”前置,把能设上限的地方全部设了上限,把能加确认的操作全部加确认,系统稳定性肉眼可见地提升了。做Agent开发,慢慢你会发现最有价值的代码都是那些不起眼的防御代码和不显眼的日志代码。
这条路越往深走越有意思,多模态、多Agent协作、长期记忆、持续学习,每一个方向都值得慢慢折腾。工具不停在变,但核心的架构思想和工程习惯,会比任何单个工具都保值。