<?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 Advanced Usage on On My Way</title>
    <link>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/</link>
    <description>Recent content in LangChain Advanced Usage on On My Way</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <atom:link href="https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Context Engineering</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/context-engineering/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/context-engineering/</guid>
      <description>Context Engineering相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<h1 id="overview">Overview</h1>
<p>构建agent的难点在于使他们足够可靠
即时他们在原型阶段往往会表现得很好</p>
<h2 id="why-do-agent-fails">Why do agent fails</h2>
<p>LLM调用采取了错误的措施或者没有按照预期执行,原因:</p>
<ol>
<li>LLM能力不够</li>
<li>正确的context没有传递给LLM</li>
</ol>
<p>更多情况是后者</p>
<h2 id="the-agent-loop">The agent loop</h2>
<p>two main step2:</p>
<ol>
<li>Model call: calls the LLM with a prompt and available tools, returns either a  response or a request to execute tools</li>
<li>Tool execution: execute the tools that LLM requested,returns tool results</li>
</ol>
<p><img alt="Core agent loop diagram" loading="lazy" src="https://mintcdn.com/langchain-5e9cc07a/Tazq8zGc0yYUYrDl/oss/images/core_agent_loop.png?fit=max&auto=format&n=Tazq8zGc0yYUYrDl&q=85&s=ac72e48317a9ced68fd1be64e89ec063"></p>
<p>What can you control:</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Context Type</th>
					<th style="text-align: left">What You Control</th>
					<th style="text-align: left">Transient or Persistent</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><strong><a href="https://docs.langchain.com/oss/python/langchain/context-engineering#model-context">Model Context</a></strong></td>
					<td style="text-align: left">What goes into model calls (instructions, message history, tools, response format)</td>
					<td style="text-align: left">Transient</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><a href="https://docs.langchain.com/oss/python/langchain/context-engineering#tool-context">Tool Context</a></strong></td>
					<td style="text-align: left">What tools can access and produce (reads/writes to state, store, runtime context)</td>
					<td style="text-align: left">Persistent</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><a href="https://docs.langchain.com/oss/python/langchain/context-engineering#life-cycle-context">Life-cycle Context</a></strong></td>
					<td style="text-align: left">What happens between model and tool calls (summarization, guardrails, logging, etc.)</td>
					<td style="text-align: left">Persistent</td>
			</tr>
	</tbody>
</table>
<h2 id="data-sources">Data sources</h2>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Data Source</th>
					<th style="text-align: left">Also Known As</th>
					<th style="text-align: left">Scope</th>
					<th style="text-align: left">Examples</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><strong>Runtime Context</strong></td>
					<td style="text-align: left">Static configuration</td>
					<td style="text-align: left">Conversation-scoped</td>
					<td style="text-align: left">User ID, API keys, database connections, permissions, environment settings</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>State</strong></td>
					<td style="text-align: left">Short-term memory</td>
					<td style="text-align: left">Conversation-scoped</td>
					<td style="text-align: left">Current messages, uploaded files, authentication status, tool results</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Store</strong></td>
					<td style="text-align: left">Long-term memory</td>
					<td style="text-align: left">Cross-conversation</td>
					<td style="text-align: left">User preferences, extracted insights, memories, historical data</td>
			</tr>
	</tbody>
</table>
<h2 id="how-it-works">How it works</h2>
<p>Using middleware:</p>
<ul>
<li>update context</li>
<li>Jump to a different step in the agent lifecycle</li>
</ul>
<h1 id="model-context">Model context</h1>
<p>Instructions,available tools,which model to use,output format.</p>
<ul>
<li>System prompt</li>
<li>Messages:conversation history</li>
<li>Tools</li>
<li>Model</li>
<li>Response format</li>
</ul>
<h2 id="system-prompt">System prompt</h2>
<p>Successful agents draw on memories, preferences, and configuration to provide the right instructions for the current state of the conversation.</p>
<ul>
<li>Access message count or conversation context from state</li>
<li>Access user preferences from long-term memory</li>
<li>Access user ID or configuration from Runtime Context</li>
</ul>
<h2 id="message">Message</h2>
<p>Make up the prompt that is sent to the LLM</p>
<p>分为state,store,Runtime context</p>
<h2 id="tools">Tools</h2>
<h3 id="defining-tools">Defining tools</h3>
<p>name,description(docstring),argument name, argument description</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-py" data-lang="py"><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 class="p">(</span><span class="n">parse_docstring</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">search_orders</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">status</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">limit</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">10</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;Search for user orders by status.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    Use this when the user asks about order history or wants to check
</span></span></span><span class="line"><span class="cl"><span class="s2">    order status. Always filter by the provided status.
</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">        user_id: Unique identifier for the user
</span></span></span><span class="line"><span class="cl"><span class="s2">        status: Order status: &#39;pending&#39;, &#39;shipped&#39;, or &#39;delivered&#39;
</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="c1"># Implementation here</span>
</span></span><span class="line"><span class="cl">    <span class="k">pass</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="selecting-tools">Selecting tools</h3>
<p>从分为从三个数据源来组织上下文</p>
<h2 id="model">Model</h2>
<p>根据三种数据源中的各种数据来选择合适的模型</p>
<h2 id="response-format">Response format</h2>
<h3 id="defining-formats">defining formats</h3>
<p>Schema definitions guide the model. Field names, types, and descriptions specify exactly what format the output should adhere to.</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 pydantic import BaseModel, Field
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">class CustomerSupportTicket(BaseModel):
</span></span><span class="line"><span class="cl">    &#34;&#34;&#34;Structured ticket information extracted from customer message.&#34;&#34;&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    category: str = Field(
</span></span><span class="line"><span class="cl">        description=&#34;Issue category: &#39;billing&#39;, &#39;technical&#39;, &#39;account&#39;, or &#39;product&#39;&#34;
</span></span><span class="line"><span class="cl">    )
</span></span><span class="line"><span class="cl">    priority: str = Field(
</span></span><span class="line"><span class="cl">        description=&#34;Urgency level: &#39;low&#39;, &#39;medium&#39;, &#39;high&#39;, or &#39;critical&#39;&#34;
</span></span><span class="line"><span class="cl">    )
</span></span><span class="line"><span class="cl">    summary: str = Field(
</span></span><span class="line"><span class="cl">        description=&#34;One-sentence summary of the customer&#39;s issue&#34;
</span></span><span class="line"><span class="cl">    )
</span></span><span class="line"><span class="cl">    customer_sentiment: str = Field(
</span></span><span class="line"><span class="cl">        description=&#34;Customer&#39;s emotional tone: &#39;frustrated&#39;, &#39;neutral&#39;, or &#39;satisfied&#39;&#34;
</span></span><span class="line"><span class="cl">    )
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="selecting-format">selecting format</h3>
<h1 id="tool-context">Tool context</h1>
<p>Both read and write context</p>
<h2 id="reads">Reads</h2>
<p>大多数的工具不只是需要LLM传入的参数,需要从其他的数据源获得,主要是state,store,Runtime context</p>
<h2 id="writes">Writes</h2>
<p>update the memory</p>
<ul>
<li>Write to State to track session-specific information using Command:</li>
<li>Write to Store to persist data across sessions:</li>
</ul>
<h1 id="life-cycle-context">Life-cycle context</h1>
<p>控制核心agent步骤之间发生的情况:拦截数据流以实现总结,安全护栏,日志记录等横切关注点</p>
<p>使用middleware:</p>
<ul>
<li>update context:修改state和存储以持久化更改,更新对话历史或者保存insights</li>
<li>Jump in the lifecycle:根据上下文移动到Agent loop中的不同步骤(例如如果满足条件就跳过工具执行,或使用修改后的上下文重复model call)</li>
</ul>
<h2 id="example-summarization">Example: Summarization</h2>
<p>automatically condensing conversation history</p>
<p>LangChain offers built-in middleware for this:</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-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">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;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="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>When the conversation exceeds the token limit, <code>SummarizationMiddleware</code> automatically:</p>
<ol>
<li>Summarizes older messages using a separate LLM call</li>
<li>Replaces them with a summary message in State (permanently)</li>
<li>Keeps recent messages intact for context</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Guardrails</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/guardrails/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/guardrails/</guid>
      <description>Guardrails相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>GuardRails通过validating和flitering content来帮助你构建安全合规的agent</p>
