data science/AI Agents

CrewAI & LangChain - 영업 통화 분석

꼰대코더 2025. 10. 16. 13:09

 

목표는 영업 통화의 오디오를 텍스트로 변환하고, 자연어 처리(NLP) 기술을 활용해 전사된 내용을 분석하며, 감정 분석, 핵심 문구, 고객의 문제점, 개선을 위한 제안 등을 포함한 상세한 보고서를 생성.

 

주요 구성 요소

  • 오디오 변환(Audio Transcription): OpenAI Whisper를 사용하여 통화 오디오를 텍스트로 변환합니다.
  • 통화 분석(Call Analysis): 감정 분석, 핵심 문구 추출, 고객의 문제점 파악, 상담원의 대응 효과성 평가 등 전사된 내용을 분석하기 위한 작업을 정의합니다.
  • 작업 자동화(Task Automation): CrewAI의 에이전트 및 태스크 프레임워크를 활용하여 분석 프로세스를 구조화하고 자동화합니다.
  • 보고서 생성(Report Generation): 영업 통화 개선을 위한 실행 가능한 인사이트를 포함한 상세하고 체계적인 보고서를 생성합니다.
from langchain_community.document_loaders.parsers import OpenAIWhisperParser
from langchain_core.documents.base import Blob
from dotenv import load_dotenv
from textwrap import dedent
from crewai import Task, Agent, Crew
from langchain_openai import ChatOpenAI
import asyncio

 

.env   화일을 생성해서 아래와 같이 키를 입력한 후 파이선 코드에서 load_dotenv() 를 기술하면 키가 자동적으로 설정됩니다.

OPENAI_API_KEY="YOUR_KEY"

 

OpenAI Whisper(유료)를 이용한 영업통화의 텍스트 변환

parser = OpenAIWhisperParser()

# Function to transcribe audio using OpenAI Whisper
def transcribe_audio(audio_path: str) -> str:
    """
    Transcribe audio from a given file path using OpenAI Whisper.

    Args:
        audio_path (str): The path to the audio file to be transcribed.

    Returns:
        str: The transcribed text from the audio.
    """
    try:
        # Initialize the Blob with the given audio path
        audio_blob = Blob(path=audio_path)

        # Transcribe the audio
        documents = parser.lazy_parse(blob=audio_blob)

        # Collect and return the transcription as a single string
        transcription = ""
        for doc in documents:
            transcription += doc.page_content

        return transcription

    except Exception as e:
        print(f"Error during transcription: {e}")
        return ""

 

CrewAI 의 기본 개념을 짚고 넘어가지.

Agent 와 Task 를 정의하고 Task에는  속할 Agent를 지정한다. 이들을 Crew 에 등록해서 호출, 사용하게 된다.

Task : Call Analysis

