
1. 从 Prompt 到 Agent一次认知范式的迁移1.1 为什么“会聊天”不等于“能干活”2023 年那会儿大多数人用大模型的姿势还是“对话框里敲一段话等它吐一段字”。那时候我们管这叫 Prompt Engineering核心技巧无非是角色设定、少样本示例、思维链引导。但很快大家就发现一个尴尬的事实模型能写诗、能编故事、能解释概念可你让它帮你订个会议室、查一下库存、把一份 PDF 里的表格提取出来填进数据库它就抓瞎了。问题出在哪出在大模型本质上是一个“无状态的无手大脑”。它没有记忆关掉对话就忘光它没有手脚不能调用任何外部系统它没有持续的目标感你问一句它答一句你不问它就停在那。这三点决定了纯 Prompt 交互只能停留在“信息加工”层面无法完成“任务执行”。AI Agent 要解决的就是这个问题。所谓 Agent拆开看就是Brain模型 Memory记忆 Tools工具 Planning规划四件套。模型负责推理决策记忆负责跨轮次保持上下文工具负责与外部世界交互规划负责把一个大目标拆成可执行的步骤。这四者缺一不可少了任何一个Agent 就退化成聊天机器人。我个人的判断标准很简单如果一个系统只能根据当前输入产生输出那它是 Prompt如果它能根据目标自主决定下一步做什么、调用什么、记住什么那它才是 Agent。这个分界线看起来模糊但在实际搭建中非常关键因为它直接决定了你的架构复杂度。1.2 演进路线从单轮问答到自主循环把 AI Agent 的演进拉成一条时间线大致可以分成四个阶段每个阶段解决的核心矛盾不同。第一阶段纯 Prompt 时代。用户输入 → 模型输出一问一答。这个阶段的关键词是“提示词技巧”大家比拼的是谁的 Prompt 写得更精准。但天花板很明显模型的知识截止于训练数据无法获取实时信息也无法执行任何操作。第二阶段Prompt Tool 时代。以 Function Calling 为代表模型可以输出结构化的工具调用请求由外部代码执行后把结果喂回模型。这一下子打开了局面——能查天气了、能搜网页了、能操作数据库了。但问题也随之而来多轮工具调用时上下文迅速膨胀模型容易“忘记”最初的目标工具调用失败后缺乏重试机制整个流程还是线性的没有真正的“自主决策”。第三阶段Prompt Tool Memory 时代。引入短期记忆对话历史和长期记忆向量数据库让 Agent 能在多轮交互中保持连贯性。这个阶段解决的是“上下文窗口不够用”和“跨会话失忆”的问题。但新的矛盾出现了记忆越多检索越慢而且容易检索到不相关的噪声反而干扰模型判断。第四阶段自主 Agent 时代。以 LangGraph、AutoGPT 这类框架为代表Agent 具备了任务规划、自我反思、循环执行的能力。它能自己拆解目标、选择工具、评估结果、决定是否继续或重试。这个阶段的核心挑战从“能不能做”变成了“怎么做得稳、做得省、做得可控”。注意很多团队在第二阶段就卡住了以为接了几个 API 就是 Agent。实际上没有记忆管理和规划能力的系统在复杂任务面前会迅速暴露出“金鱼记忆”和“无头苍蝇”两个致命问题。1.3 一个真实场景为什么我决定从 Prompt 转向 Agent去年我接手一个需求帮运营团队做一个“竞品动态日报”的自动化工具。最初的想法很简单写个 Prompt 让模型总结一下抓取到的新闻就行了。但实际跑起来发现几个问题第一新闻源有十几个格式各异需要分别抓取和清洗第二有些新闻需要对比历史数据才能判断是否“重要”第三日报需要按固定模板输出还要附带数据来源链接。纯 Prompt 方案根本搞不定。你不可能把所有新闻原文塞进一个 Prompt 里——上下文长度不允许成本也扛不住。于是被迫转向 Agent 架构用工具去抓取和清洗用记忆存储历史数据用规划模块决定哪些新闻值得深入分析最后用模板工具生成日报。这套东西搭下来我才真正理解了 Agent 各个组件存在的意义——它们不是炫技而是被真实需求逼出来的。2. 核心组件拆解Brain、Memory、Tool、Planning 到底怎么配合2.1 Brain 层模型选型与推理策略Brain 层就是大模型本身但选型不是“哪个最强用哪个”这么简单。实际搭建中要考虑三个维度推理能力、响应延迟、调用成本。推理能力决定了 Agent 能不能正确处理复杂任务。比如需要多步推理的场景先查 A 再根据 A 的结果决定是否查 B弱模型很容易在中间步骤跑偏。我实测下来在工具调用场景中模型对 JSON Schema 的理解能力比单纯的文本生成能力更重要——它得准确输出工具名和参数格式错一点整个流程就断了。延迟和成本是工程上绕不开的。一个 Agent 任务可能涉及 5 到 10 次模型调用如果每次都用最大最强的模型成本会迅速失控。我的做法是分层用模型规划层用强模型因为它决定了整个任务的方向执行层用轻量模型工具调用和结果解析对推理要求没那么高总结层再用强模型。这样能在质量和成本之间找到一个平衡点。还有一个容易被忽略的点模型的上下文窗口管理。热词里有个报错很典型——“context is too large and auto-compaction could not recover this”。这就是上下文爆了。Agent 跑多轮之后历史消息、工具返回结果、中间推理过程全堆在上下文里很快就会撑满。解决办法不是简单截断会丢关键信息而是要有选择地压缩和摘要。我通常会在上下文用到 70% 左右时触发一次摘要把早期的工具调用结果压缩成简短结论保留关键决策点。2.2 Memory 层短期记忆与长期记忆的分工Memory 是 Agent 最容易被低估的组件。很多人觉得“记忆”就是把对话历史存下来下次带上就行了。但实际远不止这么简单。短期记忆负责当前会话内的上下文连贯性。它的核心挑战是“在有限的上下文窗口里保留最有用的信息”。我的经验是不要把所有历史消息原封不动地塞回去而是要做相关性过滤——只保留与当前任务相关的消息无关的闲聊和已完成的子任务可以压缩掉。长期记忆负责跨会话的知识积累。比如一个客服 Agent它需要记住每个用户的历史问题和偏好一个研究 Agent它需要记住之前查过的资料和结论。长期记忆通常用向量数据库实现把信息 embedding 后存储需要时通过相似度检索召回。但这里有个大坑记忆污染。热词里提到的 “agentpoison: red-teaming llm agents via poisoning memory” 说的就是这个事。如果长期记忆里被写入了错误或恶意的信息Agent 在后续决策中会持续被误导。我的做法是写入长期记忆前做一次校验比如让模型判断这条信息是否值得记住、是否与已有记忆冲突读取时做一次相关性排序不要把所有召回的记忆都塞给模型只给最相关的几条。记忆类型存储介质生命周期典型用途主要风险短期记忆内存/Redis单次会话对话连贯性上下文溢出长期记忆向量数据库持久化知识积累、个性化记忆污染、检索噪声工作记忆变量/状态对象单次任务中间结果暂存状态丢失2.3 Tool 层让 Agent 真正“有手”Tool 是 Agent 与外部世界交互的桥梁。没有 ToolAgent 就是一个被困在对话框里的囚徒。但 Tool 的设计有很多讲究不是随便包个 API 就完事。工具粒度是第一个要思考的问题。粒度太粗比如一个“处理订单”的工具内部逻辑复杂模型很难准确调用粒度太细比如“查询数据库”“格式化结果”“发送邮件”拆成三个工具模型需要多轮调用才能完成一个简单任务效率和成本都上去了。我的经验是一个工具对应一个原子操作但这个原子操作的边界要清晰且自包含。比如“根据订单号查询订单状态”就是一个好工具输入明确、输出明确、不需要额外上下文。工具描述是第二个关键点。模型选择工具完全依赖描述文本描述写得含糊模型就会选错工具或者传错参数。我见过太多团队在工具描述上偷懒就写一句“查询订单”结果模型根本不知道要传什么参数、返回什么格式。好的工具描述应该包含功能说明、参数含义和类型、返回值格式、使用场景示例。这本质上是在给模型写 Prompt只不过这个 Prompt 是用来选工具的。错误处理是第三个容易被忽略的点。工具调用失败是常态——网络超时、参数错误、权限不足、返回格式异常。如果 Agent 没有错误处理机制一次失败就整个流程崩溃。我的做法是在工具层做一层包装捕获异常后返回结构化的错误信息错误类型、错误原因、建议的重试方式让模型根据错误信息决定是重试、换工具还是放弃。# 工具定义示例以查询订单为例 order_query_tool { name: query_order_status, description: 根据订单号查询订单的当前状态。适用于用户询问订单进度、物流信息的场景。, parameters: { type: object, properties: { order_id: { type: string, description: 订单号格式为 ORD- 开头的 12 位字符串 } }, required: [order_id] }, returns: { status: 订单状态pending/shipped/delivered/cancelled, update_time: 最后更新时间, tracking_info: 物流信息如有 } }2.4 Planning 层从“走一步看一步”到“谋定而后动”Planning 是 Agent 最像“智能”的部分。没有 Planning 的 Agent 就像无头苍蝇每一步都靠模型即兴发挥任务一复杂就乱套。Planning 的核心是任务分解和执行监控。任务分解是把一个高层目标拆成可执行的子任务序列。比如“帮我安排一次团队建设活动”可以拆成确定参与人数 → 查询预算 → 筛选场地 → 比较价格 → 预订 → 通知参与者。执行监控是在每个子任务完成后评估结果决定是继续下一步、调整计划还是回退重来。目前主流的 Planning 实现方式有两种ReAct 模式和Plan-and-Execute 模式。ReAct 是“推理-行动”交替进行每一步都根据当前状态决定下一步做什么灵活但容易跑偏Plan-and-Execute 是先制定完整计划再逐步执行方向明确但缺乏灵活性。实际项目中我通常混合使用先用 Plan-and-Execute 制定粗粒度计划执行过程中用 ReAct 处理意外情况。提示Planning 层最容易出现的问题是“过度规划”——模型花大量 token 在制定详细计划上真正执行时反而没力气了。我的做法是限制规划深度只规划到“下一步做什么”这个粒度不要试图一次性规划到终点。3. 从零搭建一个可用的 AI Agent完整实操流程3.1 技术选型框架不是越重越好搭建 Agent 的第一步是选框架。市面上的选择大致分三类轻量级编排框架如 LangChain、图状态机框架如 LangGraph、全托管平台如 Coze、Dify。LangChain 的优势是生态丰富、工具多、上手快适合快速验证想法。但它的抽象层比较厚调试时经常不知道问题出在哪一层。LangGraph 把 Agent 的执行流程建模成状态图每个节点是一个操作边是状态转移条件。这种方式对复杂流程的控制力更强调试也更直观但学习曲线陡一些。全托管平台适合非技术团队快速搭建但灵活性和可定制性受限。我的建议是如果是学习目的从 LangChain 入手快速跑通一个最小闭环如果是生产项目直接用 LangGraph 或自研状态机因为生产环境对可控性和可观测性的要求远高于开发效率。热词里有个 “基于 Rust 语言 AI Agent” 的搜索说明有人关注性能敏感场景。Rust 确实在并发和内存安全上有优势但生态成熟度还不如 Python。如果你的 Agent 需要处理高并发请求比如同时服务几百个用户可以考虑用 Rust 写核心调度层用 Python 写工具和模型调用层两者通过 gRPC 通信。3.2 最小可行 Agent 的代码骨架下面是一个基于 LangGraph 的最小 Agent 骨架包含规划、工具调用和记忆三个核心环节。我把它拆成了几个关键节点每个节点职责单一方便调试和替换。from langgraph.graph import StateGraph, END from typing import TypedDict, Annotated import operator # 定义 Agent 状态 class AgentState(TypedDict): messages: Annotated[list, operator.add] # 对话历史 plan: list # 当前计划 current_step: int # 当前执行到第几步 tool_results: list # 工具调用结果 memory: dict # 长期记忆摘要 # 规划节点根据用户输入生成执行计划 def plan_node(state: AgentState): user_input state[messages][-1] # 调用模型生成计划 plan llm_plan(user_input, state.get(memory, {})) return {plan: plan, current_step: 0} # 执行节点执行当前步骤 def execute_node(state: AgentState): step state[plan][state[current_step]] if step[type] tool: result call_tool(step[tool_name], step[params]) return {tool_results: state[tool_results] [result]} elif step[type] respond: return {messages: state[messages] [step[content]]} # 评估节点判断是否需要调整计划 def evaluate_node(state: AgentState): last_result state[tool_results][-1] if state[tool_results] else None if last_result and last_result.get(status) error: # 工具调用失败重新规划 return {plan: replan(state), current_step: 0} return {current_step: state[current_step] 1} # 构建图 graph StateGraph(AgentState) graph.add_node(plan, plan_node) graph.add_node(execute, execute_node) graph.add_node(evaluate, evaluate_node) graph.set_entry_point(plan) graph.add_edge(plan, execute) graph.add_edge(execute, evaluate) graph.add_conditional_edges( evaluate, lambda s: end if s[current_step] len(s[plan]) else execute, {end: END, execute: execute} ) agent graph.compile()这个骨架看起来简单但已经包含了 Agent 的核心循环规划 → 执行 → 评估 → 继续或结束。实际项目中你需要在每个节点里填充更复杂的逻辑比如规划节点要接入记忆检索执行节点要处理工具调用的超时和重试评估节点要做更细粒度的结果判断。3.3 工具接入的实操细节工具接入不是写个函数就完事。我踩过的坑包括工具返回结果太长导致上下文爆炸、工具参数类型不匹配导致调用失败、工具并发调用时状态冲突。结果截断是必须做的。一个搜索工具可能返回几千字的网页内容直接塞进上下文会迅速撑爆窗口。我的做法是在工具层做一次摘要如果返回内容超过阈值比如 500 字先用轻量模型压缩成关键信息再返回给 Agent。参数校验也要在工具层做。模型生成的参数不一定符合预期比如该传整数的地方传了字符串该传数组的地方传了单个值。在工具入口做一次类型检查和转换能避免很多莫名其妙的失败。并发控制在多工具场景下很重要。如果 Agent 同时调用多个工具而这些工具又共享某些状态比如都往同一个列表里写数据就会出现竞态条件。解决办法是给工具调用加锁或者设计成无状态工具每次调用独立不共享可变状态。# 带结果截断和参数校验的工具包装器 def safe_tool_wrapper(tool_func, max_result_length500): def wrapper(**kwargs): # 参数校验 validated validate_params(kwargs) if not validated[ok]: return {status: error, message: validated[error]} # 执行工具 try: result tool_func(**validated[params]) except Exception as e: return {status: error, message: str(e)} # 结果截断 if len(str(result)) max_result_length: result summarize_result(result, max_result_length) return {status: success, data: result} return wrapper3.4 记忆管理的落地方法记忆管理我分三层来做会话级记忆用 Redis 存设置 TTL比如 2 小时过期自动清理用户级记忆用向量数据库存按用户 ID 分区存储用户的偏好、历史行为等任务级记忆用内存状态对象存任务结束即释放。写入长期记忆时我会做一次“记忆价值判断”让模型评估这条信息是否值得长期保留。比如用户说“我今天心情不好”这属于临时状态不值得写入长期记忆用户说“我对海鲜过敏”这是持久偏好必须记住。读取长期记忆时我会做“相关性过滤”先用向量相似度召回 Top-10再用模型对这 10 条做一次精排只保留最相关的 3 条注入上下文。这样既能保证相关性又不会让记忆噪声干扰模型判断。注意长期记忆的写入频率要控制。如果每轮对话都写入数据库会迅速膨胀检索质量也会下降。我的做法是每 5 轮对话或任务结束时做一次批量写入写入前做去重和冲突检测。4. 生产环境踩坑实录那些文档不会告诉你的问题4.1 上下文爆炸的三种典型场景与解法上下文爆炸是 Agent 生产环境最常见的问题没有之一。热词里 “context is too large and auto-compaction could not recover this” 和 “this model‘s maximum context length is 1048576 tokens” 都是这个问题的表现。我总结下来有三种典型场景。场景一工具返回结果过长。比如搜索工具返回了整篇网页、数据库查询返回了上千行记录。解法是在工具层做截断和摘要只返回与当前任务相关的部分。场景二多轮对话历史累积。用户和 Agent 聊了 50 轮每轮的消息都在上下文里。解法是滑动窗口 摘要保留最近 N 轮原文更早的对话压缩成摘要。场景三规划过程本身消耗大量 token。模型在规划时输出了详细的推理步骤这些步骤又作为上下文传给执行节点。解法是规划输出只保留结构化结果步骤列表丢弃推理过程。爆炸场景根因解法效果工具结果过长工具返回原始数据未处理工具层截断摘要上下文占用降低 60%-80%对话历史累积全量历史注入滑动窗口摘要上下文占用稳定在阈值内规划过程冗长推理过程被保留只保留结构化计划规划 token 消耗降低 50%4.2 工具调用失败的排查思路工具调用失败的原因五花八门我整理了一个排查清单按出现频率排序。参数格式错误是最常见的。模型生成的参数不符合工具定义的 Schema比如该传 JSON 对象的地方传了字符串。排查方法是打印模型原始输出和工具 Schema对比差异。解法是在工具入口做参数校验和自动修正。工具名拼写错误也很常见。模型可能把 “query_order” 写成 “queryOrder” 或 “query_orders”。解法是在工具注册时做名称标准化同时给模型提供工具名列表作为参考。超时和网络错误属于基础设施问题。解法是给工具调用设置合理的超时时间我一般设 10-30 秒超时后返回结构化错误让模型决定是否重试。权限和配额问题容易被忽略。比如 API Key 过期、调用次数超限。解法是在工具层做配额监控接近限额时提前告警。4.3 让 Agent 扛住并发的工程实践热词里 “ai agent 怎么扛并发” 是个很实际的问题。单用户场景下 Agent 跑得好好的一上并发就各种问题。我的经验是并发问题主要出在三个地方模型调用限流、状态管理冲突、工具资源竞争。模型调用限流是最直接的瓶颈。大多数模型 API 都有 QPS 限制并发一高就排队或报错。解法是做请求队列和优先级调度把 Agent 任务按优先级排队高优先级任务先调用模型同时做失败重试和降级比如强模型限流时自动切到轻量模型。状态管理冲突发生在多个请求共享同一个 Agent 实例时。如果 Agent 的状态对象是全局的并发请求会互相覆盖。解法是每个请求创建独立的状态对象Agent 实例本身设计成无状态的。工具资源竞争比如多个请求同时写同一个数据库连接池。解法是给工具调用加连接池和超时控制避免一个慢请求拖垮整个系统。# 带并发控制的 Agent 调用示例 import asyncio from asyncio import Semaphore class AgentPool: def __init__(self, max_concurrent10): self.semaphore Semaphore(max_concurrent) async def run(self, user_input, user_id): async with self.semaphore: # 每个请求独立的状态 state create_initial_state(user_input, user_id) result await agent.ainvoke(state) return result # 使用 pool AgentPool(max_concurrent10) tasks [pool.run(input_i, user_i) for input_i, user_i in requests] results await asyncio.gather(*tasks)4.4 成本控制的几个狠招Agent 跑起来之后成本是个绕不开的话题。一个复杂任务可能调用模型十几次如果每次都用最大最强的模型账单会很难看。我试过几个有效的成本控制手段。分层用模型前面提过这里补充具体数据规划层用强模型比如 GPT-4 级别执行层用轻量模型比如 GPT-3.5 级别总结层用中等模型。实测下来整体成本能降低 60%-70%而任务成功率只下降不到 5%。缓存重复调用也很有效。很多 Agent 任务有重复的子任务比如“查询今天的天气”在多个任务中都会出现。把工具调用结果缓存起来设置合理的 TTL能省下不少模型调用。限制规划深度能直接减少模型调用次数。我见过一些 Agent 规划了 20 步实际执行到第 5 步就发现方向错了。限制规划最多 5 步执行过程中动态调整比一次性规划 20 步更省也更准。早停机制是最后一道防线。如果 Agent 连续 3 次工具调用都失败或者连续 5 轮没有实质性进展直接终止任务并返回错误不要让它无限循环下去。5. 进阶方向从“能用”到“好用”还差什么5.1 多 Agent 协作的适用边界单 Agent 搞不定的任务自然会想到多 Agent 协作。比如一个“市场分析”任务可以拆成数据采集 Agent、数据分析 Agent、报告撰写 Agent 三个角色。但多 Agent 不是银弹它引入了通信开销和协调复杂度。我的判断标准是如果任务可以清晰拆分成独立的子任务且子任务之间不需要频繁交互那么多 Agent 是合适的如果子任务之间需要大量共享状态和实时协调单 Agent 加工具反而更简单可靠。多 Agent 的通信方式有两种共享内存所有 Agent 读写同一个状态空间和消息传递Agent 之间通过消息队列通信。共享内存简单但容易冲突消息传递解耦但延迟高。我通常用混合模式关键状态共享非关键信息通过消息传递。5.2 可观测性怎么知道 Agent 在想什么Agent 跑在生产环境最怕的是“黑盒”——它失败了但你不知道哪一步出了问题。可观测性建设包括三个层面日志、指标、追踪。日志要记录每个节点的输入输出、模型调用的 Prompt 和响应、工具调用的参数和结果。指标要监控任务成功率、平均耗时、模型调用次数、工具失败率。追踪要把一个任务的完整执行链路串起来方便定位问题。我用的方案是 OpenTelemetry 自研的 Agent 追踪层。每个 Agent 任务生成一个 trace_id所有节点和工具调用都关联这个 ID。出问题时通过 trace_id 能快速还原整个执行过程。5.3 安全与合规的底线Agent 有了工具调用能力之后安全边界就变得非常重要。一个能操作数据库的 Agent如果被恶意 Prompt 注入攻击可能执行危险操作。热词里 “invalid prompt: your prompt was flagged as potentially violating our usage p” 也说明平台层面对 Prompt 安全有审查。我的安全实践包括工具权限最小化Agent 只能调用必要的工具且工具本身有权限控制、输入输出过滤对用户输入和工具返回做敏感信息检测、操作审计所有工具调用记录日志关键操作需要二次确认。提示不要给 Agent 直接操作生产数据库的权限。我的做法是让 Agent 调用一个中间层 API中间层做权限校验和操作审计Agent 只能通过这个 API 间接操作数据。5.4 我个人的学习路线建议如果你刚开始接触 AI Agent我建议按这个顺序来先跑通一个最小闭环用 LangChain 做一个能调用一两个工具的 Agent再深入理解每个组件分别研究 Memory、Tool、Planning 的常见实现然后做一个小型生产项目比如自动日报、客服助手最后再考虑多 Agent 和性能优化。不要一上来就追求“全自动”“通用 Agent”那东西目前还不成熟。从一个具体场景入手把单点做深做透比泛泛地搭一个什么都干不了的“通用 Agent”有价值得多。我在实际项目中的体会是Agent 的价值不在于它有多“智能”而在于它能把人从重复性的流程操作中解放出来——哪怕这个流程只有三五步只要它稳定可靠就是好 Agent。