<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Function Calling on Weiuou的博客</title><link>https://blog.weiuou.top/tags/function-calling/</link><description>Recent content in Function Calling on Weiuou的博客</description><image><title>Weiuou的博客</title><url>https://blog.weiuou.top/avatar.png</url><link>https://blog.weiuou.top/avatar.png</link></image><generator>Hugo</generator><language>zh-cn</language><copyright>Weiuou</copyright><lastBuildDate>Sun, 05 Jul 2026 18:00:00 +0800</lastBuildDate><atom:link href="https://blog.weiuou.top/tags/function-calling/index.xml" rel="self" type="application/rss+xml"/><item><title>AI Agent 开发</title><link>https://blog.weiuou.top/topics/ai-agent-development/</link><pubDate>Sun, 05 Jul 2026 18:00:00 +0800</pubDate><guid>https://blog.weiuou.top/topics/ai-agent-development/</guid><description>AI Agent 开发学习路线：从 Agent Loop 到 Harness、Tracing、Eval、Function Calling 和安全边界。</description><content:encoded><![CDATA[<p>AI Agent 开发不是把 LLM 接上几个工具就结束了，而是围绕模型建立一套可执行、可观察、可恢复、可评测的工程系统。</p>
<h2 id="一句话定义">一句话定义</h2>
<p>AI Agent 是一个能根据目标选择动作、调用工具、读取反馈并继续决策的系统；Agent 开发的重点，是把这个循环约束在可靠的工程边界里。</p>
<h2 id="推荐阅读顺序">推荐阅读顺序</h2>
<ol>
<li><a href="/posts/my-first-agent-loop-problems/">Agent开发笔记（1）我第一次手写 Agent Loop 遇到的问题</a></li>
<li><a href="/posts/agent-dev-notes-2-mini-agent-harness/">Agent开发笔记（2）从 Agent Loop 到 Mini Agent Harness</a></li>
<li><a href="/posts/agent-tracing/">Agent Tracing：理解 Agent 执行过程的可观测性</a></li>
<li><a href="/posts/agent-dev-notes-3-agent-eval-harness/">Agent开发笔记（3）从Agent Eval看为什么llm和harness是共同优化的整体</a></li>
<li><a href="/posts/agent-dev-notes-4-code-agent-sandbox-tool-permission/">Agent开发笔记（4）Code Agent 的 Sandbox 和 Tool Permission</a></li>
<li><a href="/posts/agent-development-common-problems/">Agent开发中的常见问题</a></li>
<li><a href="/posts/function-calling-notes/">Function Calling</a></li>
</ol>
<h2 id="核心概念表">核心概念表</h2>
<table>
	<thead>
			<tr>
					<th>概念</th>
					<th>作用</th>
					<th>相关问题</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Agent Loop</td>
					<td>让模型在生成、工具调用、观察之间循环</td>
					<td>什么时候停止，工具错误怎么返回</td>
			</tr>
			<tr>
					<td>Tool / Function Calling</td>
					<td>把模型意图转换为受控的外部能力</td>
					<td>schema、参数校验、tool choice</td>
			</tr>
			<tr>
					<td>Agent Harness</td>
					<td>包装 loop 的工程运行时</td>
					<td>trace、replay、错误恢复、安全边界</td>
			</tr>
			<tr>
					<td>Tracing</td>
					<td>记录一次 Agent run 的执行过程</td>
					<td>哪一步失败，为什么失败</td>
			</tr>
			<tr>
					<td>Eval Harness</td>
					<td>用固定任务集评估改动效果</td>
					<td>改 prompt、tool schema 后有没有变好</td>
			</tr>
			<tr>
					<td>Guardrail</td>
					<td>在高风险动作前后做约束</td>
					<td>权限、注入、敏感信息、输出处理</td>
			</tr>
	</tbody>
