Skip to content

Commit de57b8b

Browse files
committed
Add README documentation for each Functional API sample
Each sample now has its own README explaining: - Overview and architecture diagram - Key code patterns with examples - Why Temporal adds value - Running instructions - Customization examples Samples documented: - hello_world: Basic @entrypoint and @task usage - react_agent: Tool-calling agent with observation loop - reflection: Generate-critique-revise iteration - agentic_rag: Adaptive retrieval with query rewriting - deep_research: Parallel search and synthesis - plan_and_execute: Structured plan execution - supervisor: Multi-agent coordination - human_in_the_loop: interrupt() for approval workflows
1 parent 4fc7d31 commit de57b8b

File tree

8 files changed

+1061
-0
lines changed

8 files changed

+1061
-0
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Agentic RAG (Functional API)
2+
3+
Retrieval-Augmented Generation with document grading and query rewriting for improved answer quality.
4+
5+
## Overview
6+
7+
Unlike simple RAG, agentic RAG evaluates retrieved documents and adapts:
8+
9+
1. **Retrieve** - Fetch documents for the query
10+
2. **Grade** - Evaluate document relevance
11+
3. **Rewrite** - If not relevant, reformulate query
12+
4. **Generate** - Create answer from relevant documents
13+
14+
## Architecture
15+
16+
```
17+
User Question
18+
19+
20+
┌─────────────────┐
21+
│retrieve_documents│◄─────────┐
22+
│ (task) │ │
23+
└────────┬─────────┘ │
24+
│ │
25+
▼ │
26+
┌─────────────────┐ │
27+
│ grade_documents │ │
28+
│ (task) │ │
29+
└────────┬────────┘ │
30+
│ │
31+
▼ │
32+
Relevant? │
33+
│ │
34+
YES │ NO │
35+
│ │ │
36+
│ ▼ │
37+
│ ┌──────────────┐ │
38+
│ │ rewrite_query│──┘
39+
│ │ (task) │
40+
│ └──────────────┘
41+
42+
┌─────────────────┐
43+
│ generate_answer │
44+
│ (task) │
45+
└─────────────────┘
46+
```
47+
48+
## Key Code
49+
50+
### Adaptive Retrieval Loop
51+
52+
```python
53+
@entrypoint()
54+
async def agentic_rag_entrypoint(question: str, max_retries: int = 2) -> dict:
55+
current_query = question
56+
57+
for attempt in range(max_retries + 1):
58+
# Retrieve documents
59+
documents = await retrieve_documents(current_query)
60+
61+
# Grade for relevance
62+
grade_result = await grade_documents(question, documents)
63+
64+
if grade_result["relevant"]:
65+
# Generate answer with relevant docs
66+
answer = await generate_answer(question, documents)
67+
return {"answer": answer, "status": "success"}
68+
69+
# Rewrite query and retry
70+
if attempt < max_retries:
71+
current_query = await rewrite_query(current_query)
72+
73+
# Best-effort answer with all retrieved docs
74+
return {"answer": await generate_answer(question, all_docs), "status": "max_retries"}
75+
```
76+
77+
### Document Grading
78+
79+
```python
80+
@task
81+
def grade_documents(question: str, documents: list) -> dict:
82+
"""Evaluate if documents are relevant to the question."""
83+
relevant_docs = [doc for doc in documents if is_relevant(doc, question)]
84+
return {
85+
"relevant": len(relevant_docs) >= threshold,
86+
"relevant_count": len(relevant_docs)
87+
}
88+
```
89+
90+
## Why Temporal?
91+
92+
- **Reliability**: Multiple retrieval attempts complete reliably
93+
- **Observability**: See which queries succeeded/failed
94+
- **Retries**: Handle API failures in retrieval/LLM calls
95+
- **Audit trail**: Track query rewrites in workflow history
96+
97+
## Running the Sample
98+
99+
1. Start Temporal:
100+
```bash
101+
temporal server start-dev
102+
```
103+
104+
2. Run with API key:
105+
```bash
106+
export OPENAI_API_KEY=your-key
107+
uv run langgraph_plugin/functional_api/agentic_rag/run_worker.py
108+
```
109+
110+
3. Execute a question:
111+
```bash
112+
uv run langgraph_plugin/functional_api/agentic_rag/run_workflow.py
113+
```
114+
115+
## Customization
116+
117+
### Adjust Relevance Threshold
118+
119+
```python
120+
@task
121+
def grade_documents(question: str, documents: list) -> dict:
122+
# Require more relevant documents
123+
return {"relevant": relevant_count >= 3}
124+
```
125+
126+
### Add Query Transformation Strategies
127+
128+
```python
129+
@task
130+
def rewrite_query(query: str) -> str:
131+
strategies = ["simplify", "expand", "rephrase"]
132+
# Try different rewriting approaches
133+
...
134+
```
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Deep Research Agent (Functional API)
2+
3+
A multi-step research agent that plans queries, executes parallel searches, and synthesizes findings into a comprehensive report.
4+
5+
## Overview
6+
7+
The deep research pattern:
8+
9+
1. **Plan** - Generate research queries based on topic
10+
2. **Search** - Execute searches in parallel
11+
3. **Evaluate** - Check if results are sufficient
12+
4. **Iterate** - Refine and search again if needed
13+
5. **Synthesize** - Create final report
14+
15+
## Architecture
16+
17+
```
18+
Research Topic
19+
20+
21+
┌──────────────┐
22+
│ plan_research│
23+
│ (task) │
24+
└──────┬───────┘
25+
26+
27+
┌──────────────────────────────┐
28+
│ execute_search (task) │
29+
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐│ ← Parallel execution
30+
│ │ Q1 │ │ Q2 │ │ Q3 │ │ Q4 ││
31+
│ └────┘ └────┘ └────┘ └────┘│
32+
└──────────────┬───────────────┘
33+
34+
35+
Enough results?
36+
37+
NO │ YES
38+
│ │
39+
┌──────┘ │
40+
│ ▼
41+
│ ┌──────────────────┐
42+
│ │ synthesize_report│
43+
│ │ (task) │
44+
│ └──────────────────┘
45+
46+
└──► Plan more queries...
47+
```
48+
49+
## Key Code
50+
51+
### Parallel Search Execution
52+
53+
```python
54+
@entrypoint()
55+
async def deep_research_entrypoint(topic: str, max_iterations: int = 2) -> dict:
56+
all_results = []
57+
58+
for iteration in range(1, max_iterations + 1):
59+
# Plan research queries
60+
queries = await plan_research(topic)
61+
62+
# Execute searches IN PARALLEL
63+
search_futures = [execute_search(q["query"], q["purpose"]) for q in queries]
64+
search_results = [await future for future in search_futures]
65+
all_results.extend(search_results)
66+
67+
# Check if we have enough relevant results
68+
relevant_count = sum(1 for r in search_results if r.get("relevant"))
69+
if relevant_count >= 2:
70+
break
71+
72+
# Synthesize final report
73+
report = await synthesize_report(topic, all_results)
74+
return {"report": report, "total_searches": len(all_results)}
75+
```
76+
77+
### Parallel Pattern
78+
79+
```python
80+
# Start all tasks concurrently (non-blocking)
81+
futures = [execute_search(q) for q in queries]
82+
83+
# Wait for all to complete
84+
results = [await f for f in futures]
85+
```
86+
87+
This is the key difference from Graph API - parallel execution uses simple Python patterns.
88+
89+
## Why Temporal?
90+
91+
- **Parallel durability**: All concurrent searches complete reliably
92+
- **Cost efficiency**: Parallel execution reduces total time
93+
- **Progress tracking**: See individual search completions
94+
- **Resume**: Continue from last completed search if interrupted
95+
96+
## Running the Sample
97+
98+
1. Start Temporal:
99+
```bash
100+
temporal server start-dev
101+
```
102+
103+
2. Run with API key:
104+
```bash
105+
export OPENAI_API_KEY=your-key
106+
uv run langgraph_plugin/functional_api/deep_research/run_worker.py
107+
```
108+
109+
3. Research a topic:
110+
```bash
111+
uv run langgraph_plugin/functional_api/deep_research/run_workflow.py
112+
```
113+
114+
## Customization
115+
116+
### Adjust Search Breadth
117+
118+
```python
119+
@task
120+
def plan_research(topic: str) -> list[dict]:
121+
# Generate more or fewer queries
122+
return generate_queries(topic, count=6) # Default might be 4
123+
```
124+
125+
### Add Source Filtering
126+
127+
```python
128+
@task
129+
def execute_search(query: str, purpose: str) -> dict:
130+
# Filter to specific sources
131+
results = search(query, sources=["academic", "news"])
132+
...
133+
```
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Hello World (Functional API)
2+
3+
A minimal example demonstrating the LangGraph Functional API with Temporal integration.
4+
5+
## Overview
6+
7+
This sample shows the basic pattern for using `@task` and `@entrypoint` decorators with Temporal:
8+
9+
1. **`@task`** - Defines a function that runs as a Temporal activity
10+
2. **`@entrypoint`** - Orchestrates tasks, runs in the Temporal workflow
11+
12+
## Key Concepts
13+
14+
### Task as Activity
15+
16+
```python
17+
@task
18+
def process_query(query: str) -> str:
19+
"""This runs as a Temporal activity with automatic retries."""
20+
return f"Processed: {query}"
21+
```
22+
23+
### Entrypoint as Orchestrator
24+
25+
```python
26+
@entrypoint()
27+
async def hello_world_entrypoint(query: str) -> dict:
28+
# Use await to call tasks (required for Temporal)
29+
result = await process_query(query)
30+
return {"query": query, "result": result}
31+
```
32+
33+
### Workflow Wrapper
34+
35+
```python
36+
@workflow.defn
37+
class HelloWorldWorkflow:
38+
@workflow.run
39+
async def run(self, query: str) -> dict:
40+
app = compile_functional("hello_world")
41+
return await app.ainvoke(query)
42+
```
43+
44+
## Running the Sample
45+
46+
1. Start Temporal server:
47+
```bash
48+
temporal server start-dev
49+
```
50+
51+
2. Run the worker:
52+
```bash
53+
uv run langgraph_plugin/functional_api/hello_world/run_worker.py
54+
```
55+
56+
3. Execute the workflow:
57+
```bash
58+
uv run langgraph_plugin/functional_api/hello_world/run_workflow.py
59+
```
60+
61+
## Files
62+
63+
| File | Description |
64+
|------|-------------|
65+
| `tasks.py` | `@task` function definitions |
66+
| `entrypoint.py` | `@entrypoint` orchestration logic |
67+
| `workflow.py` | Temporal workflow wrapper |
68+
| `run_worker.py` | Worker startup script |
69+
| `run_workflow.py` | Workflow execution script |
70+
71+
## Adapting from Standard LangGraph
72+
73+
```python
74+
# Standard LangGraph
75+
result = my_task(input).result() # Blocking
76+
77+
# Temporal-compatible
78+
result = await my_task(input) # Async await
79+
```
80+
81+
See the main README for the complete migration guide.

0 commit comments

Comments
 (0)