Skip to content

Agent 开发常见误区 ​

前面我们已经从 Agent 的基本概念,一直学到 Tool、Context、Agent Loop,再亲手实现了最小 Agent 和 Coding Agent。

真正开始做项目以后,会发现很多问题并不是“不会写代码”,而是一些设计从一开始就错了。

这一篇我们不再增加新的概念,而是把我们后续真实 Agent 开发中常见的误区提前总结出来。

误区一:Agent 出问题,第一个反应就是换模型、改 Prompt ​

Agent 回答不对,很多人的第一反应是:

是不是模型不够强?

然后换一个更大的模型。

还不行,就继续修改 System Prompt:

“请认真思考。”

“请严格按照要求执行。”

“在执行之前务必检查结果是否正确。”

Prompt 越写越长,效果却不一定真的变好。

原因其实很简单:Agent 的问题并不一定发生在模型这一层。

要不然 Harness 这个概念也不会提出来(如果你不懂这个Harness也没关系,后续我们会讲)。

例如模型想读取项目配置,却发现 read 的 Tool Description 根本没有说明路径应该怎么传;模型拿到了搜索结果,但真正有用的信息已经被大量无关 Context 淹没;Tool 明明执行失败,Runtime 却返回了一段看起来像成功的信息。

这些情况下,即使换一个更强的模型,也只是让一个更聪明的模型面对同样错误的环境。

一个 Agent 大致可以看成:

Agent 分为很多层,也分为很多步骤,任何一层出了问题,最后都可能影响实际效果。

所以正确的顺序不是立马改 Prompt,而是先问:

  • 模型有没有拿到正确的信息?
  • Tool 描述和参数是不是清楚?
  • Tool Result 是不是真实反映了执行结果?
  • 当前状态有没有正确进入下一轮 Context?
  • 这个问题本身到底需不需要模型做判断?

只有确认问题确实发生在模型决策这一层,再去调整 Prompt 或模型,才更有意义。

不要把所有 Agent 问题最后都归结成一句“模型不行”。

(但是设计的再合理的Agent,如果模型不行,照样很垃圾)


误区二:Tool 越多、Context 越长,Agent 就越强 ​

后续我们接触了一段时间 Agent 以后,就感觉它已经很强大了,已经可以做很多事情了。

如果我再给它更多工具是不是会更厉害?

于是不断给 Agent 增加搜索、数据库、浏览器、邮件、文件、代码执行、各种第三方 API。

Context 也是一样。

既然模型可能需要这些信息,那就干脆全部塞进去:

text
项目文档
用户资料
历史对话
数据库结果
搜索结果
几十个 Tool Schema
……

看起来 Agent 知道得越来越多,实际上可能变得越来越难做决定。

Tool 越多,模型面对的选择也越多。

如果同时存在:

text
search_docs
search_web
search_database
find_file
grep
read
query_knowledge

但它们之间的边界又没有设计清楚,模型每一步都需要先判断:

我到底应该调用哪一个?

Tool 的数量增加了,错误的选择概览也一起增加了。

Context 也是同样的问题。

真正需要的是:

当前任务需要哪些信息。

而不是:

系统里有哪些信息就全部发给模型。

几十页文档全部塞进去,并不一定比只提供最相关的几段内容更好。相反,无关信息越多,真正重要的约束越容易被淹没。

所以 Agent 的能力并不能简单理解成:

text
更多 Tool
+
更多 Context
=
更强 Agent

更合理的目标应该是:

给模型当前真正需要的能力,以及当前真正需要的信息。

这也是为什么 Tool 设计和 Context Engineering 后面值得单独深入学习。


误区三:一开始就把 Memory、MCP、Multi-Agent 全部加上 ​

Agent 领域的新概念非常多。

做第一个项目时,很容易产生一种焦虑:

text
没有 Memory,是不是不完整?

没有 MCP,是不是已经落后了?

只有一个 Agent,是不是太简单?

是不是还应该增加 Planner、Reviewer、Researcher?

于是一个原本只需要:

text
用户提出任务
↓
Agent 调用几个 Tool
↓
完成任务

的系统,迅速变成:

text
Memory
MCP
Planner
Multi-Agent
RAG
Workflow
……

最后功能很多,但并没有在实际业务场景下运用,反而系统更加复杂了

Memory、MCP、Multi-Agent 本身当然都有价值。

问题在于,它们解决的是不同类型的问题。

如果当前 Agent 根本没有跨任务保存信息的需求,那就不一定需要 Memory。

如果只有几个本地 Tool,也没有工具标准化和外部接入需求,就没有必要为了“用了 MCP”而强行加一层。

如果一个 Agent 就能完成任务,再拆成三个 Agent,只会额外增加角色划分、Context 传递和协作成本。

合理的开发方式是:

text
先跑通最小闭环
↓
观察真正出现的问题
↓
再增加解决这个问题的能力

例如真的发现 Agent 每次都忘记长期信息,再考虑 Memory。

真的需要连接越来越多外部能力,再考虑 MCP。

真的发现单个 Agent 的 Context、职责或者任务分工已经难以控制,再考虑 Multi-Agent。

不要因为一个概念很热门,就先给自己的系统找一个使用它的理由。

应该反过来:

先出现问题,再选择合适的能力解决问题。

当然,很多时候一个概念很热门,就是因为它解决了某个特定的问题。

