三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

AI Agent执行循环:从单次调用到持续思考的智能体引擎

AI Agent执行循环:从单次调用到持续思考的智能体引擎

1. 项目概述:从“一次调用”到“持续思考”的跨越

最近和不少同行交流,大家聊起AI应用开发,尤其是Agent(智能体)时,总绕不开一个核心困惑:它到底是怎么“动”起来的?我们调用一个大模型API,拿到一段文本回复,这只是一个瞬间的“问答”。但一个真正的Agent,比如能帮你自动写周报、分析数据趋势、甚至管理一个复杂项目流程的智能助手,它展现出的是一种持续的、有目标的“行为”。这中间的鸿沟,就是由一套精巧的“执行循环”机制来填补的。今天,我就结合自己踩过的坑和项目实践,来拆解一下这个从单次模型调用到可运行Agent的核心引擎——执行循环(Execution Loop)或运行时(Runtime)是如何工作的。无论你是想用Spring AI、LangChain这类框架快速上手,还是打算从零理解其原理进行深度定制,搞懂这个循环,就等于握住了Agent开发的钥匙。

简单来说,你可以把一次孤立的模型调用想象成向一位博学的顾问提出一个问题,他给你一个答案后对话就结束了。而一个Agent,则是为你雇佣了一位拥有这位顾问大脑、同时还配备了任务清单、记事本、各种专业工具(如计算器、搜索引擎、代码执行器)并懂得如何协调使用的全能助理。这位助理的工作模式不是一个问答,而是一个“观察-思考-行动-再观察”的循环。本次探讨的核心,就是拆解这个循环的每一个齿轮是如何咬合运转的。

2. Agent执行循环的核心架构拆解

一个典型的Agent执行循环,远不止是“循环调用模型”那么简单。它是一个包含了状态管理、决策生成、工具执行、结果评估的闭环系统。其核心架构通常可以抽象为以下几个关键组件,它们共同构成了Agent的“大脑”和“身体”。

2.1 认知核心:LLM作为决策引擎

大语言模型(LLM)是Agent的“认知核心”或“决策引擎”,但它在这里扮演的角色与简单聊天场景有本质不同。在循环中,LLM的输入不再是单一的用户问题,而是一个丰富的“上下文”(Context),其中至少包含:

  1. 系统指令(System Prompt):定义Agent的角色、目标、约束和操作规范。这是Agent的“宪法”,决定了它的行为边界和思考方式。例如,“你是一个数据分析助手,专注于从给定数据中提取洞察,并以Markdown表格形式呈现。你不能执行任何文件写入操作。”
  2. 对话历史(Conversation History):包括之前的多轮用户输入、Agent的思考过程、行动和观察结果。这为Agent提供了短期记忆,使其能理解当前步骤在整体任务中的位置。
  3. 工具描述(Tool Descriptions):以结构化格式(通常是JSON Schema)向LLM说明它当前可以调用哪些工具(函数),每个工具的名称、描述、所需参数及其格式。这相当于给Agent一本“工具使用说明书”。
  4. 当前状态与目标(Current State & Objective):明确告知Agent目前任务进展到了哪一步,最终要达成什么目标。例如,“我们已经获取了上个月的销售数据CSV文件,下一步需要计算每个品类的环比增长率。”

LLM基于这个丰富的上下文,输出不是一个直接给用户的答案,而是一个“决策”。这个决策通常是一个结构化的指令,比如:

  • 调用工具(Act){"action": "calculate_growth_rate", "action_input": {"file_path": "sales_mar.csv", "category_column": "Product"}}
  • 最终回答(Final Answer):当它判断所有必要步骤已完成,信息已齐备时,会直接生成给用户的最终回复。
  • 暂停等待(Pause):在某些设计下,它也可能决定需要更多用户输入。

这个从丰富上下文到结构化决策的过程,是Agent具备“思考”能力的基础。关键在于,我们要通过精妙的Prompt工程,引导LLM学会在“使用工具”和“直接回答”之间做出正确选择。

2.2 记忆模块:维持状态的上下文管理器

