허세임
허세임
⚔️ 베테랑 파트너
📹 SNS 찐친

Make 뉴스레터 자동화를 LangChain으로: claude와 json parser

안녕하세요. 허세임 입니다. 저는 건강습관 뉴스레터를 발행하고 있습니다. 관심있으신 분은 여기서 신청해주세요. 이 뉴스레터는 지난 스터디에서 Make.com으로 자동화를 구축하여 발행되고있습니다. 이번 Langchain 스터디에서는 Make에서의 한계를 극복하고 더욱 강력하고 유연한 시스템으로 발전시키고자 합니다.

흰색 배경에 색연필 한 줄

프로젝트 배경 및 목표

  • 시작점: Make.com에서 워크플로우 구축

  • 현재 단계: LangChain을 이용한 Python 기반 시스템으로 전환 (1단계)

  • 최종 목표: 완전 자동화된 개인화 건강 뉴스레터 생성 및 배포 시스템

현재 구현 단계

  1. 텍스트 기반 뉴스레터 콘텐츠 생성

  2. 뉴스레터용 이미지 생성 프롬프트 작성

사용 기술

  • Python

  • LangChain

  • Anthropic Claude AI

  • YAML (프롬프트)

  • JSON (데이터 구조화)

LangChain 주요 개념 및 사용된 함수

1. ChatPromptTemplate

ChatPromptTemplate은 AI 모델에 전달할 프롬프트를 템플릿화하는 데 사용됩니다. 이를 통해 동적으로 프롬프트를 생성할 수 있습니다.

from langchain.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("human", "다음 정보로 뉴스레터를 작성해주세요: {topic}")
])

2. ChatAnthropic

ChatAnthropic은 Anthropic의 Claude 모델을 LangChain에서 사용할 수 있게 해주는 래퍼 클래스입니다.

from langchain_anthropic import ChatAnthropic

model = ChatAnthropic(
    model="claude-3-sonnet-20240229",
    temperature=0.7,
    max_tokens=4000,
    anthropic_api_key=ANTHROPIC_API_KEY
)

3. JsonOutputParser

JsonOutputParser는 AI 모델의 출력을 구조화된 JSON 형식으로 파싱합니다. 이는 모델의 출력을 일관된 형식으로 만드는 데 중요합니다.

from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field

class NewsletterContent(BaseModel):
    title: str = Field(description="뉴스레터 제목")
    content: str = Field(description="뉴스레터 내용")

parser = JsonOutputParser(pydantic_object=NewsletterContent)

4. RunnableSequence

RunnableSequence는 여러 LangChain 컴포넌트를 연결하여 하나의 실행 가능한 체인으로 만듭니다. 이는 복잡한 워크플로우를 구성하는 데 매우 유용합니다.

from langchain.schema.runnable import RunnableSequence

newsletter_chain = RunnableSequence(
    prompt,
    model,
    parser
)

이 체인은 다음과 같은 순서로 작동합니다:

  1. prompt를 사용해 입력을 포맷팅

  2. 포맷팅된 프롬프트를 model에 전달하여 응답 생성

  3. 생성된 응답을 parser를 통해 구조화된 JSON으로 변환

5. 체인 실행

구성된 체인은 invoke 메서드를 통해 실행할 수 있습니다:

result = newsletter_chain.invoke({"topic": "건강한 식습관"})

주요 구현 내용

1. 환경 설정 및 라이브러리 import

import os
import yaml
import json
from pydantic import BaseModel, Field
from dotenv import load_dotenv
from langchain_anthropic import ChatAnthropic
from langchain_core.output_parsers import JsonOutputParser
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableSequence

load_dotenv()

2. YAML 설정 파일 로드 및 프롬프트 생성 함수

def load_yaml_and_create_prompt(file_path: str, user_name: str, topic: str, title: str, habit: str) -> ChatPromptTemplate:
    with open(file_path, 'r', encoding='utf-8') as file:
        yaml_data = yaml.safe_load(file)

    # YAML 데이터를 사용하여 프롬프트 템플릿 생성
    prompt_content = f"""주간 건강습관 뉴스레터를 작성해주세요. 다음 정보를 사용하세요:

사용자 이름: {user_name}
주제: {topic}
제목: {title}
이번 주 건강습관: {habit}

다음 가이드라인을 따라주세요:
"""
    # YAML 데이터를 기반으로 프롬프트 내용 구성
    ...

    return ChatPromptTemplate.from_messages([
        ("human", prompt_content)
    ])

