通过上下文工程优化LangChain AI Agents(一)


上下文工程指的是在给AI分配任务之前,为其创建合适的设置。该设置包括:

  • 关于AI应如何行动的指示,例如作为一名有用的经济型旅行指南

  • 从数据库、文档或实时来源获取有用信息的权限。

  • 记住过往对话,以避免重复或遗忘。

  • AI可以使用的工具,例如计算器或搜索功能。

  • 关于你的重要细节,例如你的偏好或位置。

上下文工程

AI工程师现在正从提示工程转向上下文工程,因为上下文工程专注于为AI提供合适的背景和工具,使其答案更智能、更有用。

在接下来的两篇博客中,我们将探讨如何利用LangChain和LangGraph这两款用于构建AI agents、RAG应用和LLM应用的强大工具,有效实施上下文工程,以改进我们的AI Agents。

目录

  • 什么是上下文工程?

  • 使用LangGraph的草稿区

  • 创建StateGraph

  • LangGraph中的内存写入

  • 草稿区选择方法

  • 内存选择能力

什么是上下文工程?

大型语言模型(LLMs)的运作方式类似于一种新型操作系统。LLM 相当于中央处理器(CPU),其上下文窗口则类似于随机存取存储器(RAM),充当着它的短期记忆。但和 RAM 一样,上下文窗口容纳不同信息的空间是有限的。

就像操作系统会决定哪些内容进入 RAM 一样,"上下文工程"就是要确定 LLM 应该在其上下文中保留哪些内容。

不同类型的上下文

在构建 LLM 应用时,我们需要管理不同类型的上下文。上下文工程涵盖以下主要类型:

  • 指令:提示词、示例、记忆和工具描述

  • 知识:事实、存储的信息和记忆

  • 工具:工具调用产生的反馈和结果

今年,人们对 agents 的兴趣日益浓厚,因为 LLM 在思考和使用工具方面的能力有所提升。Agents 通过将 LLM 与工具结合使用来处理长期任务,并根据工具的反馈选择下一步行动。

Agent 工作流

但长期任务以及从工具收集过多反馈会消耗大量 tokens。这可能会引发一系列问题:上下文窗口可能溢出,成本和延迟可能增加,agent 的性能也可能下降。

Drew Breunig 解释了过多的上下文会如何影响性能,包括:

  • 上下文污染(Context Poisoning):错误或幻觉信息被添加到上下文中

  • 上下文干扰(Context Distraction):过多的上下文使模型产生困惑

  • 上下文混淆(Context Confusion):额外的、不必要的细节影响答案

  • 上下文冲突(Context Clash):上下文中的部分内容存在信息冲突

Agent 中的多轮交互

Anthropic 在其研究中强调了这一点的必要性:Agents 通常会进行数百轮对话,因此谨慎管理上下文至关重要。

那么,如今人们是如何解决这个问题的呢?agent 上下文工程的常见策略可分为四大类:

  • 写入(Write):创建清晰且有用的上下文

  • 选择(Select):只挑选最相关的信息

  • 压缩(Compress):缩短上下文以节省空间

  • 隔离(Isolate):将不同类型的上下文分开

上下文工程的类别(来自LangChain文档)

LangGraph 的设计初衷就是支持所有这些策略。我们将在 LangGraph 中逐一探讨这些组件,看看它们如何帮助提升我们的 AI agents 的性能。

使用 LangGraph 的草稿区(Scratchpad)

就像人类会做笔记以记住后续任务的相关内容一样,agents 也可以通过"草稿区"来实现这一点。草稿区将信息存储在上下文窗口之外,以便 agent 在需要时随时访问。

上下文工程的第一个组件(来自LangChain文档)

一个很好的例子是 Anthropic 的多 agent 研究工具:

主导研究的 agent(LeadResearcher)会规划其方法并将其保存到内存中,因为如果上下文窗口超过 200,000 个 tokens,内容就会被截断,所以保存计划可以确保它不会丢失。

