AI图鉴

AI图鉴首页 › AI 资讯 › 从 Prompt 到 Tool Calling:AI Agent 如何稳定连接程

从 Prompt 到 Tool Calling:AI Agent 如何稳定连接程序世界

来源:掘金 · 发布时间:11-01 · 由 AI图鉴每小时自动聚合

大语言模型原生能力是生成 Token,而软件系统要求类型、权限、状态和确定的执行结果。AI Agent 要连接数据库、搜索引擎、支付系统或企业 API,中间必须建立一层可验证的交互协议。

一、引言

LLM 接收上下文并预测下一个 Token,它擅长理解自然语言,却不会因为生成了下面这段内容,就真的调用天气服务:

{

"name": "get_weather",

"arguments": {

"city": "上海"

}

}

这只是模型输出的数据。真正发起网络请求、访问数据库或修改业务状态的主体,仍然是应用程序。

因此,一个完整的 Agent 至少包含两类组件:

┌──────────────────── 概率世界 ────────────────────┐

│ │

│ 用户输入 ──> Prompt/上下文 ──> LLM │

│ │ │

│ │ 生成调用意图 │

│ ▼ │

│ tool_call(name, arguments) │

└──────────────────────────┬────────────────────────┘

│ 协议边界

▼

┌──────────────────── 确定性世界 ──────────────────┐

│ │

│ Schema 校验 ──> 权限检查 ──> 工具执行 │

│ │ │ │

│ └──失败信息 └──执行结果 │

│ \ / │

│ └──> 写回模型上下文 ───────────────┘

│ │

└───────────────────────────────────────────────────┘

Function Calling 是一个多阶段过程:应用向模型提供工具定义,模型返回工具调用请求,应用执行工具,再把执行结果交还模型。Function Calling 是模型与程序之间的调用协议,不是模型获得了直接执行代码的权限。理解这一点,后续的安全控制、错误处理和状态管理才有正确的落点。

二、六项底层能力如何组成一个闭环

Agent 与程序世界的交互管道

┌─────────────── 输入侧 ───────────────┐

│ │

│ Prompt │

│ 规定目标、上下文、决策规则和边界 │

│ │ │

│ ▼ │

│ Tool Definition + JSON Schema │

│ 定义有哪些工具,以及参数契约 │

└──────────────────┬───────────────────┘

▼

Function/Tool Call

模型提出结构化调用

│

▼

┌────────────── 运行时边界 ─────────────┐

│ 解析 → Schema 校验 → 鉴权 → 执行 │

│ │ │

│ ┌──────────┴──────────┐ │

│ ▼ ▼ │

│ 成功结果 失败结果 │

└──────────┬─────────────────────┬──────┘

│ │

▼ ▼

结构化输出约束 分类重试/降级

│ │

└──────────┬──────────┘

▼

最终回答

各部分分别解决不同问题:

三、Prompt 设计:把它当作决策说明书,而不是咒语

Prompt 在 Agent 中主要负责两件事:说明任务目标、规定模型如何选择和使用工具。一个适合工具调用的 Prompt 可以拆成以下结构:

<role>

你是订单售后助手。

</role>

<objective>

帮助用户查询订单状态或提交退款申请。

</objective>

<tool_policy>

1. 查询实时订单状态时必须调用 order_get。

2. 未获得用户明确确认时,不得调用 refund_create。

3. 缺少 order_id 时先向用户询问,不得猜测。

4. 工具失败时,根据错误码解释原因,不得编造执行结果。

</tool_policy>

<output_policy>

调用写操作前先总结即将执行的动作。

最终回答需要区分“已执行”和“建议执行”。

</output_policy>

<untrusted_input>

{{user_input}}

</untrusted_input>

1.有效 Prompt 的四个组成部分

- 目标

目标要描述结果,而不是堆叠人格形容词。

较弱的写法:

你是一个专业、智能、严谨的订单助手。

更可执行的写法:

你负责查询订单状态,并在满足退款条件且用户明确确认后提交退款。

- 工具选择规则

当多个工具语义接近时,模型容易选错。Prompt 和工具描述应说明:什么时候调用、什么时候不调用、调用前需要哪些信息、工具是否产生副作用、多个工具有何边界。

