news 2026/10/22 3:01:49

Agent开发实战:从API调用到智能体工作流搭建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent开发实战:从API调用到智能体工作流搭建

从第5天开始,Agent学习终于进入深水区。前两天还在熟悉基础模型的调用方式,Day05-06直接切换到“怎么让模型自己干活”的核心问题。这两天的学习量很大,但收获也最明显:我把一套完整的Agent工作流从设计到实现完整走了一遍。这篇文章就对这两天的内容做一个复盘,重点讲我踩过的坑和一些可以直接复用的套路。如果你也在自学Agent开发,或者打算从API调用转向智能体应用的开发,这篇内容应该能帮你少走不少弯路。


1. 为什么Day05-06要聚焦这两块内容

1.1 从“会聊天”到“会干活”的关键跨越

很多人最初接触大模型时,觉得AI就是“你说一句,它回一句”,顶多是个更聪明的搜索引擎。但Agent学习的核心,恰恰是要打破这个被动交互的模式。Day05-06的安排,是在基础模型调用熟练之后,马上切入Agent最本质的东西:让模型拥有感知、决策、执行、记忆的闭环。

普通对话和真实Agent的最大区别,就是有没有“行动”。对话场景里,模型只需要输出一段让用户满意的文字;Agent场景里,模型必须根据用户目标,拆解出步骤,选择并调用外部工具,再根据工具返回的结果调整下一步动作。比如用户说“帮我把今天的会议记录整理成周报”,普通对话只能给出一段整理好的文本,但Agent会先去找到会议记录文件,读取内容,按周报格式生成文本,然后保存到指定位置,甚至把周报发给相关人。

这个跨越看起来只是多接了几个接口,实际上带来了一系列连锁问题:模型怎么知道该调用哪个工具?工具参数怎么传给模型?工具返回错误时模型如何恢复?用户目标太大时怎么拆解成多个步骤?这些恰是Day05-06重点解决的。

我自己最初的想法是先去做RAG或模型微调,觉得那是“大头”。后来发现方向反了。如果没有把Agent的骨架搭起来,RAG做出来也只是一个“带检索的聊天框”,而不是一个能独立完成任务的智能体。所以Day05-06把重心放在了Agent的运行机制和最小实现上,后续再往里面加记忆、加多Agent协作,都会顺很多。

1.2 学习路线的取舍:不贪多,先把骨架搭起来

这两天学习材料不少,很多教程一上来就是各种高级框架、分布式Agent编排、复杂工作流。我一开始也跟着学,但很快发现消化不良:名词太多,概念之间的关系没理清,手也动不起来。

后来我调整了策略:彻底扔掉“框架优先”的思路,回到最原始的执行逻辑。先搞清楚一个Agent自己运行起来,最少需要哪几部分,然后用最朴素的代码一步步拼。事实证明这个决策非常正确。

如果类比建房子,我前两天学的模型调用是“搞懂了砖头和水泥怎么用”,Day05-06就是在打地基和立柱子。地基是Agent的思维循环,柱子是感知、行动、记忆几个模块。柱子立不起来,后面装修得再好看也会塌。

所以这两天的内容,我把它总结成两条主线:

  • 主线一是Agent架构的整体拆解:感知层、决策层、执行层、记忆层分别解决什么问题。
  • 主线二是最小可运行Agent的实作:不依赖任何重型框架,用基础模型接口加几个工具函数,让一个Agent真的能跑通“理解问题-拆解任务-调用工具-观察结果-继续执行”的完整循环。

这两条主线学完后,再去看各种开源框架时,思路会完全不同。以前看到的是“它提供了什么”,后面看到的是“它用哪种方式实现了哪个模块,为什么这么设计”。


2. 核心架构拆解:Agent到底由哪几块组成

2.1 感知层:怎么让Agent“看懂”请求和上下文

感知层是Agent接收外部信息的入口。普通API调用里,输入就是一段用户消息;Agent场景下,输入可能包含多种形式:一句自然语言指令、一份上传的文档、一段系统日志、甚至实时轮询到的状态变化。

