<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Agent 记忆 on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/agent-%E8%AE%B0%E5%BF%86/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Wed, 11 Feb 2026 11:00:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/agent-%E8%AE%B0%E5%BF%86/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>LangGraph 入门：给传统工程师的 Agent 状态与编排指南</title>
      <link>https://ftmao.com/blog/posts/langgraph-agent-guide/</link>
      <pubDate>Wed, 11 Feb 2026 11:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/posts/langgraph-agent-guide/</guid>
      <description>&lt;h1 id=&#34;langgraph-入门给传统工程师的-agent-状态与编排指南&#34;&gt;LangGraph 入门：给传统工程师的 Agent 状态与编排指南&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;我做传统软件工程很多年，习惯了状态机、工作流引擎、消息队列这些确定性系统。第一次接触 LangGraph 时，我觉得它像是一个&amp;quot;有状态的 DAG 调度器&amp;quot;，只不过节点不再是跑批任务，而是调用 LLM、工具或业务逻辑。这篇文章结合我在方糖猫 AI 短视频生成平台和 GeekCast Engine 口播剪辑项目里的经验，聊聊 LangGraph 最核心的三个概念：State、任务编排、长期记忆，以及几个让调试更轻松的小技巧。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一langgraph-是什么&#34;&gt;一、LangGraph 是什么？&lt;/h2&gt;
