大数跨境
0
0

我是如何构建一个真正理解客户评论的情感分析工具的

我是如何构建一个真正理解客户评论的情感分析工具的 数据驱动智能
2025-11-26
6
使用 LangChain 的表达式语言创建一个人工智能系统,该系统可以从 Google 评论中提取真正的见解
最近,我发现自己经常浏览餐厅评论,想弄清楚一家餐厅是否值得一去。问题是?评论成百上千条,我根本分不清这些抱怨是针对食物、服务,还是仅仅是运气不好。这时我突然意识到:如果我能开发出一个真正理解顾客反馈的工具,那该多好啊!
于是我照做了。在这个过程中,我发现了 LangChain 的表达式语言 (LCEL),它彻底改变了我对构建 AI 应用程序的看法。
一 传统情感分析的问题
大多数情感分析工具都比较基础。它们会告诉你某件事是“正面”还是“负面”,但这其实没什么用。当顾客说“食物很棒,但服务很糟糕”时,你需要知道的是:
  • 他们讨论的是哪些方面(食物与服务)?
  • 他们对每个人的感受有多强烈
  • 他们为什么会有这种感觉
这正是现代语言学习模型(LLM)的优势所在。无需在特定数据集上训练模型,即可使用已经理解语言细微差别、讽刺和语境的GPT模型。它们无需任何训练即可自动提取结构化信息。
二 发现 LangChain LCEL
我刚开始建造这个项目的时候,用的是老方法:
def analyze_sentiment (text): 
    cleaned = clean_text (text) 

    prompt = build_prompt (cleaned) 

    response = llm.invoke (prompt) 

    result = parse_response (response) 

    return result