Day05的一个重要练习,是让Agent处理“非结构化输入”。例如用户说“帮我看看今天下午有没有空会议室,有的话就订一个,把邀请发给A同学”。这句话里包含了好几个关键点:时间范围是“今天下午”,动作是“查询+预订+发送邀请”,对象是“A同学”,状态是“如果空闲才订”。如果模型只做一次问答,这很轻松;但如果Agent要把这个指令拆成多个步骤,就必须先从输入中准确提取这些约束。

我做了一个简单验证:直接让基础模型输出一个JSON结构,包含intent、entities、params几个字段,并要求模型把用户指令拆成结构化意图。效果不错,但有一个关键心得:提示词里必须给出明确的格式约束和少量示例。否则模型会自由发挥,导致后面的工具调用环节无法稳定对接。

感知层还有一个容易忽略的点:不是所有输入都需要完整交给模型。比如一个很长的文件,直接塞进上下文会导致注意力分散,也加剧费用压力。更合理的做法是先对输入做粗加工:截断无效内容、提取章节标题、把关键人名/时间/地点单独列出来,再把加工后的信息交给Agent决策。这一步有点类似人看邮件先扫一眼主题和正文摘要,而不是每一封都逐字读完。

2.2 决策层:ReAct模式与任务规划

决策层是Agent的“大脑”,负责根据当前状态决定下一步做什么。Day05学到的核心模式是ReAct——让模型交替进行推理(Reasoning)和行动(Action),然后观察行动结果(Observation),形成循环。

我用自己的话解释这个模式:普通对话是“想完了直接说”,ReAct是“想一步,做一步,看一步”。比如任务“整理本季度报销数据”,Agent先推理“我需要先找到报销文件”,于是执行一个搜索文件的操作;工具返回三个文件路径后,Agent继续推理“这三个文件里哪些是季度的”,于是读取文件头部信息;看到第二、三个文件符合要求后,Agent再决定“读取全部内容并汇总”。每一步的推理都基于上一步的观察,行动也因此有依据。

在代码实现上,ReAct循环的结构大致如下:

  1. 把所有历史消息(包括推理、行动、观察)拼进上下文,送给模型。
  2. 要求模型输出一个结构化的行动决策,包含thought(为什么这样做)和action(要做什么)。
  3. 如果action是调用工具,则执行对应工具函数,把返回结果作为一条“观察”消息加到上下文,回到第1步。
  4. 如果action是最终回答,则结束循环,把回答返回给用户。

这个循环简单,但很容易失控。最大问题是:模型可能陷入“一直在推理,永远不行动”的状态。这时候系统提示词必须强制约束:当存在可执行工具时,必须优先选择工具;只有确认任务完成,才允许输出最终回答。此外,一定要设置最大循环次数,防止模型在异常情况下无限调用。

2.3 执行层:工具调用与动作执行

执行层是Agent能“动手干活”的关键,也是Day06大部分实操时间的去向。所谓工具,本质上就是一段函数:输入是明确的结构化参数,输出是可解析的结果。例如“读取文件”工具,入参是文件路径,出参是文件内容文本;“发送邮件”工具,入参是收件人、主题、正文,出参是发送状态。

让模型学会调用工具,重点有三件事:

第一,工具描述要写得清晰。不要用模糊的话,比如“读取文件”,而要注明参数格式、类型、取值范围。比如路径必须是绝对路径,支持 txt/md/docx 格式。模型是靠工具描述来理解“什么时候该用这个工具”的,描述不清晰,调用率就会下降。

第二,参数必须严格校验。模型输出的参数经常有幻觉:路径不存在、时间格式写错、中文标点混入。执行层必须对每个参数做校验,失败时要返回一个清晰的错误信息,让模型下次能纠正。常见的做法是,在工具函数里用try/except包住,把异常文案转换为“工具执行失败:原因xxx”的观察消息。

第三,工具返回结果要结构化。不要返回一整块杂乱文本,最好分成status、data、error等字段。这样模型在下一轮决策时,能快速看到是否成功、数据是什么、失败原因是什么。结构化的观察结果,能大幅减轻模型的理解负担,减少重复出错。

2.4 记忆层:短期上下文与长期记忆

记忆是Agent和普通对话程序最不一样的地方。普通程序可以用一个变量保存历史记录,但Agent的记忆要服务于“决策”,而不是简单回放。

