101 lines
3.0 KiB
Python
101 lines
3.0 KiB
Python
"""13 - Subgraphs:把一个已编译的图作为父图节点。
|
||
|
||
父图:START -> prepare -> research(subgraph) -> write_answer -> END
|
||
子图:START -> search_web -> filter_results -> END
|
||
|
||
运行:python 13_subgraphs.py
|
||
"""
|
||
|
||
from typing import TypedDict
|
||
|
||
from langgraph.graph import END, START, StateGraph
|
||
|
||
|
||
class ResearchState(TypedDict):
|
||
question: str
|
||
query: str
|
||
raw_results: list[str]
|
||
filtered_results: list[str]
|
||
answer: str
|
||
|
||
|
||
def search_web(state: ResearchState) -> dict:
|
||
print(" [子图/search_web] 搜索:", state["query"])
|
||
return {
|
||
"raw_results": [
|
||
"LangGraph 支持持久化、流式输出和人工介入",
|
||
"无关内容:今天适合散步",
|
||
"LangGraph 可以使用子图拆分复杂工作流",
|
||
]
|
||
}
|
||
|
||
|
||
def filter_results(state: ResearchState) -> dict:
|
||
print(" [子图/filter_results] 过滤结果")
|
||
return {
|
||
"filtered_results": [
|
||
item for item in state["raw_results"] if "LangGraph" in item
|
||
]
|
||
}
|
||
|
||
|
||
research_builder = StateGraph(ResearchState)
|
||
research_builder.add_node("search_web", search_web)
|
||
research_builder.add_node("filter_results", filter_results)
|
||
research_builder.add_edge(START, "search_web")
|
||
research_builder.add_edge("search_web", "filter_results")
|
||
research_builder.add_edge("filter_results", END)
|
||
research_graph = research_builder.compile()
|
||
|
||
|
||
def prepare(state: ResearchState) -> dict:
|
||
print("[父图/prepare] 准备查询")
|
||
return {"query": state["question"].strip()}
|
||
|
||
|
||
def write_answer(state: ResearchState) -> dict:
|
||
print("[父图/write_answer] 生成回答")
|
||
evidence = "\n".join(f"- {item}" for item in state["filtered_results"])
|
||
return {"answer": f"问题:{state['question']}\n参考资料:\n{evidence}"}
|
||
|
||
|
||
parent_builder = StateGraph(ResearchState)
|
||
parent_builder.add_node("prepare", prepare)
|
||
# 编译后的子图可以直接作为一个父图节点;双方共享同一 State schema。
|
||
parent_builder.add_node("research", research_graph)
|
||
parent_builder.add_node("write_answer", write_answer)
|
||
parent_builder.add_edge(START, "prepare")
|
||
parent_builder.add_edge("prepare", "research")
|
||
parent_builder.add_edge("research", "write_answer")
|
||
parent_builder.add_edge("write_answer", END)
|
||
graph = parent_builder.compile()
|
||
|
||
|
||
def main() -> None:
|
||
initial: ResearchState = {
|
||
"question": "LangGraph 为什么适合复杂 Agent?",
|
||
"query": "",
|
||
"raw_results": [],
|
||
"filtered_results": [],
|
||
"answer": "",
|
||
}
|
||
|
||
print("=== 普通调用 ===")
|
||
result = graph.invoke(initial)
|
||
print("\n", result["answer"])
|
||
|
||
print("\n=== Streaming:包含子图内部事件 ===")
|
||
for part in graph.stream(
|
||
initial,
|
||
stream_mode="updates",
|
||
subgraphs=True,
|
||
version="v2",
|
||
):
|
||
if part["type"] == "updates":
|
||
location = "父图" if not part["ns"] else f"子图 {part['ns']}"
|
||
print(f"{location}: {list(part['data'])}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|