<?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>LangChain Core Components on On My Way</title>
    <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/</link>
    <description>Recent content in LangChain Core Components on On My Way</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <atom:link href="https://tuanzi-wow.cn/frameworks/langchain/core_components/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>9 月 20 日学习报告：LangChain Agent 的 Tool、Memory 与 Streaming</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/langchain-agent-study-report-2026-09-20/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/langchain-agent-study-report-2026-09-20/</guid>
      <description>按修改时间与源文件结构整理 Tool、short-term memory、Event Streaming 和 Streaming。</description>
      <content:encoded><![CDATA[<h1 id="9-月-20-日学习报告langchain-agent-的-toolmemory-与-streaming">9 月 20 日学习报告：LangChain Agent 的 Tool、Memory 与 Streaming</h1>
<p>仅整理 2026-09-20 修改的 4 个文件。文件按最后修改时间排列；各文件内部保持原文标题顺序与层级，只压缩重复表述和示例，不省略知识点。</p>
<h2 id="140852--toolsmd">14:08:52 — Tools.md</h2>
<h3 id="tools">Tools</h3>
<p>Tools extend what agents can do。</p>
<h3 id="create-tools">Create tools</h3>
<h4 id="basic-tool-definition">Basic tool definition</h4>
<p>定义 Tool 最简单的方式是使用 <code>@tool</code> decorator。函数 docstring 会成为 Tool description；参数 type hints 是必须的，因为它们定义 Tool 的输入 Schema。docstring 应内容丰富且简明扼要。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<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">langchain.tools</span> <span class="kn">import</span> <span class="n">tool</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">search_database</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">limit</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Search the customer database for records matching the query.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    Args:
</span></span></span><span class="line"><span class="cl"><span class="s2">        query: Search terms to look for
</span></span></span><span class="line"><span class="cl"><span class="s2">        limit: Maximum number of results to return
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;Found </span><span class="si">{</span><span class="n">limit</span><span class="si">}</span><span class="s2"> results for &#39;</span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&#39;&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="customize-tool-properties">Customize tool properties</h4>
<h5 id="custom-tool-name">Custom tool name</h5>
<p>Tool name 默认等于函数名，可通过 <code>@tool(&quot;web_search&quot;)</code> 覆盖。</p>
<h5 id="custom-tool-description">Custom tool description</h5>
<p>默认 description 来自 docstring。需要更明确地指导 model 时，使用 <code>description=</code> 覆盖自动生成的 description。</p>
<h4 id="advanced-schema-definition">Advanced schema definition</h4>
<p>复杂输入使用 Pydantic model 或 JSON Schema。<code>Field(description=...)</code> 描述字段，<code>Literal</code> 限定可选值，<code>@tool(args_schema=...)</code> 绑定输入 Schema。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<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">typing</span> <span class="kn">import</span> <span class="n">Literal</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pydantic</span> <span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">WeatherInput</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">location</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;City name or coordinates&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">units</span><span class="p">:</span> <span class="n">Literal</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 class="o">=</span> <span class="n">Field</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">default</span><span class="o">=</span><span class="s2">&#34;celsius&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">description</span><span class="o">=</span><span class="s2">&#34;Temperature unit preference&#34;</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="n">include_forecast</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@tool</span><span class="p">(</span><span class="n">args_schema</span><span class="o">=</span><span class="n">WeatherInput</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">location</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">units</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;celsius&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">include_forecast</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get current weather and optional forecast.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="o">...</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="reserved-argument-names">Reserved argument names</h4>
<ul>
<li><code>config</code> 保留给 <code>RunnableConfig</code>；</li>
<li><code>runtime</code> 保留给 <code>ToolRuntime</code>。</li>
</ul>
<p>二者不能用作普通业务参数，否则会产生 runtime error。</p>
<h3 id="access-context">Access context</h3>
<p>Tool 通过 <code>ToolRuntime</code> 访问 conversation history、user data、persistent memory 和执行信息。</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Component</th>
					<th style="text-align: left">访问方式</th>
					<th style="text-align: left">含义与用途</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">State</td>
					<td style="text-align: left"><code>runtime.state</code></td>
					<td style="text-align: left">当前 conversation 的可变 short-term memory；messages、计数器、自定义字段</td>
			</tr>
			<tr>
					<td style="text-align: left">Context</td>
					<td style="text-align: left"><code>runtime.context</code></td>
					<td style="text-align: left">invocation 时传入的不可变配置；user ID、session info</td>
			</tr>
			<tr>
					<td style="text-align: left">Store</td>
					<td style="text-align: left"><code>runtime.store</code></td>
					<td style="text-align: left">跨 conversation 持久化的 long-term memory</td>
			</tr>
			<tr>
					<td style="text-align: left">Stream Writer</td>
					<td style="text-align: left"><code>runtime.stream_writer</code></td>
					<td style="text-align: left">Tool 执行时发送实时 custom updates</td>
			</tr>
			<tr>
					<td style="text-align: left">Execution Info</td>
					<td style="text-align: left"><code>runtime.execution_info</code></td>
					<td style="text-align: left">thread ID、run ID、attempt number</td>
			</tr>
			<tr>
					<td style="text-align: left">Server Info</td>
					<td style="text-align: left"><code>runtime.server_info</code></td>
					<td style="text-align: left">assistant ID、graph ID、authenticated user</td>
			</tr>
			<tr>
					<td style="text-align: left">Config</td>
					<td style="text-align: left"><code>runtime.config</code></td>
					<td style="text-align: left"><code>RunnableConfig</code> 的 callbacks、tags、metadata</td>
			</tr>
			<tr>
					<td style="text-align: left">Tool Call ID</td>
					<td style="text-align: left"><code>runtime.tool_call_id</code></td>
					<td style="text-align: left">当前 Tool invocation ID，用于匹配 <code>ToolMessage</code></td>
			</tr>
	</tbody>
</table>
<h4 id="short-term-memorystate">Short-term memory(State)</h4>
<p>State 包含 message history 和 graph state 中定义的自定义字段。</p>
<h5 id="access-state">Access state</h5>
<p>在 Tool 签名中声明 <code>runtime: ToolRuntime</code>。<code>ToolNode</code> 会自动注入它，但它不会出现在发送给 model 的 Tool Schema 中。Tool 通过 <code>runtime.state</code> 读取 State。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<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">langchain.messages</span> <span class="kn">import</span> <span class="n">HumanMessage</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.tools</span> <span class="kn">import</span> <span class="n">ToolRuntime</span><span class="p">,</span> <span class="n">tool</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_last_user_message</span><span class="p">(</span><span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get the most recent message from the user.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">runtime</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]):</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">HumanMessage</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">message</span><span class="o">.</span><span class="n">content</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;No user messages found&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user_preference</span><span class="p">(</span><span class="n">pref_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get a user preference value.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">runtime</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;user_preferences&#34;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pref_name</span><span class="p">,</span> <span class="s2">&#34;Not set&#34;</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>第二个 Tool 的 model-visible Schema 只有 <code>pref_name</code>，没有 <code>runtime</code>。</p>
<h5 id="update-state">Update state</h5>
<p>Tool 更新 State 时返回 <code>Command</code>。当目标是当前 graph 时：</p>
<ol>
<li>在 <code>Command.update</code> 写入 State 字段；</li>
<li>在 <code>Command.update[&quot;messages&quot;]</code> 中加入 <code>ToolMessage</code>；</li>
<li>结果写入 <code>ToolMessage.content</code>；</li>
<li><code>ToolMessage.tool_call_id</code> 必须等于 <code>runtime.tool_call_id</code>。</li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents</span> <span class="kn">import</span> <span class="n">AgentState</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.messages</span> <span class="kn">import</span> <span class="n">ToolMessage</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.tools</span> <span class="kn">import</span> <span class="n">ToolRuntime</span><span class="p">,</span> <span class="n">tool</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.types</span> <span class="kn">import</span> <span class="n">Command</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CustomState</span><span class="p">(</span><span class="n">AgentState</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">set_user_name</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">new_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="n">CustomState</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Command</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Set the user&#39;s name in the conversation state.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">Command</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">update</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;user_name&#34;</span><span class="p">:</span> <span class="n">new_name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="n">ToolMessage</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">content</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;User name set to </span><span class="si">{</span><span class="n">new_name</span><span class="si">}</span><span class="s2">.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">tool_call_id</span><span class="o">=</span><span class="n">runtime</span><span class="o">.</span><span class="n">tool_call_id</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="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></td></tr></table>
</div>
</div><p>每个 <code>AIMessage</code> tool call 都必须有对应的 <code>ToolMessage</code>。消息缺失或 ID 不匹配时，<code>ToolNode</code> 抛出 <code>ValueError</code>。多个 Tool 并行更新同一 State 字段时，应定义 reducer，明确覆盖、追加或其他合并规则。</p>
<h4 id="context">Context</h4>
<p>Context 是 invocation 时传入的不可变配置，包括 user ID、session details 和 application settings。使用 <code>context_schema</code> 声明结构，通过 <code>context=</code> 传入，Tool 从 <code>runtime.context</code> 读取。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span></code></pre></td>
<td class="lntd">
<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">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@dataclass</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">UserContext</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_account_info</span><span class="p">(</span><span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">[</span><span class="n">UserContext</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get the current user&#39;s account information.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">USER_DATABASE</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">runtime</span><span class="o">.</span><span class="n">context</span><span class="o">.</span><span class="n">user_id</span><span class="p">,</span> <span class="s2">&#34;User not found&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;openai:gpt-5.5&#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="p">[</span><span class="n">get_account_info</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">context_schema</span><span class="o">=</span><span class="n">UserContext</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></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 my balance?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">config</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;thread-1&#34;</span><span class="p">}},</span>
</span></span><span class="line"><span class="cl">    <span class="n">context</span><span class="o">=</span><span class="n">UserContext</span><span class="p">(</span><span class="n">user_id</span><span class="o">=</span><span class="s2">&#34;user123&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>thread_id</code> 标识 conversation；<code>user_id</code> 标识业务用户，二者不同。</p>
<h4 id="long-term-memorystore">Long-term memory(Store)</h4>
<p><code>BaseStore</code> 提供跨 conversation 持久化的数据。使用 <code>runtime.store</code> 访问，以 namespace/key 组织记录。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user_info</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Look up user info.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">item</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">store</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="s2">&#34;users&#34;</span><span class="p">,),</span> <span class="n">user_id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">value</span><span class="p">)</span> <span class="k">if</span> <span class="n">item</span> <span class="k">else</span> <span class="s2">&#34;Unknown user&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">save_user_info</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">age</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">email</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Save user info.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">runtime</span><span class="o">.</span><span class="n">store</span><span class="o">.</span><span class="n">put</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="s2">&#34;users&#34;</span><span class="p">,),</span> <span class="n">user_id</span><span class="p">,</span> <span class="p">{</span><span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="s2">&#34;age&#34;</span><span class="p">:</span> <span class="n">age</span><span class="p">,</span> <span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="n">email</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="k">return</span> <span class="s2">&#34;Successfully saved user info.&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>把同一 Store 传给 <code>create_agent(store=store)</code> 后，可在一个 session 保存、另一个 session 读取。</p>
<h4 id="streaming-writer">Streaming writer</h4>
<p><code>runtime.stream_writer</code> 可在 Tool 执行中发送实时 custom updates，适合长任务进度；Tool 最终仍用 <code>return</code> 返回完成结果。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get weather for a given city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">runtime</span><span class="o">.</span><span class="n">stream_writer</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Looking up data for city: </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">runtime</span><span class="o">.</span><span class="n">stream_writer</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Acquired data for city: </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;It&#39;s always sunny in </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2">!&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="execution-info">Execution info</h4>
<p><code>runtime.execution_info</code> 提供 <code>thread_id</code>、<code>run_id</code> 和 <code>node_attempt</code>，用于日志关联和重试判断。</p>
<h4 id="server-info">Server info</h4>
<p>在 LangGraph Server 上，<code>runtime.server_info</code> 提供 <code>assistant_id</code>、<code>graph_id</code> 和 authenticated user；非 Server 环境下为 <code>None</code>。</p>
<h3 id="tool-execution">Tool execution</h3>
<p>Tool 由 Agent 使用；Tool error handling 由 middleware 配置。</p>
<h4 id="tool-return-values">Tool return values</h4>
<h5 id="return-a-string">Return a string</h5>
<p>返回 human-readable <code>str</code>，供 model 下一步读取；框架自动将其转换为 <code>ToolMessage</code>。</p>
<h5 id="return-an-object">Return an object</h5>
<p>返回结构化 <code>object</code>，供 model 读取字段并推理。对象会序列化为 Tool output，但不会直接更新 graph State。</p>
<h5 id="return-multimodal-content">Return multimodal content</h5>
<p>多模态结果使用 standard content blocks，例如 text block 和 image block。结果转换成带 multimodal <code>content</code> 的 <code>ToolMessage</code>；可用 <code>message.content_blocks</code> 读取归一化 blocks。model 必须支持所返回的 image、audio 或 video modality。</p>
<h5 id="return-a-command">Return a Command</h5>
<p>需要更新 graph State 时返回 <code>Command</code>。若目标是当前 graph，必须显式提供与当前 tool call ID 匹配的 <code>ToolMessage</code>。普通 <code>str</code>/<code>object</code> 会自动包装为 <code>ToolMessage</code>，<code>Command</code> 不会。</p>
<h5 id="return-directly-from-a-tool">Return directly from a tool</h5>
<p><code>@tool(return_direct=True)</code> 使 agent loop 短路：Tool 正常执行，输出包装成 <code>ToolMessage</code> 后直接返回 caller，不再追加 model call。</p>
<p>适用于：Tool output 已是完整答案；希望避免额外 model call；需要 deterministic、unmodified output。</p>
<p>同一步包含多个并行 tool calls 时，会先执行整个批次；仅当每个 Tool 都设置 <code>return_direct=True</code> 时才路由到 <code>END</code>，最终响应包含全部 Tool outputs。</p>
<h5 id="return-a-command-with-return_direct">Return a Command with return_direct</h5>
<p><code>return_direct=True</code> 的 Tool 可返回 <code>Command</code>，在退出前更新 State。<code>Command</code> 仍不会自动生成 <code>ToolMessage</code>，必须手动加入 <code>tool_call_id=runtime.tool_call_id</code> 的消息。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@tool</span><span class="p">(</span><span class="n">return_direct</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch_and_store_order</span><span class="p">(</span><span class="n">order_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Command</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Fetch order status and store it in state.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">status</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;Order </span><span class="si">{</span><span class="n">order_id</span><span class="si">}</span><span class="s2"> is shipped.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">Command</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">update</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;last_order_status&#34;</span><span class="p">:</span> <span class="n">status</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="n">ToolMessage</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="n">status</span><span class="p">,</span> <span class="n">tool_call_id</span><span class="o">=</span><span class="n">runtime</span><span class="o">.</span><span class="n">tool_call_id</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="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="error-handing">Error handing</h4>
<p>使用 middleware 重试失败 Tool，或把异常转换为 model 可处理的自定义 <code>ToolMessage</code>。异常结果的 <code>tool_call_id</code> 必须取原调用的 <code>request.tool_call[&quot;id&quot;]</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents.middleware</span> <span class="kn">import</span> <span class="n">wrap_tool_call</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.messages</span> <span class="kn">import</span> <span class="n">ToolMessage</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@wrap_tool_call</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">handle_tool_errors</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">handler</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ToolMessage</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">error</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">ToolMessage</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">content</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;Tool error: Please check your input. (</span><span class="si">{</span><span class="n">error</span><span class="si">}</span><span class="s2">)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">tool_call_id</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">tool_call</span><span class="p">[</span><span class="s2">&#34;id&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="state-injection">State injection</h4>
<p>Tool 通过框架注入且对 model 隐藏的 <code>ToolRuntime</code> 访问 State：读取用 <code>runtime.state</code>，更新用带匹配 <code>ToolMessage</code> 的 <code>Command</code>。</p>
<h3 id="dynamic-tool-section">Dynamic tool section</h3>
<p>Tool 太多会占用 context，太少会限制能力。动态 Tool 根据启动时是否已知分为两类。</p>
<h5 id="filtering-pre-registered-tools">Filtering pre-registered tools</h5>
<p>全部 Tool 在创建 Agent 时已知：先预注册，再依据 State、permissions 或 Context 动态过滤暴露给 model 的集合。适合 Tool 静态、availability 动态的场景。</p>
<h5 id="runtime-tool-register">Runtime tool register</h5>
<p>Tool 在 runtime 才发现或创建时，需要同时处理：</p>
<ol>
<li><code>wrap_model_call</code>：用 <code>request.override(tools=[...])</code> 加入本次 model request；</li>
<li><code>wrap_tool_call</code>：识别对应 name，用 <code>request.override(tool=...)</code> 提供执行对象。</li>
</ol>
<p>只让 model 看见而不提供执行处理器，runtime 无法完成调用。此方式适合 MCP server、database、user configuration 和 external registry。</p>
<h3 id="headless-tools">Headless tools</h3>
<p>服务端只注册 name、description 和 parameter Schema，实现只在客户端。model 可正常调用，但执行通过 interrupt/resume 在进程外完成。</p>
<h4 id="when-to-use">when to use</h4>
<p>用于依赖客户端 environment、device 或 UI 的工作：Browser APIs、privacy/locality、latency、structured safe effects。</p>
<h4 id="how-it-work">How it work</h4>
<ol>
<li>定义 Tool Schema，不提供 in-process implementation；</li>
<li>将定义注册给 <code>create_agent</code>；</li>
<li>调用时 graph 暂停，返回 <code>{&quot;type&quot;:&quot;tool&quot;,&quot;tool_call&quot;:{&quot;id&quot;,&quot;name&quot;,&quot;args&quot;}}</code>；</li>
<li>客户端执行，再 resume graph。</li>
</ol>
<p><code>onTool</code> callback 可观察 <code>start</code>、<code>success</code>、<code>error</code>，用于 spinner 或 toast。</p>
<h3 id="prebuilt-tools">Prebuilt tools</h3>
<p>LangChain 提供 web search、code interpretation、database access 等 prebuilt tools/toolkits，可直接集成，无需自行实现。</p>
<h3 id="tools-from-mcp">Tools from MCP</h3>
<p>MCP 统一应用向 model 暴露 Tools 的方式。<code>MCPAdapter</code> 发现 MCP server 的 Tools，将 <code>list_tools()</code> 结果转换为 LangChain Tools，再传给 <code>create_agent</code>。</p>
<h3 id="server-side-tool-use">Server-side tool use</h3>
<p>部分 chat models 提供由 provider 执行的 built-in Tools，例如 web search 和 code interpreter，无需自行定义或托管 Tool logic；具体配置取决于 model integration。</p>
<h2 id="153837--short-term_memorymd">15:38:37 — Short-term_memory.md</h2>
<p>Conversation history 是最常见的 short-term memory；Message 包含 instructions 和 inputs。</p>
<h3 id="usage">Usage</h3>
<p>为 Agent 添加 short-term memory，需要在 <code>create_agent</code> 时指定 <code>checkpointer</code>。Short-term memory 是 Agent State 的一部分；checkpointer 按 thread 持久化 State，使 conversation 可恢复。</p>
<p>State 在 Agent invocation 或 tool call 等 step 完成时更新，在每个 step 开始时读取。相同 <code>thread_id</code> 恢复相同 conversation；不同 <code>thread_id</code> 使用独立 State。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents</span> <span class="kn">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.checkpoint.memory</span> <span class="kn">import</span> <span class="n">InMemorySaver</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;openai:gpt-5.5&#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="p">[</span><span class="n">get_user_info</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">InMemorySaver</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></span><span class="line"><span class="cl"><span class="n">config</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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;Hi! My name is Bob.&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">config</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="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 my name?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">config</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="in-production">In production</h4>
<p>生产环境使用 database-backed checkpointer；<code>InMemorySaver</code> 只适合本地示例和测试。</p>
<h3 id="customizing-agent-memory">Customizing agent memory</h3>
<p>Agent 使用 <code>AgentState</code> 管理 short-term memory，其中 <code>messages</code> key 保存 conversation history。需要额外字段时继承 <code>AgentState</code>，通过 <code>state_schema=</code> 传给 <code>create_agent</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents</span> <span class="kn">import</span> <span class="n">AgentState</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CustomAgentState</span><span class="p">(</span><span class="n">AgentState</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">preferences</span><span class="p">:</span> <span class="nb">dict</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;openai:gpt-5.5&#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="p">[</span><span class="n">get_user_info</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">state_schema</span><span class="o">=</span><span class="n">CustomAgentState</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">InMemorySaver</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></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</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="s2">&#34;messages&#34;</span><span class="p">:</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;Hello&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;user_id&#34;</span><span class="p">:</span> <span class="s2">&#34;user_123&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;preferences&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;theme&#34;</span><span class="p">:</span> <span class="s2">&#34;dark&#34;</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="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">}},</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>state_schema</code> 定义 State 结构；<code>checkpointer</code> 负责按 thread 保存它。</p>
<h3 id="common-patterns">Common patterns</h3>
<p>以下模式用于处理 conversation history 超过 LLM context window。</p>
<h4 id="trim-message截断消息">Trim message(截断消息)</h4>
<p>接近 token limit 时，根据 token count 截断，并指定 boundary strategy。也可在 <code>@before_model</code> 中清空旧 messages，再写回首条与最近 messages。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents.middleware</span> <span class="kn">import</span> <span class="n">before_model</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.messages</span> <span class="kn">import</span> <span class="n">RemoveMessage</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.graph.message</span> <span class="kn">import</span> <span class="n">REMOVE_ALL_MESSAGES</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@before_model</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">trim_messages</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">runtime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Keep only the first and most recent messages.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">messages</span> <span class="o">=</span> <span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">first_message</span> <span class="o">=</span> <span class="n">messages</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">recent_messages</span> <span class="o">=</span> <span class="n">messages</span><span class="p">[</span><span class="o">-</span><span class="mi">3</span><span class="p">:]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="n">messages</span><span class="p">[</span><span class="o">-</span><span class="mi">4</span><span class="p">:]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="n">RemoveMessage</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="n">REMOVE_ALL_MESSAGES</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">first_message</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="o">*</span><span class="n">recent_messages</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="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>None</code> 表示不更新 State。选择最近 3 或 4 条是为了尽量维持有效的 request/response 边界。</p>
<h4 id="delete-message">Delete message</h4>
<p>使用 <code>RemoveMessage</code> 删除指定 message 或清空全部 history。Messages State key 必须使用 <code>add_messages</code> reducer；默认 <code>AgentState</code> 已提供。</p>
<h6 id="to-remove-specific-messages">To remove specific messages:</h6>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<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">langchain.messages</span> <span class="kn">import</span> <span class="n">RemoveMessage</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">delete_messages</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">messages</span> <span class="o">=</span> <span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span><span class="n">RemoveMessage</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="n">message</span><span class="o">.</span><span class="n">id</span><span class="p">)</span> <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">messages</span><span class="p">[:</span><span class="mi">2</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h6 id="to-remove-all-messages">To remove all messages:</h6>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<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">langchain.messages</span> <span class="kn">import</span> <span class="n">RemoveMessage</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.graph.message</span> <span class="kn">import</span> <span class="n">REMOVE_ALL_MESSAGES</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">delete_messages</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span><span class="n">RemoveMessage</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="n">REMOVE_ALL_MESSAGES</span><span class="p">)]}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>删除后必须保持有效消息历史：部分 provider 要求以 <code>user</code> message 开始；多数 provider 要求带 tool call 的 <code>assistant</code> message 后紧跟对应的 <code>tool</code> result，不能只删除配对的一侧。</p>
<h4 id="summarize-messages">Summarize messages</h4>
<p>Trim 和 Delete 会丢失信息。需要保留旧语义时，使用内置 <code>SummarizationMiddleware</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents.middleware</span> <span class="kn">import</span> <span class="n">SummarizationMiddleware</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;openai:gpt-5.5&#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="p">[</span><span class="o">...</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">SummarizationMiddleware</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;openai:gpt-5.4-mini&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">trigger</span><span class="o">=</span><span class="p">(</span><span class="s2">&#34;tokens&#34;</span><span class="p">,</span> <span class="mi">4000</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">keep</span><span class="o">=</span><span class="p">(</span><span class="s2">&#34;messages&#34;</span><span class="p">,</span> <span class="mi">20</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="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">checkpointer</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>示例在 4000 tokens 时触发摘要，保留最近 20 条 messages。</p>
<h3 id="access-memory">Access memory</h3>
<h4 id="tools-1">tools</h4>
<h5 id="read-short-term-memory-in-a-tool">Read short-term memory in a tool</h5>
<p>Tool 使用对 model 隐藏的 <code>runtime: ToolRuntime</code>，通过 <code>runtime.state</code> 读取 short-term memory。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user_info</span><span class="p">(</span><span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Look up user info.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_id</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">&#34;user_id&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;User is John Smith&#34;</span> <span class="k">if</span> <span class="n">user_id</span> <span class="o">==</span> <span class="s2">&#34;user_123&#34;</span> <span class="k">else</span> <span class="s2">&#34;Unknown user&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h5 id="write-short-term-memory-form-tools">write short-term memory form tools</h5>
<p>Tool 写 short-term memory 时返回 <code>Command</code>，并在 <code>Command.update[&quot;messages&quot;]</code> 中加入 <code>tool_call_id=runtime.tool_call_id</code> 的 <code>ToolMessage</code>。</p>
<h4 id="prompt">Prompt</h4>
<p>使用 middleware 根据 conversation history 或 custom State fields 创建 dynamic prompt。<code>@dynamic_prompt</code> 可通过 <code>request.runtime.context</code> 读取 invocation Context。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<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">typing</span> <span class="kn">import</span> <span class="n">TypedDict</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.agents.middleware</span> <span class="kn">import</span> <span class="n">ModelRequest</span><span class="p">,</span> <span class="n">dynamic_prompt</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CustomContext</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@dynamic_prompt</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">dynamic_system_prompt</span><span class="p">(</span><span class="n">request</span><span class="p">:</span> <span class="n">ModelRequest</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_name</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">runtime</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s2">&#34;user_name&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;You are a helpful assistant. Address the user as </span><span class="si">{</span><span class="n">user_name</span><span class="si">}</span><span class="s2">.&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>创建 Agent 时传入 <code>context_schema=CustomContext</code>，调用时通过 <code>context=CustomContext(...)</code> 提供值。</p>
<h4 id="before-model">Before model</h4>
<p><code>@before_model</code> 在每次 model call 前处理 State，适合 trim、删除、注入或重排 messages。返回 <code>None</code> 表示无修改，返回 <code>dict</code> 表示要合并进 State 的更新。</p>
<p>After model</p>
<p><code>@after_model</code> 在 model call 后检查 State。可读取最后一条 response，用 <code>RemoveMessage(id=last_message.id)</code> 删除不符合要求的输出。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents.middleware</span> <span class="kn">import</span> <span class="n">after_model</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.messages</span> <span class="kn">import</span> <span class="n">RemoveMessage</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@after_model</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">validate_response</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">runtime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Remove messages containing sensitive words.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">stop_words</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;password&#34;</span><span class="p">,</span> <span class="s2">&#34;secret&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">last_message</span> <span class="o">=</span> <span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">word</span> <span class="ow">in</span> <span class="n">last_message</span><span class="o">.</span><span class="n">content</span> <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">stop_words</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span><span class="n">RemoveMessage</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="n">last_message</span><span class="o">.</span><span class="n">id</span><span class="p">)]}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">None</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>该 hook 修改最终 State；对于实时 Stream，只在 <code>after_model</code> 删除可能太晚，流式输出需在离开 run 前过滤。</p>
<h2 id="162701--event_streamingmd">16:27:01 — Event_Streaming.md</h2>
<p>LangChain Agents 构建在 LangGraph 上，因此支持相同的 streaming stack，并提供 messages、tool calls、State 和 custom updates 等 Agent-focused projections。</p>
<p>多数场景使用 <code>stream_events(..., version=&quot;v3&quot;)</code>。它返回带 typed projections 的 run object，各 projection 可独立消费，无需解析 stream-mode tuples。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream_events</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 is the weather in SF?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v3&#34;</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></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">delta</span> <span class="ow">in</span> <span class="n">message</span><span class="o">.</span><span class="n">text</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">delta</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">final_state</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">output</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="what-you-can-stream">What you can stream</h3>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Projection</th>
					<th style="text-align: left">内容</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><code>for event in stream</code></td>
					<td style="text-align: left">带完整 envelope、可访问全部 channel 的 raw protocol events</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.messages</code></td>
					<td style="text-align: left">每次 LLM call 的 model message streams</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>message.text</code></td>
					<td style="text-align: left">Text deltas 与 final text</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>message.reasoning</code></td>
					<td style="text-align: left">Model 支持时的 reasoning deltas</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>message.tool_calls</code></td>
					<td style="text-align: left">Tool-call argument chunks 与 finalized tool calls</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>message.output</code></td>
					<td style="text-align: left">本次 model call 的 final message object</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.values</code></td>
					<td style="text-align: left">Agent State snapshots</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.output</code></td>
					<td style="text-align: left">Final Agent State</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.subgraphs</code></td>
					<td style="text-align: left">Nested graph runs，包括 sub-agents 和普通 subgraphs</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.extensions</code></td>
					<td style="text-align: left">Custom transformer projections</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.tool_calls</code></td>
					<td style="text-align: left">Tool lifecycle、inputs、output deltas、final output、errors</td>
			</tr>
	</tbody>
</table>
<p><code>stream.messages</code> 产生 <code>ChatModelStream</code>。每个 message stream 暴露 <code>.text</code>、<code>.reasoning</code>、<code>.tool_calls</code>、<code>.output</code>。同步 projection 可实时迭代，也可排空后读取最终值：<code>str(message.text)</code> 得到最终文本，<code>message.tool_calls.get()</code> 得到完整 Tool calls。</p>
<h3 id="agent-messages">Agent messages</h3>
<p>需要每次 LLM call 的 model output 时使用 <code>stream.messages</code>。<code>message.output</code> 是 finalized AI message，包含 provider-specific content blocks；token usage 位于 <code>message.output.usage_metadata</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;[</span><span class="si">{</span><span class="n">message</span><span class="o">.</span><span class="n">node</span><span class="si">}</span><span class="s2">] &#34;</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">delta</span> <span class="ow">in</span> <span class="n">message</span><span class="o">.</span><span class="n">text</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">delta</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">message</span><span class="o">.</span><span class="n">output</span><span class="o">.</span><span class="n">usage_metadata</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">message</span><span class="o">.</span><span class="n">output</span><span class="o">.</span><span class="n">usage_metadata</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="reasoning-content">Reasoning content</h3>
<p><code>message.reasoning</code> 与 <code>.text</code> 用法相同，但只有 model 发出 reasoning blocks 时才有内容。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">delta</span> <span class="ow">in</span> <span class="n">message</span><span class="o">.</span><span class="n">reasoning</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;[thinking] </span><span class="si">{</span><span class="n">delta</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">delta</span> <span class="ow">in</span> <span class="n">message</span><span class="o">.</span><span class="n">text</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">delta</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="tool-calls">Tool calls</h3>
<p>Tool calls 有两种 projection：</p>
<ul>
<li><code>message.tool_calls</code>：model 生成 Tool call 时，流式输出参数 chunks 和 finalized call；</li>
<li><code>stream.tool_calls</code>：Tool 开始执行后，流式输出 lifecycle、input、output deltas、final output、error。</li>
</ul>
<p>前者观察 model 正在构造什么调用，后者观察 Tool 实际如何执行。</p>
<h3 id="streaming-sub-agent">Streaming sub-agent</h3>
<p>当一个 <code>create_agent</code> 调用另一个已命名的 <code>create_agent</code> 时，内部 Agent 事件位于嵌套 namespace。传给 <code>create_agent</code> 的 <code>name=</code> 用于标识内部 Agent。</p>
<p>命名 sub-agent 出现在 <code>stream.subagents</code> projection；每个 handle 暴露 <code>.messages</code>、<code>.values</code>、<code>.tool_calls</code>、<code>.output</code>，以及 <code>.name</code>、<code>.cause</code>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">subagent</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">subagents</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">subagent</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">: &#34;</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">subagent</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">message</span><span class="o">.</span><span class="n">text</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">token</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="state-and-final-output">state and final output</h3>
<p><code>stream.values</code> 获取运行过程中的 State snapshots；<code>stream.output</code> 获取最终 Agent State。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">snapshot</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">values</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">snapshot</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">final_state</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">output</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>message.output</code> 是单次 model call 的最终 AI message；<code>stream.output</code> 是整个 Agent run 的最终 State。</p>
<h3 id="multiple-projections">Multiple projections</h3>
<p>Async code 使用 <code>astream_events</code> 与 <code>asyncio.gather</code> 并发消费多个 projections。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</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="k">await</span> <span class="n">agent</span><span class="o">.</span><span class="n">astream_events</span><span class="p">(</span><span class="nb">input</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v3&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">consume_messages</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">async</span> <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="k">await</span> <span class="n">message</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">consume_tool_calls</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">async</span> <span class="k">for</span> <span class="n">call</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">tool_calls</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">call</span><span class="o">.</span><span class="n">tool_name</span><span class="p">,</span> <span class="n">call</span><span class="o">.</span><span class="n">input</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="n">consume_messages</span><span class="p">(),</span> <span class="n">consume_tool_calls</span><span class="p">())</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Synchronous code 使用 <code>stream.interleave(...)</code>，返回 <code>(name, item)</code> 区分 projection。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">interleave</span><span class="p">(</span><span class="s2">&#34;messages&#34;</span><span class="p">,</span> <span class="s2">&#34;tool_calls&#34;</span><span class="p">,</span> <span class="s2">&#34;values&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;messages&#34;</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">item</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;tool_calls&#34;</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">item</span><span class="o">.</span><span class="n">tool_name</span><span class="p">,</span> <span class="n">item</span><span class="o">.</span><span class="n">input</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;values&#34;</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">item</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="custom-updates">Custom updates</h3>
<p>内置 projection 不够时，使用 custom stream transformer，并从 <code>stream.extensions</code> 读取扩展 projection。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream_events</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nb">input</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">transformers</span><span class="o">=</span><span class="p">[</span><span class="n">ToolActivityTransformer</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></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">activity</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">extensions</span><span class="p">[</span><span class="s2">&#34;tool_activity&#34;</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">activity</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="register-transformers-on-middleware">Register transformers on middleware</h4>
<p>Middleware 可在 hooks 和 Tools 旁声明 transformer factories。将 <code>AgentMiddleware.transformers</code> 设置为 factories 序列；每个 factory 形如 <code>Callable[[tuple[str, ...]], StreamTransformer]</code>，框架调用 <code>factory(scope)</code>。</p>
<p>Root mux 的 <code>scope</code> 为 <code>()</code>，subgraph 为非空 tuple。每次返回新的 transformer，使各 subgraph 隔离。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents.middleware</span> <span class="kn">import</span> <span class="n">AgentMiddleware</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ToolActivityMiddleware</span><span class="p">(</span><span class="n">AgentMiddleware</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">transformers</span> <span class="o">=</span> <span class="p">(</span><span class="n">ToolActivityTransformer</span><span class="p">,)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>create_agent</code> 编译时合并 middleware factories 与自身 <code>transformers=</code>，顺序为：</p>
<ol>
<li>内置 <code>ToolCallTransformer</code>；</li>
<li>Middleware factories，按 middleware 顺序；</li>
<li>调用方传给 <code>create_agent(transformers=...)</code> 的 factories。</li>
</ol>
<p>这让内置 Tool call projection 位于消费者 transformer 之前，并让调用方条目拥有最终处理权。</p>
<p><code>PIIMiddleware(..., apply_to_output=True)</code> 会在 text deltas、tool call arguments、tool outputs、State snapshots 离开 run 前清除 PII。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;openai:gpt-5-nano&#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="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">PIIMiddleware</span><span class="p">(</span><span class="s2">&#34;email&#34;</span><span class="p">,</span> <span class="n">strategy</span><span class="o">=</span><span class="s2">&#34;redact&#34;</span><span class="p">,</span> <span class="n">apply_to_output</span><span class="o">=</span><span class="kc">True</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="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>若只依赖 <code>after_model</code> 做 State-level filtering，原始 PII 可能已通过 <code>stream_events(version=&quot;v3&quot;)</code> 实时发送给 reader。</p>
<h2 id="165227--streamingmd">16:52:27 — Streaming.md</h2>
<h3 id="overview">Overview</h3>
<p>Streaming 支持：</p>
<ul>
<li>Stream Agent progress；</li>
<li>Stream LLM tokens；</li>
<li>Streaming thinking/reasoning tokens；</li>
<li>Stream custom updates；</li>
<li>从 <code>updates</code>、<code>messages</code>、<code>custom</code> 中选择一个或多个 modes。</li>
</ul>
<h3 id="supported-stream-modes">Supported stream modes</h3>
<p>将一个 mode 或多个 modes 的 list 传给 <code>stream</code> / <code>astream</code>。</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Mode</th>
					<th style="text-align: left">Description</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><code>updates</code></td>
					<td style="text-align: left">每个 Agent step 后发送 State updates；同一步运行多个 nodes 时分别发送</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>messages</code></td>
					<td style="text-align: left">从所有调用 LLM 的 graph nodes 发送 <code>(token, metadata)</code> tuples</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>custom</code></td>
					<td style="text-align: left">发送 graph nodes 内通过 stream writer 写出的 custom data</td>
			</tr>
	</tbody>
</table>
<h3 id="agent-progress">Agent progress</h3>
<p>使用 <code>stream_mode=&quot;updates&quot;</code> 的 <code>stream</code> 或 <code>astream</code>，在每个 Agent step 后接收事件。一次 Tool call 的典型顺序是：</p>
<ol>
<li><strong>LLM node</strong>：输出带 Tool call requests 的 <code>AIMessage</code>；</li>
<li><strong>Tool node</strong>：输出带 execution result 的 <code>ToolMessage</code>；</li>
<li><strong>LLM node</strong>：输出 final AI response。</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Event Streaming</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/event-streaming/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/event-streaming/</guid>
      <description>Event Streaming相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>LangChain agents are built on LangGraph, so they support the same streaming stack with agent-focused projections for messages, tool calls, state, and custom updates.</p>
<p>For most situation,use Event Streaming through<code>stream_event(...,version=&quot;v3&quot;)</code>
Event Streaming returns a run object with typed projections, so each projection can be consumed independently instead of parsing stream-mode tuples</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">stream = agent.stream_events({
</span></span><span class="line"><span class="cl">    &#34;messages&#34;: [{&#34;role&#34;: &#34;user&#34;, &#34;content&#34;: &#34;What is the weather in SF?&#34;}],
</span></span><span class="line"><span class="cl">}, version=&#34;v3&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">for message in stream.messages:
</span></span><span class="line"><span class="cl">    for delta in message.text:
</span></span><span class="line"><span class="cl">        print(delta, end=&#34;&#34;, flush=True)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">final_state = stream.output
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="what-you-can-stream">What you can stream</h1>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Projection</th>
					<th style="text-align: left">Use</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><code>for event in stream</code></td>
					<td style="text-align: left">Raw protocol events with full envelope and access to every channel.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.messages</code></td>
					<td style="text-align: left">Model message streams, one per LLM call.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>message.text</code></td>
					<td style="text-align: left">Text deltas and final text for a message.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>message.reasoning</code></td>
					<td style="text-align: left">Reasoning deltas for models that expose reasoning content.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>message.tool_calls</code></td>
					<td style="text-align: left">Tool-call argument chunks and finalized tool calls.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>message.output</code></td>
					<td style="text-align: left">Final message object after the model call completes.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.values</code></td>
					<td style="text-align: left">Agent state snapshots.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.output</code></td>
					<td style="text-align: left">Final agent state.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.subgraphs</code></td>
					<td style="text-align: left">Nested graph runs (sub-agents and plain subgraphs).</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.extensions</code></td>
					<td style="text-align: left">Custom transformer projections.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>stream.tool_calls</code></td>
					<td style="text-align: left">Tool execution lifecycle, inputs, output deltas, final output, and errors.</td>
			</tr>
	</tbody>
</table>
<p><code>stream.messages</code> 会生成 <code>ChatModelStream</code> 对象。每个消息流都暴露了 <code>.text</code>、<code>.reasoning</code>、<code>.tool_calls</code> 和 <code>.output</code>。同步投影可迭代以获取实时增量，也可排空以获取最终值：使用 <code>str(message.text)</code> 获取最终文本，使用 <code>message.tool_calls.get()</code> 获取已完成的工具调用</p>
<h1 id="agent-messages">Agent messages</h1>
<p>Use <code>stream.message</code> when you want model output from each LLM call</p>
<p><code>message.output</code> gives you the finalized AI message,including previder-specific content blocks
read usage from <code>message.output.usage_metadata</code>.(If you want token counts)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">stream = agent.stream_events(input, version=&#34;v3&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">for message in stream.messages:
</span></span><span class="line"><span class="cl">    print(f&#34;[{message.node}] &#34;, end=&#34;&#34;)
</span></span><span class="line"><span class="cl">    for delta in message.text:
</span></span><span class="line"><span class="cl">        print(delta, end=&#34;&#34;, flush=True)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    full_message = message.output
</span></span><span class="line"><span class="cl">    usage = full_message.usage_metadata
</span></span><span class="line"><span class="cl">    if usage:
</span></span><span class="line"><span class="cl">        print(usage)
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="reasoning-content">Reasoning content</h1>
<p>the same shape as text ,but only available when the model emits reasoning blocks</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">stream = agent.stream_events(input, version=&#34;v3&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">for message in stream.messages:
</span></span><span class="line"><span class="cl">    for delta in message.reasoning:
</span></span><span class="line"><span class="cl">        print(f&#34;[thinking] {delta}&#34;, end=&#34;&#34;, flush=True)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    for delta in message.text:
</span></span><span class="line"><span class="cl">        print(delta, end=&#34;&#34;, flush=True)
</span></span></code></pre></td></tr></table>
</div>
</div><p>将上面的message.text更换为message.reasoning</p>
<h1 id="tool-calls">Tool calls</h1>
<p>有两种投影</p>
<ul>
<li>message.tool_calls在模型生成工具调用的时候,会流式传输工具调用参数块</li>
<li>stream.tool_calls会在工具调用开始后流式传输工具执行的生命周期</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">stream = agent.stream_events(input, version=&#34;v3&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">for message in stream.messages:
</span></span><span class="line"><span class="cl">    for delta in message.reasoning:
</span></span><span class="line"><span class="cl">        print(f&#34;[thinking] {delta}&#34;, end=&#34;&#34;, flush=True)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    for delta in message.text:
</span></span><span class="line"><span class="cl">        print(delta, end=&#34;&#34;, flush=True)
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="streaming-sub-agent">Streaming sub-agent</h1>
<p>当一个create_agent调用另一个已命名的create_agent时,内部智能体的时间会在一个内嵌的namespace中流动,你传递给create_agent的name= 会在stream中标识该内部智能体</p>
<p>命名的子智能体会在主智能体的stream.subagents投影上呈现,而每个句柄都暴露出该内部智能体的.message,.value,.tool_calls和.output加上你传递的name和.cause</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">upervisor</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="n">init_chat_model</span><span class="p">(</span><span class="s2">&#34;openai:gpt-5.5&#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="p">[</span><span class="n">call_weather</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span><span class="o">=</span><span class="s2">&#34;supervisor&#34;</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></span><span class="line"><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">supervisor</span><span class="o">.</span><span class="n">stream_events</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 in Boston?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v3&#34;</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></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">subagent</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">subagents</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">f</span><span class="s2">&#34;{subagent.name}: &#34;</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">subagent</span><span class="o">.</span><span class="n">messages</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">message</span><span class="o">.</span><span class="n">text</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">token</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="n">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="state-and-final-output">state and final output</h1>
<p>用<code>stream.value</code>来获取state的快照
用<code>stream.output</code>来获取最终的agent state</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">stream = agent.stream_events(input, version=&#34;v3&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">for snapshot in stream.values:
</span></span><span class="line"><span class="cl">    print(snapshot)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">final_state = stream.output
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="multiple-projections">Multiple projections</h1>
<p>对于 async code中的并发消费,请使用 <code>astream_events</code> with <code>asyncio.gather</code>
前者创建异步事件流,后者并发执行多个事件并且根据返回顺序聚合他们的结果</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">import</span> <span class="n">asyncio</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">await</span> <span class="n">agent</span><span class="o">.</span><span class="n">astream_events</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v3&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">async</span> <span class="k">def</span> <span class="nf">consume_messages</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">async</span> <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">messages</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">await</span> <span class="n">message</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">async</span> <span class="k">def</span> <span class="nf">consume_tool_calls</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">async</span> <span class="k">for</span> <span class="n">call</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">tool_calls</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">call</span><span class="o">.</span><span class="n">tool_name</span><span class="p">,</span> <span class="n">call</span><span class="o">.</span><span class="n">input</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="n">consume_messages</span><span class="p">(),</span> <span class="n">consume_tool_calls</span><span class="p">())</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>对于synchronous code,使用stream.interleave(&hellip;)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream_events</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v3&#34;</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">name</span><span class="p">,</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">interleave</span><span class="p">(</span><span class="s2">&#34;messages&#34;</span><span class="p">,</span> <span class="s2">&#34;tool_calls&#34;</span><span class="p">,</span> <span class="s2">&#34;values&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;messages&#34;</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">item</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;tool_calls&#34;</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">item</span><span class="o">.</span><span class="n">tool_name</span><span class="p">,</span> <span class="n">item</span><span class="o">.</span><span class="n">input</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;values&#34;</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">item</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="custom-updates">Custom updates</h1>
<p>使用custom stream transformer当你需要内置未提供的投影</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">stream</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream_events</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">input</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v3&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">transformers</span><span class="o">=</span><span class="p">[</span><span class="n">ToolActivityTransformer</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></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">activity</span> <span class="ow">in</span> <span class="n">stream</span><span class="o">.</span><span class="n">extensions</span><span class="p">[</span><span class="s2">&#34;tool_activity&#34;</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">activity</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="register-transformers-on-middleware">Register transformers on middleware</h2>
<p>中间件可以在其钩子和工具旁边声明流转换器工厂。工厂的形态在不同语言中有所不同：将 <code>AgentMiddleware</code> 子类上的 <code>transformers</code> 属性设置为一系列工厂。每个工厂的形态为 <code>Callable[[tuple[str, ...]], StreamTransformer]</code>，调用方式为 <code>factory(scope)</code>，其中 <code>scope</code> 是 mini-mux 作用域元组（根 mux 为 <code>()</code>，子图则为非空）。每次调用返回一个新的转换器可使每个子图保持隔离。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">AgentMiddleware</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">ToolActivityMiddleware</span><span class="p">(</span><span class="n">AgentMiddleware</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">transformers</span> <span class="o">=</span> <span class="p">(</span><span class="n">ToolActivityTransformer</span><span class="p">,)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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-nano&#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="p">[</span><span class="n">get_weather</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span><span class="n">ToolActivityMiddleware</span><span class="p">()],</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>在编译时，<code>create_agent</code> 会将中间件注册的工厂与传递给其自身的 <code>transformers=</code> 参数的内容进行合并。编译后图上的最终顺序为：</p>
<ol>
<li>内置的 <code>ToolCallTransformer</code>。</li>
<li>中间件注册的工厂，按中间件顺序排列。</li>
<li>由调用方通过 <code>create_agent</code> 提供的 <code>transformers=</code>。</li>
</ol>
<p>这使得内置的工具调用投影排在消费者转换器之前，并让调用方提供的条目拥有最终决定权。内置的 <code>PIIMiddleware</code> 使用此钩子从流式传输的线路输出中过滤 PII。通过设置 <code>apply_to_output=True</code>，其注册的转换器会在文本增量、工具调用参数、工具输出和状态快照离开运行之前，清除其中检测到的 PII，从而关闭了一个窗口——在该窗口中，<code>after_model</code> 状态级别的过滤原本会让原始 PII 透传给 <code>stream_events(version=&quot;v3&quot;)</code> 的实时读取者。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">PIIMiddleware</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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-nano&#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="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">PIIMiddleware</span><span class="p">(</span><span class="s2">&#34;email&#34;</span><span class="p">,</span> <span class="n">strategy</span><span class="o">=</span><span class="s2">&#34;redact&#34;</span><span class="p">,</span> <span class="n">apply_to_output</span><span class="o">=</span><span class="n">True</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="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>LangChain A Quick Start</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/langchain-a-quick-start/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/langchain-a-quick-start/</guid>
      <description>LangChain A Quick Start相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>一个简单的示例</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get weather for a given city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;It&#39;s always sunny in {city}!&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;claude-sonnet-4-6&#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="p">[</span><span class="n">get_weather</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">system_prompt</span><span class="o">=</span><span class="s2">&#34;You are a helpful assistant&#34;</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></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 in San Francisco?&#34;</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="nb">print</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">content_blocks</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="build-a-real-world-agent">Build a real-world agent:</h1>
<ol>
<li>Detailed System Prompt</li>
<li>Create Tools</li>
<li>Model Configuration</li>
<li>Conversational memory</li>
<li>Deep agents</li>
<li>Testing</li>
</ol>
<h3 id="1define-the-system-prompt">1.Define the system prompt</h3>
<p>defines your agent&rsquo;s role and behavior.
Keep it specific and actionable.</p>
<h3 id="2craete-tools">2.Craete tools</h3>
<p>Tools let a model interact with external systems by calling functions you define. Tools can depend on runtime context and also interact with agent memory.</p>
<p>Tools should be well-documented: their name,description,parameters will become part of the model&rsquo;s prompt. LangChain&rsquo;s tool decorator adds metadata and enables runtime injection with the <code>ToolRunTime</code> paramete.</p>
<h3 id="3configure-your-model">3.Configure your model</h3>
<p>Set up your language model with the right parameters foe your use case</p>
<h3 id="4add-memory">4.Add memory</h3>
<p>Add memory to your agent to maintain state across interactions. This allows the agent to remember previous conversations and context.</p>
<h3 id="5create-and-run-the-agent">5.Create and run the agent</h3>
<p>Tow different Frameworks for creating agents:
LangChain agents and deep agents
Use deep agents when you want maximum with minimal setup;
Choose LangChain agents when you need fine-grained contorl.</p>
<h3 id="6review-the-results">6.Review the results</h3>
<p>相较于LangChain, deep agent拥有更多定义好的功能:</p>
<ol>
<li>使用内置的 <a href="https://docs.langchain.org.cn/oss/python/deepagents/harness#task-planning"><code>write_todos</code></a> 工具<strong>规划其方法</strong>，以分解研究任务。</li>
<li>通过调用 <code>fetch_text_from_url</code> 工具<strong>加载文件</strong>以收集信息。</li>
<li>通过使用文件系统工具（<a href="https://docs.langchain.org.cn/oss/python/deepagents/harness#virtual-filesystem-access"><code>grep</code></a> 和 <a href="https://docs.langchain.org.cn/oss/python/deepagents/harness#virtual-filesystem-access"><code>read_file</code></a>）来<strong>管理上下文</strong>。</li>
<li><strong>生成子智能体</strong>：根据需要将复杂的子任务委派给专门的子智能体。</li>
</ol>
<p>For LangChain agents, you must implement more capabilities to get a similar lever of service and can customize them along the way as needed</p>
<p>In short,deep agent is well-organized and provides many integrated tools
and LangChain can fit custom needs better, but requires implementing more functionalities.</p>
<h2 id="trace-agent-calls">Trace agent calls</h2>
<p>Use LangSmith to trace LLM calls and inspect what is going on inside your agent.</p>
<p>Emmm, you should sign up for  a LangSmith account first.
Besides,you can also set up LangSmith Engine which monitors your traces,detects issues ,and preposes fixes.</p>
]]></content:encoded>
    </item>
    <item>
      <title>LangChain Philosophy</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/langchain-philosophy/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/langchain-philosophy/</guid>
      <description>LangChain Philosophy相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h3 id="langchain-is-driven-by-a-few-core-beliefs">LangChain is driven by a few core beliefs:</h3>
<ul>
<li>Large Language Models (LLMs) are great, powerful new technology.</li>
<li>LLMs are even better when you combine them with external sources of data.</li>
<li>LLMs will transform what the applications of the future look like. Specifically, the applications of the future will look more and more agentic.</li>
<li>It is still very early on in that transformation.</li>
<li>While it’s easy to build a prototype of those agentic applications, it’s still really hard to build agents that are reliable enough to put into production.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Message</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/message/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/message/</guid>
      <description>Message相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="message">Message</h1>
<p>Carrying both the content and metadata which represent the state</p>
<p>Messages contain:</p>
<ul>
<li>Role: identifies the message type(system,user)</li>
<li>Content: the actual content</li>
<li>Metadata: optional fields: such as information,message IDs,and token usage</li>
</ul>
<p>This is the standard message type</p>
<h2 id="basic-usage">Basic usage</h2>
<p>The easiest way to use message is to <strong>create message objects</strong> and pass them to a model when invoking</p>
<h2 id="text-prompts">Text prompts</h2>
<p>String
Ideal for generation tasks where you don&rsquo;t need to retain.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">response = model.invoke(&#34;Write a haiku about spring&#34;)
</span></span></code></pre></td></tr></table>
</div>
</div><p>When to use:</p>
<ul>
<li>a single ,standalone request</li>
<li>no need for conversation history</li>
<li>minimal code complexity</li>
</ul>
<h2 id="message-prompts">Message prompts</h2>
<p>Providing  a list of messages</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">from langchain.messages import SystemMessage, HumanMessage, AIMessage
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">messages = [
</span></span><span class="line"><span class="cl">    SystemMessage(&#34;You are a poetry expert&#34;),
</span></span><span class="line"><span class="cl">    HumanMessage(&#34;Write a haiku about spring&#34;),
</span></span><span class="line"><span class="cl">    AIMessage(&#34;Cherry blossoms bloom...&#34;)
</span></span><span class="line"><span class="cl">]
</span></span><span class="line"><span class="cl">response = model.invoke(messages)
</span></span></code></pre></td></tr></table>
</div>
</div><p>When:</p>
<ul>
<li>Managing multi-turn conversations</li>
<li>Working with multimodal content (images, audio, files)</li>
<li>Including system instructions</li>
</ul>
<h2 id="dictionary-format">Dictionary format</h2>
<p>Specify message in OpenAI chat completions format:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">messages = [
</span></span><span class="line"><span class="cl">    {&#34;role&#34;: &#34;system&#34;, &#34;content&#34;: &#34;You are a poetry expert&#34;},
</span></span><span class="line"><span class="cl">    {&#34;role&#34;: &#34;user&#34;, &#34;content&#34;: &#34;Write a haiku about spring&#34;},
</span></span><span class="line"><span class="cl">    {&#34;role&#34;: &#34;assistant&#34;, &#34;content&#34;: &#34;Cherry blossoms bloom...&#34;}
</span></span><span class="line"><span class="cl">]
</span></span><span class="line"><span class="cl">response = model.invoke(messages)
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="message-types">Message types</h2>
<ul>
<li>System messages</li>
<li>Human messages</li>
<li>Al messages:</li>
<li>Tool messages:</li>
</ul>
<h3 id="system-message">System message</h3>
<p>An initial set of instructions that primes the model&rsquo;s behavior</p>
<h3 id="human-message">Human message</h3>
<p>user input and interactions</p>
<h3 id="ai-message">AI message</h3>
<p>The LLM sometimes treat the message differently, so sometimes we can make up a AI message manually.</p>
<h4 id="tool-calls">Tool calls</h4>
<p>are included in AI messages</p>
<h4 id="token-usage">Token usage</h4>
<p>in AI message in usage_metadata field</p>
<h4 id="streaming-and-chunks">Streaming and chunks</h4>
<p>When streaming, u can receive <code>AIMessageChunk</code> objects and it can be combined into a full message by summing</p>
<h3 id="tool-message">Tool message</h3>
<p>tool result in <code>ToolMessage</code> object</p>
<h2 id="message-content">Message content</h2>
<p>An loosely-typed attribute,supporting strings and lists if untyped objects</p>
<p>Beside, LangChain provides dedicated content types for text, reasoning, citations, multi-modal data, server-side tool calls, and other message content</p>
<p>This may contain either:</p>
<ol>
<li>A string</li>
<li>A list of content blocks in a provider-native format</li>
<li>A list of <a href="https://docs.langchain.com/oss/python/langchain/messages#standard-content-blocks">LangChain’s standard content blocks</a></li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">from langchain.messages import HumanMessage
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># String content
</span></span><span class="line"><span class="cl">human_message = HumanMessage(&#34;Hello, how are you?&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Provider-native format (e.g., OpenAI)
</span></span><span class="line"><span class="cl">human_message = HumanMessage(content=[
</span></span><span class="line"><span class="cl">    {&#34;type&#34;: &#34;text&#34;, 
</span></span><span class="line"><span class="cl">    &#34;text&#34;: &#34;Hello, how are you?&#34;},
</span></span><span class="line"><span class="cl">    {&#34;type&#34;: &#34;image_url&#34;, 
</span></span><span class="line"><span class="cl">    &#34;image_url&#34;: {&#34;url&#34;: &#34;https://example.com/image.jpg&#34;}}
</span></span><span class="line"><span class="cl">])
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># List of standard content blocks
</span></span><span class="line"><span class="cl">human_message = HumanMessage(content_blocks=[
</span></span><span class="line"><span class="cl">    {&#34;type&#34;: &#34;text&#34;, &#34;text&#34;: &#34;Hello, how are you?&#34;},
</span></span><span class="line"><span class="cl">    {&#34;type&#34;: &#34;image&#34;, &#34;url&#34;: &#34;https://example.com/image.jpg&#34;},
</span></span><span class="line"><span class="cl">])
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="standard-content-blocks">Standard content blocks</h2>
<p>LangChain provides a standard representation for message content that works across providers.</p>
<p>消息对象实现了一个 <code>content_blocks</code> 属性，该属性会延迟将 <code>content</code> 属性解析为标准的、类型安全的表示形式。例如，从 <a href="https://docs.langchain.org.cn/oss/python/integrations/chat/anthropic"><code>ChatAnthropic</code></a> 或 <a href="https://docs.langchain.org.cn/oss/python/integrations/chat/openai"><code>ChatOpenAI</code></a> 生成的消息将包含各自提供商格式的 <code>thinking</code> 或 <code>reasoning</code> 块，但可以延迟解析为一致的 <a href="https://docs.langchain.org.cn/oss/python/langchain/messages#content-block-reference"><code>ReasoningContentBlock</code></a> 表示形式</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">from langchain.messages import AIMessage
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">message = AIMessage(
</span></span><span class="line"><span class="cl">    content=[
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;reasoning&#34;,
</span></span><span class="line"><span class="cl">            &#34;id&#34;: &#34;rs_abc123&#34;,
</span></span><span class="line"><span class="cl">            &#34;summary&#34;: [
</span></span><span class="line"><span class="cl">                {&#34;type&#34;: &#34;summary_text&#34;, &#34;text&#34;: &#34;summary 1&#34;},
</span></span><span class="line"><span class="cl">                {&#34;type&#34;: &#34;summary_text&#34;, &#34;text&#34;: &#34;summary 2&#34;},
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">        },
</span></span><span class="line"><span class="cl">        {&#34;type&#34;: &#34;text&#34;, &#34;text&#34;: &#34;...&#34;, &#34;id&#34;: &#34;msg_abc123&#34;},
</span></span><span class="line"><span class="cl">    ],
</span></span><span class="line"><span class="cl">    response_metadata={&#34;model_provider&#34;: &#34;openai&#34;}
</span></span><span class="line"><span class="cl">)
</span></span><span class="line"><span class="cl">message.content_blocks
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">[{&#39;type&#39;: &#39;reasoning&#39;, &#39;id&#39;: &#39;rs_abc123&#39;, &#39;reasoning&#39;: &#39;summary 1&#39;},
</span></span><span class="line"><span class="cl"> {&#39;type&#39;: &#39;reasoning&#39;, &#39;id&#39;: &#39;rs_abc123&#39;, &#39;reasoning&#39;: &#39;summary 2&#39;},
</span></span><span class="line"><span class="cl"> {&#39;type&#39;: &#39;text&#39;, &#39;text&#39;: &#39;...&#39;, &#39;id&#39;: &#39;msg_abc123&#39;}]
</span></span></code></pre></td></tr></table>
</div>
</div><p>将不同的provider的统一接口,是通过content_blocks属性来实现的</p>
<h2 id="multimodal">Multimodal</h2>
<p><strong>Multimodality</strong> refers to the ability to work with data that comes in different forms, such as text, audio, images, and video</p>
<p><a href="https://docs.langchain.com/oss/python/langchain/models">Chat models</a> can accept multimodal data as input and generate it as output. Below we show short examples of input messages featuring multimodal data.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># From URL
</span></span><span class="line"><span class="cl">message = {
</span></span><span class="line"><span class="cl">    &#34;role&#34;: &#34;user&#34;,
</span></span><span class="line"><span class="cl">    &#34;content&#34;: [
</span></span><span class="line"><span class="cl">        {&#34;type&#34;: &#34;text&#34;, &#34;text&#34;: &#34;Describe the content of this image.&#34;},
</span></span><span class="line"><span class="cl">        {&#34;type&#34;: &#34;image&#34;, &#34;url&#34;: &#34;https://example.com/path/to/image.jpg&#34;},
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># From base64 data
</span></span><span class="line"><span class="cl">message = {
</span></span><span class="line"><span class="cl">    &#34;role&#34;: &#34;user&#34;,
</span></span><span class="line"><span class="cl">    &#34;content&#34;: [
</span></span><span class="line"><span class="cl">        {&#34;type&#34;: &#34;text&#34;, &#34;text&#34;: &#34;Describe the content of this image.&#34;},
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;image&#34;,
</span></span><span class="line"><span class="cl">            &#34;base64&#34;: &#34;AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...&#34;,
</span></span><span class="line"><span class="cl">            &#34;mime_type&#34;: &#34;image/jpeg&#34;,
</span></span><span class="line"><span class="cl">        },
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># From provider-managed File ID
</span></span><span class="line"><span class="cl">message = {
</span></span><span class="line"><span class="cl">    &#34;role&#34;: &#34;user&#34;,
</span></span><span class="line"><span class="cl">    &#34;content&#34;: [
</span></span><span class="line"><span class="cl">        {&#34;type&#34;: &#34;text&#34;, &#34;text&#34;: &#34;Describe the content of this image.&#34;},
</span></span><span class="line"><span class="cl">        {&#34;type&#34;: &#34;image&#34;, &#34;file_id&#34;: &#34;file-abc123&#34;},
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></td></tr></table>
</div>
</div><p>Content blocks are represented (either when creating a message or accessing the <code>content_blocks</code> property) as <strong>a list of typed dictionaries</strong></p>
<h2 id="serialization">Serialization</h2>
<p>You can serialize messages to plain objects for storage and deserialize back to message instances. This is useful for persisting conversation history and resuming sessions.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">HumanMessage</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain_core</span><span class="o">.</span><span class="n">load</span> <span class="n">import</span> <span class="n">dumpd</span><span class="p">,</span> <span class="nb">load</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">message</span> <span class="o">=</span> <span class="n">HumanMessage</span><span class="p">(</span><span class="s2">&#34;What is the capital of France?&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Serialize to a plain dict</span>
</span></span><span class="line"><span class="cl"><span class="n">serialized</span> <span class="o">=</span> <span class="n">dumpd</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Deserialize back to a message object</span>
</span></span><span class="line"><span class="cl"><span class="n">restored</span> <span class="o">=</span> <span class="nb">load</span><span class="p">(</span><span class="n">serialized</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>Models</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/models/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/models/</guid>
      <description>Models相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>In addition to text generation,many LLMs provide :tool calling,Structured output,Multimodality,Reasoning
different model excel at different tasks</p>
<p>LangChain has  Standard model interface,which allow you to experiment with and switch models</p>
<h1 id="basic-usage">Basic usage</h1>
<p>1.with agents 2.Standalone(outside the agent loop)</p>
<h2 id="initialize-a-model">Initialize a model</h2>
<p>the easiest way: use <code>init_chat_model</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">import os
</span></span><span class="line"><span class="cl">from langchain.chat_models import init_chat_model
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">os.environ[&#34;OPENAI_API_KEY&#34;] = &#34;sk-...&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">model = init_chat_model(&#34;gpt-5.5&#34;)
</span></span></code></pre></td></tr></table>
</div>
</div><p>key method:
invoke,streaming.patch(批量处理)</p>
<h2 id="parameters">Parameters</h2>
<p>model: string (required)
api_key: string
temperature: number
max_tokens: number
timeout: number
max_retries: number (default: 6)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">model = init_chat_model(
</span></span><span class="line"><span class="cl">    &#34;claude-sonnet-4-6&#34;,
</span></span><span class="line"><span class="cl">    # Kwargs passed to the model:
</span></span><span class="line"><span class="cl">    temperature=0.7,
</span></span><span class="line"><span class="cl">    timeout=30,
</span></span><span class="line"><span class="cl">    max_tokens=1000,
</span></span><span class="line"><span class="cl">    max_retries=6,  # Default; increase for unreliable networks
</span></span><span class="line"><span class="cl">)
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="connection-resilience连接韧性">Connection resilience(连接韧性?)</h2>
<p>LangChain chat models automatically retry failed API requests with exponential backoff</p>
<p>By default, models retry up to <strong>6 times</strong> for network errors, rate limits (429), and server errors (5xx). Client errors like 401 (unauthorized) or 404 are not retried.</p>
<p>Use <strong>max_retries</strong> and <strong>timeout</strong></p>
<h3 id="invocation">Invocation</h3>
<h3 id="invoke">invoke:</h3>
<p>with a message along with a thread_id
role of a message: models use it to verify who sent the message</p>
<h3 id="streaming">Streaming:</h3>
<p>Calling <a href="https://reference.langchain.com/python/langchain-core/language_models/chat_models/BaseChatModel/stream"><code>stream()</code></a> returns an iterator that yields output chunks as they are produced. You can use a loop to process each chunk in real-time:</p>
<p>Return <code>AIMessageChunk</code>objects ,each chunk in a stream is designed to be gathered into a full message via summation</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">full = None  # None | AIMessageChunk
</span></span><span class="line"><span class="cl">for chunk in model.stream(&#34;What color is the sky?&#34;):
</span></span><span class="line"><span class="cl">    full = chunk if full is None else full + chunk
</span></span><span class="line"><span class="cl">    print(full.text)
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="batch">Batch</h3>
<p>Batching a collection of independent requests to a model can significantly improve performance and reduce costs, as the processing can be done in parallel:</p>
<p>Use <code>batch_as_completed()</code> to stream result,but the response is out of order</p>
<h2 id="tool-calling">Tool calling</h2>
<ol>
<li>A schema, including the name of the tool, a description, and/or argument definitions (often a JSON schema)</li>
<li>A function or coroutine to execute.</li>
</ol>
<p>Basic tool calling flow:</p>
<p><img alt="image-20260919161339819" loading="lazy" src="c:\\Users\\14152\\AppData\\Roaming\\Typora\\typora-user-images\\image-20260919161339819.png"></p>
<p>Use <code>bind_tools</code> to make tools you have defined available</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">location</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get the weather at a location.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;It&#39;s sunny in {location}.&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">model_with_tools</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">bind_tools</span><span class="p">([</span><span class="n">get_weather</span><span class="p">])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="common-way-to-use-tool-calling">Common way to use tool calling</h4>
<ul>
<li>Tool execution loop</li>
<li>Forcing tool calls</li>
<li>Parallel tool calls</li>
<li>Streaming tool calls:
tool calls are progressively built through <a href="https://reference.langchain.com/python/langchain-core/messages/tool/ToolCallChunk"><code>ToolCallChunk</code></a>
You can accumulate chunks to build complete tool calls</li>
</ul>
<h2 id="structured-output">Structured output</h2>
<p>Provide their response in a format matching a given schema
LangChain supports multiple schema types and methods for enforcing structured output.</p>
<p><a href="https://docs.pydantic.dev/latest/concepts/models/#basic-model-usage">Pydantic models</a> provide the richest feature set with field validation, descriptions, and nested structures.</p>
<p>Python’s <code>TypedDict</code> provides a simpler alternative to Pydantic models, ideal when you don’t need runtime validation.</p>
<p>Provide a <a href="https://json-schema.org/understanding-json-schema/about">JSON Schema</a> for maximum control and interoperability.</p>
<p>1.raw message和parsed message并存 2.nested structure</p>
<h2 id="multimodal">Multimodal</h2>
<p>You can use content block to provide ono-text data to the model
If the response contains multimodal data,the resulting AIMessage</p>
<p>will have content blocks with multimodal types</p>
<h2 id="reasoning">Reasoning</h2>
<p>Many models are capable of performing multi-step reasoning to arrive at a conclusion. This involves breaking down complex problems into smaller, more</p>
<p>manageable steps.<strong>If supported by the underlying model,</strong> you can surface this reasoning process to better understand how the model arrived at its final answer.</p>
<p>Depending on the model,you can sometimes specify the level of effort it should put into reasoning. Using reasoning_effort parameter when invoking.</p>
<h2 id="local-models">Local models</h2>
<h2 id="prompt-caching">Prompt caching</h2>
<p>ou can engage caching at three levels:</p>
<ul>
<li>
<p>Implicit provider caching:</p>
</li>
<li>
<p>Provider-level explicit controls(显式):
providers let you manually indicate cache points for greater control or to guarantee cost savings. These mirror the underlying provider/API behavior. Examples:</p>
<ul>
<li><a href="https://reference.langchain.com/python/langchain-openai/chat_models/base/ChatOpenAI"><code>ChatOpenAI</code></a> (via <code>prompt_cache_key</code>)</li>
<li>Anthropic content-block <a href="https://docs.langchain.com/oss/python/integrations/chat/anthropic#prompt-caching"><code>cache_control</code></a></li>
<li><a href="https://reference.langchain.com/python/integrations/langchain_google_genai/">Gemini</a>.</li>
<li>AWS Bedrock <a href="https://docs.langchain.com/oss/python/integrations/chat/bedrock#prompt-caching"><code>cachePoint</code></a> blocks</li>
</ul>
</li>
<li>
<p>LangChain middleware:</p>
<p>for agents, middleware lets LangChain optimize caching of stable system prompt and tool content. Examples:</p>
<ul>
<li>Anthropic’s <a href="https://docs.langchain.com/oss/python/integrations/middleware/anthropic#prompt-caching"><code>AnthropicPromptCachingMiddleware</code></a></li>
<li>AWS Bedrock’s <a href="https://docs.langchain.com/oss/python/integrations/middleware/aws#prompt-caching"><code>BedrockPromptCachingMiddleware</code></a></li>
</ul>
</li>
</ul>
<p>Cache usage will be reflected in the <a href="https://docs.langchain.com/oss/python/langchain/messages#token-usage">usage metadata</a> of the model response.</p>
<h2 id="server-side-tool-use">Server-side tool use</h2>
<p>Some providers support server-side <a href="https://docs.langchain.com/oss/python/langchain/models#tool-calling">tool-calling</a> loops: models can interact with web search, code interpreters, and other tools and analyze the results in a single conversational turn.</p>
<p>If a model invokes a tool server-side, the content of the response message will include content representing the invocation and result of the tool. Accessing the <a href="https://docs.langchain.com/oss/python/langchain/messages#standard-content-blocks">content blocks</a> of the response will return the server-side tool calls and results in a provider-agnostic format:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">chat_models</span> <span class="n">import</span> <span class="n">init_chat_model</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">init_chat_model</span><span class="p">(</span><span class="s2">&#34;gpt-5.4-mini&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">tool</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;web_search&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">model_with_tools</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">bind_tools</span><span class="p">([</span><span class="k">tool</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">model_with_tools</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span><span class="s2">&#34;What was a positive news story from today?&#34;</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">response</span><span class="o">.</span><span class="n">content_blocks</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;server_tool_call&#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;web_search&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;args&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;query&#34;</span><span class="p">:</span> <span class="s2">&#34;positive news stories today&#34;</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;search&#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;id&#34;</span><span class="p">:</span> <span class="s2">&#34;ws_abc123&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;server_tool_result&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;tool_call_id&#34;</span><span class="p">:</span> <span class="s2">&#34;ws_abc123&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;status&#34;</span><span class="p">:</span> <span class="s2">&#34;success&#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;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Here are some positive news stories from today...&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;annotations&#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="s2">&#34;end_index&#34;</span><span class="p">:</span> <span class="mi">410</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;start_index&#34;</span><span class="p">:</span> <span class="mi">337</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;article title&#34;</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;citation&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;...&#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="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This represents a single conversational turn; there are no associated <a href="https://docs.langchain.com/oss/python/langchain/messages#tool-message">ToolMessage</a> objects that need to be passed in as in client-side <a href="https://docs.langchain.com/oss/python/langchain/models#tool-calling">tool-calling</a>.</p>
<h2 id="model-exceptions">Model exceptions</h2>
<p>Major integration packages raise standard exception types from <code>langchain_core.exceptions</code> for common model failures such as authentication errors, rate limits, and timeouts. These exceptions inherit from both the LangChain base type and the provider SDK’s own exception type, so you can catch either one:</p>
<h2 id="rate-limiting">Rate limiting</h2>
<p>To control your call frequency ,and i you hit it, you will receive a rate limit error</p>
<p>To help manage rate limits, chat model integrations accept a <code>rate_limiter</code> parameter that can be provided during initialization to control the rate at which requests are made.</p>
<h2 id="base-url-and-proxy-settings">Base URL and proxy settings</h2>
<p>You can configure a custom base URL for providers that implement the OpenAI Chat Completions API.</p>
<p><strong>Custom base URL:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">model = init_chat_model(
</span></span><span class="line"><span class="cl">    model=&#34;MODEL_NAME&#34;,
</span></span><span class="line"><span class="cl">    model_provider=&#34;openai&#34;,
</span></span><span class="line"><span class="cl">    base_url=&#34;BASE_URL&#34;,
</span></span><span class="line"><span class="cl">    api_key=&#34;YOUR_API_KEY&#34;,
</span></span><span class="line"><span class="cl">)
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>HTTP proxy configuration:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">from langchain_openai import ChatOpenAI
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">model = ChatOpenAI(
</span></span><span class="line"><span class="cl">    model=&#34;gpt-5.5&#34;,
</span></span><span class="line"><span class="cl">    openai_proxy=&#34;http://proxy.example.com:8080&#34;
</span></span><span class="line"><span class="cl">)
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="log-probabilities">Log probabilities</h2>
<h2 id="token-usage">Token usage</h2>
<p>A number of model providers return token usage information as part of the invocation response.</p>
<p>You can track aggregate token counts across models in an application using either a callback or context manager, as shown below:</p>
<p><strong>Callback:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">You can track aggregate token counts across models in an application using either a callback or context manager, as shown below:
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>Context manager:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">from langchain.chat_models import init_chat_model
</span></span><span class="line"><span class="cl">from langchain_core.callbacks import get_usage_metadata_callback
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">model_1 = init_chat_model(model=&#34;gpt-5.4-mini&#34;)
</span></span><span class="line"><span class="cl">model_2 = init_chat_model(model=&#34;claude-haiku-4-5-20251001&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">with get_usage_metadata_callback() as cb:
</span></span><span class="line"><span class="cl">    model_1.invoke(&#34;Hello&#34;)
</span></span><span class="line"><span class="cl">    model_2.invoke(&#34;Hello&#34;)
</span></span><span class="line"><span class="cl">    print(cb.usage_metadata)
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="invocation-config">Invocation config</h2>
<p>When invoking a model, you can pass additional configuration through the <code>config</code> parameter using a <a href="https://reference.langchain.com/python/langchain-core/runnables/config/RunnableConfig"><code>RunnableConfig</code></a> dictionary. This provides run-time control over execution behavior, callbacks, and metadata tracking.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">response = model.invoke(
</span></span><span class="line"><span class="cl">    &#34;Tell me a joke&#34;,
</span></span><span class="line"><span class="cl">    config={
</span></span><span class="line"><span class="cl">        &#34;run_name&#34;: &#34;joke_generation&#34;,      # Custom name for this run
</span></span><span class="line"><span class="cl">        &#34;tags&#34;: [&#34;humor&#34;, &#34;demo&#34;],          # Tags for categorization
</span></span><span class="line"><span class="cl">        &#34;metadata&#34;: {&#34;user_id&#34;: &#34;123&#34;},     # Custom metadata
</span></span><span class="line"><span class="cl">        &#34;callbacks&#34;: [my_callback_handler], # Callback handlers
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">)
</span></span></code></pre></td></tr></table>
</div>
</div><p>Key configuration attributes
run_name: string : identifier
tags: string[]
metadata: object
max_concurrency: number
callbacks: array
recursion_limit: number</p>
<p>Configurable models:
You can also create a runtime-configurable model by specifying <a href="https://reference.langchain.com/python/langchain_core/language_models/#langchain_core.language_models.chat_models.BaseChatModel.configurable_fields"><code>configurable_fields</code></a>. If you don’t specify a model value, then <code>'model'</code> and <code>'model_provider'</code> will be configurable by default.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">from langchain.chat_models import init_chat_model
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">configurable_model = init_chat_model(temperature=0)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">configurable_model.invoke(
</span></span><span class="line"><span class="cl">    &#34;what&#39;s your name&#34;,
</span></span><span class="line"><span class="cl">    config={&#34;configurable&#34;: {&#34;model&#34;: &#34;gpt-5-nano&#34;}},  # Run with GPT-5-Nano
</span></span><span class="line"><span class="cl">)
</span></span><span class="line"><span class="cl">configurable_model.invoke(
</span></span><span class="line"><span class="cl">    &#34;what&#39;s your name&#34;,
</span></span><span class="line"><span class="cl">    config={&#34;configurable&#34;: {&#34;model&#34;: &#34;claude-sonnet-4-6&#34;}},  # Run with Claude
</span></span><span class="line"><span class="cl">)
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="dynamic-model-selection">Dynamic model selection</h2>
<p>Dynamic models are selected at runtime based on the current state and context. This enables sophisticated routing logic and cost optimization.</p>
<p>To use a dynamic model, create middleware using the <a href="https://reference.langchain.com/python/langchain/agents/middleware/types/wrap_model_call"><code>@wrap_model_call</code></a> decorator that modifies the model in the request:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain_openai</span> <span class="n">import</span> <span class="n">ChatOpenAI</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">wrap_model_call</span><span class="p">,</span> <span class="n">ModelRequest</span><span class="p">,</span> <span class="n">ModelResponse</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">basic_model</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="s2">&#34;gpt-5.4-mini&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">advanced_model</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">(</span><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></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">wrap_model_call</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">dynamic_model_selection</span><span class="p">(</span><span class="n">request</span><span class="p">:</span> <span class="n">ModelRequest</span><span class="p">,</span> <span class="n">handler</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ModelResponse</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Choose model based on conversation complexity.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">message_count</span> <span class="o">=</span> <span class="n">len</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">])</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">message_count</span> <span class="o">&gt;</span> <span class="mi">10</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Use an advanced model for longer conversations</span>
</span></span><span class="line"><span class="cl">        <span class="n">model</span> <span class="o">=</span> <span class="n">advanced_model</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">model</span> <span class="o">=</span> <span class="n">basic_model</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">override</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="n">basic_model</span><span class="p">,</span>  <span class="c1"># Default model</span>
</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="n">middleware</span><span class="o">=</span><span class="p">[</span><span class="n">dynamic_model_selection</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Pre-bound models (models with <a href="https://reference.langchain.com/python/langchain-core/language_models/chat_models/BaseChatModel/bind_tools"><code>bind_tools</code></a> already called) are not supported when using structured output. If you need dynamic model selection with structured output, ensure the models passed to the middleware are not pre-bound.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Short-term Memory</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/short-term-memory/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/short-term-memory/</guid>
      <description>Short-term Memory相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>Conversation history is the most common form of short-term memory</p>
<p>Fact1: message includes instructions and inpus</p>
<h1 id="usage">Usage</h1>
<p>To add short-term memory to an agent ,you need to specify a <code>checkpointer</code> when creating an agent
note: short-term memory is part of your agent&rsquo;s state. State is persisted in a database using a checkpointer so thread can resume it an any time.
Short-term memory updates when the agent is invoked or a step (like a tool call) is completed, and the state is read at the start of each step.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">checkpoint</span><span class="o">.</span><span class="n">memory</span> <span class="n">import</span> <span class="n">InMemorySaver</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user_info</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Look up information about the current user.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;No user profile on file.&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;openai:gpt-5.5&#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="p">[</span><span class="n">get_user_info</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">InMemorySaver</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></span><span class="line"><span class="cl"><span class="n">thread_config</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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;Hi! My name is Bob.&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">thread_config</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">content</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>  <span class="c1"># &#34;Hi Bob! Nice to see you here. How are you doing?&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 my name?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">thread_config</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">content</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>  <span class="c1"># &#34;You are Bob!&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="in-production">In production</h2>
<p>use a checkpointer backed by a database</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">checkpoint</span><span class="o">.</span><span class="n">memory</span> <span class="n">import</span> <span class="n">InMemorySaver</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user_info</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Look up information about the current user.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;No user profile on file.&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;openai:gpt-5.5&#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="p">[</span><span class="n">get_user_info</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">InMemorySaver</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></span><span class="line"><span class="cl"><span class="n">thread_config</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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;Hi! My name is Bob.&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">thread_config</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">content</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>  <span class="c1"># &#34;Hi Bob! Nice to see you here. How are you doing?&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 my name?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">thread_config</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">content</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>  <span class="c1"># &#34;You are Bob!&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="customizing-agent-memory">Customizing agent memory</h1>
<p>Agents use <code>AgentState</code> to manage short-term memory, specifically the
conversation history via a <code>message</code> key</p>
<p>You can extend <code>AgentState</code> to ad additional fields
Custom state schema are passed to <code>create_agent</code> using the <code>state_scheam</code> parameter</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span><span class="p">,</span> <span class="n">AgentState</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">checkpoint</span><span class="o">.</span><span class="n">memory</span> <span class="n">import</span> <span class="n">InMemorySaver</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">CustomAgentState</span><span class="p">(</span><span class="n">AgentState</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">    <span class="n">preferences</span><span class="p">:</span> <span class="n">dict</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;gpt-5.5&#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="p">[</span><span class="n">get_user_info</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">state_schema</span><span class="o">=</span><span class="n">CustomAgentState</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">InMemorySaver</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></span><span class="line"><span class="cl"><span class="c1"># Custom state can be passed in invoke</span>
</span></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</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="s2">&#34;messages&#34;</span><span class="p">:</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;Hello&#34;</span><span class="p">}],</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;user_id&#34;</span><span class="p">:</span> <span class="s2">&#34;user_123&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;preferences&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;theme&#34;</span><span class="p">:</span> <span class="s2">&#34;dark&#34;</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="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">}})</span>
</span></span><span class="line"><span class="cl">    
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="common-patterns">Common patterns</h1>
<p>Common solutions to exceed the LLM&rsquo;s context window</p>
<h2 id="trim-message截断消息">Trim message(截断消息)</h2>
<p>A way: keep track of the token count and truncate when it approaches that limit</p>
<p>Using trim messages utility and specify the number if tokens to keep ang the <code>strategy</code> to use for handing the boundary</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">before_mfrom</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">RemoveMessage</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">graph</span><span class="o">.</span><span class="n">message</span> <span class="n">import</span> <span class="n">REMOVE_ALL_MESSAGES</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">checkpoint</span><span class="o">.</span><span class="n">memory</span> <span class="n">import</span> <span class="n">InMemorySaver</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span><span class="p">,</span> <span class="n">AgentState</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">before_model</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">runtime</span> <span class="n">import</span> <span class="n">Runtime</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain_core</span><span class="o">.</span><span class="n">runnables</span> <span class="n">import</span> <span class="n">RunnableConfig</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">typing</span> <span class="n">import</span> <span class="n">Any</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">before_model</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">trim_messages</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">AgentState</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">Runtime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Keep only the last few messages to fit context window.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">messages</span> <span class="o">=</span> <span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]</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">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">None</span>  <span class="c1"># No changes needed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">first_msg</span> <span class="o">=</span> <span class="n">messages</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">recent_messages</span> <span class="o">=</span> <span class="n">messages</span><span class="p">[</span><span class="o">-</span><span class="mi">3</span><span class="p">:]</span> <span class="k">if</span> <span class="n">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="n">messages</span><span class="p">[</span><span class="o">-</span><span class="mi">4</span><span class="p">:]</span>
</span></span><span class="line"><span class="cl">    <span class="n">new_messages</span> <span class="o">=</span> <span class="p">[</span><span class="n">first_msg</span><span class="p">]</span> <span class="o">+</span> <span class="n">recent_messages</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="n">RemoveMessage</span><span class="p">(</span><span class="n">id</span><span class="o">=</span><span class="n">REMOVE_ALL_MESSAGES</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="o">*</span><span class="n">new_messages</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">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;gpt-5.5&#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="p">[</span><span class="o">...</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span><span class="n">trim_messages</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">InMemorySaver</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></span><span class="line"><span class="cl"><span class="n">config</span><span class="p">:</span> <span class="n">RunnableConfig</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="s2">&#34;hi, my name is bob&#34;</span><span class="p">},</span> <span class="n">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="s2">&#34;write a short poem about cats&#34;</span><span class="p">},</span> <span class="n">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="s2">&#34;now do the same but for dogs&#34;</span><span class="p">},</span> <span class="n">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">final_response</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="s2">&#34;what&#39;s my name?&#34;</span><span class="p">},</span> <span class="n">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">final_response</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">pretty_print</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">================================== Ai Message ==================================
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">Your name is Bob. You told me that earlier.
</span></span></span><span class="line"><span class="cl"><span class="s2">If you&#39;d like me to call you a nickname or use a different name, just say the word.
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="delete-message">Delete message</h2>
<p>Useful when you want to remove specific message or clear the entire message history
Use <code>RemoveMessage</code> to delete message from the graph state
and you need to use a state key with <code>add_messages</code> reducer and  default the<code>AgentState</code> provides it</p>
<h4 id="to-remove-specific-messages">To remove specific messages:</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">from langchain.messages import RemoveMessage  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">def delete_messages(state):
</span></span><span class="line"><span class="cl">    messages = state[&#34;messages&#34;]
</span></span><span class="line"><span class="cl">    if len(messages) &gt; 2:
</span></span><span class="line"><span class="cl">        # remove the earliest two messages
</span></span><span class="line"><span class="cl">        return {&#34;messages&#34;: [RemoveMessage(id=m.id) for m in messages[:2]]}
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="to-remove-all-messages">To remove all messages:</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">from langgraph.graph.message import REMOVE_ALL_MESSAGES  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">def delete_messages(state):
</span></span><span class="line"><span class="cl">    return {&#34;messages&#34;: [RemoveMessage(id=REMOVE_ALL_MESSAGES)]}
</span></span></code></pre></td></tr></table>
</div>
</div><p>ps:
删除消息时，<strong>请确保</strong>生成的消息历史有效。检查你正在使用的 LLM 提供商的限制。例如：</p>
<ul>
<li>某些提供程序期望消息历史记录以 <code>user</code> 消息开头</li>
<li>大多数提供程序要求带有工具调用的 <code>assistant</code> 消息后跟相应的 <code>tool</code> 结果消息。</li>
</ul>
<h2 id="summarize-messages">Summarize messages</h2>
<p>above pattern will lose information
Summarizing message with a LLM and use the built-in <code>SUmmarizationMiddleware</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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="n">tools</span><span class="o">=</span><span class="p">[</span><span class="o">...</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">SummarizationMiddleware</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.4-mini&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">trigger</span><span class="o">=</span><span class="p">(</span><span class="s2">&#34;tokens&#34;</span><span class="p">,</span> <span class="mi">4000</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">keep</span><span class="o">=</span><span class="p">(</span><span class="s2">&#34;messages&#34;</span><span class="p">,</span> <span class="mi">20</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="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">checkpointer</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="access-memory">Access memory</h1>
<h2 id="tools">tools</h2>
<h3 id="read-short-term-memory-in-a-tool">Read short-term memory in a tool</h3>
<p>Using <code>runtime</code> parameter(typed as <code>ToolRuntime</code>)
runtime parameter can not be seen by model but the tool can access the state through it</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user_info</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Look up user info.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_id</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">&#34;user_id&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;User is John Smith&#34;</span> <span class="k">if</span> <span class="n">user_id</span> <span class="o">==</span> <span class="s2">&#34;user_123&#34;</span> <span class="k">else</span> <span class="s2">&#34;Unknown user&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="write-short-term-memory-form-tools">write short-term memory form tools</h3>
<p>Using return Command with a <code>ToolMessage</code></p>
<h2 id="prompt">Prompt</h2>
<p>Using middleware to access to ~ to create dynamic prompts on conversation history or custom state fields</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">typing</span> <span class="n">import</span> <span class="n">TypedDict</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">dynamic_prompt</span><span class="p">,</span> <span class="n">ModelRequest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">CustomContext</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get the weather in a city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;The weather in {city} is always sunny!&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">dynamic_prompt</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">dynamic_system_prompt</span><span class="p">(</span><span class="n">request</span><span class="p">:</span> <span class="n">ModelRequest</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_name</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">runtime</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s2">&#34;user_name&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">system_prompt</span> <span class="o">=</span> <span class="n">f</span><span class="s2">&#34;You are a helpful assistant. Address the user as {user_name}.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">system_prompt</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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-nano&#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="p">[</span><span class="n">get_weather</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span><span class="n">dynamic_system_prompt</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">context_schema</span><span class="o">=</span><span class="n">CustomContext</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></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 is the weather in SF?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">context</span><span class="o">=</span><span class="n">CustomContext</span><span class="p">(</span><span class="n">user_name</span><span class="o">=</span><span class="s2">&#34;John Smith&#34;</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="k">for</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">result</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">    <span class="n">msg</span><span class="o">.</span><span class="n">pretty_print</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="before-model">Before model</h2>
<p>Using @before_model middleware to process message before model calls</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">RemoveMessage</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">graph</span><span class="o">.</span><span class="n">message</span> <span class="n">import</span> <span class="n">REMOVE_ALL_MESSAGES</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">checkpoint</span><span class="o">.</span><span class="n">memory</span> <span class="n">import</span> <span class="n">InMemorySaver</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span><span class="p">,</span> <span class="n">AgentState</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">before_model</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain_core</span><span class="o">.</span><span class="n">runnables</span> <span class="n">import</span> <span class="n">RunnableConfig</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">runtime</span> <span class="n">import</span> <span class="n">Runtime</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">typing</span> <span class="n">import</span> <span class="n">Any</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">before_model</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">trim_messages</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">AgentState</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">Runtime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">|</span> <span class="n">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Keep only the last few messages to fit context window.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">messages</span> <span class="o">=</span> <span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]</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">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">3</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">None</span>  <span class="c1"># No changes needed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">first_msg</span> <span class="o">=</span> <span class="n">messages</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">recent_messages</span> <span class="o">=</span> <span class="n">messages</span><span class="p">[</span><span class="o">-</span><span class="mi">3</span><span class="p">:]</span> <span class="k">if</span> <span class="n">len</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="n">messages</span><span class="p">[</span><span class="o">-</span><span class="mi">4</span><span class="p">:]</span>
</span></span><span class="line"><span class="cl">    <span class="n">new_messages</span> <span class="o">=</span> <span class="p">[</span><span class="n">first_msg</span><span class="p">]</span> <span class="o">+</span> <span class="n">recent_messages</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="n">RemoveMessage</span><span class="p">(</span><span class="n">id</span><span class="o">=</span><span class="n">REMOVE_ALL_MESSAGES</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="o">*</span><span class="n">new_messages</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></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;gpt-5-nano&#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="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span><span class="n">trim_messages</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">InMemorySaver</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></span><span class="line"><span class="cl"><span class="n">config</span><span class="p">:</span> <span class="n">RunnableConfig</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;1&#34;</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="s2">&#34;hi, my name is bob&#34;</span><span class="p">},</span> <span class="n">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="s2">&#34;write a short poem about cats&#34;</span><span class="p">},</span> <span class="n">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="s2">&#34;now do the same but for dogs&#34;</span><span class="p">},</span> <span class="n">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">final_response</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="s2">&#34;what&#39;s my name?&#34;</span><span class="p">},</span> <span class="n">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">final_response</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">pretty_print</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">================================== Ai Message ==================================
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">Your name is Bob. You told me that earlier.
</span></span></span><span class="line"><span class="cl"><span class="s2">If you&#39;d like me to call you a nickname or use a different name, just say the word.
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>After model
Using @after_model</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">RemoveMessage</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">checkpoint</span><span class="o">.</span><span class="n">memory</span> <span class="n">import</span> <span class="n">InMemorySaver</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span><span class="p">,</span> <span class="n">AgentState</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">after_model</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">runtime</span> <span class="n">import</span> <span class="n">Runtime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">after_model</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">validate_response</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">AgentState</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">Runtime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">dict</span> <span class="o">|</span> <span class="n">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Remove messages containing sensitive words.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">STOP_WORDS</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;password&#34;</span><span class="p">,</span> <span class="s2">&#34;secret&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">last_message</span> <span class="o">=</span> <span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">any</span><span class="p">(</span><span class="n">word</span> <span class="ow">in</span> <span class="n">last_message</span><span class="o">.</span><span class="n">content</span> <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">STOP_WORDS</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span><span class="n">RemoveMessage</span><span class="p">(</span><span class="n">id</span><span class="o">=</span><span class="n">last_message</span><span class="o">.</span><span class="n">id</span><span class="p">)]}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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-nano&#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="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span><span class="n">validate_response</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">checkpointer</span><span class="o">=</span><span class="n">InMemorySaver</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>Streaming</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/streaming/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/streaming/</guid>
      <description>Streaming相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="overview">Overview</h1>
<p>实现的功能:</p>
<ul>
<li>Stream agent progress</li>
<li>Stream LLM tokens</li>
<li>Streaming thinking/reasoning tokens</li>
<li>Stream custom updates</li>
<li>Stream multiple modes:从updates,messages,custom中进行选择</li>
</ul>
<h1 id="supported-stream-modes">Supported stream modes</h1>
<p>将下列的一个或者多个流式传输模式作为列表传输给stream或者astream方法</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Mode</th>
					<th style="text-align: left">Description</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><code>updates</code></td>
					<td style="text-align: left">Streams state updates after each agent step. If multiple updates are made in the same step (e.g., multiple nodes are run), those updates are streamed separately.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>messages</code></td>
					<td style="text-align: left">Streams tuples of <code>(token, metadata)</code> from any graph nodes where an LLM is invoked.</td>
			</tr>
			<tr>
					<td style="text-align: left"><code>custom</code></td>
					<td style="text-align: left">Streams custom data from inside your graph nodes using the stream writer.</td>
			</tr>
	</tbody>
</table>
<h1 id="agent-progress">Agent progress</h1>
<p>使用带有stream_mode =&ldquo;updates&quot;的stream或者astream方法
将在每个agent step之后发送一个事件</p>
<p>例子:
在一次tool call之后,你应该看到下列更新</p>
<ul>
<li><strong>LLM node</strong>: <a href="https://reference.langchain.com/python/langchain-core/messages/ai/AIMessage"><code>AIMessage</code></a> with tool call requests</li>
<li><strong>Tool node</strong>: <a href="https://reference.langchain.com/python/langchain-core/messages/tool/ToolMessage"><code>ToolMessage</code></a> with execution result</li>
<li><strong>LLM node</strong>: Final AI response</li>
</ul>
<p>通过<code>config</code>传递thread_id以便checkpointer进行保存和后续的resume
也可以传递context,后续可以使用runtime.context进行访问</p>
<h1 id="llm-tokens">LLM tokens</h1>
<p>使用<code>stream_mode = &quot;message&quot;</code>来访问token usage
在输出中可以看到agent的工具调用和最终的response</p>
<h1 id="custom-updates">Custom updates</h1>
<p>想要流式传输工具执行的过程(或结果),使用``get_stream_writer `inside the tool</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">config</span> <span class="n">import</span> <span class="n">get_stream_writer</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get weather for a given city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span> <span class="o">=</span> <span class="n">get_stream_writer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># stream any arbitrary data</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Looking up data for city: {city}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Acquired data for city: {city}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;It&#39;s always sunny in {city}!&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;claude-sonnet-4-6&#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="p">[</span><span class="n">get_weather</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></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 is the weather in SF?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">stream_mode</span><span class="o">=</span><span class="s2">&#34;custom&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v2&#34;</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="k">if</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;custom&#34;</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">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="stream-multiple-modes">Stream multiple modes</h1>
<p>通过将它们以mode列表的形式传输:stream_mode=[&ldquo;updates&rdquo;,&ldquo;custom&rdquo;]</p>
<p>每一段streamed chunk都是<code>StreamPart</code>的dict with type,ns and data 的keys
通过chunk[&ldquo;type&rdquo;]来决定流式模式,通过chunk[&ldquo;data&rdquo;]来访问负载</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">config</span> <span class="n">import</span> <span class="n">get_stream_writer</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get weather for a given city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span> <span class="o">=</span> <span class="n">get_stream_writer</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Looking up data for city: {city}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Acquired data for city: {city}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;It&#39;s always sunny in {city}!&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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-nano&#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="p">[</span><span class="n">get_weather</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></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 is the weather in SF?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">stream_mode</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;updates&#34;</span><span class="p">,</span> <span class="s2">&#34;custom&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v2&#34;</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="nb">print</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;stream_mode: {chunk[&#39;type&#39;]}&#34;</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">f</span><span class="s2">&#34;content: {chunk[&#39;data&#39;]}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="common-patterns">Common patterns</h1>
<p>常见的几种应用场景</p>
<h2 id="stream-thinkingreasoning-tokens">Stream thinking/reasoning tokens</h2>
<p>一些模型会在产生最终的answer之前在内部进行思考
可以通过过滤standard contnent blocks中的type = &ldquo;reasoning&quot;的部分来这些thinging/reasoning tokens</p>
<p>需要使用的mode为message即,stream_mode =&ldquo;message&rdquo;(与上文相符合)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">stream = agent.stream_events(
</span></span><span class="line"><span class="cl">    {&#34;messages&#34;: [{&#34;role&#34;: &#34;user&#34;, &#34;content&#34;: &#34;What is the weather in SF?&#34;}]},
</span></span><span class="line"><span class="cl">    version=&#34;v3&#34;,
</span></span><span class="line"><span class="cl">)
</span></span><span class="line"><span class="cl">for message in stream.messages:
</span></span><span class="line"><span class="cl">    for token in message.reasoning:
</span></span><span class="line"><span class="cl">        print(f&#34;[thinking] {token}&#34;, end=&#34;&#34;)
</span></span><span class="line"><span class="cl">    for token in message.text:
</span></span><span class="line"><span class="cl">        print(token, end=&#34;&#34;, flush=True)
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="streaming-tool-calls">Streaming tool calls</h2>
<p>if you want to stream both:</p>
<ol>
<li>Partial JSON as <a href="https://docs.langchain.com/oss/python/langchain/models#tool-calling">tool calls</a> are generated</li>
<li>The completed, parsed tool calls that are executed</li>
</ol>
<p>前者可以通过指定stream_mode= &ldquo;message&rdquo;
后者,根据是否在state中被tracked:
True: 指定stream_mode = [&ldquo;messages&rdquo;,&ldquo;updates&rdquo;],并通过state updates来访问(如下所示)
False: 使用custom updates 或者 aggregate the chunks during the streaming loop (<a href="https://docs.langchain.com/oss/python/langchain/streaming#accessing-completed-messages">next section</a>).</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span><span class="n">input_message</span><span class="p">]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">stream_mode</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">,</span> <span class="s2">&#34;updates&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v2&#34;</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="k">if</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;messages&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">token</span><span class="p">,</span> <span class="n">metadata</span> <span class="o">=</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">AIMessageChunk</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">_render_message_chunk</span><span class="p">(</span><span class="n">token</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;updates&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">source</span><span class="p">,</span> <span class="n">update</span> <span class="ow">in</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">source</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&#34;model&#34;</span><span class="p">,</span> <span class="s2">&#34;tools&#34;</span><span class="p">):</span>  <span class="c1"># `source` captures node name</span>
</span></span><span class="line"><span class="cl">                <span class="n">_render_completed_message</span><span class="p">(</span><span class="n">update</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="accessing-completed-messages">Accessing completed messages</h3>
<p>在message不通过state updates反映时采取的途径之一
通过aggrrgate message chunks in the streaming loop</p>
<p>1.使用stream_writer inside the tool
2.如果你不能添加自定义的时间到stream中时,你可以流式传输中聚合消息块</p>
<h2 id="streaming-with-human-in-the-loop">Streaming with human-in-the-loop</h2>
<p>解决human-in-the-loop interrupts:</p>
<ol>
<li>为agent配置hunman-in-the-loop middleare 和 checkpointer</li>
<li>搜集在&quot;update&quot;流式传输模式下的interrupts</li>
<li>通过command来对这些interrupts进行响应</li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">typing</span> <span class="n">import</span> <span class="n">Any</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">HumanInTheLoopMiddleware</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">AIMessage</span><span class="p">,</span> <span class="n">AIMessageChunk</span><span class="p">,</span> <span class="n">AnyMessage</span><span class="p">,</span> <span class="n">ToolMessage</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">checkpoint</span><span class="o">.</span><span class="n">memory</span> <span class="n">import</span> <span class="n">InMemorySaver</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">types</span> <span class="n">import</span> <span class="n">Command</span><span class="p">,</span> <span class="n">Interrupt</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get weather for a given city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;It&#39;s always sunny in {city}!&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">checkpointer</span> <span class="o">=</span> <span class="n">InMemorySaver</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;openai:gpt-5.5&#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="p">[</span><span class="n">get_weather</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">HumanInTheLoopMiddleware</span><span class="p">(</span><span class="n">interrupt_on</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;get_weather&#34;</span><span class="p">:</span> <span class="n">True</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="n">checkpointer</span><span class="o">=</span><span class="n">checkpointer</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></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_render_message_chunk</span><span class="p">(</span><span class="n">token</span><span class="p">:</span> <span class="n">AIMessageChunk</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">token</span><span class="o">.</span><span class="n">text</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">token</span><span class="o">.</span><span class="n">text</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;|&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">token</span><span class="o">.</span><span class="n">tool_call_chunks</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">token</span><span class="o">.</span><span class="n">tool_call_chunks</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_render_completed_message</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">AnyMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">AIMessage</span><span class="p">)</span> <span class="ow">and</span> <span class="n">message</span><span class="o">.</span><span class="n">tool_calls</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">f</span><span class="s2">&#34;Tool calls: {message.tool_calls}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">ToolMessage</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">f</span><span class="s2">&#34;Tool response: {message.content_blocks}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_render_interrupt</span><span class="p">(</span><span class="n">interrupt</span><span class="p">:</span> <span class="n">Interrupt</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">interrupts</span> <span class="o">=</span> <span class="n">interrupt</span><span class="o">.</span><span class="n">value</span>  
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">request</span> <span class="ow">in</span> <span class="n">interrupts</span><span class="p">[</span><span class="s2">&#34;action_requests&#34;</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">request</span><span class="p">[</span><span class="s2">&#34;description&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">input_message</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;user&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;content&#34;</span><span class="p">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;Can you look up the weather in Boston and San Francisco?&#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="n">config</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="s2">&#34;some_id&#34;</span><span class="p">}}</span>
</span></span><span class="line"><span class="cl"><span class="n">interrupts</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span><span class="n">input_message</span><span class="p">]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">config</span><span class="o">=</span><span class="n">config</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">stream_mode</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">,</span> <span class="s2">&#34;updates&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v2&#34;</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="k">if</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;messages&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">token</span><span class="p">,</span> <span class="n">metadata</span> <span class="o">=</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">AIMessageChunk</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">_render_message_chunk</span><span class="p">(</span><span class="n">token</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;updates&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">source</span><span class="p">,</span> <span class="n">update</span> <span class="ow">in</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">source</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&#34;model&#34;</span><span class="p">,</span> <span class="s2">&#34;tools&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="n">_render_completed_message</span><span class="p">(</span><span class="n">update</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">source</span> <span class="o">==</span> <span class="s2">&#34;__interrupt__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">interrupts</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">update</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="n">_render_interrupt</span><span class="p">(</span><span class="n">update</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>接下来,为每一个interrupt收集对应的decision,并且decision的顺序与我们收集的action对应</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">def _get_interrupt_decisions(interrupt: Interrupt) -&gt; list[dict]:
</span></span><span class="line"><span class="cl">    return [
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;edit&#34;,
</span></span><span class="line"><span class="cl">            &#34;edited_action&#34;: {
</span></span><span class="line"><span class="cl">                &#34;name&#34;: &#34;get_weather&#34;,
</span></span><span class="line"><span class="cl">                &#34;args&#34;: {&#34;city&#34;: &#34;Boston, U.K.&#34;},
</span></span><span class="line"><span class="cl">            },
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">        if &#34;boston&#34; in request[&#34;description&#34;].lower()
</span></span><span class="line"><span class="cl">        else {&#34;type&#34;: &#34;approve&#34;}
</span></span><span class="line"><span class="cl">        for request in interrupt.value[&#34;action_requests&#34;]
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">decisions = {}
</span></span><span class="line"><span class="cl">for interrupt in interrupts:
</span></span><span class="line"><span class="cl">    decisions[interrupt.id] = {
</span></span><span class="line"><span class="cl">        &#34;decisions&#34;: _get_interrupt_decisions(interrupt)
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">decisions
</span></span></code></pre></td></tr></table>
</div>
</div><p>我们可以通过向流式传输的循环传入一个command来resume</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">interrupts</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">Command</span><span class="p">(</span><span class="n">resume</span><span class="o">=</span><span class="n">decisions</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">config</span><span class="o">=</span><span class="n">config</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">stream_mode</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">,</span> <span class="s2">&#34;updates&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v2&#34;</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="c1"># Streaming loop is unchanged</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;messages&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">token</span><span class="p">,</span> <span class="n">metadata</span> <span class="o">=</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">AIMessageChunk</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">_render_message_chunk</span><span class="p">(</span><span class="n">token</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;updates&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">source</span><span class="p">,</span> <span class="n">update</span> <span class="ow">in</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">source</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&#34;model&#34;</span><span class="p">,</span> <span class="s2">&#34;tools&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="n">_render_completed_message</span><span class="p">(</span><span class="n">update</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">source</span> <span class="o">==</span> <span class="s2">&#34;__interrupt__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">interrupts</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">update</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="n">_render_interrupt</span><span class="p">(</span><span class="n">update</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="streaming-from-sub-agents">Streaming from sub-agents</h2>
<p>当agent中有多个LLMs时,需要对其来源进行消歧
在创建agent时使用<code>name</code>参数,该参数在&quot;message&quot;的stream_mode中可以通过lc_agent_name键中的metadata访问
ps: 在创建stream时specify <code>subgraph是= True</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">typing</span> <span class="n">import</span> <span class="n">Any</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">chat_models</span> <span class="n">import</span> <span class="n">init_chat_model</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">AIMessage</span><span class="p">,</span> <span class="n">AnyMessage</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get weather for a given city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;It&#39;s always sunny in {city}!&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">weather_model</span> <span class="o">=</span> <span class="n">init_chat_model</span><span class="p">(</span><span class="s2">&#34;openai:gpt-5.5&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">weather_agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="n">weather_model</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span><span class="o">=</span><span class="s2">&#34;weather_agent&#34;</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></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">call_weather_agent</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Query the weather agent.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">result</span> <span class="o">=</span> <span class="n">weather_agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;messages&#34;</span><span class="p">:</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="n">query</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="k">return</span> <span class="n">result</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">text</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">supervisor_model</span> <span class="o">=</span> <span class="n">init_chat_model</span><span class="p">(</span><span class="s2">&#34;openai:gpt-5.5&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">model</span><span class="o">=</span><span class="n">supervisor_model</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">call_weather_agent</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span><span class="o">=</span><span class="s2">&#34;supervisor&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_render_message_chunk</span><span class="p">(</span><span class="n">token</span><span class="p">:</span> <span class="n">AIMessageChunk</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">token</span><span class="o">.</span><span class="n">text</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">token</span><span class="o">.</span><span class="n">text</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&#34;|&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">token</span><span class="o">.</span><span class="n">tool_call_chunks</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">token</span><span class="o">.</span><span class="n">tool_call_chunks</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">_render_completed_message</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="n">AnyMessage</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">AIMessage</span><span class="p">)</span> <span class="ow">and</span> <span class="n">message</span><span class="o">.</span><span class="n">tool_calls</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">f</span><span class="s2">&#34;Tool calls: {message.tool_calls}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">ToolMessage</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">f</span><span class="s2">&#34;Tool response: {message.content_blocks}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">input_message</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 is the weather in Boston?&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">current_agent</span> <span class="o">=</span> <span class="n">None</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">chunk</span> <span class="ow">in</span> <span class="n">agent</span><span class="o">.</span><span class="n">stream</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span><span class="n">input_message</span><span class="p">]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">stream_mode</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">,</span> <span class="s2">&#34;updates&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraphs</span><span class="o">=</span><span class="n">True</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">version</span><span class="o">=</span><span class="s2">&#34;v2&#34;</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="k">if</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;messages&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">token</span><span class="p">,</span> <span class="n">metadata</span> <span class="o">=</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">agent_name</span> <span class="p">:</span><span class="o">=</span> <span class="n">metadata</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;lc_agent_name&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">agent_name</span> <span class="o">!=</span> <span class="n">current_agent</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">f</span><span class="s2">&#34;🤖 {agent_name}: &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="n">current_agent</span> <span class="o">=</span> <span class="n">agent_name</span>  
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">AIMessageChunk</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">_render_message_chunk</span><span class="p">(</span><span class="n">token</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;type&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;updates&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">source</span><span class="p">,</span> <span class="n">update</span> <span class="ow">in</span> <span class="n">chunk</span><span class="p">[</span><span class="s2">&#34;data&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">source</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&#34;model&#34;</span><span class="p">,</span> <span class="s2">&#34;tools&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="n">_render_completed_message</span><span class="p">(</span><span class="n">update</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="disable-streaming">Disable streaming</h1>
<p>初始化时: set <code>streaming = False</code></p>
<h1 id="v2-streaming-format">v2 streaming format</h1>
<p>Pass <code>version=&quot;v2&quot;</code> to <code>stream()</code> or <code>astream()</code> to get a unified output format. Every chunk is a <code>StreamPart</code> dict with <code>type</code>, <code>ns</code>, and <code>data</code> keys — the same shape regardless of stream mode or number of modes:</p>
<p>The v2 format also improves <code>invoke()</code> — it returns a <code>GraphOutput</code> object with <code>.value</code> and <code>.interrupts</code> attributes, cleanly separating state from interrupt metadata:</p>
]]></content:encoded>
    </item>
    <item>
      <title>Structured Output</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/structured-output/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/structured-output/</guid>
      <description>Structured Output相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>返回的形式:
JSON objects, Pydantic models,or dataclasses that your application can use directly</p>
<p>LangChain&rsquo;s <code>create_agent</code> 会自动处理结构化输出
用户设置desired 结构化输出的schema
返回在 in the key <code>strucured_responese</code> key of the agent&rsquo;s state</p>
<p>Field函数的作用:
结构化输出时,是创建元数据的重要途径,且其内部的description可以作为Prompt的一部分指导LLM的工作</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">def create_agent(
</span></span><span class="line"><span class="cl">    ...
</span></span><span class="line"><span class="cl">    response_format: Union[
</span></span><span class="line"><span class="cl">        ToolStrategy[StructuredResponseT],
</span></span><span class="line"><span class="cl">        ProviderStrategy[StructuredResponseT],
</span></span><span class="line"><span class="cl">        type[StructuredResponseT],
</span></span><span class="line"><span class="cl">        None,
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">)
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="response-format">Response format</h1>
<p>使用<code>response_format</code>来控制agent返回结构化数据的方式</p>
<ul>
<li><strong><code>ToolStrategy[StructuredResponseT]</code></strong>: Uses tool calling for structured output</li>
<li><strong><code>ProviderStrategy[StructuredResponseT]</code></strong>: Uses provider-native structured output</li>
<li><strong><code>type[StructuredResponseT]</code></strong>: Schema type - automatically selects best strategy based on model capabilities</li>
<li><strong><code>None</code></strong>: Structured output not explicitly requested</li>
</ul>
<p>When a schema type is provided directly, LangChain automatically chooses:</p>
<ul>
<li><code>ProviderStrategy</code> if the model and provider chosen supports native structured output (e.g. <a href="https://docs.langchain.com/oss/python/integrations/providers/openai">OpenAI</a>, <a href="https://docs.langchain.com/oss/python/integrations/providers/anthropic">Anthropic (Claude)</a>, or <a href="https://docs.langchain.com/oss/python/integrations/providers/xai">xAI (Grok)</a>).</li>
<li><code>ToolStrategy</code> for all other models.</li>
</ul>
<h1 id="provider-strategy">Provider strategy</h1>
<p>一些provider支持原生的结构化输出
这是最可靠的方式
要使用这种方式,请配置 <code>Providerstrategy</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class ProviderStrategy(Generic[SchemaT]):
</span></span><span class="line"><span class="cl">    schema: type[SchemaT]
</span></span><span class="line"><span class="cl">    strict: bool | None = None
</span></span></code></pre></td></tr></table>
</div>
</div><p>参数
schema(required):
规定了结构化输出的format,取值有:</p>
<ul>
<li><strong>Pydantic models</strong>: <code>BaseModel</code> subclasses with field validation. Returns validated Pydantic instance.</li>
<li><strong>Dataclasses</strong>: Python dataclasses with type annotations. Returns dict.</li>
<li><strong>TypedDict</strong>: Typed dictionary classes. Returns dict.</li>
<li><strong>JSON Schema</strong>: Dictionary with JSON schema specification. Must include top-level <code>title</code> and <code>description</code> keys. Returns dict.</li>
</ul>
<p>strict:
可选;默认None;控制是否严格遵守schema</p>
<p>当你直接把schema type传给<a href="https://reference.langchain.com/python/langchain/agents/factory/create_agent"><code>create_agent.response_format</code></a> 时且模型支持原生的结构化输出时,LangChain会自动选择ProviderStrategy</p>
<h1 id="tool-calling-strategy">Tool calling strategy</h1>
<p>对于模型不支持原生的结构化输出,LangChain使用tool calling,这对于所有的支持tool calling的模型都适用
使用:配置 <code>ToolStrategy</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ToolStrategy</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">SchemaT</span><span class="p">]):</span>
</span></span><span class="line"><span class="cl">    <span class="n">schema</span><span class="p">:</span> <span class="nb">type</span><span class="p">[</span><span class="n">SchemaT</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">tool_message_content</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="n">handle_errors</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="nb">bool</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nb">type</span><span class="p">[</span><span class="ne">Exception</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="nb">tuple</span><span class="p">[</span><span class="nb">type</span><span class="p">[</span><span class="ne">Exception</span><span class="p">],</span> <span class="o">...</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">Callable</span><span class="p">[[</span><span class="ne">Exception</span><span class="p">],</span> <span class="nb">str</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>schema: required
同上</p>
<p>tool_message_content:
生成结构化输出时的tool message的自定义内容
如果没有提供,为显示结构化响应的响应数据</p>
<p>handle_errors:
默认为True
当结构化输出的验证失败的时候的错误处理策略,参数如下</p>
<ul>
<li><strong><code>True</code></strong>: Catch all errors with default error template</li>
<li><strong><code>str</code></strong>: Catch all errors with this custom message</li>
<li><strong><code>type[Exception]</code></strong>: Only catch this exception type with default message</li>
<li><strong><code>tuple[type[Exception], ...]</code></strong>: Only catch these exception types with default message</li>
<li><strong><code>Callable[[Exception], str]</code></strong>: Custom function that returns error message</li>
<li><strong><code>False</code></strong>: No retry, let exceptions propagate</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<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">pydantic</span> <span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Literal</span><span class="p">,</span> <span class="n">Union</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.agents</span> <span class="kn">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.agents.structured_output</span> <span class="kn">import</span> <span class="n">ToolStrategy</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ProductReview</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Analysis of a product review.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rating</span><span class="p">:</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The rating of the product&#34;</span><span class="p">,</span> <span class="n">ge</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sentiment</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;positive&#34;</span><span class="p">,</span> <span class="s2">&#34;negative&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The sentiment of the review&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">key_points</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The key points of the review. Lowercase, 1-3 words each.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CustomerComplaint</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;A customer complaint about a product or service.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">issue_type</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;product&#34;</span><span class="p">,</span> <span class="s2">&#34;service&#34;</span><span class="p">,</span> <span class="s2">&#34;shipping&#34;</span><span class="p">,</span> <span class="s2">&#34;billing&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The type of issue&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">severity</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;low&#34;</span><span class="p">,</span> <span class="s2">&#34;medium&#34;</span><span class="p">,</span> <span class="s2">&#34;high&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The severity of the complaint&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">description</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;Brief description of the complaint&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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="n">tools</span><span class="o">=</span><span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">response_format</span><span class="o">=</span><span class="n">ToolStrategy</span><span class="p">(</span><span class="n">Union</span><span class="p">[</span><span class="n">ProductReview</span><span class="p">,</span> <span class="n">CustomerComplaint</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></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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;Analyze this review: &#39;Great product: 5 out of 5 stars. Fast shipping, but expensive&#39;&#34;</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="n">result</span><span class="p">[</span><span class="s2">&#34;structured_response&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ProductReview(rating=5, sentiment=&#39;positive&#39;, key_points=[&#39;fast shipping&#39;, &#39;expensive&#39;])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="custom-tool-message-content">Custom tool message content</h2>
<p>the <code>tool_message_content</code> 参数允许你自定义结构化输出产生时呈现在会话历史中的message</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<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">pydantic</span> <span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Literal</span><span class="p">,</span> <span class="n">Union</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.agents</span> <span class="kn">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.agents.structured_output</span> <span class="kn">import</span> <span class="n">ToolStrategy</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ProductReview</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Analysis of a product review.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rating</span><span class="p">:</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The rating of the product&#34;</span><span class="p">,</span> <span class="n">ge</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sentiment</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;positive&#34;</span><span class="p">,</span> <span class="s2">&#34;negative&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The sentiment of the review&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">key_points</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The key points of the review. Lowercase, 1-3 words each.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">CustomerComplaint</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;A customer complaint about a product or service.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">issue_type</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;product&#34;</span><span class="p">,</span> <span class="s2">&#34;service&#34;</span><span class="p">,</span> <span class="s2">&#34;shipping&#34;</span><span class="p">,</span> <span class="s2">&#34;billing&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The type of issue&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">severity</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&#34;low&#34;</span><span class="p">,</span> <span class="s2">&#34;medium&#34;</span><span class="p">,</span> <span class="s2">&#34;high&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;The severity of the complaint&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">description</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;Brief description of the complaint&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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="n">tools</span><span class="o">=</span><span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">response_format</span><span class="o">=</span><span class="n">ToolStrategy</span><span class="p">(</span><span class="n">Union</span><span class="p">[</span><span class="n">ProductReview</span><span class="p">,</span> <span class="n">CustomerComplaint</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></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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;Analyze this review: &#39;Great product: 5 out of 5 stars. Fast shipping, but expensive&#39;&#34;</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="n">result</span><span class="p">[</span><span class="s2">&#34;structured_response&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ProductReview(rating=5, sentiment=&#39;positive&#39;, key_points=[&#39;fast shipping&#39;, &#39;expensive&#39;])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="error-handing">Error handing</h2>
<p>LangChain提供了智能重试机制</p>
<h3 id="multiple-structured-outputs-error">Multiple structured outputs error</h3>
<p>当模型错误地调用了多个结构化工具输出,会在<code>ToolMessage</code>中生成相应的反馈和提示词以便模型进行重试</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">pydantic</span> <span class="n">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">typing</span> <span class="n">import</span> <span class="n">Union</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">structured_output</span> <span class="n">import</span> <span class="n">ToolStrategy</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">ContactInfo</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;Person&#39;s name&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">email</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;Email address&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">EventDetails</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">event_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;Name of the event&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">date</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;Event date&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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="n">tools</span><span class="o">=</span><span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">response_format</span><span class="o">=</span><span class="n">ToolStrategy</span><span class="p">(</span><span class="n">Union</span><span class="p">[</span><span class="n">ContactInfo</span><span class="p">,</span> <span class="n">EventDetails</span><span class="p">])</span>  <span class="c1"># Default: handle_errors=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="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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;Extract info: John Doe (john@email.com) is organizing Tech Conference on March 15th&#34;</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="schema-validation-error">Schema validation error</h3>
<p>当结构化输出和schema不匹配时,agent会返回特定的错误反馈</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<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">pydantic</span> <span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.agents</span> <span class="kn">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.agents.structured_output</span> <span class="kn">import</span> <span class="n">ToolStrategy</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ProductRating</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">rating</span><span class="p">:</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;Rating from 1-5&#34;</span><span class="p">,</span> <span class="n">ge</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">comment</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;Review comment&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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="n">tools</span><span class="o">=</span><span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">response_format</span><span class="o">=</span><span class="n">ToolStrategy</span><span class="p">(</span><span class="n">ProductRating</span><span class="p">),</span>  <span class="c1"># Default: handle_errors=True</span>
</span></span><span class="line"><span class="cl">    <span class="n">system_prompt</span><span class="o">=</span><span class="s2">&#34;You are a helpful assistant that parses product reviews. Do not make any field or value up.&#34;</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">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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;Parse this: Amazing product, 10/10!&#34;</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="o">================================</span> <span class="n">Human</span> <span class="n">Message</span> <span class="o">=================================</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Parse</span> <span class="n">this</span><span class="p">:</span> <span class="n">Amazing</span> <span class="n">product</span><span class="p">,</span> <span class="mi">10</span><span class="o">/</span><span class="mi">10</span><span class="o">!</span>
</span></span><span class="line"><span class="cl"><span class="o">==================================</span> <span class="n">Ai</span> <span class="n">Message</span> <span class="o">==================================</span>
</span></span><span class="line"><span class="cl"><span class="n">Tool</span> <span class="n">Calls</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">ProductRating</span> <span class="p">(</span><span class="n">call_1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">Call</span> <span class="n">ID</span><span class="p">:</span> <span class="n">call_1</span>
</span></span><span class="line"><span class="cl">  <span class="n">Args</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">rating</span><span class="p">:</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl">    <span class="n">comment</span><span class="p">:</span> <span class="n">Amazing</span> <span class="n">product</span>
</span></span><span class="line"><span class="cl"><span class="o">=================================</span> <span class="n">Tool</span> <span class="n">Message</span> <span class="o">=================================</span>
</span></span><span class="line"><span class="cl"><span class="n">Name</span><span class="p">:</span> <span class="n">ProductRating</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Error</span><span class="p">:</span> <span class="n">Failed</span> <span class="n">to</span> <span class="n">parse</span> <span class="n">structured</span> <span class="n">output</span> <span class="k">for</span> <span class="k">tool</span> <span class="s1">&#39;ProductRating&#39;</span><span class="p">:</span> <span class="mi">1</span> <span class="n">validation</span> <span class="n">error</span> <span class="k">for</span> <span class="n">ProductRating</span><span class="o">.</span><span class="n">rating</span>
</span></span><span class="line"><span class="cl">  <span class="ne">Input</span> <span class="n">should</span> <span class="n">be</span> <span class="n">less</span> <span class="n">than</span> <span class="ow">or</span> <span class="n">equal</span> <span class="n">to</span> <span class="mi">5</span> <span class="p">[</span><span class="n">type</span><span class="o">=</span><span class="n">less_than_equal</span><span class="p">,</span> <span class="n">input_value</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">input_type</span><span class="o">=</span><span class="ne">int</span><span class="p">]</span><span class="o">.</span>
</span></span><span class="line"><span class="cl"> <span class="n">Please</span> <span class="n">fix</span> <span class="n">your</span> <span class="n">mistakes</span><span class="o">.</span>
</span></span><span class="line"><span class="cl"><span class="o">==================================</span> <span class="n">Ai</span> <span class="n">Message</span> <span class="o">==================================</span>
</span></span><span class="line"><span class="cl"><span class="n">Tool</span> <span class="n">Calls</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">  <span class="n">ProductRating</span> <span class="p">(</span><span class="n">call_2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">Call</span> <span class="n">ID</span><span class="p">:</span> <span class="n">call_2</span>
</span></span><span class="line"><span class="cl">  <span class="n">Args</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">rating</span><span class="p">:</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl">    <span class="n">comment</span><span class="p">:</span> <span class="n">Amazing</span> <span class="n">product</span>
</span></span><span class="line"><span class="cl"><span class="o">=================================</span> <span class="n">Tool</span> <span class="n">Message</span> <span class="o">=================================</span>
</span></span><span class="line"><span class="cl"><span class="n">Name</span><span class="p">:</span> <span class="n">ProductRating</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Returning</span> <span class="n">structured</span> <span class="n">response</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;rating&#39;</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span> <span class="s1">&#39;comment&#39;</span><span class="p">:</span> <span class="s1">&#39;Amazing product&#39;</span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="error-handling-strategies">Error handling strategies</h3>
<p>你可以通过handle_errors参数自定义错误处理的方式</p>
<p><strong>Custom error message:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">ToolStrategy</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">schema</span><span class="o">=</span><span class="n">ProductRating</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">handle_errors</span><span class="o">=</span><span class="s2">&#34;Please provide a valid rating between 1-5 and include a comment.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>If <code>handle_errors</code> is a string, the agent will <em>always</em> prompt the model to re-try with a fixed tool message:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">=================================</span> <span class="n">Tool</span> <span class="n">Message</span> <span class="o">=================================</span>
</span></span><span class="line"><span class="cl"><span class="n">Name</span><span class="p">:</span> <span class="n">ProductRating</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Please</span> <span class="n">provide</span> <span class="n">a</span> <span class="n">valid</span> <span class="n">rating</span> <span class="n">between</span> <span class="mi">1</span><span class="o">-</span><span class="mi">5</span> <span class="ow">and</span> <span class="n">include</span> <span class="n">a</span> <span class="n">comment</span><span class="o">.</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>Handle specific exceptions only:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">ToolStrategy</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">schema</span><span class="o">=</span><span class="n">ProductRating</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">handle_errors</span><span class="o">=</span><span class="ne">ValueError</span>  <span class="c1"># Only retry on ValueError, raise others</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>If <code>handle_errors</code> is an exception type, the agent will only retry (using the default error message) if the exception raised is the specified type. In all other cases, the exception will be raised.<strong>Handle multiple exception types:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">ToolStrategy</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">schema</span><span class="o">=</span><span class="n">ProductRating</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">handle_errors</span><span class="o">=</span><span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">)</span>  <span class="c1"># Retry on ValueError and TypeError</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>If <code>handle_errors</code> is a tuple of exceptions, the agent will only retry (using the default error message) if the exception raised is one of the specified types. In all other cases, the exception will be raised.<strong>Custom error handler function:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span></code></pre></td>
<td class="lntd">
<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">langchain.agents.structured_output</span> <span class="kn">import</span> <span class="n">StructuredOutputValidationError</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.agents.structured_output</span> <span class="kn">import</span> <span class="n">MultipleStructuredOutputsError</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">custom_error_handler</span><span class="p">(</span><span class="n">error</span><span class="p">:</span> <span class="ne">Exception</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">error</span><span class="p">,</span> <span class="n">StructuredOutputValidationError</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s2">&#34;There was an issue with the format. Try again.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">error</span><span class="p">,</span> <span class="n">MultipleStructuredOutputsError</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s2">&#34;Multiple structured outputs were returned. Pick the most relevant one.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="sa">f</span><span class="s2">&#34;Error: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">error</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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="n">tools</span><span class="o">=</span><span class="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">response_format</span><span class="o">=</span><span class="n">ToolStrategy</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                        <span class="n">schema</span><span class="o">=</span><span class="n">Union</span><span class="p">[</span><span class="n">ContactInfo</span><span class="p">,</span> <span class="n">EventDetails</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                        <span class="n">handle_errors</span><span class="o">=</span><span class="n">custom_error_handler</span>
</span></span><span class="line"><span class="cl">                    <span class="p">)</span>  <span class="c1"># Default: handle_errors=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="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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;Extract info: John Doe (john@email.com) is organizing Tech Conference on March 15th&#34;</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></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;messages&#39;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># If message is actually a ToolMessage object (not a dict), check its class name</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;ToolMessage&#34;</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">msg</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># If message is a dictionary or you want a fallback</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span> <span class="ow">and</span> <span class="n">msg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;tool_call_id&#39;</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">msg</span><span class="p">[</span><span class="s1">&#39;content&#39;</span><span class="p">])</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>On <code>StructuredOutputValidationError</code>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">================================= Tool Message =================================
</span></span><span class="line"><span class="cl">Name: ToolStrategy
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">There was an issue with the format. Try again.
</span></span></code></pre></td></tr></table>
</div>
</div><p>On <code>MultipleStructuredOutputsError</code>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">================================= Tool Message =================================
</span></span><span class="line"><span class="cl">Name: ToolStrategy
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Multiple structured outputs were returned. Pick the most relevant one.
</span></span></code></pre></td></tr></table>
</div>
</div><p>On other errors:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">================================= Tool Message =================================
</span></span><span class="line"><span class="cl">Name: ToolStrategy
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Error: &lt;error message&gt;
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>No error handling:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">response_format = ToolStrategy(
</span></span><span class="line"><span class="cl">    schema=ProductRating,
</span></span><span class="line"><span class="cl">    handle_errors=False  # All errors raised
</span></span><span class="line"><span class="cl">)
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
    <item>
      <title>Tools</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/core_components/tools/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/core_components/tools/</guid>
      <description>Tools相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="tools">Tools</h1>
<p>Extend what agents can do!</p>
<h1 id="create-tools">Create tools</h1>
<h2 id="basic-tool-definition">Basic tool definition</h2>
<p>The easiest way to create a tool is to use the <strong><code>@tool</code> decorator</strong>
In this way the <strong>docstring</strong> will become the description of the tool</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">search_database</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">limit</span><span class="p">:</span> <span class="ne">int</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Search the customer database for records matching the query.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    Args:
</span></span></span><span class="line"><span class="cl"><span class="s2">        query: Search terms to look for
</span></span></span><span class="line"><span class="cl"><span class="s2">        limit: Maximum number of results to return
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;Found {limit} results for &#39;{query}&#39;&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>docstring:&rsquo;&rsquo;'
ada
&rsquo;&rsquo;'
的部分
docstring应该内容丰富且简明扼要
参数的type hints是必须的,因为他们定义了工具的输入参数</p>
<h2 id="customize-tool-properties">Customize tool properties</h2>
<h3 id="custom-tool-name">Custom tool name</h3>
<p>by default,the tool name is the function name. But you can override it.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span><span class="p">(</span><span class="s2">&#34;web_search&#34;</span><span class="p">)</span>  <span class="c1"># Custom name</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Search the web for information.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;Results for: {query}&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">search</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>  <span class="c1"># web_search</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="custom-tool-description">Custom tool description</h3>
<p>Override the auto-generated tool description(refer to the docstring) for clearer model guidance</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span><span class="p">(</span><span class="s2">&#34;calculator&#34;</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="s2">&#34;Performs arithmetic calculations. Use this for any math problems.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">calc</span><span class="p">(</span><span class="n">expression</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Evaluate mathematical expressions.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">eval</span><span class="p">(</span><span class="n">expression</span><span class="p">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="advanced-schema-definition">Advanced schema definition</h2>
<p>Define complex inputs with Pydantic models or JSON schemas</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">pydantic</span> <span class="n">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">typing</span> <span class="n">import</span> <span class="n">Literal</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">WeatherInput</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Input for weather queries.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">location</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&#34;City name or coordinates&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">units</span><span class="p">:</span> <span class="n">Literal</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 class="o">=</span> <span class="n">Field</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">default</span><span class="o">=</span><span class="s2">&#34;celsius&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">description</span><span class="o">=</span><span class="s2">&#34;Temperature unit preference&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">include_forecast</span><span class="p">:</span> <span class="ne">bool</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">default</span><span class="o">=</span><span class="n">False</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">description</span><span class="o">=</span><span class="s2">&#34;Include 5-day forecast&#34;</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="err">@</span><span class="k">tool</span><span class="p">(</span><span class="n">args_schema</span><span class="o">=</span><span class="n">WeatherInput</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">location</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">units</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;celsius&#34;</span><span class="p">,</span> <span class="n">include_forecast</span><span class="p">:</span> <span class="ne">bool</span> <span class="o">=</span> <span class="n">False</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get current weather and optional forecast.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">temp</span> <span class="o">=</span> <span class="mi">22</span> <span class="k">if</span> <span class="n">units</span> <span class="o">==</span> <span class="s2">&#34;celsius&#34;</span> <span class="k">else</span> <span class="mi">72</span>
</span></span><span class="line"><span class="cl">    <span class="n">result</span> <span class="o">=</span> <span class="n">f</span><span class="s2">&#34;Current weather in {location}: {temp} degrees {units[0].upper()}&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">include_forecast</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">result</span> <span class="o">+=</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">Next 5 days: Sunny&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">result</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="reserved-argument-names">Reserved argument names</h2>
<p>Those can not be used as parameters&rsquo; name which will cause runtime errors
config: reserved for  RunnableConfig
runtime: reserved for ToolRuntime</p>
<h1 id="access-context">Access context</h1>
<p>How to access and update this information(conversation history,user data,persistent memory)</p>
<p>How!
By the <code>ToolRuntime</code> parameter</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Component</th>
					<th style="text-align: left">Description</th>
					<th style="text-align: left">Use case</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><strong>State</strong></td>
					<td style="text-align: left">Short-term memory - mutable data that exists for the current conversation (messages, counters, custom fields)</td>
					<td style="text-align: left">Access conversation history, track tool call counts</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Context</strong></td>
					<td style="text-align: left">Immutable configuration passed at invocation time (user IDs, session info)</td>
					<td style="text-align: left">Personalize responses based on user identity</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Store</strong></td>
					<td style="text-align: left">Long-term memory - persistent data that survives across conversations</td>
					<td style="text-align: left">Save user preferences, maintain knowledge base</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Stream Writer</strong></td>
					<td style="text-align: left">Emit real-time updates during tool execution</td>
					<td style="text-align: left">Show progress for long-running operations</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Execution Info</strong></td>
					<td style="text-align: left">Identity and retry information for the current execution (thread ID, run ID, attempt number)</td>
					<td style="text-align: left">Access thread/run IDs, adjust behavior based on retry state</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Server Info</strong></td>
					<td style="text-align: left">Server-specific metadata when running on LangGraph Server (assistant ID, graph ID, authenticated user)</td>
					<td style="text-align: left">Access assistant ID, graph ID, or authenticated user info</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Config</strong></td>
					<td style="text-align: left"><a href="https://reference.langchain.com/python/langchain-core/runnables/config/RunnableConfig"><code>RunnableConfig</code></a> for the execution</td>
					<td style="text-align: left">Access callbacks, tags, and metadata</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Tool Call ID</strong></td>
					<td style="text-align: left">Unique identifier for the current tool invocation</td>
					<td style="text-align: left">Correlate tool calls for logs and model invocations</td>
			</tr>
	</tbody>
</table>
<p><img alt="image-20260919214843362" loading="lazy" src="c:\\Users\\14152\\AppData\\Roaming\\Typora\\typora-user-images\\image-20260919214843362.png"></p>
<h2 id="short-term-memorystate">Short-term memory(State)</h2>
<p>Include the message history and any custom field you define in your graph state.</p>
<h3 id="access-state">Access state</h3>
<p>Use <code>runtime: ToolRuntime</code> to your signature to access state
在调用的时候,<code>ToolNode</code>会自动地注入value,但是这个参数不会出现在发送给model地schema上
你需要通过<code>runtime.state</code>才能访问到当前对话的state</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span><span class="p">,</span> <span class="n">ToolRuntime</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">HumanMessage</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_last_user_message</span><span class="p">(</span><span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get the most recent message from the user.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">messages</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Find the last human message</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">reversed</span><span class="p">(</span><span class="n">messages</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">isinstance</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">HumanMessage</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">message</span><span class="o">.</span><span class="n">content</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;No user messages found&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Access custom state fields</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user_preference</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">pref_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get a user preference value.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">preferences</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">state</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;user_preferences&#34;</span><span class="p">,</span> <span class="p">{})</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">preferences</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pref_name</span><span class="p">,</span> <span class="s2">&#34;Not set&#34;</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The <code>runtime</code> parameter is hidden from the model. For the example above, the model only sees <code>pref_name</code> in the tool schema.(上面说过了,结合例子更好理解)</p>
<h3 id="update-state">Update state</h3>
<p>Use <code>Command</code> to update the agent&rsquo;s state.
Useful to update custom state field.
Include a <code>ToolMessage</code> in the update so the model can see the result of this tool call</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">AgentState</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">ToolMessage</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="n">ToolRuntime</span><span class="p">,</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">types</span> <span class="n">import</span> <span class="n">Command</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">CustomState</span><span class="p">(</span><span class="n">AgentState</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_name</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">set_user_name</span><span class="p">(</span><span class="n">new_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">[</span><span class="n">None</span><span class="p">,</span> <span class="n">CustomState</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Command</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Set the user&#39;s name in the conversation state.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">Command</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">update</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;user_name&#34;</span><span class="p">:</span> <span class="n">new_name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="n">ToolMessage</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">content</span><span class="o">=</span><span class="n">f</span><span class="s2">&#34;User name set to {new_name}.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">tool_call_id</span><span class="o">=</span><span class="n">runtime</span><span class="o">.</span><span class="n">tool_call_id</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="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></td></tr></table>
</div>
</div><p>When tools update state variables, consider defining a <a href="https://docs.langchain.com/oss/python/langgraph/graph-api#reducers">reducer</a> for those fields. Since LLMs can call multiple tools in parallel, a reducer determines how to resolve conflicts when the same state field is updated by concurrent tool calls.
(创建reducer来应对并发修改同一个state值)</p>
<h2 id="context">Context</h2>
<p>Provides immutable configuration at invocation time
Including user IDs,session details,application-specific settings</p>
<p>Access context through <code>runtime.context</code>.
Pass it alongside a <code>thread_id</code> so the conversation is persisted across turns.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">dataclasses</span> <span class="n">import</span> <span class="n">dataclass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span><span class="p">,</span> <span class="n">ToolRuntime</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain_core</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">uuid</span> <span class="n">import</span> <span class="n">uuid7</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain_openai</span> <span class="n">import</span> <span class="n">ChatOpenAI</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">USER_DATABASE</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;user123&#34;</span><span class="p">:</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;Alice Johnson&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;account_type&#34;</span><span class="p">:</span> <span class="s2">&#34;Premium&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;balance&#34;</span><span class="p">:</span> <span class="mi">5000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;alice@example.com&#34;</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="s2">&#34;user456&#34;</span><span class="p">:</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;Bob Smith&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;account_type&#34;</span><span class="p">:</span> <span class="s2">&#34;Standard&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;balance&#34;</span><span class="p">:</span> <span class="mi">1200</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="s2">&#34;bob@example.com&#34;</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="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">dataclass</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">UserContext</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_account_info</span><span class="p">(</span><span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">[</span><span class="n">UserContext</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get the current user&#39;s account information.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_id</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">context</span><span class="o">.</span><span class="n">user_id</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">user_id</span> <span class="ow">in</span> <span class="n">USER_DATABASE</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">user</span> <span class="o">=</span> <span class="n">USER_DATABASE</span><span class="p">[</span><span class="n">user_id</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">f</span><span class="s2">&#34;Account holder: {user[&#39;name&#39;]}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="n">f</span><span class="s2">&#34;Type: {user[&#39;account_type&#39;]}</span><span class="se">\n</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="n">f</span><span class="s2">&#34;Balance: ${user[&#39;balance&#39;]}&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;User not found&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">(</span><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="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">model</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_account_info</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">context_schema</span><span class="o">=</span><span class="n">UserContext</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">system_prompt</span><span class="o">=</span><span class="s2">&#34;You are a financial assistant.&#34;</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></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="s2">&#34;messages&#34;</span><span class="p">:</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 my current balance?&#34;</span><span class="p">}]},</span>
</span></span><span class="line"><span class="cl">    <span class="n">config</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;configurable&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;thread_id&#34;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid7</span><span class="p">())}},</span>
</span></span><span class="line"><span class="cl">    <span class="n">context</span><span class="o">=</span><span class="n">UserContext</span><span class="p">(</span><span class="n">user_id</span><span class="o">=</span><span class="s2">&#34;user123&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="long-term-memorystore">Long-term memory(Store)</h2>
<p>The <a href="https://reference.langchain.com/python/langchain-core/stores/BaseStore"><code>BaseStore</code></a> provides persistent storage that survives across conversations.
Access store through <code>runtime.store</code>. The store uses a namespace/key pattern to organize data</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">store</span><span class="o">.</span><span class="n">memory</span> <span class="n">import</span> <span class="n">InMemoryStore</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span><span class="p">,</span> <span class="n">ToolRuntime</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain_openai</span> <span class="n">import</span> <span class="n">ChatOpenAI</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Access memory</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_user_info</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Look up user info.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">store</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">store</span>
</span></span><span class="line"><span class="cl">    <span class="n">user_info</span> <span class="o">=</span> <span class="n">store</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="s2">&#34;users&#34;</span><span class="p">,),</span> <span class="n">user_id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">user_info</span><span class="o">.</span><span class="n">value</span><span class="p">)</span> <span class="k">if</span> <span class="n">user_info</span> <span class="k">else</span> <span class="s2">&#34;Unknown user&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Update memory</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">save_user_info</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">age</span><span class="p">:</span> <span class="ne">int</span><span class="p">,</span> <span class="n">email</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Save user info.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">store</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">store</span>
</span></span><span class="line"><span class="cl">    <span class="n">store</span><span class="o">.</span><span class="n">put</span><span class="p">((</span><span class="s2">&#34;users&#34;</span><span class="p">,),</span> <span class="n">user_id</span><span class="p">,</span> <span class="p">{</span><span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="s2">&#34;age&#34;</span><span class="p">:</span> <span class="n">age</span><span class="p">,</span> <span class="s2">&#34;email&#34;</span><span class="p">:</span> <span class="n">email</span><span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;Successfully saved user info.&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">(</span><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></span><span class="line"><span class="cl"><span class="n">store</span> <span class="o">=</span> <span class="n">InMemoryStore</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">model</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_user_info</span><span class="p">,</span> <span class="n">save_user_info</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">store</span><span class="o">=</span><span class="n">store</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="c1"># First session: save user info</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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;Save the following user: userid: abc123, name: Foo, age: 25, email: foo@langchain.dev&#34;</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></span><span class="line"><span class="cl"><span class="c1"># Second session: get user info</span>
</span></span><span class="line"><span class="cl"><span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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;Get user info for user with id &#39;abc123&#39;&#34;</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="c1"># Here is the user info for user with ID &#34;abc123&#34;:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - Name: Foo</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - Age: 25</span>
</span></span><span class="line"><span class="cl"><span class="c1"># - Email: foo@langchain.dev</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="streaming-writer">Streaming writer</h2>
<p>Stream real-time updates from tools during execution.
Useful for providing progress feedback
Use <code>runtime.stream_Writer</code> to emit custom updates</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span><span class="p">,</span> <span class="n">ToolRuntime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get weather for a given city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">stream_writer</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># Stream custom updates as the tool executes</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Looking up data for city: {city}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">writer</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Acquired data for city: {city}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;It&#39;s always sunny in {city}!&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="execution-info">Execution info</h2>
<p>Access thread ID,run ID,and retry state from within a tool via <code>runtime.execution_info</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span><span class="p">,</span> <span class="n">ToolRuntime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">log_execution_context</span><span class="p">(</span><span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Log execution identity information.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">info</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">execution_info</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Thread: {info.thread_id}, Run: {info.run_id}&#34;</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">f</span><span class="s2">&#34;Attempt: {info.node_attempt}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;done&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="server-info">Server info</h2>
<p>When your tool runs on LangGraph Server , access assistant ID,graph ID,and authenticated user via <code>runtime.server_info</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span><span class="p">,</span> <span class="n">ToolRuntime</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_assistant_scoped_data</span><span class="p">(</span><span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Fetch data scoped to the current assistant.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">server</span> <span class="o">=</span> <span class="n">runtime</span><span class="o">.</span><span class="n">server_info</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">server</span> <span class="n">is</span> <span class="ow">not</span> <span class="n">None</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">f</span><span class="s2">&#34;Assistant: {server.assistant_id}, Graph: {server.graph_id}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">user</span> <span class="n">is</span> <span class="ow">not</span> <span class="n">None</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">f</span><span class="s2">&#34;User: {server.user.identity}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;done&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>server_info</code> is <code>None</code> when the tool is not running on LangGraph Server</p>
<h1 id="tool-execution">Tool execution</h1>
<p>Tool: used by agent
Tool error handing is configured by middleware</p>
<h2 id="tool-return-values">Tool return values</h2>
<p>a <code>string</code> for human-readable results;an <code>object</code> for structured results;a <code>Command</code> with optional message when you need to update the state</p>
<h3 id="return-a-string">Return a string</h3>
<p>when tool should provide plain text for the model to read and use in its next response</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get weather for a city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;It is currently sunny in {city}.&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The return value is converted to a <code>ToolMessage</code></p>
<h3 id="return-an-object">Return an object</h3>
<p>when your tool produces structured data that the model should inspect</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">get_weather_data</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Get structured weather data for a city.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;city&#34;</span><span class="p">:</span> <span class="n">city</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;temperature_c&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;conditions&#34;</span><span class="p">:</span> <span class="s2">&#34;sunny&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>The object is serialized and sent back as tool output.</li>
<li>The model can read specific fields and reason over them.</li>
<li>Like string returns, this does not directly update graph state.</li>
</ul>
<h3 id="return-multimodal-content">Return multimodal content</h3>
<p>For multimodal content ,use <strong>standard content blocks</strong> so the model receives multimodal resources</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">capture_screenshot</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">list</span><span class="p">[</span><span class="n">dict</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Capture a screenshot of the current page.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="s2">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Screenshot of the current page:&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;image&#34;</span><span class="p">,</span> <span class="s2">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;https://example.com/page.png&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>The return value is converted to a <code>ToolMessage</code> with multimodal <code>content</code>.</li>
<li>Use <code>message.content_blocks</code> to read the normalized block list after the tool runs.</li>
<li>The model must support the modalities you return. Check your <a href="https://docs.langchain.com/oss/python/integrations/chat">model’s capabilities</a> before returning images, audio, or video.</li>
</ul>
<h3 id="return-a-command">Return a Command</h3>
<p>when the tool need to update graph state(or example, setting user preferences or app state)</p>
<p>When the <code>Command</code> targets the current graph, include a <code>ToolMessage</code> in the update whose tool call ID matches the current tool call. Every tool call in the message history must have a corresponding <code>ToolMessage</code>.
返回的一个Command的Command.update中必须包含一个对应的ToolMessage.对应是指tool_call_id对应</p>
<p>Use <code>runtime.tool_call_id</code> for the <code>tool_call_id</code> parameter. <code>ToolNode</code> enforces this requirement: if the update has no <code>ToolMessage</code> matching the tool call, it raises a <code>ValueError</code>.
否则会返回一个ValueError</p>
<h3 id="return-directly-from-a-tool">Return directly from a tool</h3>
<p>设置return_direct来使得agent-loop短路,这样工具输出不会传回给模型而是直接传给caller</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain_openai</span> <span class="n">import</span> <span class="n">ChatOpenAI</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span><span class="p">(</span><span class="n">return_direct</span><span class="o">=</span><span class="n">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch_order_status</span><span class="p">(</span><span class="n">order_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Fetch the current status of a customer order.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># In production, query your order management system here</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;Order {order_id} is shipped and will arrive in 2 days.&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">ChatOpenAI</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="s2">&#34;gpt-4o-mini&#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="p">[</span><span class="n">fetch_order_status</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></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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 is the status of order #12345?&#34;</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="c1"># The agent returns the tool output directly without another LLM call:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &#34;Order 12345 is shipped and will arrive in 2 days.&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Behavior:</p>
<ul>
<li>The tool executes normally and its output is wrapped in a <code>ToolMessage</code>.</li>
<li>The agent stops looping and returns the tool’s output as the final response, bypassing any additional model call.</li>
<li><strong>Multiple parallel tool calls:</strong> When the model calls several tools in one step, all of them execute first. After all tools finish, the agent routes to <code>END</code> only if <strong>every</strong> tool in that batch has <code>return_direct=True</code>. The final response includes the <code>ToolMessage</code> outputs of every tool that was called in that step.</li>
</ul>
<p>Use this when:</p>
<ul>
<li>The tool’s output is the complete, user-ready answer (for example, a lookup that returns a ready-to-display result).</li>
<li>You want to avoid an extra model call when no additional reasoning is needed.</li>
<li>You need deterministic, unmodified output: the model cannot rephrase, summarize, or act on the tool result.</li>
</ul>
<h3 id="return-a-command-with-return_direct">Return a Command with return_direct</h3>
<p>A tool with <code>return_direct=True</code> can also return a <a href="https://reference.langchain.com/python/langgraph/types/Command"><code>Command</code></a> to update graph state before the agent exits. Unlike a plain return value, a <code>Command</code> is not automatically converted into a <code>ToolMessage</code>. When the <code>Command</code> targets the current graph (<code>graph</code> is not set or is <code>None</code>), include a <code>ToolMessage</code> in <code>Command.update</code> matching the tool call’s <code>tool_call_id</code>. Omitting it causes <code>ToolNode</code> to raise a <code>ValueError</code>, because every <code>AIMessage</code> tool call must have a corresponding <code>ToolMessage</code> in the message history.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">ToolMessage</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="n">ToolRuntime</span><span class="p">,</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langgraph</span><span class="o">.</span><span class="n">types</span> <span class="n">import</span> <span class="n">Command</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span><span class="p">(</span><span class="n">return_direct</span><span class="o">=</span><span class="n">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch_and_store_order</span><span class="p">(</span><span class="n">order_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">runtime</span><span class="p">:</span> <span class="n">ToolRuntime</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Command</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Fetch order status and store it in state.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">status</span> <span class="o">=</span> <span class="n">f</span><span class="s2">&#34;Order {order_id} is shipped and will arrive in 2 days.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">Command</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">update</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;last_order_status&#34;</span><span class="p">:</span> <span class="n">status</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># Must include a ToolMessage so the message history stays valid</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;messages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="n">ToolMessage</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                    <span class="n">content</span><span class="o">=</span><span class="n">status</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">tool_call_id</span><span class="o">=</span><span class="n">runtime</span><span class="o">.</span><span class="n">tool_call_id</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="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></td></tr></table>
</div>
</div><h2 id="error-handing">Error handing</h2>
<p>Using LangChain middleware to retry failed tool calls or return custom error message</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">collections</span><span class="o">.</span><span class="n">abc</span> <span class="n">import</span> <span class="n">Callable</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">wrap_tool_call</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">messages</span> <span class="n">import</span> <span class="n">ToolMessage</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span><span class="o">.</span><span class="n">tool_node</span> <span class="n">import</span> <span class="n">ToolCallRequest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">wrap_tool_call</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">handle_tool_errors</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">request</span><span class="p">:</span> <span class="n">ToolCallRequest</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">handler</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">ToolCallRequest</span><span class="p">],</span> <span class="n">ToolMessage</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ToolMessage</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Convert tool exceptions into ToolMessages the model can handle.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">except</span> <span class="n">Exception</span> <span class="n">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">ToolMessage</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">content</span><span class="o">=</span><span class="n">f</span><span class="s2">&#34;Tool error: Please check your input and try again. ({e})&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">tool_call_id</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">tool_call</span><span class="p">[</span><span class="s2">&#34;id&#34;</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></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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;openai:gpt-5.5&#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="p">[],</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span><span class="n">handle_tool_errors</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="state-injection">State injection</h2>
<p>Tool access graph state through <code>ToolRUntime</code></p>
<h1 id="dynamic-tool-section">Dynamic tool section</h1>
<p>太多tool会占用过多的context,太少则会限制能力
动态工具允许在runtime时修改
主要有两种方式实现,取决于工具是否事先已知</p>
<h3 id="filtering-pre-registered-tools">Filtering pre-registered tools</h3>
<p>When all tools are known at agent creation time,you can pre-register them and dynamically filter which ones are exposed to the model based on state,permissions,or context</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">  代码有三个,自己去官网看
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>All possible tools are known at compile/startup time</li>
<li>You want to filter based on permissions, feature flags, or conversation state</li>
<li>Tools are static but their availability is dynamic</li>
</ul>
<h3 id="runtime-tool-register">Runtime tool register</h3>
<p>when tools are not discovered or created at runtime</p>
<ol>
<li><code>wrap_model_call</code> - Add the dynamic tools to the request</li>
<li><code>wrap_tool_call</code> - Handle execution of the dynamically added tools</li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">tools</span> <span class="n">import</span> <span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span><span class="o">.</span><span class="n">middleware</span> <span class="n">import</span> <span class="n">AgentMiddleware</span><span class="p">,</span> <span class="n">ModelRequest</span><span class="p">,</span> <span class="n">ToolCallRequest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># A tool that will be added dynamically at runtime</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">calculate_tip</span><span class="p">(</span><span class="n">bill_amount</span><span class="p">:</span> <span class="ne">float</span><span class="p">,</span> <span class="n">tip_percentage</span><span class="p">:</span> <span class="ne">float</span> <span class="o">=</span> <span class="mf">20.0</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Calculate the tip amount for a bill.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">tip</span> <span class="o">=</span> <span class="n">bill_amount</span> <span class="o">*</span> <span class="p">(</span><span class="n">tip_percentage</span> <span class="o">/</span> <span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">f</span><span class="s2">&#34;Tip: ${tip:.2f}, Total: ${bill_amount + tip:.2f}&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">DynamicToolMiddleware</span><span class="p">(</span><span class="n">AgentMiddleware</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Middleware that registers and handles dynamic tools.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">wrap_model_call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span> <span class="n">ModelRequest</span><span class="p">,</span> <span class="n">handler</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Add dynamic tool to the request</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># This could be loaded from an MCP server, database, etc.</span>
</span></span><span class="line"><span class="cl">        <span class="n">updated</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">override</span><span class="p">(</span><span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="o">*</span><span class="n">request</span><span class="o">.</span><span class="n">tools</span><span class="p">,</span> <span class="n">calculate_tip</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">updated</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">wrap_tool_call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span> <span class="n">ToolCallRequest</span><span class="p">,</span> <span class="n">handler</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Handle execution of the dynamic tool</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">tool_call</span><span class="p">[</span><span class="s2">&#34;name&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;calculate_tip&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">override</span><span class="p">(</span><span class="k">tool</span><span class="o">=</span><span class="n">calculate_tip</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">handler</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</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="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_weather</span><span class="p">],</span>  <span class="c1"># Only static tools registered here</span>
</span></span><span class="line"><span class="cl">    <span class="n">middleware</span><span class="o">=</span><span class="p">[</span><span class="n">DynamicToolMiddleware</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></span><span class="line"><span class="cl"><span class="c1"># The agent can now use both get_weather AND calculate_tip</span>
</span></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">agent</span><span class="o">.</span><span class="n">invoke</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;messages&#34;</span><span class="p">:</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;Calculate a 20% tip on $85&#34;</span><span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This approach is best when:</p>
<ul>
<li>Tools are discovered at runtime (e.g., from an MCP server)</li>
<li>Tools are generated dynamically based on user data or configuration</li>
<li>You’re integrating with external tool registries</li>
</ul>
<h1 id="headless-tools">Headless tools</h1>
<p>某些工具应该运行在<strong>用户应用运行的地方</strong>（通常是浏览器），而不是在进程内部。<strong>无头工具 (Headless tools)<strong>是工具定义（包括名称、描述和参数 schema），您在</strong>服务端</strong>向智能体进行注册。而<strong>实现</strong>仅在<strong>客户端</strong>注册，并在简短的中断/恢复（interrupt/resume）握手后执行</p>
<h2 id="when-to-use">when to use</h2>
<p>when the work depends on the <strong>environment, device, or UI</strong> that only exists on the client. For example:</p>
<ul>
<li>Browser APIs</li>
<li>Privacy and locality</li>
<li>Latency(延迟)</li>
<li>Structured,safe effects</li>
</ul>
<h2 id="how-it-work">How it work</h2>
<p>model can see it and call it but it actually happens outside the process</p>
<ol>
<li>Define with (name, description,parameter) without in-process implementation</li>
<li>Register it with create agent so the model can call it normally</li>
<li>Handle the interrupt payload when the tool is invoked. Instead of running locally, the graph pauses with a payload shaped like <code>{&quot;type&quot;: &quot;tool&quot;, &quot;tool_call&quot;: {&quot;id&quot;, &quot;name&quot;, &quot;args&quot;}}</code>.</li>
<li>Resume the graph</li>
</ol>
<p>Use the optional <strong><code>onTool</code></strong> callback to observe lifecycle events (<code>start</code>, <code>success</code>, <code>error</code>) for UI feedback such as spinners or toasts.</p>
<h1 id="prebuilt-tools">Prebuilt tools</h1>
<p>LangChain provides a large collection of prebuilt tools and toolkits for common tasks like web search, code interpretation, database access, and more. These ready-to-use tools can be directly integrated into your agents without writing custom code.See the <a href="https://docs.langchain.com/oss/python/integrations/tools">tools and toolkits</a> integration page for a complete list of available tools organized by category.</p>
<h1 id="tools-from-mcp">Tools from MCP</h1>
<p><a href="https://modelcontextprotocol.io/">Model Context Protocol (MCP)</a> is an open protocol that standardizes how applications expose tools to language models. Rather than hand-authoring a tool, you connect to an MCP server and adapt the tools it advertises into LangChain tools, ready to pass to an agent like any other tool.<a href="https://reference.langchain.com/python/langchain/mcp/adapter/MCPAdapter"><code>MCPAdapter</code></a> discovers a server’s tools and converts them into LangChain tools. Open the adapter, call <code>list_tools()</code>, and hand the result to <a href="https://reference.langchain.com/python/langchain/agents/factory/create_agent"><code>create_agent</code></a>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">agents</span> <span class="n">import</span> <span class="n">create_agent</span>
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="n">langchain</span><span class="o">.</span><span class="n">mcp</span> <span class="n">import</span> <span class="n">MCPAdapter</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">async</span> <span class="n">with</span> <span class="n">MCPAdapter</span><span class="p">(</span><span class="s2">&#34;https://example.com/mcp&#34;</span><span class="p">)</span> <span class="n">as</span> <span class="n">adapter</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">await</span> <span class="n">adapter</span><span class="o">.</span><span class="n">list_tools</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">agent</span> <span class="o">=</span> <span class="n">create_agent</span><span class="p">(</span><span class="s2">&#34;claude-sonnet-4-6&#34;</span><span class="p">,</span> <span class="n">tools</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="server-side-tool-use">Server-side tool use</h1>
<p>Some chat models feature built-in tools that are executed server-side by the model provider. These include capabilities like web search and code interpreters that don’t require you to define or host the tool logic.Refer to the individual <a href="https://docs.langchain.com/oss/python/integrations/providers">chat model integration pages</a> and the <a href="https://docs.langchain.com/oss/python/langchain/models#server-side-tool-use">tool calling documentation</a> for details on enabling and using these built-in tools.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