短期记忆最直接的做法,就是把对话历史放进上下文窗口。但上下文窗口是有限的,而且每轮消息都全量塞给模型,费用和延迟都会不断增加。我这两天实验下来,发现一个比较实用的办法:只保留最近3-5轮关键消息,超过的部分压缩成一段摘要放在历史开头。这样模型既不失上下文,又不会超过窗口限制。

长期记忆对应的是需要跨会话保存的信息:用户偏好、之前的项目进展、环境配置等。Day06我测试了最朴素的长期记忆方案:所有重要信息都写入一个本地JSON文件,需要时用关键词或简单规则检索。比如用户之前提到“我习惯周五晚上开会”,这条偏好被写入记忆文件;下次Agent规划日程时,会先检查记忆文件里有没有时间偏好,再决定发会议邀请。

很多人一上来就准备上向量数据库、做embedding。但我的建议是,如果你的数据量没有上千条,先用关键词检索和规则匹配完全够用。等跑通了完整流程,再判断是否真的需要向量检索。过早引入重型组件,反而会把注意力从核心逻辑转移到基建维护上。


3. 实操记录:用纯手工方式搭一个最小可用Agent

3.1 场景选择:做一个“会议纪要整理Agent”

Day05-06最核心的产出,是一个真能跑起来的“会议纪要整理Agent”。场景选得比较小:用户传入一段会议原始记录,Agent自动完成“提取任务、整理待办、生成摘要”,并把结果保存成一个Markdown文件。

选择这个场景有三个原因。第一,输入输出边界清晰,不会陷入“什么叫整理好”这种模糊问题。第二,需要用到至少三种工具:读取文件、解析文本、写文件,能覆盖工具调用的基本形态。第三,结果可验证,跑完就能打开文件看效果,能带来实实在在的正反馈,对学习状态很重要。

我强烈建议自学的朋友先选一个这类“小而有边界”的场景,不要一开始就做“全自动数据分析助手”这种野心太大的东西。Agent能不能跑通,关键不在于模型多强,而在于任务边界和工具设计是否清晰。

3.2 定义工具函数

因为我是在本地实验,没有引入重型框架,工具就是普通的Python函数。在设计上,每个工具都遵循“参数简单、返回结构化”的原则。

下面是一个简化版的工具注册逻辑:

def read_file(path: str) -> dict: try: with open(path, "r", encoding="utf-8") as f: return {"status": "success", "data": f.read()} except Exception as e: return {"status": "error", "error": str(e)} def write_file(path: str, content: str) -> dict: try: with open(path, "w", encoding="utf-8") as f: f.write(content) return {"status": "success", "path": path} except Exception as e: return {"status": "error", "error": str(e)}

为了让模型能正确选择工具,我还维护了一个工具清单,包含工具名、功能说明、参数格式、返回格式。这个清单会写入系统提示词中,同时也在上下文里给一个调用示例。

举个例子:

{ "tool": "write_file", "params": { "path": "/tmp/meeting_summary.md", "content": "今天讨论了..." } }

工具函数的代码并不复杂,但有一处容易被忽略:参数类型必须严格。比如read_file如果接收一个None路径,Python会抛TypeError,而模型下一轮可能还搞不清原因。所以我统一在每个工具入口做了防御性检查,确保返回的是结构化的错误信息,而不是让异常直接打断循环。

3.3 编写决策主循环

主循环是整个Agent的心脏。它做的事情可以概括为:把所有的历史消息拼接到上下文,询问模型下一步行动,然后执行并返回观察结果,反复循环。

我用的是非常朴素的while循环,逻辑如下:

def run_agent(user_query): msgs = [system_prompt, {"role": "user", "content": user_query}] for step in range(max_steps): response = model_client.chat(messages=msgs) action = parse_action(response) if action["type"] == "final_answer": return action["answer"] result = execute_tool(action["tool"], action["params"]) msgs.append({"role": "tool", "content": json.dumps(result, ensure_ascii=False)}) return "超过最大步数,任务未完成"

这个循环有几个关键细节。

一是我在所有历史消息里同时保留了模型自己的推理、工具调用和观察结果,这样模型能“看到”自己刚才做了什么,避免反复提出同一个行动。