<p>常见的应用场景:</p>
<ul>
<li>预防个人信息的泄露</li>
<li>检测和阻止提示词注入攻击</li>
<li>阻止不恰当和有害的攻击</li>
<li>执行业务规则和合规性要求</li>
<li>验证输出重量和正确性</li>
</ul>
<p>你可以在使用middleware在关键节点拦截执行
before the agent starts, after it completes, or around model and tool calls.</p>
<p>两种互补的办法实现 Guardrails:
1.Deterministic guardrails:
使用规则的逻辑比如正则表达式,关键词匹配或者显式检查
优点:快且省 缺点:可能漏掉细微的违规情况</p>
<p>2.Model-based guradrails
使用LLM或者classifiers进行语义分析
优点:效果好 缺点:延迟高,成本更高</p>
<h1 id="built-in-guardrail">Built-in guardrail</h1>
<h2 id="pii-detection">PII detection</h2>
<p>可以检测emails,credit cards,IP addresses和其他的PII
提供了几种解决PII检测的策略:</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Strategy</th>
					<th style="text-align: left">Description</th>
					<th style="text-align: left">Example</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><code>redact</code></td>
					<td style="text-align: left">Replace with <code>[REDACTED_{PII_TYPE}]</code></td>
					<td style="text-align: left"><code>[REDACTED_EMAIL]</code></td>
			</tr>
			<tr>
					<td style="text-align: left"><code>mask</code></td>
					<td style="text-align: left">Partially obscure (e.g., last 4 digits)</td>
					<td style="text-align: left"><code>****-****-****-1234</code></td>
			</tr>
			<tr>
					<td style="text-align: left"><code>hash</code></td>
					<td style="text-align: left">Replace with deterministic hash</td>
					<td style="text-align: left"><code>a8f5f167...</code></td>
			</tr>
			<tr>
					<td style="text-align: left"><code>block</code></td>
					<td style="text-align: left">Raise exception when detected</td>
					<td style="text-align: left">Error thrown</td>
			</tr>
	</tbody>
