Overview
The GenerateAnswerNode is responsible for generating answers from scraped content using language models. It supports both single-chunk and multi-chunk processing with parallel execution and automatic merging.
Class Signature
class GenerateAnswerNode ( BaseNode ):
def __init__ (
self ,
input : str ,
output : List[ str ],
node_config : Optional[ dict ] = None ,
node_name : str = "GenerateAnswer" ,
)
Source: scrapegraphai/nodes/generate_answer_node.py:30
Parameters
Boolean expression defining the input keys needed from the state. Common patterns:
"user_prompt & document" - User question with document
"user_prompt & parsed_doc" - User question with parsed chunks
"user_prompt & relevant_chunks" - User question with relevant content
List of output keys to be updated in the state. Typically ["answer"]
Configuration dictionary with the following options: Show Configuration Options
Language model instance (ChatOpenAI, ChatOllama, ChatBedrock, etc.)
Pydantic model defining the expected output structure
Whether to show progress bars during chunk processing
Force markdown-based prompt templates
Whether the node is in script creation mode
Whether processing markdown content
Additional context to prepend to prompt templates
Timeout in seconds for LLM inference (per chunk or merge operation)
node_name
str
default: "GenerateAnswer"
The unique identifier name for the node
State Keys
The user’s question or instruction for content extraction
document
List[Document] | List[str]
Document content to process (raw format)
Pre-chunked document content
Filtered relevant content chunks
Generic content field (fallback option)
Output State
Generated answer, either as structured JSON (if schema provided) or plain text
Methods
execute(state: dict) -> dict
Executes the GenerateAnswerNode to generate an answer from the provided content.
def execute ( self , state : dict ) -> dict :
"""
Executes the GenerateAnswerNode.
Args:
state (dict): The current state of the graph.
Returns:
dict: The updated state with the output key containing the generated answer.
"""
Source: scrapegraphai/nodes/generate_answer_node.py:118
Processing Logic:
Single chunk : Direct LLM inference
Multiple chunks : Parallel processing + merge step
Returns: Updated state dictionary with generated answer
Helper method to invoke LangChain with timeout protection.
def invoke_with_timeout ( self , chain , inputs , timeout ):
"""Helper method to invoke chain with timeout"""
Source: scrapegraphai/nodes/generate_answer_node.py:75
Usage Examples
Basic Answer Generation
from scrapegraphai.nodes import GenerateAnswerNode
from langchain_openai import ChatOpenAI
# Create generate answer node
generate_node = GenerateAnswerNode(
input = "user_prompt & parsed_doc" ,
output = [ "answer" ],
node_config = {
"llm_model" : ChatOpenAI( model = "gpt-4" ),
"verbose" : False ,
"timeout" : 480
}
)
# Execute node
state = {
"user_prompt" : "What is the main topic of this article?" ,
"parsed_doc" : [ "Article content chunk 1..." , "Article content chunk 2..." ]
}
updated_state = generate_node.execute(state)
print (updated_state[ "answer" ])
# Output: {"content": "The main topic is..."}
Structured Output with Schema
from pydantic import BaseModel, Field
from typing import List
class ProductInfo ( BaseModel ):
name: str = Field( description = "Product name" )
price: float = Field( description = "Product price" )
features: List[ str ] = Field( description = "List of product features" )
generate_node = GenerateAnswerNode(
input = "user_prompt & document" ,
output = [ "answer" ],
node_config = {
"llm_model" : ChatOpenAI( model = "gpt-4" ),
"schema" : ProductInfo, # Define output structure
"verbose" : True
}
)
state = {
"user_prompt" : "Extract product information" ,
"document" : [Document( page_content = "Product page content..." )]
}
updated_state = generate_node.execute(state)
print (updated_state[ "answer" ])
# Output: {"name": "...", "price": 99.99, "features": [...]}
Multi-Chunk Parallel Processing
generate_node = GenerateAnswerNode(
input = "user_prompt & parsed_doc" ,
output = [ "answer" ],
node_config = {
"llm_model" : ChatOpenAI( model = "gpt-4" ),
"verbose" : True , # Show progress bar
"timeout" : 600 # Longer timeout for multiple chunks
}
)
state = {
"user_prompt" : "Summarize all the key points" ,
"parsed_doc" : [
"Chunk 1 content..." ,
"Chunk 2 content..." ,
"Chunk 3 content..." ,
"Chunk 4 content..."
]
}
updated_state = generate_node.execute(state)
# Processes all chunks in parallel, then merges results
Using Ollama Model
from langchain_community.chat_models import ChatOllama
generate_node = GenerateAnswerNode(
input = "user_prompt & document" ,
output = [ "answer" ],
node_config = {
"llm_model" : ChatOllama( model = "llama3" ),
"verbose" : False
}
)
state = {
"user_prompt" : "Extract contact information" ,
"document" : [Document( page_content = "Contact page content..." )]
}
updated_state = generate_node.execute(state)
With Additional Context
generate_node = GenerateAnswerNode(
input = "user_prompt & parsed_doc" ,
output = [ "answer" ],
node_config = {
"llm_model" : ChatOpenAI( model = "gpt-4" ),
"additional_info" : """You are a financial analyst.
Focus on extracting numerical data and financial metrics.""" ,
"verbose" : False
}
)
state = {
"user_prompt" : "What are the company's financial metrics?" ,
"parsed_doc" : [ "Financial report content..." ]
}
updated_state = generate_node.execute(state)
Markdown Content Processing
generate_node = GenerateAnswerNode(
input = "user_prompt & document" ,
output = [ "answer" ],
node_config = {
"llm_model" : ChatOpenAI( model = "gpt-4" ),
"is_md_scraper" : True , # Optimized for markdown content
"force" : True
}
)
state = {
"user_prompt" : "Extract all code examples" ,
"document" : [Document( page_content = "# Tutorial \n\n ```python \n ..." )]
}
updated_state = generate_node.execute(state)
AWS Bedrock Model
from langchain_aws import ChatBedrock
generate_node = GenerateAnswerNode(
input = "user_prompt & parsed_doc" ,
output = [ "answer" ],
node_config = {
"llm_model" : ChatBedrock(
model_id = "anthropic.claude-3-sonnet-20240229-v1:0" ,
region_name = "us-east-1"
),
"verbose" : False
}
)
state = {
"user_prompt" : "Analyze the sentiment" ,
"parsed_doc" : [ "Customer reviews content..." ]
}
updated_state = generate_node.execute(state)
Processing Modes
Single-Chunk Mode
When the document consists of only one chunk:
Uses TEMPLATE_NO_CHUNKS prompt template
Direct LLM inference (no parallel processing)
Faster execution
Best for short documents
# Triggered when len(doc) == 1
state = {
"user_prompt" : "Extract info" ,
"parsed_doc" : [ "Single chunk content" ]
}
Multi-Chunk Mode
When the document has multiple chunks:
Parallel Processing : Each chunk processed independently
Uses TEMPLATE_CHUNKS prompt template
Runs all chunks in parallel with RunnableParallel
Shows progress bar if verbose=True
Merge Step : Combines individual chunk results
Uses TEMPLATE_MERGE prompt template
Synthesizes coherent final answer
Removes duplicates and conflicts
# Triggered when len(doc) > 1
state = {
"user_prompt" : "Extract info" ,
"parsed_doc" : [ "Chunk 1" , "Chunk 2" , "Chunk 3" ]
}
Prompt Templates
The node uses different templates based on configuration:
Standard HTML Templates
TEMPLATE_NO_CHUNKS - Single chunk processing
TEMPLATE_CHUNKS - Individual chunk processing
TEMPLATE_MERGE - Merge multiple chunk results
Markdown Templates
TEMPLATE_NO_CHUNKS_MD - Single markdown chunk
TEMPLATE_CHUNKS_MD - Individual markdown chunks
TEMPLATE_MERGE_MD - Merge markdown chunk results
Templates are selected based on:
is_md_scraper=True - Forces markdown templates
force=True and script_creator=False - Forces markdown templates
Otherwise uses standard HTML templates
Output Parsing
With Schema (Structured Output)
node_config = {
"llm_model" : ChatOpenAI( model = "gpt-4" ),
"schema" : YourPydanticModel
}
# Output is parsed into Pydantic model structure
Without Schema (JSON Output)
node_config = {
"llm_model" : ChatOpenAI( model = "gpt-4" )
}
# Output is parsed as generic JSON with 'content' field
# Example: {"content": "your analysis here"}
Special Case: Bedrock Models
Bedrock models bypass output parsers and return raw responses.
Error Handling
The node handles various error scenarios:
Timeout Errors
state = { "answer" : {
"error" : "Response timeout exceeded" ,
"raw_response" : "..."
}}
JSON Parsing Errors
state = { "answer" : {
"error" : "Invalid JSON response format" ,
"raw_response" : "..."
}}
Missing Content
# Raises ValueError: "No content found in state to generate answer from"
Missing User Prompt
# Raises ValueError: "No user prompt found in state"
Parallel Processing
Multiple chunks are processed in parallel using LangChain’s RunnableParallel:
chains_dict = {
"chunk1" : prompt1 | llm_model,
"chunk2" : prompt2 | llm_model,
"chunk3" : prompt3 | llm_model,
}
async_runner = RunnableParallel( ** chains_dict)
results = async_runner.invoke({ "question" : user_prompt})
Timeout Management
Each operation has independent timeout:
Chunk processing: timeout seconds per chunk
Merge operation: timeout seconds for final merge
Progress Tracking
Enable verbose=True to see chunk processing progress:
Processing chunks: 100 %| ██████████ | 5 / 5 [ 00 : 12 < 00 : 00 , 2. 5s / chunk]
Best Practices
Set appropriate timeouts - Longer for complex extractions
Use schemas for structured data - Ensures consistent output format
Enable verbose for debugging - Monitor processing progress
Optimize chunk size - Balance between context and parallelism
Add context with additional_info - Improves extraction quality
Handle errors gracefully - Check for error fields in output
Use appropriate templates - Markdown for docs, HTML for web pages