PocketFlow 循序渐进指南

PocketFlow 是一个 100 行的极简 LLM 框架,用于构建智能体、任务分解、RAG 等应用。本指南将通过循序渐进的方式,带你深度理解其核心设计并学会构建各种 AI 应用。

pip install pocketflow

目录

  1. 核心概念
  2. 基础应用
  3. 进阶模式
  4. 实战项目

核心概念

1. 核心抽象:Node

Node 是 PocketFlow 的最小构建块,每个 Node 都有三个步骤:

  • prep(shared) - 从共享存储读取和预处理数据
  • exec(prep_res) - 执行计算逻辑(通常是 LLM 调用)
  • post(shared, prep_res, exec_res) - 后处理并写回共享存储,返回下一步动作
class SimpleNode(Node):
    def prep(self, shared):
        return shared["input_text"]
    
    def exec(self, text):
        return call_llm(f"处理文本: {text}")
    
    def post(self, shared, prep_res, exec_res):
        shared["result"] = exec_res
        return "default"  # 返回动作名称

2. 核心抽象:Flow

Flow 通过 Action 连接多个 Node,形成有向图:

# 基础连接
node_a >> node_b  # 默认连接(action="default")

# 条件分支
node_a - "success" >> node_b
node_a - "error" >> error_handler

# 创建 Flow
flow = Flow(start=node_a)
flow.run(shared)

3. 通信机制

Shared Store 是全局数据字典,所有 Node 都可以读写:

shared = {
    "input": "用户输入",
    "results": {},
    "config": {...}
}

基础应用

应用1:简单文本处理流水线

我们先从最基础的文本处理开始,了解 Node 和 Flow 的基本用法。

架构图

flowchart TD A[用户输入] --> B[文本清理] B --> C[情感分析] C --> D[生成回复] D --> E[输出结果] classDef nodeStyle fill:#e1f5fe,stroke:#01579b,stroke-width:2px class B,C,D nodeStyle

代码实现

from pocketflow import Node, Flow

def call_llm(prompt):
    """简单的LLM调用函数"""
    from openai import OpenAI
    client = OpenAI()
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

class TextCleanNode(Node):
    """文本清理节点"""
    def prep(self, shared):
        return shared["user_input"]
    
    def exec(self, text):
        # 简单的文本清理
        cleaned = text.strip().lower()
        return cleaned
    
    def post(self, shared, prep_res, exec_res):
        shared["cleaned_text"] = exec_res
        return "default"

class SentimentAnalysisNode(Node):
    """情感分析节点"""
    def prep(self, shared):
        return shared["cleaned_text"]
    
    def exec(self, text):
        prompt = f"分析这段文本的情感倾向(积极/消极/中性):{text}"
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["sentiment"] = exec_res
        return "default"

class ResponseGeneratorNode(Node):
    """回复生成节点"""
    def prep(self, shared):
        return shared["cleaned_text"], shared["sentiment"]
    
    def exec(self, inputs):
        text, sentiment = inputs
        prompt = f"基于文本:'{text}' 和情感:'{sentiment}',生成一个合适的回复"
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["response"] = exec_res

# 创建流水线
def create_text_processing_pipeline():
    clean_node = TextCleanNode()
    sentiment_node = SentimentAnalysisNode()
    response_node = ResponseGeneratorNode()
    
    # 连接节点
    clean_node >> sentiment_node >> response_node
    
    return Flow(start=clean_node)

# 使用示例
def main():
    shared = {
        "user_input": "今天天气真好!我很开心。"
    }
    
    pipeline = create_text_processing_pipeline()
    pipeline.run(shared)
    
    print(f"原始输入:{shared['user_input']}")
    print(f"清理后:{shared['cleaned_text']}")
    print(f"情感分析:{shared['sentiment']}")
    print(f"生成回复:{shared['response']}")

if __name__ == "__main__":
    main()

学习要点

  1. 关注点分离:每个 Node 只负责一个特定任务
  2. 数据流:通过 shared store 在节点间传递数据
  3. 简单连接:使用 >> 操作符连接节点

应用2:带条件分支的智能客服

接下来我们学习如何使用条件分支处理不同类型的用户请求。

架构图

