langgraph-functional-api

LangGraph Functional API (Python) — build stateful agent workflows with @entrypoint and @task decorators. Imperative Python style with LangGraph persistence, streaming, HITL, and durable execution. Ideal for wrapping existing agents (CrewAI, AutoGen, Strands) or complex parallel task logic.

11 stars

Best use case

langgraph-functional-api is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

LangGraph Functional API (Python) — build stateful agent workflows with @entrypoint and @task decorators. Imperative Python style with LangGraph persistence, streaming, HITL, and durable execution. Ideal for wrapping existing agents (CrewAI, AutoGen, Strands) or complex parallel task logic.

Teams using langgraph-functional-api should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/langgraph-functional-api/SKILL.md --create-dirs "https://raw.githubusercontent.com/enuno/claude-command-and-control/main/skills/langgraph-functional-api/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/langgraph-functional-api/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How langgraph-functional-api Compares

Feature / Agentlanggraph-functional-apiStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

LangGraph Functional API (Python) — build stateful agent workflows with @entrypoint and @task decorators. Imperative Python style with LangGraph persistence, streaming, HITL, and durable execution. Ideal for wrapping existing agents (CrewAI, AutoGen, Strands) or complex parallel task logic.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# LangGraph Functional API Skill

Expert assistance for the LangGraph **Functional API**: imperative, Python-native agent workflows using `@entrypoint` and `@task` decorators. Gets you LangGraph persistence, streaming, and human-in-the-loop with minimal boilerplate — especially useful for wrapping existing agents or frameworks.

**When to choose Functional API over Graph API:**
- You're wrapping an existing agent (CrewAI, AutoGen, Strands, etc.)
- Your workflow is naturally imperative (sequential Python logic with branches)
- You need parallel task execution without defining a graph topology
- You want to add persistence/streaming to an agent you didn't write in LangGraph

Full corpus: `../langgraph/references/llms-txt.md` (5.4 MB) and `../../langchain-deepagents/references/llms-full.md` (10 MB).

## When to Use This Skill

Activate when:
- **Writing @entrypoint workflows** — defining the top-level entry to a LangGraph application
- **Defining @task functions** — wrapping individual operations with checkpointing and retries
- **Running tasks in parallel** — invoking multiple tasks concurrently and awaiting results
- **Wrapping third-party agents** — integrating CrewAI, AutoGen, Strands, or any framework
- **Configuring durable execution** — choosing `exit`, `async`, or `sync` durability modes
- **Using tasks inside Graph API nodes** — mixing both APIs in one graph
- **Handling RunControl / GraphDrained** — controlling graph execution lifecycle programmatically
- **Streaming from functional workflows** — getting token-level or state-level streaming output

## Quick Reference

### Minimal @entrypoint + @task

```python
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.func import entrypoint, task

@task
def fetch_data(query: str) -> str:
    return call_api(query)  # Any IO operation

@task
def process_data(raw: str) -> str:
    return transform(raw)

@entrypoint(checkpointer=InMemorySaver())
def my_workflow(inputs: dict) -> dict:
    raw = fetch_data(inputs["query"]).result()
    processed = process_data(raw).result()
    return {"output": processed}

# Invoke with thread_id for persistence
result = my_workflow.invoke(
    {"query": "hello"},
    config={"configurable": {"thread_id": "1"}},
)
```

### Parallel task execution

```python
from langgraph.func import entrypoint, task

@task
def search_web(query: str) -> str:
    return web_search(query)

@task
def search_docs(query: str) -> str:
    return doc_search(query)

@entrypoint(checkpointer=InMemorySaver())
def research_workflow(inputs: dict) -> dict:
    # Launch both tasks concurrently
    web_future = search_web(inputs["query"])
    docs_future = search_docs(inputs["query"])

    # Collect results (blocks until both done)
    web_result = web_future.result()
    docs_result = docs_future.result()

    return {"web": web_result, "docs": docs_result}
```

### Task retry policy

```python
from langgraph.func import entrypoint, task
from langgraph.types import RetryPolicy

@task(retry=RetryPolicy(max_attempts=3, backoff_factor=2.0))
def flaky_api_call(payload: dict) -> dict:
    return requests.post(API_URL, json=payload).json()

@entrypoint(checkpointer=InMemorySaver())
def workflow(inputs: dict) -> dict:
    result = flaky_api_call(inputs).result()
    return {"result": result}
```

### Durable execution modes