草稿区可以通过多种方式实现:

  • 作为一种工具调用,用于写入文件。

  • 作为运行时状态对象中的一个字段,在会话期间持续存在。

简而言之,草稿区帮助 agents 在会话期间保存重要笔记,以便有效地完成任务。

在 LangGraph 中,它支持短期(线程范围内)和长期记忆。

  • 短期记忆使用检查点(checkpointing)来保存会话期间的 agent 状态。它的作用类似于草稿区,允许你在 agent 运行时存储信息并在之后检索。

状态对象是在图节点之间传递的主要结构。你可以定义其格式(通常是一个 Python 字典)。它就像一个共享的草稿区,每个节点都可以读取和更新特定的字段。

我们只会在需要时导入模块,这样我们就能以清晰的方式逐步学习。

为了获得更好、更清晰的输出,我们将使用 Python 的 pprint 模块进行美观打印,并使用 rich 库中的 Console 模块。让我们先导入并初始化它们:

python 复制代码
# Import necessary libraries
from typing import TypedDict  # For defining the state schema with type hints

from rich.console import Console  # For pretty-printing output
from rich.pretty import pprint  # For pretty-printing Python objects

# Initialize a console for rich, formatted output in the notebook.
console = Console()

接下来,我们将为状态对象创建一个 TypedDict。

python 复制代码
# Define the schema for the graph's state using TypedDict.
# This class acts as a data structure that will be passed between nodes in the graph.
# It ensures that the state has a consistent shape and provides type hints.
class State(TypedDict):
    """
    Defines the structure of the state for our joke generator workflow.

    Attributes:
        topic: The input topic for which a joke will be generated.
        joke: The output field where the generated joke will be stored.
    """

    topic: str
    joke: str

这个状态对象将存储主题以及我们要求 agent 根据给定主题生成的笑话。

创建状态图(StateGraph)

定义状态对象后,我们可以使用StateGraph向其写入上下文。

StateGraph是LangGraph中用于构建有状态agents或工作流的主要工具。可以将其视为一个有向图:

  • 节点(Nodes)是工作流中的步骤。每个节点接收当前状态作为输入,对其进行更新,然后返回变更内容。

  • 边(Edges)连接节点,定义执行流程------可以是线性的、有条件的,甚至是循环的。

接下来,我们将:

1.通过选择Anthropic模型来创建一个聊天模型(chat model)。

2.在LangGraph工作流中使用该模型。

python 复制代码
# 导入用于环境管理、显示和LangGraph的必要库
import getpass
import os

from IPython.display import Image, display
from langchain.chat_models import init_chat_model
from langgraph.graph import END, START, StateGraph

# --- 环境和模型设置 ---
# 设置Anthropic API密钥以验证请求
from dotenv import load_dotenv
api_key = os.getenv("ANTHROPIC_API_KEY")
if not api_key:
    raise ValueError("环境中缺少ANTHROPIC_API_KEY")

# 初始化将在工作流中使用的聊天模型
# 我们使用特定的Claude模型,设置temperature=0以获得确定性输出
llm = init_chat_model("anthropic:claude-sonnet-4-20250514", temperature=0)

我们已经初始化了Sonnet模型。LangChain通过API支持许多开源和闭源模型,因此你可以使用其中任何一种。

现在,我们需要创建一个使用该Sonnet模型生成响应的函数。

python 复制代码
# --- 定义工作流节点 ---
def generate_joke(state: State) -> dict[str, str]:
    """
    一个基于当前状态中的主题生成笑话的节点函数。

    该函数从状态中读取'topic',使用LLM生成笑话,
    并返回一个字典以更新状态中的'joke'字段。

    参数:
        state: 图的当前状态,必须包含'topic'。

    返回:
        一个包含'joke'键的字典,用于更新状态。
    """
    # 从状态中读取主题
    topic = state["topic"]
    print(f"正在生成关于以下主题的笑话:{topic}")

    # 调用语言模型生成笑话
    msg = llm.invoke(f"写一个关于{topic}的短笑话")

    # 返回生成的笑话,以便写回状态
    return {"joke": msg.content}