flowchart TD A[用户输入] --> B[意图识别] B -->|查询| C[信息查询] B -->|投诉| D[投诉处理] B -->|其他| E[通用回复] C --> F[格式化输出] D --> F E --> F classDef nodeStyle fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px classDef branchStyle fill:#fff3e0,stroke:#ef6c00,stroke-width:2px class B branchStyle class C,D,E,F nodeStyle

代码实现

class IntentClassificationNode(Node):
    """意图识别节点"""
    def prep(self, shared):
        return shared["user_input"]
    
    def exec(self, text):
        prompt = f"""
        分析用户意图,只返回以下之一:query, complaint, other
        用户输入:{text}
        """
        return call_llm(prompt).strip().lower()
    
    def post(self, shared, prep_res, exec_res):
        shared["intent"] = exec_res
        return exec_res  # 返回意图作为 action

class QueryHandlerNode(Node):
    """查询处理节点"""
    def prep(self, shared):
        return shared["user_input"]
    
    def exec(self, text):
        prompt = f"这是一个查询请求,请提供相关信息:{text}"
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["response"] = f"查询结果:{exec_res}"
        return "format"

class ComplaintHandlerNode(Node):
    """投诉处理节点"""
    def prep(self, shared):
        return shared["user_input"]
    
    def exec(self, text):
        prompt = f"这是一个投诉,请给出专业的回应:{text}"
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["response"] = f"投诉处理:{exec_res}"
        return "format"

class DefaultHandlerNode(Node):
    """默认处理节点"""
    def prep(self, shared):
        return shared["user_input"]
    
    def exec(self, text):
        prompt = f"给出友好的通用回复:{text}"
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["response"] = f"通用回复:{exec_res}"
        return "format"

class FormatOutputNode(Node):
    """输出格式化节点"""
    def prep(self, shared):
        return shared["response"]
    
    def exec(self, response):
        # 简单的格式化
        return f"🤖 客服助手:{response}"
    
    def post(self, shared, prep_res, exec_res):
        shared["final_response"] = exec_res

# 创建智能客服流程
def create_customer_service_flow():
    intent_node = IntentClassificationNode()
    query_node = QueryHandlerNode()
    complaint_node = ComplaintHandlerNode()
    default_node = DefaultHandlerNode()
    format_node = FormatOutputNode()
    
    # 设置分支逻辑
    intent_node - "query" >> query_node
    intent_node - "complaint" >> complaint_node
    intent_node - "other" >> default_node
    
    # 所有处理节点都连接到格式化节点
    query_node - "format" >> format_node
    complaint_node - "format" >> format_node
    default_node - "format" >> format_node
    
    return Flow(start=intent_node)

# 测试多种输入
def test_customer_service():
    test_cases = [
        "我想查询我的订单状态",
        "你们的服务太差了,我要投诉!",
        "今天天气怎么样?"
    ]
    
    flow = create_customer_service_flow()
    
    for user_input in test_cases:
        shared = {"user_input": user_input}
        flow.run(shared)
        print(f"用户:{user_input}")
        print(f"意图:{shared['intent']}")
        print(f"回复:{shared['final_response']}")
        print("-" * 50)

if __name__ == "__main__":
    test_customer_service()

学习要点

  1. 条件分支:使用 node - "action" >> next_node 设置条件跳转
  2. 动态路由:根据计算结果决定下一步执行哪个节点
  3. 收敛节点:多个分支可以汇聚到同一个后续节点

进阶模式

模式1:Batch 批处理 - 批量文档摘要

当需要处理大量数据时,BatchNode 可以将任务分解为小块并行处理。

架构图

flowchart TD A[多个文档] --> B[BatchNode: 文档处理] B --> C[文档1摘要] B --> D[文档2摘要] B --> E[文档N摘要] C --> F[合并摘要] D --> F E --> F F --> G[最终报告] classDef batchStyle fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px classDef processStyle fill:#e3f2fd,stroke:#1976d2,stroke-width:2px class B batchStyle class C,D,E,F,G processStyle

代码实现

from pocketflow import BatchNode

