AI Agent 解决的不是“怎么写代码”,而是“谁来做决策”
AI(Artificial Intelligence,人工智能)Agent、传统编程和 Workflow 工作流经常被放在一起比较。它们都能完成任务,也都可以调用外部系统,比如查询天气、读取数据库、生成文件、发送消息。真正的差异不在工具本身,而在任务执行过程中由谁决定下一步做什么。
一句话概括:
传统编程和 Workflow 是人提前把路径设计好,程序按路径执行;AI Agent 是人给出目标,模型根据当前状态动态决定路径。
这个区别会直接影响开发方式、维护成本、适用场景和用户体验。
| 维度 | 传统编程 | Workflow 工作流 | AI Agent |
|---|---|---|---|
| 决策者 | 程序员 | 流程设计者 | 大模型 |
| 执行路径 | 写死在代码里 | 固定在流程图里 | 运行时动态生成 |
| 输入方式 | 参数、接口、配置 | 表单、节点配置 | 自然语言目标 + 上下文 |
| 适合场景 | 规则明确、结果可控、性能要求高 | 流程清晰、步骤固定、需要可视化编排 | 目标明确但路径不固定、输入多变、需要探索 |
| 修改成本 | 改代码、测试、部署 | 改流程、测试、发布 | 调整提示词、工具、约束,必要时改代码 |
| 主要风险 | 规则覆盖不全 | 流程膨胀、分支复杂 | 不确定性、可控性、评估难度 |
传统编程、Workflow 和 Agent 不是简单的替代关系。更准确地说,它们适合解决不同确定性的问题。
确定性越强,越适合代码;不确定性越强,越需要 Agent。
flowchart LR
A[任务需求] --> B{路径是否明确?}
B -- 非常明确 --> C[传统编程]
B -- 基本明确但需要编排 --> D[Workflow 工作流]
B -- 目标明确但路径不确定 --> E[AI Agent]
C --> C1[高可控性<br/>高性能<br/>工程化成熟]
D --> D1[可视化流程<br/>节点复用<br/>适合业务编排]
E --> E1[动态决策<br/>自然语言交互<br/>适合复杂开放任务]
传统编程:人把所有判断提前写进代码
传统编程的基本模式是:程序员先理解需求,再把业务规则转换成代码。程序运行时不会“思考”,它只会按照已经写好的条件、循环、函数调用执行。
假设要做一个“根据天气推荐穿衣”的功能,传统代码通常会这样写:
def get_weather_recommendation(city: str) -> str:
weather = query_weather_api(city)
temperature = weather["temperature"]
condition = weather["condition"]
if temperature < 10:
return "建议穿厚外套"
elif temperature < 20:
return "建议穿薄外套"
elif temperature < 25:
return "建议穿长袖"
else:
return "建议穿短袖"
这段代码清晰、稳定、便宜,也很容易测试。只要需求是“按照温度区间返回固定建议”,传统编程就是合适的方案。
问题出现在需求变复杂以后。
例如用户可能会问:
- “北京今天适合穿什么?我晚上还要骑车。”
- “明天去杭州出差,上午开会、晚上散步,要不要带外套?”
- “帮我查天气,结合紫外线和降雨情况,给一个适合通勤的建议,并保存成文件。”
如果仍然完全依赖传统编程,就需要不断增加规则:
def get_weather_recommendation(city: str, user_profile: dict) -> str:
try:
weather = query_weather_api(city)
except Exception:
return "天气查询失败,请稍后再试"
temperature = weather.get("temperature")
condition = weather.get("condition")
wind_level = weather.get("wind_level")
uv_index = weather.get("uv_index")
rain_probability = weather.get("rain_probability")
if temperature is None or condition is None:
return "天气数据不完整,无法给出建议"
suggestions = []
if temperature < 10:
suggestions.append("穿厚外套")
elif temperature < 20:
suggestions.append("穿薄外套")
elif temperature < 25:
suggestions.append("穿长袖")
else:
suggestions.append("穿短袖")
if rain_probability and rain_probability > 60:
suggestions.append("带伞")
if wind_level and wind_level >= 4:
suggestions.append("注意防风")
if uv_index and uv_index >= 7:
suggestions.append("注意防晒")
if user_profile.get("commute") == "bike":
suggestions.append("骑车时建议多加一件防风衣物")
return ",".join(suggestions)
代码还能继续扩展,但每新增一种情况,都需要有人提前想到,并把规则写进去。传统编程的强项和弱点都在这里:
| 特点 | 说明 |
|---|---|
| 可控 | 每个分支都由代码决定,结果容易解释 |
| 可测 | 输入输出明确,方便写单元测试 |
| 性能稳定 | 不需要大模型推理,延迟和成本可控 |
| 扩展依赖开发 | 新规则、新异常、新需求通常要改代码 |
| 难处理开放输入 | 用户自然语言越自由,规则越容易膨胀 |
所以,传统编程适合规则稳定、边界清晰、需要强控制的系统,比如订单状态流转、支付扣款、库存扣减、权限校验、风控拦截等。
Workflow:把代码里的路径变成可视化流程
Workflow 工作流把任务拆成多个节点,再用连线定义执行顺序。它比纯代码更直观,业务人员或低代码平台用户也能理解流程结构。
天气推荐功能可以被设计成这样:
flowchart TD
A[开始] --> B[输入城市]
B --> C[调用天气 API]
C --> D{温度区间}
D -- 小于 10℃ --> E[推荐厚外套]
D -- 10℃ 到 20℃ --> F[推荐薄外套]
D -- 20℃ 到 25℃ --> G[推荐长袖]
D -- 大于 25℃ --> H[推荐短袖]
E --> I[返回结果]
F --> I
G --> I
H --> I
I --> J[结束]
Workflow 的价值在于“流程显性化”。它把原本散落在代码里的步骤、条件、动作放到流程图中,便于查看、调整和复用。
常见 Workflow 节点包括:
| 节点类型 | 作用 |
|---|---|
| 输入节点 | 接收用户参数、表单数据或上游事件 |
| 调用节点 | 调用 API(Application Programming Interface,应用程序编程接口)、数据库、函数 |
| 条件节点 | 根据字段值选择不同分支 |
| 转换节点 | 格式化数据、提取字段、拼接文本 |
| 人工审核节点 | 等待人工确认后继续执行 |
| 输出节点 | 返回结果、发送通知、写入系统 |
Workflow 比传统代码更适合业务流程编排。例如审批流、客户线索分配、通知发送、数据同步、报表生成,都可以用 Workflow 表达。
但它的本质仍然是“固定路径”。
如果用户突然提出:“查天气后,如果今天下雨就把建议保存到文件;如果不下雨就只返回文字;如果天气接口失败,就换一个数据源;如果两个数据源都失败,就根据历史天气给保守建议。”流程图会迅速变复杂:
flowchart TD
A[开始] --> B[调用天气 API A]
B --> C{是否成功}
C -- 是 --> D{是否下雨}
C -- 否 --> E[调用天气 API B]
E --> F{是否成功}
F -- 是 --> D
F -- 否 --> G[查询历史天气]
G --> H[生成保守建议]
D -- 下雨 --> I[生成穿衣建议]
I --> J[写入文件]
D -- 不下雨 --> K[生成穿衣建议]
J --> L[返回结果]
K --> L
H --> L
这种流程可以画出来,也可以运行,但维护成本会随着分支数量快速上升。尤其当流程节点很多、异常路径很多、业务变化频繁时,Workflow 很容易变成“可视化的复杂代码”。
Workflow 的典型优缺点如下:
| 优点 | 代价 |
|---|---|
| 流程直观,便于沟通 | 分支多了以后图会很复杂 |
| 节点可复用,适合标准流程 | 动态调整能力有限 |
| 配置门槛低于写代码 | 复杂逻辑仍然需要脚本或函数 |
| 适合审批、通知、同步等确定流程 | 不适合开放式、多轮探索任务 |
Workflow 不是没有 AI 能力。很多 Workflow 平台也可以加入大模型节点,比如“调用模型总结文本”“调用模型分类用户意图”。但只要流程路径仍然由人提前画好,它本质上还是 Workflow,而不是 Agent。
AI Agent:给目标,不固定路线
AI Agent 的核心变化是:不再要求人提前写出完整路径,而是让大模型在运行过程中根据目标、上下文和工具反馈决定下一步动作。
一个典型 Agent 至少包含四部分:
| 组成部分 | 作用 |
|---|---|
| 大模型 | 理解目标、分析状态、决定下一步 |
| Prompt(提示词) | 约束角色、目标、规则、输出格式 |
| Tools(工具) | 提供外部能力,比如查天气、读文件、写数据库 |
| Memory / Context(记忆 / 上下文) | 保存任务历史、用户偏好、中间结果 |
Agent 的运行过程通常不是一次调用完成,而是一个循环:观察当前状态,思考下一步,调用工具,读取结果,再继续判断。
flowchart TD
A[用户给出目标] --> B[Agent 理解任务]
B --> C[选择下一步动作]
C --> D{需要调用工具吗?}
D -- 是 --> E[调用工具]
E --> F[观察工具结果]
F --> G{目标是否完成?}
G -- 否 --> C
G -- 是 --> H[生成最终结果]
D -- 否 --> H
这种模式和 ReAct 有关。ReAct 是 Reasoning and Acting 的缩写,可以理解为“推理 + 行动”的循环。模型不只是生成答案,还会根据任务需要调用工具,并根据工具返回结果继续推理。
同样是天气穿衣任务,用户可以直接说:
帮我查一下北京今天的天气,结合通勤场景给穿衣建议,然后保存到文件。
Agent 不需要人提前画出“查天气 -> 判断温度 -> 生成建议 -> 写文件”的固定流程。它可以根据任务自己规划:
sequenceDiagram
participant U as 用户
participant A as Agent
participant W as 天气工具
participant R as 建议生成工具
participant F as 文件工具
U->>A: 查询北京天气,给通勤穿衣建议并保存
A->>A: 分析目标,拆分任务
A->>W: 查询北京今日天气
W-->>A: 返回温度、降雨、风力等信息
A->>R: 根据天气和通勤场景生成建议
R-->>A: 返回穿衣建议
A->>F: 写入文件
F-->>A: 返回保存路径
A-->>U: 返回建议和文件位置
如果天气工具失败,Agent 可以决定换一个工具;如果用户补充“我晚上要骑车”,Agent 可以把这个新条件纳入判断;如果文件写入失败,Agent 可以尝试换路径、返回可复制文本,或者询问用户是否继续。
这就是 Agent 和 Workflow 的关键差异:Workflow 的异常路径需要提前设计,Agent 的异常处理可以在运行时根据情况选择。
三者真正的分界线:决策权
判断一个系统是传统编程、Workflow 还是 Agent,不要只看它有没有调用大模型,而要看“谁决定下一步”。
flowchart LR
A[输入需求] --> B{谁决定执行路径?}
B -- 代码中的 if/else/策略类 --> C[传统编程]
B -- 预先配置的流程图和节点连线 --> D[Workflow]
B -- 大模型根据上下文动态选择 --> E[AI Agent]
很多系统会混合使用这三种方式。例如一个客服系统可能是这样的:
- 订单查询、退款规则、权限校验用传统代码;
- 工单流转、人工审核、消息通知用 Workflow;
- 用户意图理解、多轮追问、复杂问题处理用 Agent。
这不是冲突,而是合理分工。关键是不要把所有问题都塞给 Agent,也不要用固定流程硬扛开放式任务。
为什么 Agent 更适合开放式任务
Agent 的优势来自大模型的语言理解、推理和工具选择能力。它特别适合目标明确但路径不确定的问题。
例如:
帮我分析这个项目为什么启动失败,能改就改,改完跑一下测试。
这个任务很难提前写成固定流程,因为 Agent 可能需要:
- 查看错误日志;
- 判断是依赖问题、配置问题还是代码问题;
- 打开相关文件;
- 修改配置或代码;
- 执行测试命令;
- 根据新错误继续排查;
- 直到成功或无法继续时给出解释。
这个过程天然适合循环式决策:
flowchart TD
A[目标:修复项目启动失败] --> B[读取错误日志]
B --> C[分析可能原因]
C --> D[选择工具或文件]
D --> E[执行修改或命令]
E --> F[观察结果]
F --> G{问题解决了吗?}
G -- 否 --> C
G -- 是 --> H[返回修复说明]
如果用传统编程实现,需要提前枚举大量错误类型和修复方式;如果用 Workflow 实现,需要画出大量分支。Agent 则可以根据实际错误现场动态选择路径。
这也是 Coding Agent 能快速被感知到价值的原因:写代码、查日志、改配置、运行命令、根据结果继续调整,本身就是一个动态决策过程。
Agent 不是万能替代品
Agent 的能力来自动态决策,也因此带来不确定性。对于一些要求严格一致、可审计、低延迟、低成本的场景,传统编程仍然更合适。
| 场景 | 更推荐的方式 | 原因 |
|---|---|---|
| 支付扣款 | 传统编程 | 金额、状态、事务必须严格准确 |
| 库存扣减 | 传统编程 | 需要强一致性和并发控制 |
| 审批流转 | Workflow | 流程明确,需要可视化追踪 |
| 定时数据同步 | Workflow / 传统编程 | 步骤固定,可重复执行 |
| 智能客服多轮沟通 | Agent + 代码兜底 | 用户表达多变,需要理解上下文 |
| 自动排查故障 | Agent | 路径不固定,需要根据结果继续探索 |
| 代码辅助开发 | Agent | 需要读文件、改代码、运行测试的循环 |
| 既有系统增加 AI 摘要能力 | 代码 + Tool Calling | 只需在固定位置调用模型,不必引入完整 Agent |
一个常见误区是:只要系统调用了大模型,就叫 Agent。实际上,如果系统只是固定地把用户输入发给模型,再把模型结果返回,这更像“AI 功能调用”;如果系统按固定流程调用多个模型节点,那仍然是 Workflow;只有当模型参与决定下一步动作、工具选择和任务推进时,才接近 Agent。
代码 + Tool Calling 适合增强既有系统
Tool Calling 指让大模型按照约定格式调用外部函数或接口。它可以把模型接入已有业务系统,同时保留代码的控制权。
例如,一个订单系统可以让模型识别用户意图,但真正的订单查询仍然由后端代码执行:
tools = [
{
"name": "query_order",
"description": "根据订单号查询订单状态",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "订单号"
}
},
"required": ["order_id"]
}
}
]
user_message = "帮我查一下订单 202606070001 到哪了"
# 大模型识别出需要调用 query_order,并提取 order_id
tool_call = model.chat(user_message, tools=tools)
if tool_call.name == "query_order":
result = query_order(order_id=tool_call.arguments["order_id"])
answer = model.chat(f"订单查询结果是:{result},请用自然语言回复用户")
这种方式很适合给既有系统增加 AI 能力,因为核心流程仍然由代码控制,大模型负责理解语言、提取参数、生成自然语言回复。
它和 Agent 的区别在于:代码仍然决定“什么时候调用什么工具”。Agent 则会在多个步骤中持续决定下一步。
flowchart LR
A[用户输入] --> B[大模型理解意图]
B --> C[代码判断可调用工具]
C --> D[业务系统执行]
D --> E[大模型组织回复]
E --> F[返回用户]
如果业务目标只是“让用户用自然语言操作已有功能”,代码 + Tool Calling 往往比完整 Agent 更稳定,也更容易上线。
Workflow 适合把固定业务流程产品化
Workflow 的价值不是“比代码更聪明”,而是“比代码更容易配置流程”。当流程本身稳定,只是节点较多、参与角色较多、需要可视化管理时,Workflow 很合适。
例如报销审批:
flowchart TD
A[员工提交报销] --> B{金额是否超过 5000}
B -- 否 --> C[直属主管审批]
B -- 是 --> D[部门负责人审批]
C --> E[财务复核]
D --> E
E --> F{材料是否完整}
F -- 是 --> G[打款]
F -- 否 --> H[退回补充材料]
这个流程并不需要 Agent 动态规划。审批路径是组织制度决定的,不能让模型自由发挥。即使加入 AI,也更适合放在某些节点里,例如自动检查发票、总结申请理由、识别异常金额。
Agent 适合做新交互入口
Agent 更像一个“任务执行入口”。用户不需要理解系统内部有哪些按钮、页面和流程,只需要描述目标。
传统软件通常要求用户适应产品结构:
打开页面 -> 找入口 -> 填表单 -> 点按钮 -> 看结果 -> 再切换页面 -> 再操作
Agent 交互则更接近:
说明目标 -> Agent 拆解任务 -> 调用工具 -> 处理中间问题 -> 返回结果
这种差异会带来明显的新体验,尤其适合复杂软件、专业工具和跨系统任务。例如:
- “把这个会议录音整理成纪要,并把待办事项同步到任务系统。”
- “检查这个代码仓库有没有明显的安全风险,按严重程度列出来。”
- “根据最近 30 天销售数据,找出异常波动并生成分析报告。”
- “帮我规划一条三天出差行程,考虑天气、交通和会议地点。”
这些任务都不是单个按钮能完成的,也不适合提前画出所有路径。Agent 的价值在于把多个工具、多个步骤和多轮判断组合起来。
选择方案时看三个问题
技术选型可以从三个问题开始。
1. 任务路径是否稳定?
如果路径稳定,代码或 Workflow 更合适;如果路径会根据中间结果不断变化,Agent 更合适。
| 路径特征 | 推荐方式 |
|---|---|
| 固定输入、固定处理、固定输出 | 传统编程 |
| 固定步骤、多角色参与、需要可视化 | Workflow |
| 步骤依赖中间结果,无法提前穷举 | Agent |
2. 错误代价是否很高?
如果错误代价高,比如支付、权限、医疗诊断、法律判断,不能完全依赖 Agent 自主决策。更稳妥的方式是让 Agent 做辅助分析,关键动作交给代码校验或人工确认。
flowchart TD
A[Agent 给出建议] --> B[规则校验]
B --> C{是否低风险?}
C -- 是 --> D[自动执行]
C -- 否 --> E[人工确认]
E --> F[执行或拒绝]
3. 用户是否需要感知 AI 驱动的新体验?
如果只是给已有系统增加一个“智能摘要”“自然语言查询”“自动分类”,不一定需要完整 Agent。固定流程里嵌入模型调用就够了。
如果目标是让用户用自然语言完成复杂任务,并且系统需要自己拆解步骤、选择工具、处理异常,就应该考虑 Agent。
工程落地时的边界设计
Agent 要进入真实系统,不能只依赖“让模型自己想办法”。需要给它清晰边界。
| 设计点 | 作用 |
|---|---|
| 工具白名单 | 限制 Agent 能调用哪些能力 |
| 参数校验 | 防止错误参数进入业务系统 |
| 权限控制 | 不同用户只能执行授权动作 |
| 中间步骤记录 | 便于调试、审计和回放 |
| 超时与步数限制 | 避免 Agent 无限循环 |
| 人工确认 | 高风险操作必须确认 |
| 结果评估 | 判断 Agent 是否真的完成任务 |
一个更安全的 Agent 架构通常是“大模型决策 + 工具层约束 + 业务系统校验”。
flowchart TD
A[用户目标] --> B[Agent Planner]
B --> C[工具选择]
C --> D[工具网关]
D --> E{权限与参数校验}
E -- 通过 --> F[业务工具 / 外部 API]
E -- 拒绝 --> G[返回错误原因]
F --> H[工具结果]
H --> B
B --> I[最终回复]
Agent 可以决定“想做什么”,但系统必须控制“允许做什么”。这条边界非常重要。
一个实用判断标准
可以用一句话判断该选哪种方案:
能提前写清楚规则,就用代码;能提前画清楚流程,就用 Workflow;只能描述目标、路径需要运行时探索,就用 Agent。
三种方式的关系可以这样理解:
| 方式 | 本质 | 最适合解决 |
|---|---|---|
| 传统编程 | 人把规则写成代码 | 确定性计算和强控制业务 |
| Workflow | 人把步骤画成流程 | 标准化业务编排 |
| AI Agent | 模型根据目标动态决策 | 开放式、多步骤、不确定任务 |
Agent 的核心价值不是替代所有代码,而是把 AI 从“被调用的能力”提升为“参与决策的执行者”。当任务需要理解自然语言、处理不确定性、根据反馈调整策略时,Agent 会比固定程序和固定流程更自然;当任务要求严格确定、低风险、强一致时,代码和 Workflow 仍然是更稳的基础。