# Define the MyTasks class that will structure the task for analysis
class MyTasks():
    def call_analysis_task(self, transcription, call_analysis_agent):
        return Task(
            description=dedent(f"""
            고객과 상담원 간의 영업 통화 변환 텍스트를 분석하세요.
            다음 항목을 포함한 상세하고 종합적인 보고서를 생성하십시오:

            - 감정 분석(Sentiment Analysis): 통화 전반에서 고객의 어조와 감정 상태를 평가합니다.
            - 핵심 문구(Key Phrases): 고객의 관심사, 우려 사항 또는 반대 의견을 나타내는 중요한 문구를 추출합니다.
            - 고객의 문제점(Customer Pain Points): 통화 중 고객이 표현한 구체적인 문제나 장애 요인을 식별합니다.
            - 상담원 효과성 점수(Agent Effectiveness Score): 상담원이 통화를 처리한 성과를 10점 만점으로 평가합니다.
            - 판매 기회(Sales Opportunities): 업셀링(upselling) 또는 교차 판매(cross-selling)의 가능성을 강조합니다.
            - 경쟁사 언급(Competitor Mentions): 고객이 경쟁사를 언급한 경우, 어떤 내용이 언급되었는지 기록합니다.
            - 통화 몰입도(Call Engagement): 대화 중 고객의 참여도를 분석합니다 (예: 질문 빈도, 반응성, 어조 등).
            - 개선 제안(Recommendations): 상담원이 향후 통화에서 접근 방식을 개선할 수 있도록 맞춤형 조언을 제공합니다.
            - 실행 가능한 인사이트(Actionable Insights): 상담원과 고객 각각에게 명확한 다음 단계, 책임자, 그리고 일정이 포함된 실행 계획을 제시합니다.

            응답은 다음 키를 포함한 JSON 객체 형태로 구조화해야 합니다:
            - sentiment_analysis
            - key_phrases
            - customer_pain_points
            - agent_effectiveness_score
            - sales_opportunities
            - competitor_mentions
            - call_engagement
            - recommendations
            - actionable_insights

            각 항목에 관련된 정보가 없거나 찾을 수 없는 경우, 해당 키의 값으로 "No relevant information found"를 명시해야 합니다.
            JSON은 간결하고, 체계적이며, 전문적인 형식으로 작성해야 합니다.

            다음은 분석할 텍스트 내용입니다:
                {transcription}
            """),
            expected_output=dedent("""
            {
                "sentiment_analysis": "고객의 상호작용에서 드러난 감정 상태를 설명하며, 주목할 만한 감정적 어조나 망설임이 있었는지를 기술합니다.",
                "key_phrases": [
                    "고객의 주요 관심사, 우려 사항, 또는 선호도를 나타내는 핵심 문구를 나열합니다."
                ],
                "customer_pain_points": [
                    "대화 중 고객이 제기한 구체적인 문제, 반대 의견, 또는 불만 사항을 나열합니다."
                ],
                "agent_effectiveness_score": "상담원의 커뮤니케이션 능력, 문제 해결력, 공감 능력 등을 바탕으로 성과를 평가하고 점수를 제공합니다.",
                "sales_opportunities": [
                    "대화 내용을 기반으로 업셀링(upselling) 또는 교차 판매(cross-selling)의 잠재적 기회를 식별합니다.",
                    "고객에게 가치를 제공하거나 매출을 증대시킬 수 있는 제안을 포함합니다."
                ],
                "competitor_mentions": "고객이 언급한 경쟁사 및 관련 맥락(예: 기능, 가격, 서비스 등)을 기술합니다.",
                "call_engagement": "통화 중 고객의 참여 수준을 설명하고, 침묵, 주저, 또는 활발한 대화가 있었는지 기록합니다.",
                "recommendations": "대화 분석을 기반으로 상호작용을 개선하거나 향후 영업 성과를 높이기 위한 전략적 제안을 제공합니다.",
                "actionable_insights": [
                    {
                        "action": "고객의 문제를 해결하거나 영업 프로세스를 개선하기 위해 취할 수 있는 구체적인 조치를 기술합니다.",
                        "assigned_to": "해당 조치를 담당할 개인 또는 팀을 명시합니다.",
                        "timeline": "조치를 완료해야 하는 기간 또는 마감일을 제시합니다."
                    }
                ]
            }
            """),
            agent=call_analysis_agent
        )

 

Agent : call_analysis_agent 

class MyAgents():
    # Define the agents
    def call_analysis_agent(self, model):
        return Agent(
            role="AI-Powered Call Analyzer",
            goal="영업 통화 텍스트 데이터를 기반으로 실행 가능한 인사이트와 고급 성과 분석을 제공하여, 상담원이 더욱 효과적으로 거래를 성사시킬 수 있도록 지원합니다.",
            backstory="AI 기반 통화 분석기는 감정 분석을 통해 영업 대화를 평가하고, 고객의 문제점을 식별하며, 더 나은 성과를 위한 구체적인 개선 제안을 제공합니다.",
            verbose=True,
            allow_delegation=False,
            llm=model
        )

 

실행할 내용들을 하나의 함수에 정의

async def get_final_conversation_result(transcription):
    # Define the LLM model
    llm = ChatOpenAI(model="gpt-4o-2024-08-06", temperature=0.7)

    # Define the Agents
    my_agents = MyAgents()
    better_call_analysis_agent = my_agents.call_analysis_agent(llm)

    # Define the Tasks
    my_tasks = MyTasks()
    better_call_analysis_task = my_tasks.call_analysis_task(transcription, better_call_analysis_agent)

    # Start the Crew
    crew = Crew(
        agents=[better_call_analysis_agent],
        tasks=[better_call_analysis_task],
        verbose=True,
    )

    # Get the result from the crew
    result = crew.kickoff()

    return result

 

audio_path = "./dog.mp3"  # Replace with the actual path to your audio file
transcribed_text = transcribe_audio(audio_path)

if transcribed_text:
    print("Transcribed Text:\n", transcribed_text)

    # Get the final conversation result after analysis
    analysis_result = await get_final_conversation_result(transcribed_text)
    print("\nAnalysis Result:\n", analysis_result)