欢迎光临
我们一直在努力

lLangGraph实战:状态即上下文,智能对话的四大管理法则

在构建AI应用时,我们常常听到"上下文"这个术语,但LangGraph通过"状态"这一概念,将上下文管理提升到了新的高度。本文将通过一个实战例子,深入探讨状态即上下文的核心理念,并详解四种上下文管理方法。

引言:为什么需要上下文管理?

想象一下这个场景:你正在和旅行助手聊天,已经讨论了目的地、预算和兴趣。当你说"帮我订一个那里附近的酒店"时,AI需要理解"那里"指的是之前提到的目的地,"附近"需要结合之前的兴趣点。这就是上下文的力量。

传统AI应用往往在上下文管理上力不从心,而LangGraph通过状态(State) 这一核心概念,为我们提供了一套完整的解决方案。

实战例子:智能旅行规划助手

让我们从一个完整的例子开始,逐步深入理解状态即上下文的概念:

python

import os
from typing import TypedDict, List, Annotated, Optional, Literal
from langgraph.graph import StateGraph, END, START
from langgraph.graph.message import add_messages
from langchain_openai import ChatOpenAI
from datetime import datetime

# 定义状态结构 – 这就是我们的上下文容器
class TravelState(TypedDict):
"""旅行规划的状态/上下文"""
messages: Annotated[List, add_messages] # 对话历史上下文
user_id: str # 用户身份上下文
destination: Optional[str] # 目的地上下文
budget: Optional[float] # 预算上下文
interests: List[str] # 兴趣偏好上下文
travel_dates: Optional[str] # 旅行日期上下文
current_step: str # 当前流程步骤上下文
extracted_info: dict # 已提取信息上下文
conversation_summary: str # 对话摘要上下文

状态即上下文:LangGraph的核心哲学

在LangGraph中,状态不仅仅是数据容器,更是工作流的智能记忆系统。让我们看看这个旅行助手如何使用状态管理上下文:

python

# 初始化LLM
llm = ChatOpenAI(model="gpt-3.5-turbo")

def extract_travel_info(state: TravelState):
"""提取旅行信息节点 – 展示上下文写入"""
# 获取完整的对话历史作为上下文
conversation = state["messages"]

# 使用LLM从对话中提取结构化信息
extraction_prompt = f"""
从以下对话中提取旅行信息:
{conversation}

请提取以下信息(如果提到):
1. 目的地
2. 预算(数字)
3. 兴趣(列表)
4. 旅行日期

以JSON格式返回。
"""

response = llm.invoke([{"role": "user", "content": extraction_prompt}])

# 解析响应并更新状态(写入上下文)
import json
try:
extracted = json.loads(response.content)
except:
extracted = {}

# 更新状态 – 这就是上下文写入
updates = {
"destination": extracted.get("destination"),
"budget": extracted.get("budget"),
"interests": extracted.get("interests", []),
"travel_dates": extracted.get("travel_dates"),
"extracted_info": extracted,
"current_step": "planning"
}

# 同时将提取结果添加到对话历史
updates["messages"] = [{
"role": "assistant",
"content": f"已提取您的旅行偏好:{extracted}"
}]

return updates

def generate_recommendations(state: TravelState):
"""生成推荐节点 – 展示上下文使用"""
# 基于完整上下文生成个性化推荐
prompt = f"""
基于以下旅行上下文为用户生成推荐:

用户信息:
– 目的地:{state.get('destination', '未指定')}
– 预算:{state.get('budget', '未指定')}
– 兴趣:{', '.join(state.get('interests', []))}
– 旅行日期:{state.get('travel_dates', '未指定')}

对话历史摘要:{state.get('conversation_summary', '无')}

请提供:
1. 3个景点推荐
2. 餐饮建议
3. 活动推荐
"""

response = llm.invoke([{"role": "user", "content": prompt}])

return {
"messages": [{
"role": "assistant",
"content": f"基于您的偏好,我的推荐:\\n{response.content}"
}],
"current_step": "completed"
}

四大上下文管理方法

方法一:写入 – 构建完整上下文

写入是上下文管理的基础,确保所有相关信息都被记录到状态中:

python