记忆是Agent实现多轮交互和持续任务的基础。它不仅仅是存储历史消息,更是一个动态的、有结构的上下文管理器。通常分为几个层次:

  • 短期记忆/对话记忆:保存当前会话中的交互序列。实现时需要注意上下文窗口的长度限制。常见的策略包括:
    • 滑动窗口:只保留最近N条交互。
    • 摘要压缩:将较旧的对话内容通过另一个LLM调用总结成一段精炼的文字,再放入上下文。这能保留关键信息同时节省Token。
    • 关键信息提取:只结构化地存储关键实体、数字、决策点。
  • 长期记忆:跨越会话保存的信息,通常需要外部存储(如向量数据库)。例如,Agent可以从历史文档中学习你的偏好,或者在多次数据分析任务后记住常用的数据清洗步骤。这通过将信息嵌入(Embedding)为向量并存储,在需要时进行检索(Retrieval)来实现。
  • 工作记忆(Working Memory):这是当前任务执行循环中的核心。它维护着任务的当前状态,例如:“步骤1完成:已下载数据;步骤2进行中:正在计算增长率;待办:生成可视化图表”。这个状态会随着每一步的执行而更新,并作为输入的一部分提供给下一轮的LLM决策。

在实现时,一个常见的“坑”是记忆的无限制增长导致上下文爆炸。我的经验是,一定要为短期记忆设置一个清晰的逐出(Eviction)或压缩策略。例如,在工具执行步骤,只把工具调用的“结果摘要”而非全部原始数据(可能是一张巨大的表格)放入上下文。直接塞入原始日志或大数据块,是导致后续LLM调用混乱或超限的最常见原因。

2.3 工具集:Agent的行动手脚

工具(Tools)是Agent与外部世界交互、执行具体操作的接口。一个工具本质上是一个可以被Agent调用的函数。工具集的设计质量直接决定了Agent的能力边界。

  • 工具类型
    • 信息获取类:网络搜索(如SerperAPI、Tavily)、数据库查询、API数据抓取。
    • 计算与处理类:Python代码执行器(需在沙盒环境中)、数据计算(Pandas)、字符串处理。
    • 系统操作类:读写文件(需严格控制权限)、发送邮件、操作键盘鼠标(RPA)。
    • 专用领域类:调用专业软件API、执行行业特定分析模型。
  • 工具描述的关键性:给LLM的工具描述必须清晰、无歧义。除了名称和功能描述,参数的定义要尽可能详细和类型严格。例如,与其说“输入一个日期”,不如说{"name": "date", "type": "string", "description": "日期,格式必须为YYYY-MM-DD"}。模糊的描述会导致LLM生成错误的参数格式,调用失败。
  • 安全性考量:这是工具设计的重中之重。绝对不能让Agent拥有不受限制的文件系统访问权或网络权限。必须通过沙盒环境(如Docker容器、受限的Pythonexec环境)来运行代码类工具。对于文件操作,应限定在特定的“工作区”目录内。每次工具调用都应有日志记录,便于审计和回滚。

在我的项目中,曾因为一个文件读取工具的描述不够严格,导致LLM试图用“上周的数据”这样的模糊描述作为文件名,从而引发了一连串的错误。后来我们为所有文件操作工具都加上了严格的路径校验和默认目录限制。

2.4 执行引擎:协调循环的运行时

执行引擎(Runtime)是粘合以上所有组件的“总控程序”。它负责驱动整个“观察-思考-行动”循环。一个最小化的执行循环伪代码如下所示:

# 初始化Agent状态 state = initialize_agent(task=用户任务, memory=记忆系统, tools=工具集) max_iterations = 10 # 防止无限循环 for i in range(max_iterations): # 1. 观察:构建当前上下文 context = build_context(state, memory, tools) # 2. 思考:调用LLM进行决策 llm_response = call_llm(context) decision = parse_llm_response(llm_response) # 解析出是调用工具还是最终回答 # 3. 决策与行动 if decision.type == "tool_call": # 执行工具 tool_result = execute_tool(decision.tool_name, decision.tool_args) # 更新状态:将“行动(工具调用)”和“观察(工具结果)”存入记忆 state.update(行动=decision, 观察=tool_result) # 检查工具执行是否出错,出错可进入错误处理分支 if tool_result.status == "error": handle_error(tool_result, state) elif decision.type == "final_answer": # 输出最终答案,结束循环 return decision.answer_to_user break else: # 处理无法解析或其他情况 handle_unknown_decision(decision, state) # 循环结束(可能因超最大迭代次数) return "任务未在指定步数内完成,可能过于复杂或遇到障碍。"

这个循环的核心逻辑是:基于当前完整状态(记忆+目标)做出一个最原子的下一步决策,执行它,将结果作为新状态的一部分,然后进入下一轮决策。这里的“原子性”很重要,理想情况下,一轮循环只做一个明确的动作(调用一个工具),这有助于LLM理解和保持任务的连贯性。