</table>
<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-py" data-lang="py"><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.middleware</span> <span class="kn">import</span> <span class="n">PIIMiddleware</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 class="n">customer_service_tool</span><span class="p">,</span> <span class="n">email_tool</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="c1"># Redact emails in user input before sending to model</span>
</span></span><span class="line"><span class="cl">        <span class="n">PIIMiddleware</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></span><span class="line"><span class="cl">            <span class="n">strategy</span><span class="o">=</span><span class="s2">&#34;redact&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">apply_to_input</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="c1"># Mask credit cards in user input</span>
</span></span><span class="line"><span class="cl">        <span class="n">PIIMiddleware</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;credit_card&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">strategy</span><span class="o">=</span><span class="s2">&#34;mask&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">apply_to_input</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="c1"># Block API keys - raise error if detected</span>
</span></span><span class="line"><span class="cl">        <span class="n">PIIMiddleware</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;api_key&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">detector</span><span class="o">=</span><span class="sa">r</span><span class="s2">&#34;sk-[a-zA-Z0-9]</span><span class="si">{32}</span><span class="s2">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">strategy</span><span class="o">=</span><span class="s2">&#34;block&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">apply_to_input</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><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"># When user provides PII, it will be handled according to the strategy</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;My email is john.doe@example.com and card is 5105-1051-0510-5100&#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="human-in-the-loop">Human-in-the-loop</h2>
<p>执行敏感操作之前征求人工的approval</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><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.middleware</span> <span class="kn">import</span> <span class="n">HumanInTheLoopMiddleware</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 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></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">search_tool</span><span class="p">,</span> <span class="n">send_email_tool</span><span class="p">,</span> <span class="n">delete_database_tool</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></span><span class="line"><span class="cl">            <span class="n">interrupt_on</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># Require approval for sensitive operations</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;send_email&#34;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;delete_database&#34;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># Auto-approve safe operations</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;search&#34;</span><span class="p">:</span> <span class="kc">False</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="c1"># Persist the state across interrupts</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"># Human-in-the-loop requires a thread ID for persistence</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></span><span class="line"><span class="cl"><span class="c1"># Agent will pause and wait for approval before executing sensitive tools</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;Send an email to the team&#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="n">config</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="n">Command</span><span class="p">(</span><span class="n">resume</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;decisions&#34;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;approve&#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="n">config</span>  <span class="c1"># Same thread ID to resume the paused conversation</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="custom-guardrail">Custom guardrail</h1>
<p>对于更加复杂的需求,可以自定义在agent执行之前和之后的middleware</p>
<h2 id="before-agent-guardrail">Before agent guardrail</h2>
<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></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">Any</span>
</span></span><span class="line"><span class="cl">
</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">AgentMiddleware</span><span class="p">,</span> <span class="n">AgentState</span><span class="p">,</span> <span class="n">hook_config</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.runtime</span> <span class="kn">import</span> <span class="n">Runtime</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">ContentFilterMiddleware</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;Deterministic guardrail: Block requests containing banned keywords.&#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="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">banned_keywords</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">banned_keywords</span> <span class="o">=</span> <span class="p">[</span><span class="n">kw</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">for</span> <span class="n">kw</span> <span class="ow">in</span> <span class="n">banned_keywords</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nd">@hook_config</span><span class="p">(</span><span class="n">can_jump_to</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;end&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">before_agent</span><span class="p">(</span><span class="bp">self</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="nb">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="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Get the first user message</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</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">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">state</span><span class="p">[</span><span class="s2">&#34;messages&#34;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">first_message</span><span class="o">.</span><span class="n">type</span> <span class="o">!=</span> <span class="s2">&#34;human&#34;</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">content</span> <span class="o">=</span> <span class="n">first_message</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1"># Check for banned keywords</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">banned_keywords</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">content</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="c1"># Block execution before any processing</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="s2">&#34;role&#34;</span><span class="p">:</span> <span class="s2">&#34;assistant&#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="s2">&#34;I cannot process requests containing inappropriate content. Please rephrase your request.&#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;jump_to&#34;</span><span class="p">:</span> <span class="s2">&#34;end&#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="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="c1"># Use the custom guardrail</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></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">search_tool</span><span class="p">,</span> <span class="n">calculator_tool</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">ContentFilterMiddleware</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">banned_keywords</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;hack&#34;</span><span class="p">,</span> <span class="s2">&#34;exploit&#34;</span><span class="p">,</span> <span class="s2">&#34;malware&#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 class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># This request will be blocked before any processing</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;How do I hack into a database?&#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>Use &ldquo;before agent&rdquo; hook 来验证
适用于会话级别的检查(例如身份验证,速率限制,拦截不安全的请求)</p>
<h2 id="after-agent-guardrail">After agent guardrail</h2>
<p>使用&quot;after agent&quot; hooks来验证输出
使用于居于模型的安全检查,质量验证和最终合规性扫描</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><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 class="p">,</span> <span class="n">AgentState</span><span class="p">,</span> <span class="n">hook_config</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.runtime</span> <span class="kn">import</span> <span class="n">Runtime</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">AIMessage</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.chat_models</span> <span class="kn">import</span> <span class="n">init_chat_model</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">Any</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">SafetyGuardrailMiddleware</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;Model-based guardrail: Use an LLM to evaluate response safety.&#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="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">safety_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="nd">@hook_config</span><span class="p">(</span><span class="n">can_jump_to</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;end&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">after_agent</span><span class="p">(</span><span class="bp">self</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="nb">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="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Get the final AI response</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</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">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">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="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">last_message</span><span class="p">,</span> <span class="n">AIMessage</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="c1"># Use a model to evaluate safety</span>
</span></span><span class="line"><span class="cl">        <span class="n">safety_prompt</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;&#34;&#34;Evaluate if this response is safe and appropriate.
</span></span></span><span class="line"><span class="cl"><span class="s2">        Respond with only &#39;SAFE&#39; or &#39;UNSAFE&#39;.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">        Response: </span><span class="si">{</span><span class="n">last_message</span><span class="o">.</span><span class="n">content</span><span class="si">}</span><span class="s2">&#34;&#34;&#34;</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="bp">self</span><span class="o">.</span><span class="n">safety_model</span><span class="o">.</span><span class="n">invoke</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">safety_prompt</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="s2">&#34;UNSAFE&#34;</span> <span class="ow">in</span> <span class="n">result</span><span class="o">.</span><span class="n">content</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">content</span> <span class="o">=</span> <span class="s2">&#34;I cannot provide that response. Please rephrase your request.&#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="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Use the safety guardrail</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></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">search_tool</span><span class="p">,</span> <span class="n">calculator_tool</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">SafetyGuardrailMiddleware</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;How do I make explosives?&#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="combine-multiple-guardrails">Combine multiple guardrails</h2>
<p>你可以将多个安全护栏加入middleware数组来堆叠他们,他们将按顺序执行,并且允许你构建层级保护</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-py" data-lang="py"><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.middleware</span> <span class="kn">import</span> <span class="n">PIIMiddleware</span><span class="p">,</span> <span class="n">HumanInTheLoopMiddleware</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">search_tool</span><span class="p">,</span> <span class="n">send_email_tool</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="c1"># Layer 1: Deterministic input filter (before agent)</span>
</span></span><span class="line"><span class="cl">        <span class="n">ContentFilterMiddleware</span><span class="p">(</span><span class="n">banned_keywords</span><span class="o">=</span><span class="p">[</span><span class="s2">&#34;hack&#34;</span><span class="p">,</span> <span class="s2">&#34;exploit&#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"># Layer 2: PII protection (before and after model)</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_input</span><span class="o">=</span><span class="kc">True</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></span><span class="line"><span class="cl">        <span class="c1"># Layer 3: Human approval for sensitive tools</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;send_email&#34;</span><span class="p">:</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="c1"># Layer 4: Model-based safety check (after agent)</span>
</span></span><span class="line"><span class="cl">        <span class="n">SafetyGuardrailMiddleware</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>Human-in-the-loop</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/human-in-the-loop/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/human-in-the-loop/</guid>
      <description>Human-in-the-loop相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>By checking each tool call against a configurable policy
如果需要暂停,middleware将会issue an interrupt来暂停执行
图状态将会使用LangGraph的persistence layer来保存,因此可以pause and resume later</p>
<h1 id="interrupt-decision-types">Interrupt decision types</h1>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Decision Type</th>
					<th style="text-align: left">Description</th>
					<th style="text-align: left">Example Use Case</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">✅ <code>approve</code></td>
					<td style="text-align: left">Execute the tool with the original arguments as proposed by the agent.</td>
					<td style="text-align: left">Send an email draft exactly as written</td>
			</tr>
			<tr>
					<td style="text-align: left">✏️ <code>edit</code></td>
					<td style="text-align: left">Modify the tool arguments before execution.</td>
					<td style="text-align: left">Change the recipient before sending an email</td>
			</tr>
			<tr>
					<td style="text-align: left">❌ <code>reject</code></td>
					<td style="text-align: left">Skip executing this tool call entirely and return rejection feedback to the agent.</td>
					<td style="text-align: left">Deny file deletion and explain why</td>
			</tr>
			<tr>
					<td style="text-align: left">💬 <code>respond</code></td>
					<td style="text-align: left">Return the human’s message directly as a synthetic tool result, skipping execution, for “ask user” style tools.</td>
					<td style="text-align: left">Answer an <code>&quot;ask_user&quot;</code> prompt with a direct reply</td>
			</tr>
	</tbody>
</table>
<p>每个工具可用的决策类型取决于你在<code>interrupt_on</code>中配置的策略
使用场景:
Use <code>reject</code> when the human is denying the requested action. Use <code>respond</code> only when the human is acting as the tool, such as answering an <code>ask_user</code> prompt. Do not use <code>respond</code> to deny side-effecting tools, because its message is treated as a successful tool result.</p>
<h1 id="configurable-interrupt">Configurable interrupt</h1>
<p>要使用HITL,在<code>create_agent</code>时把中间件添加到agent的middleware列表
你可以使用tool actions到允许的决策类型的映射来配置他</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><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.middleware</span> <span class="kn">import</span> <span class="n">HumanInTheLoopMiddleware</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></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">write_file</span><span class="p">,</span> <span class="n">execute_sql</span><span class="p">,</span> <span class="n">read_data</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></span><span class="line"><span class="cl">            <span class="n">interrupt_on</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;write_file&#34;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>  <span class="c1"># All decisions (approve, edit, reject, respond) allowed</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;execute_sql&#34;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&#34;allowed_decisions&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;approve&#34;</span><span class="p">,</span> <span class="s2">&#34;reject&#34;</span><span class="p">]},</span>  <span class="c1"># No editing allowed</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;read_data&#34;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span> <span class="c1"># Safe operation, no approval needed</span>
</span></span><span class="line"><span class="cl">            <span class="p">},</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># Prefix for interrupt messages - combined with tool name and args to form the full message</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># e.g., &#34;Tool execution pending approval: execute_sql with query=&#39;DELETE FROM...&#39;&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># Individual tools can override this by specifying a &#34;description&#34; in their interrupt config</span>
</span></span><span class="line"><span class="cl">            <span class="n">description_prefix</span><span class="o">=</span><span class="s2">&#34;Tool execution pending approval&#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 class="c1"># Human-in-the-loop requires checkpointing to handle interrupts.</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># In production, use a persistent checkpointer like AsyncPostgresSaver or MongoDBSaver.</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><p>ps:你必须配置一个checkpointer来持久化graph state,
在生产环境中,使用持久性的checkpointerSaver,如<a href="https://reference.langchain.org.cn/python/langgraph/checkpoints/#langgraph.checkpoint.postgres.aio.AsyncPostgresSaver"><code>AsyncPostgresSaver</code></a> 或 <a href="https://pypi.ac.cn/project/langgraph-checkpoint-mongodb/"><code>MongoDBSaver</code></a>,对于测试和原型设计,使用<a href="https://reference.langchain.org.cn/python/langgraph/checkpoints/#langgraph.checkpoint.memory.InMemorySaver"><code>InMemorySaver</code></a>。</p>
<h1 id="conditional-interrupts">Conditional interrupts</h1>
<p>默认情况下,<code>interrupt_on</code>中列出的tools都会暂停以供审查,如果要仅暂停某些调用,在tool的<code>InterruptConfig</code>中添加<code>when</code>谓词,该谓词接受一个<code>ToolCallRequest</code>来返回True以中断或者False以自动批准</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><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.middleware</span> <span class="kn">import</span> <span class="n">HumanInTheLoopMiddleware</span><span class="p">,</span> <span class="n">ToolCallRequest</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></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">writes_outside_workspace</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="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Pause writes to paths outside the workspace directory.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">path</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;args&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;path&#34;</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="ow">not</span> <span class="n">path</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;/workspace/&#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">is_write_query</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="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Pause SQL that isn&#39;t a read-only SELECT.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">query</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;args&#34;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;query&#34;</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="ow">not</span> <span class="n">query</span><span class="o">.</span><span class="n">lstrip</span><span class="p">()</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;SELECT&#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">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">write_file</span><span class="p">,</span> <span class="n">execute_sql</span><span class="p">,</span> <span class="n">read_data</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></span><span class="line"><span class="cl">            <span class="n">interrupt_on</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;write_file&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="s2">&#34;allowed_decisions&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;approve&#34;</span><span class="p">,</span> <span class="s2">&#34;edit&#34;</span><span class="p">,</span> <span class="s2">&#34;reject&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                    <span class="s2">&#34;when&#34;</span><span class="p">:</span> <span class="n">writes_outside_workspace</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;execute_sql&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="s2">&#34;allowed_decisions&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;approve&#34;</span><span class="p">,</span> <span class="s2">&#34;reject&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                    <span class="s2">&#34;when&#34;</span><span class="p">:</span> <span class="n">is_write_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="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">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><p>评估为False的tool不会pause</p>
<h1 id="responding-to-interrupts">Responding to interrupts</h1>
<p>在<code>version=v2</code>中,结果时一个带有interrupts属性的<code>GraphOutput</code>,该属性包含需要审查的动作,你可以将这些动作提交给审查者,并在提供决策后恢复执行</p>
<h2 id="decision-types">Decision types</h2>
<p>同上</p>
<h2 id="multiple-types">Multiple types</h2>
<p>当出现多个actions时,根据中断触发的顺序为每个动作提供一个决策</p>
<h1 id="streaming-with-human-in-the-loop">Streaming with human-in-the-loop</h1>
<p>使用stream_event()在agent运行和中断时流式传输实时更新;
stream.message流式传输LLM令牌,使用stream.value检查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><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-fallback" data-lang="fallback"><span class="line"><span class="cl">from langgraph.types import Command
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config = {&#34;configurable&#34;: {&#34;thread_id&#34;: &#34;some_id&#34;}}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Stream agent progress and LLM tokens until interrupt
</span></span><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;Delete old records from the database&#34;}]},
</span></span><span class="line"><span class="cl">    config=config,
</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.text:
</span></span><span class="line"><span class="cl">        print(token, end=&#34;&#34;, flush=True)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Check whether the run paused for human input
</span></span><span class="line"><span class="cl">if stream.interrupted:
</span></span><span class="line"><span class="cl">    print(f&#34;\n\nInterrupt: {stream.interrupts}&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Resume with streaming after human decision
</span></span><span class="line"><span class="cl">stream = agent.stream_events(
</span></span><span class="line"><span class="cl">    Command(resume={&#34;decisions&#34;: [{&#34;type&#34;: &#34;approve&#34;}]}),
</span></span><span class="line"><span class="cl">    config=config,
</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.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><h1 id="execution-lifecycle">Execution lifecycle</h1>
<p>middleware定义了一个在模型产生response之后但是在任何的tool call之前的hook</p>
<ol>
<li>The agent invokes the model to generate a response.</li>
<li>The middleware inspects the response for tool calls.</li>
<li>If any calls require human input, the middleware builds a <a href="https://reference.langchain.com/python/langchain/agents/middleware/human_in_the_loop/HITLRequest">HITLRequest</a> with <code>action_requests</code> and <code>review_configs</code> and calls <a href="https://reference.langchain.com/python/langgraph/types/interrupt">interrupt</a>.</li>
<li>The agent waits for human decisions.</li>
<li>Based on the <code>HITLResponse</code> decisions, the middleware executes approved or edited calls, synthesizes <a href="https://reference.langchain.com/python/langchain-core/messages/tool/ToolMessage">ToolMessage</a>’s for rejected calls, returns human replies directly as <a href="https://reference.langchain.com/python/langchain-core/messages/tool/ToolMessage">ToolMessage</a>’s for <code>respond</code> decisions, and resumes execution.</li>
</ol>
<p>Custom HITL logic
对于更加复杂的工作流,你可以构建自定义的中断原语哥中间件来实现</p>
]]></content:encoded>
    </item>
    <item>
      <title>Long-term-memory</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/long-term-memory/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/long-term-memory/</guid>
      <description>Long-term-memory相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>Across sessions and conversations</p>
<p>Long-term memory 建立在Lang Graph stores,存储的形式:JSON documents organized by namespace and key</p>
<h1 id="usage">Usage</h1>
<p>为了给一个agent添加memory功能,在使用<code>create_agent</code>时create a store and pass it to 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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><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_core.runnables</span> <span class="kn">import</span> <span class="n">Runnable</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.store.memory</span> <span class="kn">import</span> <span class="n">InMemoryStore</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># InMemoryStore saves data to an in-memory dictionary. Use a DB-backed store in production use.</span>
</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></span><span class="line"><span class="cl"><span class="n">agent</span><span class="p">:</span> <span class="n">Runnable</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;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></span><span class="line"><span class="cl">    <span class="n">store</span><span class="o">=</span><span class="n">store</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><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_core.runnables</span> <span class="kn">import</span> <span class="n">Runnable</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.store.postgres</span> <span class="kn">import</span> <span class="n">PostgresStore</span>  <span class="c1"># type: ignore[import-not-found]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">DB_URI</span> <span class="o">=</span> <span class="s2">&#34;postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="n">PostgresStore</span><span class="o">.</span><span class="n">from_conn_string</span><span class="p">(</span><span class="n">DB_URI</span><span class="p">)</span> <span class="k">as</span> <span class="n">store</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">setup</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">agent</span><span class="p">:</span> <span class="n">Runnable</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;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></span><span class="line"><span class="cl">        <span class="n">store</span><span class="o">=</span><span class="n">store</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>tool可以通过<code>runtime.store</code>来访问并且写入store</p>
<h1 id="memory-storage">Memory storage</h1>
<p>每个记忆都被组织在自定义的<code>namespace</code>(类似于文件夹)和一个独特的<code>key</code>(类似于文件名)之下
随后可以通过内容过滤器实现跨命名空间的搜索
InmemoryStore</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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Sequence</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.store.base</span> <span class="kn">import</span> <span class="n">IndexConfig</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.store.memory</span> <span class="kn">import</span> <span class="n">InMemoryStore</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">embed</span><span class="p">(</span><span class="n">texts</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">list</span><span class="p">[</span><span class="nb">float</span><span class="p">]]:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Replace with an actual embedding function or LangChain embeddings object</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[[</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">]</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="n">texts</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="c1"># InMemoryStore saves data to an in-memory dictionary. Use a DB-backed store in production use.</span>
</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 class="n">index</span><span class="o">=</span><span class="n">IndexConfig</span><span class="p">(</span><span class="n">embed</span><span class="o">=</span><span class="n">embed</span><span class="p">,</span> <span class="n">dims</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">user_id</span> <span class="o">=</span> <span class="s2">&#34;my-user&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">application_context</span> <span class="o">=</span> <span class="s2">&#34;chitchat&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">namespace</span> <span class="o">=</span> <span class="p">(</span><span class="n">user_id</span><span class="p">,</span> <span class="n">application_context</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">put</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">namespace</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;a-memory&#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;rules&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;User likes short, direct language&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;User only speaks English &amp; python&#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;my-key&#34;</span><span class="p">:</span> <span class="s2">&#34;my-value&#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 class="c1"># get the &#34;memory&#34; by ID</span>
</span></span><span class="line"><span class="cl"><span class="n">item</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="n">namespace</span><span class="p">,</span> <span class="s2">&#34;a-memory&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># search for &#34;memories&#34; within this namespace, filtering on content equivalence, sorted by vector similarity</span>
</span></span><span class="line"><span class="cl"><span class="n">items</span> <span class="o">=</span> <span class="n">store</span><span class="o">.</span><span class="n">search</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">namespace</span><span class="p">,</span> <span class="nb">filter</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;my-key&#34;</span><span class="p">:</span> <span class="s2">&#34;my-value&#34;</span><span class="p">},</span> <span class="n">query</span><span class="o">=</span><span class="s2">&#34;language preferences&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>PostgreSQL</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></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 collections.abc import Sequence
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">from langgraph.store.base import IndexConfig
</span></span><span class="line"><span class="cl">from langgraph.store.postgres import PostgresStore  # type: ignore[import-not-found]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">def embed(texts: Sequence[str]) -&gt; list[list[float]]:
</span></span><span class="line"><span class="cl">    # Replace with an actual embedding function or LangChain embeddings object
</span></span><span class="line"><span class="cl">    return [[1.0, 2.0] for _ in texts]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">DB_URI = &#34;postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">with PostgresStore.from_conn_string(
</span></span><span class="line"><span class="cl">    DB_URI,
</span></span><span class="line"><span class="cl">    index=IndexConfig(embed=embed, dims=2),  # type: ignore[arg-type]
</span></span><span class="line"><span class="cl">) as store:
</span></span><span class="line"><span class="cl">    store.setup()
</span></span><span class="line"><span class="cl">    user_id = &#34;my-user&#34;
</span></span><span class="line"><span class="cl">    application_context = &#34;chitchat&#34;
</span></span><span class="line"><span class="cl">    namespace = (user_id, application_context)
</span></span><span class="line"><span class="cl">    store.put(
</span></span><span class="line"><span class="cl">        namespace,
</span></span><span class="line"><span class="cl">        &#34;a-memory&#34;,
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            &#34;rules&#34;: [
</span></span><span class="line"><span class="cl">                &#34;User likes short, direct language&#34;,
</span></span><span class="line"><span class="cl">                &#34;User only speaks English &amp; python&#34;,
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">            &#34;my-key&#34;: &#34;my-value&#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">    item = store.get(namespace, &#34;a-memory&#34;)
</span></span><span class="line"><span class="cl">    items = store.search(
</span></span><span class="line"><span class="cl">        namespace, filter={&#34;my-key&#34;: &#34;my-value&#34;}, query=&#34;language preferences&#34;
</span></span><span class="line"><span class="cl">    )
</span></span></code></pre></td></tr></table>
</div>
</div><h1 id="read-long-term-memory-in-tools">Read long-term memory in tools</h1>
<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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><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="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.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">langchain_core.runnables</span> <span class="kn">import</span> <span class="n">Runnable</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.store.postgres</span> <span class="kn">import</span> <span class="n">PostgresStore</span>  <span class="c1"># type: ignore[import-not-found]</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="nd">@dataclass</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Context</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="n">DB_URI</span> <span class="o">=</span> <span class="s2">&#34;postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="n">PostgresStore</span><span class="o">.</span><span class="n">from_conn_string</span><span class="p">(</span><span class="n">DB_URI</span><span class="p">)</span> <span class="k">as</span> <span class="n">store</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">setup</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">put</span><span class="p">((</span><span class="s2">&#34;users&#34;</span><span class="p">,),</span> <span class="s2">&#34;user_123&#34;</span><span class="p">,</span> <span class="p">{</span><span class="s2">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;John Smith&#34;</span><span class="p">,</span> <span class="s2">&#34;language&#34;</span><span class="p">:</span> <span class="s2">&#34;English&#34;</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></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="n">Context</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="k">assert</span> <span class="n">runtime</span><span class="o">.</span><span class="n">store</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">        <span class="n">user_info</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">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></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="n">agent</span><span class="p">:</span> <span class="n">Runnable</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;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_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 class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">context_schema</span><span class="o">=</span><span class="n">Context</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;look up user information&#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">Context</span><span class="p">(</span><span class="n">user_id</span><span class="o">=</span><span class="s2">&#34;user_123&#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><h1 id="write-long-term-memory-from-tools">Write long-term memory from tools</h1>
<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></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-py" data-lang="py"><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="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.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">langchain_core.runnables</span> <span class="kn">import</span> <span class="n">Runnable</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langgraph.store.postgres</span> <span class="kn">import</span> <span class="n">PostgresStore</span>  <span class="c1"># type: ignore[import-not-found]</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">typing_extensions</span> <span class="kn">import</span> <span class="n">TypedDict</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="nd">@dataclass</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Context</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="k">class</span> <span class="nc">UserInfo</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">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="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 class="n">user_info</span><span class="p">:</span> <span class="n">UserInfo</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">Context</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="k">assert</span> <span class="n">runtime</span><span class="o">.</span><span class="n">store</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</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 class="s2">&#34;users&#34;</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="nb">dict</span><span class="p">(</span><span class="n">user_info</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></span><span class="line"><span class="cl"><span class="n">DB_URI</span> <span class="o">=</span> <span class="s2">&#34;postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="n">PostgresStore</span><span class="o">.</span><span class="n">from_conn_string</span><span class="p">(</span><span class="n">DB_URI</span><span class="p">)</span> <span class="k">as</span> <span class="n">store</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">setup</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">agent</span><span class="p">:</span> <span class="n">Runnable</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;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">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 class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">context_schema</span><span class="o">=</span><span class="n">Context</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">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;My name is John Smith&#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">Context</span><span class="p">(</span><span class="n">user_id</span><span class="o">=</span><span class="s2">&#34;user_123&#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>]]></content:encoded>
    </item>
    <item>
      <title>Retrieval</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/retrieval/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/retrieval/</guid>
      <description>Retrieval相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>Two limitations of LLM:</p>
<ol>
<li>finite context</li>
<li>Static Knowledge</li>
</ol>
<p>RAG(检索增强生成)</p>
<h1 id="building-a-knowledge-base">Building a knowledge base</h1>
<p>A repository of documents of structured data
使用LangChain&rsquo;s document loaders and vector stores 来建立你自己的知识库
如果你已经有知识库,你不需要重建,你只需要</p>
<ul>
<li>Connect it as a tool for agent in agentic RAG</li>
<li>Query it and supply the retrieved content as context to the LLM <a href="https://docs.langchain.com/oss/python/deepagents/retrieval#2-step-rag">(2-Step RAG)</a></li>
</ul>
<h2 id="from-retrieval-to-rag">From retrieval to RAG</h2>
<h2 id="retrieval-pipeline">Retrieval pipeline</h2>
<p><img alt="image-20260922210616005" loading="lazy" src="c:\\Users\\14152\\AppData\\Roaming\\Typora\\typora-user-images\\image-20260922210616005.png"></p>
<p>Document loaders,text splitters,Embedding models,vector stores,retrievers</p>
<h1 id="rag-architectures">RAG architectures</h1>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Architecture</th>
					<th style="text-align: left">Description</th>
					<th style="text-align: left">Control</th>
					<th style="text-align: left">Flexibility</th>
					<th style="text-align: left">Latency</th>
					<th style="text-align: left">Example Use Case</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><strong>2-Step RAG</strong></td>
					<td style="text-align: left">Retrieval always happens before generation. Simple and predictable</td>
					<td style="text-align: left">✅ High</td>
					<td style="text-align: left">❌ Low</td>
					<td style="text-align: left">⚡ Fast</td>
					<td style="text-align: left">FAQs, documentation bots</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Agentic RAG</strong></td>
					<td style="text-align: left">An LLM-powered agent decides <em>when</em> and <em>how</em> to retrieve during reasoning</td>
					<td style="text-align: left">❌ Low</td>
					<td style="text-align: left">✅ High</td>
					<td style="text-align: left">⏳ Variable</td>
					<td style="text-align: left">Research assistants with access to multiple tools</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong>Hybrid</strong></td>
					<td style="text-align: left">Combines characteristics of both approaches with validation steps</td>
					<td style="text-align: left">⚖️ Medium</td>
					<td style="text-align: left">⚖️ Medium</td>
					<td style="text-align: left">⏳ Variable</td>
					<td style="text-align: left">Domain-specific Q&amp;A with quality validation</td>
			</tr>
	</tbody>
</table>
<h2 id="2-step-rag">2-step RAG</h2>
<p><img alt="image-20260922210932476" loading="lazy" src="c:\\Users\\14152\\AppData\\Roaming\\Typora\\typora-user-images\\image-20260922210932476.png"></p>
<h2 id="agentic-rag">Agentic RAG</h2>
<p><img alt="image-20260922211016040" loading="lazy" src="c:\\Users\\14152\\AppData\\Roaming\\Typora\\typora-user-images\\image-20260922211016040.png"></p>
<p>由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><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-py" data-lang="py"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">requests</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">tool</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">langchain.chat_models</span> <span class="kn">import</span> <span class="n">init_chat_model</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></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">fetch_url</span><span class="p">(</span><span class="n">url</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 text content from a URL&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mf">10.0</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">raise_for_status</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">response</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 class="n">system_prompt</span> <span class="o">=</span> <span class="s2">&#34;&#34;&#34;</span><span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="s2">Use fetch_url when you need to fetch information from a web-page; quote relevant snippets.
</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></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">fetch_url</span><span class="p">],</span> <span class="c1"># A tool for retrieval</span>
</span></span><span class="line"><span class="cl">    <span class="n">system_prompt</span><span class="o">=</span><span class="n">system_prompt</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="hybrid-rag">Hybrid RAG</h2>
<p><img alt="image-20260922211229661" loading="lazy" src="c:\\Users\\14152\\AppData\\Roaming\\Typora\\typora-user-images\\image-20260922211229661.png"></p>
<p>结合了前两者的优点,核心组件包括:</p>
<p>查询增强:修改question来提高检索质量,这可能包括重写不清晰的查询、生成多个变体，或使用其他上下文扩展查询。</p>
<p>检索验证:评估检索到的资料是否充足</p>
<p>答案验证:检查生成的答案准确性,完整性和于源文件的一致性</p>
<p>此架构适用于</p>
<ul>
<li>存在模糊或描述不详的查询的应用场景</li>
<li>需要验证或质量控制步骤的系统</li>
<li>涉及多个数据源或迭代优化的工作流</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Runtime</title>
      <link>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/runtime/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://tuanzi-wow.cn/frameworks/langchain/advanced-usage/runtime/</guid>
      <description>Runtime相关学习笔记与实践要点。</description>
      <content:encoded><![CDATA[<p>LangChain&rsquo;s <code>create_agent</code>的底层运行在LangGraph&rsquo;s runtime
LangGraph暴露一个Runtime object,提供以下的信息:
1.context:静态信息:user id,数据库连接和其他的依赖
2.Store:用于长期记忆的BaseStore实例
3.Stream writer:通过&quot;custom&quot;流式传输模式来硫化信息的object
4.Execution info: identity and retry information for the current execution(thread ID, run ID ,attmpt number)
5.Server info:在 LangGraph Server 上运行时的特定于服务器的元数据(assistant ID,graph ID, authenticated user
)
You can access the runtime information within tools and middleware</p>
<h1 id="access">Access</h1>
<p>当创建agent with <code>create_agent</code>时,可以传入一个context_schema来定义存储在agent的<code>Runtime</code>中的context的结构</p>
<p>当调用agent是,则可以传入<code>context</code> with 相关的参数</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">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></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">Context</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="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="o">...</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">Context</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="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">context</span><span class="o">=</span><span class="n">Context</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></code></pre></td></tr></table>
</div>
</div><h2 id="inside-tools">Inside tools</h2>
<p>你可以在tool中访问runtime来:</p>
<ul>
<li>Access the context</li>
<li>Read or write long-term memory</li>
<li>Wtrie tp the custom stream</li>
</ul>
<p>通过<code>ToolRuntime</code>参数来访问<code>Runtime</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></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 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="n">dataclass</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">Context</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="err">@</span><span class="k">tool</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">fetch_user_email_preferences</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">Context</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 user&#39;s email preferences from the store.&#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="n">preferences</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&#34;The user prefers you to write a brief and polite email.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">runtime</span><span class="o">.</span><span class="n">store</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">memory</span> <span class="p">:</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="n">preferences</span> <span class="o">=</span> <span class="n">memory</span><span class="o">.</span><span class="n">value</span><span class="p">[</span><span class="s2">&#34;preferences&#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">preferences</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="execution-info-and-server-info-inside-tools">Execution info and server info inside tools</h2>
<p>Access execution identity (thread ID, run ID) via <code>runtime.execution_info</code>, and server-specific metadata (assistant ID, authenticated user) via <code>runtime.server_info</code> when running on LangGraph Server</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">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">context_aware_tool</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;A tool that uses execution and server info.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Access thread and run IDs</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></span><span class="line"><span class="cl">    <span class="c1"># Access server info (only available on LangGraph Server)</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}&#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></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="inside-middleware">Inside middleware</h2>
<p>通过middleware访问runtime来:创建动态prompt,修改messages,根据上下文控制agent的行为</p>
<p>Use the <code>Runtime</code> parameter to access the <a href="https://reference.langchain.com/python/langgraph/runtime/Runtime"><code>Runtime</code></a> object inside <a href="https://docs.langchain.com/oss/python/langchain/middleware/custom#node-style-hooks">node-style hooks</a>. For <a href="https://docs.langchain.com/oss/python/langchain/middleware/custom#wrap-style-hooks">wrap-style hooks</a>, the <code>Runtime</code> object is available inside the <a href="https://reference.langchain.com/python/langchain/agents/middleware/types/ModelRequest"><code>ModelRequest</code></a> 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><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></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">messages</span> <span class="n">import</span> <span class="n">AnyMessage</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">dynamic_prompt</span><span class="p">,</span> <span class="n">ModelRequest</span><span class="p">,</span> <span class="n">before_model</span><span class="p">,</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">dataclass</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="n">Context</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="c1"># Dynamic prompts</span>
</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="o">.</span><span class="n">user_name</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 class="c1"># Before model hook</span>
</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">log_before_model</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="n">Context</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="nb">print</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Processing request for user: {runtime.context.user_name}&#34;</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="c1"># After model hook</span>
</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">log_after_model</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="n">Context</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="nb">print</span><span class="p">(</span><span class="n">f</span><span class="s2">&#34;Completed request for user: {runtime.context.user_name}&#34;</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 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_system_prompt</span><span class="p">,</span> <span class="n">log_before_model</span><span class="p">,</span> <span class="n">log_after_model</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">Context</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="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">context</span><span class="o">=</span><span class="n">Context</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></code></pre></td></tr></table>
</div>
</div><h2 id="execution-info-and-server-info-inside-middleware">Execution info and server info inside middleware</h2>
<p>Middleware hooks can also access <code>runtime.execution_info</code> and <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><span class="lnt">12
</span><span class="lnt">13
</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.agents import AgentState
</span></span><span class="line"><span class="cl">from langchain.agents.middleware import before_model
</span></span><span class="line"><span class="cl">from langgraph.runtime import Runtime
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">@before_model
</span></span><span class="line"><span class="cl">def auth_gate(state: AgentState, runtime: Runtime) -&gt; dict | None:
</span></span><span class="line"><span class="cl">    &#34;&#34;&#34;Block unauthenticated users when running on LangGraph Server.&#34;&#34;&#34;
</span></span><span class="line"><span class="cl">    server = runtime.server_info
</span></span><span class="line"><span class="cl">    if server is not None and server.user is None:
</span></span><span class="line"><span class="cl">        raise ValueError(&#34;Authentication required&#34;)
</span></span><span class="line"><span class="cl">    print(f&#34;Thread: {runtime.execution_info.thread_id}&#34;)
</span></span><span class="line"><span class="cl">    return None
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
  </channel>
</rss>
