欢迎来到啾啾的博客🐱。
记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。
有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。
目录
- 1 引言
- 2 基础概念
- 3 Agent的挑战
- 3.1 复杂度带来的“可控性”与“可靠性”的挑战
- 3.1.1 工具使用幻觉
- 3.2 ReAct循环带来 “成本”与“状态管理”的挑战
- 3.3 “评估”与“错误处理”的挑战
- 4 展望:超越ReAct
- 4.1 Plan-and-Execute Agents
- 4.2 Agentic Workflows with Graphs
1 引言
LLM应用开发的主要内容就是RAG与Agent。
在RAG轻松通系列中,我们已经了解了RAG基本流程与些许原理。
RAG的逻辑是固定的:检索——>组装提示——>生成。它只会“查资料”这一种行为。
而我们接下来要了解的Agent是动态的。它拥有一个“工具箱”,并且具备“思考”和“决策”的能力。面对一个任务,它会自己决定:
- 我应该使用哪个工具? (例如:是上网搜索,还是计算数学题,还是查询数据库?)
- 我应该给这个工具输入什么参数?
- 我拿到工具的输出后,下一步该做什么? (是继续使用别的工具,还是已经可以得出最终答案了?)
下面,就让我们一起来了解一下Agent。
2 基础概念
Agent是一个能感知并自主地采取行动的实体,这里的自主性极其关键,Agent要能够实现设定的目标,其中包括具备学习和获取知识的能力以提高自身性能。
Agent核心思想:ReAct (Reason + Act)
在Agent中,LLM不再是一次性生成最终答案,而是在一个“思考-行动”的循环中工作:
- Thought (思考): LLM首先会分析当前的任务和情况,然后生成一段“内心独白”,说明它接下来的计划。例如:“用户想知道今天北京的天气,我需要一个能查天气的工具。”
- Action (行动): 基于这个思考,LLM会决定调用一个具体的 工具 (Tool),并确定该工具的 输入 (Input)。例如:Tool: weather_api, Tool Input: “北京”。
- Observation (观察): 系统执行这个行动(即调用天气API),然后将返回的结果(例如:“北京今天晴,25摄氏度”)作为“观察结果”反馈给LLM。
- Repeat (重复): LLM接收到这个观察结果,然后再次进入“思考”阶段。它可能会想:“我已经拿到了天气信息,现在可以回答用户了。”然后生成最终答案,结束循环。也可能它会想:“用户还问了明天是否适合户外活动,我还需要查询明天的天气预报。”然后开始一个新的“思考-行动-观察”循环。
这个循环往复的过程,赋予了LLM规划复杂任务和与外部世界互动的能力。
Q:目前的Agent是“真自主”还是“伪自主”?
A:Agent所有行为都源于其提示(Prompt)中的指令和工具描述。它的“自主性”更像是一种被精确引导的、在有限选项内的“决策能力”,而非人类意义上的自由意志。
3 Agent的挑战
不同于RAG的挑战主要在分块与检索相对单调。
Agent的ReAct明显要复杂的多。
3.1 复杂度带来的“可控性”与“可靠性”的挑战
Agent的复杂度体现在“可控性”与“可靠性”:
-
可控性 (Controllability)
Q:如何引导它走在“正确的道路”上?
RAG的流程是线性的、确定的。而Agent的路径是动态的、非确定的。它可能会选择一条你意想不到的工具调用路径,或者陷入一个无意义的循环(比如反复搜索同一个关键词)。这是一个巨大的挑战。 -
可靠性 (Reliability)
Q:如何用最少的ReAct步骤生成最准确的结果?
一个Agent可能会因为对工具的错误理解、对观察结果的错误解读,或者糟糕的推理链,而导致任务失败。比如,它可能决定用“计算器”工具去回答“苹果和橘子哪个好吃”的问题。
A:高质量的工具描述+引导(提示词+计划图)。
- 精巧的提示工程: 在主提示中加入更强的约束和示例(Few-shot Prompting),向Agent展示“好的思考路径”是什么样的。
- 高质量的工具描述: 给工具起一个清晰的名字,并写一段详尽、无歧-义的描述,告诉Agent这个工具“能做什么”、“不能做什么”、“输入应该是什么格式”。这是引导Agent正确选择工具的最重要手段。
- 强制的路径规划: 对于一些关键任务,可以不让Agent完全自由发挥,而是预先定义一个大致的“计划图”,Agent可以在这个框架内选择工具,而不是天马行空。
3.1.1 工具使用幻觉
在“可靠性”挑战下,有一个非常具体且常见的问题,叫做 “工具使用幻觉” (Tool-use Hallucination)。
这指的是LLM“幻想”出了一个工具的执行结果,而不是真的去等待并使用工具的实际输出。例如,它可能会在“Action”步骤后,不等“Observation”返回,就直接在下一步的“Thought”中编造一个观察结果。这是导致Agent“脱轨”的重要原因之一,需要通过更强的提示约束和流程控制来解决。
3.2 ReAct循环带来 “成本”与“状态管理”的挑战
在ReAct的每一次循环中,历史的“思考-行动-观察”记录都会被加入到下一次的提示中,以维持Agent的“记忆”。这会导致上下文像滚雪球一样越来越大。
-
成本 (Cost)
多次调用LLM,并且每次调用的上下文都在增长,会导致API费用急剧上升。 -
状态管理 (State Management)
当上下文变得极长时,除了max_tokens的硬限制,还会遇到我们之前讨论过的“中间迷失”问题。Agent可能会“忘记”它最初的目标或者早期的重要发现。
Q:循环中成本和状态要怎么控制?
A:总结摘要+选择记忆+限制循环次数
- 上下文摘要 (Context Summarization): 在几次循环后,可以调用一次LLM,让它将之前的对话历史“总结”成一段简短的文字,然后用这个摘要来代替冗长的历史记录。
- 选择性记忆 (Selective Memory): 设计更复杂的记忆模块,只保留与当前任务最相关的历史记录,而不是全部保留。
- 限制循环次数 (Max Iterations): 强制规定Agent最多只能进行N次循环,防止其陷入无限循环,同时也控制了成本上限。
这个总结摘要类似处理操作日志时保留数据的最终状态。
除了“总结”,还有一种常见的记忆管理方式叫 “向量化记忆流” (Vectorized Memory Stream)。即,将每一步的“思考-行动-观察”都向量化并存入一个临时的向量数据库,当上下文过长时,Agent可以“检索”自己过去的记忆,找出与当前子任务最相关的历史记录来参考,而不是依赖一个线性的、易于遗忘的完整对话历史。
3.3 “评估”与“错误处理”的挑战
Agent的每一步都可能出错,比如每次LLM生成的评估是9/10分,然后LLM再依据9/10的结果继续循环。最后会产生类似“滑坡”的错误现象。给出一个看似合理但实际上完全错误的最终答案。
甚至过程中可能执行错误,以至于Agent的工具们难以解析LLM输入,导致Agent崩溃。
应对方案思考:
- 健壮的工具封装: 在代码中,每个工具都应该被包裹在一个try…except块中,捕获所有可能的异常,并将错误信息作为“观察结果”返回给Agent,让它知道“这条路走不通,请换个思路”。
- 输出解析器 (Output Parser): 使用专门的解析器来处理LLM的输出。如果解析失败,可以自动向LLM发送一条“你的输出格式不对,请按此格式重试”的反馈,实现自动纠错。
- 评估框架 (Evaluation Framework): 这是第二阶段的另一个核心。我们将学习如何使用像LangSmith、RAGAs或自定义评估脚本这样的工具,来量化评估Agent在特定任务上的成功率、效率和成本,用数据驱动的方式来发现和修复“结果滑坡”的问题。
4 展望:超越ReAct
ReAct的“一步一思考”模式,对于需要复杂规划和多步推理的任务来说,可能效率不高且容易“短视”。它就像一个只看脚下一步路的登山者,很难规划翻越整座山脉的路线。
为了解决这个问题,社区已经发展出更高级的Agent架构。
4.1 Plan-and-Execute Agents
这类Agent会先把任务分解成一个详细的“计划(Plan)”,然后逐一“执行(Execute)”计划中的每一步。它把“规划”和“执行”两个阶段分开了,避免了ReAct的短视问题。
4.2 Agentic Workflows with Graphs
使用图(Graph)结构来定义Agent的工作流。图中的每个节点是一个操作(如调用工具、LLM推理),边代表了不同操作之间的依赖关系。这允许我们设计出可以并行执行、可以条件分支、可以循环的、高度复杂的Agent行为,而不仅仅是ReAct的线性链条。