一、会聊天,不等于会做事
在 OPC中国 的讨论里,智能体常被理解为“能自己完成任务的 AI”。这个理解并不算错,但容易忽略其中最脆弱的一段:从自然语言到外部动作的转换。
例如,用户说:“把华东区昨天待处理的退款订单发给值班同事。”这句话至少包含四层信息:
- 要做什么:查询退款订单,再发送通知;
- 查什么范围:华东区、昨天、待处理;
- 发给谁:值班同事,而不是所有人;
- 何时不该执行:地区、日期或接收人无法确定时。
大模型擅长理解这类含蓄表达,却不是数据库、消息系统或权限系统。它需要借助工具完成动作。于是,工具调用的质量,取决于模型和工具之间是否存在一份足够明确的“能力合同”。
阿里云百炼将智能体描述为由提示词驱动、能够根据意图规划并调用知识库和外部工具的应用;官方也明确建议:当任务是固定的多步骤链路时,应优先选择可控、可复现的工作流,而不是把所有步骤都交给智能体临场决定。智能体应用说明 应用类型介绍
这给了我们一个实用原则:让模型负责理解与选择,让程序负责约束与执行。
二、工具调用到底发生了什么
一次可信的工具调用,不应是“模型生成一段 JSON,服务端照单全收”。更合理的链路如下:
- 理解意图:从用户输入中识别任务和必要条件;
- 挑选工具:在有限工具集内选择最合适的一项;
- 生成参数:按约定字段组织参数;
- 服务端校验:检查类型、范围、权限与业务状态;
- 执行与核验:调用外部服务,确认真实结果;
- 反馈结果:把成功、失败和待确认的原因明确告诉用户。
其中第 4 步最不能省。模型输出只是“候选指令”,不是授权。尤其涉及发消息、修改数据、提交订单等动作时,最终服务必须再次判断:当前用户是否有权限、参数是否完整、动作是否允许发生。
三、先把工具边界写清楚,而不是堆很多工具
工具说明越模糊,模型越容易猜。常见问题不是模型“不聪明”,而是两个工具的职责本来就重叠。
假设系统里有两个工具:
search_orders(query)
send_message(content)
它们几乎没有告诉模型:支持哪些筛选字段、谁能接收消息、什么内容需要人工确认。此时,模型只好根据名字推测用法。
更好的设计是给工具一份可读、可校验的合同:
{
"name": "list_pending_refunds",
"description": "查询指定区域和日期范围内状态为 pending 的退款订单。仅查询,不会修改订单。",
"parameters": {
"type": "object",
"properties": {
"region": {"type": "string", "enum": ["华东", "华南", "华北"]},
"date": {"type": "string", "description": "ISO 日期,格式 YYYY-MM-DD"}
},
"required": ["region", "date"],
"additionalProperties": false
}
}
这段定义包含了四个关键点:
- 名称使用动词加对象,能看出动作与对象;
- 描述说明“能做什么”和“不会做什么”;
- 参数类型、枚举值与必填项清晰可见;
additionalProperties: false避免悄悄混入未定义字段。
不要把“查询、修改、删除”混在一个万能工具里。查询工具默认只读;有副作用的工具单独命名、单独授权。这样不仅便于模型选择,也便于审计和权限配置。
四、参数校验:防住最常见的三类错误
参数校验不需要复杂框架。先把最常见的错误挡在服务端入口,就能让系统稳定很多。
from datetime import date
ALLOWED_REGIONS = {"华东", "华南", "华北"}
def validate_refund_query(args: dict) -> dict:
if set(args) != {"region", "date"}:
raise ValueError("参数必须且只能包含 region、date")
region = args["region"]
if region not in ALLOWED_REGIONS:
raise ValueError("region 不在允许范围内")
try:
query_date = date.fromisoformat(args["date"])
except (TypeError, ValueError) as exc:
raise ValueError("date 必须是 YYYY-MM-DD") from exc
if query_date > date.today():
raise ValueError("不能查询未来日期")
return {"region": region, "date": query_date.isoformat()}
这段代码有意不相信任何上游输入,包括模型。它检查字段是否恰好匹配、区域是否属于业务范围、日期能否解析以及是否落在合理区间。校验失败时,返回的错误信息应该能让智能体继续追问,例如:“你希望查询华东、华南还是华北?”而不是把底层异常原样暴露给用户。
需要注意的是,参数合法并不代表操作被允许。发送消息前还应检查调用者身份、接收人是否在值班表中、是否超过频率限制;删除或付款等高风险动作,则应进入人工确认。
五、把“确认”当成产品能力,而不是失败补丁
有副作用的动作可以按风险分级:
| 动作类型 | 示例 | 建议策略 |
| 低风险、只读 | 查订单、读知识库 | 自动执行,记录调用日志 |
| 中风险、可撤销 | 创建草稿、生成待发送通知 | 自动生成,但展示摘要供确认 |
| 高风险、不可逆 | 对外发送、删除数据、退款 | 明确展示对象与影响,等待人工确认 |
确认页不应只出现一个“确定”按钮。它至少要让人看见:将调用哪个工具、参数是什么、会影响哪些对象、是否能撤销。用户真正确认的是一项具体动作,而不是一句含糊的自然语言。
在 OPC中国 的实际应用中,这一步尤其重要:一人或小团队通常没有专门的人工巡检岗位,越早把风险动作收口,越不会让“自动化”变成新的返工来源。
六、结果也要校验:HTTP 200 不等于任务完成
另一个容易忽略的问题是:外部接口返回成功,业务是否真的成功?
例如,通知接口可能返回 200,但只表示“请求已接收”;订单查询可能返回空数组,也可能是权限错误被错误地转成空结果。调用工具后,应检查与任务相关的业务字段,并将工具的原始返回保留在日志中。
可以把结果统一归为三类:
{"status": "success", "data": {"count": 12}}
{"status": "needs_confirmation", "reason": "将向 3 位外部联系人发送通知"}
{"status": "failed", "retryable": true, "reason": "上游服务超时"}
这种结构比让工具直接返回一大段自然语言更适合程序处理。智能体可以根据 status 选择继续、重试、向用户确认或说明失败;调用日志也更容易统计。
若工具来源于 MCP 服务,还应把输入、输出和错误边界设计得更清楚。阿里云百炼新版智能体将知识库和 MCP 等外部能力纳入统一调度,并支持呈现规划、执行与反思过程;这类可回溯信息很适合用于定位“选错工具”还是“工具执行失败”。新版智能体应用说明
七、从一个小场景开始的落地清单
第一次做工具型智能体,不妨只选一个“查—答”场景,例如“查询指定区域当天的待处理退款数”。完成下面五项后,再逐步加入通知、创建工单等能力:
- 只开放一个只读工具,并写清输入、输出和边界;
- 准备 20 条真实或脱敏的用户问法,覆盖简称、缺参和歧义;
- 在服务端实现 schema、权限和业务规则三层校验;
- 记录工具名、参数、校验结果、耗时和业务结果;
- 对发送、修改、删除等动作增加确认和幂等标识。
如果回答依赖企业制度、产品说明等私有资料,再在这一条链路上接入知识库。知识库的作用是为回答补充外部事实,而不是替代权限、参数校验或业务规则。阿里云百炼的知识库基于 RAG 检索相关内容并供模型生成时参考,且支持将知识库关联到智能体或工作流应用中。知识库说明
结语
智能体的价值不只在于“会调用多少工具”,而在于每次调用是否可理解、可限制、可追溯。把工具做成边界清楚的能力合同;把校验放在真正执行动作的服务端;把高风险动作交给明确确认——这三件事做好后,智能体才有资格从演示走向日常工作。
对于 OPC中国 而言,可靠的自动化并非让系统替人做出所有决定,而是把重复的、规则清楚的环节交给系统,把真正需要判断的地方留给人。