1. 项目概述:先想清楚“智能体”和“聊天机器人”的分界线
AI智能体的开发流程,是我被问得最多的问题。很多人以为接个大模型API,写几段提示词,就能得到一个自动干活的数字员工。但真正做过项目就会明白,AI智能体的开发流程是一条从需求定义、架构选型、工具封装到效果调试的完整链条,任何一段缺位,交付物大概率只是个“会聊天的机器人”,而不是“能办成事的智能体”。
聊天机器人回答你,智能体替你做事。这是我这几年做项目下来最深的体会。智能体不仅要理解你的意图,还要把意图拆成可执行的动作,主动调用外部工具读取数据、操作业务系统,并且在行动过程中根据反馈不断调整自己,直到把任务完成。所以它本质上是一个从“被动问答”到“主动执行”的系统升级,而不是简单的接口对接。
这篇内容适合两类人看。一类是负责交付一个AI项目的工程师或产品经理,想搞清楚到底怎么把智能体落到业务里;另一类是自己公司已经做了类似ChatBot的对话系统,但发现回答漂亮不等于执行到位,想向智能体方向升级的团队。我会把整个开发流程拆开讲,从需求梳理到技术选型,再到核心循环实现和踩坑记录,偏向实操,不扯太多理论。
我想先给一个贯穿全文的框架:一个合格的智能体等于大模型推理内核,加上任务拆解机制,加上外部工具调用能力,加上记忆系统,再加上反馈闭环。后面所有章节,本质都是围绕这个框架展开的。
1.1 智能体和大模型应用到底差在哪
很多团队一开始就会纠结:大模型应用和智能体,听起来差不多,边界到底在哪?我们常见的智能客服,也是把问题发给模型,模型直接输出答案。如果只是这么一层调用关系,无论提示词写多长,都还停留在问答层面。而真正让系统从“问答”升级为“智能体”的,是它在输出内容之前多了一道“行动计划”的环节。
我举个特别常见的例子。用户说:“帮我查一下最近三天的会议安排,再列一份参会准备清单。”普通大模型应用的做法是:模型根据训练记忆或者上下文,凭空生成一份看起来合理的清单,其中很可能混着一两个根本不存在的会议。智能体的做法则完全不同:它先判断自己需要“查询日程”这个能力,于是触发对应的工具函数,从日历系统里拿到真实会议数据,再基于这些真实数据做汇总和格式整理,最后才生成回答。前者是在“想”,后者是在“做”,差别非常大。
就是这一步之差,决定了系统的可用性。没有工具调用能力的模型,面对需要事实、需要操作、需要实时数据的任务,一定会产生幻觉。有了工具调用和结果回填,模型输出的可靠性才会发生质变。所以在规划AI智能体开发流程的时候,第一步就要明确方向:你要做的到底是一个会思考的“脑”,还是一个能动手的“手”。这两者的架构思路完全不同,成本和周期也完全不同。
1.2 需求边界直接决定复杂度
第二个容易犯的错,是需求定义得太宽。我见过不少团队,立项文档里写着“智能体要能处理所有业务咨询”,结果做到一半就崩溃了,因为意图识别和分支逻辑乱成一锅粥。智能体的复杂度跟任务边界高度相关,边界越宽,模型出错的空间越大,排查成本也成倍上升。
我在实际操作中,习惯把需求分成三个层级。第一层是纯问答,不需要查询任何外部系统,比如解释产品概念、回复常见政策问题,这一层用提示词工程就能解决,根本不值得动用智能体。第二层是需要调用一个明确工具才能完成的任务,比如查天气、查日程、算指标,这是智能体的主战场,我个人非常推荐作为第一个落地场景。第三层是多工具协同、按条件动态决策的复杂任务,比如“帮我订机票、订酒店、顺便生成一份行程单”,价值最高,但技术复杂度和失败风险也最高,我建议放到项目二期再上。
| 任务层级 | 典型场景 | 涉及能力 | 技术复杂度 | 建议优先级 |
|---|---|---|---|---|
| 单轮问答 | 解释概念、政策问答 | 提示词工程、知识检索 | 低 | 基础能力 |
| 单工具任务 | 查日程、查天气、查账单 | Function Calling、工具封装 | 中 | 优先落地 |
| 多工具协同 | 订酒店+订机票+生成行程 | 任务编排、动态规划、记忆管理 | 高 | 二期再上 |
提示:新团队做AI智能体,我强烈建议从“单工具任务”起步。它最能体现智能体相对普通问答系统的差异化价值,同时验证链条短,从模型发起调用到工具返回结果再到生成最终内容,完整链路很快就能跑通,团队信心也会建立起来。
2. 技术选型与架构设计:先搭骨架,再填血肉
2.1 模型选型:能力、延迟和成本的三方博弈
模型是整个智能体的内核,它的上限基本决定了智能体的上限。但我不建议上来就追最强、最大的模型,因为智能体场景不是单次问答,而是一连串调用。每次模型思考要不要调用工具、调用哪个工具、参数怎么填,都需要消耗token和时间。一个需要三次工具调用的任务,实际产生的请求轮数可能是六到八轮,总延迟和成本都会成倍放大。
所以在选型时,我重点看三个指标:工具调用成功率、上下文长度、端到端延迟。工具调用成功率是最关键的,模型需要精准输出结构化的工具参数,这部分能力和模型代际强相关。闭源大模型通常在函数调用上有更稳定的表现,因为它们经过专门的指令微调;开源模型如果选型不当,经常出现参数漏填、格式乱套的情况,需要额外加一层解析容错。上下文长度决定智能体能承载多长的过程信息,工具往返的记录都要留在上下文里。
| 选型维度 | 闭源API大模型 | 开源模型本地部署 |
|---|---|---|
| 工具调用稳定性 | 通常更好 | 依赖具体模型和微调水平 |
| 单次调用成本 | 按token计费 | 主要是硬件和电费 |
| 数据隔离 | 数据需要出内网 | 数据可以不出内网 |
| 部署和维护成本 | 基本为零 | 需要团队具备运维能力 |
| 适合场景 | 快速验证、业务早期 | 数据敏感、长线部署 |
我初期比较建议先用闭源API把整个流程跑通,确认智能体的业务价值之后,再评估是否要切换到私有化部署。很多团队一上来就买显卡、搞本地模型,结果效果不稳定,花了两倍时间才追平。开源模型当然可行,但适合对成本和数据隔离有强约束的场景,不适合验证阶段。
2.2 智能体的五大核心组件
一个典型的单智能体架构,我会拆成五个部分。意图理解模块负责判断用户这句话要不要调用工具,以及调用哪个工具;任务规划模块负责把目标拆解成有序步骤;工具调用层负责执行真实操作;记忆系统负责保存过程中的临时信息和跨会话的长期信息;生成与反馈模块则负责消化工具返回的结果,生成面向用户的最终回答。
这些组件之间的协作关系,可以理解成一条流水线。用户输入先进意图理解;判断出需要操作后进入任务规划;规划结果落到工具调用层执行;执行结果回传到上下文,模型根据结果决定继续下一步还是收尾;整个过程被记忆系统持续记录。需要注意的是,这五个模块不一定要独立成五个服务,初期完全可以都在一个进程里实现,但接口要做清晰,尤其是工具层和记忆层,要为后续扩展留空间。
还有一个容易忽略的设计原则:工具的接口要和模型解耦。比如查询日程,业务系统里可能叫“getCalendarEventById”,但暴露给模型的名字最好叫“query_user_schedule”,参数也必须是语义化的字段,而不是一堆内部编码。模型理解的是自然语言化的接口,业务层再去做映射转换。这样即使底层系统更换,模型侧的工具描述也不需要大规模改动。
2.3 自己写循环,还是用现成框架
这是团队里经常吵起来的话题。我的态度很明确:如果你还处于学习阶段,或者项目复杂度可控,先自己写消息循环;如果团队要快速交付、任务链路复杂,可以引入现成的Agent开发框架。自己写循环的优点是每个环节都透明可控,模型在什么时候调用了工具、工具返回了什么、为什么决定结束,全部清清楚楚,出了问题排查起来非常直接。缺点是要自己处理很多边界情况,比如上下文爆长度、循环不终止这类问题。
用现成框架的好处是起步快,很多能力开箱即用,但坏处是黑盒化程度高。框架封装了太多逻辑,一旦行为不符合预期,想修改内部的编排策略会比较吃力。框架适合两个时间点使用:要么是项目周期极紧,必须两周内出Demo;要么是任务流程已经非常成熟,直接套模板就好。至于处于探索期的项目,我建议还是先亲手写一遍循环。
写消息循环其实不复杂,核心就是反复执行“模型生成、判断是否调用工具、执行工具、把结果回填给模型”这几个动作。先把这个透明版本跑通,你再看框架的源码就很容易理解它在做什么了,到时候再决定要不要切换,成本也不高。
3. 实操过程:把流程跑起来的完整细节
3.1 系统提示词:给智能体立清楚规矩
在写任何代码之前,先定义智能体的系统提示词。这个提示词是智能体的“岗位说明书”,它决定了模型什么时候应该调用工具、什么时候应该直接回答、什么情况下不能乱做。我见过很多失败的Demo,问题就出在提示词写得太笼统,模型完全不知道自己的职责边界。
我习惯在系统提示词里明确几个部分:角色定位、核心职责、可用工具清单、行为限制、输出格式要求。下面这个示例,展示的是“会议与日程助手”的提示词骨架。
你是一个企业内部日程管理助手。 你的核心职责是帮用户查询会议安排、整理参会准备清单、提醒重要日程。 你可以使用以下工具: - query_user_schedule:查询指定日期范围内的用户日程 - query_meeting_participants:查询某场会议的参会人信息 - generate_preparation_list:根据会议主题生成准备事项 行为限制: - 用户没有明确要求查询日程时,不得擅自调用工具。 - 工具返回为空时,必须如实告知用户“没有查到相关日程”,禁止编造。 - 生成准备清单时必须基于真实日程内容,不得虚构议题。 - 日期默认取当天,但用户明确指定日期时以用户指定为准。 输出要求: - 回答简洁直接,可以先给结论,再给明细。这段提示词里有几个细节值得注意。第一,“可以使用的工具”清单要写清楚,模型需要知道能力边界;第二,“行为限制”非常重要,尤其那句“禁止编造”,能明显降低幻觉概率;第三,输出要求里“先给结论,再给明细”,符合用户实际使用习惯。提示词本质上是在给模型立规矩,规矩越明确,行为越可控。
3.2 工具封装:把业务能力变成模型能调用的函数
工具是智能体的手,而工具封装决定了这双手灵不灵活。封装的核心不仅是写业务函数,还要写好给模型看的接口描述,也就是JSON Schema。这个描述的质量,直接影响模型能不能准确调用工具。我见过太多项目,函数本身没问题,但描述写得含糊不清,模型要么不触发调用,要么传错参数。
以“查询日程”为例,业务函数本身可能已经在系统里存在了,现在要做的是暴露成一个模型可调用的接口。Python侧的伪代码大概是这样的:
def query_user_schedule(user_id: str, date_from: str, date_to: str) -> dict: # 这里调用业务系统接口,返回日程列表 events = schedule_service.get_events(user_id, date_from, date_to) return {"events": events, "count": len(events)}真正花心思的是对应的JSON Schema描述。我在给模型定义工具时,会把每个参数的业务含义、格式、默认值都写清楚。同样以日程查询为例:
[ { "name": "query_user_schedule", "description": "查询指定日期范围内的用户日程安排。适用于用户询问会议、约会、出差安排等场景。", "parameters": { "type": "object", "properties": { "user_id": { "type": "string", "description": "当前用户的内部唯一标识,应使用会话context中的用户ID,不可为空。" }, "date_from": { "type": "string", "description": "查询起始日期,格式为YYYY-MM-DD。不传时默认取今天。" }, "date_to": { "type": "string", "description": "查询结束日期,格式为YYYY-MM-DD。不传时默认与date_from相同。" } }, "required": ["user_id"] } } ]这里面有两个容易踩坑的地方。一是“description”不能太宽泛,比如只写“查询日程”,模型可能不清楚什么场景该触发,要写清楚“用户询问会议、约会、出差安排等场景时调用”;二是“required”字段要尽量精简,只保留绝对必填的参数,减少模型为了凑参数而瞎编的概率。工具描述的质量,本质上是在节省模型的判断成本。
3.3 核心循环:消息怎么一轮轮转起来
智能体的主循环,其实就是不断重复“模型看上下文、决定动作、执行动作、拿反馈”这个过程。刚学的时候不要用框架,先把最直白的代码写出来,你会对智能体的行为逻辑有很直观的理解。下面这段伪代码,是整个开发流程里最核心的执行骨架:
messages = [{"role": "system", "content": system_prompt}, {"role": "user", "content": user_query}] for step in range(max_steps): response = chat_model.chat(messages, tools=tool_schemas) # 情况一:模型决定调用工具 if response.tool_calls: messages.append(response.to_message()) for tool_call in response.tool_calls: tool_name = tool_call.function.name args = json.loads(tool_call.function.arguments) # 执行真实工具 result = execute_tool(tool_name, args) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False) }) continue # 执行完工具后,回到循环顶部,让模型看结果 # 情况二:模型不再调用工具,直接输出最终答案 else: final_answer = response.content print(final_answer) break这段代码看起来简单,但它体现了智能体最重要的机制。模型每次决定调用工具时,不会立刻返回最终答案,而是先返回一个“工具调用请求”,我们执行完工具后,把结果作为“role=tool”的消息追加回对话,模型再基于真实结果继续思考。continue之后,模型可能会再次调用新工具,也可能直接输出答案,这个判断完全由模型根据当前上下文决定。
有几个参数想单独强调。max_steps一定要设置,我一般设5,最多不超过8,防止模型陷入无意义的循环;execute_tool一定要做异常捕获,工具崩溃不能直接让整个程序崩溃,而是把错误信息作为工具结果返回给模型,让模型自己决定怎么解释给用户。主循环越稳,智能体越像一个靠谱的执行者。
3.4 记忆系统:短期便签和长期笔记本
智能体要持续完成任务,离不开记忆。记忆系统我会分成两层来理解:短期记忆就是对话上下文,模型在同一个会话里能记住前面说了什么;长期记忆则需要跨会话保存,比如用户偏好、历史决策、常用设置,下次对话还能想起来。
短期记忆最容易出现的问题是上下文太长。工具结果、中间判断、历史对话都堆在上下文里,不到几轮就可能超过模型的上下文窗口。我的做法是“摘要压缩”:当对话轮次多到一定程度后,把前面的历史交给模型总结成一段摘要,替代原始对话记录,并保留最新几轮完整消息。这就像工作时记便签,旧的内容浓缩成一行字,新的内容完整保留。
长期记忆的方案有很多,最简单的可以拍平成本地文件或结构化数据库。比如用户在下一次会话中说“以后约会议都定在下午”,智能体可以把这条偏好抽取出结构化的用户属性存起来。下次开会安排日程时,模型先检索用户偏好记录,连同系统提示词一起注入,就能主动避开上午开会。
提示:记忆不是越多越好。上下文长度超过一定阈值后,模型对远端信息的分辨率会下降,反而更容易忽略关键指令。所以长期记忆真正注入的,应该是“与当前任务相关”的那部分片段,而不是把记忆库一股脑倒进上下文。
3.5 调优方法论:从跑通到稳定,靠的是Badcase复盘
代码层面跑通之后,真正的挑战才刚开始。我的流程是先准备一个20条左右的真实测试集,覆盖正常请求、边界请求和异常请求。比如对日程助手来说,正常请求是“明天有什么会”,边界请求是“帮我查一下去年三月的日程”,异常请求是“我不确定日期,你能帮我看看最近有没有安排”。然后人工一条条跑,记录每一条是否完成。
评估标准我坚持看三类指标:任务完成率,也就是用户目的真正达成;无失败调用的轮次,也就是模型有没有出现胡乱调用工具的情况;用户主观体验,也就是回答是否清晰、语气是否自然。完成率是最硬的指标,但后两项决定了用户真的愿不愿意用。
调优的手段优先级也非常讲究。先改工具描述和提示词,这是成本最低、见效最快的手段;再增加参数校验和返回结果整理;最后才考虑换模型或加微调。我会把失败的案例逐个拿出来,看模型当时的调用参数,再反推是描述问题、还是数据问题、还是模型能力问题。这个环节没有任何捷径,就是扎扎实实复盘,改一轮跑一轮。
4. 实操中常见的坑:一份拿来就能用的排雷清单
4.1 模型幻觉:工具没查到的数据,它自己编
最头疼的问题就是幻觉。日程助手明明查到当天没有会议记录,模型却在回答里写“下午有一场产品评审会”。排查这个问题时,我看日志后会发现模型根本没有触发或返回空结果。根因在系统提示词没有强调“工具返回为空时,必须如实说明”。所以在实践中,工具返回空结果时要显式标注,空数组后面加一条提醒,同时配合提示词双重约束,效果会好很多。
另外一个衍生问题,是模型会在参数上“编”。比如系统其实只有三个日程类目,模型却传了一个不存在的类目进去。解决思路就是在工具函数里加参数白名单校验,不合法就返回错误信息让模型自行修正。校验层是智能体最底层的护栏,业务规则不需要靠模型自觉,代码先把关。
4.2 循环不终止:模型在一个工具上反复横跳
模型反复调用同一个工具,比如连续五次查询同一个日程,就是典型的状态卡死。出现这种情况一般是上下文已经足够,但模型出于“不放心”或者本身就处于混乱状态,持续重复动作。对待这类问题,除了设置max_steps兜底外,还要检测“连续n次完全相同的工具调用”,一旦发现,立刻停止循环并按基调逻辑向用户输出当前状态。
系统层面还要加上时间预算,比如整个循环超过30秒强制退出。智能体是给真实用户用的,不能因为模型“思考太久”让用户干瞪眼。兜底文案我会设计成“系统正在尝试处理,但当前步骤执行时间较长,请稍后重试或缩小范围”,把控制权交还给用户,而不是默默卡死。
4.3 工具返回结果太长,直接把上下文塞爆
一次查询返回几百条会议记录,如果原样拼接进上下文,token可能瞬间消耗几万。这个问题在真实数据环境里太常见了。解决思路是每个工具都要为模型设计“摘要版返回”。查询日程工具不要返回全部明细,而是返回今天有几场会议、每场会议的时间和主题摘要,完整明细放到二级接口供按需查询。
我用过一个分页方案,工具第一层只返回前10条数据和总数量,系统提示词里写明“数量较大时,用户可追问查看某一场会议细节”。这样既能控制上下文长度,又能保留进一步深挖的路径。相反的教训是,一次性把所有数据都塞给模型,模型不仅耗token,处理准确性也会显著下降。
4.4 工具参数格式乱套,模型返回了非法JSON
开源模型或者部分轻量模型在调用工具时,偶尔返回残缺的JSON,比如漏了一个大括号,或者参数值多了引号。这种问题出现在生产环境非常致命,因为解析错误会直接导致整条任务失败。所以我对工具参数解析永远加一层容错代码,先把JSON字符串里的代码块标记清理干净,再尝试解析;解析失败就自动发起一次重试请求,并提示模型“上次返回的JSON格式非法,请重新生成工具调用”。
更省心的方式是用模型厂商提供的结构化输出模式,让模型直接按照Schema输出结构化对象,比解析字符串稳定得多。但即便有了这层保障,我依然保留了重试机制。两件事叠加起来,格式错误导致的失败率基本能降到一个很低的水平。
4.5 错误信息不够可读,模型“将错就错”
工具执行失败时,如果返回的是底层系统的一串异常堆栈,模型不仅读不懂,还可能基于错误信息编造出“系统正在维护”之类的解释。我的经验是,给工具统一做错误封装,任何异常都转成人类可读的描述,并明确告诉模型“该问题当前不可重试”还是“建议换个参数重试”。
比如查询日程超时,工具就返回:请求日程系统超时,请稍后重试。如果是因为传入日期格式不对,就返回:日期格式应为YYYY-MM-DD,请检查后更新参数。模型在拿到清晰错误信息后,才能做出正确的下一步判断。我把这一整套问题整理成了一张速查表,项目交付时直接留给运维团队。
| 常见现象 | 根本原因 | 排查手段 | 解决方案 |
|---|---|---|---|
| 模型编造数据 | 空结果未做约束 | 查看最终回答前后的工具结果 | 显式空结果标记+提示词约束 |
| 重复调用工具 | 循环无终止条件 | 打点记录每轮动作 | 设置max_steps+重复调用检测 |
| 上下文爆长 | 工具返回量过大 | 观察token消耗 | 工具分层返回+数量控制 |
| 非JSON输出 | 模型格式能力弱 | 查看原始响应 | 清理标记+重试机制+SWE结构化输出 |
| 错误信息误导 | 原始异常堆栈回传 | 检查工具返回体 | 统一错误封装+可读提示 |
5. 复盘与建议:我踩过最值得说的坑
整个AI智能体的开发流程,我最想分享的经验其实不是某个技术细节,而是“先跑最小闭环,再谈扩展”。很多人喜欢一上来就设计一个宏大架构,组件拆了七八个,结果连一个工具调用都还没跑通。我自己做过一个教训很深的项目:某团队要求智能体从查询数据、生成报告、到自动发出预览邮件,一条龙全自动。听起来很酷,结果第一次空跑测试就把邮件草稿发给了一位并不该收到的人。幸运的是,添加了“人工确认发送”这一层兜底,否则后果很难处理。
所以现在设计任何有外部副作用的工具时,我的原则都是“先预览,后执行”。智能体负责把方案做出来,用户点击确认后才真正落地。这种半自动模式在早期远比全自动可靠。不是模型不行,而是我们还没建立足够的信任边界。开发智能体和带新人很像,先给一个明确的小任务,用日志和反馈确认每一步都靠谱,再慢慢放手让它独立处理更复杂的链路。
另一个特别想提醒的点是:日志系统一定要从第一天就建。不是开发后期再补,是第一个版本就要把每一次模型请求、每一次工具调用、每一次错误返回都记录下来。没有日志的智能体项目,出了问题根本无从下手,只能靠改提示词碰运气。有了完整日志,调优就是一门有依据的工程,而不是玄学。智能体的行为是非确定性的,能让你真正掌控它的,就是这些细颗粒度的运行记录。
最后说一说我对这套流程的扩展想法。单智能体只是起点,当多个智能体分别负责数据查询、内容生成、对外联络时,你还需要考虑它们之间的协作方式、权限边界和消息协议。但这些都不是现在要考虑的事。先把一个智能体做扎实,把工具、记忆、反馈闭环打磨顺了,再迈向更复杂的多智能体编排,你会发现自己已经积累了一整套判断标准。开发AI智能体不像考试做卷子,更像是在打磨一个手艺活,多踩一个坑,就意味着多懂了一层。