二是parse_action用的是双保险:优先按JSON解析,如果JSON失败,再用正则匹配输出里的action: xxx和params: xxx部分。为什么这么麻烦?因为模型有时候会输出额外文字,比如“好的,我来处理”,如果不把这些噪音去掉,工具调用就失败了。

三是max_steps必须存在。我一开始没设置上限,结果碰到一次模型连续调了十几次工具,白白消耗了Token和等待时间。后来固定为8步,正常任务基本都够用,超时了就返回“需要人工介入”的兜底信息。

3.4 提示词设计与参数选择

这个小Agent的系统提示词我改了很多版,里面最核心的是三部分:

  • 角色定义:你是一个自动整理会议纪要的Agent,目标是完成用户指定任务。
  • 工具使用规范:当你认为需要读取或写入文件时,必须调用工具;工具调用必须用指定JSON格式;一次只能调用一个工具。
  • 决策输出规范:给出两个选项,一是调用工具,二是输出最终回答,不能同时做。

其中“一次只能调用一个工具”非常关键。没有这条约束时,模型经常尝试在一个响应里同时调用多个工具,比如一边读文件一边写文件,这会让执行逻辑变得很复杂。作为最小实现,我更希望模型一步步来。

参数方面,我做了一组对比,发现temperature设置为 0 时工具调用最稳定,因为不需要创造性发散;但最终回答摘要会有一点机械。折中后我把大部分对话流程的温度设为 0.2,只对最后写摘要的步骤设为 0.4,既能保证工具调用稳定,又不太冷冰冰。

max_tokens同样需要控制。如果给的max_tokens太小,模型的行动决策可能会被截断,后半截输出就成了乱码;给太大又浪费。我实测下来,决策输出通常300-500 token足够,最终回答可以放宽到1000左右。

3.5 运行结果与效果观察

第一次跑通的时候,我盯着控制台看了好久。用户输入是一段模拟会议记录:

“今天讨论了新版本延期问题,前端资源不够,决定从其他项目临时借调一名开发;待办:周三前完成接口联调;王工负责更新排期。”

Agent的执行过程大致是:

  • 第一步,读取原始会议记录文件。
  • 第二步,生成结构化摘要,提取了三个关键待办。
  • 第三步,调用写文件工具,把整理结果保存为meeting_summary.md。
  • 第四步,输出最终回答,告诉用户摘要文件和待办列表已经生成。

虽然每一步都很慢,中途还出现过一次工具参数写错的情况,模型读到错误提醒后自己纠正了路径。那种“模型自己纠错成功”的感觉,是学Agent最上头的瞬间。

这次实操也让我意识到,一个最小Agent并不需要多么复杂的组件,一个模型接口、几个工具函数、一个循环、一份提示词,就够了。但真实工程里,难点会转移到稳定性和边界处理上,这也是Day06后半段一直在做的事。


4. 两天里踩过的坑与排查方法

4.1 模型陷入“嘴上跑火车”的循环

第一天下午第一次跑完整流程时,我遇到一个特别典型的问题:模型一直在输出“我需要先读取文件”“我接下来要做的是……”“好的,让我想想怎么处理”,看起来逻辑通顺,却始终没有输出工具调用JSON。

排查下来,原因是系统提示词给了太多的“推理空间”。模型倾向于把推理过程写得完整漂亮,但这在Agent里是灾难。后来我把输出规范改成了“如果存在可以完成任务的工具,必须直接调用;只有在不需要任何工具时,才能输出回答”,同时给了一个“错误示范”和“正确示范”的对比。这个问题立刻缓解。

后续还遇到过一种变体:模型确实调用了工具,但工具完成得很好之后,它并不总结,而是继续调用同一个工具,造成重复劳动。解决方法是要求在观察结果后先判断“任务是否已完成”,如果已完成,下一轮必须给最终回答。

4.2 工具参数解析总是失败

这是Day06最磨人的问题。模型返回的工具调用大概是这样:

{"tool": "read_file", "params": {"path": "/tmp/会议记录.txt"}}

但偶尔它会在JSON前后加一堆解释文字,比如 “好的,我将会读取该文件:{...}”。直接用json.loads必然报错。我最初想靠严格提示词解决,但实测下来,无论提示词多严格,模型都可能在边缘情况下夹带私货。