class DocumentBatchProcessor(BatchNode):
    """批量文档处理节点"""
    def prep(self, shared):
        # 返回文档列表,每个元素将被单独处理
        documents = shared["documents"]
        return list(documents.items())  # [(filename, content), ...]
    
    def exec(self, doc_item):
        filename, content = doc_item
        # 为每个文档生成摘要
        prompt = f"请为以下文档生成100字摘要:\n{content}"
        summary = call_llm(prompt)
        return (filename, summary)
    
    def post(self, shared, prep_res, exec_res_list):
        # exec_res_list 包含所有文档的处理结果
        summaries = dict(exec_res_list)
        shared["individual_summaries"] = summaries
        return "default"

class SummaryCombinerNode(Node):
    """摘要合并节点"""
    def prep(self, shared):
        return shared["individual_summaries"]
    
    def exec(self, summaries):
        # 将所有摘要合并成最终报告
        summary_text = "\n\n".join([
            f"📄 {filename}:\n{summary}" 
            for filename, summary in summaries.items()
        ])
        
        prompt = f"""
基于以下各文档摘要,生成一个综合报告:

{summary_text}

请提供:
1. 总体概述
2. 关键发现
3. 建议行动
"""
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["final_report"] = exec_res

# 创建批处理流程
def create_batch_document_processor():
    batch_processor = DocumentBatchProcessor()
    combiner = SummaryCombinerNode()
    
    batch_processor >> combiner
    
    return Flow(start=batch_processor)

# 使用示例
def test_batch_processing():
    documents = {
        "报告1.txt": "这是第一份技术报告,主要讨论AI在医疗领域的应用...",
        "报告2.txt": "这是第二份市场分析报告,分析了当前AI市场趋势...",
        "报告3.txt": "这是第三份产品规划文档,描述了未来产品发展方向..."
    }
    
    shared = {"documents": documents}
    
    flow = create_batch_document_processor()
    flow.run(shared)
    
    print("个别摘要:")
    for filename, summary in shared["individual_summaries"].items():
        print(f"{filename}: {summary[:100]}...")
    
    print("\n综合报告:")
    print(shared["final_report"])

if __name__ == "__main__":
    test_batch_processing()

模式2:Agent 智能代理 - 研究助手

Agent 模式让 AI 能够根据上下文动态选择行动,实现更复杂的任务处理。

架构图

flowchart TD A[研究任务] --> B[决策节点] B -->|搜索| C[网络搜索] B -->|分析| D[信息分析] B -->|总结| E[生成报告] C --> F[更新上下文] D --> F F --> B E --> G[完成] classDef agentStyle fill:#ffebee,stroke:#c62828,stroke-width:2px classDef actionStyle fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px classDef contextStyle fill:#fff3e0,stroke:#ef6c00,stroke-width:2px class B agentStyle class C,D,E actionStyle class F contextStyle

代码实现

import yaml

class ResearchAgentNode(Node):
    """研究代理决策节点"""
    def prep(self, shared):
        task = shared["research_task"]
        context = shared.get("research_context", [])
        return task, context
    
    def exec(self, inputs):
        task, context = inputs
        context_text = "\n".join([f"- {item}" for item in context])
        
        prompt = f"""
你是一个研究助手AI。根据当前任务和已有信息,决定下一步行动。

研究任务:{task}

已收集信息:
{context_text}

可选行动:
1. search - 搜索更多相关信息
2. analyze - 分析已有信息并得出洞察
3. report - 生成最终研究报告

请以YAML格式回复:
```yaml
thinking: |
  你的思考过程
action: search/analyze/report
parameters:
  query: 搜索查询词(如果action是search)
  focus: 分析重点(如果action是analyze)
```
"""
        
        response = call_llm(prompt)
        yaml_str = response.split("```yaml")[1].split("```")[0].strip()
        return yaml.safe_load(yaml_str)
    
    def post(self, shared, prep_res, exec_res):
        action = exec_res["action"]
        shared["current_action"] = exec_res
        return action

class SearchActionNode(Node):
    """搜索行动节点"""
    def prep(self, shared):
        return shared["current_action"]["parameters"]["query"]
    
    def exec(self, query):
        # 模拟搜索(实际应用中可接入真实搜索API)
        prompt = f"模拟搜索'{query}'的结果,返回3个关键信息点"
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        context = shared.get("research_context", [])
        context.append(f"搜索结果({prep_res}):{exec_res}")
        shared["research_context"] = context
        return "continue"

