Appearance
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 ServiceAgent 可以调用业务能力,但不应该把所有业务实现本身都重新塞进 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 很重要,但真正的安全边界最终还是要由代码和运行环境保证。
(网上有很多破甲提示词,哪怕模型再强,可能仍然会被用户提示词误导,这是现阶段很常见的一个现象)
总结
这几个误区是我目前能够想到的比较常见的,我们后续在真实业务项目开发中,都要考虑到这些问题。
针对这些问题,做出不同的方案来完善优化。