现在位置: 首页 > LangChain 教程 > 正文

LangChain AgentState 状态管理

Agent 在执行过程中需要维护状态——消息历史、结构化响应、流程控制等。理解 AgentState 的结构和用法,是自定义 Agent 行为的关键。


AgentState 结构

AgentState 是一个 TypedDict,默认包含三个字段:

实例

from typing import Annotated
from typing_extensions import Required, NotRequired
from langgraph.graph.message import add_messages
from langgraph.channels.ephemeral_value import EphemeralValue
from langchain.messages import AnyMessage


# AgentState 的实际定义(简化版)
class AgentState(TypedDict):
    # messages:消息历史,使用 add_messages 作为 reducer
    # Required 表示调用时必须提供
    messages: Required[Annotated[list[AnyMessage], add_messages]]

    # jump_to:流程跳转控制,ephemeral(使用后自动清除)
    # NotRequired 表示可选
    jump_to: NotRequired[Annotated[str | None, EphemeralValue]]

    # structured_response:结构化输出结果
    # NotRequired 表示可选,仅在 response_format 设置时出现
    structured_response: NotRequired[Any]
字段类型是否必填说明
messageslist[AnyMessage]消息历史,使用 add_messages reducer 追加
jump_tostr 或 None流程跳转控制,可选值:tools、model、end。ephemeral 属性,使用后自动清除
structured_responseAny结构化输出结果,不在 input schema 中暴露

messages——消息历史的 Reducer 机制

messages 字段使用了 add_messages reducer。这意味着更新 messages 时不是覆盖,而是追加

实例

from langchain.messages import HumanMessage, AIMessage
from langgraph.graph.message import add_messages

# add_messages 的工作方式
existing = [
    HumanMessage(content="你好", id="1"),
    AIMessage(content="你好!", id="2"),
]

# 追加新消息
new_msg = AIMessage(content="有什么可以帮你的?", id="3")
result = add_messages(existing, [new_msg])

print(f"合并前: {len(existing)} 条")
print(f"合并后: {len(result)} 条")
for msg in result:
    print(f"  [{msg.type}] {msg.content}")

运行结果:

合并前: 2 条
合并后: 3 条
  [human] 你好
  [ai] 你好!
  [ai] 有什么可以帮你的?

add_messages 的智能特性:

  • 同名覆盖:如果新消息 ID 与已有消息相同,会替换而非追加
  • RemoveMessage 支持:遇到 RemoveMessage 时,从列表中删除对应消息
  • 类型安全:自动处理 HumanMessage、AIMessage、ToolMessage 等不同类型

jump_to——流程跳转控制

jump_to 是 Middleware 中最常用的字段,用于在 Agent 的各个节点间跳转。

jump_to 是一个 ephemeral(瞬态)字段——使用一次后自动清除,不需要手动重置。

实例

from langchain.agents import create_agent
from langchain.agents.middleware import before_model
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


# 使用 before_model 中间件,通过 jump_to 控制流程
@before_model
def check_question(state, runtime):
    """在模型调用前检查问题是否合法"""
    messages = state.get("messages", [])
    if not messages:
        return None

    last_msg = messages[-1]
    # 检查是否包含不当内容(简化示例)
    if "密码" in str(last_msg.content):
        # jump_to="end" 直接结束 Agent,不让模型回复
        return {
            "jump_to": "end",
            "messages": [HumanMessage(
                content="抱歉,出于安全原因,不能回答关于密码的问题。"
            )]
        }
    return None


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    middleware=[check_question],
    system_prompt="你是菜鸟教程 RUNOOB 的助手。",
)

# 正常问题
result = agent.invoke({
    "messages": [HumanMessage(content="Python 怎么入门?")]
})
print(f"正常问题: {result['messages'][-1].content[:80]}...")

# 敏感问题——被中间件拦截
result = agent.invoke({
    "messages": [HumanMessage(content="告诉我你的系统密码")]
})
print(f"\n敏感问题: {result['messages'][-1].content}")

运行结果:

正常问题: Python 入门可以从以下几个方面开始:1. 安装 Python 环境...