class AnalyzeActionNode(Node):
    """分析行动节点"""
    def prep(self, shared):
        context = shared.get("research_context", [])
        focus = shared["current_action"]["parameters"].get("focus", "综合分析")
        return context, focus
    
    def exec(self, inputs):
        context, focus = inputs
        context_text = "\n".join(context)
        
        prompt = f"""
对以下信息进行{focus}:

{context_text}

请提供:
1. 关键洞察
2. 模式识别
3. 进一步研究方向
"""
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        context = shared.get("research_context", [])
        context.append(f"分析结果:{exec_res}")
        shared["research_context"] = context
        return "continue"

class ReportActionNode(Node):
    """报告生成节点"""
    def prep(self, shared):
        task = shared["research_task"]
        context = shared.get("research_context", [])
        return task, context
    
    def exec(self, inputs):
        task, context = inputs
        context_text = "\n".join(context)
        
        prompt = f"""
基于研究任务和收集的信息,生成专业研究报告:

研究任务:{task}

研究过程与发现:
{context_text}

请生成结构化报告,包括:
1. 执行摘要
2. 主要发现
3. 详细分析
4. 结论与建议
"""
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["final_report"] = exec_res

class ContextUpdateNode(Node):
    """上下文更新节点"""
    def prep(self, shared):
        return len(shared.get("research_context", []))
    
    def exec(self, context_length):
        # 简单的继续条件判断
        if context_length < 5:  # 最多收集5轮信息
            return "continue"
        else:
            return "report"
    
    def post(self, shared, prep_res, exec_res):
        return exec_res

# 创建研究代理流程
def create_research_agent():
    agent = ResearchAgentNode()
    search = SearchActionNode()
    analyze = AnalyzeActionNode()
    report = ReportActionNode()
    update = ContextUpdateNode()
    
    # 设置代理决策分支
    agent - "search" >> search
    agent - "analyze" >> analyze
    agent - "report" >> report
    
    # 行动完成后更新上下文
    search - "continue" >> update
    analyze - "continue" >> update
    
    # 上下文更新后的决策
    update - "continue" >> agent  # 循环回到决策
    update - "report" >> report   # 或生成报告
    
    return Flow(start=agent)

# 使用示例
def test_research_agent():
    shared = {
        "research_task": "研究量子计算在密码学中的应用前景"
    }
    
    flow = create_research_agent()
    flow.run(shared)
    
    print("研究过程:")
    for i, context in enumerate(shared.get("research_context", []), 1):
        print(f"{i}. {context}")
    
    print("\n最终报告:")
    print(shared.get("final_report", "未生成报告"))

if __name__ == "__main__":
    test_research_agent()

学习要点

  1. 动态决策:Agent 根据当前状态选择最合适的行动
  2. 循环控制:通过条件判断控制何时结束循环
  3. 上下文管理:在多轮交互中积累和利用信息
  4. 结构化输出:使用 YAML/JSON 格式确保可解析的决策输出

模式3:RAG 检索增强生成 - 智能文档问答

RAG 模式将检索和生成相结合,让 AI 能够基于知识库回答问题。

架构图

flowchart TD subgraph "离线索引阶段" A[文档集合] --> B[文档分块] B --> C[向量化] C --> D[构建索引] end subgraph "在线查询阶段" E[用户问题] --> F[问题向量化] F --> G[相似度检索] G --> H[上下文生成] H --> I[生成答案] end D -.-> G classDef offlineStyle fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px classDef onlineStyle fill:#e3f2fd,stroke:#1976d2,stroke-width:2px class A,B,C,D offlineStyle class E,F,G,H,I onlineStyle

代码实现

# 首先实现一些工具函数
def get_embedding(text):
    """获取文本嵌入向量(示例实现)"""
    # 实际应用中应该调用真实的嵌入API
    import hashlib
    import numpy as np
    
    # 简化的伪嵌入实现
    hash_obj = hashlib.md5(text.encode())
    seed = int(hash_obj.hexdigest(), 16) % (2**31)
    np.random.seed(seed)
    return np.random.rand(768).tolist()

def create_simple_index(embeddings):
    """创建简单的向量索引"""
    import numpy as np
    return np.array(embeddings)