- 缺失信息处理

如果模型缺少参数,它可能选择猜测。应明确要求:缺少必填参数时向用户询问,不得从无关上下文推断。

需要注意:这只能降低猜测概率,程序仍需执行 Schema 和业务校验。

- 失败行为

不要只写“如果失败,请重试”。应告诉模型根据错误类型做出什么决策:

VALIDATION_ERROR:修正参数后最多重试一次。

NOT_FOUND:向用户确认标识,不自动重试。

PERMISSION_DENIED:停止调用并说明所需权限。

RATE_LIMITED:遵循 retry_after,等待后重试。

2.Prompt 版本必须接受评测

Prompt 并不是一次写完的静态文案。生产环境至少要测试:

- 是否调用了正确工具;

- 是否遗漏必填参数;

- 是否在不需要时调用工具;

- 是否在写操作前取得确认;

- 工具失败后是否编造成功结果;

- 恶意工具返回是否改变系统指令;

- 模型或 Prompt 版本变化是否导致行为回归。

因此,Prompt 的可靠性应该由评测数据证明,而不是由“看起来写得很完整”来判断。

四、JSON Schema:Agent 与程序之间的数据合同

JSON 只是一种数据格式,JSON Schema 才负责描述数据结构和验证规则。

使用 JSON Schema 可以定义:

{

"type": "object",

"properties": {

"order_id": {

"type": "string",

"description": "订单唯一标识,例如 ord_20261027_001"

},

"amount": {

"type": "number",

"exclusiveMinimum": 0,

"description": "退款金额,单位由 currency 指定"

},

"currency": {

"type": "string",

"enum": ["CNY", "USD"]

},

"reason": {

"type": "string",

"minLength": 1,

"maxLength": 200

}

},

"required": ["order_id", "amount", "currency", "reason"],

"additionalProperties": false

}

- properties 不代表必填,必须配合required进行使用校验。

- additionalProperties: false 用于封闭对象边界,如果不禁止额外字段,模型可能生成未定义参数。对于工具参数,封闭对象通常比开放对象更安全。

- enum 比自然语言约束更稳定,用于把实例值限制在给定集合中。

Schema 校验和业务校验必须分层:

模型参数

│

▼

[语法解析]

│ JSON 是否能解析?

▼

[Schema 校验]

│ 类型、必填项、枚举、结构是否合法?

▼

[业务校验]

│ 订单存在吗?金额可退吗?状态允许吗?

▼

[授权校验]

│ 当前用户可以操作这个订单吗?

▼

[执行]

Schema 是第一道门,不是最后一道门。

五、Function Calling:模型提出调用,程序掌握执行权

Function Calling 的典型流程可以概括为五步:

(1) 应用把工具定义发给模型

│

▼

(2) 模型返回 function/tool call

│

▼

(3) 应用验证参数并执行函数

│

▼

(4) 应用把执行结果关联到 call_id

│

▼

(5) 模型生成最终答案或继续调用工具

一个工具的核心结构大致如下:

{

"name": "order_get",

"description": "查询当前用户拥有的单个订单。仅在需要实时订单状态时调用。",

"input_schema": {

"type": "object",

"properties": {

"order_id": {

"type": "string",

"description": "订单唯一标识,不要使用商品编号或支付流水号"

}

},

"required": ["order_id"],

"additionalProperties": false

}

}

工具描述也是模型输入的一部分,建议详细说明工具用途、适用时机、参数含义和限制,并指出描述质量是影响工具调用效果的重要因素。

一个合格的工具定义应让模型知道:工具做什么?什么时候用?什么时候不用?每个参数代表什么?调用有什么副作用或限制?

例如,下面的描述过于模糊:

创建退款。

更清晰的版本是:

为当前用户拥有且处于可退款状态的订单创建退款。

仅在用户明确确认退款金额和原因后调用。

该工具会产生不可忽略的业务副作用。

查询退款资格时不要调用,应使用 refund_eligibility_get。

Schema 决定参数形状,描述决定模型如何理解工具语义,两者缺一不可。