最终的解法是双保险解析:

  1. 先用正则找到{到}之间的部分,截取出来。
  2. 再尝试json.loads;如果失败,把里面的中文引号和转义符修复一遍。

同时,我在工具调用示例里特意给了“带解释文字”的反例,帮助模型理解必须原样输出JSON。这样处理之后,解析成功率从最初的70%提升到了95%以上。

4.3 长期记忆写不进、读不出

做长期记忆功能时,我把用户偏好直接存进了一个本地文本文件。一开始遇到的问题是:Agent在决策时根本不知道“还有记忆这回事”,每次都是直接忽略记忆去问用户或按默认参数执行。

后来我把记忆检索做成一个独立工具,叫search_memory,并把它的描述写清楚:“在历史偏好中搜索与当前任务相关的信息,如果没有相关信息,返回空列表。”这样一来,模型在接到一个新任务时,会先主动调用记忆检索,再决定是否继续问用户。

还有一个更隐蔽的问题:检索逻辑太粗糙,导致把无关偏好也捞了出来。比如用户说“周五开会”,记忆里有一条“周五交通拥堵,会议时间安排在下午更好”,模型就会去调整时间。解决方法是给每条记忆加标签,比如time_preference、meeting_habit、file_location、contact_name,检索时先按标签过滤,再按关键词筛选。这比纯向量检索慢一点,但胜在规则完全可控,也特别适合小型数据量。

4.4 上下文越堆越长,费用和延迟直线上升

第三天下午我观察到一个现象:循环跑得越久,单轮响应时间越长。原因很直接:我把每一轮的工具观察结果都原封不动地拼进上下文,导致上下文越来越长,模型处理成本随之飙升。

最简单的解法,就是做“历史裁剪”。我实现的策略是:只保留最近两轮的工具调用和观察结果,更早的内容压缩成一段摘要放在开头,比如“已完成的操作:读取了文件A,生成过两版摘要”。这个是纯文本拼接,效果已经够用,至少不会再出现上下文长度超限的报错。

但要注意一点:裁剪历史时要保留“重要的中间结论”。例如模型曾经从文件A中提取出“预算为5000元”,如果这段观察被裁掉了,后续模型可能会忘记这个数字。所以我在裁剪前会先让模型把关键信息同步到记忆文件里,再对历史做压缩。这样即使历史丢了,Agent也能通过调用记忆检索找回关键信息。

4.5 常见问题速查表

说白了,Agent开发里有大量问题不来自模型本身,而来自工程细节。我把这两天遇过的典型问题做成了一张速查表:

现象根因解决办法
模型一直输出分析但不调用工具提示词约束太弱强制要求存在工具时优先调用,并给正反示例
调用工具时一直在JSON前后加解释文字输出格式不稳定正则截取 + 容错解析 + 减少prompt中的干扰项
模型做已经完成过的动作缺少对历史观察的利用循环内保留工具结果,加“任务是否已完成”判断
内存检索结果不相关检索策略太粗加标签过滤,再做关键词匹配
上下文增长导致延迟升高历史全量保留历史裁剪 + 摘要压缩 + 关键信息外置记忆
工具返回错误,模型反复用同样参数重试错误信息不够具体返回结构化错误,写明哪一步失败、参数问题是什么

这张表我会继续补充,因为很多问题是会反复出现的。每次花时间在工程上做好兜底,后面跑新场景时都会轻松不少。


5. 下一步要补的功课,以及这两天学习最直接的体会

5.1 下一步要补的功课

两天学完,我对Agent的“骨架”已经心里有数,但这还只是开始。我最想补的第一块,是如何让多个Agent分工协作。现在做的单Agent,所有任务都压在同一个模型循环里,一旦任务复杂,工具数量超过几十个,模型的选择困难会明显增加。多Agent分工的好处是每个Agent专注一个子任务,决策和工具调用都会更稳定。

第二块是系统性评估。我现在验证一个Agent好不好,基本靠肉眼观察输出是否合理。这太不严谨了。后面至少要做一批测试用例,覆盖正常、异常、边界场景,记录成功率、平均调用步数、无效调用比例等指标。只有量化了这些数据,才能知道改一次提示词是变好还是变差。

