<?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>AI Agent on Weiuou的博客</title><link>https://blog.weiuou.top/tags/ai-agent/</link><description>Recent content in AI Agent 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/ai-agent/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>MCP 学习路线</title><link>https://blog.weiuou.top/topics/mcp-learning-path/</link><pubDate>Sun, 05 Jul 2026 18:00:00 +0800</pubDate><guid>https://blog.weiuou.top/topics/mcp-learning-path/</guid><description>MCP 学习路线：从 MCP 是什么、MCP 架构到 Server 的 Tools、Resources 和 Prompts。</description><content:encoded><![CDATA[<p>MCP 的价值在于把 AI 应用和外部系统之间的连接方式标准化。理解 MCP 时，不要只看“它能调用工具”，还要看 Host、Client、Server 如何分工。</p>
<h2 id="一句话定义">一句话定义</h2>
<p>MCP 是一种让 AI 应用连接外部工具、数据源和提示模板的开放协议，可以把它理解为 AI 应用访问外部上下文的标准接口。</p>
<h2 id="推荐阅读顺序">推荐阅读顺序</h2>
<ol>
<li><a href="/posts/what-is-mcp/">什么是 MCP</a></li>
<li><a href="/posts/mcp-architecture/">MCP 架构</a></li>
<li><a href="/posts/mcp-server-tools-resources-prompts/">MCP Server</a></li>
<li><a href="/topics/ai-agent-development/">AI Agent 开发</a></li>
</ol>
<h2 id="核心概念表">核心概念表</h2>
<table>
	<thead>
			<tr>
					<th>概念</th>
					<th>作用</th>
					<th>常见例子</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>MCP Host</td>
					<td>使用 MCP 能力的 AI 应用</td>
					<td>Codex、Claude Desktop</td>
			</tr>
			<tr>
					<td>MCP Client</td>
					<td>Host 内部负责连接某个 Server 的组件</td>
					<td>每个 Server 通常对应一个 Client</td>
			</tr>
			<tr>
					<td>MCP Server</td>
					<td>向 AI 应用暴露能力的程序</td>
					<td>文件系统、GitHub、数据库、浏览器</td>
			</tr>
			<tr>
					<td>Tools</td>
					<td>主动执行动作的接口</td>
					<td>搜索、写入、调用 API</td>
			</tr>
			<tr>
					<td>Resources</td>
					<td>只读上下文或数据源</td>
					<td>文件、文档、数据库记录</td>
			</tr>
			<tr>
					<td>Prompts</td>
					<td>可复用的任务模板</td>
					<td>代码审查模板、调研模板</td>
			</tr>
	</tbody>
