LlamaIndex之Workflow工作流案例

目录:

一、客服工单自动化处理系统简介

场景需求:

  • 输入:客户提交的工单文本(如"订单未收到,物流号123456")。
  • 输出:
  1. 自动分类工单类型(物流/售后/技术问题)。
  2. 检索关联的订单数据、知识库文档。
  3. 生成解决方案草稿(含操作步骤和引用来源)。
  4. 要求:端到端延迟 <3秒,支持历史工单学习。

二、流程设计

三、分步实现与代码解析

1. 定义子工作流(Sub-Workflows)

(1) 工单分类工作流

python 复制代码
from llama_index.core.workflows import Workflow
from llama_index.core import PromptTemplate

# 定义分类Prompt
classify_prompt = PromptTemplate("""\
判断以下工单类型,仅输出物流/售后/技术:
工单内容: {ticket_text}
""")

# 创建分类工作流
classify_workflow = Workflow(
    steps=[
        ("llm_chain", classify_prompt),  # 调用LLM分类
        ("output_parser", lambda x: x.lower().strip())  # 标准化输出
    ],
    name="工单分类"
)

(2) 物流检索工作流

python 复制代码
from llama_index.core import VectorStoreIndex

# 假设已构建物流知识库索引
logistics_index = VectorStoreIndex.from_documents(logistics_docs)

logistics_workflow = Workflow(
    steps=[
        ("retriever", logistics_index.as_retriever(similarity_top_k=2)),
        ("reranker", lambda nodes: sorted(nodes, key=lambda x: x.score, reverse=True)[:1])  # 重排序
    ],
    name="物流检索"
)

2. 组装主工作流

python 复制代码
from llama_index.core.workflows import SequentialWorkflow

main_workflow = SequentialWorkflow(
    steps=[
        classify_workflow,
        {
            "物流": logistics_workflow,
            "default": knowledge_base_workflow  # 其他类型走知识库
        },
        {
            "template": PromptTemplate("""\
            根据以下信息生成解决方案:
            工单类型: {workflow_1_output}
            检索结果: {workflow_2_output}
            """),
            "llm": "gpt-4"
        }
    ],
    verbose=True  # 打印执行日志
)

3. 执行与监控

python 复制代码
# 输入工单
ticket = "订单号123456显示已签收,但未收到货"

# 执行工作流
result = main_workflow.run(ticket_text=ticket)

# 输出结构化结果
print(f"""
工单类型: {result['workflow_1_output']}
解决方案: {result['workflow_3_output']}
引用文档: {result['workflow_2_output'][0].metadata['source']}
""")

工作流流程图:

python 复制代码
     [工单分类] 输入: "订单号123456..." → 输出: "物流"
     [物流检索] 检索到2个节点 → 筛选1个
     [生成] 使用gpt-4生成156 tokens

四、完整代码和优化

结合 LlamaIndex 工作流与性能优化技巧(并行分类/检索、异步生成、缓存复用)。

python 复制代码
import asyncio
from llama_index.core import (
    VectorStoreIndex, SimpleDirectoryReader, PromptTemplate, 
    StorageContext, Document
)
from llama_index.core.workflows import Workflow, SequentialWorkflow, ParallelWorkflow
from llama_index.core.cache import SimpleCache
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding

# #######################
# 0. 初始化全局配置(API密钥、缓存等)
# #######################
llm = OpenAI(model="gpt-3.5-turbo", temperature=0)  # 分类和生成用
embed_model = OpenAIEmbedding()  # 检索用
cache = SimpleCache()  # 缓存工单处理结果

# #######################
# 1. 数据准备:知识库索引构建(启用缓存)
# #######################
def load_knowledge_base():
    """加载客服知识库文档并构建索引(缓存优化)"""
    storage_context = StorageContext.from_defaults(cache=cache)
    
    # 假设知识库包含物流/售后/技术文档
    documents = [
        Document(text="物流问题处理流程:1. 核对订单号 2. 联系物流公司", metadata={"type": "物流"}),
        Document(text="售后退货步骤:提交申请→寄回商品→退款", metadata={"type": "售后"}),
        Document(text="API故障排查:检查token有效期和接口权限", metadata={"type": "技术"})
    ]
    
    # 并行构建两种索引
    with ParallelWorkflow() as parallel:
        vector_index = parallel.add_step(
            VectorStoreIndex.from_documents,
            args=(documents,),
            kwargs={"embed_model": embed_model, "storage_context": storage_context},
            description="向量索引"
        )
        keyword_index = parallel.add_step(
            KeywordTableIndex.from_documents,
            args=(documents,),
            description="关键词索引"
        )
    return vector_index, keyword_index

