尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Function calling 函数调用

Function calling 函数调用 文章目录The tool calling flow 工具调用流程Defining functions 定义函数Defining namespaces 定义命名空间Tool search 工具搜索Best practices for defining functions 定义函数的最佳实践Write clear and detailed function names, parameter descriptions, and instructions.编写清晰详细的函数名称、参数描述和指令。system promptInclude examples and edge cases, especially to rectify any recurring failures.意思加入例子和边界情况特别是模型经常犯错的地方。对于推理模型reasoning model大量例子可能反而降低效果Apply software engineering best practices.应用软件工程最佳实践Offload the burden from the model and use code where possible. 减轻模型的负担尽可能使用代码Keep the number of initially available functions small for higher accuracy. 为了提高精度应尽量减少初始可用函数的数量。Leverage OpenAI resources.充分利用 OpenAI 的资源Token Usage 代币使用情况Handling function calls 处理函数调用Formatting results 格式化结果Incorporating results into response 将结果纳入应对措施Tool choice 工具选择When to use allowed_tools 何时使用 allowed_toolsParallel function calling 并行函数调用Strict mode 严格模式strict: true 并不是单纯给模型一句提示“请你一定按照这个 Schema 输出”而是会启用 Structured Outputs 的约束解码constrained decoding机制。OpenAI 官方也特别指出Structured Outputs 不能防止 JSON 值里的语义错误它保证结构符合 Schema但模型仍可能在字段值内容上犯错严格“结构正确” ≠ “内容一定正确”那系统怎么知道什么 token 合法推理引擎就是让模型启动的推理框架吗是推理框架的一部分真正的硬约束主要是推理框架/推理引擎实现的不是模型天然保证的Streaming 流Custom tools 自定义工具Context-free grammars 上下文无关文法Function Calling 原理token loopLLM 内部 token 循环,推理引擎不断让模型预测下一个 token把新 token 接到已生成序列后面再继续预测直到满足停止条件。推理引擎负责“生成”推理框架的 API 服务层负责“封装和返回”。怎么知道什么时候不再吐 token模型自己生成了自然结束标记stop sequence 是推理系统额外检查的达到 max_output_tokens而被强制截断某些安全/系统原因强制终止 生成过程被服务端或外部状态中断/截断finish_reason是 API 层对“这一轮为什么结束/这一轮输出是什么性质”的描述finish_reason tool_calls平常调用一次 LLM只有“token loop”Agent 在 token loop 外面又套了一层“agent loop”。tool_choice Parallel function calling 也是推理框架决定The tool calling flow 工具调用流程Function calling 函数调用模型本身不能直接执行外部操作查询数据库、调用接口、执行代码等而是通过“提出工具调用请求 → 应用执行 → 把结果返回模型 →模型继续推理”的方式完成任务。请注意对于 GPT-5 或 o4-mini 等推理模型工具调用中模型响应返回的任何推理项也必须随工具调用输出一起传递回去。Defining functions 定义函数函数通常在每个 API 请求的 tools 参数中声明。借助工具搜索您的应用程序还可以在交互过程中稍后加载延迟函数。无论哪种方式每个可调用函数都使用相同的模式结构。函数定义具有以下属性json schemaDefining namespaces 定义命名空间使用 namespace命名空间把相关的工具按照领域分组比如 CRM、账单、物流。namespace 可以帮助整理相似工具特别是当模型需要在不同系统或不同用途的工具之间做选择时很有用比如一个搜索工具用于 CRM另一个搜索工具用于客服工单系统。namespace 是什么namespace 就是给工具加一个“类别”。当 Agent 有很多工具时不要把所有工具平铺给模型而是按照业务领域分组让模型通过 namespace 判断工具属于哪个系统从而减少工具选择错误。Tool search 工具搜索如果您需要让模型访问庞大的工具生态系统可以使用 tool_search 延迟加载部分或全部工具 tool_search 工具允许模型搜索相关工具将其添加到模型上下文中然后使用它们。只有 gpt-5.4 及更高版本的模型支持此功能。请阅读工具搜索指南工具搜索指南了解更多信息。Best practices for defining functions 定义函数的最佳实践Write clear and detailed function names, parameter descriptions, and instructions.编写清晰详细的函数名称、参数描述和指令。system promptInclude examples and edge cases, especially to rectify any recurring failures.意思加入例子和边界情况特别是模型经常犯错的地方。对于推理模型reasoning model大量例子可能反而降低效果Apply software engineering best practices.应用软件工程最佳实践Offload the burden from the model and use code where possible. 减轻模型的负担尽可能使用代码Keep the number of initially available functions small for higher accuracy. 为了提高精度应尽量减少初始可用函数的数量。Leverage OpenAI resources.充分利用 OpenAI 的资源Token Usage 代币使用情况Handling function calls 处理函数调用响应 output 数组包含一个 type 为 function_call 的条目。每个条目包含 call_id 稍后用于提交函数结果让模型知道是哪个函数调用的结果、 name 和 JSON 编码的 arguments即arguments是json字符串Formatting results 格式化结果传递给 function_call_output 消息中的结果通常应该是字符串字符串里面写什么格式你自己决定。模型并不要求一定 JSON。模型会根据上下文理解这个字符串。如果函数返回图片或文件可以传递图片或文件对象数组而不是字符串。如果函数没有返回值例如 send_email只需要返回表示成功或失败的字符串。input_messages.append({type:function_call_output,call_id:tool_call.call_id,output:str(result)})Incorporating results into response 将结果纳入应对措施Tool choice 工具选择默认情况下模型会决定何时以及使用多少工具。您可以使用 tool_choice 参数强制执行特定行为。自动 默认 调用零个、一个或多个函数。tool_choice: “auto”required 模型必须调用至少一个工具但具体调用哪个工具、调用几个工具由模型决定。 tool_choice: “required”强制函数Forced Function: 调用一个特定的函数不让模型选择强制它调用xx 函数。无论模型认为是否需要都必须调用。 tool_choice: {“type”: “function”, “name”: “get_weather”}.一次只能指定一个函数名,想限制在多个函数中选择使用 allowed_tools允许的工具 将模型可以调用的工具限制为模型可用工具的子集tool_choice{“type”: “allowed_tools”,“mode”: “auto”,设置 tool_choice“none”禁止模型调用任何工具从而达到“这次请求没有传入任何函数”的类似效果。此时模型能看到这些工具定义但不能生成工具调用只能直接返回普通文本回答。none 表示模型不会调用任何工具而是生成一条普通消息tool_choice 这个参数本身支持两种不同的数据形式tool_choice 字符串或者tool_choice 对象直接写 “auto” 或 required例如tool_choice“auto”已经完整表达了在所有已提供的工具中模型可以选择不调用也可以调用一个或多个。而tool_choice“required”已经完整表达了在所有已提供的工具中模型必须调用至少一个。所以用一个字符串就够了。使用 allowed_tools 时只写tool_choice“allowed_tools”信息是不完整的因为系统还不知道允许哪些工具允许不调用工具还是必须调用因此必须改成对象tool_choice{“type”: “allowed_tools”,“mode”: “auto”,“tools”: [{“type”: “function”, “name”: “get_weather”},{“type”: “function”, “name”: “search_docs”}]}这里每个字段分别表示type 这是什么类型的 tool_choice 配置mode 在允许的工具中是否必须调用tools 具体允许哪些工具官方说明中allowed_tools 对象的 mode 可以是 auto 或 requiredauto 允许从白名单中选择工具或直接回复required 模型必须调用至少一个工具但具体调用哪个工具、调用几个工具由模型决定When to use allowed_tools 何时使用 allowed_tools你可能希望使用 allowed_tools在每次请求中只开放全部工具的一部分同时保持传入的 tools 列表不变这样更容易命中 Prompt Caching从而减少输入成本。核心在于不要频繁修改 tools而是用 allowed_tools 动态限制本次能调用的工具。tools 给模型注册的完整工具库allowed_tools 本次请求允许模型使用的工具白名单tool_search先决定加载哪些工具使其变成“当前可调用” tool_choice再决定如何从“当前可调用工具”中进行调用tool_search 可以把延迟加载的工具搜索出来、加入模型上下文然后让模型使用tool_choice 只作用于当前回合已经可以调用的工具Parallel function calling 并行函数调用模型可能会在一次操作中调用多个函数。您可以通过将 parallel_tool_calls 设置为 false来防止这种情况这将确保只调用零个或一个工具。自定义 function → 模型返回 function_call → 你的程序执行 → 可以存在 parallel functioncallingbuilt-in tool → OpenAI 平台负责执行 → 不适用这种 parallel function calling 机制目前如果您使用的是经过微调的模型并且该模型在一次运算中调用多个函数则这些调用将禁用严格模式这一批同时产生的多个 function call不再应用 strict modefine-tuned model一次只调用 1 个函数 → strictTrue 正常生效fine-tuned model同一轮调用多个函数 → 这一轮这些调用 strict 失效这里说的 fine-tuned model 指的是 OpenAI API 里的微调模型也就是你基于某个 OpenAI 基础模型使用Fine-tuning API 再训练得到的自定义模型。这里说的 fine-tuned model微调模型就是指你通过 OpenAI 提供的 Fine-tuning API在一个支持微调的 OpenAI 基础模型上用自己的训练数据继续训练得到的自定义模型。Strict mode 严格模式strict 设置为 true 将确保函数调用始终严格遵循函数模式而不是尽力而为。我们建议始终启用严格模式如果你想让函数调用参数“严格符合你定义的 JSON Schema”就把这个函数的 strict 设置成 true开启 strictTrue 后你的 parameters 要满足额外规则。第一条“additionalProperties”: False必须给每一个 object 都设置。properties 中的所有字段都必须标记为 required您可以通过添加 null 作为 type 选项来表示可选字段schema 层面仍然把这个字段列为 required但是允许它的值为 null用 null 来表示“没有提供”。strictTrueproperties 里写了哪些字段 -》 required 里必须全部包含不允许额外字段 -》 additionalPropertiesFalse想要“可选字段” -》 不要从 required 删除 而是把 type 写成 [“xxx”, “null”]当你“不写 strict”时Responses API 和 Chat Completions API 的默认行为不一样。如果你明确写了“strict”: True那么你的 schema 就必须满足 strict mode 的规则比如“additionalProperties”: False而且 properties 里的字段都要出现在 required 中。如果不满足API 会直接拒绝这次请求而不是偷偷帮你按非 strict 模式执行完全不写 strict这时要看你用的是 Responses API 还是 Chat Completions API。你没有指定 strict↓ Responses API 尝试自动变成 strict↓ 能兼容 → strict 模式不能兼容 → 退回 non-strict / best-effort如果退回了 non-strict返回的工具定义里会显示“strict”: False如果你用的是client.chat.completions.create(…)那么不写 strict 时行为不同默认就是 non-strict也就是 best-effort function calling。它不会像 Responses API 那样默认尝试帮你转成 strict。Responses API strict 省略 → 尝试 strict → 不兼容才退回 non-strictChat Completions strict 省略 → 默认 non-strict如果你使用 Responses API但你明确就不想用 strict mode那不要仅仅省略 strict。写法Responses APIChat Completionsstrict: true强制 strict不符合要求则报错使用 strict不写strict尝试自动转成 strict失败再 non-strict默认 non-strictstrict: false明确 non-strict明确 non-strict在 OpenAI Playground 里自动生成出来的函数 schema默认都会开启 strict mode通过 Playground 的界面/生成器创建出来的 schema会按 strict 模式生成Playground 是 OpenAI 官方提供的一个网页调试界面可以理解成不写完整代码也能在网页上直接测试 OpenAI API。strict mode 底层依赖 Structured Outputs而 Structured Outputs 只支持 JSON Schema 的一个子集不是完整 JSON Schema 的所有能力都支持也就是说你不能认为“只要是标准 JSON Schema 语法都一定能放进 strict mode”。完整 JSON Schema↓OpenAI Structured Outputs 只支持其中一部分↓strict mode 也只能使用这一部分微调模型第一次碰到某个 strict schema 时OpenAI 后台需要先对这个 Schema 做额外处理strictTrue 很推荐│├─ 一般限制│ 不是完整 JSON Schema 都支持│└─ 对 fine-tuned model 还有两个限制1. 新 Schema 第一次要额外处理→ Schema 经常变化可能增加延迟2. Schema 会被缓存 → Schema 不符合 Zero Data Retentionstrict: true 并不是单纯给模型一句提示“请你一定按照这个 Schema 输出”而是会启用 Structured Outputs 的约束解码constrained decoding机制。OpenAI 官方也特别指出Structured Outputs 不能防止 JSON 值里的语义错误它保证结构符合 Schema但模型仍可能在字段值内容上犯错模型每生成一个 token 之前推理系统都会根据你的 JSON Schema 判断“哪些 token 此刻是合法的”然后把所有不合法token 的概率直接变成 0严格“结构正确” ≠ “内容一定正确”OpenAI 官方也特别指出Structured Outputs 不能防止 JSON 值里的语义错误它保证结构符合 Schema但模型仍可能在字段值内容上犯错严格“结构正确” ≠ “内容一定正确”严格“结构正确” ≠ “内容一定正确”OpenAI 官方也特别指出Structured Outputs 不能防止 JSON 值里的语义错误它保证结构符合 Schema但模型仍可能在字段值内容上犯错结构正确strict:true 可以保证key 对不对key 是否缺失value 类型对不对enum 对不对有没有额外字段JSON 结构是否符合 schema语义/事实正确strict:true 不能保证温度是不是真实的城市是不是选对了金额是不是算对了ID 是不是真实存在参数是否符合你的业务意图strict:true 之所以能够可靠保证 Schema不是因为 GPT“更听话了”而是因为 OpenAI 在生成 token的过程中使用 Structured Outputs 的 constrained decoding根据 Schema动态屏蔽所有会导致非法结构的 token。模型仍然负责在“合法 token”中选择具体内容那系统怎么知道什么 token 合法这里就是底层另一个关键步骤OpenAI 会先把你提供的 JSON Schema 转换成 CFGContext-Free Grammar上下文无关文法CFG 决定“哪些 token 合法”推理引擎负责根据 CFG 的判断结果把非法 token 屏蔽掉使它们在采样时的概率变成 0推理引擎就是让模型启动的推理框架吗是推理框架的一部分推理引擎就是让模型启动的推理框架吗大体可以这么理解但“推理引擎”和“推理框架”不是完全同义词。例如你自己部署开源模型时vLLM SGLang TensorRT-LLM Transformers这些通常可以叫推理框架 / serving framework而这些框架内部真正负责模型推理、调度、解码、采样等工作的部分可以叫inference engine推理引擎但我们不知道 OpenAI 内部具体使用什么推理框架。官方只公开描述“our inference engine” 会根据 grammar 判断下一步有效 token并 mask 无效 token模型负责给 token 打分CFG 负责判断哪些 token 符合 Schema推理引擎负责使用 CFG 的结果屏蔽非法token并从剩下的合法 token 中采样真正的硬约束主要是推理框架/推理引擎实现的不是模型天然保证的Streaming 流函数调用也可以像普通文本回复一样“流式返回”而不是等模型把完整的函数名和所有参数都生成完以后你才一次性拿到结果response.function_call_arguments.delta官方定义就是函数调用参数的一部分增量。官方 Streaming Events 里同时定义了 response.function_call_arguments.delta 和 response.function_call_arguments.done在 Responses API 的函数调用流式事件里函数名本身不是像参数那样一个字符一个字符地 delta流出来的。官方示例里当函数调用刚开始时会先收到一个 response.output_item.added 事件这个事件中的 item已经带着完整的 name例如 name: “get_weather”而 arguments 此时还是空字符串。随后才会连续收到response.function_call_arguments.delta这些事件只是在增量返回 arguments 字段最后再收到response.function_call_arguments.done表示完整参数已经生成完。官方文档明确说明response.output_item.added 里的函数调用项包含 name、arguments、id之后的 response.function_call_arguments.delta 事件只包含 arguments 的增量response.output_item.added→ 已经知道name “get_weather”arguments “”然后response.function_call_arguments.delta → { → location → “:” → Paris→ , France → }最后 response.function_call_arguments.doneChat Completions 里的“函数流式调用”本质上就是设置 streamTrue 后模型不是等完整的 tool_calls 都生成完再一次性返回而是通过一系列chunk把函数调用信息逐步返回给你OpenAI 原始 streaming 的核心是 delta 增量累计流一般是在客户端基于 delta 拼出来的Chat Completions 的官方文档明确说明streaming 返回的是一系列 ChatCompletionChunk其中使用 delta 而不是完整的 message官方示例也是直接把每个 delta.content 依次输出多个函数同时调用时为什么还有 index但是您不是将数据块聚合到一个单独的 content 字符串中而是将数据块聚合到一个编码后的 arguments JSON 对象中如果模型这一轮决定调用一个或多个函数那么每产生一个函数调用Responses API 都会先发出一个response.output_item.added 事件之后各自的参数 delta 会通过 item_id / output_index 告诉你它属于哪个函数调用。当模型调用一个或多个函数时每次函数调用都会发出一个类型为 response.output_item.added的事件该事件包含以下字段response_id 响应 ID函数调用所属的响应的 IDoutput_index 输出索引响应中输出项的索引。这代表响应中的各个函数调用。item 正在进行中的函数调用项包含 name 、 arguments 和 id 字段之后您将收到一系列类型为 response.function_call_arguments.delta 的事件其中包含 arguments 字段的 delta字段含义response_id这次整个模型响应的 IDitem_id这个 delta 属于哪一个具体的 function calloutput_index这个 function call 在response.output数组里的位置delta这一次新生成的arguments参数片段 delta 不是当前完整参数只是本次新增的一小段。response_id -》 哪一次完整模型响应output_index -》这个函数调用在 response.output 的哪个位置item_id -》 这个具体 function_call item 的唯一 IDdelta -》 这个 function_call 的 arguments 本次新增了什么当模型完成函数调用后将发出一个类型为 response.function_call_arguments.done的事件。此事件包含完整的函数调用信息包括以下字段response_id这个函数调用属于哪一次完整 Response。output_index这个函数调用是 response.output 中第几个 output item例如 0 表示 response.output[0]。item这个已经生成完整的 function-call item其中可以拿到函数名和完整参数。Custom tools 自定义工具OpenAI 官方把 function tool 定义为基于 JSON Schema 的工具而 custom tool 则使用自由文本输入最容易理解的对比是function tool→ 模型必须生成 JSON 参数custom tool→ 模型可以直接生成任意字符串Context-free grammars 上下文无关文法可以给 custom tool 的自由文本输入加一套“语法规则”让模型只能生成符合这些规则的字符串。CFGContext-Free Grammar上下文无关文法。OpenAI 文档把 CFG 定义为一组规则用于规定什么样的文本才是有效格式custom tool 可以通过 grammar 来约束模型生成的工具输入。最简单地说没有 grammar模型可以随便生成字符串有 grammar模型只能生成符合你定义语法的字符串Function Calling 原理在底层函数会以模型训练时所用的语法注入到系统消息中Token Usage 章节从 API 使用者角度你传的是 input tools但 OpenAI 官方说底层会把函数定义注入 system messageOpenAI 的 LLM 底层仍然是在生成 token当它决定调用函数时会按照训练过的“工具调用语法”生成一段特殊的工具调用表示。OpenAI API 服务层再把这种输出组织成你看到的结构化 function_call / tool_calls 对象LLM 生成 token↓这些 token 可能表示普通文本或者工具调用↓OpenAI 服务层识别/处理↓按照 API 协议返回普通文本 → output_text/message.content 工具调用 → function_call/tool_callstoken loopLLM 内部 token 循环,推理引擎不断让模型预测下一个 token把新 token 接到已生成序列后面再继续预测直到满足停止条件。LLM 内部 token 循环,推理引擎不断让模型预测下一个 token把新 token接到已生成序列后面再继续预测直到满足停止条件。推理引擎根据当前上下文预测下一个 token把新生成的 token 加入“已生成序列”再继续预测直到遇到模型的结束标记、命中 stop sequence、达到最大输出 token 限制等停止条件。推理引擎以输入 token 为上下文让模型预测下一个 token随后把新生成 token 加入当前生成上下文继续预测下一个 token如此循环直到生成 EOS、命中 stop sequence、达到最大输出长度或其他停止条件。原始输入 token模型已经生成的 token下一步预测时的当前上下文input_tokens 你原来给模型的generated_tokens 模型一轮一轮新生成的current context input_tokens generated_tokens下一步预测时的上下文 input_tokens generated_tokens 其中input_tokens 一开始传给模型的输入generated_tokens 模型到目前为止已经生成出来的 tokengenerated_tokens 既是当前已经生成的输出也是下一次 token 预测所需要的上下文的一部分例如input_tokens [A, B, C]第一次生成D此时generated_tokens [D]下一次预测上下文 [A, B, C, D]再生成 Egenerated_tokens [D, E]下一次预测上下文 [A, B, C, D, E]预测用input_tokens generated_tokens返回用generated_tokensgenerated_tokens后面有很多用途比如 API 最终只需要返回新生成部分、统计 input_tokens 和 output_tokens、做 streaming、检查最大输出长度等推理引擎负责“生成”推理框架的 API 服务层负责“封装和返回”。推理引擎负责生成推理框架的 serving/API 层 负责把生成结果转换、组织成接口协议推理引擎负责生成 token推理框架的 serving/API 层负责把这些生成结果转换成文本或结构化结果再按照 API 协议组织并返回。怎么知道什么时候不再吐 token不是永远循环它有停止条件。除了模型自己生成结束标记之外还可能因为其他条件停止比如达到最大输出 token 数 命中你配置的 stop sequence 工具调用这一轮已经结束 API/系统规定的其他终止条件。OpenAI 文档也说明可以通过 stop/stop sequences 或最大输出 token 限制让生成提前结束。推理引擎不断让模型预测下一个 token并把新 token接到已有上下文后继续预测每生成一步都会检查停止条件直到模型生成自然结束标记、命中 stop sequence、达到长度限制或者当前tool call 等输出项已经完成然后退出 token generation loop。推理引擎是靠停止条件判断“不要再生成下一个 token 了”的。 最常见的就是这几种模型生成了自然结束标记 / EOS命中了你设置的 stop sequence达到了最大输出 token 数某些安全/系统原因强制终止模型自己生成了自然结束标记最正常的情况模型自己生成 EOS模型词表里通常会有某种特殊的结束 token 不是模型突然“不输出了”而是模型实际上预测出了一个表示结束的特殊token推理引擎看到后停止继续调用模型生成下一个 token。stop sequence 是推理系统额外检查的stop sequence。它本质上只是普通文本序列模型正常生成时碰巧/按语义生成到了这段内容推理服务发现“当前输出已经匹配你配置的stop sequence”于是停止后续生成。OpenAI 官方说明stop sequence用来让模型在生成到指定序列时停止而且返回内容里不会包含这段 stop sequence达到 max_output_tokens而被强制截断还可能因为 达到 max_output_tokens 而被强制截断。OpenAI 的 Responses API 可以用max_output_tokens 限制模型最多生成多少 output tokens。某些安全/系统原因强制终止 生成过程被服务端或外部状态中断/截断finish_reason是 API 层对“这一轮为什么结束/这一轮输出是什么性质”的描述finish_reason 是 API 层给“一次 Chat Completion 为什么结束”做的分类不等同于底层 token loop 里的某个 if 条件目前 Chat Completions 的 finish_reason 一共有 5 个取值stoplengthtool_callscontent_filterfunction_call # 已废弃token loop 负责把这一轮模型输出生成完整finish_reason 是 Chat Completions API在这一轮结束后对“为什么/以什么形式结束”给出的状态分类。tool_calls表示这一轮最终产生了一个或多个工具调用并不意味着生成第一个 function call 时 token loop 就立即停止。finish_reason “tool_calls”底层 generation/token loop不断生成 token -》直到这一轮生成终止然后API 层检查这一轮是以什么情况结束的-》给出 finish_reason平常调用一次 LLM只有“token loop”Agent 在 token loop 外面又套了一层“agent loop”。tool_choice Parallel function calling 也是推理框架决定
返回列表