
这三个词经常被混着用,但它们的工程属性完全不同。
形态 | 谁做决策 | 控制流 | 典型场景 | 可靠性 |
|---|---|---|---|---|
Copilot | 人 | 人驱动,AI 建议 | 代码补全、写作辅助 | 高(人兜底) |
Workflow | 开发者(写死) | 预设 DAG / 状态机 | 固定业务流程、批处理 | 高(路径确定) |
Agent | 模型 | 模型运行时决定 | 开放任务、多步探索 | 低(需工程约束) |
关键区别在控制流由谁决定。Workflow 的每一步是开发者写死的,模型只在单步内工作;Agent 则是模型在运行时决定下一步调什么工具、走哪条分支、什么时候停。
这带来的直接后果是:Workflow 的行为可枚举、可测试、可预测;Agent 的行为不可枚举,只能靠评估集抽样逼近。 所以选择标准非常清晰:
现实中大量被包装成 Agent 的东西,其实是 Workflow。这不是退步,而是成熟团队的自觉——用确定性解决问题,比用自主性碰运气便宜得多、稳得多。
一句话原则:能写成流程的,就不要交给 Agent 自主决策。
抛开所有包装,一个 Agent 的核心就是一个循环:
观察状态 → 模型决定动作 → 执行工具 → 把结果写回状态 → 继续或终止它比普通 LLM 调用多的只有三样东西:工具、循环、状态。这三样东西各自带来一类新问题:
所以 Agent 工程的本质,就是围绕这三样东西设计约束。一个没有步数上限、没有工具权限控制、没有状态持久化的"Agent",只是一个碰巧会调用函数的聊天机器人。
很多人以为 Agent 的能力取决于模型,其实很大程度上取决于工具设计。模型再强,工具描述含糊、参数设计反人类、返回结果噪声巨大,Agent 也做不对事。
工具设计有几条硬经验:
1. 工具要"少而正交"。 十个功能重叠的工具会让模型选择困难。宁可少几个工具,也不要有两个语义相近的。工具的命名和描述要像给新人写文档——模型就是那个新人。
2. 参数要结构化、可校验。 用 JSON Schema 严格定义参数类型、枚举值、必填项。自由文本参数越少越好,因为那是幻觉的高发区。
3. 返回值要"信息密度高、噪声低"。 工具返回给模型的内容不是给人看的日志,而是模型的"观察"。返回一大坨无关字段,模型就会被淹没。返回结果应该是为决策服务的最小信息集。
4. 副作用工具要可幂等、可回滚。 发邮件、下单、删文件这类操作,一旦模型调错就不可逆。要么设计成幂等,要么加人工确认,要么提供撤销。
5. 工具失败要返回结构化错误,而不是抛异常。 模型需要知道"为什么失败",才能决定重试、换工具还是放弃。
一个工具定义骨架大致长这样:
# tools/search_docs.yaml —— 工具即契约
name: search_docs
description: 在企业知识库中检索文档。当需要事实依据时使用,不要凭记忆回答。
parameters:
type: object
properties:
query: { type: string, description: 检索关键词,尽量具体 }
top_k: { type: integer, default: 5, minimum: 1, maximum: 10 }
required: [query]
returns:
type: array
items: { doc_id: string, title: string, snippet: string, updated_at: string }
errors: [TIMEOUT, NO_RESULT, PERMISSION_DENIED]注意 description 里那句"不要凭记忆回答"——工具描述本身就是提示词,是引导模型正确使用工具最有效的位置,比在系统提示词里写十条规则都管用。
这是 Agent 工程里最容易被忽视、却最决定成败的一节。自主循环必须配一套"刹车系统"。
1. 步数与预算上限。 硬性限制最大步数、最大 token、最大工具调用次数、最大耗时。任一超限立即终止并返回中间结果。这是防止成本失控的第一道闸。
2. 显式终止条件。 不能只靠模型自己说"我完成了"。要定义可判定的完成条件,比如"必须调用了 submit 工具"或"输出满足某个 schema"。让模型决定"什么时候停"是最危险的放手。
3. 状态机约束关键节点。 对于有明确阶段的任务(如"检索→分析→起草→审核→提交"),用状态机约束每个阶段允许的动作集合。模型在阶段内自由,阶段间受控。这是把 Agent 和 Workflow 结合的最实用方式。
4. 中断与人工介入。 高风险动作(支付、外发、删除)前设置确认点。Agent 不是不能停,而是要能停在该停的地方。
5. 循环检测。 检测"同样的工具 + 同样的参数"重复调用,识别死循环并强制换策略或终止。
一段带预算和终止控制的最小循环骨架:
# agent_loop.py —— 有刹车的自主循环
def run(task, tools, budget=Budget(max_steps=12, max_cost=0.5)):
state = State(task=task, history=[])
while not budget.exhausted():
action = llm.decide(state, tools) # 模型决策
if action.type == "finish": # 显式终止
return validate(state, action.output)
if action.type == "ask_human": # 人工介入点
return suspend(state, action.question)
if state.is_repeating(action): # 循环检测
state.nudge("你已经重复调用,请换一种方法")
continue
result = tools.call(action, acl=state.user) # 带权限执行
state.record(action, result)
budget.consume(action)
return partial(state) # 超限返回中间结果这段代码的重点不在实现,而在那几个 if:终止、介入、防循环、预算。每一个都是给自主性装的刹车。没有这些的 Agent,本质上是个没有边界的 while 循环。
Agent 跑得越久,上下文越臃肿。把所有历史都塞进窗口,成本飙升、关键信息被淹没、模型开始"忘事"。记忆管理要分层:
核心手法是压缩与检索:把冗长的工具返回结果摘要成结论,把历史步骤归纳成"已做什么、得到什么",需要细节时再按需检索回来。Agent 的上下文应该是"工作台",不是"仓库"。
另外,状态要能持久化。Agent 跑到一半进程挂了、或者需要等人工审批,必须能从断点恢复。这就要求状态可序列化、可重放——这一点在长任务 Agent 里是硬需求。
"多 Agent 协作"是当前最热也最容易被滥用的概念。把任务拆给规划 Agent、执行 Agent、评审 Agent,听起来分工明确、能力倍增。
现实往往是:通信成本爆炸、错误在 Agent 之间传播放大、调试变成噩梦、成本翻几倍而效果提升有限。
多智能体真正有价值的场景其实很窄:
而如果只是"让流程更清晰",那用状态机或 Workflow 就能实现,没必要引入多 Agent 的复杂度。多智能体是分布式系统的复杂度,不是免费的午餐。
一条务实建议:先做单 Agent,把工具、状态、评估做扎实;只有在单 Agent 确实撞墙、且瓶颈明确是"并行"或"权限隔离"时,才拆多 Agent。
普通 LLM 应用评估"输入→输出";Agent 评估的是"输入→一串动作→最终结果"。这意味着:
评估集应当包含三类任务:典型任务(高频、路径清晰)、边界任务(工具缺失、信息不足、需要拒答)、对抗任务(诱导危险操作、提示注入)。
指标上除了任务成功率,还要盯:平均步数、平均成本、人工介入率、超预算率、危险动作拦截率。一个成功率高但平均要跑 30 步的 Agent,在生产里往往不可接受。
Agent 出错时,你不能只看到一句"任务失败"。你需要完整还原它每一步的决策:看到了什么状态、为什么选这个工具、工具返回了什么、下一步为什么这么走。
所以 Agent 系统必须内建轨迹记录(trace):每一步的输入状态、模型输出、工具调用与结果、耗时与成本,全部结构化记录,可按任务 ID 回放。
这不是可选项。没有轨迹的 Agent,调试基本靠猜,优化基本靠玄学。可回放性是 Agent 从玩具走向生产的分水岭。
普通 LLM 说错话,Agent 会做错事。它拿着工具,能发邮件、改数据库、调支付接口。安全等级必须相应提高:
Agent 的安全模型要按"它一定会被诱导做错事"来设计,而不是假设它总是听话。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。