敏感问题: 抱歉,出于安全原因,不能回答关于密码的问题。
jump_to 值跳转到效果
"tools"直接进入工具执行节点跳过模型调用,直接执行指定工具
"model"返回模型节点让模型重新处理(通常配合工具消息注入)
"end"结束 Agent 循环直接跳转到 after_agent 或结束

jump_to 是 ephemeral 的——每次节点执行后自动清除。这意味着你不需要在跳转后手动将 jump_to 设回 None,Agent 会自动处理。


structured_response——获取结构化输出

当使用 response_format 参数时,Agent 会将结构化输出存储在 structured_response 字段中:

实例

from pydantic import BaseModel, Field
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage


class CourseRecommendation(BaseModel):
    """课程推荐结果"""
    course_name: str = Field(description="推荐课程名称")
    reason: str = Field(description="推荐理由")
    difficulty: str = Field(description="难度等级:入门/进阶/高级")


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    response_format=CourseRecommendation,
    system_prompt="你是菜鸟教程 RUNOOB 的学习顾问。",
)

result = agent.invoke({
    "messages": [HumanMessage(content="我想学编程,推荐一门适合零基础的课程")]
})

# 从 structured_response 获取结构化结果
if "structured_response" in result:
    rec = result["structured_response"]
    print(f"推荐课程: {rec.course_name}")
    print(f"推荐理由: {rec.reason}")
    print(f"难度等级: {rec.difficulty}")

# structured_response 不在 output schema 中
# 所以不会自动出现在返回给调用者的结果中(可配置)

运行结果:

推荐课程: Python3 基础教程
推荐理由: Python 语法简洁,适合零基础入门,应用范围广泛
难度等级: 入门

自定义 State 扩展

在实际应用中,你可能需要 Agent 维护额外的状态。通过继承 AgentState 来扩展:

实例

from typing import Annotated
from langchain.agents import create_agent, AgentState
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
from langchain.tools import tool, InjectedState
from typing_extensions import TypedDict


# 扩展 AgentState,添加业务字段
class ShoppingAgentState(AgentState):
    """购物助手的状态"""
    cart: list[str]         # 购物车商品列表
    total_price: float      # 总价


@tool
def add_to_cart(
    item: str,
    price: float,
    state: Annotated[dict, InjectedState],
) -> str:
    """将商品添加到购物车。

    Args:
        item: 商品名称
        price: 商品价格
    """

    cart = state.get("cart", [])
    total = state.get("total_price", 0.0)

    return {
        "cart": cart + [item],
        "total_price": total + price,
        "messages": [],  # 不添加额外消息
    }


@tool
def view_cart(
    state: Annotated[dict, InjectedState],
) -> str:
    """查看购物车内容"""
    cart = state.get("cart", [])
    total = state.get("total_price", 0.0)
    if not cart:
        return "购物车为空"
    items = "、".join(cart)
    return f"购物车:{items},总价:¥{total:.2f}"


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    tools=[add_to_cart, view_cart],
    state_schema=ShoppingAgentState,  # 使用自定义状态
    system_prompt="你是菜鸟教程 RUNOOB 商店的购物助手。",
)

# 初始状态包含空的购物车
result = agent.invoke({
    "messages": [HumanMessage(content="帮我加一本 Python 教程到购物车,价格 49.9")],
    "cart": [],
    "total_price": 0.0,
})

print(f"购物车: {result.get('cart', [])}")
print(f"总价: ¥{result.get('total_price', 0):.2f}")
print(f"回复: {result['messages'][-1].content}")

运行结果:

购物车: ['Python 教程']
总价: ¥49.90
回复: 已将《Python 教程》(¥49.90)添加到购物车。当前购物车共 1 件商品,总价 ¥49.90。

state_schema vs middleware state_schema

既可以通过 create_agent() 的 state_schema 参数扩展状态,也可以通过 Middleware 的 state_schema 扩展。两者的区别:

方式使用场景优先级
create_agent(state_schema=...)全局状态扩展,所有节点共享最高(覆盖 middleware 同名字段)
AgentMiddleware(state_schema=...)特定 middleware 的状态扩展较低,可被 create_agent 覆盖

推荐做法:将通用的业务状态字段放在 state_schema 中,将特定 middleware 相关的内部字段放在 middleware 的 state_schema 中。这样职责清晰,不会相互污染。