def search_similar(index, query_embedding, top_k=3):
    """搜索最相似的向量"""
    import numpy as np
    
    query_emb = np.array(query_embedding)
    similarities = np.dot(index, query_emb) / (
        np.linalg.norm(index, axis=1) * np.linalg.norm(query_emb)
    )
    top_indices = np.argsort(similarities)[-top_k:][::-1]
    return top_indices, similarities[top_indices]

# 离线索引阶段
class DocumentChunkerNode(BatchNode):
    """文档分块节点"""
    def prep(self, shared):
        return shared["documents"]
    
    def exec(self, document):
        filename, content = document
        # 简单按段落分块
        chunks = [chunk.strip() for chunk in content.split('\n\n') if chunk.strip()]
        return [(filename, i, chunk) for i, chunk in enumerate(chunks)]
    
    def post(self, shared, prep_res, exec_res_list):
        all_chunks = []
        for chunk_list in exec_res_list:
            all_chunks.extend(chunk_list)
        shared["chunks"] = all_chunks

class EmbeddingNode(BatchNode):
    """向量化节点"""
    def prep(self, shared):
        return shared["chunks"]
    
    def exec(self, chunk_info):
        filename, chunk_id, text = chunk_info
        embedding = get_embedding(text)
        return {
            "filename": filename,
            "chunk_id": chunk_id,
            "text": text,
            "embedding": embedding
        }
    
    def post(self, shared, prep_res, exec_res_list):
        shared["embedded_chunks"] = exec_res_list

class IndexBuilderNode(Node):
    """索引构建节点"""
    def prep(self, shared):
        return shared["embedded_chunks"]
    
    def exec(self, embedded_chunks):
        embeddings = [chunk["embedding"] for chunk in embedded_chunks]
        index = create_simple_index(embeddings)
        return index
    
    def post(self, shared, prep_res, exec_res):
        shared["index"] = exec_res

# 在线查询阶段
class QueryEmbeddingNode(Node):
    """查询向量化节点"""
    def prep(self, shared):
        return shared["question"]
    
    def exec(self, question):
        return get_embedding(question)
    
    def post(self, shared, prep_res, exec_res):
        shared["query_embedding"] = exec_res

class RetrievalNode(Node):
    """检索节点"""
    def prep(self, shared):
        return (shared["query_embedding"], 
                shared["index"], 
                shared["embedded_chunks"])
    
    def exec(self, inputs):
        query_emb, index, chunks = inputs
        top_indices, scores = search_similar(index, query_emb, top_k=3)
        
        retrieved_chunks = []
        for idx, score in zip(top_indices, scores):
            chunk = chunks[idx]
            retrieved_chunks.append({
                "text": chunk["text"],
                "filename": chunk["filename"],
                "score": float(score)
            })
        
        return retrieved_chunks
    
    def post(self, shared, prep_res, exec_res):
        shared["retrieved_contexts"] = exec_res

class AnswerGenerationNode(Node):
    """答案生成节点"""
    def prep(self, shared):
        return shared["question"], shared["retrieved_contexts"]
    
    def exec(self, inputs):
        question, contexts = inputs
        
        context_text = "\n\n".join([
            f"文档片段 {i+1} (来源: {ctx['filename']}, 相似度: {ctx['score']:.3f}):\n{ctx['text']}"
            for i, ctx in enumerate(contexts)
        ])
        
        prompt = f"""
基于以下文档内容回答问题。如果文档中没有相关信息,请明确说明。

问题:{question}

相关文档内容:
{context_text}

请提供准确、详细的答案,并引用相关的文档来源。
"""
        
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["answer"] = exec_res

# 创建 RAG 系统
def create_rag_system():
    # 离线索引流程
    chunker = DocumentChunkerNode()
    embedder = EmbeddingNode()
    indexer = IndexBuilderNode()
    
    chunker >> embedder >> indexer
    offline_flow = Flow(start=chunker)
    
    # 在线查询流程
    query_emb = QueryEmbeddingNode()
    retriever = RetrievalNode()
    generator = AnswerGenerationNode()
    
    query_emb >> retriever >> generator
    online_flow = Flow(start=query_emb)
    
    return offline_flow, online_flow