3. 关键实现细节与避坑指南

理解了架构,我们来看看在具体实现中,有哪些细节决定了Agent的稳定性和智能程度。

3.1 Prompt工程:引导LLM做出可靠决策

系统指令(System Prompt)是Agent的“灵魂”。一个糟糕的指令会让最强大的模型表现得像个傻瓜。编写有效的指令有几个原则:

  • 角色与目标清晰:开宗明义。“你是一个专注于XXX的助手,你的目标是YYY。”
  • 输出格式强制约束:这是避免LLM“胡说八道”的关键。你必须明确要求它以特定格式(如JSON)响应,并定义好键名。例如:“你必须以以下JSON格式回应:{“thought”: “你的推理过程”, “action”: “工具名或FINAL_ANSWER”, “action_input”: “参数或最终回复”}
  • 工具使用规范:明确告诉LLM:“你只能使用提供的工具列表中的工具。在决定使用工具前,先检查工具的描述和参数要求。如果现有工具无法完成任务,请直接输出FINAL_ANSWER说明情况,不要编造工具。”
  • 分步思考鼓励:鼓励LLM在thought字段中展示其推理链(Chain-of-Thought)。这不仅能提高决策质量,也为调试提供了宝贵窗口。例如:“在输出JSON前,请在‘thought’字段中简要分析当前情况和下一步计划。”

一个常见的陷阱是LLM有时会“忘记”格式要求,或者在工具参数中输出多余的解释文字。解决方法是:在调用LLM的API时,将格式要求同时放在system消息和user消息中作为强提醒,并且在解析响应后,增加一个健壮的JSON解析和校验层,如果解析失败,可以将错误信息和原始响应再次喂给LLM,要求它纠正。

3.2 工具执行与错误处理

工具执行并非总是成功的。网络超时、参数无效、资源不足都会导致失败。一个健壮的Runtime必须包含错误处理机制。

  • 结构化工具结果:工具函数应返回一个结构化的对象,至少包含:status(成功/失败)、result(成功时的结果数据)、error(失败时的错误信息)、log(执行日志)。
  • 错误反馈循环:当工具执行失败时,不应直接让整个Agent崩溃。而是应该将格式良好的错误信息(例如:“调用搜索API失败,原因:网络超时。请检查网络或稍后重试。”)作为“观察”存入状态,并进入下一轮循环。LLM在接收到这个“观察”后,就有可能做出新的决策,比如重试、换一种方法或向用户求助。
  • 超时与重试:对于可能超时的工具(如网络请求),必须在Runtime层面设置超时限制,并可能实现有限次数的重试逻辑,避免Agent卡死。

我曾实现过一个需要调用外部天气API的Agent。最初没有处理API限流错误,导致Agent一遇到“429 Too Many Requests”就僵住。后来在工具层封装了错误码识别和友好的错误信息生成(如“天气服务当前繁忙,建议稍后再试或使用缓存数据”),Agent就能优雅地处理这个问题,并在后续循环中尝试其他方案。

3.3 循环终止条件

Agent不能无限循环下去。必须定义清晰的终止条件,通常包括:

  1. 成功终止:LLM输出FINAL_ANSWER
  2. 失败终止:达到最大迭代次数(如50步),防止陷入死循环。
  3. 外部中断:用户手动取消任务。
  4. 逻辑终止:检测到连续多次工具调用无效或进入重复状态(可通过状态哈希判断)。

设置合理的最大迭代次数非常重要。对于简单任务,10-20步可能就够了;对于复杂规划任务,可能需要50步甚至更多。这需要根据具体任务类型进行测试和调整。

4. 主流框架中的实现窥探

理解了原理,我们再看看主流框架是如何封装这些概念的。这能帮助我们在“造轮子”和“用轮子”之间做出选择。

4.1 LangChain/ LangGraph 的视角

LangChain 的 Agent 执行器(AgentExecutor)本质上就是上述循环的一个高度封装实现。它将工具、LLM、记忆组合成一个可执行对象。其核心优势在于丰富的工具集成和相对易用的API。

  • 关键概念
    • Agent:包含LLM和Prompt模板,负责生成决策。
    • Tools:工具集合。
    • AgentExecutor:运行时,驱动循环。
    • Memory:对话记忆。
  • 执行流程AgentExecutor.run()内部就封装了观察-思考-行动的循环,并处理了解析、工具调用和迭代限制。
  • LangGraph的进阶:对于更复杂、有状态、需要分支或循环的工作流,LangGraph提供了基于图(Graph)的编程模型。你可以将Agent的每个步骤(节点)和状态转移(边)显式地定义出来,实现比简单循环更精细的控制流。这对于实现具有严格阶段划分的复杂Agent(如先调研、再分析、最后报告)非常有用。

