Files
langgraph/libs/langgraph/bench/wide_state.py
T
Nuno CamposandGitHub 4c89bb39d4 Add benchmark script for typed dict version of existing wide state benchmark (#4174)
- to easily compare perf impact of using pydantic, data class, or typed
dict for same workload
2025-04-04 18:37:57 +00:00

164 lines
5.3 KiB
Python

import operator
from dataclasses import dataclass, field
from functools import partial
from random import choice
from typing import Annotated, Optional, Sequence
from langgraph.constants import END, START
from langgraph.graph.state import StateGraph
def wide_state(n: int) -> StateGraph:
@dataclass(kw_only=True)
class State:
messages: Annotated[list, operator.add] = field(default_factory=list)
trigger_events: Annotated[list, operator.add] = field(default_factory=list)
"""The external events that are converted by the graph."""
primary_issue_medium: Annotated[str, lambda x, y: y or x] = field(
default="email"
)
autoresponse: Annotated[Optional[dict], lambda _, y: y] = field(
default=None
) # Always overwrite
issue: Annotated[dict | None, lambda x, y: y if y else x] = field(default=None)
relevant_rules: Optional[list[dict]] = field(default=None)
"""SOPs fetched from the rulebook that are relevant to the current conversation."""
memory_docs: Optional[list[dict]] = field(default=None)
"""Memory docs fetched from the memory service that are relevant to the current conversation."""
categorizations: Annotated[list[dict], operator.add] = field(
default_factory=list
)
"""The issue categorizations auto-generated by the AI."""
responses: Annotated[list[dict], operator.add] = field(default_factory=list)
"""The draft responses recommended by the AI."""
user_info: Annotated[Optional[dict], lambda x, y: y if y is not None else x] = (
field(default=None)
)
"""The current user state (by email)."""
crm_info: Annotated[Optional[dict], lambda x, y: y if y is not None else x] = (
field(default=None)
)
"""The CRM information for organization the current user is from."""
email_thread_id: Annotated[
Optional[str], lambda x, y: y if y is not None else x
] = field(default=None)
"""The current email thread ID."""
slack_participants: Annotated[dict, operator.or_] = field(default_factory=dict)
"""The growing list of current slack participants."""
bot_id: Optional[str] = field(default=None)
"""The ID of the bot user in the slack channel."""
notified_assignees: Annotated[dict, operator.or_] = field(default_factory=dict)
list_fields = {
"messages",
"trigger_events",
"categorizations",
"responses",
"memory_docs",
"relevant_rules",
}
dict_fields = {
"user_info",
"crm_info",
"slack_participants",
"notified_assignees",
"autoresponse",
"issue",
}
def read_write(read: str, write: Sequence[str], input: State) -> dict:
val = getattr(input, read)
val = {val: val} if isinstance(val, str) else val
val_single = val[-1] if isinstance(val, list) else val
val_list = val if isinstance(val, list) else [val]
return {
k: val_list
if k in list_fields
else val_single
if k in dict_fields
else "".join(choice("abcdefghijklmnopqrstuvwxyz") for _ in range(n))
for k in write
}
builder = StateGraph(State)
builder.add_edge(START, "one")
builder.add_node(
"one",
partial(read_write, "messages", ["trigger_events", "primary_issue_medium"]),
)
builder.add_edge("one", "two")
builder.add_node(
"two",
partial(read_write, "trigger_events", ["autoresponse", "issue"]),
)
builder.add_edge("two", "three")
builder.add_edge("two", "four")
builder.add_node(
"three",
partial(read_write, "autoresponse", ["relevant_rules"]),
)
builder.add_node(
"four",
partial(
read_write,
"trigger_events",
["categorizations", "responses", "memory_docs"],
),
)
builder.add_node(
"five",
partial(
read_write,
"categorizations",
[
"user_info",
"crm_info",
"email_thread_id",
"slack_participants",
"bot_id",
"notified_assignees",
],
),
)
builder.add_edge(["three", "four"], "five")
builder.add_edge("five", "six")
builder.add_node(
"six",
partial(read_write, "responses", ["messages"]),
)
builder.add_conditional_edges(
"six", lambda state: END if len(state.messages) > n else "one"
)
return builder
if __name__ == "__main__":
import asyncio
import uvloop
from langgraph.checkpoint.memory import MemorySaver
graph = wide_state(1000).compile(checkpointer=MemorySaver())
input = {
"messages": [
{
str(i) * 10: {
str(j) * 10: ["hi?" * 10, True, 1, 6327816386138, None] * 5
for j in range(50)
}
for i in range(50)
}
]
}
config = {"configurable": {"thread_id": "1"}, "recursion_limit": 20000000000}
async def run():
async for c in graph.astream(input, config=config):
print(c.keys())
uvloop.install()
asyncio.run(run())