# 使用示例
def test_rag_system():
    # 准备文档数据
    documents = [
        ("AI技术报告.txt", """
        人工智能技术在过去十年中取得了重大突破。深度学习、自然语言处理和计算机视觉等领域都有显著进展。

        特别是大型语言模型的出现,如GPT系列,为AI应用开辟了新的可能性。这些模型能够理解和生成人类语言,在文本摘要、翻译、代码生成等任务上表现出色。

        然而,AI技术也面临一些挑战,包括数据隐私、算法偏见和计算资源消耗等问题。
        """),
        ("量子计算概述.txt", """
        量子计算是一种利用量子力学原理进行信息处理的计算方式。与传统计算机使用二进制位不同,量子计算机使用量子位(qubits)。

        量子位可以同时处于0和1的叠加状态,这使得量子计算机在处理某些特定问题时具有指数级的速度优势。

        目前,量子计算在密码学、优化问题和药物发现等领域显示出巨大潜力。不过,构建稳定的量子计算机仍面临技术挑战。
        """)
    ]
    
    shared = {"documents": documents}
    
    # 构建索引
    offline_flow, online_flow = create_rag_system()
    print("正在构建文档索引...")
    offline_flow.run(shared)
    print(f"索引构建完成,共处理 {len(shared['chunks'])} 个文档块")
    
    # 回答问题
    questions = [
        "AI技术有哪些主要应用?",
        "量子计算相比传统计算有什么优势?",
        "区块链技术是什么?"  # 文档中没有的内容
    ]
    
    for question in questions:
        print(f"\n问题:{question}")
        shared["question"] = question
        online_flow.run(shared)
        
        print("检索到的相关内容:")
        for i, ctx in enumerate(shared["retrieved_contexts"]):
            print(f"  {i+1}. {ctx['filename']} (相似度: {ctx['score']:.3f})")
            print(f"     {ctx['text'][:100]}...")
        
        print(f"\n答案:{shared['answer']}")
        print("-" * 80)

if __name__ == "__main__":
    test_rag_system()

学习要点

  1. 两阶段架构:离线构建索引,在线检索生成
  2. 向量检索:将文本转换为向量,通过相似度匹配相关内容
  3. 上下文注入:将检索到的内容作为上下文提供给生成模型
  4. 可追溯性:答案可以追溯到具体的文档来源

实战项目

综合项目:智能内容创作平台

这个项目将综合运用多种设计模式,构建一个完整的智能内容创作系统,包括:

  • Agent 模式用于内容策划
  • RAG 模式用于资料检索
  • MapReduce 模式用于并行创作
  • Workflow 模式用于内容流水线

系统架构图

graph TB subgraph "智能内容创作平台" subgraph "策划阶段" U[用户需求] --> PA[策划Agent] PA -->|研究| RA[研究Agent] PA -->|创意| CA[创意Agent] RA --> KB[(知识库RAG)] CA --> KB end subgraph "创作阶段" PA --> BP[Batch并行创作] BP --> W1[作者1: 大纲] BP --> W2[作者2: 内容] BP --> W3[作者3: 配图] end subgraph "整合阶段" W1 --> WF[Workflow整合] W2 --> WF W3 --> WF WF --> QA[质量审核Agent] QA --> OUT[最终输出] end end classDef agentStyle fill:#ffebee,stroke:#c62828,stroke-width:2px classDef ragStyle fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px classDef batchStyle fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px classDef workflowStyle fill:#e3f2fd,stroke:#1976d2,stroke-width:2px class PA,RA,CA,QA agentStyle class KB ragStyle class BP,W1,W2,W3 batchStyle class WF workflowStyle

核心代码实现

import json
from typing import List, Dict, Any

class ContentPlanningAgent(Node):
    """内容策划代理"""
    def prep(self, shared):
        return shared["user_requirements"]
    
    def exec(self, requirements):
        prompt = f"""
作为内容策划专家,分析以下需求并制定创作计划:

需求:{requirements}

请提供结构化的策划方案:
```yaml
content_type: 文章类型
target_audience: 目标受众
key_topics: 
  - 主题1
  - 主题2
research_areas:
  - 研究方向1
  - 研究方向2
action: research/creative/execute
```
"""
        
        response = call_llm(prompt)
        yaml_str = response.split("```yaml")[1].split("```")[0].strip()
        return yaml.safe_load(yaml_str)
    
    def post(self, shared, prep_res, exec_res):
        shared["content_plan"] = exec_res
        return exec_res["action"]