这个函数仅返回一个包含生成的响应(笑话)的字典。

现在,借助StateGraph,我们可以轻松构建并编译这个图。接下来就让我们动手操作。

makefile 复制代码
# --- 构建并编译图 ---
# 使用预定义的State schema初始化一个新的StateGraph
workflow = StateGraph(State)

# 将'generate_joke'函数添加为图中的一个节点
workflow.add_node("generate_joke", generate_joke)

# 定义工作流的执行路径:
# 图从START入口点开始,流向我们的'generate_joke'节点。
workflow.add_edge(START, "generate_joke")
# 'generate_joke'完成后,图的执行结束。
workflow.add_edge("generate_joke", END)

# 将工作流编译为可执行的链
chain = workflow.compile()

# --- 可视化图 ---
# 显示已编译工作流图的可视化表示
display(Image(chain.get_graph().draw_mermaid_png()))

我们生成的图

现在我们可以执行这个工作流了。

perl 复制代码
# --- 执行工作流 ---
# 使用包含主题的初始状态调用已编译的图。
# `invoke`方法从START节点运行图直至END节点。
joke_generator_state = chain.invoke({"topic": "cats"})

# --- 显示最终状态 ---
# 打印执行后图的最终状态。
# 这将同时显示输入的'topic'和已写入状态的输出'joke'。
console.print("\n[bold blue]笑话生成器状态:[/bold blue]")
pprint(joke_generator_state)

#### 输出 ####
{
  'topic': 'cats',
  'joke': '猫为什么加入乐队?\n\n因为它想当"喵"克风手(打击乐手)!'
}

它返回的字典本质上是我们agent的笑话生成状态。这个简单的例子展示了我们如何向状态写入上下文。

你可以了解更多关于检查点(Checkpointing)的内容(用于保存和恢复图状态),以及人机协作(Human-in-the-loop)的内容(用于暂停工作流,以在继续之前获取人工输入)。

LangGraph中的内存写入

草稿区(Scratchpad)帮助agents在单个会话中工作,但有时agents需要跨多个会话记住信息。

  • Reflexion引入了agents在每一轮交互后进行反思并重用自我生成提示的理念。

  • Generative Agents通过总结过往agent的反馈来创建长期记忆。

内存写入(来自LangChain文档)

这些理念现已应用于ChatGPT、Cursor和Windsurf等产品中,它们能从用户交互中自动创建长期记忆。

  • 检查点(Checkpointing)会在一个线程(thread)的每一步保存图的状态。一个线程有唯一ID,通常代表一次交互------比如ChatGPT中的一次单独聊天。

  • 长期记忆允许你跨线程保留特定上下文。你可以保存单个文件(例如用户资料)或记忆集合。

  • 它使用BaseStore接口,一种键值存储。你可以在内存中使用它(如下所示),也可以在LangGraph平台部署中使用。

现在,让我们创建一个InMemoryStore,用于本 notebook 中的多个会话。

ini 复制代码
from langgraph.store.memory import InMemoryStore

# --- 初始化长期记忆存储 ---
# 创建InMemoryStore实例,它提供了一个简单的、非持久化的键值存储系统,用于当前会话内。
store = InMemoryStore()

# --- 定义用于组织的命名空间 ---
# 命名空间用于在存储中对相关数据进行逻辑分组。
# 这里,我们使用元组表示分层命名空间,它可以对应用户ID和应用上下文。
namespace = ("rlm", "joke_generator")

# --- 向内存存储写入数据 ---
# 使用`put`方法将键值对保存到指定命名空间中。
# 此操作会持久化上一步生成的笑话,使其可在不同会话或线程中检索。
store.put(
    namespace,  # 要写入的命名空间
    "last_joke",  # 数据条目的键
    {"joke": joke_generator_state["joke"]},  # 要存储的值
)

我们将在接下来的部分讨论如何从命名空间中选择上下文。目前,我们可以使用search方法查看命名空间中的项目,确认写入成功。

