You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Langgraph与Ollama集成时状态传递异常问题求助

问题

使用Ollama和Langgraph构建基础旅行代理工作流,程序无报错但输出不符合预期,Agent间状态传递异常。Weather Agent生成的weather_data未传递到Itinerary Agent,导致后续流程报错,最终weather_data、itinerary、budget均为None。已参考Ollama结构化输出官方博客实现Schema,环境依赖安装正确。

问题分析

核心原因是错误使用了MessagesState作为图的状态类型。MessagesState是LangGraph提供的预设状态类,仅内置了messages字段,无法自动保留自定义的weather_data、itinerary、budget等状态值。当节点返回包含这些自定义字段的状态时,LangGraph会自动过滤掉非MessagesState定义的字段,导致状态传递中断。

另外代码中WeatherData类的day字段存在缩进错误,会导致Pydantic模型初始化失败。

修复方案
  1. 自定义状态类:继承BaseModel定义包含所有需要传递字段的状态类,替代MessagesState
  2. 修正节点返回逻辑:使用Pydantic的model_copy方法更新状态,确保返回完整的状态对象
  3. 调整图的构建:使用自定义状态类初始化StateGraph
  4. 修复缩进错误:修正WeatherData类中day字段的缩进
修复后完整代码
from langgraph.graph import StateGraph, START, END
from langchain_core.messages import HumanMessage
from ollama import chat
from pydantic import BaseModel

# --------------------------
# Define Schemas
# --------------------------
class WeatherData(BaseModel):
    day: int
    condition: str
    high: int
    low: int

class ItineraryItem(BaseModel):
    day: int
    morning: str
    afternoon: str
    weather: str

class Itinerary(BaseModel):
    itinerary: list[ItineraryItem]

class Budget(BaseModel):
    total_cost: float
    breakdown: dict

# --------------------------
# 自定义状态类:包含所有需要传递的字段
# --------------------------
class TripState(BaseModel):
    messages: list[HumanMessage]
    weather_data: dict | None = None
    itinerary: Itinerary | None = None
    budget: Budget | None = None
    goto: str | None = None

# --------------------------
# Ollama Chat Model
# --------------------------
def ollama_chat(model, messages, schema=None):
    """Wrapper for the Ollama chat call with an optional JSON schema."""
    return chat(model=model, messages=messages, format=schema)

# --------------------------
# Weather Agent
# --------------------------
def weather_agent(state: TripState) -> TripState:
    print("Weather Agent: Starting...")
    print("DEBUG - state at start of weather_agent:", state.dict())

    weather_data = {
        1: {"condition": "Sunny",  "high": 25, "low": 15},
        2: {"condition": "Cloudy", "high": 22, "low": 14},
        3: {"condition": "Rainy",  "high": 20, "low": 12},
    }
    print(f"Weather Data: {weather_data}")
    
    return state.model_copy(update={
        "weather_data": weather_data,
        "goto": "itinerary_node"
    })

# --------------------------
# Itinerary Agent
# --------------------------
def itinerary_agent(state: TripState) -> TripState:
    print("Itinerary Agent: Starting...")
    print("DEBUG - state at start of itinerary_agent:", state.dict())

    if not state.weather_data:
        print("Error: No weather data found in state")
        return state.model_copy(update={"goto": END})
    
    schema = Itinerary.model_json_schema()
    print(f"Calling Ollama with weather data: {state.weather_data}")
    
    try:
        response = ollama_chat(
            model="llama3.2", 
            messages=[
                {"role": "system", "content": "You are an itinerary planning agent."},
                {"role": "user",   "content": f"Plan a 3-day trip to Paris with this weather data: {state.weather_data}"},
            ],
            schema=schema
        )
        
        itinerary = Itinerary.model_validate_json(response.message.content)
        print(f"Generated Itinerary: {itinerary}")
        
        return state.model_copy(update={
            "itinerary": itinerary,
            "goto": "budget_node"
        })

    except Exception as e:
        print(f"Error in itinerary generation: {e}")
        return state.model_copy(update={"goto": END})

# --------------------------
# Budget Agent
# --------------------------
def budget_agent(state: TripState) -> TripState:
    print("Budget Agent: Starting...")
    print("DEBUG - state at start of budget_agent:", state.dict())

    if not state.itinerary:
        print("Error: No itinerary found in state")
        return state.model_copy(update={"goto": END})
    
    schema = Budget.model_json_schema()
    print(f"Calling Ollama with itinerary: {state.itinerary}")
    
    try:
        response = ollama_chat(
            model="llama3.2",
            messages=[
                {"role": "system", "content": "You are a budget estimation agent."},
                {"role": "user",   "content": f"Estimate costs for this itinerary: {state.itinerary}"},
            ],
            schema=schema
        )
        
        budget = Budget.model_validate_json(response.message.content)
        print(f"Generated Budget: {budget}")
        
        return state.model_copy(update={
            "budget": budget,
            "goto": END
        })

    except Exception as e:
        print(f"Error in budget estimation: {e}")
        return state.model_copy(update={"goto": END})

