Clipping 微信公众号

如何构建真正能上线的 AI Agent:7 条生产原则

by 基咯咯 原文 ↗
Created: 2026-05-16

公众号名称:Halo咯咯

作者名称:基咯咯

发布时间:2026-03-20 18:01

这两年,AI Agent 几乎成了默认热点。

网上教程一大堆,案例也一大堆,公众号等各个平台上隔三差五就有人发一条:“我用 30 分钟做了一个 Agent,或者我用Vibe Coding做了一个APP。”各种平台的视频里看着也很唬人:模型会思考、会调工具、会自己往下执行,很像模像样。

但真实情况往往却是,那些做出来的 demo 看着很顺,但用户一上手就开始出现各种问题。

  • 有的 agent 会原地打转,反复调用同一个工具;

  • 有的该查资料时不查,直接猜;

  • 有的看起来很聪明,但一旦换个输入就彻底跑偏;

  • 还有一种最麻烦:它错了,但错得特别像对的。

所以问题其实不在“能不能做出一个 agent”,而在于:你做出来的,究竟是个演示品,还是个能进生产环境的系统。

很多人卡住的地方,不是模型不够强,也不是框架不够新,而是从一开始就把 agent 想错了。

聊天机器人和 agent 看起来都在“跟人说话”,但骨子里完全不是一回事。

  • 聊天机器人,本质上是在回应一句话

  • Agent,本质上是在完成一件事

前者更像对话,后者更像执行。 如果你拿设计聊天机器人的思路去设计一个执行系统,它迟早会失控。因为对话可以模糊,执行不行;对话允许“差不多”,任务系统最终拼的是边界、反馈、约束和闭环。

这也是为什么,真正能上线的 agent,和那些看着很聪明的 demo,往往不是同一种东西。


先把最重要的一件事讲清楚:Agent 和聊天机器人到底差在哪

很多人会说,agent 不就是“能调用工具的大模型”吗?

这话不算错,但只说到表面。 真正的差别,不在于它有没有工具,而在于它是不是处在一个持续推进任务的循环里。

聊天机器人通常是一问一答:

输入 → 输出

Agent 不是。Agent 接到的是一个目标,然后它要经历这样一个过程:

输入 → 判断 → 调工具/执行动作 → 观察结果 → 再判断 → 继续推进或结束

关键就在这个循环。

因为一旦系统进入这个循环,你面对的就不再只是“回答得像不像”,而是:

  • 什么时候该继续?

  • 什么时候该停?

  • 什么时候该换方法?

  • 什么时候该承认做不到?

  • 什么时候必须把事情交给人?

这里有个特别容易被忽略的细节:agent 是否结束,不能靠它说了什么来判断,而要靠系统级的停止信号(stop_reason)来判断。

这件事看起来很小,其实非常关键。因为自然语言本来就是模糊的。模型说“我已经完成了分析”,可能只是完成了一个阶段;它写出一段像结论的话,也不代表后面不会继续调用工具。

所以,agent 的结束条件必须是结构化的,而不是“看起来像结束了”。

这个点一旦没想明白,后面很多诡异问题都会冒出来:提前结束、错误循环、假完成、重复执行。表面上看像模型不稳定,本质上是系统设计不够严谨。


做生产级 Agent,有 7 条原则绕不过去

这 7 条不是什么锦上添花的建议,而是决定一个 agent 最后能不能真的用起来的基本盘。 你可以不用一次就做全,但你最好从一开始设计Agent就知道它们后面迟早都得补上。


原则一:先写清楚它要做什么,再去写 prompt

很多人一兴奋,第一步就是开编辑器,开始接模型、绑工具、调接口。 这是最常见的顺序错误。

在你写任何代码之前,最好先回答几个很朴素的问题:

  • 这个 agent 的目标到底是什么?

  • 它要完成的是哪一类具体任务?

  • 它需要哪些输入才能开始?

  • 成功的结果长什么样?

  • 失败时应该怎么处理?

  • 哪些情况必须交给人工,而不是继续猜?