def collect_destination(state: TravelState):
"""收集目的地信息 – 上下文写入示例"""
# 从对话历史中获取最新的用户消息
last_user_message = None
for msg in reversed(state["messages"]):
if msg["role"] == "user":
last_user_message = msg["content"]
break

if last_user_message and "巴黎" in last_user_message:
# 写入目的地上下文
# 同时写入相关上下文(如假设的预算和兴趣)
return {
"destination": "巴黎",
"budget": 5000.0, # 假设的默认预算
"interests": ["艺术", "美食"], # 假设的兴趣
"current_step": "collecting_details",
"messages": [{
"role": "assistant",
"content": "巴黎是个好选择!您是喜欢艺术还是美食更多呢?"
}]
}

return {"messages": [{"role": "assistant", "content": "您想去哪里旅行呢?"}]}

关键点:写入不仅仅是添加数据,更是建立数据间的关联,形成丰富的上下文网络。

方法二:压缩 – 管理上下文长度

当对话历史过长时,我们需要压缩上下文以节省token并保持相关性:

python

def compress_conversation(state: TravelState, max_messages: int = 10):
"""压缩对话历史 – 上下文压缩示例"""
messages = state["messages"]

if len(messages) <= max_messages:
return state # 无需压缩

# 策略1:保留系统消息和最近对话
system_messages = [m for m in messages if m["role"] == "system"]
recent_messages = messages[-max_messages//2:] # 保留最近的一半

# 策略2:总结旧的历史
old_messages = messages[:len(messages)-max_messages//2]
summary_prompt = f"请用一段话总结以下对话的核心内容:\\n{old_messages}"

summary_response = llm.invoke([{"role": "user", "content": summary_prompt}])
summary_message = {
"role": "system",
"content": f"对话历史摘要:{summary_response.content}"
}

# 构建压缩后的消息列表
compressed_messages = system_messages + [summary_message] + recent_messages

# 更新状态
return {
"messages": compressed_messages,
"conversation_summary": summary_response.content
}

# 在图中添加压缩节点
def compression_node(state: TravelState):
"""压缩节点 – 自动触发压缩"""
if len(state["messages"]) > 15: # 超过15条消息时压缩
return compress_conversation(state)
return {} # 无更新

方法三:选择 – 智能上下文筛选

不是所有上下文对每个任务都重要,选择让我们能提取最相关的部分:

python

def select_relevant_context(state: TravelState, context_type: str):
"""根据任务类型选择相关上下文"""

if context_type == "budget_planning":
# 对于预算规划,选择与预算相关的上下文
relevant_messages = []
for msg in state["messages"]:
content = msg.get("content", "").lower()
if any(word in content for word in ["预算", "价格", "花费", "成本", "money", "budget"]):
relevant_messages.append(msg)

# 添加上下文摘要
context_summary = f"""
预算规划相关上下文:
目的地:{state.get('destination')}
当前预算:{state.get('budget')}
相关对话历史:{len(relevant_messages)}条相关消息
"""

return {
"selected_context": relevant_messages,
"context_summary": context_summary
}

elif context_type == "activity_suggestion":
# 对于活动建议,选择兴趣相关的上下文
interests = state.get("interests", [])
relevant_messages = []

for msg in state["messages"]:
content = msg.get("content", "")
if any(interest in content for interest in interests):
relevant_messages.append(msg)

return {
"selected_context": relevant_messages,
"context_summary": f"用户兴趣:{', '.join(interests)}"
}

return {"selected_context": state["messages"][-5:]} # 默认选择最近5条

# 应用选择策略的节点
def budget_advisor_node(state: TravelState):
"""预算建议节点 – 使用选择的上下文"""
# 选择与预算相关的上下文
selected = select_relevant_context(state, "budget_planning")

prompt = f"""
基于以下上下文提供预算建议:

{selected['context_summary']}

相关对话片段:
{selected['selected_context'][-3:] if selected['selected_context'] else '无'}

请提供详细的预算分配建议。
"""

response = llm.invoke([{"role": "user", "content": prompt}])

return {
"messages": [{"role": "assistant", "content": response.content}]
}

方法四:隔离 – 上下文边界管理

有些任务需要独立的上下文空间,避免信息污染:

python

def create_subgraph_for_flight_search(state: TravelState):
"""创建机票搜索子图 – 上下文隔离示例"""
# 提取机票搜索所需的最小上下文
flight_context = {
"destination": state.get("destination"),
"travel_dates": state.get("travel_dates"),
"user_id": state.get("user_id")
}

# 在隔离的上下文中执行机票搜索
# 这里不会接触到主对话的其他细节
def flight_search_subgraph(flight_state):
"""机票搜索子图 – 独立上下文"""
# 模拟API调用
flights = [
{"airline": "Airline A", "price": 800, "time": "10:00"},
{"airline": "Airline B", "price": 750, "time": "14:00"}
]

# 根据预算过滤(仅使用子图自己的上下文)
budget = state.get("budget", float('inf'))
filtered_flights = [f for f in flights if f["price"] <= budget/3] # 假设机票占预算1/3

return {
"available_flights": filtered_flights,
"search_completed": True
}

# 执行子图
flight_results = flight_search_subgraph(flight_context)

# 将结果整合回主上下文
return {
"extracted_info": {
**state.get("extracted_info", {}),
"flight_options": flight_results["available_flights"]
},
"messages": [{
"role": "assistant",
"content": f"找到{len(flight_results['available_flights'])}个航班选项"
}]
}

完整的工作流示例

让我们将这些方法整合到一个完整的旅行规划图中:

python

from langgraph.graph import StateGraph, END

def build_travel_planner():
"""构建完整的旅行规划图"""
builder = StateGraph(TravelState)

# 添加节点
builder.add_node("start_conversation", collect_destination)
builder.add_node("extract_info", extract_travel_info)
builder.add_node("compress_context", compression_node)
builder.add_node("budget_advice", budget_advisor_node)
builder.add_node("flight_search", create_subgraph_for_flight_search)
builder.add_node("make_recommendations", generate_recommendations)

# 设置流程
builder.set_entry_point("start_conversation")

# 定义边
builder.add_edge("start_conversation", "extract_info")
builder.add_conditional_edges(
"extract_info",
lambda state: "compress" if len(state.get("messages", [])) > 15 else "budget_advice"
)
builder.add_edge("compress_context", "budget_advice")
builder.add_edge("budget_advice", "flight_search")
builder.add_edge("flight_search", "make_recommendations")
builder.add_edge("make_recommendations", END)

return builder.compile()

# 使用示例
async def main():
travel_planner = build_travel_planner()

# 初始状态
initial_state = {
"messages": [
{"role": "system", "content": "你是一个专业的旅行规划助手"},
{"role": "user", "content": "我想去巴黎旅行,预算5000元"}
],
"user_id": "user123",
"destination": None,
"budget": None,
"interests": [],
"travel_dates": None,
"current_step": "start",
"extracted_info": {},
"conversation_summary": ""
}

# 执行图
result = await travel_planner.ainvoke(initial_state)

print("最终推荐:", result["messages"][-1]["content"])
print("提取的信息:", result["extracted_info"])
print("当前步骤:", result["current_step"])

四种方法的对比总结

方法目的适用场景示例
写入 记录和丰富上下文 信息收集阶段 记录用户偏好、提取结构化数据
压缩 减少上下文长度 长对话、节省token成本 总结旧历史、保留关键信息
选择 提取相关上下文 任务专业化处理 预算规划只关注财务相关对话
隔离 创建独立上下文 子任务、避免污染 机票搜索不接触餐饮偏好

最佳实践建议

  • 分层管理上下文:将上下文分为会话级、用户级、应用级

  • 适时压缩:定期检查上下文长度,避免无限增长

  • 智能选择:根据任务类型动态选择相关上下文

  • 明确隔离边界:清晰定义子任务的输入输出,避免隐式依赖

  • 结语

    LangGraph通过状态即上下文的理念,为AI应用提供了强大的上下文管理能力。掌握写入、压缩、选择和隔离这四种方法,你将能够构建出真正智能、高效且可维护的对话系统。

    上下文不再是隐式的、难以管理的负担,而是成为了我们构建智能应用的强大工具。在LangGraph的世界里,状态不仅记录了发生了什么,更指导着接下来会发生什么——这就是现代AI应用上下文管理的艺术。

    赞(0)
    未经允许不得转载:171主机测评 » lLangGraph实战:状态即上下文,智能对话的四大管理法则
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址