&lt;p&gt;LangGraph 是 LangChain 生态里的一个 Agent 编排框架。它和传统工作流引擎最大的区别是：&lt;strong&gt;它把 LLM 调用、工具调用、业务判断都看成图里的节点，节点之间通过共享的 State 对象传递信息。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你可以把它理解成：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;状态机 + LLM + 工具调用 + 持久化 = LangGraph&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;在方糖猫里，一个短视频生成任务的流程大致是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;接收用户输入（主题、风格、素材偏好）；&lt;/li&gt;
&lt;li&gt;ReAct Agent 规划分镜和素材需求；&lt;/li&gt;
&lt;li&gt;检索 RAG 本地素材库；&lt;/li&gt;
&lt;li&gt;生成脚本初稿；&lt;/li&gt;
&lt;li&gt;检查脚本长度与平台规范；&lt;/li&gt;
&lt;li&gt;组装渲染任务并推送到 RocketMQ；&lt;/li&gt;
&lt;li&gt;Python Worker 拉取任务，用 Remotion + FFmpeg 渲染成片。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个流程如果写成 LangGraph，就是一张图：每个步骤是一个节点，节点之间根据 State 里的数据决定下一步去哪。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二stateagent-的工作记忆&#34;&gt;二、State：Agent 的&amp;quot;工作记忆&amp;quot;&lt;/h2&gt;
&lt;p&gt;State 是 LangGraph 里最重要的概念。它是一个 Python 字典（或 TypedDict/Pydantic 模型），在整个图的执行过程中被所有节点共享。&lt;/p&gt;
&lt;h3 id=&#34;一个简单的-state-定义&#34;&gt;一个简单的 State 定义&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; typing &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; TypedDict, List, Optional
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VideoGenState&lt;/span&gt;(TypedDict):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    topic: str                    &lt;span style=&#34;color:#75715e&#34;&gt;# 用户输入的主题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    style: str                    &lt;span style=&#34;color:#75715e&#34;&gt;# 风格偏好&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    script: Optional[str]         &lt;span style=&#34;color:#75715e&#34;&gt;# 生成的脚本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    materials: List[str]          &lt;span style=&#34;color:#75715e&#34;&gt;# 检索到的素材 ID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    render_task: Optional[dict]   &lt;span style=&#34;color:#75715e&#34;&gt;# 渲染任务描述&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    error: Optional[str]          &lt;span style=&#34;color:#75715e&#34;&gt;# 错误信息&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;每个节点接收 State，修改 State，然后返回更新后的 State。LangGraph 会自动合并这些更新。&lt;/p&gt;
&lt;h3 id=&#34;为什么-state-如此重要&#34;&gt;为什么 State 如此重要？&lt;/h3&gt;
&lt;p&gt;在传统工作流里，我们通常把中间结果写到数据库或 Redis。LangGraph 的 State 相当于一个&lt;strong&gt;内存中的上下文容器&lt;/strong&gt;，让 Agent 在单轮执行里记住：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户原始需求；&lt;/li&gt;
&lt;li&gt;已经做过什么；&lt;/li&gt;
&lt;li&gt;下一步该做什么；&lt;/li&gt;
&lt;li&gt;是否有错误需要处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 GeekCast Engine 里，长视频口播稿会被切分成多个 segment。每个 segment 的处理可以是一个子图，父图的 State 里保存全局信息（比如视频总时长、字幕样式），子图的 State 里保存 segment 级别的信息（比如台词、B-roll、标题卡）。这种&amp;quot;全局 + 局部&amp;quot;的 State 设计，和我们做分布式系统时的&amp;quot;全局配置 + 局部任务&amp;quot;思想是一致的。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三任务编排图节点边&#34;&gt;三、任务编排：图、节点、边&lt;/h2&gt;
&lt;p&gt;LangGraph 的编排模型很直观：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;节点（Node）&lt;/strong&gt;：执行一个函数，通常是调用 LLM、工具或业务逻辑；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;边（Edge）&lt;/strong&gt;：连接两个节点，控制执行流向；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;条件边（Conditional Edge）&lt;/strong&gt;：根据 State 的内容决定下一步去哪个节点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;一个简化版的视频生成图&#34;&gt;一个简化版的视频生成图&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langgraph.graph &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; StateGraph, END
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; StateGraph(VideoGenState)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_node(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plan&amp;#34;&lt;/span&gt;, plan_node)           &lt;span style=&#34;color:#75715e&#34;&gt;# Agent 规划&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_node(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;retrieve&amp;#34;&lt;/span&gt;, retrieve_node)   &lt;span style=&#34;color:#75715e&#34;&gt;# RAG 检索素材&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_node(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write_script&amp;#34;&lt;/span&gt;, script_node) &lt;span style=&#34;color:#75715e&#34;&gt;# 写脚本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_node(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;check&amp;#34;&lt;/span&gt;, check_node)         &lt;span style=&#34;color:#75715e&#34;&gt;# 检查规范&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_node(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;render&amp;#34;&lt;/span&gt;, render_node)       &lt;span style=&#34;color:#75715e&#34;&gt;# 推送渲染任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;set_entry_point(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plan&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_edge(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plan&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;retrieve&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_edge(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;retrieve&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write_script&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_edge(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write_script&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;check&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 条件边：检查不通过则重写脚本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_conditional_edges(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;check&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;lambda&lt;/span&gt; state: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rewrite&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; state&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;render&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rewrite&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;write_script&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;render&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;render&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;add_edge(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;render&amp;#34;&lt;/span&gt;, END)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;graph &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;compile()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;这个结构和传统状态机几乎一样：每个节点做完一件事，根据结果决定下一个状态。对于习惯画状态图的工程师来说，上手很快。&lt;/p&gt;
&lt;h3 id=&#34;条件边的价值&#34;&gt;条件边的价值&lt;/h3&gt;
&lt;p&gt;没有条件边，LangGraph 就只是一个固定的 Pipeline。有了条件边，Agent 才能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据 LLM 判断决定调用哪个工具；&lt;/li&gt;
&lt;li&gt;根据执行结果决定重试还是继续；&lt;/li&gt;
&lt;li&gt;根据用户反馈决定是否需要人工介入。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在方糖猫里，素材检索节点之后，如果召回的素材数量不足，我们会走&amp;quot;放宽检索条件&amp;quot;的分支；如果素材足够，才进入脚本生成。这种动态决策能力，是 LangGraph 比简单 Pipeline 更适合 Agent 场景的原因。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四长期记忆从单线程到跨会话&#34;&gt;四、长期记忆：从单线程到跨会话&lt;/h2&gt;
&lt;p&gt;LangGraph 的持久化分为两层，这是很多人刚开始会混淆的地方：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;能力&lt;/th&gt;
					&lt;th&gt;Checkpointer&lt;/th&gt;
					&lt;th&gt;Store（Memory Store）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;作用范围&lt;/td&gt;
					&lt;td&gt;单个线程（&lt;code&gt;thread_id&lt;/code&gt;）&lt;/td&gt;
					&lt;td&gt;跨线程、跨会话&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;保存内容&lt;/td&gt;
					&lt;td&gt;执行过程中的 State 快照&lt;/td&gt;
					&lt;td&gt;用户事实、交互经验、行为偏好&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;典型用途&lt;/td&gt;
					&lt;td&gt;断点续跑、人在回路、time-travel&lt;/td&gt;
					&lt;td&gt;长期记忆、个性化&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;存储示例&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;InMemorySaver&lt;/code&gt;、&lt;code&gt;PostgresSaver&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;InMemoryStore&lt;/code&gt;、&lt;code&gt;PostgresStore&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;checkpointer线程级的短期记忆&#34;&gt;Checkpointer：线程级的&amp;quot;短期记忆&amp;quot;&lt;/h3&gt;
&lt;p&gt;Checkpointer 让 LangGraph 可以在任意节点暂停、恢复、回溯。这对于&amp;quot;人在回路&amp;quot;（Human-in-the-loop）场景特别重要。&lt;/p&gt;
&lt;p&gt;比如视频生成任务里，脚本生成节点完成后，我们可以让系统停下来，等用户确认脚本内容，确认后再继续渲染。没有 Checkpointer，这种中断-恢复就很难优雅实现。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langgraph.checkpoint.memory &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; MemorySaver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;graph &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; builder&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;compile(checkpointer&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;MemorySaver())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;store真正的长期记忆&#34;&gt;Store：真正的长期记忆&lt;/h3&gt;
&lt;p&gt;Store 是 LangGraph 为长期记忆设计的存储层。吴恩达和 Harrison Chase 在《Long-Term Agentic Memory with LangGraph》课程里，把长期记忆分为三类：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;语义记忆（Semantic Memory）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;存储关于用户的稳定事实，比如&amp;quot;用户偏好科技感风格&amp;quot;、&amp;ldquo;用户通常发布横屏视频&amp;rdquo;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;情景记忆（Episodic Memory）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;存储具体交互案例，比如&amp;quot;上次用户拒绝了这个 BGM，后来换成了另一首&amp;quot;。这些案例可以作为 few-shot 示例，帮助 Agent 在未来做出类似判断。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;程序记忆（Procedural Memory）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;存储 Agent 自身应该遵循的行为模式，也就是系统提示词或判断标准的优化版本。比如&amp;quot;对于这类用户，生成脚本前要先确认时长&amp;quot;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;在项目中怎么落地&#34;&gt;在项目中怎么落地？&lt;/h3&gt;
&lt;p&gt;在方糖猫里，我们目前主要用了语义记忆：把用户确认过的风格偏好、常用素材、发布平台规格等写入 Store，下次用户再创建视频时，Agent 会先读取这些记忆，减少重复确认。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; langgraph.store.memory &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; InMemoryStore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;store &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; InMemoryStore()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 在某个节点里写入记忆&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;store&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;put(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_123&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;preferences&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;style&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;preferred_style&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tech&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;aspect_ratio&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;16:9&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 后续会话中读取&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;memories &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; store&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;search((&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_123&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;preferences&amp;#34;&lt;/span&gt;), query&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;风格偏好&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;生产环境建议用 &lt;code&gt;PostgresStore&lt;/code&gt;，并把记忆更新放到后台节点执行，避免阻塞主流程。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五实战小技巧&#34;&gt;五、实战小技巧&lt;/h2&gt;
&lt;h3 id=&#34;1-用图片mermaid-输出流程图&#34;&gt;1. 用图片/Mermaid 输出流程图&lt;/h3&gt;
&lt;p&gt;LangGraph 编译后的图可以用 Mermaid 或图片方式可视化。这在设计阶段特别有用，尤其是在团队沟通时。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; IPython.display &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Image, display
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;display(Image(graph&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_graph()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;draw_mermaid_png()))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;如果你没有 Jupyter 环境，也可以输出 Mermaid 文本：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(graph&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_graph()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;draw_mermaid())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;然后贴到支持 Mermaid 的编辑器（比如 Notion、GitHub、Draw.io）里查看。这个习惯能帮你在写代码前先确认流程没有死循环或遗漏分支。&lt;/p&gt;
&lt;h3 id=&#34;2-打印提示词调试&#34;&gt;2. 打印提示词调试&lt;/h3&gt;
&lt;p&gt;LangGraph 节点里经常会拼接复杂的 Prompt。调试时，把最终发给 LLM 的完整 Prompt 打印出来，比看代码直观得多。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;plan_node&lt;/span&gt;(state: VideoGenState):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    prompt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; build_plan_prompt(state)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;===== PLAN PROMPT =====&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(prompt)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;===== END PROMPT =====&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; llm&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;invoke(prompt)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plan&amp;#34;&lt;/span&gt;: response&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;content}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;相信我，80% 的&amp;quot;模型表现不好&amp;quot;问题，打印完 Prompt 就会发现：上下文缺失、格式混乱、或者约束互相矛盾。&lt;/p&gt;
&lt;h3 id=&#34;3-把节点拆小便于追踪&#34;&gt;3. 把节点拆小，便于追踪&lt;/h3&gt;
&lt;p&gt;一个大节点里做太多事，调试和复用都困难。我建议每个节点只负责一个明确职责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个节点做 LLM 调用；&lt;/li&gt;
&lt;li&gt;一个节点做工具调用；&lt;/li&gt;
&lt;li&gt;一个节点做 State 校验；&lt;/li&gt;
&lt;li&gt;一个节点做错误处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 GeekCast Engine 里，我们把&amp;quot;口播精剪&amp;quot;拆成了：Whisper 转写 → 时间轴分析 → 删除气口 → 重新对齐 → 输出剪辑点。每个节点都可以单独测试、单独复用。&lt;/p&gt;
&lt;h3 id=&#34;4-用-state-的字段做日志锚点&#34;&gt;4. 用 State 的字段做日志锚点&lt;/h3&gt;
&lt;p&gt;给 State 加上 &lt;code&gt;logs&lt;/code&gt; 或 &lt;code&gt;trace&lt;/code&gt; 字段，在每个节点记录关键信息。这样出问题后，可以直接看 State 快照定位到哪个节点、哪个决策点出错。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VideoGenState&lt;/span&gt;(TypedDict):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ... 其他字段&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    logs: List[str]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;retrieve_node&lt;/span&gt;(state):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    materials &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; search_materials(state[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    logs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; state&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;logs&amp;#34;&lt;/span&gt;, [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    logs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;retrieve: found &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;len(materials)&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; materials&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;materials&amp;#34;&lt;/span&gt;: materials, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;logs&amp;#34;&lt;/span&gt;: logs}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;5-不要忽视错误分支&#34;&gt;5. 不要忽视错误分支&lt;/h3&gt;
&lt;p&gt;LangGraph 的图很容易画成&amp;quot;理想路径&amp;quot;，但生产环境必须考虑异常：LLM 返回格式错误、工具调用超时、检索结果为空、State 校验失败。&lt;/p&gt;
&lt;p&gt;我的做法是：每个可能失败的节点后面都跟一个错误处理节点，或者把错误信息写入 State，由条件边统一路由到重试或人工审核。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六langgraph-适合什么场景&#34;&gt;六、LangGraph 适合什么场景？&lt;/h2&gt;
&lt;p&gt;不是每个 LLM 应用都需要 LangGraph。如果你只是做一个简单的聊天机器人或单次文本生成，直接调 API 可能更轻量。&lt;/p&gt;
&lt;p&gt;但当你遇到以下情况时，LangGraph 会很有价值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务需要多步骤决策，且步骤之间有依赖；&lt;/li&gt;
&lt;li&gt;需要调用多个工具，并根据中间结果动态选择；&lt;/li&gt;
&lt;li&gt;需要支持中断、人工确认、断点续跑；&lt;/li&gt;
&lt;li&gt;需要长期记忆来提供个性化体验；&lt;/li&gt;
&lt;li&gt;团队需要把 Agent 流程可视化、可维护。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;方糖猫和 GeekCast Engine 都属于这类场景。LangGraph 让我们把原本散落在代码各处的&amp;quot;if-else + LLM 调用 + 工具调用&amp;quot;统一成了可看的、可调的、可持久化的图。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七总结&#34;&gt;七、总结&lt;/h2&gt;
&lt;p&gt;LangGraph 不是另一个&amp;quot;让代码更复杂&amp;quot;的框架，而是把 Agent 执行过程显性化的工具。它的核心概念其实和传统工程很像：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;State&lt;/strong&gt; 就是工作记忆或上下文容器；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图编排&lt;/strong&gt; 就是状态机加上动态分支；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checkpointer&lt;/strong&gt; 提供会话内的断点续跑；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Store&lt;/strong&gt; 提供跨会话的长期记忆。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于传统工程师来说，最值得培养的能力不是背 API，而是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如何把业务问题拆成清晰的节点和状态；&lt;/li&gt;
&lt;li&gt;如何设计 State，让它既能表达业务语义，又便于调试；&lt;/li&gt;
&lt;li&gt;什么时候用短期记忆，什么时候用长期记忆；&lt;/li&gt;
&lt;li&gt;如何通过可视化和小技巧降低系统的认知复杂度。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果你正在用 LangGraph 做项目，我的建议是：先画图，再写代码；先打印 Prompt，再调模型；先把主流程跑通，再逐步加入记忆和异常处理。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;我在 ftmao.com/blog 持续记录 AI Agent、LangGraph 和多模态生成相关的工程实践，欢迎关注和交流。&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
  </channel>
</rss>