使用这类框架的“坑”在于,有时其抽象会隐藏底层细节,当出现诡异行为时调试起来比较困难。务必打开verbose调试模式,查看每一步LLM的输入输出和工具调用记录,这是定位问题的唯一捷径。

4.2 Spring AI 的集成思路

对于Java生态的开发者,Spring AI 提供了一种将AI能力(包括Agent)以Spring Way集成到应用中的方式。它抽象了与不同模型提供商(OpenAI, Azure OpenAI, Ollama等)的交互,并提供了类似Spring风格的模板和回调机制。

  • 核心组件
    • ChatClient:模型调用客户端。
    • PromptTemplate:提示词模板。
    • AiServices:一种声明式创建AI服务接口的方式,可以用于构建Agent的核心决策函数。
    • Function Calling:支持将Java方法暴露为工具,供模型调用,这是构建Agent工具集的关键。
  • 实现模式:在Spring AI中构建一个Agent,你可能需要自己实现外层的执行循环控制器,但可以利用其FunctionCallback机制来方便地注册和管理工具。Spring的依赖注入和AOP特性,可以让你优雅地处理工具执行中的事务、日志、安全等问题。

选择Spring AI意味着你更看重与现有Java技术栈(如Spring Boot, Spring Security)的无缝集成、类型安全以及企业级特性(如监控、链路追踪)。它的学习曲线对于Spring开发者来说相对平缓。

4.3 轻量级自定义Runtime的实现要点

有时,使用全功能框架显得臃肿,或者你需要极致的控制和性能。这时,从零开始构建一个轻量级Runtime也是一个选择。核心组件如下:

  1. 状态管理类(StateManager):维护当前任务状态、记忆和上下文。
  2. 提示词组装器(ContextBuilder):负责根据当前状态,组装出符合LLM要求的消息列表(system, user, history)。
  3. LLM客户端封装(LLMClient):处理与不同模型API的通信、格式化请求、解析响应。
  4. 工具注册表(ToolRegistry):管理和调度所有可用工具。
  5. 主循环控制器(LoopController):实现上述伪代码逻辑,控制迭代、终止和错误处理。

在自定义实现中,最大的优势是透明度和灵活性。你可以精确控制每一步的日志、定制任何环节的逻辑(比如特殊的状态压缩策略)、并优化性能(比如并发执行多个不依赖的工具)。但代价是需要自己处理所有底层细节,包括连接池、重试、监控等“脏活累活”。

5. 实战:构建一个数据分析Agent的循环

让我们通过一个简化但完整的例子,将理论串联起来。目标是构建一个Agent,用户给它一个公司名称,它能自动获取该公司最近的股票价格,计算简单统计量(如近期平均价),并生成一段文字分析。

5.1 定义工具集

我们需要两个工具:

  1. get_stock_price(symbol: str, days: int) -> dict: 根据股票代码和天数,获取历史价格数据(假设调用一个金融数据API)。
  2. calculate_statistics(price_data: list) -> dict: 计算价格列表的平均值、标准差等。
# 工具实现示例 import requests import statistics def get_stock_price(symbol: str, days: int = 30): """获取股票历史价格。参数:symbol-股票代码,days-天数。""" # 模拟API调用 # 实际应使用yfinance、Alpha Vantage等库 try: # 这里返回模拟数据 mock_prices = [100 + i + random.uniform(-5,5) for i in range(days)] return {"status": "success", "result": {"symbol": symbol, "prices": mock_prices}} except Exception as e: return {"status": "error", "error": f"获取数据失败: {str(e)}"} def calculate_statistics(price_data: list): """计算价格数据的统计量。参数:price_data-价格列表。""" if not price_data: return {"status": "error", "error": "输入数据为空"} try: avg = statistics.mean(price_data) stdev = statistics.stdev(price_data) if len(price_data) > 1 else 0 return {"status": "success", "result": {"average": avg, "standard_deviation": stdev}} except Exception as e: return {"status": "error", "error": f"计算失败: {str(e)}"}

5.2 设计系统指令与循环

系统指令:

你是一个股票数据分析助手。你的目标是根据用户提供的公司名称或股票代码,获取其近期股价并进行分析。 你拥有以下工具: 1. get_stock_price: 用于获取股票历史价格。参数:symbol(字符串,股票代码),days(整数,默认30)。 2. calculate_statistics: 用于计算价格数据的统计量。参数:price_data(数字列表)。 你的工作流程必须是: 1. 首先,思考需要做什么。如果用户给了公司名,你需要先将其转换为股票代码(假设你知道映射,例如“苹果”->“AAPL”)。如果直接给了代码,则使用它。 2. 然后,使用get_stock_price工具获取数据。 3. 接着,使用calculate_statistics工具分析数据。 4. 最后,结合获取的数据和统计结果,用一段简洁的话向用户汇报,包括平均价格和波动性。 你必须严格按照以下JSON格式回应,只输出JSON,不要有其他任何文字: { "thought": "你的推理思考过程", "action": "工具名 或 FINAL_ANSWER", "action_input": "工具的参数(如果是对象请用JSON字符串)或给用户的最终回答" } 如果决定使用工具,`action`必须是工具名,`action_input`必须是符合工具要求的参数字符串。 如果任务完成,`action`必须是"FINAL_ANSWER"。

5.3 模拟执行循环

假设用户输入:“分析一下苹果公司最近一个月的股价。”

第一轮循环:

  • 状态:任务开始,记忆为空。
  • 构建上下文:包含系统指令、用户问题、工具描述。
  • LLM决策
    { "thought": "用户要求分析苹果公司股价。我需要先将‘苹果公司’映射为股票代码‘AAPL’,然后获取其最近30天的股价数据。", "action": "get_stock_price", "action_input": "{\"symbol\": \"AAPL\", \"days\": 30}" }
  • 执行工具:调用get_stock_price("AAPL", 30),成功返回价格列表。
  • 更新状态:将本次“行动”和“观察(价格数据)”存入记忆。