别小看这几问。很多 agent 后面之所以越来越难修,不是因为代码写错了,而是从第一天开始就没有定义清楚“它到底该负责什么”。

举个简单对比。

模糊目标

“做一个客服 agent。”

明确目标

“处理用户的物流咨询:根据订单号查询订单状态、调取物流信息、给出预计送达时间;如果查不到或涉及退款,转人工。”

这两种描述看起来只差了几句话,后面工程复杂度差得非常大。

因为第一种说法其实什么都没限定,agent 很容易不断越界; 第二种才是真正能落到系统里的定义。

一句话:先定职责,再写 prompt。

Prompt 只能放大清晰的目标,不能替你发明目标。


原则二:工具要少,而且边界要硬

很多人第一次做 agent,都会下意识地觉得:工具越多,它越强。 但真实情况通常相反。

工具每多一个,模型就多一道判断题。 一旦工具职责有重叠,系统就容易开始犹豫、误用或者绕路。

所以,早期 agent 最好控制在少量核心工具里。重点不是“多”,而是“准”。

每个工具都要回答清楚几件事:

  • 它是做什么的

  • 它不做什么

  • 它需要什么输入

  • 它会返回什么结果

  • 失败时会返回什么状态

这里最重要的,往往不是“能做什么”,而是“不要拿它做什么”。

对于一个好的工具,至少要包含以下4个维度:

  1. **名称:**名称必须清晰、直观,最好就是让模型一眼就知道做什么用。

  2. **描述:**描述直接决定了模型要不要调用这个工具,所以描述必须准确。

  3. **参数:**使用严格的 JSON Schema,对于必填项要明确标记,指定参数类型,字段定义也要说明清楚。

  4. **返回格式:**返回值必须结构化、一致、可解析。给个小建议,可以要求始终带一个 status 字段。方便清洗定位工具调用的结果。

比如:

差的工具描述

“用于搜索产品信息”

好的工具描述

“按产品名称或 SKU 搜索产品数据库,返回价格、规格和库存状态。仅用于查询产品信息,不用于查询订单、物流或售后状态。”

后者之所以更稳,不是因为字更多,而是因为它把边界说清楚了。

Agent 用工具时最怕的不是不会用,而是“以为能用”。 工具设计得越像一份清楚的操作手册,系统行为就越稳定。


原则三:错误处理不是补丁,是主流程的一部分

做 demo 的时候,大家默认一切都正常:接口能通、数据干净、返回完整、用户输入也正好在预期范围里。 但只要系统一上线,现实世界马上会告诉你什么叫复杂:

  • 接口超时

  • 查询结果为空

  • 第三方服务挂了

  • token 过期

  • 数据格式异常

  • 请求被限流

这类问题不是例外,而是日常。

而模型遇到这些情况时,最常见的反应通常只有两种:

  • 假装没出错,开始编

  • 一直重试,直到陷入循环

这两种都很危险。前者会误导用户,后者会烧成本、烧信任。

所以,生产级 agent 的错误处理必须是显式的:

  • 查不到,就明确返回“没查到”

  • 服务异常,就明确返回“当前不可用”

  • 多次失败后,不再盲重试

  • 高风险情况,直接转人工

可以把这里理解成一个很现实的原则:

好的 agent,不是永远做成事,而是知道什么时候不该继续乱做。

这一点其实特别重要。因为用户未必会因为“没查到”而不满,但很可能会因为“明明没查到还硬说查到了”而彻底失去信任。


原则四:权限边界不能只写在 prompt 里

这是很多人最容易高估模型、低估系统的地方。

你当然可以在 system prompt 里写:

  • 超过一定金额的退款必须人工审批

  • 删除操作必须确认

  • 不能泄露内部信息

  • 不能直接给外部用户发消息

问题是,如果这些规则真的重要,就不能只靠模型“记住”。 因为 prompt 说到底只是行为引导,不是硬约束。

真正高风险的边界,必须放进程序逻辑里。

也就是说:

  • 模型可以提议退款

  • 但超过阈值,系统必须拦住

  • 模型可以判断是否要删记录

  • 但真正执行前,必须经过确认 gate

  • 模型可以生成给客户的回复草稿

  • 但是否发送,由系统或人工决定

