我以为自己在用 Agent,结果发现只是把 GPT 调用了五次
我以为自己在用 Agent,结果发现只是把 GPT 调用了五次
上个月,一个做竞品分析的朋友跟我说,他们团队"做了一个 Agent,能自动拉数据、分析、出报告"。
我问他怎么实现的。他打开代码给我看——四个 call_gpt() 函数,用变量把上一步的输出塞进下一步的 Prompt,最后拼成一份 Word 文档。
我没有嘲笑他。因为六个月前,我自己也是这么干的,还觉得"这不就是 Agent 吗?"
这不是 Agent。这是一条装扮成 Agent 的 Prompt 链。
两者的区别,不在于调用了几次 API,也不在于有没有用上什么框架,而在于一个根本问题:"下一步做什么",是你决定的,还是 AI 自己决定的?
这个控制权的归属,才是 Prompt 链和 Agent Harness 的真正分水岭。
---
第一章:打碎"伪 Agent"的幻觉
先来看一张对比图,把两种模式的控制流拉开:
graph TD
subgraph Prompt链(你在指挥)
A[你写Step1 Prompt] --> B[LLM执行]
B --> C[你取出输出]
C --> D[你写Step2 Prompt]
D --> E[LLM执行]
E --> F[你取出输出]
F --> G[你写Step3 Prompt]
end
subgraph Agent Harness(AI在决策)
H[你给目标+工具集] --> I[LLM决定:先用哪个工具?]
I --> J{执行结果是否满足?}
J -- 否 --> K[LLM自主选择下一步]
K --> J
J -- 是 --> L[输出结果]
end
左边的 Prompt 链,控制流在你手里:你决定第一步做什么,你决定第二步做什么,你把每一步的输入和输出都手动串联起来。AI 只是在每个节点上"执行命令"。
右边的 Agent Harness,你只告诉 AI 一个目标和一个工具箱。AI 自己决定先用哪个工具、结果不对的时候换哪条路、什么时候停下来说"完成了"。
大白话版:Prompt 链是你写好了乐谱,AI 照着弹;Agent Harness 是你告诉 AI "给我演奏一首适合今晚气氛的曲子",它自己决定弹什么、怎么弹。
大多数人卡在 Prompt 链这一层,不是因为懒,而是因为它在简单任务上真的够用,甚至更好控制。问题在于,当任务开始出现不确定性——中途需要判断、需要重试、需要根据上下文改变策略——Prompt 链就开始露出它的脆弱性了。
---
第二章:同一个任务,两种跑法
我选了一个在实际工作中高频出现的任务来做对比实验:
任务描述:从一份竞品报告 PDF 中提取关键财务指标 → 联网补充该公司最新季度数据 → 生成结构化摘要并对每条数据标注置信度(高/中/低)。这个任务的"坏"之处在于:PDF 质量参差不齐,有时候数字被扫描成图片;联网搜索结果不一定准确;置信度标注需要模型自己判断信息来源的可靠性。每一步都有可能出岔子。
方案一:Prompt 链版本
import openai
import pdfplumber
def extract_from_pdf(pdf_path):
with pdfplumber.open(pdf_path) as pdf:
text = "\n".join([p.extract_text() for p in pdf.pages if p.extract_text()])
prompt = f"""
从以下竞品报告文本中提取关键财务指标,
包括:营收、净利润、毛利率、用户数。
以JSON格式返回。
文本:{text[:3000]}
"""
response = client.chat.completions.create(
model="gpt-4o", messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
def search_latest_data(company_name, metrics):
prompt = f"""
请搜索{company_name}最新季度的以下指标:{metrics}
返回数据及来源URL。
"""
# 假设这里调用了联网搜索工具
response = client.chat.completions.create(...)
return response.choices[0].message.content
def generate_summary(extracted, latest):
prompt = f"""
综合以下两份数据,生成结构化摘要,
并为每条数据标注置信度(高/中/低):
PDF提取数据:{extracted}
最新联网数据:{latest}
"""
response = client.chat.completions.create(...)
return response.choices[0].message.content
主流程——你在手动串联每一步
extracted = extract_from_pdf("competitor_report.pdf")
latest = search_latest_data("某公司", extracted)
summary = generate_summary(extracted, latest)
关键问题:如果 extract_from_pdf 返回的 JSON 格式不对,search_latest_data 直接拿着错误数据继续跑,最终输出一份"自信满满的垃圾"。整条链没有任何自我纠错能力。
方案二:Agent Harness 版本(以 Flue 框架为例)
from flue import Agent, tool
@tool
def extract_pdf_metrics(pdf_path: str) -> dict:
"""从PDF中提取财务指标,失败时返回错误信息"""
...
@tool
def web_search(query: str) -> list[dict]:
"""联网搜索,返回结果列表和来源"""
...
@tool
def validate_and_score(data: dict) -> dict:
"""验证数据一致性并打置信度分"""
...
agent = Agent(
goal="分析竞品报告PDF,补充最新数据,生成带置信度的结构化摘要",
tools=[extract_pdf_metrics, web_search, validate_and_score],
model="gpt-4o",
max_iterations=10
)
result = agent.run(input={"pdf_path": "competitor_report.pdf"})
关键差异:你只告诉 Agent 目标是什么、有哪些工具可用。Agent 自己决定:先提取 PDF,发现格式有问题,主动调用 validate_and_score 检查,发现某个字段缺失,再次调用 web_search 补充,最后整合输出。
实验结果对比
我用同一份 PDF(故意选了一份有扫描图片页的低质量报告)跑了两遍,接口统一走的是 [api.884819.xyz](https://api.884819.xyz)——国内直连,支持 Function Calling 和 Streaming,两种方案在同一接口环境下跑,排除了模型差异的干扰。
| 指标 | Prompt 链 | Agent Harness | | 任务完成率(10次测试) | 60% | 90% | | 平均执行步骤数 | 3(固定) | 5.2(动态) | | Token 消耗(平均) | 约 4,200 | 约 6,800 | | 出错后自动恢复次数 | 0(需人工重启) | 平均 1.8 次 | | 输出质量(人工评分 1-5) | 3.1 | 4.3 |⚠️ 注意:Agent Harness 的 Token 消耗明显更高(约多 60%),这是它自主决策的代价。没有免费的午餐。
---
第三章:三个维度,说清本质差异
① 决策权:静态路由 vs 动态规划
Prompt 链的"路由"是你在写代码时就固定好的:Step1 → Step2 → Step3,顺序不变。
Agent Harness 的路由是运行时动态生成的。AI 在每一步之后都会问自己:"现在的状态,下一步最合理的行动是什么?"
大白话:Prompt 链是地铁,只走固定线路;Agent Harness 是导航软件,实时根据路况重新规划。② 错误恢复:人工重试 vs 自主回溯
Prompt 链出错时的典型行为:卡在某一步,或者带着错误数据继续往下跑,最终输出一个"看起来正常但内容有问题"的结果。你不看输出内容,根本不知道哪里出了问题。
Agent Harness 出错时:AI 会识别到工具返回了异常结果,自主选择"重试这一步"或"换一个工具解决同样的问题",并在最终输出里标注"这一步经过了重试"。
大白话:Prompt 链出错像多米诺骨牌,一倒全倒;Agent Harness 出错像有人在玩积木,一块没搭好,自己换个方向再来。③ 工具调用粒度:预定义序列 vs 按需组合
Prompt 链里,工具的调用顺序是你硬编码的。就算某一步的结果已经足够好,它也会老老实实把后面的步骤全跑一遍。
Agent Harness 里,AI 会根据当前状态决定"这个工具现在有没有必要调"。如果 PDF 提取结果已经很完整,它可能直接跳过联网搜索,节省 Token。
大白话:Prompt 链是全套套餐,不管你饿不饿都得上;Agent Harness 是点单制,需要什么点什么。---
第四章:要不要切换?给你一个决策树
不是所有任务都值得用 Agent Harness。 这一点必须说清楚。你的任务步骤数 > 3 步?
├── 否 → 用 Prompt 链,简单可控,别过度设计
└── 是 ↓
每一步的输入是否高度依赖上一步的"判断结果"(而不只是"输出内容")?
├── 否 → Prompt 链仍然够用
└── 是 ↓
出错的代价是什么?
├── 低(重跑一次无所谓)→ Prompt 链 + 简单重试逻辑
└── 高(出错影响业务决策)↓
你能接受 Token 消耗增加 50-100% 吗?
├── 否 → 优化 Prompt 链,或手动加检查点
└── 是 → 切换 Agent Harness,值得
一句话判断标准:如果你的 Prompt 链里有任何一个地方,你每次运行完都要手动检查、手动修正、手动决定"要不要重跑"——那就是你需要 Agent Harness 的信号。
明确不推荐切换的场景:
- 任务步骤少于 3 步且路径固定
- 对 Token 成本极度敏感
- 团队没有 Agent 调试经验(调试成本会超过收益)
- 输出格式有严格约束(Agent 的自由度有时候会带来格式不稳定)
---
第五章:上手成本和坑——用了一段时间之后说真话
配置复杂度
Flue 的 Agent Harness 上手门槛不算高,用 @tool 装饰器定义工具、给 Agent 传目标和工具列表,基本配置十几行搞定。
Token 消耗
这是最现实的问题。Agent 每次决策都需要把当前状态、可用工具列表、历史步骤全部塞进上下文,Token 消耗随步骤数线性增长,有时候甚至是指数增长。
实验数据里,Agent Harness 的 Token 消耗比 Prompt 链多了约 60%。在高频调用场景下,这个差异会直接体现在账单上。
应对方案:合理设置max_iterations,避免 Agent 陷入无限循环;对历史步骤做摘要压缩,控制上下文长度。
调试可观测性
这是目前最大的痛点,也是我接下来最想聊的话题。
Prompt 链出错,你能精确定位到哪一行代码、哪一个 Prompt 有问题。Agent Harness 出错,你只知道"最终结果不对",但 Agent 中间走了哪条路、在哪个节点做了错误的决策——这些信息默认是不透明的。
Flue 提供了基础的步骤日志,但离真正的"可观测性"还有距离。你能看到 Agent 调用了哪些工具、每步的输入输出,但很难追问"它为什么在这里选择了这个工具而不是那个"。
这个问题在简单任务上无所谓,但一旦你的 Agent 开始跑复杂的多步骤任务,"我不知道它为什么这么决策"会让你非常不安。
结论:Agent Harness 不是银弹。在对的场景——任务复杂、路径不确定、需要自主容错——它是降维打击。在错的场景,它只是一个更贵、更难调试的 Prompt 链。
---
写在最后
回到开头那个问题:你现在手上的那个 Prompt 链,有没有一个地方你每次都要手动干预?
如果有,那就是你需要 Agent Harness 的信号。不是因为 Agent 更"先进",而是因为那个需要手动干预的地方,本质上是一个需要"判断"的节点——而判断,正是 Agent 存在的意义。
从 Prompt 链升级到 Agent Harness,不是技术信仰的跳跃,是对任务复杂度的务实响应。
---
不过,用了 Agent Harness 之后,我发现了一个更难的问题:当 Agent 开始自主决策,你怎么知道它走的路径是对的?
Prompt 链出错,你能 debug;Agent 出错,你在 debug 一个"黑盒"。可观测性,才是多 Agent 系统真正的硬骨头。
下一篇我会专门拆这个问题——怎么给 Agent 的每一步决策加上可追溯的日志,用什么工具能让 Agent 的"思考过程"变得透明,以及当 Agent 走了一条奇怪的路径时,你如何在事后还原它的决策逻辑。
如果你已经在用 Agent Harness,这篇文章可能会帮你睡得更安稳一点。
---
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。 新用户注册即送体验token。 国产模型(Deepseek/千问等)完全免费,无月租,按量付费,国内直连:[api.884819.xyz](https://api.884819.xyz)#AI Agent #Prompt工程 #LLM开发 #Agent框架 #AI教程 #8848AI #人工智能 #大模型应用