class ResearchAgent(Node):
    """研究代理"""
    def prep(self, shared):
        plan = shared["content_plan"]
        return plan["research_areas"]
    
    def exec(self, research_areas):
        research_results = []
        for area in research_areas:
            # 这里可以接入真实的搜索API或RAG系统
            prompt = f"针对'{area}'进行深度研究,提供关键信息和数据"
            result = call_llm(prompt)
            research_results.append({"area": area, "findings": result})
        return research_results
    
    def post(self, shared, prep_res, exec_res):
        shared["research_results"] = exec_res
        return "creative"

class CreativeAgent(Node):
    """创意代理"""
    def prep(self, shared):
        plan = shared["content_plan"]
        research = shared["research_results"]
        return plan, research
    
    def exec(self, inputs):
        plan, research = inputs
        research_text = "\n".join([f"{r['area']}: {r['findings']}" for r in research])
        
        prompt = f"""
基于策划方案和研究结果,生成创意内容框架:

策划方案:{json.dumps(plan, ensure_ascii=False)}
研究结果:{research_text}

请提供:
1. 内容大纲(详细章节结构)
2. 创作指导(每个章节的写作要点)
3. 素材建议(图片、图表、案例)
"""
        
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["creative_framework"] = exec_res
        return "execute"

class ParallelContentCreation(BatchFlow):
    """并行内容创作"""
    def prep(self, shared):
        # 为不同创作任务分配参数
        tasks = [
            {"role": "outline_writer", "task": "创建详细大纲"},
            {"role": "content_writer", "task": "撰写主要内容"},
            {"role": "visual_designer", "task": "设计视觉元素"}
        ]
        return tasks

class ContentCreatorNode(Node):
    """内容创作节点"""
    def prep(self, shared):
        role = self.params["role"]
        task = self.params["task"]
        framework = shared["creative_framework"]
        plan = shared["content_plan"]
        return role, task, framework, plan
    
    def exec(self, inputs):
        role, task, framework, plan = inputs
        
        if role == "outline_writer":
            prompt = f"""
作为大纲编写专家,基于创意框架创建详细大纲:

创意框架:{framework}
内容计划:{json.dumps(plan, ensure_ascii=False)}

请创建结构化的内容大纲,包括:
- 标题层级
- 每节要点
- 预估字数
"""
        elif role == "content_writer":
            prompt = f"""
作为内容写作专家,基于创意框架撰写主要内容:

创意框架:{framework}

请撰写高质量的内容,注意:
- 逻辑清晰
- 表达生动
- 信息准确
"""
        else:  # visual_designer
            prompt = f"""
作为视觉设计专家,基于创意框架设计视觉方案:

创意框架:{framework}

请提供视觉设计建议:
- 图片类型和风格
- 图表数据可视化方案
- 整体视觉布局
"""
        
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        role = self.params["role"]
        if "creation_results" not in shared:
            shared["creation_results"] = {}
        shared["creation_results"][role] = exec_res

class ContentIntegrationWorkflow(Flow):
    """内容整合工作流"""
    def prep(self, shared):
        return shared["creation_results"]
    
    def post(self, shared, prep_res, exec_res):
        # Flow的post方法,可以在这里进行整合后的处理
        return "quality_check"

class QualityAssuranceAgent(Node):
    """质量保证代理"""
    def prep(self, shared):
        creation_results = shared["creation_results"]
        original_plan = shared["content_plan"]
        return creation_results, original_plan
    
    def exec(self, inputs):
        results, plan = inputs
        
        combined_content = "\n\n".join([
            f"【{role}】\n{content}" 
            for role, content in results.items()
        ])
        
        prompt = f"""
作为质量审核专家,请评估以下创作内容:

原始需求:{json.dumps(plan, ensure_ascii=False)}

创作内容:
{combined_content}

请提供:
1. 质量评估(1-10分)
2. 具体建议
3. 是否需要修改(approve/revise)
"""
        
        return call_llm(prompt)
    
    def post(self, shared, prep_res, exec_res):
        shared["quality_assessment"] = exec_res
        # 简化处理,实际可以根据评估结果决定是否重新创作
        return "approve"