这里有个很简单的区分:

Prompt 的作用

告诉模型“应该怎么做”

代码的作用

保证系统“不能乱做”

真正的生产系统,不能把底线交给概率。 边界必须是硬的。

你需要的是:程序级强制执行。

要写 hook,在工具真正执行之前拦截调用。 要写 gate,在敏感操作之前先检查条件。

例如:

def execute_tool(tool_name, params):
    # 硬性闸门:超过 100 美元的退款必须人工审批
    if tool_name == "process_refund" and params["amount"] > 100:
        return {
            "status": "blocked",
            "reason": "退款金额超过自动审批阈值。",
            "action": "该退款需要人工审核,已路由至经理审批队列。"
        }

    # 硬性闸门:删除操作必须有人确认
    if tool_name == "delete_record":
        return {
            "status": "blocked",
            "reason": "删除操作必须经过明确人工确认。",
            "action": "请先要求用户确认是否真的要删除该记录。"
        }

    return tool_registry[tool_name](params)

原则五:任务复杂了,不要硬把所有事塞进一个 Agent

很多人遇到复杂任务时,第一反应是继续给同一个 agent 加工具、加职责、加上下文。 结果通常是:系统越来越大,行为越来越乱,最后自己都不知道哪一步出了问题。

更好的方式,往往是拆分。

一个协调者负责理解总目标和任务分发; 不同的子 agent 负责各自明确的小任务,比如:

  • 研究

  • 数据分析

  • 写作整理

  • 对外沟通

这样的好处很明显:每个 agent 工具更少,边界更清楚,也更容易调试。

但多 agent 有一个特别容易踩坑的地方:子 agent 不会自动继承协调者的上下文。

这点非常重要。

协调者前面已经聊了很多轮,知道背景、限制和目标; 新拉起的子 agent 并不知道这些,除非你显式传给它。

所以,做多 agent 时,千万不要偷懒地写:

“根据我们前面的讨论,帮我写一个总结。”

对新 agent 来说,它根本不知道“前面的讨论”是什么。

正确做法是把需要的内容讲完整:

  • 背景是什么

  • 数据是什么

  • 要完成什么

  • 输出格式是什么

  • 哪些限制必须遵守

多 agent 的核心不是“分工”本身,而是上下文传递是否清楚。 否则看起来像协作,实际上只是多个模型在各自猜。

# 坏例子:默认它知道上下文
现在请分析我们刚才讨论的数据,并写一份摘要。

# 好例子:把上下文完整传入
你是一名数据分析专家。请基于以下 2026 年 Q3 销售数据,
输出一份结构化摘要报告。

数据:
{sales_data}

分析要求:
1. 按地区比较营收趋势(逐月对比)
2. 找出增长最快的前 5 个产品(百分比和绝对值都要)
3. 识别异常值或离群点(异常定义为超过 2 个标准差)
4. 与 2026 年 Q2 基线对比:{q2_benchmarks}

前序分析背景:
研究团队发现 APAC 区域出现异常增长。
市场团队确认 8 月启动过面向企业客户的营销活动。

输出格式:
请返回 JSON,对应字段包括:
revenue_trends, top_products, anomalies, q2_comparison, executive_summary

原则六:别只测正常输入,坏输入才是真测试

一个 agent 在理想输入上表现不错,说明不了太多问题。 真实用户几乎一定会给你各种偏、怪、乱、长、矛盾的输入。

真正值得测的,反而是这些:

  • 空输入("" 或 null)

  • 自相矛盾的指令

  • 完全越界的请求

  • 超长上下文

  • 不存在的订单号、产品号

  • 带注入意图的提示

  • 情绪化甚至攻击性的表达

  • 高频连续请求

因为系统不是在实验室里用的,而是在真实世界里用的。 真实世界最大的特点就是:人会把系统用成你没想过的样子。

所以测试时,不妨反过来想:

  • 什么输入最容易让它误判?

  • 什么情况最容易让它陷入循环?

  • 哪些话会诱导它越权?

  • 它在“不知道”时会不会开始乱猜?

