In part 3 we looked at creating the researcher. As promised, today we’ll look at the author.

You’ll notice in the following code a great deal of similarity to what we’ve seen before. The goal is to create a code “template” that we can follow as we create any agent; departing only for the agent’s special requirements and abilities.
As usual, we start with the factory method:
def create_author_chain():
"""Creates the author chain."""
def author_invoke(state):
research = state.get("research_findings", [])
research_text = "\n\n".join(research) if research else "No research available."
prompt = author_prompt_template.format(
main_task=state.get("main_task", ""),
research_findings=research_text,
draft=state.get("draft", ""),
review_notes=state.get("review_notes", "")
)
try:
response = llm.invoke(prompt)
content = response.content if hasattr(response, 'content') else str(response)
return content if content else "Draft in progress..."
except Exception as e:
print(f"Author error: {e}")
return "Error generating draft. Please try again."
return author_invoke
# Creating a callable object
author_chain = create_author_chain()
We start by getting the research findings as a collection. We join all the entries into a single text string, or if there are no findings, we create the string “No research available.”
A local variable, prompt, is created from the author_prompt_template and passed to the invoke method of the LLM. The local variable content will contain the metadata or just the response from the LLM if there is no metadata.
The structure, so far, is identical to what we’ve seen before.
Next, we create the author_prompt_template used above,
author_prompt_template = """
You are a professional blogger.
Main Task: {main_task}
Research Findings:
{research_findings}
Current Draft: {draft}
Review Notes: {review_notes}
Instructions:
- If this is the first draft (no current draft), create a comprehensive post based on the findings
- If there is a current draft and review notes, revise the draft to address all feedback
- Use professional tone
- Make the post consise (aim for 250-500 words)
Write the complete post now:
"""
This is pretty self-explanatory. The interpolation variables (e.g., {draft}) will be filled in when the create_author_chain runs.
Finally, we create the author_node,
def author_node(state: ResearchState) -> dict:
"""Author node that creates or revises draft."""
print("\n>>>Author")
draft = author_chain(state)
print(f"Draft created: {len(draft)} characters")
return {
"draft": draft,
"revision_number": state.get("revision_number", 0) + 1
}
Reviewer
The reviewer follows the same pattern, so we might as well look at it here. We start with the factory
def create_reviewer_chain():
"""Creates the reviewer chain."""
def reviewer_invoke(state):
draft = state.get("draft", "")
revision_num = state.get("revision_number", 0)
if len(draft.strip()) < 100:
return "APPROVED - Draft is minimal but acceptable."
if revision_num >= 4:
return "APPROVED - Maximum revisions reached. The report is satisfactory."
prompt = reviewer_prompt_template.format(
main_task=state.get("main_task", ""),
draft=draft
)
try:
response = llm.invoke(prompt)
content = response.content if hasattr(response, 'content') else str(response)
return content if content else "APPROVED"
except Exception as e:
print(f"Review error: {e}")
return "APPROVED - Error in review, proceeding with current draft."
return reviewer_invoke
# Creating a callable object
reviewer_chain = create_reviewer_chain()
The reviewer will either approve the draft or kick it back directly to the author for revision. The only other part here is creating the node for the reviewer.
def reviewer_node(state: ResearchState) -> dict:
"""Node that reviews the draft."""
print("\n>>REVIEWER")
review = reviewer_chain(state)
print(f"Review: {review[:100]}...")
is_approved = "APPROVED" in review.upper()
if is_approved:
print("✓ Draft APPROVED")
return {
"review_notes": "APPROVED",
"next_step": "END"
}
else:
print("✗ Revisions needed")
return {
"review_notes": review,
"next_step": "author"
}
In the next post we’ll finally see how the nodes are used in creating a workflow.





