ini 复制代码
# 搜索命名空间以查看所有存储的项目
stored_items = list(store.search(namespace))

# 用rich格式化显示存储的项目
console.print("\n[bold green]内存中存储的项目:[/bold green]")
pprint(stored_items)

输出:

ini 复制代码
[
  Item(namespace=['rlm', 'joke_generator'], key='last_joke', 
  value={'joke': 'Why did the cat join a band?\n\nBecause it wanted to be the purr-cussionist!'},
  created_at='2025-07-24T02:12:25.936238+00:00',
  updated_at='2025-07-24T02:12:25.936238+00:00', score=None)
]

现在,让我们将所有操作嵌入到LangGraph工作流中。

我们将用两个参数编译工作流:

  • checkpointer:在一个线程的每一步保存图的状态。

  • store:跨不同线程保留上下文。

    from langgraph.checkpoint.memory import InMemorySaver from langgraph.store.base import BaseStore from langgraph.store.memory import InMemoryStore

    初始化存储组件

    checkpointer = InMemorySaver() # 用于线程级状态持久化 memory_store = InMemoryStore() # 用于跨线程内存存储

    def generate_joke(state: State, store: BaseStore) -> dict[str, str]: """具有内存感知的笑话生成。

    css 复制代码
    这个增强版本会在生成新笑话前检查内存中是否有现有笑话。
    
    参数:
        state: 包含主题的当前状态
        store: 用于持久化上下文的内存存储
        
    返回:
        包含生成的笑话的字典
    """
    # 检查内存中是否有现有笑话
    existing_jokes = list(store.search(namespace))
    if existing_jokes:
        existing_joke = existing_jokes[0].value
        print(f"现有笑话:{existing_joke}")
    else:
        print("现有笑话:无现有笑话")
    
    # 根据主题生成新笑话
    msg = llm.invoke(f"写一个关于{state['topic']}的短笑话")
    
    # 将新笑话存储到长期记忆中
    store.put(namespace, "last_joke", {"joke": msg.content})
    
    # 返回要添加到状态中的笑话
    return {"joke": msg.content}

    构建具有内存功能的工作流

    workflow = StateGraph(State)

    添加具有内存感知的笑话生成节点

    workflow.add_node("generate_joke", generate_joke)

    连接工作流组件

    workflow.add_edge(START, "generate_joke") workflow.add_edge("generate_joke", END)

    结合检查点和内存存储进行编译

    chain = workflow.compile(checkpointer=checkpointer, store=memory_store)

很好!现在我们可以简单地执行更新后的工作流,并测试启用内存功能后的效果。

ini 复制代码
# 以基于线程的配置执行工作流
config = {"configurable": {"thread_id": "1"}}
joke_generator_state = chain.invoke({"topic": "cats"}, config)

# 用rich格式化显示工作流结果
console.print("\n[bold cyan]工作流结果(线程1):[/bold cyan]")
pprint(joke_generator_state)

输出:

arduino 复制代码
现有笑话:无现有笑话

工作流结果(线程1):
{  'topic': 'cats', 
   'joke': 'Why did the cat join a band?\n\nBecause it wanted to be the purr-cussionist!'}

由于这是线程1,我们的AI agent内存中没有现有笑话,这与新线程的预期完全一致。

因为我们用检查点编译了工作流,现在可以查看图的最新状态。

ini 复制代码
# --- 检索并检查图状态 ---
# 使用`get_state`方法检索`config`中指定线程(此处为线程"1")的最新状态快照。
# 之所以能做到这一点,是因为我们用检查点编译了图。
latest_state = chain.get_state(config)

# --- 显示状态快照 ---
# 将检索到的状态打印到控制台。StateSnapshot不仅包含数据('topic'、'joke'),还包含执行元数据。
console.print("\n[bold magenta]最新图状态(线程1):[/bold magenta]")
pprint(latest_state)

看看输出:

perl 复制代码
### 我们最新状态的输出 ###
最新图状态:

StateSnapshot(
    values={
        'topic': 'cats',
        'joke': 'Why did the cat join a band?\n\nBecause it wanted to be the purr-cussionist!'
    },
    next=(),
    config={
        'configurable': {
            'thread_id': '1',
            'checkpoint_ns': '',
            'checkpoint_id': '1f06833a-53a7-65a8-8001-548e412001c4'
        }
    },
    metadata={'source': 'loop', 'step': 1, 'parents': {}},
    created_at='2025-07-24T02:12:27.317802+00:00',
    parent_config={
        'configurable': {
            'thread_id': '1',
            'checkpoint_ns': '',
            'checkpoint_id': '1f06833a-4a50-6108-8000-245cde0c2411'
        }
    },
    tasks=(),
    interrupts=()
)

可以看到,我们的状态现在显示了我们与agent的最后一次对话------在这个案例中,我们让它讲一个关于猫的笑话。

让我们用不同的ID重新运行工作流。

ini 复制代码
# 用不同的线程ID执行工作流
config = {"configurable": {"thread_id": "2"}}
joke_generator_state = chain.invoke({"topic": "cats"}, config)

# 显示跨线程内存持久化的结果
console.print("\n[bold yellow]工作流结果(线程2):[/bold yellow]")
pprint(joke_generator_state)

输出:

arduino 复制代码
现有笑话:{'joke': 'Why did the cat join a band?\n\nBecause it wanted to be the purr-cussionist!'}
工作流结果(线程2):
{'topic': 'cats', 'joke': 'Why did the cat join a band?\n\nBecause it wanted to be the purr-cussionist!'}

我们可以看到,第一个线程中的笑话已成功保存到内存中。

你可以自行了解更多关于LangMem和Ambient Agents Course的内容。

草稿区选择方法

如何从草稿区(scratchpad)中选择上下文,取决于其实现方式:

  • 如果它是一个工具(tool),agent可以通过工具调用(tool call)直接读取。

  • 如果它是agent运行时状态(runtime state)的一部分,那么你(开发者)可以决定在每一步向agent共享状态的哪些部分。这让你能精确控制暴露哪些上下文。

上下文工程的第二个组件(来自LangChain文档)

在上一步中,我们学习了如何写入LangGraph状态对象。现在,我们将学习如何从状态中选择上下文,并将其传递到下游节点的LLM调用中。

这种选择性方法让你能精确控制LLM在执行过程中看到的上下文。

python 复制代码
def generate_joke(state: State) -> dict[str, str]:
    """生成关于该主题的初始笑话。
    
    参数:
        state: 包含主题的当前状态
        
    返回:
        包含生成的笑话的字典
    """
    msg = llm.invoke(f"Write a short joke about {state['topic']}")
    return {"joke": msg.content}


def improve_joke(state: State) -> dict[str, str]:
    """通过添加文字游戏来改进现有笑话。
    
    这展示了从状态中选择上下文------我们从状态中读取现有笑话,
    并使用它生成改进版本。
    
    参数:
        state: 包含原始笑话的当前状态
        
    返回:
        包含改进后笑话的字典
    """
    print(f"初始笑话:{state['joke']}")
    
    # 从状态中选择笑话并呈现给LLM
    msg = llm.invoke(f"Make this joke funnier by adding wordplay: {state['joke']}")
    return {"improved_joke": msg.content}

为了让示例稍微复杂一点,我们现在给agent添加两个工作流:

1.生成笑话(Generate Joke)------与之前相同。

2.改进笑话(Improve Joke)------接收生成的笑话并将其优化。

这种设置将帮助我们理解LangGraph中的草稿区选择是如何工作的。现在,让我们用之前的方法编译这个工作流,并查看图的样子。

makefile 复制代码
# 构建包含两个顺序节点的工作流
workflow = StateGraph(State)

# 添加两个笑话生成节点
workflow.add_node("generate_joke", generate_joke)
workflow.add_node("improve_joke", improve_joke)