你越早用坏输入去折腾它,越不容易在上线后被用户教育。


原则七:不记录,就谈不上优化

Agent 一旦上线,最常见的反馈通常不是“完全不能用”,而是:

“它昨天有一轮表现特别奇怪。”

这时候,最可怕的不是它出问题,而是你根本没法复盘。

所以日志不是可选项,而是 agent 设计的一部分。你至少得知道:

  • 它收到了什么输入

  • 做了哪些判断

  • 调了哪些工具

  • 每个工具返回了什么

  • 在哪一步开始重复

  • 哪一轮耗时异常

  • token 花在了哪里

  • 最后是怎样结束的

没有这些信息,调 agent 基本靠猜。 而一旦你开始记录,你会发现很多问题并不神秘:

  • 有些工具总被误用

  • 有些查询一空结果,模型就开始编

  • 有些请求一长,就容易丢前文

  • 有些任务成本特别高,但并没有更好的结果

Agent 最终能不能越做越稳,不只取决于模型本身,更取决于你能不能看清它到底是怎么运行的。

import json
import logging
from datetime import datetime

logger = logging.getLogger("agent")

def log_agent_event(event_type, data):
    log_entry = {
        "timestamp": datetime.utcnow().isoformat(),
        "event_type": event_type,
        "run_id": current_run_id,
        "data": data
    }
    logger.info(json.dumps(log_entry))

# 示例
log_agent_event("tool_call", {
    "tool": "search_products",
    "params": {"query": "laptop"},
    "result_status": "success",
    "result_count": 12,
    "duration_ms": 340
})

log_agent_event("model_response", {
    "stop_reason": "tool_use",
    "tokens_in": 1520,
    "tokens_out": 230
})

log_agent_event("agent_complete", {
    "total_turns": 4,
    "total_tokens": 8200,
    "total_duration_ms": 12400,
    "outcome": "success"
})

如果只记一件事:先做一个最小可用版本

很多人一上来就想做一个“大而全”的 agent: 能搜索、能分析、能写报告、能发邮件、能跟日历联动,最好还能自己拆任务。

这种想法很正常,但通常也最容易把系统做散。

更现实的起点其实很朴素:

  • 一个 agent

  • 三个工具

  • 一个清楚目标

比如,一个产品问答 agent 就够了:

  • 搜索产品

  • 查看详情

  • 查询库存

它能回答的就回答,回答不了就明确说不知道。 先把这个系统做稳,测够,把日志打全,把错误处理补齐,把边界锁住。然后你再决定要不要加第四个工具、要不要加第二个 agent。

这件事听起来没那么性感,但它几乎是所有可靠系统的共同起点。

复杂度不是一开始靠想象堆出来的, 而是靠一次次迭代慢慢挣出来的。


最后总结一下

AI Agent 真正难的,从来不是“让它动起来”,而是“让它稳定地把事情做完”。

很多 demo 之所以看起来很惊艳,是因为它们只展示了最顺利的那一面。 真正的生产环境不是这样。生产环境里有脏数据、有空结果、有服务故障、有越界请求、有长上下文、有情绪化用户,也有各种你根本没提前想到的输入。

所以,做 agent 最后拼的不是谁更会写 prompt,也不是谁框架用得更新。 真正拉开差距的是这 7 件事:

  1. 先定义清楚目标

  2. 工具少而清晰

  3. 错误处理要显式

  4. 权限边界要程序化

  5. 复杂任务要拆分

  6. 坏输入要认真测

  7. 全链路要可观测

你可以把 agent 理解成一个“会推理的系统”,但别忘了,它首先还是一个系统。 而系统这件事,最后拼的永远不是灵感,而是设计。


参考:https://x.com/eng\_khairallah1/status/2033863233287733353

如果你喜欢这篇文章,别忘了 ​_关注​_我们!


AI在持续学习,你我也该更新了。


cover_image

原创 基咯咯 Halo咯咯


内容效果不满意?点此反馈

输入关键词开始搜索