第三块是安全与容错。Agent一旦拥有写文件、发消息这类真实操作权限,一个错误决策就可能造成实打实的损失。所以后面必须给工具加上权限分级、二次确认、操作日志,确保Agent的行为可审计、可回滚。

5.2 学习体会:工程化细节才是真正的分水岭

这两天最直接的体会就是:Agent能否跑通,决定因素不是模型聪明不聪明,而是你愿不愿意把每一个环节的细节抠到位。

模型能力再强,如果你不告诉它有哪些工具、每个工具怎么用、输出格式是什么,它照样会瞎猜。反过来,只要你把工具描述、参数校验、循环约束、历史管理这些工程细节做好,即便用很基础的模型,也能跑出稳定可用的Agent。

我见过很多人一上来就追最新框架、最新模型,结果核心逻辑没搞懂,遇到问题只会换框架换模型。但我的亲身经历是,回归到最小实现,亲手把每一个模块写一遍,才能真正理解Agent为什么是今天这个样子,以及各种框架想帮你解决什么问题。


最后再分享一个小建议:如果你也正在学习Agent,请一定给自己留出大量的调试时间。不要指望第一次跑通就是完美结果,更不要因为一次失败就怀疑路线。我这两天大概有60%的时间都在盯日志、改参数、调提示词。但正是这些“磨人”的时刻,把Agent的原理一点点刻进了我的直觉里。这种手感,光看文章和视频是永远得不到的,只有自己动手踩几次坑,才能真正变成自己的东西。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 2:59:01

SPPF融合焦点调制:YOLO全局语义增强的轻量即插即用改进

直接说结论:把Focal Modulation焦点调制模块接进SPPF,是我最近几轮YOLO改进实验里收益最稳、改动最少的一步。它不需要换backbone,也不需要重写整个检测头,参数增量可以控制在几十万到一百多万之间,却能把中高层特征长…

作者头像 李华
网站建设 2026/10/22 2:58:51

多元线性回归避坑指南:从共线性诊断到业务落地的工程实践

简介:这份资源围绕多元线性回归模型展开,面向具备一定R语言基础、希望掌握统计建模完整流程的数据分析学习者与研究者。内容以上海人均生产总值为案例,演示从数据导入、探索性分析到模型构建、评估、残差诊断与系数显著性检验的全过程&#x…

作者头像 李华
网站建设 2026/10/22 2:58:47

SpringBoot+Vue+MySQL企业OA系统部署与二次开发实战指南

从接到需求到把系统跑起来,中间隔着的往往不是代码,而是一堆文档没写清楚的环境问题、版本兼容问题和逻辑理解问题。最近帮某家公司的行政部搭建内部管理系统,他们在用Excel表格和微信群里转来转去的审批消息管考勤、管请假、管报销&#xff…

作者头像 李华
网站建设 2026/10/22 2:58:36

基于SSM与JSP的生鲜配送系统实战:从下单到配送全流程解析

简介:这份资源是面向高校计算机相关专业毕业生的SSM框架生鲜配送系统完整设计与实现方案,适合正在准备毕业设计、需要真实项目参考或答辩演练的同学。压缩包共1320个文件,约18.86MB,包含124个Java源文件、148个JSP页面、359个Java…

作者头像 李华
网站建设 2026/10/22 2:58:14

射频笔试核心:腔体谐振器与噪声系数计算及避坑指南

简介:这份文档整理的是2017年华为射频工程师岗位的笔试题,面向准备应聘射频相关职位、需要检验理论基础的工程师与应届求职者。内容围绕腔体谐振器、噪声系数计算等核心考点展开,并延伸至射频电路设计、微波工程、频谱分析、射频信号处理、无…

作者头像 李华
网站建设 2026/10/22 2:56:58

OpenClaw接入聊天APP实战:从终端到手机,打造随身AI助手工作流

上周我把OpenClaw接到了聊天APP里,现在每天在手机上发一条消息就能让它查资料、写提醒、整理信息,再也不用打开终端敲命令。这篇文章就把完整的对接过程、配置思路和踩坑经验写下来,重点覆盖两个方向:一是如何把OpenClaw接入常见的…

作者头像 李华