第二轮循环:

  • 构建上下文:包含系统指令、用户问题、第一轮的历史(行动+观察)、工具描述。
  • LLM决策
    { "thought": "我已经获取了AAPL过去30天的股价数据。下一步是使用calculate_statistics工具计算平均价格和标准差,以评估其表现和波动性。", "action": "calculate_statistics", "action_input": "[100.5, 101.2, 99.8, ...]" // 实际是上一轮观察中的数据 }
  • 执行工具:调用calculate_statistics,成功返回统计结果。
  • 更新状态:存入第二轮的行动和观察。

第三轮循环:

  • 构建上下文:包含所有历史。
  • LLM决策
    { "thought": "我已成功获取数据并完成了统计分析。平均价格约为102.5美元,标准差为3.2,表明近期有一定波动。现在可以生成最终答案了。", "action": "FINAL_ANSWER", "action_input": "根据过去30天的数据,苹果公司(AAPL)的平均股价约为102.5美元,价格波动(标准差)约为3.2美元,显示出温和的市场波动性。" }
  • 循环终止:检测到FINAL_ANSWER,循环结束,向用户返回最终答案。

这个简单的例子展示了状态如何随着循环演进,以及LLM如何根据包含历史动作和结果的上下文,做出连贯的下一步决策。

6. 高级模式与优化策略

当基础循环跑通后,我们可以探索更高级的模式来提升Agent的效率和能力。

6.1 规划-执行-反思(Plan-Act-Reflect)模式

这是对基础“思考-行动”循环的增强。在这个模式中,Agent不是走一步看一步,而是先制定一个初步计划(Plan),然后按计划执行(Act),并在执行过程中或结束后进行反思(Reflect),根据反思结果可能调整计划。

  • 规划阶段:LLM根据任务目标,生成一个步骤列表或一个高层次的任务分解。例如:“1. 搜索‘2024年电动汽车市场报告’;2. 从报告中提取关键数据点;3. 将数据整理成表格;4. 基于数据撰写总结。”
  • 执行阶段:按照计划步骤,依次或选择性地进入标准“思考-行动”子循环。
  • 反思阶段:在关键节点或任务完成后,LLM回顾已执行的动作和结果,评估是否偏离目标、是否有更优解、计划是否需要调整。反思的结果可以作为新的信息输入到后续的规划或执行中。

这种模式让Agent具备了更强的全局观和适应性,尤其适合复杂、多步骤的任务。实现难点在于如何设计有效的“反思”Prompt,让LLM能够进行有价值的自我评估。

6.2 多Agent协作与子任务分发

对于极其复杂的任务,可以引入多个具有不同专长的Agent进行协作。一个“管理Agent”(或“协调者”)负责接收用户请求,将其分解为子任务,然后分发给不同的“专家Agent”(如“搜索专家”、“数据分析专家”、“文案专家”)去执行,最后汇总结果。

  • 架构:这通常需要一个更上层的“编排层”(Orchestrator)来管理Agent间的通信和任务流。可以使用消息队列、工作流引擎或专门的框架(如CrewAI)来实现。
  • 通信:Agent之间如何传递信息和结果?通常通过共享的工作区(如一个共享的上下文存储或数据库)或直接的消息传递。
  • 挑战:协调逻辑复杂,调试困难,且可能增加延迟。需要精心设计Agent的职责边界和交互协议,避免循环依赖或通信死锁。

6.3 效率优化:并行、缓存与流式输出

  • 并行工具执行:如果多个工具调用之间没有数据依赖关系,可以在同一轮“思考”后并行执行它们,显著减少总耗时。例如,一个Agent需要同时获取天气、新闻和股票信息,这三个工具调用可以并行。
  • 结果缓存:对于耗时的工具调用(如复杂计算、网络请求),且结果在一定时间内有效,可以引入缓存机制。将(工具名+参数哈希)作为键,缓存结果。下次遇到相同请求时直接返回缓存,避免重复计算或调用。
  • 流式输出(Streaming):对于生成最终答案较长的任务,可以采用流式输出,让LLM一边思考一边生成部分答案,或者让Agent在完成一个子任务后就即时输出部分结果,提升用户体验的响应感。这需要Runtime支持中间结果的输出和状态保持。

7. 开发与调试心法

构建和调试Agent是一个迭代过程。以下是一些血泪教训换来的经验:

7.1 可观测性是生命线

你必须能清晰地看到Agent内部发生了什么。至少要实现以下日志:

  • 每轮循环的完整上下文(输入给LLM的提示词)。
  • LLM的原始响应和解析后的决策
  • 工具调用的参数和返回结果(敏感信息可脱敏)。
  • Agent的完整状态变迁历史

将这些日志结构化地输出到控制台或日志系统,并考虑可视化工具(如LangSmith, Weights & Biases的Prompts工具)。当Agent行为异常时,第一步永远是查看最近一轮或几轮的完整日志,问题往往出在Prompt的歧义、工具描述的模糊或LLM输出的格式偏差上。

7.2 测试策略:从单元到集成

  • 工具单元测试:确保每个工具函数在各种边界条件下都能正确工作并返回结构化结果。
  • 决策解析测试:用大量精心设计的Prompt和模拟的LLM响应,测试你的解析逻辑是否健壮,能否处理各种奇怪的LLM输出(比如多了一段解释文字)。
  • 单轮循环测试:给定一个固定状态,测试Agent是否能做出预期的决策。
  • 端到端集成测试:用代表性的用户任务进行测试,关注最终结果的质量和整个执行过程的稳定性(是否死循环、是否调用了不该调的工具)。

7.3 应对LLM的“不稳定性”

LLM本质上是概率模型,其输出具有不确定性。这会导致Agent行为偶尔“抽风”。缓解策略包括:

  • 温度(Temperature)设置:在决策循环中,通常使用较低的温度(如0.1或0),以减少随机性,使输出更确定、更可预测。
  • 重试与回退:当LLM输出无法解析或明显不合理时,可以尝试用修正性的Prompt(如“你刚才的响应格式不正确,请严格按照要求输出JSON”)重试一次。如果多次失败,则回退到安全操作(如终止任务并报错)。
  • 后处理校验:在解析LLM的决策后,增加业务逻辑校验。例如,检查要调用的工具是否真的存在,参数类型是否大致匹配。这可以作为一道安全防线。

构建一个稳定、可靠的Agent执行循环,就像在训练一位新员工。你需要给它清晰的指令(Prompt)、好用的工具、明确的工作流程(循环逻辑),并时刻观察它的工作过程(日志),及时纠正它的错误(错误处理与调试)。这个过程没有银弹,需要大量的迭代、测试和对细节的耐心打磨。但当你看到它能够自动、连贯地完成一个复杂任务时,那种成就感是无与伦比的。希望这篇长文能为你点亮Agent开发之路上的几盏灯,少走一些我当年走过的弯路。

← 返回列表