</table>
<h2 id="学习路径">学习路径</h2>
<p>先理解最小 Agent Loop，再给它补上工具结果格式、trace、错误恢复和上下文管理。等系统可以稳定复盘后，再引入 eval，用固定任务判断改动是否真的提升了行为。</p>
<p>对于真实应用，安全边界要尽早进入设计。模型可以提出动作意图，但系统必须决定它是否真的有权执行。</p>
<h2 id="延伸阅读">延伸阅读</h2>
<ul>
<li><a href="/posts/vibe-coding-ai-prototype-overengineering/">Vibe Coding AI 应用原型时，别让“过度工程化”掩盖了真正的问题</a></li>
<li><a href="/about/">关于 Weiuou 和这个博客</a></li>
</ul>
]]></content:encoded></item><item><title>Function Calling</title><link>https://blog.weiuou.top/posts/function-calling-notes/</link><pubDate>Mon, 29 Jun 2026 23:59:00 +0800</pubDate><guid>https://blog.weiuou.top/posts/function-calling-notes/</guid><description>学习 Function calling 时整理的一些笔记，包括函数定义、namespace、最佳实践、tool choice、并行调用、严格模式和 streaming。</description><content:encoded><![CDATA[<h2 id="本文结论">本文结论</h2>
<ul>
<li>Function calling 的本质是让模型输出受 schema 约束的工具调用意图，再由程序决定是否执行。</li>
<li>工具描述、参数 schema、tool choice 和工具数量，会直接影响模型选择工具和生成参数的稳定性。</li>
<li>严格模式适合默认开启，但需要遵守 <code>additionalProperties: false</code>、字段 required 和可空类型等约束。</li>
<li>Streaming 不只适合展示文本进度，也可以实时观察函数参数是如何逐步生成的。</li>
</ul>
<h2 id="适合谁读">适合谁读</h2>
<ul>
<li>正在给 LLM 应用接入外部工具、数据库或业务 API 的开发者。</li>
<li>想理解 tool schema、tool choice、并行调用和严格模式如何影响 Agent 行为的人。</li>
<li>准备把 Function calling 放进 Agent Harness 或 MCP 工具体系里的人。</li>
</ul>
<h2 id="什么是-function-calling">什么是 Function calling</h2>
<p>Function calling 是一种强大且灵活的方式，让 LLM 能够与外部系统进行交互，获取模型训练数据之外的大量信息。</p>
<blockquote>
<p>如果 AI 应用程序包含复杂的功能或数据库结构，可以将函数调用与工具搜索功能结合，来按需加载工具，不过只有少部分新模型支持 <code>tool_search</code>。</p>
</blockquote>
<h2 id="function-calling-定义与主要参数">Function calling 定义与主要参数</h2>
<p>function 的定义就比较简单，也是使用 JSON Schema，例子如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Retrieves current weather for the given location.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;parameters&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;location&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;City and country e.g. Bogotá, Colombia&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;units&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;enum&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;celsius&#34;</span><span class="p">,</span> <span class="s2">&#34;fahrenheit&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Units the temperature will be returned in.&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;location&#34;</span><span class="p">,</span> <span class="s2">&#34;units&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;additionalProperties&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;strict&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>其中主要的参数和作用如下：</p>
<table>
	<thead>
			<tr>
					<th>Field</th>
					<th>Description</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>type</code></td>
					<td><code>function</code></td>
			</tr>
			<tr>
					<td><code>name</code></td>
					<td>函数的名称（例如：<code>get_weather</code>）</td>
			</tr>
			<tr>
					<td><code>description</code></td>
					<td>关于该功能的使用时间与方式的详细说明</td>
			</tr>
			<tr>
					<td><code>parameters</code></td>
					<td>用于定义该函数输入参数的 JSON 模式</td>
			</tr>
			<tr>
					<td><code>strict</code></td>
					<td>是否对函数调用启用严格模式</td>
			</tr>
	</tbody>