이 함수는 YAML 파일에서 뉴스레터 구조와 가이드라인을 로드하고, 이를 바탕으로 동적인 프롬프트 템플릿을 생성합니다.

name_placeholder: "ㅎ이름자리ㅎ"
guide:
  sections:
    - section: "사용자 이름 언급"
      details:
        - "중간중간 사용자의 이름을 언급하세요. 사용자의 이름은 'ㅎ이름자리ㅎ'으로 표기"
        - "예: 이번주는 ㅎ이름자리ㅎ님의 날입니다."

    - section: "제목"
      details:
        - "제공된 제목을 사용하세요."

    - section: "도입부 (약 150단어)"
      details:
        - "독자의 관심을 끄는 질문이나 통계로 시작하세요."
        - "이번 주 건강습관과 관련된 건강 주제를 소개하세요."

    - section: "이번 주 건강습관 소개 (약 200단어)"
      details:
        - "실천할 구체적인 건강습관을 명확히 설명하세요."
        - "언제, 어디서, 어떻게 실천할 수 있는지 구체적으로 안내하세요."

    - section: "과학적 근거 및 기전 설명 (약 600단어)"
      details:
        - "해당 습관의 효과를 뒷받침하는 2-3개의 핵심 연구나 관련 기사를 인용하세요."
        - "각 연구나 기사에 대해 출처(저자, 발행년도, 저널명 또는 웹사이트 등)를 구체적으로 제시하세요."
        - "이 습관이 건강에 도움이 되는 자세한 기전과 원리를 쉽게 설명하세요."
        - "복잡한 생물학적 과정을 일상생활의 비유를 사용해 설명하세요."

    - section: "기대효과 (약 300단어)"
      details:
        - "이 습관을 꾸준히 실천했을 때 기대할 수 있는 단기 및 장기 효과를 설명하세요."
        - "가능하다면 수치나 구체적인 예시를 포함하세요."
        - "앞서 설명한 기전과 연결 지어 왜 이런 효과가 나타나는지 설명하세요."

    - section: "실천 팁 (약 300단어)"
      details:
        - "습관을 쉽게 실천할 수 있는 4-5가지 팁을 제공하세요."
        - "각 팁에 대해 상세한 설명과 예시를 덧붙이세요."
        - "가능하다면 각 팁이 어떻게 앞서 설명한 기전과 연관되는지 설명하세요."

    - section: "주의사항 (약 150단어)"
      details:
        - "습관 실천 시 주의해야 할 점이나 피해야 할 사항을 안내하세요."
        - "필요하다면 전문가의 조언을 구해야 하는 상황도 명시하세요."

    - section: "추가 정보 및 관련 연구 (약 400단어)"
      details:
        - "주제와 관련된 추가적인 연구 결과나 최신 트렌드를 소개하세요."
        - "이 정보들이 어떻게 주간 건강습관과 연관되는지 설명하세요."
        - "가능하다면 이 분야의 향후 연구 방향이나 전망에 대해 언급하세요."

    - section: "독자 참여 유도 (약 100단어)"
      details:
        - "독자들에게 이번 주 습관 실천 경험을 공유해달라고 요청하세요."
        - "다음 주 건강습관에 대한 아이디어나 의견을 물어보세요."

    - section: "마무리 (약 100단어)"
      details:
        - "이번 주 건강습관의 핵심 메시지를 다시 한 번 강조하세요."
        - "실천을 독려하는 긍정적인 메시지로 마무리하세요."

additional_guidelines:
  - "전체 길이는 2000-2200단어로 유지하세요."
  - "'-습니다', '-입니다'와 '-요', '-죠'를 2:3 비율로 적절히 섞어 사용하세요."
  - "전문 용어는 가능한 쉽게 풀어서 설명하세요."
  - "문장은 간결하게, 단락은 3-4문장으로 구성하세요."
  - "중간중간 흥미로운 부제목을 사용하세요."
  - "실천 가능성과 효과를 강조하되, 과장된 표현은 피하세요."
  - "복잡한 개념을 설명할 때는 일상생활의 예시나 비유를 활용하세요."
  - "중간중간 사용자의 이름을 불러주세요. 사용자의 이름은 'ㅎ이름자리ㅎ'으로 표기하세요."

output_format:
  - title: "주간 건강습관 뉴스레터: [주제]"
  - introduction: "도입부 내용"
  - habit_intro: "이번 주 건강습관 소개 내용"
  - scientific_evidence: "과학적 근거 및 기전 설명 내용"
  - expected_effects: "기대효과 내용"
  - practical_tips: "실천 팁 내용"
  - precautions: "주의사항 내용"
  - additional_info: "추가 정보 및 관련 연구 내용"
  - reader_participation: "독자 참여 유도 내용"
  - conclusion: "마무리 내용"