# 按顺序连接节点
workflow.add_edge(START, "generate_joke")
workflow.add_edge("generate_joke", "improve_joke")
workflow.add_edge("improve_joke", END)

# 编译工作流
chain = workflow.compile()

# 显示工作流可视化图
display(Image(chain.get_graph().draw_mermaid_png()))

我们生成的图

当我们执行这个工作流时,会得到如下结果。

ini 复制代码
# 执行工作流,查看上下文选择的实际效果
joke_generator_state = chain.invoke({"topic": "cats"})

# 用rich格式化显示最终状态
console.print("\n[bold blue]工作流最终状态:[/bold blue]")
pprint(joke_generator_state)

输出:

bash 复制代码
初始笑话:Why did the cat join a band?

Because it wanted to be the purr-cussionist!
工作流最终状态:
{
  'topic': 'cats',
  'joke': 'Why did the cat join a band?\n\nBecause it wanted to be the purr-cussionist!'}

现在我们已经执行了工作流,可以继续将其用于内存选择步骤了。

内存选择能力

如果agents能够保存记忆,它们还需要为当前任务选择相关的记忆。这在以下方面很有用:

  • 情景记忆(Episodic memories)------展示期望行为的少样本示例。

  • 程序记忆(Procedural memories)------指导行为的指令。

  • 语义记忆(Semantic memories)------提供任务相关上下文的事实或关系。

有些agents使用狭窄的、预定义的文件来存储记忆:

  • Claude Code使用CLAUDE.md

  • Cursor和Windsurf使用"规则"文件来存储指令或示例。

但当存储大量事实集合(语义记忆)时,选择会变得更困难。

  • ChatGPT有时会检索不相关的记忆,正如Simon Willison所展示的那样------ChatGPT错误地获取了他的位置并将其注入到图像中,使得上下文感觉"不再属于他"。

  • 为了改进选择,会使用嵌入(embeddings)或知识图谱(knowledge graphs)进行索引。

在上一节中,我们向图节点中的InMemoryStore写入了数据。现在,我们可以使用get方法从其中选择上下文,将相关状态拉入我们的工作流中。

ini 复制代码
from langgraph.store.memory import InMemoryStore

# 初始化内存存储
store = InMemoryStore()

# 定义用于组织记忆的命名空间
namespace = ("rlm", "joke_generator")

# 将生成的笑话存储到内存中
store.put(
    namespace,                             # 用于组织的命名空间
    "last_joke",                          # 键标识符
    {"joke": joke_generator_state["joke"]} # 要存储的值
)

# 从内存中选择(检索)笑话
retrieved_joke = store.get(namespace, "last_joke").value

# 显示检索到的上下文
console.print("\n[bold green]从内存中检索到的上下文:[/bold green]")
pprint(retrieved_joke)

输出:

vbnet 复制代码
从内存中检索到的上下文:
{'joke': 'Why did the cat join a band?\n\nBecause it wanted to be the purr-cussionist!'}

它成功地从内存中检索到了正确的笑话。

现在,我们需要编写一个合适的generate_joke函数,该函数能够:

1.接收当前状态(用于草稿区上下文)。

2.使用内存(如果我们正在执行笑话改进任务,用于获取过去的笑话)。

接下来让我们编写代码。

python 复制代码
# 初始化存储组件
checkpointer = InMemorySaver()
memory_store = InMemoryStore()


def generate_joke(state: State, store: BaseStore) -> dict[str, str]:
    """生成具有内存感知上下文选择的笑话。
    
    该函数展示了在生成新内容之前从内存中选择上下文,以确保一致性并避免重复。
    
    参数:
        state: 包含主题的当前状态
        store: 用于持久化上下文的内存存储
        
    返回:
        包含生成的笑话的字典
    """
    # 如果存在,从内存中选择之前的笑话
    prior_joke = store.get(namespace, "last_joke")
    if prior_joke:
        prior_joke_text = prior_joke.value["joke"]
        print(f"之前的笑话:{prior_joke_text}")
    else:
        print("之前的笑话:无!")

    # 生成一个与之前不同的新笑话
    prompt = (
        f"写一个关于{state['topic']}的短笑话,"
        f"但要与你之前写过的任何笑话不同:{prior_joke_text if prior_joke else '无'}"
    )
    msg = llm.invoke(prompt)

    # 将新笑话存储到内存中,供未来的上下文选择使用
    store.put(namespace, "last_joke", {"joke": msg.content})

    return {"joke": msg.content}