```python
from langgraph.runtime import RunControl

# Choose durability level — trade-off: performance vs crash recovery
control = RunControl(
    durability="sync"    # "exit" | "async" | "sync"
    # exit: fastest, saves only at exit (no mid-run crash recovery)
    # async: saves asynchronously (good balance)
    # sync: saves before every step (slowest, most durable)
)
```

### Human-in-the-loop interrupt in a task

```python
from langgraph.types import interrupt, Command
from langgraph.func import entrypoint, task

@task
def get_approval(action: str) -> str:
    return interrupt({"prompt": f"Approve: {action}?"})

@entrypoint(checkpointer=InMemorySaver())
def workflow(inputs: dict) -> dict:
    decision = get_approval(inputs["action"]).result()
    if decision == "yes":
        return {"status": "approved"}
    return {"status": "rejected"}

# Resume after interrupt
workflow.invoke(
    Command(resume="yes"),
    config={"configurable": {"thread_id": "1"}},
)
```

### Wrap a third-party agent (Strands, CrewAI, AutoGen)

```python
from langgraph.func import entrypoint
from langgraph.checkpoint.memory import InMemorySaver

# Example: wrap a Strands agent
from strands import Agent as StrandsAgent
from strands_tools import http_request

strands_agent = StrandsAgent(tools=[http_request])

@entrypoint(checkpointer=InMemorySaver())
def strands_workflow(inputs: dict) -> dict:
    # Your existing agent runs inside @entrypoint
    # Gets LangSmith persistence, streaming, HITL for free
    result = strands_agent(inputs["prompt"])
    return {"output": str(result)}

# Now deployable to LangSmith with full observability
```

### Tasks inside Graph API nodes (mixing APIs)

```python
from langgraph.graph import StateGraph, START
from langgraph.func import task
from langgraph.types import RetryPolicy

@task(retry=RetryPolicy(max_attempts=2))
def llm_call(prompt: str) -> str:
    return llm.invoke(prompt)

# Use @task inside a StateGraph node
def my_node(state: State) -> State:
    # Convert node operations to tasks for granular checkpointing
    result = llm_call(state["input"]).result()
    return {"output": result}

graph = StateGraph(State)
graph.add_node("my_node", my_node)
```

### Streaming from an @entrypoint

```python
# Functional API supports the same stream modes as Graph API
config = {"configurable": {"thread_id": "1"}}

for chunk in my_workflow.stream(inputs, config, stream_mode="updates"):
    print(chunk)

for chunk in my_workflow.stream(inputs, config, stream_mode="messages"):
    print(chunk)  # LLM tokens
```

## Functional API Concepts

| Concept | Decorator/Type | Notes |
|---------|---------------|-------|
| Workflow entry | `@entrypoint(checkpointer=...)` | Top-level callable; required for persistence |
| Unit of work | `@task` | Individually checkpointed; retryable |
| Invoke | `workflow.invoke(inputs, config)` | Blocking call |
| Stream | `workflow.stream(inputs, config, stream_mode=...)` | Streaming call |
| Parallel | Launch multiple tasks, call `.result()` to collect | Like `asyncio.gather` |
| Retry | `@task(retry=RetryPolicy(...))` | Per-task retry logic |
| Durability | `RunControl(durability="sync\|async\|exit")` | Checkpoint frequency |
| Interrupt | `interrupt(payload)` inside task | Pause for human input |
| Resume | `workflow.invoke(Command(resume=value), config)` | Continue after interrupt |
| Third-party | Any callable inside `@entrypoint` | Wrap CrewAI, AutoGen, etc. |

## Functional API vs Graph API

| Need | Use |
|------|-----|
| Explicit graph topology / visualization | Graph API |
| Imperative Python logic | Functional API |
| Wrapping an existing agent | Functional API |
| Named, inspectable stages | Graph API |
| Parallel tasks with dynamic count | Functional API |
| Complex conditional branching | Graph API |
| Minimal boilerplate | Functional API |
| Fan-out with `Send` | Graph API |

## Reference Files

| File | Location |
|------|----------|
| LangGraph Python docs index | `../langgraph/references/llms.md` |
| 1473-page corpus summaries | `../langgraph/references/llms-txt.md` |
| Full content + all code | `../../langchain-deepagents/references/llms-full.md` |

Key doc pages: `docs.langchain.com/oss/python/langgraph/functional-api`, `/use-functional-api`, `/choosing-apis`, `/durable-execution`

Related Skills

We are still matching the closest adjacent skills for this page. In the meantime, continue through the full directory.