Blog writer
Breaking down complex tasks into smaller, discrete steps is one of the best ways to improve the quality of LLM outputs. The blog writer workflow example does this by following the same approach a human would take to write a blog post: conducting research, creating an outline, writing a structured draft, and finally editing that draft.
Workflow
The Blog Writer workflow consists of the following steps:
- Research phase:
- Generate focused research topics using Claude (
GenerateTopics
) - Conduct web research with citations via Perplexity API (
WebResearch
) - Search internal documentation catalog using GenSX storage (
CatalogResearch
)
- Generate focused research topics using Claude (
- Outline creation: Structure the blog post with sections, key points, and research integration (
WriteOutline
) - Draft writing: Generate content section-by-section with expert SaaS company writer prompts (
WriteDraft
) - Editorial enhancement: Polish content for engagement, style, and readability (
Editorial
) - Tone matching (optional): Adapt writing style to match a reference URL (
MatchTone
)
Running the example
# Navigate to the example directory
cd examples/blog-writer
# Install dependencies
pnpm install
# Set your API keys
export ANTHROPIC_API_KEY=<your_anthropic_api_key>
export PERPLEXITY_API_KEY=<your_perplexity_api_key>
# Optional: For catalog search
export GENSX_API_KEY=<your_gensx_api_key>
export GENSX_PROJECT=<your_project_name>
export GENSX_ENV=development
# Run the example
pnpm run start
Key patterns
Multi-step content generation
The workflow demonstrates how to break complex content generation into discrete, manageable steps. Each component has a specific role and produces structured output for the next step:
const WriteBlog = gensx.Workflow("WriteBlog", async (props: WriteBlogProps) => {
// Step 1: Conduct research
const research = await Research({
title: props.title,
prompt: props.prompt,
});
// Step 2: Create outline based on research
const outline = await WriteOutline({
title: props.title,
prompt: props.prompt,
research: research,
});
// Step 3: Write draft based on outline and research
const draft = await WriteDraft({
title: props.title,
prompt: props.prompt,
outline: outline.object,
research: research,
targetWordCount: props.wordCount ?? 1500,
});
// Step 4: Editorial pass to make it more engaging
const finalContent = await Editorial({
title: props.title,
prompt: props.prompt,
draft: draft,
targetWordCount: props.wordCount ?? 1500,
});
return { title: props.title, content: finalContent, metadata: {...} };
});
Parallel research processing
The Research
component processes multiple research topics in parallel using Promise.all
, combining web research with optional catalog search:
const Research = gensx.Component("Research", async (props: ResearchProps) => {
// Generate research topics
const topicsResult = await GenerateTopics({
title: props.title,
prompt: props.prompt,
});
// Conduct web research in parallel
const webResearchPromises = topicsResult.topics.map((topic) =>
WebResearch({ topic }),
);
const webResearch = await Promise.all(webResearchPromises);
return {
topics: topicsResult.topics,
webResearch: webResearch,
};
});
Real-time web research with citations
The WebResearch
component uses Perplexity’s Sonar API to get current information with proper citations:
const WebResearch = gensx.Component(
"WebResearch",
async (props: { topic: string }) => {
const result = await generateText({
model: perplexity("sonar-pro"),
prompt: `Research the following topic comprehensively: ${props.topic}
Provide detailed, current information with proper citations.`,
});
return {
topic: props.topic,
content: result.text,
citations: result.response.citations || [],
source: "perplexity",
};
},
);
Tool integration for dynamic research
Components can use tools to gather additional information during generation. The WriteSection
component includes a web research tool for section-specific information:
const webResearchTool = tool({
description: "Conduct additional web research on a specific topic",
parameters: z.object({
topic: z.string().describe("The specific topic to research"),
}),
execute: async ({ topic }: { topic: string }) => {
const result = await WebResearch({ topic });
return {
topic: result.topic,
content: result.content,
citations: result.citations,
source: result.source,
};
},
});
Additional resources
Check out the other examples in the GenSX Github Repo .