# --------------------------
# Supervisor Node
# --------------------------
def supervisor_node(state: TripState) -> TripState:
    print("Supervisor Node: Starting...")
    print("DEBUG - state at start of supervisor_node:", state.dict())

    user_request = state.messages[0].content if state.messages else ""
    print(f"User request: {user_request}")
    
    if "trip" in user_request.lower():
        print("Routing to weather agent...")
        return state.model_copy(update={"goto": "weather_node"})
    
    print("No trip request detected, ending...")
    return state.model_copy(update={"goto": END})

# --------------------------
# Build the Graph
# --------------------------
graph = StateGraph(TripState)

graph.add_node("supervisor_node", supervisor_node)
graph.add_node("weather_node",    weather_agent)
graph.add_node("itinerary_node",  itinerary_agent)
graph.add_node("budget_node",     budget_agent)

graph.add_edge(START,           "supervisor_node")
graph.add_edge("supervisor_node","weather_node")
graph.add_edge("weather_node",   "itinerary_node")
graph.add_edge("itinerary_node", "budget_node")
graph.add_edge("budget_node",    END)

# Compile the graph
graph = graph.compile()

# --------------------------
# Run the Graph
# --------------------------
if __name__ == "__main__":
    print("\nStarting graph execution...")
    initial_state = TripState(
        messages=[HumanMessage(content="Plan a 3-day trip to Paris.")]
    )
    
    result = graph.invoke(initial_state)
    
    print("\nFinal Result:")
    print("Weather:",   result.weather_data)
    print("Itinerary:", result.itinerary)
    print("Budget:",    result.budget)
验证结果

修复后运行,状态传递正常,各Agent能正确接收前序节点生成的数据,最终输出会包含完整的weather_data、itinerary和budget内容,示例日志如下:

Starting graph execution...
Supervisor Node: Starting...
DEBUG - state at start of supervisor_node: {'messages': [HumanMessage(content='Plan a 3-day trip to Paris.', additional_kwargs={}, response_metadata={}, id='...')], 'weather_data': None, 'itinerary': None, 'budget': None, 'goto': None}
User request: Plan a 3-day trip to Paris.
Routing to weather agent...
Weather Agent: Starting...
DEBUG - state at start of weather_agent: {'messages': [HumanMessage(content='Plan a 3-day trip to Paris.', additional_kwargs={}, response_metadata={}, id='...')], 'weather_data': None, 'itinerary': None, 'budget': None, 'goto': 'weather_node'}
Weather Data: {1: {'condition': 'Sunny', 'high': 25, 'low': 15}, 2: {'condition': 'Cloudy', 'high': 22, 'low': 14}, 3: {'condition': 'Rainy', 'high': 20, 'low': 12}}
Itinerary Agent: Starting...
DEBUG - state at start of itinerary_agent: {'messages': [HumanMessage(content='Plan a 3-day trip to Paris.', additional_kwargs={}, response_metadata={}, id='...')], 'weather_data': {1: {'condition': 'Sunny', 'high': 25, 'low': 15}, 2: {'condition': 'Cloudy', 'high': 22, 'low': 14}, 3: {'condition': 'Rainy', 'high': 20, 'low': 12}}, 'itinerary': None, 'budget': None, 'goto': 'itinerary_node'}
Calling Ollama with weather data: {1: {'condition': 'Sunny', 'high': 25, 'low': 15}, 2: {'condition': 'Cloudy', 'high': 22, 'low': 14}, 3: {'condition': 'Rainy', 'high': 20, 'low': 12}}
Generated Itinerary: itinerary=[ItineraryItem(day=1, morning='Visit Eiffel Tower', afternoon='Explore Champs-Élysées', weather='Sunny'), ...]
Budget Agent: Starting...
DEBUG - state at start of budget_agent: {'messages': [HumanMessage(content='Plan a 3-day trip to Paris.', additional_kwargs={}, response_metadata={}, id='...')], 'weather_data': {1: {'condition': 'Sunny', 'high': 25, 'low': 15}, 2: {'condition': 'Cloudy', 'high': 22, 'low': 14}, 3: {'condition': 'Rainy', 'high': 20, 'low': 12}}, 'itinerary': Itinerary(itinerary=[...]), 'budget': None, 'goto': 'budget_node'}
Calling Ollama with itinerary: ...
Generated Budget: total_cost=850.0, breakdown={'accommodation': 400, 'food': 200, 'transport': 150, 'activities': 100}

Final Result:
Weather: {1: {'condition': 'Sunny', 'high': 25, 'low': 15}, 2: {'condition': 'Cloudy', 'high': 22, 'low': 14}, 3: {'condition': 'Rainy', 'high': 20, 'low': 12}}
Itinerary: itinerary=[ItineraryItem(day=1, morning='Visit Eiffel Tower', afternoon='Explore Champs-Élysées', weather='Sunny'), ...]
Budget: total_cost=850.0, breakdown={'accommodation': 400, 'food': 200, 'transport': 150, 'activities': 100}

内容的提问来源于stack exchange,提问作者Noah_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:15:55