# #######################
# 2. 定义子工作流(模块化复用)
# #######################
def create_classify_workflow():
    """工单分类工作流(复用LLM)"""
    return Workflow(
        steps=[
            ("llm", PromptTemplate("判断工单类型(物流/售后/技术): {ticket_text}")),
            ("output_parser", lambda x: x.split(":")[-1].strip())
        ],
        output_key="ticket_type",
        name="工单分类"
    )

def create_retrieve_workflow(index, workflow_type):
    """检索工作流(动态路由到不同知识库)"""
    return Workflow(
        steps=[
            ("retriever", index.as_retriever(similarity_top_k=2)),
            ("reranker", lambda nodes: [n for n in nodes if n.metadata["type"] == workflow_type])
        ],
        output_key=f"{workflow_type}_docs",
        name=f"{workflow_type}检索"
    )

# #######################
# 3. 主工作流(异步+缓存+并行)
# #######################
async def process_ticket(ticket_text, vector_index, keyword_index):
    """处理单个工单的完整工作流"""
    # 定义子工作流
    classify_wf = create_classify_workflow()
    logistics_wf = create_retrieve_workflow(vector_index, "物流")
    tech_wf = create_retrieve_workflow(keyword_index, "技术")
    
    # 主工作流(条件路由+并行检索)
    main_workflow = SequentialWorkflow(
        steps=[
            # 第一步:分类
            classify_wf,
            
            # 第二步:根据类型并行检索
            {
                "物流": logistics_wf,
                "技术": tech_wf,
                "default": create_retrieve_workflow(vector_index, "售后")
            },
            
            # 第三步:异步生成解决方案
            {
                "template": PromptTemplate("""
                根据工单类型「{ticket_type}」和以下信息生成解决方案:
                 {{{ticket_type}_docs}}  # 动态注入变量名,如 {物流_docs}
                要求:列出步骤并标注来源
                """),
                "llm": llm,
                "mode": "async"  # 启用异步生成
            }
        ],
        verbose=True  # 打印执行日志
    )
    
    # 执行工作流(优先读缓存)
    cache_key = f"ticket_{hash(ticket_text)}"
    if cache_key in cache:
        print("命中缓存!")
        return cache.get(cache_key)
    
    result = await main_workflow.arun(ticket_text=ticket_text)
    
    # 缓存结果(有效期60秒)
    cache.put(cache_key, result, expire=60)
    return result

# #######################
# 4. 批量处理工单(性能测试)
# #######################
async def batch_process_tickets(tickets):
    """并发处理多个工单"""
    # 初始化知识库
    vector_index, keyword_index = load_knowledge_base()
    
    # 启动异步任务
    tasks = [process_ticket(t, vector_index, keyword_index) for t in tickets]
    return await asyncio.gather(*tasks)

# #######################
# 示例运行
# #######################
if __name__ == "__main__":
    # 测试工单
    test_tickets = [
        "我的订单123456物流显示签收但未收到",
        "API接口返回500错误",
        "想退货但找不到入口"
    ]
    
    # 异步执行
    results = asyncio.run(batch_process_tickets(test_tickets))
    
    # 打印结果
    for ticket, solution in zip(test_tickets, results):
        print(f"工单: {ticket}")
        print(f"解决方案: {solution}\n")

流程图:


关键总结:

相关推荐
栗少2 小时前
雅思口语高分进阶:从“中式表达”到“母语者逻辑”的深度重构
人工智能
落雨盛夏2 小时前
深度学习|李哥考研2
人工智能·深度学习
美狐美颜sdk2 小时前
人脸美型美颜SDK在直播平台中的实现方式与开发策略
人工智能·音视频·美颜sdk·视频美颜sdk·美狐美颜sdk
zpedu2 小时前
软考想一次过,有一个学习衡量标准吗?
人工智能·笔记
人工智能AI技术3 小时前
【Agent从入门到实践】25 主流向量数据库速览:Pinecone、Chroma、Milvus,本地/云端选型建议
人工智能·python
liliangcsdn3 小时前
VS Code开源LLM编程插件的调研
人工智能
私域合规研究3 小时前
2026年私域的八大挑战及发展方向
大数据·人工智能
在线打码3 小时前
禅道二次开发:项目月报整合Dify工作流实现AI智能分析
人工智能·ai·禅道·工作流·dify
nihao5613 小时前
Mumu 模拟器配置host代理
人工智能