这两年“AI Agent”几乎成了软件工程领域最高频的词。但如果你和我一样真正在业务系统里尝试把 Agent 从 Demo 推向生产环境大概率会遇到同一批问题演示时看起来很聪明的模型放到真实请求里开始乱调工具给它的权限稍微大一点就开始在数据库里“自由发挥”跑了几周之后没人说得清它到底做了哪些决策、为什么这么做。问题不在模型能力而在于绝大多数 Agent 项目从一开始就缺少工程约束。Linear 团队作为一家长期做项目管理工作流、以“克制、高效、高质量”著称的团队他们在构建生产级 Agent 时总结的态度非常值得借鉴不要把 Agent 当成一个“能回答问题的模型”而要把它当成一个“有边界、可观测、可回滚的软件系统”。本文基于 Linear 团队公开分享中体现的工程理念和当前业界构建生产级 Agent 的主流共识梳理出 5 条规则。读完你会明白Agent 开发真正的门槛不在提示词和模型选择而在工作流设计、权限边界、评估体系和可观测性。1. 这篇文章真正要解决的问题先说一个常见现象。很多团队开发 Agent 的路径是这样的先接一个大模型 API写一段提示词然后丢进一个“Agent 框架”里配几个工具跑通一个业务 Demo。Demo 演示的时候产品经理和老板都很满意。但等到接入真实数据、真实用户、真实权限之后问题开始爆发Agent 开始调用不应该调用的工具同一个问题今天回答正确明天换了一个模型版本就答偏了出现问题之后翻日志只能看到“模型返回了结果”但看不到它为什么选择调用某个工具、中间经历了哪些步骤更可怕的是没有回滚机制Agent 一旦执行了写操作错误就无法挽回。这些问题本质上不是模型能力问题而是工程化问题。生产和 Demo 之间最大的差距是“不确定性”的处理方式。Demo 只需要展示最优路径生产环境必须处理边界情况、失败路径、权限问题、审计需求。Linear 团队在生产级 Agent 建设中反复强调一个观点Agent 不是用来“自由发挥”的它需要被放进一个受控的工作流里每一步都有验证、有记录、有回退方案。这篇文章要解决的就是从“能跑”到“能生产”之间的这段路。我会结合场景、代码示例和错误排查把这 5 条规则拆开讲清楚。如果你正准备在公司内部落地一个 Agent 项目或者已经被线上 Agent 的失控行为折磨过这篇文章应该能帮你少走不少弯路。2. 规则一从具体任务出发用最小可验证单元证明价值很多 Agent 项目失败的起点不是技术选型错了而是目标定得太宏大。团队一上来就想做一个“能处理所有请求的智能助手”然后花几周时间搭框架、选模型、设计复杂的 Prompt 体系最后发现整个系统无法验证到底什么算“成功”什么算“失败”模型回答得对不对完全靠人主观判断。Linear 团队的建议很朴素先找到一个足够具体、足够狭窄、结果可以被明确验证的任务把它跑通、跑稳再考虑扩展。2.1 什么是“最小可验证单元”所谓最小可验证单元需要满足三个条件。第一输入是明确的。比如“根据 issue 标题和描述给它打上正确的标签”就是一个明确输入而不是“帮用户处理问题”这种模糊描述。第二输出是可以客观判断的。结果正确就是正确错误就是错误不需要人工做主观评审。第三这个任务本身有明确业务价值。哪怕是每个月帮团队节省两个小时也是一个值得先做的场景。一个很典型的例子是把 Agent 用于 issue 自动分类输入一个 issue 的标题、描述和项目上下文输出这个 issue 应该属于哪个模块、应该分配给哪个团队。这个任务结果可验证、出错影响可控、可以逐步扩展。2.2 最小验证示例基于 LLM 的 issue 分类下面这个示例演示的是用一个 Python 脚本调用模型 API对一条 issue 做分类。代码重点是“验证链路”而不是模型本身。# 文件路径agent_demo/issue_classifier.py import os import json from openai import OpenAI client OpenAI( api_keyos.environ.get(LLM_API_KEY), base_urlos.environ.get(LLM_BASE_URL), ) ISSUE_CATEGORIES [ bug, # 缺陷 feature, # 新功能 refactor, # 重构 documentation # 文档 ] TARGET_TEAMS [ frontend, backend, data, platform ] def classify_issue(title: str, description: str) - dict: 根据 issue 内容返回分类结果。 prompt f 你是一个项目管理助手。请根据以下 issue 信息判断它属于哪个分类、应该分配给哪个团队。 issue 标题{title} issue 描述{description} 分类必须是以下之一{, .join(ISSUE_CATEGORIES)} 团队必须是以下之一{, .join(TARGET_TEAMS)} 请以 JSON 格式返回不要有其他内容{{category: ..., team: ...}} response client.chat.completions.create( modelos.environ.get(LLM_MODEL, gpt-4o-mini), messages[ {role: system, content: 你是一个严谨的项目管理助手只输出结构化结果。}, {role: user, content: prompt}, ], temperature0, ) raw_text response.choices[0].message.content.strip() # 实际项目中需要兼容模型额外输出 markdown 代码块的情况 if raw_text.startswith(): raw_text raw_text.strip() if raw_text.startswith(json): raw_text raw_text[4:] raw_text raw_text.strip() return json.loads(raw_text) if __name__ __main__: test_issue { title: 用户点击导出按钮后页面白屏, description: 在 Chrome 最新版本下复现控制台报错 TypeError: Cannot read property map of undefined } result classify_issue(test_issue[title], test_issue[description]) print(json.dumps(result, ensure_asciiFalse, indent2))运行方式export LLM_API_KEYyour-api-key export LLM_BASE_URLhttps://your-llm-gateway.example.com export LLM_MODELgpt-4o-mini python agent_demo/issue_classifier.py预期输出是一段 JSON例如{ category: bug, team: frontend }这段代码的核心价值不在于提示词写得多好而在于它构成了一个“最小可验证单元”。你可以准备几十条历史 issue人工标好正确答案然后批量跑这个脚本统计准确率。准确率达标之后再接入生产流程。2.3 这条规则背后的原因从工程角度看小任务意味着小风险、小排查范围、小评估成本。先让 Agent 在一个足够小的任务上稳定输出建立评估基线再逐步扩展。这比一开始就铺一个大而全的系统稳健得多。这里也想提醒一句Agent 的能力边界不是由模型参数决定的而是由你给它设计的“任务边界”决定的。明确边界是生产级 Agent 的第一步。3. 规则二设计为“有边界的协作者”不是“全自动的替代者”第二类常见的 Agent 项目失败是对自动化程度的错误预期。不少团队对 Agent 的设想是你告诉它一个目标它自己规划、自己执行、自己完成。听起来很美好但一旦涉及真实业务这种“全自动”模式会带来两个致命问题一是错误被自动放大模型只要在某个环节理解偏差后续所有步骤都会基于错误前提运行二是责任不清晰出问题之后你不知道该归咎于模型、工具、数据还是流程。Linear 团队的实践中更倾向于把 Agent 定位为“协作者”而不是“替代者”。它负责高效地完成确定性的、重复性的工作但关键节点必须由人来做决策和确认。3.1 人机协同的正确姿势Draft 模式所谓 Draft 模式就是让 Agent 先生成一份“草稿”而不是直接执行。例如在一个自动化生成周报的 Agent 中Agent 读取本周项目数据、筛选关键事件、生成周报内容。但它不会直接把周报发送到团队群里而是生成一份待确认的草稿由项目经理审核、修改、确认之后再发送。这个模式的好处很明显错误被限制在“草稿”范围内不会直接造成对外影响。同时每次人工确认的过程都成为一次隐式的标注数据收集你可以记录“Agent 生成了什么、人改了什么”这些数据后续可以用来优化 Prompt 或评估模型效果。3.2 用代码约束 Agent 的执行权限真正把“边界”落到代码层面需要引入执行权限控制。下面是一个简单但实用的设计# 文件路径agent_demo/action_guard.py from enum import Enum from dataclasses import dataclass from typing import Callable class ActionType(Enum): READ read WRITE write SEND send DELETE delete dataclass class Action: name: str action_type: ActionType handler: Callable require_approval: bool False class ActionGuard: 执行权限守卫 1. 只允许执行已注册的 Action 2. 写操作和对外发送操作默认需要人工审批 3. 所有执行记录写入审计日志。 def __init__(self): self._actions: dict[str, Action] {} self._audit_log: list[dict] [] def register(self, action: Action): self._actions[action.name] action def execute(self, action_name: str, context: dict, approved: bool False): action self._actions.get(action_name) if action is None: raise ValueError(fAction {action_name} 未注册拒绝执行。) if action.action_type in (ActionType.WRITE, ActionType.SEND, ActionType.DELETE): if not approved: # 实际项目这里会发起一个人工审批任务而不是简单抛异常 raise PermissionError(fAction {action_name} 需要人工审批后才能执行。) result action.handler(context) self._audit_log.append({ action: action_name, type: action.action_type.value, approved: approved, context: {k: v for k, v in context.items() if k ! secret}, }) return result这个类解决的核心问题是Agent 的“自由意志”被硬编码的规则约束住了。它可以建议做某事但真正落地执行时必须经过守卫。你可以把ActionGuard理解成 Agent 和真实世界之间的一道闸门。3.3 边界设计的程度判断边界也不是越严越好。如果每一步都需要人来确认Agent 的价值就消失了。这里的判断标准是风险等级只读操作不需要审批但需要记录。可回滚的写操作可以设置自动执行但要保留回滚快照。不可回滚或对外可见的写操作必须人工审批。删除操作无论什么场景都必须双人确认。这个分级思路在 Linear 团队的工程实践里也非常常见优先保证系统不做蠢事其次才是追求自动化效率。记住一个原则Agent 的能力越强边界就应该越清晰。4. 规则三工具注册与权限最小化是 Agent 的安全底座如果说“有边界的协作者”是设计理念那么工具注册与权限最小化就是落地这个理念的技术手段。Agent 的能力来自它可以调用工具。工具越强大潜在风险就越高。一个能读写文件、执行 Shell 命令、访问数据库、发送消息的 Agent本质上等于拥有了一个超级账号。如果这个超级账号没有约束一旦 Agent 被诱导执行恶意指令后果不堪设想。4.1 工具白名单与接口定义真正的生产级系统不会让 Agent 自己“发现”和“决定”能调什么工具。工具列表是预先注册好的白名单Agent 只能在这个白名单内选择。一个典型的工具注册配置长这样{ tools: [ { name: get_project_issues, description: 根据项目 key 查询未关闭的 issue 列表, type: read, endpoint: /api/projects/{project_key}/issues, parameters: { project_key: {type: string, required: true} } }, { name: update_issue_status, description: 更新 issue 状态, type: write, endpoint: /api/issues/{issue_id}/status, parameters: { issue_id: {type: string, required: true}, status: {type: string, enum: [todo, in_progress, done]} } }, { name: send_team_message, description: 发送团队消息, type: send, endpoint: /api/messages, parameters: { channel: {type: string, required: true}, content: {type: string, required: true} } } ] }在这个配置里每个工具都有清晰的类型标签。read类型可以自动执行write和send类型默认进入审批流。工具的参数也做了严格约束枚举值、必填项都在接口层定义清楚防止模型生成不合法的参数。4.2 最小权限原则最小权限原则不只是概念它落实到 Agent 系统上有几个具体操作第一Agent 服务本身的运行账号必须是一个受限账号。不要用 root 或管理员账号跑 Agent。很多线上事故本质上是 Agent 有了它本不该有的系统权限。第二数据库账号和 API Token 要做细粒度隔离。Agent 如果只需要读取某个项目的 issue 列表那它对应的 Token 就只有这个范围的读取权限不应该拥有整个组织的读写权限。第三输出要做校验。模型返回的“工具调用参数”不能直接透传给后端服务。在转发之前要按工具定义的 JSON Schema 做一次参数校验不合法就直接拒绝。4.3 Agent 与 MCP 的关系当前关于 Agent 工具调用MCPModel Context Protocol是一个绕不开的话题。你可以把 MCP 理解为“Agent 工具调用的标准接口协议”它定义了模型、客户端、服务端之间如何交换上下文、如何发现工具、如何调用工具。实际项目里是否引入 MCP 需要结合已有技术栈判断。如果你的工具生态复杂MCP 能降低集成成本但无论用不用 MCP工具白名单、参数校验、类型分级这几件事都必须自己落地。标准协议解决的是互联互通问题权限边界和安全约束永远是应用层的责任。5. 规则四可观测性与评估体系是迭代的前提不少 Agent 项目还存在一个隐蔽的问题上线了但你没有能力判断它“好不好”。传统的软件系统有明确的日志、监控、错误码出了问题可以快速定位。但 Agent 系统是在和模型交互模型输出具有不确定性。如果没有一套针对 Agent 的可观测性和评估体系你很快就会陷入一种状态好像系统在正常工作但你不能确定它什么时候会不正常也不能评估一次 Prompt 调整到底是变好了还是变差了。5.1 从“日志”到“轨迹”普通系统记录的是请求和响应Agent 系统需要记录的是“决策轨迹”。所谓轨迹就是这个 Agent 从收到用户请求开始中间经历了哪些推理步骤、调用了哪些工具、每个工具返回了什么结果、最终输出是什么、每一步花费了多少 Token 和时间。这个轨迹可以用结构化的方式记录{ request_id: req_20240601_001, user_intent: 请把 P2 的 issue 分配给我, trajectory: [ { step: 1, action: call_tool, tool: get_project_issues, params: {project_key: LINEAR, priority: P2}, result_summary: 返回 5 条 issue }, { step: 2, action: reasoning, content: 用户要求分配给自己需要先获取当前用户信息 }, { step: 3, action: call_tool, tool: assign_issue_to_user, params: {issue_ids: [ISS-103], user_id: user_42}, approved: true, result_summary: 分配成功 } ], final_output: 已将 LINEAR-103 分配给你, total_tokens: 842, latency_ms: 2300 }有了轨迹数据你才能回答两个核心问题这个 Agent 是怎么得到这个结论的如果结论错了错在哪一步5.2 建设回归评估集评估是 Agent 迭代的另一个基石。没有评估集就没有办法判断“新 Prompt 是否优于旧 Prompt”“新模型版本是否引入回归”。一个可落地的做法是每个 Agent 项目都维护一个“黄金评估集”里面放几百条带有标准答案的历史任务。每当你修改 Prompt、更换模型、调整工具定义就批量跑一遍评估集对比准确率、延迟、Token 消耗和失败率。# 文件路径agent_demo/evaluate.py import json from issue_classifier import classify_issue def load_golden_set(path: str) - list[dict]: with open(path, r, encodingutf-8) as f: return json.load(f) def evaluate(golden_set_path: str) - dict: golden_set load_golden_set(golden_set_path) total len(golden_set) correct 0 errors [] for item in golden_set: try: result classify_issue(item[title], item[description]) if result.get(category) item[expected_category]: correct 1 else: errors.append({ title: item[title], expected: item[expected_category], actual: result.get(category), }) except Exception as exc: errors.append({ title: item[title], error: str(exc), }) return { total: total, correct: correct, accuracy: round(correct / total, 4) if total else 0, errors: errors[:20], } if __name__ __main__: result evaluate(golden_set.json) print(json.dumps(result, ensure_asciiFalse, indent2))运行评估后关注的不只是准确率还要关注错误模式。如果错误的 issue 高度集中在某类描述上说明在这个领域需要补充 few-shot 示例或者工具参数定义需要调整。5.3 Demo 级与生产级的差异把是否具备可观测性和评估体系作为分界可以画出一条清晰的线对比维度Demo 级 Agent生产级 Agent输出记录只记录最终结果记录完整决策轨迹失败定位重跑一遍看结果回放轨迹定位出错步骤Prompt 修改人工观察几个用例回归评估集批量验证权限控制通常没有或很宽松分级审批 操作审计回滚能力通常没有写操作有快照和回滚安全测试通常没有包含恶意输入和边界测试从这个表格可以看得很清楚生产级 Agent 的复杂度不在于模型调用而在于围绕模型建立的整套工程防护和评测体系。6. 规则五用工作流和状态机约束流程而不是让模型自由发挥最后一条规则可能是区分“有趣 Demo”和“可靠产品”最明显的一条生产级 Agent 不能只有模型必须有一个确定性的业务流程骨架。很多人对 Agent 的想象是给它一个目标它能自主规划、自主执行、自主修正。但在真实生产环境里“自主规划”意味着不可预测的步骤、不可控的成本、不可复现的结果。真正可靠的 Agent 系统通常用工作流把大目标拆解成固定步骤每个步骤有明确输入、输出和校验模型只负责其中“需要智能”的部分。6.1 状态机控制流程用状态机管理 Agent 流程是一个有效的方式。例如一个“自动处理用户反馈并生成工单”的 Agent状态可以设计为INIT接收原始反馈CLASSIFY模型判断反馈类型DEDUPLICATE检查是否已有重复工单CREATE_TICKET创建工单写操作需审批NOTIFY通知责任人COMPLETED流程结束FAILED流程终止转人工状态之间的转移条件是明确的、确定性的模型不参与状态转移的决策。模型只负责在CLASSIFY阶段输出分类结果或者在CREATE_TICKET阶段生成工单描述。这样即使模型某一次输出错误它也无法跳出流程框架。# 文件路径agent_demo/feedback_workflow.py from enum import Enum from dataclasses import dataclass, field class State(Enum): INIT INIT CLASSIFY CLASSIFY DEDUPLICATE DEDUPLICATE CREATE_TICKET CREATE_TICKET NOTIFY NOTIFY COMPLETED COMPLETED FAILED FAILED dataclass class WorkflowContext: feedback_text: str category: str duplicate_of: str ticket_id: str state: State State.INIT history: list field(default_factorylist) class FeedbackWorkflow: def __init__(self): self.handlers { State.INIT: self._handle_init, State.CLASSIFY: self._handle_classify, State.DEDUPLICATE: self._handle_deduplicate, State.CREATE_TICKET: self._handle_create_ticket, State.NOTIFY: self._handle_notify, } def run(self, ctx: WorkflowContext) - WorkflowContext: while ctx.state not in (State.COMPLETED, State.FAILED): handler self.handlers.get(ctx.state) if handler is None: ctx.state State.FAILED break ctx handler(ctx) return ctx def _transition(self, ctx: WorkflowContext, next_state: State): ctx.history.append((ctx.state.value, next_state.value)) ctx.state next_state def _handle_init(self, ctx: WorkflowContext) - WorkflowContext: if not ctx.feedback_text.strip(): ctx.state State.FAILED return ctx self._transition(ctx, State.CLASSIFY) return ctx def _handle_classify(self, ctx: WorkflowContext) - WorkflowContext: # 实际项目中这里调用模型分类而不是硬编码 ctx.category bug if 报错 in ctx.feedback_text else feature self._transition(ctx, State.DEDUPLICATE) return ctx def _handle_deduplicate(self, ctx: WorkflowContext) - WorkflowContext: # 检查重复工单这里简化为固定值 ctx.duplicate_of self._transition(ctx, State.CREATE_TICKET) return ctx def _handle_create_ticket(self, ctx: WorkflowContext) - WorkflowContext: # 写操作需要经过审批 ctx.ticket_id TCK-20240601-001 self._transition(ctx, State.NOTIFY) return ctx def _handle_notify(self, ctx: WorkflowContext) - WorkflowContext: # 发送通知 self._transition(ctx, State.COMPLETED) return ctx这个示例演示了工作流骨架的做法。实际项目中你可以在CLASSIFY和CREATE_TICKET阶段调用模型同时把审批逻辑嵌入其中。状态机的价值在于Agent 的行为在宏观上是可预期的微观上才允许模型发挥。6.2 理解 Agent 与工作流的关系需要说明的是这里并不是否定“自主 Agent”方向。而是说自主性应该被限制在“给定约束内”。你可以让模型在分类时自由推理但你不能让模型决定“要不要创建工单”“要不要给用户发消息”。当前业界的 Agent 框架例如 LangGraph 等本质上也是在用图结构管理 Agent 的流程。你可以把状态机理解为一个简化版的流程控制用图管理则支持更复杂的条件分支和并行节点。但指导思想是一样的外部流程确定内部模型灵活。理解了这一点你才算真正理解了 Agent 架构。7. 常见问题与排查思路把 Agent 从 Demo 推向生产的过程中有些错误是大多数人都会遇到的。下面整理了一份排查清单供你参考问题现象可能原因排查方式解决方案Agent 调用了不该调用的工具工具白名单未生效或 Agent 被诱导使用其他工具查看决策轨迹检查工具注册列表是否完整收紧工具白名单禁止模型自由创建工具调用同一个输入在不同时间得到不同结果模型 temperature 过高或模型版本被更换检查模型配置和请求日志对确定性任务设置 temperature0固化模型版本Agent 执行了写操作但没有人工确认审批机制没有覆盖该写操作检查 ActionGuard 中的操作分级将不可回滚的写操作强制设为需审批提示词微调后效果变差缺少回归评估集无法及时发现回退对比历史评估结果建立黄金评估集每次改动后批量回归线上问题无法定位只记录了最终输出没有记录决策轨迹查看是否有 request_id 和轨迹日志为每次请求生成 request_id记录完整轨迹Agent 响应很慢多次模型调用串行或工具调用超时查看分步耗时对工具调用设置超时必要时并行化处理Agent 的调用凭证泄露密钥写死在代码或配置文件中扫描代码仓库和配置中心改用密钥管理服务定期轮换密钥这些问题的共同规律是绝大多数故障不是模型“笨”而是工程防护缺失。所以排查时先看流程和权限再看模型输出。8. 最佳实践与工程建议8.1 每个 Agent 项目必须有“评估集”无论你的业务是 issue 分类、周报生成、客服问答还是数据分析在上线之前都应该建立一个不少于 200 条标注数据的评估集。评估集不是一次性的它会随着业务变化持续维护。没有评估集的 Agent 项目本质上是在裸奔。8.2 配置与环境管理Agent 涉及模型、工具、权限、Prompt 多类配置。建议把配置分成三层全局配置、环境配置、业务配置。全局配置放模型地址、超时时间环境配置区分开发、测试、生产业务配置放 Prompt 模板、工具白名单、审批规则。所有配置都接入配置中心禁止改代码改配置。8.3 日志与审计Agent 的日志必须包含两个层面系统日志和决策日志。系统日志记录服务运行情况决策日志记录每轮 Agent 的轨迹。决策日志需要长期保留因为当你需要复盘一次线上事故时这些轨迹是唯一的证据。涉及生成内容的系统还要考虑内容安全。输出内容要经过合规过滤和敏感信息检测不能直接把模型原始输出透传给用户。8.4 回滚能力所有 Agent 的写操作都建议在业务层支持回滚。一种简单的做法是Agent 写操作前记录原始状态操作后保留变更快照。当人工审核发现问题时可以一键恢复。8.5 团队协作Agent 项目需要一个“模型 工程 业务”三方协作的团队结构。工程负责搭建边界和观测体系模型侧负责 Prompt 和评估业务侧负责定义“什么是对的”。三者缺一不可。很多项目失败就是因为在团队里没有明确这三方的职责。9. 总结与后续学习方向Linear 团队这套理念核心可以浓缩成一句话生产级 Agent 可控的流程 清晰的边界 完整的数据闭环。这 5 条规则值得按顺序落地从最小可验证任务开始建立评估基线。把 Agent 设计为需要人审的协作者而不是全自动替代者。用工具白名单和最小权限控制风险。用决策轨迹和回归评估集保障可观测性和可迭代性。用工作流或状态机约束整体流程让模型在框架内发挥。如果你正准备开始 Agent 开发建议不要急着选框架先找一个具体业务场景用最简单的方式把模型调用、工具调用、评估验证这条链路跑通。跑通之后你会自然地意识到Agent 开发的核心挑战不是模型不够聪明而是你能否用工程手段让“聪明”安全、稳定、可预期地对外输出。下一步值得深入的方向包括Agent 框架与编排引擎的原理对比、Agent Skills 与 MCP 工具协议的具体应用方式、Agent 安全测试方法论以及如何用轨迹数据持续迭代 Prompt。每个方向单独展开都足够写几篇长文。但无论深入哪个方向这套“先约束再扩展先评估再迭代”的思维框架都适用于所有生产级 Agent 项目。建议收藏等你真正开始做 Agent 工程化时再回来看一遍。