class FinalOutputNode(Node):
    """最终输出节点"""
    def prep(self, shared):
        return shared["creation_results"], shared["quality_assessment"]
    
    def exec(self, inputs):
        results, assessment = inputs
        
        # 整合所有内容
        final_content = {
            "outline": results.get("outline_writer", ""),
            "content": results.get("content_writer", ""),
            "visuals": results.get("visual_designer", ""),
            "quality_score": assessment
        }
        
        return final_content
    
    def post(self, shared, prep_res, exec_res):
        shared["final_output"] = exec_res

# 组装完整的内容创作平台
def create_content_creation_platform():
    # 策划阶段
    planner = ContentPlanningAgent()
    researcher = ResearchAgent()
    creative = CreativeAgent()
    
    # 并行创作阶段
    creator_node = ContentCreatorNode()
    parallel_creation = ParallelContentCreation(start=creator_node)
    
    # 整合和质检阶段
    qa_agent = QualityAssuranceAgent()
    final_output = FinalOutputNode()
    
    # 连接流程
    planner - "research" >> researcher
    planner - "creative" >> creative
    planner - "execute" >> parallel_creation
    
    researcher - "creative" >> creative
    creative - "execute" >> parallel_creation
    
    parallel_creation >> qa_agent
    qa_agent - "approve" >> final_output
    
    return Flow(start=planner)

# 使用示例
def demo_content_platform():
    shared = {
        "user_requirements": """
我需要创作一篇关于'人工智能在教育领域应用'的深度文章,
目标读者是教育工作者和技术管理人员。
文章需要包含现状分析、技术解读、案例研究和未来展望。
希望内容专业且易懂,篇幅约3000字。
"""
    }
    
    platform = create_content_creation_platform()
    
    print("🚀 启动智能内容创作平台...")
    platform.run(shared)
    
    print("\n📋 策划方案:")
    print(json.dumps(shared["content_plan"], ensure_ascii=False, indent=2))
    
    print("\n🔍 研究结果:")
    for result in shared["research_results"]:
        print(f"- {result['area']}: {result['findings'][:100]}...")
    
    print("\n💡 创意框架:")
    print(shared["creative_framework"][:300] + "...")
    
    print("\n✍️ 创作结果:")
    for role, content in shared["creation_results"].items():
        print(f"【{role}】: {content[:150]}...")
    
    print("\n✅ 质量评估:")
    print(shared["quality_assessment"])
    
    print("\n🎯 最终输出已完成!")

if __name__ == "__main__":
    demo_content_platform()

项目特点

  1. 多模式融合

    • Agent 模式处理策划和决策
    • Batch 模式实现并行创作
    • Workflow 模式管理整体流程
  2. 可扩展架构

    • 易于添加新的创作角色
    • 支持不同类型的内容创作
    • 可集成外部API和服务
  3. 质量控制

    • 多阶段审核机制
    • 自动化质量评估
    • 迭代优化支持
  4. 并行处理

    • 多个创作任务同时进行
    • 提高整体创作效率
    • 专业化分工协作

最佳实践总结

1. 设计原则

  • 单一职责:每个 Node 只负责一个具体任务
  • 松耦合:通过 shared store 实现数据解耦
  • 可组合:Flow 可以嵌套和重用
  • 故障隔离:合理使用重试和降级机制

2. 性能优化

  • 批处理:对相似任务使用 BatchNode
  • 并行处理:利用 AsyncParallelBatchNode 提升效率
  • 缓存策略:为昂贵的计算添加缓存
  • 资源管理:控制并发数量避免超过API限制

3. 可维护性

  • 结构化数据:使用 YAML/JSON 格式化输入输出
  • 日志记录:在关键节点添加详细日志
  • 错误处理:提供有意义的错误信息和降级方案
  • 文档化:为每个节点和流程编写清晰文档

4. 扩展建议

  • 插件机制:通过配置文件动态加载不同的处理逻辑
  • 监控告警:集成监控系统跟踪性能和错误
  • A/B测试:支持不同策略的对比实验
  • 版本管理:为模型和流程建立版本控制

通过掌握这些概念和实践,你已经具备了使用 PocketFlow 构建复杂 AI 应用的能力。框架的简洁性和灵活性将帮助你快速迭代和优化你的 AI 系统。

posted @ 2025-07-02 14:21  ffl  阅读(331)  评论(0)    收藏  举报