它确实有效,但过程很混乱。后来我发现了LCEL,一切都豁然开朗了。
LCEL(LangChain表达式语言)允许你使用Python的管道运算符(|`)来构建AI工作流。它类似于Unix管道,但专用于AI。你无需嵌套函数调用,只需编写:
chain = preprocess | prompt | llm | parser 
result = await chain.ainvoke({ "text" : text})
这看似是一个很小的改动,但它会让你的代码:
  • 更易于阅读:思路清晰明了。
  • 更易于修改:可以轻松更换组件。
  • 更易于测试:每个部件都是独立的。
  • 速度更快:内置异步支持和批量处理功能
三 系统工作原理
以下是有人请求分析企业评论时发生的情况:
第一步:查找商家
用户提供类似“
狗不理披萨店”的查询。我们使用 Google Places API 将其转换为一个place_id不会改变的稳定标识符。
步骤二:获取评价 获取
获取地点 ID 后,我们从 Google 获取评论。每条评论包含文本、作者、评分和时间戳。我们仅提取文本部分进行分析。
步骤 3:流程处理
这是 LCEL 的优势所在。每份审核报告都会经过我们的流程处理:
预处理:清理空白字符和编码问题
提示构建:创建包含说明的结构化提示
LLM 处理:发送至 OpenAI GPT 进行分析
解析:验证并构建响应结构
步骤 4:汇总结果
多条评论并行处理(多亏了abatch()),我们返回包含情感分数、方面和解释的结构化数据。
四 构建核心链
应用程序的核心部分位于此处app/chains.py。以下是我的构建方法:
def build_sentiment_chain(model_name: str | None = None): 
    "" " 

    LCEL 链:(预处理) -> prompt -> llm -> Pydantic 解析器

    " "" 

# 步骤 1:创建 Pydantic 输出解析器
    parser = PydanticOutputParser(pydantic_object=ReviewSentiment) 


# 步骤 2:定义系统提示
system = ( 
        "您是一位精准的情感分析师。 " 

        "返回一个严格匹配给定模式的 JSON 对象。\n" 

        "{format_instructions}\n" 

        "评分:negative=-1..-0.05,neutral≈-0.05..0.05,positive=0.05..1.0。\n" 

        "保持理由简洁。如果存在,则提取方面;否则返回空列表。"

     ) 

# 步骤 3:创建提示模板
    prompt = ChatPromptTemplate.from_messages([ 

        ( "system" , 
system ), 
        ( "user" , “分析以下评论的情感。\n” 

                 “语言提示:{language_hint}\n” 

                 “文本:``` 
{text} 

```” ), 

    ]) 

# 步骤 4:初始化 LLM
     llm = build_llm(model_name) 

# 步骤 5:预处理步骤
    pre = RunnableLambda( 

        lambda 
x : { 
            "text" : normalize_text( 
x [ "text" ]), 
            "language_hint" : x.get( "language_hint" ), 

            "format_instructions" : parser.get_format_instructions(), 

        } 

    ) 

# 步骤 6:使用管道运算符构建链 chain
     = pre | prompt | llm | parser 

return chain
让我来逐一解释每个部件的作用:
RunnableLambda:您的自定义逻辑
RunnableLambda它封装了任何 Python 函数,使其成为链式调用的一部分。我用它来做预处理:
pre = RunnableLambda( 
    lambda x: { 

        "text" : normalize_text(x[ "text" ]), 

        "language_hint" : x. 
get ( "language_hint" ), 
        "format_instructions" : parser.get_format_instructions(), 

    } 

)
这会清理文本并在构建提示符之前注入格式指令。它非常适合不需要 LLM 的转换。
ChatPromptTemplate:结构化对话
提示模板将系统指令与用户输入分开:
prompt = ChatPromptTemplate.from_messages([ 
    ( "system" , system), 

    ( "user" , "分析情感..." ) 

])
这一点至关重要,因为:
  • 系统消息设置上下文和角色
  • 用户消息包含实际数据
  • 模板会自动处理变量替换。
它适用于任何聊天模型(OpenAI、Anthropic 等)。
我使用这款软件是gpt-4o-mini因为它速度快、性价比高,而且非常适合情感分析。如果需要更复杂的推理,你可能需要其他工具gpt-4o,但就这个用例而言,迷你版已经足够用了。
PydanticOutputParser:类型安全
这就是奇迹发生的地方。解析器:
  • 从LLM答题中提取文本
  • 解析 JSON
  • 根据您的 Pydantic 模型进行验证
  • 返回一个类型化的 Python 对象
如果 JSON 格式错误或验证失败,它会抛出一个错误,您可以捕获并处理该错误。这确保您始终能获得预期格式的数据。
五 为什么Pydantic模型很重要
我使用 Pydantic 模型来定义我的数据结构:
class  SentimentLabel ( str , Enum): 
    positive = "positive"

     neutral = "neutral"

     negative = "negative" 


class  AspectSentiment ( BaseModel ): 
    aspect: str = Field(..., description= "提及的方面/主题" ) 

    label: SentimentLabel 

    score: float = Field(..., ge= -1.0 , le= 1.0 ) 

class  ReviewSentiment ( BaseModel ): 
    text: str

     language: 
Optional [ str ] = None
     label: SentimentLabel 

    score: float = Field(..., ge= -1.0 , le= 1.0 ) 

    rationale: str = Field(..., description= "简短解释" ) 

    aspects: 
List [AspectSentiment] = Field(default_factory= list )
Pydantic 为您提供:
  • 自动验证:立即检测出无效数据。
  • 类型提示:您的 IDE 知道该预期是什么
  • JSON 模式生成:解析器使用此信息来告知 LLM 要返回的格式。
  • 结构保证:您始终能获得预期格式的数据
它PydanticOutputParser会自动根据您的模型生成格式指令,并将其包含在提示信息中。LLM 可以准确地识别要返回的 JSON 结构,从而显著提高可靠性。
高效处理多条评论
LCEL 最大的优点之一就是它让批量处理变得非常简单:
async def analyze_texts (payload: AnalyzeTextRequest) -> List [ReviewSentiment] : 
    chain = build_sentiment_chain (payload.model_name) 

    inputs = [ 

        {"text": t, "language_hint" : payload.language_hint} 

        for t in payload.texts ]

     #

    并行处理所有评论!

    results: List[ReviewSentiment] = await chain.abatch ( inputs) 

    return results
该abatch()方法处理:
  • 并行执行:所有评论同时处理
  • 速率限制:自动遵守 API 限制。
  • 错误处理:个别故障不会导致批处理停止。
  • 进度跟踪:您可以监控正在发生的事情。
这比顺序处理好得多。无需等待上一个审核完成才能开始下一个,所有审核都是并行进行的。
六 提示工程的艺术
以下是我总结的一些经验:
1.系统消息策略
系统消息设置了上下文。我告诉模型:
“您是一位精准的情感分析师。” 
“返回一个严格符合给定模式的 JSON 对象。\n ” 

“{format_instructions} \n ” 

“评分:负面=-1..-0.05,中性≈-0.05..0.05,正面=0.05..1.0。\n ” 

“保持理由简洁。如果存在,则提取相关方面;否则返回空列表。”
关键要素:
  • 角色定义:“您是一位精准的情感分析师”——这有助于模型采用正确的角色。
  • 格式要求:明确指定要返回的格式。
  • 评分指南:明确的评分范围可避免出现歧义分数。
  • 输出指南:告诉模型何时提取方面以及解释的长度。
2.用户信息设计
用户信息简洁明了:
分析以下评论的情感倾向。\n " 
"语言提示:{language_hint} \n " 

"文本:`"" 


{text} 


`""
我使用三个反引号来清晰地标记文本,并为多语言评论添加语言提示。越简单越好——避免歧义。
3.格式说明
它PydanticOutputParser会自动生成详细的格式说明,如下所示:
输出应格式化为符合以下JSON 模式的 JSON 实例。模式:{   "properties": {     "text": { "title": "文本" , "type" : "string" },     " label ": { "title": "标签" , "enum" : [ "positive" , "neutral" , "negative" ]},     "score": { "title": "分数" , "type" : "number" , "minimum" : -1.0 , "maximum" : 1.0 },     ...   },   "required": [ "text" , "label" , "score" , "rationale" , "aspects" ] }

这确保了LLM确切地知道要返回什么,从而大大提高了可靠性。
七 提高速度:异步和批量处理
我最初开发这个功能的时候,是逐条处理评论的,速度很慢。后来我发现了异步/等待和批量处理的强大功能。
传统方法(慢速):
result1 = analyze(text1)   # 等待 2 秒
result2 = analyze(text2)   
# 等待 2 秒
# 总计:4 秒
新方法(快速):
results = await asyncio.gather( 
    analyze(text1),   
# 立即开始
    analyze(text2)    
# 立即开始

# 总计:约 2 秒(并行)
LCEL 链默认是异步的,所以您可以免费获得此功能。可ainvoke()用于单个项目和abatch()多个项目。
成本优化技巧
运行LLM应用程序成本可能很高。以下是我总结的经验:
令牌使用情况细分:
系统提示:~100 个令牌(每次请求发送一次)
用户提示:每篇评论约需 50-200 个代币
回复:每篇评论约 100-300 个代币
省钱妙招:
  • 批量处理:通过同时处理多个项目来降低开销。
  • 模型选择:gpt-4o-mini价格比其他方法便宜 10 倍gpt-4o,而且非常适合情感分析。
  • 提示优化:更短的提示 = 更低的成本。
  • 缓存:缓存相同评论的结果,以避免重复的 API 调用。
八 我学到了什么
参与这个项目让我学到了几个重要的经验教训:
1. LCEL 使代码更易于维护。
管道运算符 ( |) 创建了一个清晰的流程,易于理解和修改。每个组件都是独立的,这使得测试和调试更加容易。
2. 结构化输出至关重要。
使用 Pydantic 模型可PydanticOutputParser确保您始终获得预期格式的数据。这可以消除一大类错误。
3. Async/await 是你的好帮手
现代 AI 应用需要高效地处理多个请求。LCEL 内置的异步支持让这一切变得自然而然。
4. 提示设计至关重要。
提示的细微改动都可能显著影响输出质量。花时间完善提示——这是值得的。
5. 错误处理至关重要
API 可能会出现故障,网络可能会超时。务必妥善处理错误,并向用户提供有意义的反馈。
使其运作的架构
该系统采用清晰的职责分离原则构建:
  • Google Places 客户端:处理外部 API 调用
  • LCEL链:管理人工智能处理
  • FastAPI:处理 HTTP 请求和响应
  • Pydantic:确保每一步的数据验证
这种模块化方法使得代码库易于理解、测试和扩展。每个组件都只负责一项职责,这大大简化了调试过程。
总结
本项目演示了您将在生产 AI 应用中使用的实际模式。LCEL、Pydantic 和 async/await 的结合为任何基于 LLM 的服务构建了强大的基础。
如果你正在学习生成式人工智能,我强烈推荐:
  • 尝试不同的提示,看看它们如何影响输出
  • 尝试不同的LLM模型以了解它们的优势。
  • 在此基础上构建您自己的功能
  • 部署到生产环境,看看它在负载下的性能如何。
构建人工智能应用不必复杂。借助 LangChain LCEL 等工具,您可以创建功能强大、易于维护且易于理解的系统。这才是真正的优势所在。

点赞转发获取代码



往期推荐

全国首部AI大模型私有化部署标准,公开征集起草单位和个人!

如何构建一个能与数据库对话的人工智能:一段 RAG 之旅

IT项目经理应该如何推动数据治理项目?

面向人工智能企业的5种数据产品采用分发模式

50个我们都在用但没人真正理解的流行语

真正理解人工智能的三个简单原则

高管必须了解哪些内容才能构建数据和人工智能驱动型组织

谈谈实体关系图 (ERD) 与数据血缘关系


【声明】内容源于网络
0
0
数据驱动智能
专注数据治理、数字化转型、数据资产、数据要素等方面的实践分享。
内容 1046
粉丝 0
数据驱动智能 专注数据治理、数字化转型、数据资产、数据要素等方面的实践分享。
总阅读2.2k
粉丝0
内容1.0k