docs: adding interactive graph widget (#4785)
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -53,3 +53,139 @@ The high-level components are organized into several packages, each with a speci
|
||||
| `langmem` | Agent memory management: [**short-term and long-term**](./memory.md) | `pip install -U langmem` |
|
||||
| `agentevals` | Utilities to [**evaluate agent performance**](./evals.md) | `pip install -U agentevals` |
|
||||
|
||||
## Visualize an agent graph
|
||||
|
||||
Use the following tool to visualize the graph generated by
|
||||
[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
and to view an outline of the corresponding code.
|
||||
It allows you to explore the infrastructure of the agent as defined by the presence of:
|
||||
|
||||
* [`tools`](../agents/tools.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
|
||||
* [`pre_model_hook`](../how-tos/create-react-agent-manage-message-history.ipynb): A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks.
|
||||
* `post_model_hook`: A function that is called after the model is invoked. It can be used to implement guardrails, human-in-the-loop flows, or other postprocessing tasks.
|
||||
* [`response_format`](../agents/agents.md#6-configure-structured-output): A data structure used to constrain the type of the final output, e.g., a `pydantic` `BaseModel`.
|
||||
|
||||
<div class="agent-layout">
|
||||
<div class="agent-graph-features-container">
|
||||
<div class="agent-graph-features">
|
||||
<h3 class="agent-section-title">Features</h3>
|
||||
<label><input type="checkbox" id="tools" checked> <code>tools</code></label>
|
||||
<label><input type="checkbox" id="pre_model_hook"> <code>pre_model_hook</code></label>
|
||||
<label><input type="checkbox" id="post_model_hook"> <code>post_model_hook</code></label>
|
||||
<label><input type="checkbox" id="response_format"> <code>response_format</code></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agent-graph-container">
|
||||
<h3 class="agent-section-title">Graph</h3>
|
||||
<img id="agent-graph-img" src="../assets/react_agent_graphs/0001.svg" alt="graph image" style="max-width: 100%;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
The following code snippet shows how to create the above agent (and underlying graph) with
|
||||
[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]:
|
||||
|
||||
<div class="language-python">
|
||||
<pre><code id="agent-code" class="language-python"></code></pre>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
function getCheckedValue(id) {
|
||||
return document.getElementById(id).checked ? "1" : "0";
|
||||
}
|
||||
|
||||
function getKey() {
|
||||
return [
|
||||
getCheckedValue("response_format"),
|
||||
getCheckedValue("post_model_hook"),
|
||||
getCheckedValue("pre_model_hook"),
|
||||
getCheckedValue("tools")
|
||||
].join("");
|
||||
}
|
||||
|
||||
function generateCodeSnippet({ tools, pre, post, response }) {
|
||||
const lines = [
|
||||
"from langgraph.prebuilt import create_react_agent",
|
||||
"from langchain_openai import ChatOpenAI"
|
||||
];
|
||||
|
||||
if (response) lines.push("from pydantic import BaseModel");
|
||||
|
||||
lines.push("", 'model = ChatOpenAI("o4-mini")', "");
|
||||
|
||||
if (tools) {
|
||||
lines.push(
|
||||
"def tool() -> None:",
|
||||
' """Testing tool."""',
|
||||
" ...",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
if (pre) {
|
||||
lines.push(
|
||||
"def pre_model_hook() -> None:",
|
||||
' """Pre-model hook."""',
|
||||
" ...",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
if (post) {
|
||||
lines.push(
|
||||
"def post_model_hook() -> None:",
|
||||
' """Post-model hook."""',
|
||||
" ...",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
if (response) {
|
||||
lines.push(
|
||||
"class ResponseFormat(BaseModel):",
|
||||
' """Response format for the agent."""',
|
||||
" result: str",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
lines.push("agent = create_react_agent(");
|
||||
lines.push(" model,");
|
||||
|
||||
if (tools) lines.push(" tools=[tool],");
|
||||
if (pre) lines.push(" pre_model_hook=pre_model_hook,");
|
||||
if (post) lines.push(" post_model_hook=post_model_hook,");
|
||||
if (response) lines.push(" response_format=ResponseFormat,");
|
||||
|
||||
lines.push(")", "", "agent.get_graph().draw_mermaid_png()");
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
async function render() {
|
||||
const key = getKey();
|
||||
document.getElementById("agent-graph-img").src = `../assets/react_agent_graphs/${key}.svg`;
|
||||
|
||||
const state = {
|
||||
tools: document.getElementById("tools").checked,
|
||||
pre: document.getElementById("pre_model_hook").checked,
|
||||
post: document.getElementById("post_model_hook").checked,
|
||||
response: document.getElementById("response_format").checked
|
||||
};
|
||||
|
||||
document.getElementById("agent-code").textContent = generateCodeSnippet(state);
|
||||
}
|
||||
|
||||
function initializeWidget() {
|
||||
render(); // no need for `await` here
|
||||
document.querySelectorAll(".agent-graph-features input").forEach((input) => {
|
||||
input.addEventListener("change", render);
|
||||
});
|
||||
}
|
||||
|
||||
// Init for both full reload and SPA nav (used by MkDocs Material)
|
||||
window.addEventListener("DOMContentLoaded", initializeWidget);
|
||||
document$.subscribe(initializeWidget);
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"0000": "graph TD;\n\t__start__ --> agent;\n\tagent --> __end__;",
|
||||
"0001": "graph TD;\n\t__start__ --> agent;\n\tagent -.-> __end__;\n\tagent -.-> tools;\n\ttools --> agent;",
|
||||
"0010": "graph TD;\n\t__start__ --> pre_model_hook;\n\tpre_model_hook --> agent;\n\tagent --> __end__;",
|
||||
"0011": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent -.-> __end__;\n\tagent -.-> tools;\n\tpre_model_hook --> agent;\n\ttools --> pre_model_hook;",
|
||||
"0100": "graph TD;\n\t__start__ --> agent;\n\tagent --> post_model_hook;\n\tpost_model_hook --> __end__;",
|
||||
"0101": "graph TD;\n\t__start__ --> agent;\n\tagent --> post_model_hook;\n\tpost_model_hook -.-> __end__;\n\tpost_model_hook -.-> agent;\n\tpost_model_hook -.-> tools;\n\ttools --> agent;",
|
||||
"0110": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> post_model_hook;\n\tpre_model_hook --> agent;\n\tpost_model_hook --> __end__;",
|
||||
"0111": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> post_model_hook;\n\tpost_model_hook -.-> __end__;\n\tpost_model_hook -.-> pre_model_hook;\n\tpost_model_hook -.-> tools;\n\tpre_model_hook --> agent;\n\ttools --> pre_model_hook;",
|
||||
"1000": "graph TD;\n\t__start__ --> agent;\n\tagent --> generate_structured_response;\n\tgenerate_structured_response --> __end__;",
|
||||
"1001": "graph TD;\n\t__start__ --> agent;\n\tagent -.-> generate_structured_response;\n\tagent -.-> tools;\n\ttools --> agent;\n\tgenerate_structured_response --> __end__;",
|
||||
"1010": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> generate_structured_response;\n\tpre_model_hook --> agent;\n\tgenerate_structured_response --> __end__;",
|
||||
"1011": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent -.-> generate_structured_response;\n\tagent -.-> tools;\n\tpre_model_hook --> agent;\n\ttools --> pre_model_hook;\n\tgenerate_structured_response --> __end__;",
|
||||
"1100": "graph TD;\n\t__start__ --> agent;\n\tagent --> post_model_hook;\n\tpost_model_hook --> generate_structured_response;\n\tgenerate_structured_response --> __end__;",
|
||||
"1101": "graph TD;\n\t__start__ --> agent;\n\tagent --> post_model_hook;\n\tpost_model_hook -.-> agent;\n\tpost_model_hook -.-> generate_structured_response;\n\tpost_model_hook -.-> tools;\n\ttools --> agent;\n\tgenerate_structured_response --> __end__;",
|
||||
"1110": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> post_model_hook;\n\tpost_model_hook --> generate_structured_response;\n\tpre_model_hook --> agent;\n\tgenerate_structured_response --> __end__;",
|
||||
"1111": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> post_model_hook;\n\tpost_model_hook -.-> generate_structured_response;\n\tpost_model_hook -.-> pre_model_hook;\n\tpost_model_hook -.-> tools;\n\tpre_model_hook --> agent;\n\ttools --> pre_model_hook;\n\tgenerate_structured_response --> __end__;"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
.agent-layout {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 1rem;
|
||||
align-items: flex-start;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.agent-layout h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.agent-graph-features {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
max-width: 300px;
|
||||
flex-shrink: 0;
|
||||
|
||||
border: 1px solid var(--md-default-fg-color--lightest);
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--md-default-bg-color);
|
||||
}
|
||||
|
||||
.agent-graph-features label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--md-typeset-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.agent-graph-features input[type="checkbox"] {
|
||||
accent-color: var(--md-accent-fg-color);
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.agent-graph-container {
|
||||
flex: 1 1 50%;
|
||||
max-width: 70%;
|
||||
padding: 1rem;
|
||||
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
border: 1px solid var(--md-default-fg-color--lightest);
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--md-default-bg-color);
|
||||
}
|
||||
|
||||
.agent-graph-container img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -416,3 +416,5 @@ extra_css:
|
||||
- stylesheets/version_admonitions.css
|
||||
- stylesheets/logos.css
|
||||
- stylesheets/sticky_navigation.css
|
||||
- stylesheets/agent_graph_widget.css
|
||||
|
||||
|
||||
@@ -2917,11 +2917,12 @@ dev = [
|
||||
{ name = "pytest-mock" },
|
||||
{ name = "pytest-watcher" },
|
||||
{ name = "ruff" },
|
||||
{ name = "syrupy" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "langgraph-sdk"
|
||||
version = "0.1.69"
|
||||
version = "0.1.70"
|
||||
source = { editable = "../libs/sdk-py" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
|
||||