</table>
<p>然后比较有意思的是 namespaces 的概念，类似于编程语言中的命名空间，有助于帮助 AI 整理和选择各种类似的工具。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;namespace&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;crm&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;CRM tools for customer lookup and order management.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;tools&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_customer_profile&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Fetch a customer profile by customer ID.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;parameters&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;customer_id&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;customer_id&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;additionalProperties&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;list_open_orders&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;List open orders for a customer ID.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;defer_loading&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;parameters&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;customer_id&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;customer_id&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;additionalProperties&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>例如上面这个用于 CRM 系统的搜索工具，还可以定义其他的比如 OA 系统的 xx 工具。一旦你希望你的 AI 应用于庞大的工具生态，可以使用前面提到的 <code>tool_search</code> 来延迟加载部分或全部工具。</p>
<h2 id="最佳实践">最佳实践</h2>
<ol>
<li>编写详细、清晰的函数名称、参数说明以及使用说明。
<ul>
<li>明确说明函数用途，参数的用途以及格式，输出的结果代表什么含义。</li>
<li>利用 system prompt 来说明什么时候应该/不该使用某功能。</li>
<li>举例说明常见的情况和边缘情况，尤其是容易反复出现错误的情况。</li>
<li>对于延迟加载的工具，应在函数描述中提供详细的操作指南同时保持命名空间简洁，这分别有助于 LLM 正确使用已加载工具和正确决定应该加载哪个工具。</li>
</ul>
</li>
<li>遵循软件工程的最佳实践。
<ul>
<li>让工具直观易用。</li>
<li>用枚举和对象结构来确保无效状态无法被表达出来。</li>
<li>将工具提供给小白，看他们能否正确使用功能，如果不能，将他们提出的问题的答案写在 prompt 中。</li>
</ul>
</li>
<li>尽量减轻 LLM 负担，使用代码处理相关任务。
<ul>
<li>例如一个多轮工具调用的 workflow，需要使用同一个 <code>order_id</code>，那就不要在后续的调用中设置这个参数，而是通过代码来传递参数。</li>
<li>将总是按顺序被调用的函数组合在一起，减少 LLM 决策压力。</li>
</ul>
</li>
<li>为了 LLM 调用准确性，减少初始可用的工具数量。
<ul>
<li>尝试使用不同数量的工具来评估 AI 应用的表现。</li>
<li>建议每轮开始时，限制可用工具数量在 20 以内。</li>
<li>使用 <code>tool_search</code> 隐藏工具中不常被使用的部分。</li>
</ul>
</li>
</ol>
<h2 id="处理-function-calling">处理 Function calling</h2>
<p>类似于后端的工作，把收到的请求路由到不同的程序来处理，然后将结果包装成符合格式的形式，然后将分析结果添加到 input 中，反馈给 LLM。</p>
<h2 id="其他配置选项">其他配置选项</h2>
<p>默认情况下，模型会自行决定何时使用何种工具，以及使用多少个工具。你可以通过 <code>tool_choice</code> 参数来强制指定特定的行为。</p>
<ol>
<li><code>auto</code>：自动模式（默认）调用 0 个、1 个或多个函数。</li>
<li><code>required</code>：要求至少调用一个函数。</li>
<li><code>forced function</code>：强调必须调用某个特定函数，且只调用一次。</li>
<li><code>allowed tools</code>：允许使用的工具，限制模型可用的工具范围。</li>
</ol>
<h2 id="并行函数调用">并行函数调用</h2>
<blockquote>
<p>使用内置工具时无法实现并行函数调用。</p>
</blockquote>
<p>模型可能在一轮调用中选择调用多个工具，可以将 <code>parallel_tool_calls</code> 设置为 <code>false</code> 来避免这种情况，这样就能保证恰好调用 0 或 1 个函数。</p>
<h2 id="严格模式">严格模式</h2>
<p>将 <code>strict</code> 设置为 <code>true</code> 后，可以确保函数调用始终符合函数规范，而不是尽力符合规范，通常建议始终开启严格模式，同时该模式也带来了一些要求：</p>
<ul>
<li><code>additionalProperties</code> 必须为 <code>parameters</code> 中的每个对象设置为 <code>false</code>。</li>
<li>所有的 <code>properties</code> 字段必须标记为 <code>required</code>。</li>
<li>在可选字段前加 <code>null</code> 来标记该字段为可选项。</li>
</ul>
<p>如果在请求中发送了 <code>strict: true</code> 但是架构不符合上述要求，请求会被拒绝。</p>
<h2 id="streaming-传输">Streaming 传输</h2>
<p>通过流式处理，可以了解 LLM 的处理进度：即能够显示模型处理过程中调用了哪些函数，甚至实时展示函数的参数，只需要将 <code>stream</code> 设置为 <code>true</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">openai</span> <span class="kn">import</span> <span class="n">OpenAI</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">OpenAI</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">tools</span> <span class="o">=</span> <span class="p">[{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;function&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Get current temperature for a given location.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;parameters&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;location&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;City and country e.g. Bogotá, Colombia&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;location&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;additionalProperties&#34;</span><span class="p">:</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">responses</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="s2">&#34;gpt-5.5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nb">input</span><span class="o">=</span><span class="p">[{</span><span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="s2">&#34;What&#39;s the weather like in Paris today?&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="cl">    <span class="n">tools</span><span class="o">=</span><span class="n">tools</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">stream</span><span class="o">=</span><span class="kc">True</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">stream</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.output_item.added&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;item&#34;</span><span class="p">:{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;function_call&#34;</span><span class="p">,</span><span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;call_id&#34;</span><span class="p">:</span><span class="s2">&#34;call_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;get_weather&#34;</span><span class="p">,</span><span class="nt">&#34;arguments&#34;</span><span class="p">:</span><span class="s2">&#34;&#34;</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.function_call_arguments.delta&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;item_id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;delta&#34;</span><span class="p">:</span><span class="s2">&#34;{\&#34;&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.function_call_arguments.delta&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;item_id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;delta&#34;</span><span class="p">:</span><span class="s2">&#34;location&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.function_call_arguments.delta&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;item_id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;delta&#34;</span><span class="p">:</span><span class="s2">&#34;\&#34;:\&#34;&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.function_call_arguments.delta&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;item_id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;delta&#34;</span><span class="p">:</span><span class="s2">&#34;Paris&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.function_call_arguments.delta&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;item_id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;delta&#34;</span><span class="p">:</span><span class="s2">&#34;,&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.function_call_arguments.delta&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;item_id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;delta&#34;</span><span class="p">:</span><span class="s2">&#34; France&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.function_call_arguments.delta&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;item_id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;delta&#34;</span><span class="p">:</span><span class="s2">&#34;\&#34;}&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.function_call_arguments.done&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;item_id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;arguments&#34;</span><span class="p">:</span><span class="s2">&#34;{\&#34;location\&#34;:\&#34;Paris, France\&#34;}&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;response.output_item.done&#34;</span><span class="p">,</span><span class="nt">&#34;response_id&#34;</span><span class="p">:</span><span class="s2">&#34;resp_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;output_index&#34;</span><span class="p">:</span><span class="mi">0</span><span class="p">,</span><span class="nt">&#34;item&#34;</span><span class="p">:{</span><span class="nt">&#34;type&#34;</span><span class="p">:</span><span class="s2">&#34;function_call&#34;</span><span class="p">,</span><span class="nt">&#34;id&#34;</span><span class="p">:</span><span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;call_id&#34;</span><span class="p">:</span><span class="s2">&#34;call_1234xyz&#34;</span><span class="p">,</span><span class="nt">&#34;name&#34;</span><span class="p">:</span><span class="s2">&#34;get_weather&#34;</span><span class="p">,</span><span class="nt">&#34;arguments&#34;</span><span class="p">:</span><span class="s2">&#34;{\&#34;location\&#34;:\&#34;Paris, France\&#34;}&#34;</span><span class="p">}}</span>
</span></span></code></pre></div><p>以下是代码示例，用来将多个 <code>delta</code> 对象合并为最终的 <code>tool_call</code> 对象：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">final_tool_calls</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">stream</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="s2">&#34;response.output_item.added&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">final_tool_calls</span><span class="p">[</span><span class="n">event</span><span class="o">.</span><span class="n">output_index</span><span class="p">]</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">item</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="s2">&#34;response.function_call_arguments.delta&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">index</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">output_index</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">final_tool_calls</span><span class="p">[</span><span class="n">index</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">            <span class="n">final_tool_calls</span><span class="p">[</span><span class="n">index</span><span class="p">]</span><span class="o">.</span><span class="n">arguments</span> <span class="o">+=</span> <span class="n">event</span><span class="o">.</span><span class="n">delta</span>
</span></span></code></pre></div><p>最终的 <code>final_tool_calls[0]</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;function_call&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;fc_1234xyz&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;call_id&#34;</span><span class="p">:</span> <span class="s2">&#34;call_2345abc&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;get_weather&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;arguments&#34;</span><span class="p">:</span> <span class="s2">&#34;{\&#34;location\&#34;:\&#34;Paris, France\&#34;}&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="常见问题">常见问题</h2>
<h3 id="function-calling-是让模型直接执行函数吗">Function calling 是让模型直接执行函数吗？</h3>
<p>不是。模型通常只生成函数名和参数，真正执行函数的是你的程序。程序仍然需要做参数校验、权限判断、错误包装和结果回传。</p>
<h3 id="strict-mode-为什么还需要服务端校验">strict mode 为什么还需要服务端校验？</h3>
<p>严格模式能提高模型输出符合 schema 的概率，但它不是业务权限边界。路径、权限、枚举、资源归属、危险动作确认这些检查仍然应该在服务端或 Harness 层完成。</p>
<h3 id="tool-choice-应该什么时候使用-required">tool choice 应该什么时候使用 required？</h3>
<p>当任务流程明确需要至少调用一个工具时可以使用 <code>required</code>。如果问题本身可能直接回答，长期强制调用工具会增加成本，也可能让模型做不必要的动作。</p>
<h2 id="延伸阅读">延伸阅读</h2>
<ul>
<li><a href="/topics/ai-agent-development/">AI Agent 开发</a></li>
<li><a href="/posts/my-first-agent-loop-problems/">Agent开发笔记（1）我第一次手写 Agent Loop 遇到的问题</a></li>
<li><a href="/posts/agent-development-common-problems/">Agent开发中的常见问题</a></li>
</ul>
]]></content:encoded></item></channel></rss>