现在,我们可以像之前一样简单地执行这个具有内存感知的工作流。

ini 复制代码
# 构建具有内存感知的工作流
workflow = StateGraph(State)
workflow.add_node("generate_joke", generate_joke)

# 连接工作流
workflow.add_edge(START, "generate_joke")
workflow.add_edge("generate_joke", END)

# 结合检查点和内存存储进行编译
chain = workflow.compile(checkpointer=checkpointer, store=memory_store)

# 用第一个线程执行工作流
config = {"configurable": {"thread_id": "1"}}
joke_generator_state = chain.invoke({"topic": "cats"}, config)

输出:

复制代码
之前的笑话:无!

未检测到之前的笑话。现在我们可以打印最新的状态结构。

ini 复制代码
# 获取图的最新状态
latest_state = chain.get_state(config)

console.print("\n[bold magenta]最新图状态:[/bold magenta]")
pprint(latest_state)

我们的输出:

perl 复制代码
#### 最新状态的输出 ####
StateSnapshot(
    values={
        'topic': 'cats',
        'joke': "Here's a new one:\n\nWhy did the cat join a band?\n\nBecause it wanted to be the purr-cussionist!"
    },
    next=(),
    config={
        'configurable': {
            'thread_id': '1',
            'checkpoint_ns': '',
            'checkpoint_id': '1f068357-cc8d-68cb-8001-31f64daf7bb6'
        }
    },
    metadata={'source': 'loop', 'step': 1, 'parents': {}},
    created_at='2025-07-24T02:25:38.457825+00:00',
    parent_config={
        'configurable': {
            'thread_id': '1',
            'checkpoint_ns': '',
            'checkpoint_id': '1f068357-c459-6deb-8000-16ce383a5b6b'
        }
    },
    tasks=(),
    interrupts=()
)

我们从内存中获取之前的笑话,并将其传递给LLM以进行改进。

ini 复制代码
# 用第二个线程执行工作流,以展示内存持久性
config = {"configurable": {"thread_id": "2"}}
joke_generator_state = chain.invoke({"topic": "cats"}, config)

输出:

vbnet 复制代码
之前的笑话:Here is a new one:
Why did the cat join a band?
Because it wanted to be the purr-cussionist!

它已成功地从内存中获取了正确的笑话,并按预期对其进行了改进。

以上是第一篇博客的全部内容,下一篇博客中我们将继续讨论这一话题,欢迎持续关注我们。

相关推荐
阿里云云原生1 小时前
垂直和领域 Agent 的护城河:上下文工程
agent
大虫小呓2 小时前
OpenAI 的首个开源模型 ChatGPT gpt-oss 发布!重点:手机就能运行!
开源·openai
KevinZhang135793 小时前
ShadowAI 支持二维表格数据生成了
人工智能·agent·ai编程
哪吒编程3 小时前
时隔六年,OpenAI再次发布开源模型gpt-oss-120b,全网狂欢
chatgpt·openai
AI大模型4 小时前
人工智能大模型(LLMs)高效学习指南:30天系统性掌握
程序员·llm·agent
阑梦清川4 小时前
借助CNB进行dify私有化部署的教程(零成本)
aigc
AI大模型4 小时前
RAG(检索增强生成)的深度解析——如何让人工智能告别“胡说八道”?
程序员·llm·agent
用户848508146905 小时前
OpenAI重返开源!GPT-OSS本地部署完全指南
openai
百度Geek说5 小时前
AI在实际生成环境中的提效实践
aigc