3. 뉴스레터 생성 체인 구성

parser = JsonOutputParser(pydantic_object=NewsletterContent)
prompt = load_yaml_and_create_prompt(prompt_file, user_name, topic, title, habit)
model = ChatAnthropic(
    model="claude-3-sonnet-20240229",
    temperature=0.7,
    max_tokens=4000,
    anthropic_api_key=ANTHROPIC_API_KEY
)

newsletter_chain = RunnableSequence(
    prompt,
    model,
    parser
)

이 코드는 프롬프트, AI 모델, 그리고 출력 파서를 하나의 실행 가능한 체인으로 연결해서 실행합니다.

4. 이미지 프롬프트 생성 함수

뉴스레터 내용을 생성했다면, 이 내용으로 이미지 생성 프롬프트도 만들어야 합니다.

def create_image_prompts(newsletter_content: NewsletterContent) -> RunnableSequence:
    prompt_template = """다음 뉴스레터 내용을 바탕으로 3개의 이미지 생성 프롬프트를 만들어주세요:

1. 도입부: {introduction}
2. 이번 주 건강습관: {habit_intro}
3. 기대효과: {expected_effects}

각 이미지 프롬프트는 다음 형식을 따라야 합니다:
[구체적인 동작 또는 상황 설명]. The overall color scheme is pastel, with brand colors (#004a30, #ff4a1c) used sparingly for emphasis on key elements. The background is a soft pastel blue. The illustration style is flat and simple with white space around the main elements. The design is a vector graphic in a minimalist flat style with no shadows, suitable for various media applications. Do not include any logos or text. --ar 16:9 --stylize 1000 --v 5.2

응답은 반드시 다음 형식의 유효한 JSON 객체로만 제공해주세요:

{format_instructions}
"""

    prompt = ChatPromptTemplate.from_template(prompt_template)

    model = ChatAnthropic(
        model="claude-3-sonnet-20240229",
        temperature=0.7,
        max_tokens=1000,
        anthropic_api_key=ANTHROPIC_API_KEY
    )

    parser = JsonOutputParser(pydantic_object=ImagePrompts)

    return RunnableSequence(
        prompt,
        model,
        parser
    )

이 함수는 생성된 뉴스레터 콘텐츠를 바탕으로 이미지 생성 프롬프트를 만드는 새로운 체인을 구성합니다.

정리된 플로우 입니다

프로젝트의 단계를 보여주는 순서도

결과

한국어 스크립트의 스크린샷

컴퓨터에 있는 한국어 텍스트 스크린샷

CursorAI도 아닌, Replit도 아닌 Claude Project

Google 검색 페이지의 스크린샷

랭체인 최근 도큐먼트들, 내가 해야하는 일, 완성된 코드 등 지식으로 넣어두고 작업하고 작업하면서 하나씩 더 추가해나가면서 개발하면 대화가 잘된다. 현재까지 나온 툴중에 나와 가장 잘 맞는 방법.

다음 단계 계획

  1. 이미지 생성 구현: 생성된 이미지 프롬프트를 바탕으로 실제 이미지를 생성하는 기능을 추가할 예정입니다.

  2. HTML 템플릿 생성: 텍스트 콘텐츠와 이미지를 조합하여 HTML 형식의 뉴스레터를 만들 계획입니다.

  3. 이메일 발송 자동화: 생성된 HTML 뉴스레터를 자동으로 이메일로 발송하는 기능을 구현할 예정입니다.

결론

테디노트님의 강의를 들어도 들어도 끝이 없어서 일단 클로드랑 상의하면서 만들어보았습니다. 그래도 중간중간 어떤함수가 어떤역할을 하는지 강의에서 들은게 있어 빨리 진행되었습니다. ChatGPT에는 JSON 모드가 있지만 Claude에는 따로 없어서 이를 처리하게 위한 자잘한 조치들이 많이 필요했습니다. 그 과정에서 에러가 많이 났습니다.

현재는 첫 번째 단계인 텍스트 생성과 이미지 프롬프트 생성을 완료했으며, 앞으로 이미지 생성, HTML 조합, 이메일 발송 등의 기능을 순차적으로 구현해 나갈 예정입니다. 이 과정에서 AI 모델의 활용, 효과적인 프롬프트 엔지니어링, 그리고 복잡한 워크플로우의 코드화에 대해 많은 것을 배우고 있습니다.

7
2개의 답글

👉 이 게시글도 읽어보세요