
1. 为什么现在聊 AI Agent 正是时候过去一年我断断续续做了五六个 Agent 项目从最早用 LangChain 拼一个能查天气的玩具到后来给团队做内部知识问答、工单自动分类、代码审查辅助踩过的坑比写过的 Prompt 还多。身边不少朋友一上来就问“AI Agent 到底怎么搭”但聊两句就发现大家卡住的地方根本不是某个 API 怎么调而是脑子里没有一张完整的图——不知道 Agent 和 Workflow 的边界在哪不知道 LLM 在整条链路里到底扮演什么角色更不知道一个能上生产的 Agent 需要哪些工程配套。这篇东西就是把我自己从零摸索的过程摊开讲一遍。核心关键词是AI Agent、Workflow、LLM、DevOps、Anthropic我会围绕这几个词把“从零理解如何构建高效的 AI Agent”这件事拆成能落地的模块。适合谁看如果你写过一点 Python 或 Java调过 OpenAI 或者 Claude 的接口但一想到要把 Agent 做成一个稳定跑起来的东西就发怵那这篇就是写给你的。如果你已经能熟练搭 Agent也可以看看我在工程化和踩坑部分的经验说不定能帮你省几天调试时间。先说清楚一个前提Agent 不是魔法它本质上是“LLM 工具调用 循环控制 状态管理”的组合体。理解了这句话后面所有内容都是它的展开。我见过太多人把 Agent 想得太玄结果连最基本的“什么时候该用 Workflow、什么时候该用 Agent”都分不清做出来的东西要么过度设计要么根本跑不通。2. 先把概念理清楚Agent、Workflow 和 LLM 到底什么关系2.1 一句话区分 Agent 和 Workflow我习惯用做菜来类比。Workflow就像一份固定菜谱先切菜、再热油、然后下锅、最后调味每一步的顺序和条件都是你提前写死的。Agent则像一个有经验的厨师你只告诉他“做一道能吃饱的晚饭”他自己决定是炒饭还是煮面中途发现冰箱里没鸡蛋了还会临时改方案。落到代码层面Workflow 是确定性的编排用 if-else、状态机、DAG 就能描述清楚Agent 则是把“下一步做什么”的决策权交给 LLM由模型根据当前上下文动态选择工具和参数。这个区别决定了它们的适用场景完全不同。维度WorkflowAgent决策来源开发者预设LLM 动态决策可预测性高中到低调试难度低高适合任务流程固定、步骤明确开放式、需要探索典型例子表单审批、数据 ETL客服对话、研究助手我的经验是能用 Workflow 解决的绝不上 Agent。因为 Agent 的不确定性会带来调试成本、成本波动和安全风险。只有当任务路径无法穷举、需要模型自己判断时才值得引入 Agent。2.2 LLM 在 Agent 里到底干什么很多人以为 LLM 是 Agent 的“大脑”这个说法对但不精确。更准确地说LLM 在 Agent 里承担三个职责意图理解、决策规划、结果生成。它不负责执行执行是工具的事它也不负责记忆记忆是外部存储的事。这就引出一个关键设计原则把 LLM 的能力边界收窄。我早期犯的错就是让 LLM 什么都干结果它既要做意图分类又要生成 SQL 还要格式化输出Prompt 越写越长准确率反而下降。后来我改成“一个 LLM 调用只做一件事”比如专门有一个调用做意图路由另一个专门做参数抽取整体稳定性立刻上来了。Anthropic 在它的工程博客里反复强调过一个观点给模型清晰的工具定义和边界比给它一堆模糊的指令更有效。这一点我在实际项目里验证过很多次。工具描述写得越精确模型选错工具的概率越低。2.3 为什么 2026 年这个时间点值得认真做 Agent热词里出现了“2026 年国内 AI Agent 智能体产品盘点”说明这个赛道已经从概念验证进入产品化阶段。我观察到几个明显变化一是模型的原生工具调用能力越来越强不再需要靠 Prompt 硬凑 JSON二是工程框架成熟了Spring AI、Dify 这类工具让搭建门槛大幅降低三是企业开始认真考虑 Agent 的 DevOps 配套而不是停留在 Demo 阶段。这意味着什么意味着现在做 Agent拼的不再是“能不能跑通”而是“能不能稳定、可控、可观测地跑”。这也是我写这篇的核心动机——把工程化的部分讲透。3. 从零搭建一个 Agent 的完整思路拆解3.1 先想清楚你的任务真的需要 Agent 吗我在动手前会问自己三个问题。第一这个任务的步骤能不能提前穷举如果能直接写 Workflow。第二任务过程中需不需要根据中间结果动态调整策略如果需要才考虑 Agent。第三失败一次的代价大不大如果代价很高比如涉及资金操作那必须加人工确认环节。举个例子我之前做过一个“自动整理会议纪要并生成待办”的需求。表面看很适合 Agent但拆解后发现转录是固定步骤抽取待办是固定步骤分配负责人也是固定步骤。整条链路其实是一个标准 Workflow用 Agent 反而增加了不确定性。最后我用 Workflow 实现准确率和速度都更好。反过来我做过一个“帮用户排查线上问题”的助手。用户描述的现象千奇百怪可能要看日志、查监控、翻文档、比对配置路径完全无法预设。这种就必须用 Agent让它自己决定先查什么。3.2 架构分层把 Agent 拆成可替换的模块我现在的 Agent 项目基本都按这个分层来组织接入层处理用户输入、鉴权、限流编排层决定用 Workflow 还是 Agent管理多轮循环能力层LLM 调用、工具注册、Prompt 管理记忆层短期对话上下文、长期知识库执行层具体工具的实现比如查数据库、调 API观测层日志、追踪、成本统计这样分层的好处是每一层都能独立替换。比如今天用 Claude明天想换别的模型只动能力层就行今天用内存存上下文明天想上 Redis只动记忆层。我见过太多项目把 LLM 调用和业务逻辑揉在一起换模型时改到崩溃。3.3 工具设计Agent 的手脚怎么造工具是 Agent 和外部世界交互的唯一通道设计好坏直接决定 Agent 的上限。我的原则是工具要原子化、幂等化、可描述化。原子化是指一个工具只做一件事。不要设计一个“处理订单”的巨型工具而要拆成“查订单状态”“取消订单”“修改地址”三个。这样模型选择时更清晰出错也更容易定位。幂等化是指同一个工具用相同参数调用多次结果应该一致。因为 Agent 可能会重试如果工具不幂等重试就会造成副作用。比如“发送邮件”这种工具我会加一个去重键避免重复发送。可描述化是指工具的 name、description、参数 schema 要写得让模型一看就懂。我通常会在 description 里写清楚“什么时候用这个工具”“参数格式是什么”“返回什么”。实测下来description 写得好模型选错工具的概率能降一半以上。# 一个工具定义的示例伪代码 tool { name: query_order_status, description: 根据订单号查询订单当前状态。当用户询问订单进度、是否发货时使用。, parameters: { type: object, properties: { order_id: { type: string, description: 订单号通常是 16 位数字 } }, required: [order_id] } }3.4 循环控制Agent 的“思考-行动”节奏Agent 的核心是一个循环观察当前状态 → LLM 决策 → 执行工具 → 更新状态 → 再决策。这个循环什么时候停我一般设三个终止条件模型主动输出最终答案、达到最大轮数、检测到重复动作。最大轮数很关键。我早期没设上限结果模型陷入死循环一直调同一个工具烧了不少 token。现在我一般设 10 到 15 轮超过就强制返回当前结果并记录异常。重复动作检测也很实用。如果模型连续两次调用同一个工具且参数相同基本可以判定它卡住了这时候直接中断并给出提示比让它继续空转强。4. 核心细节解析与实操要点4.1 Prompt 工程别把 Prompt 写成小说我见过最长的系统 Prompt 有三千多字塞满了各种规则和示例。结果模型反而抓不住重点。后来我总结出一个原则系统 Prompt 只放角色定位和硬约束具体任务指令放到用户消息里。系统 Prompt 我一般控制在 500 字以内包含三部分你是谁、你的能力边界、你必须遵守的规则。比如“你是一个订单查询助手只能查询订单状态不能修改订单。如果用户要求修改引导他联系人工客服。”工具的描述放在工具定义里不要重复写进系统 Prompt。任务相关的指令比如“请用 JSON 格式输出”放在当轮的用户消息里。这样模型每次看到的上下文更聚焦准确率更高。还有一个细节少用否定句。与其说“不要编造订单号”不如说“如果用户没有提供订单号请询问他”。模型对正向指令的遵循度明显更高。4.2 上下文管理Agent 的记忆怎么管Agent 跑多轮之后上下文会越来越长成本和延迟都会上升。我的做法是分层管理最近 N 轮完整保留保证对话连贯更早的轮次压缩成摘要只保留关键信息工具调用结果只保留必要字段大段原始数据不入上下文压缩摘要这一步我一般用一次额外的 LLM 调用来做把前面对话浓缩成两三句话。虽然多花一点 token但能显著降低后续每轮的上下文长度总体是划算的。长期记忆则放到外部知识库用 RAG 的方式按需检索。热词里提到的“llm wiki 知识库”“rag graphrag llm wiki”就是这个思路。我的经验是知识库的切分粒度很重要切得太碎检索不准切得太大又浪费上下文。一般按语义段落切每段 300 到 500 字比较合适。4.3 错误处理Agent 出错了怎么办Agent 的错误分三类LLM 调用失败、工具执行失败、模型决策错误。每一类的处理方式不同。LLM 调用失败通常是网络或限流问题我会做指数退避重试重试三次还失败就降级到备用模型或返回兜底话术。热词里“unable to connect to anthropic services”这类报错基本都是网络或配置问题重试加超时设置能解决大部分。工具执行失败要把错误信息回传给模型让它决定是重试还是换方案。这里有个技巧错误信息要写得对模型友好比如“订单号格式错误应该是 16 位数字”而不是抛一个原始异常堆栈。模型决策错误最难处理比如选错工具、参数抽错。我的做法是加一层校验工具执行前先检查参数合法性不合法就直接返回错误让模型重新决策而不是真的去执行。4.4 成本控制别让 Agent 变成烧钱机器Agent 的成本主要来自 LLM 调用次数和上下文长度。我做过统计一个设计不好的 Agent成本可能是设计良好的三到五倍。控制成本有几个手段第一用小模型做路由。意图分类、参数抽取这类简单任务用便宜的小模型就够了只有复杂推理才用大模型。第二缓存重复调用。相同输入的结果可以缓存尤其是知识库检索这类。第三限制上下文长度。前面说的分层管理就是为这个。第四设置预算上限。每个会话或每个用户设一个 token 上限超了就降级。我一般会在观测层记录每次调用的 token 数和成本按天汇总。这样能快速发现异常比如某个工具突然被频繁调用往往意味着 Prompt 或工具描述有问题。5. 实操过程手把手搭一个能跑的 Agent5.1 环境准备与技术选型假设我们要搭一个“内部知识问答 Agent”能回答员工关于公司制度的问题还能查一些简单的业务数据。技术选型上我倾向用 Python 起步因为生态最全。LLM 用 Claude 系列工具调用稳定。框架可以用 LangGraph 或者自己写循环我建议新手先自己写一遍理解原理后再用框架。依赖大概这些anthropic官方 SDK、fastapi做接口、redis做上下文存储、chromadb或pgvector做向量检索。如果你用 Java 技术栈Spring AI 现在也成熟了热词里“spring ai 开发 agent”“spring cloud spring ai 开发自己的 agent”说明这条路走的人不少。pip install anthropic fastapi redis chromadb uvicorn5.2 第一步定义工具集我们先定义三个工具查制度文档、查员工信息、查业务数据。tools [ { name: search_policy, description: 搜索公司制度文档。当用户询问考勤、报销、假期等制度问题时使用。, input_schema: { type: object, properties: { query: {type: string, description: 搜索关键词} }, required: [query] } }, { name: get_employee_info, description: 查询员工基本信息。当需要确认员工部门、职级时使用。, input_schema: { type: object, properties: { employee_id: {type: string, description: 员工工号} }, required: [employee_id] } }, { name: query_business_data, description: 查询业务数据。当用户询问销售额、订单量等数据时使用。, input_schema: { type: object, properties: { metric: {type: string, description: 指标名称}, period: {type: string, description: 时间范围如 2026-01} }, required: [metric, period] } } ]注意每个 description 都写清楚了“什么时候用”这是关键。5.3 第二步实现 Agent 主循环import anthropic client anthropic.Anthropic() def run_agent(user_input, history, max_turns10): messages history [{role: user, content: user_input}] for turn in range(max_turns): response client.messages.create( modelclaude-sonnet-4-20250514, max_tokens2048, system你是一个内部助手只能通过提供的工具回答问题。如果工具无法回答如实告知用户。, toolstools, messagesmessages ) # 如果模型直接给出最终答案 if response.stop_reason end_turn: return extract_text(response), messages # 如果模型要调用工具 if response.stop_reason tool_use: tool_results [] for block in response.content: if block.type tool_use: result execute_tool(block.name, block.input) tool_results.append({ type: tool_result, tool_use_id: block.id, content: result }) messages.append({role: assistant, content: response.content}) messages.append({role: user, content: tool_results}) return 抱歉我暂时无法回答这个问题。, messages这段代码就是 Agent 的心脏。核心逻辑是调模型 → 看它是要回答还是要调工具 → 调工具把结果塞回去 → 再调模型。循环直到模型给出最终答案或达到轮数上限。5.4 第三步工具执行与错误处理def execute_tool(name, params): try: if name search_policy: return search_policy(params[query]) elif name get_employee_info: return get_employee_info(params[employee_id]) elif name query_business_data: return query_business_data(params[metric], params[period]) else: return f未知工具{name} except Exception as e: # 返回对模型友好的错误信息 return f工具执行失败{str(e)}。请检查参数或换一种方式。错误信息一定要对模型友好这样它才能自己纠正。我试过直接抛异常模型收到一堆堆栈信息后完全不知道怎么办反而更容易卡住。5.5 第四步接入知识库做 RAG制度文档的检索用 RAG。先把文档切分、向量化、存进向量库查询时做相似度检索。import chromadb chroma_client chromadb.Client() collection chroma_client.get_or_create_collection(policy) def search_policy(query, top_k3): results collection.query(query_texts[query], n_resultstop_k) docs results[documents][0] return \n\n.join(docs)切分粒度我一般按段落每段 300 到 500 字。太碎了检索出来的片段不完整太长了又浪费上下文。检索数量 top_k 设 3 到 5 比较合适太多会稀释关键信息。5.6 第五步加上观测和成本统计import time def log_call(model, input_tokens, output_tokens, duration): cost input_tokens * 0.000003 output_tokens * 0.000015 # 示例单价 print(f[{time.strftime(%Y-%m-%d %H:%M:%S)}] fmodel{model} in{input_tokens} out{output_tokens} fcost${cost:.4f} duration{duration:.2f}s)每次 LLM 调用都记一笔按天汇总。这样能快速发现异常。我有一次发现某个会话的成本是平均值的十倍查下来是模型陷入了工具调用循环加了重复检测后就好了。6. 常见问题与排查技巧实录6.1 模型不调用工具直接瞎编答案这是最常见的问题。原因通常是工具描述不够清晰或者系统 Prompt 没有强调“必须用工具”。解决办法在系统 Prompt 里明确写“回答任何事实性问题前必须先调用工具”同时把工具 description 写得更具体。还有一种情况是模型觉得问题太简单不需要工具。这时候可以在用户消息里加一句“请先查询再回答”。我实测下来这两招组合使用瞎编的概率能降到很低。6.2 工具调用参数格式错误模型有时候会把参数写成字符串而不是对象或者漏掉必填字段。解决办法是在工具 schema 里把 required 写清楚同时在系统 Prompt 里强调参数格式。如果还是出错可以在工具执行前加一层校验不合法就返回错误让模型重试。热词里“llm request failed: provider rejected the request schema or tool payload”就是这类问题。遇到这个报错先检查工具 schema 是否符合 JSON Schema 规范再看模型返回的参数是否匹配。6.3 Agent 陷入死循环表现是模型反复调用同一个工具或者在不同工具之间来回跳。解决办法有三个设最大轮数、检测重复调用、在系统 Prompt 里加“如果连续两次得到相同结果请换一种方式或直接回答”。我一般三个都上。最大轮数兜底重复检测提前中断Prompt 引导模型自救。实测下来死循环基本能杜绝。6.4 上下文太长导致响应变慢多轮对话后上下文会膨胀。解决办法是分层管理最近几轮完整保留更早的压缩成摘要工具结果只留关键字段。我一般每 5 轮做一次摘要压缩把之前的对话浓缩成两三句话。还有一个技巧是给工具结果设长度上限超过就截断。比如查数据库返回 100 条记录只取前 10 条塞进上下文剩下的告诉模型“还有更多结果如需请缩小范围”。6.5 成本突然飙升先看观测日志定位是哪个环节的 token 数异常。常见原因有上下文没压缩、工具结果太长、模型陷入循环、Prompt 里有冗余内容。逐个排查一般都能找到。我还会设一个预算告警比如单日成本超过阈值就发通知。这样能在问题扩大前及时干预。问题典型表现排查方向解决手段瞎编答案不调工具直接回答工具描述、系统 Prompt强化指令、细化描述参数错误schema 校验失败工具 schema、模型输出加校验、返回友好错误死循环重复调用同一工具轮数、重复检测设上限、加检测响应变慢延迟逐渐增加上下文长度分层压缩、截断结果成本飙升token 数异常观测日志定位环节、加预算告警6.6 一些独家避坑心得第一别在 Prompt 里写太多规则。规则越多模型越容易顾此失彼。我现在的做法是规则不超过 5 条每条一句话。第二工具数量别太多。我试过给模型 20 个工具结果它选择困难准确率反而下降。一般控制在 10 个以内超过就分组用路由先选组再选工具。第三测试要覆盖边界情况。比如用户输入空字符串、超长文本、特殊字符这些都要测。我踩过坑用户输入一个 emoji整个链路就崩了。第四日志要记全。每次 LLM 调用的输入输出、工具调用的参数和结果、最终响应都要记下来。出问题时这些日志就是救命稻草。第五版本管理很重要。Prompt、工具定义、模型版本都要版本化。我吃过亏改了 Prompt 没记录结果效果变差了都不知道回滚到哪一版。7. 工程化与 DevOps让 Agent 真正能上生产7.1 部署架构怎么设计Agent 服务我一般拆成两个部分无状态的 API 服务和有状态的任务队列。API 服务处理同步请求任务队列处理耗时长的 Agent 任务。这样既能保证响应速度又能处理复杂任务。API 服务用 FastAPI 或 Spring Boot 都行水平扩展很容易。任务队列用 Redis 或 RabbitMQAgent 任务丢进去异步执行结果通过回调或轮询返回。热词里“ai agent 部署”“devops 平台搭建”说的就是这个层面的东西。7.2 监控和告警怎么做监控分三个层面技术指标延迟、错误率、QPS、业务指标任务成功率、用户满意度、成本指标token 消耗、单次成本。技术指标用 Prometheus Grafana业务和成本指标我一般自己写个看板。告警阈值我设得比较保守比如错误率超过 5% 就告警单日成本超过预算 80% 就告警。宁可多告警几次也别等出大事才发现。7.3 灰度发布和回滚Agent 的变更风险比普通服务高因为 Prompt 或模型的微小改动都可能导致效果大幅波动。所以我坚持灰度发布新版本先放 10% 流量观察一两天指标正常再逐步放量。回滚要快。Prompt 和工具定义都存配置中心出问题一键切回旧版本。模型版本也要能切换别把模型名写死在代码里。7.4 安全与合规Agent 能调工具就意味着它能产生副作用。所以权限控制必须做。我的做法是工具按敏感度分级低敏感的直接执行高敏感的加人工确认。比如查数据可以直接执行改数据必须确认。输入输出也要过滤。用户输入可能包含注入攻击工具返回可能包含敏感信息。我一般会在接入层做一层清洗在输出层做一层脱敏。8. 一些关于选型和学习的个人建议框架选型上我的建议是先手写再上框架。手写一遍 Agent 循环你会真正理解每一步在干什么。之后再去看 LangGraph、Spring AI 这些框架就能看懂它们帮你封装了什么遇到问题也知道去哪找。模型选型上别迷信某一个模型。我一般会准备两个模型主力用 Claude 或同级别模型备用一个更便宜的。主力限流或故障时自动切换保证服务可用。学习路径上我建议按这个顺序先理解 LLM 的工具调用机制再手写一个最小 Agent然后加工具、加记忆、加观测最后再考虑多 Agent 协作。热词里“ai agent 学习”“ai agent 练手小项目”说明很多人想找入门项目我的建议是从“查天气”“查快递”这种单工具 Agent 开始跑通了再逐步加复杂度。最后分享一个我自己的体会Agent 的效果八成取决于工具设计和 Prompt 质量两成取决于模型能力。我见过太多人花大量时间调模型参数却不肯花半小时把工具描述写清楚。方向错了再努力也是白费。把工具设计好、把边界划清楚、把错误处理好一个中等模型也能跑出很好的效果。反过来工具一团糟再强的模型也救不了。