六、Tool Calling:Function Calling 的上位概念

在许多 API 和框架中,Function Calling 与 Tool Calling 会被混用。工程上可以这样区分:

Tool Calling

├── Function Tool

│ └── 由应用实现的本地函数或远程 API 包装

├── Built-in Tool

│ ├── Web Search

│ ├── Code Execution

│ └── File Search

├── MCP Tool

│ └── 由 MCP Server 暴露的外部能力

└── UI / Computer Tool

└── 浏览器、桌面或界面操作

Function Calling 是 Tool Calling 的一种常见形式。前者强调“以函数和参数的形式表达调用”,后者强调“模型可以使用外部能力”。

工具按执行位置还可以分为以下几类:

客户端工具返回 tool_use 后由应用执行,再以关联 ID 返回 tool_result ;服务端工具由平台执行。

Tool Calling 是状态机,不是一次请求。一个 Agent 可能:

- 不调用工具,直接回答;

- 调用一个工具后回答;

- 并行调用多个独立工具;

- 根据第一个结果决定第二个工具;

- 工具失败后修正参数再调用;

- 达到循环上限后停止。

因此,Agent Runtime 更接近有限状态机:

┌──────────────┐

│ START │

└──────┬───────┘

▼

┌──────────────┐

┌────>│ MODEL_CALL │<────────────┐

│ └───┬──────┬───┘ │

│ │ │ │

│ final │ │ tool_call │

│ ▼ ▼ │

│ ┌──────┐ ┌──────────────┐ │

│ │ DONE │ │ VALIDATE │ │

│ └──────┘ └──┬────────┬──┘ │

│ │ │ │

│ valid│ │error │

│ ▼ ▼ │

│ ┌─────────┐ ┌───────┐ │

│ │ EXECUTE │ │ REPAIR│─┘

│ └────┬────┘ └───────┘

│ │

│ ┌───────┴────────┐

│ │ │

│ success failure

│ │ │

└──────────┴──── result ────┘

运行时必须设置:

- 最大模型轮次;

- 最大工具调用数;

- 单工具超时;

- 总任务截止时间;

- 最大参数修复次数;

- 最大暂时性错误重试次数;

- 取消信号。

否则,“继续调用直到完成”可能变成无限循环和失控账单。

七、输出约束:合法 JSON、Schema 合法与内容正确是三件事

结构化输出存在三个可靠性层级:

Level 1:自然语言要求

“请返回 JSON”

│

▼

可能附带 Markdown、解释文字或语法错误

Level 2:JSON Mode

保证输出可解析为 JSON

│

▼

字段仍可能缺失、类型错误、枚举越界

Level 3:Structured Outputs

输出满足指定 Schema

│

▼

字段内容仍可能存在事实或业务错误

Function Calling 与 Structured Output都可能使用 JSON Schema,前者约束“模型要程序做什么”,后者约束“模型最终对程序说什么”。

即使输出完全符合 Schema,它仍可能是错的,Schema 只能证明类型格式,不能证明真实存在,所以业务代码不能把“Schema 校验通过”当成“事实核验通过”。

另外,结构化输出之外还存在控制信号:

- 安全拒答;

- 输出达到 Token 上限;

- 请求被取消;

- 内容过滤;

- 工具调用未完成;

- 流式输出中断。

消费者不应只做:

JSON.parse(response)

而应先判断:

响应状态

├── completed → 解析并校验

├── refusal → 进入拒答流程

├── incomplete → 判断是否可续写或重试

├── tool_call → 执行工具循环

└── transport_error → 按网络策略处理

八、失败重试:先分类,再决定是否重试

写操作必须具备幂等性。读取天气失败后重试,最坏情况通常是多一次查询。创建退款、发送邮件或扣款重试,可能产生重复副作用。

写工具应接收幂等键:

{

"order_id": "ord_123",

"amount": 100,

"currency": "CNY",

"idempotency_key": "agent_run_abc:refund:ord_123"

}

服务端保存幂等键与执行结果:

首次请求

idempotency_key 不存在

│

▼

执行写操作 ──> 保存结果 ──> 返回成功