我们的确可以合理地使用这些新概念,但是绝对不应该跟风,尤其是生产环境中。


误区四:贴近业务,就把 Agent 写得和业务完全耦合 ​

还有一种情况和前面正好相反。

既然这个 Agent 就是给自己的业务用,又不是做开源框架,那是不是完全没有必要考虑架构和扩展?

于是最后可能出现一个巨大的 agent.ts:

text
agent.ts
├─ 模型调用
├─ System Prompt
├─ Tool 定义
├─ 数据库查询
├─ 订单规则
├─ 退款逻辑
├─ 权限判断
├─ 消息发送
└─ 各种业务 if / else

短期确实开发非常快,效果可能还不错。

但 Agent 领域变化尤其快。

今天模型直接写死 OpenAI,过一段时间可能需要切换 Provider。

今天只有三个 Tool,后面可能需要增加 MCP 或远程 Tool。

今天 Context 只是几段字符串,后面可能要加入项目规则、用户状态或者其他上下文。

如果这些能力从一开始就和具体业务逻辑完全揉在一起,每次修改 Agent 的底层能力,都可能牵动整个业务代码。

当然,另一个极端也没有必要。

一个只服务自己业务的 Agent,没有必要刚写第一版就设计:

text
十层接口
插件系统
抽象工厂
动态注册中心

最后为了“可扩展”,把一个简单项目做成半个框架。

真正需要的是合理分层,而不是无限抽象。

例如至少能看出这些边界:

text
Agent Runtime
├─ Model
├─ Context
├─ Tools
└─ Loop

Business
├─ Order Service
├─ Refund Service
└─ Notification Service

Agent 可以调用业务能力,但不应该把所有业务实现本身都重新塞进 Agent Runtime。

同样,业务代码也不应该到处直接依赖某一个模型 SDK、某一种 Tool Call 格式。

我们不需要预测未来所有变化。

只需要对那些已经很明显会变化的地方留出边界:

text
模型可能会换
Tool 会增加
Context 会变化
业务规则也会变化

贴近业务,不等于把系统写死。


误区五:只设计成功路径,不设计 Agent 怎么失败 ​

写 Demo 时,我们最喜欢看到的是:

text
用户提出任务
↓
模型正确理解
↓
Tool 调用成功
↓
任务完成

但真实 Agent 不可能永远按照这条路径运行。

Tool 可能报错。

文件可能不存在。

网络请求可能超时。

模型可能连续几轮选择错误的 Tool。

bash 甚至可能执行一个永远不结束的命令。

如果系统只设计:

text
成功以后下一步做什么

却没有设计:

text
失败以后怎么办

那么 Agent 一旦离开理想路径,就很容易陷入失控。

例如:

text
Tool Error
↓
模型再次调用
↓
继续 Error
↓
再次调用
↓
……

这时候需要考虑的已经不只是 Prompt。

而是整个 Runtime 的行为:

text
什么时候可以 Retry?

最多 Retry 几次?

连续失败以后是否应该停止?

一轮最多允许执行多少 Step?

Shell Command 要不要 Timeout?

用户能不能 Abort?

高风险情况下是否应该交还给人工?

有些失败适合让模型自己调整。

例如文件路径错误,Tool 把真实错误返回以后,模型可以重新选择路径。

但有些问题不应该无限重试。

例如连续多轮做相同的事情都失败,这时候继续循环往往只是浪费 Token 和时间。

所以一个真正可用的 Agent,不只是:

知道怎么继续。

还应该知道:

什么时候不应该继续。

Stop、Timeout、Abort、人工接管,并不是 Agent “不够自动化”的表现。

它们本来就是完整执行系统的一部分。


误区六:把 Prompt 当成权限和安全边界 ​

最后一个误区非常常见。

为了避免 Agent 做危险操作,在 System Prompt 中写:

text
不要访问工作目录之外的文件。

不要执行危险命令。

未经允许不要删除数据。

不要读取敏感信息。

这些要求当然要写。

但它们只是:

行为指导。

并不是:

安全边界。

因为最终决定 Agent 能不能读取文件、执行命令的,并不是 Prompt,而是 Tool 和运行环境真正给了它什么权限。

如果一个 bash Tool 实际拥有当前用户完整的 Shell 权限,那么即使 Prompt 写着:

text
只能访问 workspace

底层能力本身仍然可能访问其他目录。

所以需要把几个概念分清楚:

text
Prompt
→ 告诉模型应该怎么做

Tool Permission
→ 决定某次操作是否允许执行

Sandbox
→ 决定这个进程实际上最多能访问什么

例如删除重要文件前要求确认,可以在 Tool 执行之前增加权限检查。

某些目录绝对不能访问,可以在代码层限制路径。

如果运行的是不可信代码,或者 Agent 需要长时间无人值守执行,那么真正的隔离应该继续下沉到 Container、VM 或其他 Sandbox 环境。

最重要的一点是:

不要把“模型被要求不要做”误认为“模型实际上做不到”。

Prompt 很重要,但真正的安全边界最终还是要由代码和运行环境保证。

(网上有很多破甲提示词,哪怕模型再强,可能仍然会被用户提示词误导,这是现阶段很常见的一个现象)


总结 ​

这几个误区是我目前能够想到的比较常见的,我们后续在真实业务项目开发中,都要考虑到这些问题。

针对这些问题,做出不同的方案来完善优化。