Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions langgraph-crusoe/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.env
__pycache__/
*.pyc
.DS_Store
85 changes: 85 additions & 0 deletions langgraph-crusoe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# LangGraph × Crusoe AI

Run multi-step agentic pipelines on [Crusoe Managed Inference](https://www.crusoe.ai/cloud/managed-inference) using LangGraph — ultra-low latency, powered by MemoryAlloy™.

## What this does

A 3-node research pipeline built with LangGraph:
Research → Analysis → Summarize

Each node calls Crusoe Managed Inference independently. LangGraph manages state between nodes — no manual plumbing required.

## Prerequisites

- Python 3.10+
- A Crusoe Cloud account → [console.crusoecloud.com](https://console.crusoecloud.com)
- Inference API key (Intelligence API Keys section under Security in the console)

## Setup

```bash
pip install -r requirements.txt
export CRUSOE_API_KEY="your-api-key"
```

## Run the example

```bash
python examples/research_agent.py
```

## Local testing (no Crusoe account needed)

The agent automatically falls back to Groq if `CRUSOE_API_KEY` is not set. Groq is free and OpenAI-compatible — identical behavior.

```bash
pip install langchain-groq
export GROQ_API_KEY="your-groq-key" # free at console.groq.com
python examples/research_agent.py
```

## How it works

```python
from agent import run_research_agent

result = run_research_agent("GPU memory optimization for LLM inference")
print(result["summary"])
```

The graph wires three nodes together:

| Node | Role |
|------|------|
| `research` | Gathers key facts about the topic |
| `analysis` | Extracts 3 insights and open questions |
| `summarize` | Produces a clean 3-paragraph summary |

## Swap the model

Change the model string in `agent.py` to any model available on [Crusoe Intelligence Foundry](https://console.crusoecloud.com/foundry/models):

```python
return ChatCrusoe(
model="deepseek-ai/DeepSeek-R1-0528",
temperature=0.3,
max_tokens=1024,
)
```

## Extend the pipeline

Add nodes to the graph in `agent.py`:

```python
graph.add_node("fact_check", fact_check_node)
graph.add_edge("analysis", "fact_check")
graph.add_edge("fact_check", "summarize")
```

LangGraph handles state passing. You just write the node logic.

## Related

- [langchain-crusoe](../langchain-crusoe/) — LangChain integration for Crusoe Managed Inference
- [Crusoe Managed Inference Docs](https://docs.crusoecloud.com/managed-inference/overview)
102 changes: 102 additions & 0 deletions langgraph-crusoe/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"""
LangGraph multi-node research agent.
Designed for Crusoe Managed Inference (OpenAI-compatible).
Tested locally with Groq as a drop-in replacement.
"""
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langchain_core.messages import HumanMessage, SystemMessage


class AgentState(TypedDict):
messages: Annotated[list, add_messages]
topic: str
analysis: str
summary: str


def get_llm():
"""
Returns a ChatCrusoe instance for production use.
For local testing, we use ChatGroq as a drop-in replacement
since both are OpenAI-compatible.
"""
import os
if os.getenv("CRUSOE_API_KEY"):
from langchain_crusoe import ChatCrusoe
return ChatCrusoe(
model="meta-llama/Llama-3.3-70B-Instruct",
temperature=0.3,
max_tokens=1024,
)
else:
from langchain_groq import ChatGroq
return ChatGroq(
model="llama-3.3-70b-versatile",
temperature=0.3,
max_tokens=1024,
)


def research_node(state: AgentState) -> AgentState:
"""Node 1: gather key facts about the topic."""
llm = get_llm()
response = llm.invoke([
SystemMessage(content="You are a research assistant. Gather key facts and context about the given topic. Be thorough and factual."),
HumanMessage(content=f"Research this topic and return key facts: {state['topic']}")
])
return {"messages": [response]}


def analysis_node(state: AgentState) -> AgentState:
"""Node 2: analyze the research and extract insights."""
llm = get_llm()
prior_research = state["messages"][-1].content
response = llm.invoke([
SystemMessage(content="You are an analyst. Given research notes, identify the 3 most important insights and any open questions."),
HumanMessage(content=f"Analyze this research:\n\n{prior_research}")
])
return {"messages": [response], "analysis": response.content}


def summarize_node(state: AgentState) -> AgentState:
"""Node 3: produce a clean, concise final summary."""
llm = get_llm()
response = llm.invoke([
SystemMessage(content="You are a writer. Produce a clear, 3-paragraph summary from the analysis provided. Use plain language."),
HumanMessage(content=f"Summarize this analysis:\n\n{state['analysis']}")
])
return {"messages": [response], "summary": response.content}


def build_research_graph():
"""Build and compile the 3-node research graph."""
graph = StateGraph(AgentState)

graph.add_node("research", research_node)
graph.add_node("analysis", analysis_node)
graph.add_node("summarize", summarize_node)

graph.set_entry_point("research")
graph.add_edge("research", "analysis")
graph.add_edge("analysis", "summarize")
graph.add_edge("summarize", END)

return graph.compile()


def run_research_agent(topic: str) -> dict:
"""Run the full pipeline on a topic."""
graph = build_research_graph()
result = graph.invoke({
"topic": topic,
"messages": [],
"analysis": "",
"summary": ""
})
return {
"topic": topic,
"analysis": result["analysis"],
"summary": result["summary"],
}
35 changes: 35 additions & 0 deletions langgraph-crusoe/examples/research_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
Example: Run the LangGraph research agent on Crusoe Managed Inference.

For production (Crusoe):
export CRUSOE_API_KEY="your-api-key"

For local testing (Groq - free):
export GROQ_API_KEY="your-groq-key"

Then run:
python examples/research_agent.py
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from dotenv import load_dotenv
load_dotenv()

from agent import run_research_agent

if __name__ == "__main__":
topic = "GPU memory optimization techniques for large language model inference"

print(f"\nTopic: {topic}")
print("=" * 60)
print("Running 3-node LangGraph pipeline: Research → Analysis → Summarize")
print("=" * 60)

result = run_research_agent(topic)

print("\n📊 ANALYSIS:")
print(result["analysis"])
print("\n📝 SUMMARY:")
print(result["summary"])
6 changes: 6 additions & 0 deletions langgraph-crusoe/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
langchain-crusoe>=0.1.0
langgraph>=0.2.0
langchain-core>=0.3.0
langchain-openai>=0.1.0
python-dotenv
groq