LangChain 은 언어 모델로 구동되는 애플리케이션을 개발하기 위한 프레임워크로서 개발자가 LLM 및 AI의 강력한 기능을 사용하여 데이터를 분석할 수 있도록 해줍니다. LangChain과 파이썬을 이용하여 자신만의 AI 앱을 구축해 보세요.
※ 이 글은 아래 기사 내용을 토대로 작성되었습니다만, 필자의 개인 의견이나 추가 자료들이 다수 포함되어 있습니다.
- 원문: 7 Best Online Business Analytics Programs With Certificates
- URL: https://azednews.com/best-online-business-analytics-programs-with-certificates/
준비
아래에서 소개하는 작업을 진행하려면 새로운 폴더를 만들고 pip를 사용하여 LangChain과 OpenAI를 설치해야 합니다.
pip3 install langchain openai
파일 읽기, 텍스트 분할 및 데이터 추출
책과 같은 큰 텍스트를 분석하려면 텍스트를 더 작은 덩어리로 분할해야 합니다. 책과 같은 대용량 텍스트에는 수십만 ~ 수백만 개의 토큰이 포함되어 있고, 그 많은 토큰을 한 번에 처리할 수 있는 LLM이 아직 없기 때문입니다. 또한 각 텍스트 덩어리에 대한 개별 프롬프트 출력을 저장하는 대신 템플릿을 사용하여 데이터를 추출하고 이를 JSON 또는 CSV와 같은 형식으로 저장하는 것이 더 효율적입니다. 이 글에서는 JSON을 사용하겠습니다.
이 예제에서 사용할 책은 [여기]에서 확인할 수 있습니다. 이 책은 Project Gutenberg에서 무료로 다운로드했습니다. 이 [코드]는 프리드리히 니체(Friedrich Nietzsche)의 책 Beyond Good and Evil 을 읽고, 장으로 나누고, 첫 번째 장의 요약을 만들고, 본문에 제시된 철학적 메시지, 윤리 이론 및 도덕 원칙을 추출하여 모두 JSON 형식으로 저장합니다.
필자는 'gpt-3.5-turbo-1106' 모델을 사용하여 최대 16000개 토큰과 0.3 temperature의 더 큰 컨텍스트로 작업하여 약간의 창의성을 부여했습니다.
[참고] temperature 매개변수는 LLM이 창의적이고 때로는 무작위로 답변할 수 있는 자유를 결정합니다. 온도가 낮을수록 LLM 출력은 더욱 사실적이며, 온도가 높을수록 LLM 출력은 더욱 창의적이고 무작위적입니다.
추출된 데이터는 create_structured_output_chain과 제공된 JSON 스키마를 사용하여 JSON 형식으로 변환됩니다.
json_schema = {
"type": "object",
"properties": {
"summary": {"title": "Summary", "description": "The chapter summary", "type": "string"},
"messages": {"title": "Messages", "description": "Philosophical messages", "type": "string"},
"ethics": {"title": "Ethics", "description": "Ethical theories and moral principles presented in the text", "type": "string"}
},
"required": ["summary", "messages", "ethics"],
}
chain = create_structured_output_chain(json_schema, llm, prompt, verbose=False)
코드는 책이 포함된 텍스트 파일을 읽고 이를 장별로 나눕니다. 체인에는 책의 첫 번째 장이 텍스트 입력으로 제공됩니다.
f = open("texts/Beyond Good and Evil.txt", "r")
phi_text = str(f.read())
chapters = phi_text.split("CHAPTER")
print(chain.run(chapters[1]))
출력 결과는 다음과 같습니다.
{'summary': 'The chapter discusses the concept of utilitarianism and its application in ethical decision-making. It explores the idea of maximizing overall happiness and minimizing suffering as a moral principle. The chapter also delves into the criticisms of utilitarianism and the challenges of applying it in real-world scenarios.', 'messages': 'The chapter emphasizes the importance of considering the consequences of our actions and the well-being of all individuals affected. It encourages thoughtful and empathetic decision-making, taking into account the broader impact on society.', 'ethics': 'The ethical theories presented in the text include consequentialism, hedonistic utilitarianism, and the principle of the greatest good for the greatest number.'}
정말 멋진. 150년 전에 쓰여진 철학적 텍스트는 읽고 이해하기가 꽤 어렵지만, 이 코드는 첫 번째 장의 주요 요점을 해당 장의 요약, 메시지 및 윤리 이론/도덕 원칙에 대한 이해하기 쉬운 보고서로 즉시 번역했습니다.
이제 모든 장에 대해 동일한 작업을 수행하고 이 코드를 사용하여 모든 것을 JSON 파일에 넣을 수 있습니다. 큰 텍스트로 작업할 때 속도 제한에 도달할 가능성이 있기 때문에, 대부분 OpenAI API의 무료 티어를 사용하는 경우 time.sleep(20)을 주석으로 추가했습니다. 실수로 계정이 고갈되지 않도록 요청에 얼마나 많은 토큰과 크레딧을 사용하고 있는지 알면 편리할 것 같아서, 각 챕터에 얼마나 많은 토큰과 크레딧이 사용되는지 확인하기 위해 get_openai_callback()을 cb:로 사용했습니다.
모든 장을 분석하고 각 장에 대해 추출된 데이터를 공유 JSON 파일에 저장하는 코드의 일부입니다.
for chi in range(1, len(chapters), 1):
with get_openai_callback() as cb:
ch = chain.run(chapters[chi])
print(cb)
print("\n")
print(ch)
print("\n\n")
json_object = json.dumps(ch, indent=4)
if chi == 1:
with open("Beyond Good and Evil.json", "w") as outfile:
outfile.write("[\n"+json_object+",")
elif chi < len(chapters)-1:
with open("Beyond Good and Evil.json", "a") as outfile:
outfile.write(json_object+",")
else:
with open("Beyond Good and Evil.json", "a") as outfile:
outfile.write(json_object+"\n]")
1장 앞에 0장이 없기 때문에 chi 인덱스는 1에서 시작합니다. chi 인덱스가 1(첫 번째 챕터)이면 코드가 JSON 데이터를 파일에 쓰고(기존 콘텐츠를 덮어씁니다), 시작 부분에 여는 대괄호와 새 줄을 추가하고 끝에 쉼표를 추가하여 JSON 구문을 따릅니다. chi가 최소값(1)이나 최대값(len(chapters)-1)이 아닌 경우, JSON 데이터는 그냥 파일에 추가되고 마지막에 쉼표가 추가됩니다. 마지막으로, chi가 최대값이면 새 줄과 닫는 대괄호와 함께 JSON이 JSON 파일에 추가됩니다.
코드 실행이 완료되면 모든 챕터에서 추출한 정보로 Beyond Good and Evil.json이 채워진 것을 볼 수 있습니다.
여러 파일 작업
수십 개의 개별 파일을 하나씩 분석하려는 경우 방금 본 것과 유사한 스크립트를 사용할 수 있지만, 챕터별로 반복하는 대신 폴더에 있는 파일을 반복합니다.
여기서는 상위 10위 테니스 선수(2023년 12월 3일 기준)에 대한 Wikipedia 문서로 채워진 top_10_tennis_players라는 폴더를 예로 들어 보겠습니다. 폴더는 여기에서 다운로드할 수 있습니다. 이 코드는 각 Wikipedia 기사를 읽고 각 선수의 나이, 키, 가장 빠른 서브(km/h)를 추출한 후 추출된 데이터를 player_data라는 별도의 폴더에 JSON 파일로 저장합니다.
다음은 추출된 선수 데이터 파일의 예시입니다.
그러나 이 코드는 그렇게 간단하지 않습니다. 청크 분할 없이 분석하기에는 너무 큰 텍스트에서 가장 정확한 데이터를 효율적이고 안정적으로 추출하기 위해 다음 코드를 사용했습니다.
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=16000,
chunk_overlap=2000,
length_function=len,
add_start_index=True,
)
sub_texts = text_splitter.create_documents([player_text])
ch = []
for ti in range(len(sub_texts)):
with get_openai_callback() as cb:
ch.append(chain.run(sub_texts[ti]))
print(ch[-1])
print(cb)
print("\n")
# time.sleep(10) if you hit rate limits
for chi in range(1, len(ch), 1):
if (ch[chi]["age"] > ch[0]["age"]) or (ch[0]["age"] == "not found" and ch[chi]["age"] != "not found"):
ch[0]["age"] = ch[chi]["age"]
break
if (ch[chi]["serve"] > ch[0]["serve"]) or (ch[0]["serve"] == "not found" and ch[chi]["serve"] != "not found"):
ch[0]["serve"] = ch[chi]["serve"]
break
if (ch[0]["height"] == "not found") and (ch[chi]["height"] != "not found"):
ch[0]["height"] = ch[chi]["height"]
break
else:
continue
이 코드는 다음을 수행합니다:
- 텍스트를 16000 토큰 크기의 청크로 분할하고, 청크 겹침은 2000으로 하여 약간의 컨텍스트를 유지합니다.
- 각 청크에서 지정된 데이터를 추출합니다.
- 최신 청크에서 추출한 데이터가 첫 번째 청크의 데이터보다 더 관련성이 높거나 정확할 경우(또는 첫 번째 청크에는 없는 값이 최신 청크에서 발견될 경우) 첫 번째 청크의 값을 조정합니다. 예를 들어, 청크 1의 '나이'가 26이고 청크 2의 '나이'가 27이면 플레이어의 최신 나이가 필요하므로 나이 값을 27로 업데이트하거나, 청크 1의 '서브'가 231이고 청크 2의 '서브'가 232이면 가장 빠른 서브 속도를 찾아야 하므로 서브 값을 232로 업데이트할 수 있습니다.
텍스트를 임베딩으로
임베딩은 텍스트 조각을 서로 연결하는 데 사용되는 벡터 목록입니다. LangChain의 텍스트 분석의 가장 큰 측면은 특정 입력이나 질문과 관련된 특정 덩어리에 대한 큰 텍스트를 검색하는 것입니다.
Friedrich Nietzsche의 Beyond Good and Evil 책 의 예로 돌아가서 "철학자의 결점은 무엇입니까?"와 같은 텍스트에 대한 질문을 가져오는 간단한 스크립트를 만들어 이를 임베딩으로 바꾸고 책을 다음으로 분할할 수 있습니다. 챕터는 여러 챕터를 임베딩으로 변환하고 문의와 가장 관련성이 높은 챕터를 찾아 저자가 작성한 대로 이 질문에 대한 답을 찾기 위해 읽어야 할 챕터를 제안합니다. 이 작업을 수행하는 코드는 [여기]에서 찾을 수 있습니다 . 특히 이 코드는 주어진 입력이나 질문에 대해 가장 관련성이 높은 장을 검색합니다.
embedded_question = embeddings_model.embed_query("What are the flaws of philosophers?")
similarities = []
tags = []
for i2 in range(len(emb_list)):
similarities.append(cosine_similarity(emb_list[i2], embedded_question))
tags.append(f"CHAPTER {i2}")
print(tags[similarities.index(max(similarities))])
각 챕터와 입력 사이의 임베디드 유사성은 목록(similarities)에 저장되고 각 챕터의 번호는 태그 목록에 저장됩니다. 그런 다음 유사도 목록의 최대값에 해당하는 챕터 번호를 태그 목록에서 가져오는 print(tags[similarities.index(max(similarities))])를 사용하여 가장 관련성이 높은 챕터를 출력합니다.
기타 응용 아이디어
LangChain 및 LLM이 포함된 대규모 텍스트에는 다른 많은 분석적 용도가 있으며, 이 글에서 다루기에는 너무 복잡하더라도 그 중 일부를 나열하고 이 섹션에서 이를 달성할 수 있는 방법을 간략하게 설명하겠습니다.
주제 시각화
예를 들어, 이 데이터 세트 에 있는 것과 같은 AI 관련 YouTube 비디오의 스크립트를 가져와서 각 비디오에서 언급된 AI 관련 도구(LangChain, OpenAI, TensorFlow 등)를 추출하여 목록으로 컴파일한 다음 가장 많이 언급된 AI 도구 전체를 찾거나 막대 그래프를 사용하여 각 도구의 인기를 시각화해 보세요.
팟캐스트 녹취록 분석
팟캐스트 내용을 받아 특정 주제에 대한 의견과 정서 측면에서 다양한 게스트 간의 유사점과 차이점을 찾을 수 있습니다. 또한 입력 또는 질문을 기반으로 팟캐스트 녹취록에서 가장 관련성이 높은 대화를 검색하는 임베딩 스크립트를 만들 수도 있습니다.
뉴스 기사의 변화 분석
BBC 뉴스 헤드라인 및 설명에 대한 데이터세트 , 금융 뉴스 헤드라인 및 설명에 대한 데이터세트 등 대규모 뉴스 기사 데이터세트가 많이 있습니다 . 이러한 데이터 세트를 사용하면 각 뉴스 기사에 대한 정서, 주제, 키워드 등을 분석할 수 있습니다. 그런 다음 뉴스 기사의 이러한 측면이 시간이 지남에 따라 어떻게 변화하는지 시각화할 수 있습니다.
'Python' 카테고리의 다른 글
Python 튜플의 중요성과 사용 방법 (0) | 2023.12.24 |
---|---|
Python 마스터하기: 초보자를 위한 종합 가이드 (2) | 2023.12.23 |
Python Slice 함수를 사용하는 방법 (2) | 2023.12.21 |
Python 프로젝트 — 초급부터 고급까지 (4) | 2023.12.20 |
개발을 위한 고급 Python 팁 (2) | 2023.12.17 |