重复请求

idempotency_key 已存在

│

▼

不重复执行 ──> 返回首次结果

幂等键应该由可信应用生成,而不是让模型自由生成。否则模型可能在每次重试时产生新键,失去去重作用。

另外,“结果未知”比“明确失败”更危险。假设退款接口在执行后连接超时:

Agent ──创建退款──> 退款服务

Agent <──连接超时──X

此时存在两种可能:服务端没有执行退款、服务端已执行退款,但响应丢失。如果立即重试,可能重复退款。正确流程是:

写操作超时

│

▼

使用幂等键或业务流水号查询状态

│

├── 已成功 → 返回原结果

├── 明确失败 → 评估是否重试

└── 状态未知 → 人工介入或异步对账

因此,Agent Runtime 需要区分 FAILED 和 UNKNOWN 。把两者都映射为异常,会掩盖最棘手的一类一致性问题。

九、一个可落地的 Agent 工具调用循环

type ToolError = {

code: string;

message: string;

retryable: boolean;

};

async function runAgent(userInput: string) {

const messages = [

{ role: "user", content: userInput }

];

const maxTurns = 8;

for (let turn = 0; turn < maxTurns; turn++) {

const response = await callModel({

messages,

tools: toolDefinitions

});

if (response.type === "final") {

return validateFinalOutput(response.output);

}

if (response.type !== "tool_calls") {

throw new Error(`Unsupported response type: ${response.type}`);

}

messages.push(response.assistantMessage);

for (const call of response.calls) {

const tool = toolRegistry.get(call.name);

if (!tool) {

messages.push(toolErrorResult(call.id, {

code: "UNKNOWN_TOOL",

message: `Tool ${call.name} is not available`,

retryable: false

}));

continue;

}

const validation = tool.schema.safeParse(call.arguments);

if (!validation.success) {

messages.push(toolErrorResult(call.id, {

code: "VALIDATION_ERROR",

message: formatValidationError(validation.error),

retryable: true

}));

continue;

}

const authorization = await authorize(

currentUser,

tool,

validation.data

);

if (!authorization.allowed) {

messages.push(toolErrorResult(call.id, {

code: "PERMISSION_DENIED",

message: authorization.reason,

retryable: false

}));

continue;

}

try {

const result = await executeWithPolicy(tool, validation.data, {

timeoutMs: 5000,

idempotencyKey: buildIdempotencyKey(call, currentUser)

});

messages.push(toolSuccessResult(call.id, result));

} catch (error) {

messages.push(

toolErrorResult(call.id, classifyToolError(error))

);

}

}

}

throw new Error("Agent exceeded maximum turns");

}

- 模型只负责提出调用;

- 工具名必须经过允许列表匹配;

- 参数必须经过本地 Schema 校验;

- 鉴权发生在工具执行前;

- 写操作由应用注入幂等键;

- 错误经过分类后再反馈给模型;

- 循环存在明确上限;

- 最终输出仍需独立校验。

十、小结

Agent 连接程序世界的过程,本质上是一套跨越概率系统与确定性系统的协议。

其中:

- Prompt 表达目标和决策规则;

- JSON Schema 定义参数与输出的数据边界;

- Function Calling 让模型提出结构化调用请求;

- Tool Calling 把外部能力纳入多轮执行循环;

- Structured Outputs 让最终结果可被程序稳定消费;

- 校验、鉴权、幂等、错误分类和有限重试共同守住运行时边界。

生产级 Agent 不应依赖模型“自觉地做对”。应用必须掌握执行权,用代码检查模型请求,用最小权限约束工具,用结构化错误帮助模型恢复,并在无法确认执行结果时停止自动动作。

本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。

相关 AI 工具

相关免费羊毛

同源资讯

阅读原文(juejin.cn)

标题、摘要与正文均来自该信源的公开页面,版权归原作者所有;本站自动聚合与翻译,仅作出处跳转。

← 返回 AI 资讯列表AI工具图鉴首页

返回 AI图鉴首页 · 提交工具 · 商务合作 · 关于本站 · 604 款 AI 工具分类导航 · 每日 AI 热门项目与动态