1. 为什么“提示词玄学”是Agent优化的死胡同
我见过太多团队在Agent项目上栽跟头,栽的方式还出奇一致:第一版Demo跑通之后效果不理想,于是所有人围在屏幕前开始改提示词。加一句“请仔细思考”,不行;再加一句“你是一个专业的XX专家”,还是不行;换个说法“如果遇到不确定的情况请先询问用户”,结果Agent变得畏首畏尾什么都不敢做。折腾两三天,效果时好时坏,最后得出结论——“提示词工程是玄学”。
这个场景你一定不陌生。Agent开发走到2024、2025年,提示词工程已经被过度神化了。打开任何一个技术社区,满屏都是“鹈鹕骑自行车提示词怎么写”“鹈鹕测试提示词”这类内容,仿佛只要找到那句神奇的咒语,Agent就能从智障变成天才。但真实情况是:一个Agent系统的表现,提示词能解释的方差通常不超过20%,剩下80%取决于工具接口设计、控制逻辑编排和记忆管理机制。
这篇文章想聊的就是那80%。我会从Agent的整体架构设计讲起,拆解工具接口怎么定义才合理、控制逻辑怎么编排才稳定、自动课程学习怎么让Agent持续进化,最后给出一套可以直接抄作业的实操方案。不管你是刚接触Agent开发的新手,还是已经踩过几轮坑的老手,应该都能从中找到一些能立刻用上的东西。
核心观点提前说:提示词是Agent的“用户手册”,不是“大脑”。你不可能靠一本写得更漂亮的手册让一台机器变得更聪明。
2. Agent系统整体设计与思路拆解
2.1 从“提示词驱动”转向“架构驱动”的思维转变
大部分Agent项目的第一版架构是这样的:一个System Prompt定义角色和行为规范,几个工具函数注册进去,然后让模型自己决定什么时候调用什么工具。这个架构在Demo阶段没问题,但一旦任务复杂度上来,就会暴露三个致命问题。
第一个问题是工具选择的歧义性。假设你给Agent注册了search和query_database两个工具,当用户问“帮我查一下最近的销售数据”时,模型可能选search也可能选query_database,因为从语义上两者都说得通。你可以在提示词里写“查询结构化数据时使用query_database”,但模型并不总能准确判断什么是“结构化数据”。
第二个问题是控制流的不可预测性。Agent可能陷入循环调用、可能跳过关键步骤、可能在某个中间状态卡死。你没法用提示词保证它“一定先做A再做B”,因为提示词是软约束,不是硬逻辑。
第三个问题是状态管理的缺失。多轮对话之后,Agent可能忘记之前执行过什么操作、得到了什么结果。你可以在提示词里塞入历史记录,但上下文窗口是有限的,塞得越多,模型对关键信息的注意力越分散。
所以我的核心设计思路是:把Agent系统当成一个软件系统来设计,而不是当成一个聊天机器人来调教。提示词只负责语义理解和自然语言生成这两件事,其余的控制逻辑、状态管理、工具路由全部用代码来实现。
2.2 分层架构:把“聪明”留给模型,把“可靠”交给代码
基于上面的思路,我通常会把Agent系统拆成四层:
| 层级 | 职责 | 实现方式 |
|---|---|---|
| 意图理解层 | 解析用户输入,提取结构化意图 | LLM + 结构化输出 |
| 任务规划层 | 将意图拆解为可执行的步骤序列 | 代码编排 + LLM辅助 |
| 工具执行层 | 调用具体工具,处理返回结果 | 纯代码实现 |
| 状态管理层 | 维护对话历史、任务状态、中间结果 | 代码 + 持久化存储 |
这个分层的关键在于:LLM只在意图理解层和任务规划层的部分环节发挥作用,工具执行和状态管理完全由代码控制。这样做的好处是,系统的行为变得可预测、可测试、可调试。你可以对工具执行层写单元测试,可以对状态管理层做快照和回滚,而这些都是纯提示词方案做不到的。
2.3 工具接口设计:Agent能力的真正边界
很多人把工具接口当成一个简单的函数注册,觉得只要把API包一层就行了。但实际上,工具接口的设计质量直接决定了Agent的能力上限。一个设计糟糕的工具接口,再强的模型也用不好;一个设计精良的工具接口,中等模型也能发挥出不错的水平。
我举个例子来说明。假设你要给Agent一个“发送邮件”的能力,最直觉的做法是定义一个send_email(to, subject, body)函数。但这样定义有几个问题:模型需要自己判断什么时候该发邮件、需要自己生成邮件内容、需要自己决定收件人。这些决策分散在模型的推理过程中,每一步都可能出错。
更好的做法是把“发送邮件”拆成更细粒度的工具:draft_email(intent, recipient_hint)负责根据意图生成邮件草稿,confirm_email(draft_id)负责确认发送,send_email(draft_id)负责实际发送。这样每个工具的职责单一、输入输出明确,模型只需要做“选择哪个工具”这一个决策,而不是把多个决策揉在一起。
实操心得:工具接口的粒度应该“刚好让模型不需要做额外推理就能选择”。太粗,模型需要自己拆解;太细,模型需要自己编排。找到这个平衡点需要反复测试,但一旦找到,效果提升非常明显。
3. 核心细节解析与实操要点
3.1 工具接口定义的五个关键原则
在多个Agent项目中反复迭代之后,我总结了工具接口设计的五个原则,按重要性排序:
原则一:单一职责。每个工具只做一件事,工具名称应该是一个动词短语,能准确描述它的功能。避免出现handle_user_request这种模糊的工具名,模型看到这个名字根本不知道什么时候该用它。
原则二:参数自描述。每个参数的类型、含义、取值范围都要在定义中明确说明。不要用data、input这种泛泛的参数名,要用user_query、date_range这种一看就懂的名字。参数描述要写清楚“什么时候该传什么值”,而不是只写“用户输入”。
原则三:返回值结构化。工具返回的结果应该是结构化的JSON,而不是一段自然语言文本。结构化返回值让后续的控制逻辑可以基于字段做判断,而不是去解析文本。比如返回{"status": "success", "count": 42, "items": [...]}就比返回“查询成功,共找到42条记录”要好得多。
原则四:错误信息可操作。当工具执行失败时,返回的错误信息应该包含足够的信息让模型或代码决定下一步怎么做。{"error": "not_found", "suggestion": "try_search_instead"}就比{"error": "查询失败"}有用得多。
原则五:幂等性。对于查询类工具,要保证多次调用结果一致;对于写入类工具,要提供幂等键或者去重机制。Agent可能会因为各种原因重复调用同一个工具,幂等性可以避免重复操作带来的副作用。
下面是一个工具定义的示例,展示了上述原则的实际应用:
tools = [ { "name": "search_knowledge_base", "description": "在内部知识库中搜索相关文档。当用户询问产品功能、操作流程、常见问题时使用此工具。", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "搜索关键词,应该是用户问题的核心概念,不要直接传用户原话" }, "category": { "type": "string", "enum": ["product", "troubleshooting", "billing", "general"], "description": "文档分类,根据用户问题类型选择" }, "max_results": { "type": "integer", "default": 5, "description": "返回结果数量,默认5条" } }, "required": ["query"] } } ]3.2 控制逻辑编排:用代码保证确定性
控制逻辑是Agent系统中最容易被忽视、但影响最大的部分。很多人把所有控制逻辑都塞进提示词里,比如“如果用户问的是A类问题,先调用工具X,然后根据结果决定是否调用工具Y”。这种做法的问题在于,LLM对条件逻辑的执行并不稳定,尤其是当条件嵌套多层时。
我的做法是把控制逻辑从提示词中抽离出来,用代码实现一个状态机。每个状态定义明确的入口条件、执行动作和出口条件,状态之间的转移由代码控制,LLM只在需要做语义判断的节点参与。
class AgentStateMachine: def __init__(self): self.state = "idle" self.context = {} def transition(self, user_input): if self.state == "idle": intent = self.parse_intent(user_input) self.context["intent"] = intent self.state = "routing" if self.state == "routing": if self.context["intent"]["type"] == "query": self.state = "searching" elif self.context["intent"]["type"] == "action": self.state = "planning" if self.state == "searching": results = self.execute_search(self.context["intent"]) if results["count"] > 0: self.state = "responding" else: self.state = "fallback" # ... 其余状态转移逻辑这个状态机的核心价值在于:它把“什么时候该做什么”这个决策从LLM的推理过程中剥离出来,变成了确定性的代码逻辑。LLM只需要在每个状态内部完成它擅长的事情——理解语义、生成文本,而不需要同时管理整个流程。
3.3 记忆管理:让Agent不再“失忆”
Agent的记忆问题经常被简化为“把历史对话塞进上下文”,但实际上面临三个挑战:上下文窗口有限、关键信息淹没在噪声中、跨会话状态无法保持。
我的解决方案是分层记忆:
- 工作记忆:当前对话轮次的相关信息,直接放在上下文中,容量小但访问快。
- 短期记忆:最近N轮对话的摘要,用LLM压缩成关键信息,减少token占用。
- 长期记忆:持久化的用户偏好、历史任务记录,存储在外部数据库中,需要时通过检索召回。
class MemoryManager: def __init__(self, max_working_tokens=2000): self.working_memory = [] self.short_term_summary = "" self.long_term_store = VectorStore() def add_interaction(self, user_input, agent_output): self.working_memory.append({ "user": user_input, "agent": agent_output }) if self.count_tokens(self.working_memory) > self.max_working_tokens: self.compress_to_short_term() def compress_to_short_term(self): # 用LLM将工作记忆压缩为摘要 summary = llm.summarize(self.working_memory) self.short_term_summary = summary self.working_memory = self.working_memory[-2:] # 保留最近两轮 def recall(self, query): # 从长期记忆中检索相关信息 return self.long_term_store.search(query, top_k=3)注意事项:压缩记忆时一定要保留“任务状态”相关的信息,比如“用户正在办理退款”“已经确认了订单号”。这些信息一旦丢失,Agent就会重复询问用户已经提供过的信息,体验极差。
4. 实操过程与核心环节实现
4.1 从零搭建一个可调试的Agent框架
这一节我会给出一个完整的、可以直接运行的Agent框架实现。代码基于Python,核心依赖只有LLM的API接口,不依赖任何特定的Agent框架。这样做的好处是你可以完全掌控每一行代码,出了问题知道去哪里找。
先定义核心数据结构:
from dataclasses import dataclass, field from typing import Any, Callable import json @dataclass class Tool: name: str description: str parameters: dict function: Callable def to_schema(self): return { "name": self.name, "description": self.description, "parameters": self.parameters } @dataclass class AgentContext: messages: list = field(default_factory=list) task_state: dict = field(default_factory=dict) tool_results: list = field(default_factory=list) max_iterations: int = 10然后是Agent的核心执行循环:
class Agent: def __init__(self, llm_client, tools: list[Tool], system_prompt: str): self.llm = llm_client self.tools = {t.name: t for t in tools} self.system_prompt = system_prompt def run(self, user_input: str, context: AgentContext) -> str: context.messages.append({"role": "user", "content": user_input}) for i in range(context.max_iterations): response = self.llm.chat( system=self.system_prompt, messages=context.messages, tools=[t.to_schema() for t in self.tools.values()] ) if response.has_tool_call(): tool_call = response.tool_call result = self.execute_tool(tool_call) context.tool_results.append(result) context.messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False) }) else: context.messages.append({ "role": "assistant", "content": response.content }) return response.content return "任务执行超过最大迭代次数,请检查工具调用逻辑。" def execute_tool(self, tool_call) -> dict: tool = self.tools.get(tool_call.name) if not tool: return {"error": "unknown_tool", "message": f"工具 {tool_call.name} 不存在"} try: result = tool.function(**tool_call.arguments) return {"status": "success", "data": result} except Exception as e: return {"status": "error", "message": str(e), "tool": tool_call.name}这个框架虽然简单,但已经包含了Agent系统的核心要素:工具注册、工具调用、结果回传、迭代控制。你可以在此基础上逐步添加状态管理、记忆压缩、日志追踪等功能。
4.2 工具接口的注册与参数校验
工具注册不是简单地把函数塞进字典就完事了。每个工具在注册时都应该做参数校验,确保模型传入的参数符合预期。我通常会用Pydantic来做这件事:
from pydantic import BaseModel, Field, validator class SearchParams(BaseModel): query: str = Field(..., min_length=1, max_length=200) category: str = Field(default="general") max_results: int = Field(default=5, ge=1, le=20) @validator("category") def validate_category(cls, v): allowed = ["product", "troubleshooting", "billing", "general"] if v not in allowed: raise ValueError(f"category 必须是 {allowed} 之一") return v def search_knowledge_base(query: str, category: str = "general", max_results: int = 5): params = SearchParams(query=query, category=category, max_results=max_results) # 实际搜索逻辑 results = vector_store.search(params.query, top_k=params.max_results) return {"count": len(results), "items": results}这样做的好处是:当模型传入了不合法的参数时,会在工具执行前就被拦截,返回明确的错误信息,而不是让错误渗透到业务逻辑中。
4.3 控制逻辑的代码实现:一个完整的任务编排示例
假设我们要实现一个“客服工单处理”的Agent,流程是:理解用户问题 → 查询知识库 → 如果知识库有答案则直接回复 → 如果没有则创建工单 → 通知用户工单号。
用状态机来实现:
class TicketAgent: def __init__(self, llm, knowledge_base, ticket_system): self.llm = llm self.kb = knowledge_base self.tickets = ticket_system self.states = { "understand": self.understand_issue, "search_kb": self.search_knowledge, "respond": self.generate_response, "create_ticket": self.create_ticket, "notify": self.notify_user } def process(self, user_input: str) -> str: context = {"user_input": user_input, "state": "understand"} while context["state"] != "done": handler = self.states[context["state"]] context = handler(context) return context["final_response"] def understand_issue(self, ctx): intent = self.llm.extract_intent(ctx["user_input"]) ctx["intent"] = intent ctx["state"] = "search_kb" return ctx def search_knowledge(self, ctx): results = self.kb.search(ctx["intent"]["query"]) ctx["kb_results"] = results if results["count"] > 0: ctx["state"] = "respond" else: ctx["state"] = "create_ticket" return ctx def generate_response(self, ctx): answer = self.llm.generate( f"基于以下知识库内容回答用户问题:\n{ctx['kb_results']}\n\n用户问题:{ctx['user_input']}" ) ctx["final_response"] = answer ctx["state"] = "done" return ctx def create_ticket(self, ctx): ticket = self.tickets.create( title=ctx["intent"]["summary"], description=ctx["user_input"], priority=ctx["intent"].get("priority", "normal") ) ctx["ticket"] = ticket ctx["state"] = "notify" return ctx def notify_user(self, ctx): ctx["final_response"] = ( f"您的问题已记录,工单号为 {ctx['ticket']['id']}," f"我们会在24小时内处理。" ) ctx["state"] = "done" return ctx这个实现的关键点是:每个状态的职责单一,状态之间的转移条件明确,LLM只在需要语义理解的地方参与。整个流程是确定性的,你可以对每个状态单独写测试,也可以很容易地添加新的状态或修改转移逻辑。
4.4 自动课程学习:让Agent在运行中持续进化
“自动课程学习”这个词听起来很学术,但落到Agent开发中,它的核心思想很简单:让Agent从自己的执行历史中学习,自动发现薄弱环节并针对性改进。
具体怎么做?我的做法是建立一个“执行日志分析”管道:
- 记录每次执行的完整轨迹:用户输入、Agent的每一步决策、工具调用参数、工具返回结果、最终输出。
- 自动标注失败案例:通过规则(如工具调用报错、用户负面反馈、任务超时)自动标记失败案例。
- 聚类分析失败模式:将失败案例按失败原因聚类,找出高频失败模式。
- 生成改进建议:针对每种失败模式,自动生成提示词调整建议或工具接口优化建议。
class ExecutionAnalyzer: def __init__(self, log_store): self.logs = log_store def analyze_failures(self, time_range): failures = self.logs.query(status="failed", time_range=time_range) # 按失败类型聚类 clusters = {} for f in failures: key = self.classify_failure(f) clusters.setdefault(key, []).append(f) # 生成改进建议 suggestions = [] for key, cases in clusters.items(): if len(cases) < 3: continue suggestion = self.generate_suggestion(key, cases) suggestions.append(suggestion) return suggestions def classify_failure(self, log): if log["error_type"] == "tool_not_found": return "tool_selection_error" elif log["error_type"] == "invalid_arguments": return "parameter_error" elif log["iterations"] >= log["max_iterations"]: return "infinite_loop" elif log["user_feedback"] == "negative": return "quality_issue" return "unknown"这个分析管道跑一段时间之后,你会得到一份“Agent薄弱环节报告”,比如“30%的失败是因为模型在查询类任务中错误选择了写入类工具”。针对这个问题,你可以调整工具描述、增加路由规则、或者在提示词中增加示例。这种基于数据的优化,比拍脑袋改提示词有效得多。
5. 常见问题与排查技巧实录
5.1 Agent反复调用同一个工具怎么办
这是最常见的问题之一。Agent在某个状态下反复调用同一个工具,每次得到相似的结果,但就是不走下一步。排查思路如下:
首先检查工具的返回值是否包含足够的信息让模型判断“下一步该做什么”。如果工具返回的是空结果或者模糊的结果,模型可能会认为“还没完成”而继续调用。解决方法是让工具在返回结果时明确标注状态,比如{"status": "completed", "data": ...}或{"status": "empty", "suggestion": "no_more_data"}。
其次检查控制逻辑是否有明确的退出条件。如果完全依赖模型自己判断“什么时候停止”,那它可能会一直调用下去。我的做法是在代码层面设置最大迭代次数,并且在达到上限时强制退出并返回当前状态。
最后检查提示词中是否有“必须调用工具”的硬性要求。有些提示词会写“你必须使用工具来回答问题”,这会导致模型在不需要工具的时候也强行调用。改成“如果需要外部信息,可以使用工具”会好很多。
5.2 工具调用参数错误的排查方法
模型传错参数是另一个高频问题。常见的原因和解决方法:
| 错误类型 | 典型表现 | 解决方法 |
|---|---|---|
| 参数名错误 | 传了search_query但工具定义的是query | 在工具描述中明确参数名,增加示例 |
| 参数类型错误 | 传了字符串"5"但期望整数5 | 在参数定义中写明类型,代码层做类型转换 |
| 缺少必填参数 | 没有传required中列出的参数 | 在工具描述中强调必填参数,代码层做校验 |
| 参数值超出范围 | 传了max_results=100但上限是20 | 在参数描述中写明取值范围,代码层做截断 |
实操心得:在工具描述中加一个“调用示例”字段,展示一个完整的参数JSON,能显著降低参数错误率。模型看到具体示例比看到抽象描述更容易理解。
5.3 多轮对话中状态丢失的修复方案
多轮对话中Agent忘记之前说过什么,通常是因为上下文管理有问题。排查步骤:
第一步,确认历史消息是否完整地传给了LLM。有些框架会自动截断历史消息,导致关键信息丢失。检查你的消息列表是否包含了所有必要的轮次。
第二步,确认关键信息是否被淹没在噪声中。如果历史消息很长,模型可能忽略中间部分的内容。解决方法是在每轮对话开始时,把关键状态信息以结构化格式放在消息列表的最前面。
第三步,确认跨会话状态是否持久化。如果用户关闭页面再打开,Agent是否还记得之前的对话?这需要把状态存储到外部数据库,并在新会话开始时加载。
def build_messages(context): messages = [] # 关键状态放在最前面 if context.task_state: state_summary = format_state(context.task_state) messages.append({ "role": "system", "content": f"当前任务状态:{state_summary}" }) # 然后是历史对话 messages.extend(context.messages[-10:]) # 只保留最近10轮 return messages5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 | 解决手段 |
|---|---|---|---|
| Agent不调用任何工具 | 提示词过于保守 | 检查是否有“尽量直接回答”的表述 | 改为“需要外部信息时使用工具” |
| Agent调用错误工具 | 工具描述有歧义 | 对比工具描述的重叠部分 | 细化描述,增加使用场景说明 |
| 工具调用超时 | 工具执行时间过长 | 检查工具内部逻辑 | 增加超时设置,异步化处理 |
| 输出格式不符合预期 | 缺少格式约束 | 检查提示词中的格式要求 | 增加结构化输出示例 |
| 多轮后效果下降 | 上下文过长 | 检查消息列表长度 | 压缩历史,保留关键状态 |
| 并发请求互相干扰 | 状态未隔离 | 检查是否有全局变量 | 每个请求独立上下文 |
6. 从“能用”到“好用”的进阶思路
6.1 建立Agent的评估体系
没有评估就没有优化。很多团队改提示词全靠感觉,改完也不知道是变好了还是变差了。我的做法是建立一套自动化的评估管道:
准备一个测试集,包含50-100个典型用户请求,每个请求标注期望的工具调用序列和期望的输出要点。每次修改提示词或工具接口后,自动跑一遍测试集,计算工具选择准确率、参数正确率、任务完成率等指标。
class AgentEvaluator: def __init__(self, agent, test_cases): self.agent = agent self.test_cases = test_cases def evaluate(self): results = { "tool_selection_accuracy": 0, "parameter_accuracy": 0, "task_completion_rate": 0, "avg_iterations": 0 } for case in self.test_cases: context = AgentContext() output = self.agent.run(case["input"], context) # 检查工具调用序列 actual_tools = [r["tool"] for r in context.tool_results] expected_tools = case["expected_tools"] if actual_tools == expected_tools: results["tool_selection_accuracy"] += 1 # 检查任务是否完成 if case["completion_check"](output): results["task_completion_rate"] += 1 results["avg_iterations"] += len(context.tool_results) n = len(self.test_cases) for key in results: results[key] = results[key] / n if key != "avg_iterations" else results[key] / n return results这套评估体系的价值在于:它把“Agent好不好用”这个模糊的问题,变成了几个可以量化的指标。你可以清楚地看到每次修改带来的影响,而不是凭感觉判断。
6.2 工具接口的版本管理与灰度发布
当Agent系统上线之后,工具接口的修改需要格外小心。一个看似无害的描述修改,可能导致模型的行为发生巨大变化。我的做法是:
- 每个工具接口都有版本号,修改后版本号递增。
- 新版本先在测试环境跑评估,确认指标不下降后再上线。
- 上线时采用灰度策略,先让10%的流量走新版本,观察一段时间后再全量。
class ToolRegistry: def __init__(self): self.tools = {} self.versions = {} def register(self, tool: Tool, version: str = "v1"): key = f"{tool.name}:{version}" self.tools[key] = tool self.versions.setdefault(tool.name, []).append(version) def get_active_tools(self, rollout_config): active = [] for name, versions in self.versions.items(): latest = versions[-1] if rollout_config.get(name, {}).get("enabled", True): active.append(self.tools[f"{name}:{latest}"]) return active6.3 日志与可观测性建设
Agent系统的调试难度远高于传统软件,因为它的行为不是完全确定的。完善的日志系统是排查问题的前提。我通常会在以下几个关键节点打日志:
- 用户输入进入时:记录原始输入和时间戳。
- 每次LLM调用前后:记录请求的messages、返回的tool_calls或content。
- 每次工具调用前后:记录工具名、参数、返回值、耗时。
- 状态转移时:记录从哪个状态转移到哪个状态、触发条件是什么。
- 最终输出时:记录完整输出和总耗时。
这些日志不仅用于排查问题,也是自动课程学习的数据来源。日志格式建议用结构化的JSON,方便后续分析和可视化。
import logging import json import time logger = logging.getLogger("agent") def log_event(event_type, data): logger.info(json.dumps({ "timestamp": time.time(), "event": event_type, "data": data }, ensure_ascii=False)) # 使用示例 log_event("tool_call", { "tool": "search_knowledge_base", "arguments": {"query": "退款流程", "category": "billing"}, "result_count": 3, "duration_ms": 245 })7. 一些踩坑之后的真实体会
做Agent开发这两年,最大的体会就是:不要试图用提示词解决所有问题。提示词能解决的是“模型不知道该怎么表达”的问题,解决不了“模型不知道该做什么”的问题。后者需要靠架构设计、工具接口、控制逻辑来解决。
另一个体会是:Agent系统的优化是一个系统工程,不是单点突破。你改了一个工具的描述,可能会影响模型对其他工具的选择;你调整了控制逻辑,可能会影响提示词的效果。所以每次修改都要跑评估,用数据说话,而不是凭感觉。
还有一个很实际的建议:尽早建立评估体系。我见过太多团队在项目后期才发现效果不稳定,但那时候已经积累了大量提示词修改,根本不知道哪个修改是有效的、哪个是无效的。如果一开始就有评估体系,每次修改都能看到明确的指标变化,优化效率会高很多。
最后说一个关于“自动课程学习”的观察。这个概念听起来很美好,但落地的时候要注意:自动学习的前提是自动评估。如果你不能自动判断一次执行是成功还是失败,那就没法自动学习。所以先把评估体系建起来,再考虑自动课程学习,顺序不能反。
一个实用的小技巧:在Agent的System Prompt最后加一句“如果你不确定该怎么做,请先说明你的困惑,而不是猜测”。这句话能显著减少Agent在不确定情况下的胡乱操作,虽然简单,但实测有效。