</table>
<h2 id="学习路径">学习路径</h2>
<p>先弄清楚 MCP 解决的是“连接标准化”问题，再理解 C-S 架构里的 Host、Client、Server。之后再看 Server 暴露的三类能力：Tools、Resources、Prompts。</p>
<p>如果你已经在做 Agent 应用，可以把 MCP 放到工具生态和上下文管理里理解：它不是替代 Agent Harness，而是给 Harness 提供更标准的能力入口。</p>
<h2 id="延伸阅读">延伸阅读</h2>
<ul>
<li><a href="/posts/function-calling-notes/">Function Calling</a></li>
<li><a href="/posts/agent-development-common-problems/">Agent开发中的常见问题</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><item><title>什么是 MCP</title><link>https://blog.weiuou.top/posts/what-is-mcp/</link><pubDate>Wed, 24 Jun 2026 09:10:00 +0800</pubDate><guid>https://blog.weiuou.top/posts/what-is-mcp/</guid><description>MCP 是一种用于将 AI 应用与外部系统相连的开源协议，可以理解为 AI 应用的 USB-C 协议。</description><content:encoded><![CDATA[<h2 id="本文结论">本文结论</h2>
<ul>
<li>MCP 是一种让 AI 应用连接外部工具、数据源和提示模板的开放协议。</li>
<li>它解决的是“AI 应用如何标准化访问外部上下文和能力”的问题。</li>
<li>MCP 常被类比为 AI 应用的 USB-C：不同应用和工具可以围绕同一套接口连接。</li>
<li>理解 MCP 时，要同时理解 Host、Client、Server，以及 Tools、Resources、Prompts 三类能力。</li>
</ul>
<h2 id="适合谁读">适合谁读</h2>
<ul>
<li>第一次听到 MCP，想快速理解它解决什么问题的人。</li>
<li>正在使用 Codex、Claude 等 AI 应用，想知道它们如何连接外部工具的人。</li>
<li>准备开发 MCP Server 或把 MCP 放进 Agent 工具体系里的人。</li>
</ul>
<h2 id="mcp-的定义">MCP 的定义</h2>
<p>MCP 是 Model Context Protocol 的缩写，是一种用于将 AI 应用与外部系统相连的开源协议。借助 MCP，AI 应用可以获取所需的信息并完成各种任务。</p>
<p>通俗地讲，可以把 MCP 理解为 AI 应用的 “USB-C” 协议。USB-C 为电子设备提供标准化连接方式，MCP 则为 AI 应用访问工具、数据和提示模板提供标准化接口。</p>
<h2 id="mcp-可以用来做什么">MCP 可以用来做什么</h2>
<p>通过 MCP，智能体可以访问邮箱、日历、代码仓库、文件系统、数据库、设计工具和浏览器等外部系统。常见场景包括：</p>
<ul>
<li>连接 GitHub，读取 issue、PR 或仓库内容。</li>
<li>连接数据库，通过自然语言分析数据。</li>
<li>连接文件系统，让 AI 应用读取或整理本地项目。</li>
<li>连接 Figma、Blender 等创作工具，把 AI 生成能力接入设计和 3D 工作流。</li>
<li>连接内部系统，让客服、运维或数据分析 Agent 使用企业上下文。</li>
</ul>
<h2 id="mcp-由哪些部分组成">MCP 由哪些部分组成</h2>
<p>理解 MCP 时，可以先看三层角色：</p>
<table>
	<thead>
			<tr>
					<th>角色</th>
					<th>作用</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>MCP Host</td>
					<td>使用 MCP 能力的 AI 应用，例如 Codex 或 Claude Desktop</td>
			</tr>
			<tr>
					<td>MCP Client</td>
					<td>Host 内部负责连接某个 MCP Server 的组件</td>
			</tr>
			<tr>
					<td>MCP Server</td>
					<td>暴露工具、资源和提示模板的程序</td>
			</tr>
	</tbody>
</table>
<p>MCP Server 通常提供三类能力：</p>
<table>
	<thead>
			<tr>
					<th>能力</th>
					<th>作用</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Tools</td>
					<td>可以被 AI 应用主动调用的动作，例如搜索、写入、调用 API</td>
			</tr>
			<tr>
					<td>Resources</td>
					<td>只读上下文或数据源，例如文件、文档、数据库记录</td>
			</tr>
			<tr>
					<td>Prompts</td>
					<td>可复用的任务模板，用来指导模型完成特定工作</td>
			</tr>
	</tbody>
</table>
<h2 id="常见误区">常见误区</h2>
<h3 id="mcp-不是一个具体工具">MCP 不是一个具体工具</h3>
<p>MCP 是协议，不是某一个单独的应用。文件系统 Server、GitHub Server、数据库 Server 都可以是 MCP Server。</p>
<h3 id="mcp-不等于-agent-harness">MCP 不等于 Agent Harness</h3>
<p>MCP 提供标准化连接方式，但 Agent 仍然需要自己的 Harness 来处理权限、trace、错误恢复、上下文管理和 eval。</p>
<h3 id="mcp-不会自动解决安全问题">MCP 不会自动解决安全问题</h3>
<p>MCP Server 暴露能力之后，仍然要认真设计权限、确认机制和审计。尤其是写文件、发请求、改数据库这类动作，不能只靠模型自觉。</p>
<h2 id="延伸阅读">延伸阅读</h2>
<ul>
<li><a href="/topics/mcp-learning-path/">MCP 学习路线</a></li>
<li><a href="/posts/mcp-architecture/">MCP 架构</a></li>
<li><a href="/posts/mcp-server-tools-resources-prompts/">MCP Server</a></li>
</ul>
]]></content:encoded></item></channel></rss>