摘要:
百炼官方 Function Calling 的流程中,模型负责提出工具调用请求,应用端负责真正执行外部工具并回填结果。接实时行情查询时,关键不是把函数名交给模型,而是把工具限定为只读、让结果可核对,并在查询失败或返回空数据时阻止模型继续输出当前价格。
当用户问“某个标的现在的价格是多少”时,把一个 query_quote 函数描述交给 Qwen,只完成了第一层工作:让模型知道“可以请求一个工具”。
它并不等于模型已经拿到行情,也不等于最终回答里的价格可以相信。
按照百炼官方 Function Calling 流程,模型负责识别是否需要调用工具并返回工具请求;真正执行外部查询、检查结果是否有效、再把结果回填给模型的是应用程序。对于行情问题,可信链路的关键因此不是函数名写得多漂亮,而是三件事:
- 工具只能读取行情,不能承载操作指令。
- 回填给模型的结果必须来自一次可检查的查询。
- 查询失败、返回空结果或无法确认数据时,最终回答必须停止输出价格。
一条可核对的工具调用链路
| 步骤 | 发生了什么 | 应用端必须守住的边界 |
|---|---|---|
| 用户问题 | 用户询问当前行情或某标的当前价格 | 识别这是需要外部数据的问题,不能让模型凭已有上下文报数 |
| Qwen 工具请求 | 应用把问题与工具列表发给模型;模型可能返回包含函数名与参数的 tool_calls |
工具请求只是“拟查询”,此时还没有可回答的价格 |
| 应用执行只读查询 | 应用校验参数后,调用一个只读行情查询函数 | 函数只允许查询,不把写入、下单或其他操作混入 schema |
| 结果回填 / 失败阻断 | 成功时,将工具输出加入消息并再次请求模型;失败时,只提供失败状态 | 没有有效查询结果,就不能把任何当前价格交给模型组织成答案 |
| 最终回答 | 模型基于已回填的工具结果形成自然语言回复 | 成功时说明查询所得结果;失败时只说明暂无法确认当前价格 |
这里最容易误解的一点是:tool_calls 证明模型发起了请求,不证明外部工具成功执行,更不证明响应里存在可用价格。
为什么行情工具应该被设计成只读
行情问答需要的是“查到什么就回答什么”,而不是让一个自然语言入口顺带承担更多动作。一个收敛的工具定义,通常只接收查询所需参数,例如标的标识;应用端再把它映射为只读 HTTP 查询。
这样设计有两个直接好处:
- 模型即使生成了不合适的参数,应用也可以在执行前拒绝,而不是扩大后果。
- 审核最终答案时,可以清楚追溯:用户问了什么、工具查了什么、结果是否成功回填。
一个最小只读查询片段
下面代码是用于说明职责边界的教学伪代码,不是“复制即可上线”的完整工程。示例中的 TickDB 仅代表应用端可调用的一条只读行情数据路径,不代表百炼官方集成或合作。
# 教学伪代码:仅展示只读查询与阻断规则
def query_quote_readonly(symbols):
resp = http_get(
"https://api.tickdb.ai/v1/market/ticker",
headers={
"X-API-Key": env("TICKDB_API_KEY")},
params={
"symbols": symbols},
timeout=TIMEOUT,
)
if resp.request_failed:
return {
"ok": False, "reason": "quote_unavailable"}
body = resp.json()
if body["code"] != 0 or not body["data"]:
return {
"ok": False, "reason": "quote_unavailable"}
return {
"ok": True,
"requested_symbols": symbols,
"last_price": body["data"][0]["last_price"],
}
这个片段只表达四个已经足以影响回答可信度的事实:请求走只读行情快照接口;鉴权放在应用端;结果从 data 中读取;价格字段使用 last_price。超时、重试、日志、参数白名单和响应归档仍需要由实际工程补齐。
失败分支清单:哪些情况下不能继续生成价格
| 失败分支 | 应用端处理 | 模型最终可以回答什么 |
|---|---|---|
| 模型没有为当前行情问题发起工具请求 | 不接受直接生成的价格,转为提示需要完成外部查询 | “当前行情尚未通过工具查询确认。” |
| 工具参数缺失、格式不符合约束 | 拒绝执行查询,返回参数错误状态 | “无法完成本次行情查询,请补充有效标的。” |
| HTTP 请求超时或连接失败 | 返回失败状态,不回填价格字段 | “查询暂时失败,当前价格无法确认。” |
| 接口返回错误状态,例如鉴权、限流或服务异常 | 按错误类别处理;本轮答案不输出价格 | “本次未获得可核对的行情结果。” |
请求成功但 data 为空 |
将其视为无可用结果,而不是价格为零 | “未查询到可用于回答的当前行情数据。” |
| 成功结果没有正确回填到消息链路 | 不允许模型基于旧上下文补写数字 | “结果回填未完成,暂不提供当前价格。” |
| 最终生成内容包含工具结果之外的新价格判断 | 应用侧拦截或重发受限回答 | 只保留工具结果能够支持的表述 |
其中,失败阻断并不意味着系统必须无响应。更合理的行为是:系统仍然回答用户,但明确回答“为什么当前不能给出价格”,而不是填入一个未经核对的数字。
把职责分开,回答才有证据链
在百炼 Function Calling 中,模型擅长判断“是否需要某个工具”以及“如何把结果组织成自然语言”;应用程序必须负责真正执行工具、限制工具能力、验证返回结果,并决定失败时是否允许继续回答具体数值。
对实时行情这类问题,一条合格链路应满足:
- 模型不把自身知识当作当前价格来源。
- 工具定义只服务于读取数据。
- 应用端能够识别查询失败、空结果和回填缺失。
- 只有经过工具成功返回并回填的数据,才可以进入最终价格回答。
函数名只是入口。能否在失败时停住,才决定这条工具调用链是否值得信任。
标签:阿里云百炼 通义千问 Function Calling 工具调用 应用架构 错误处理