Evalution¶
- Generate or Curate the QA Set
- Automation Evalution
Generate DataSet from ChatGPT¶
- 현존 가장 똑똑하다고 알려진 모델을 이용해서 데이터셋을 생성합니다.
- ChatGPT, 데이터 셋 생성 대화
- My GPT, 프롬프팅 & Knowledge 기능을 이용한 데이터 셋 생성 대화
- 참고 - 삼국지피티
In [ ]:
Copied!
import pandas as pd
data = {
"Input": [
"삼국지연의의 저자는 누구입니까?",
"유비의 자는 무엇입니까?",
"조조의 자는 무엇입니까?",
"제갈량의 별명은 무엇입니까?",
"유비의 두 번째 부인의 이름은 무엇입니까?",
"관우의 무기는 무엇입니까?",
"장비의 무기는 무엇입니까?",
"삼국지연의에서 오나라를 세운 사람은 누구입니까?",
"조조의 아들 중 황제가 된 사람은 누구입니까?",
"조운의 자는 무엇입니까?",
"유비가 유일하게 패배한 전투는 무엇입니까?",
"조조의 정적 중 하나로 유명한 인물은 누구입니까?",
"관우가 죽음을 맞이한 곳은 어디입니까?",
"동탁의 양자는 누구입니까?",
"삼국지연의에서 유비의 의형제는 누구입니까?",
"제갈량이 북벌을 할 때 자주 사용한 계책은 무엇입니까?",
"육손이 활약한 전투는 무엇입니까?"
],
"Output": [
"나관중",
"현덕",
"맹덕",
"와룡",
"손부인",
"청룡언월도",
"장팔사모",
"손권",
"조비",
"자룡",
"이릉대전",
"원소",
"맥성",
"여포",
"관우, 장비",
"공성계",
"이릉대전"
]
}
df = pd.DataFrame(data)
df.to_csv('qa_dataset_match.csv', index=False, encoding='utf-8')
import pandas as pd
data = {
"Input": [
"삼국지연의의 저자는 누구입니까?",
"유비의 자는 무엇입니까?",
"조조의 자는 무엇입니까?",
"제갈량의 별명은 무엇입니까?",
"유비의 두 번째 부인의 이름은 무엇입니까?",
"관우의 무기는 무엇입니까?",
"장비의 무기는 무엇입니까?",
"삼국지연의에서 오나라를 세운 사람은 누구입니까?",
"조조의 아들 중 황제가 된 사람은 누구입니까?",
"조운의 자는 무엇입니까?",
"유비가 유일하게 패배한 전투는 무엇입니까?",
"조조의 정적 중 하나로 유명한 인물은 누구입니까?",
"관우가 죽음을 맞이한 곳은 어디입니까?",
"동탁의 양자는 누구입니까?",
"삼국지연의에서 유비의 의형제는 누구입니까?",
"제갈량이 북벌을 할 때 자주 사용한 계책은 무엇입니까?",
"육손이 활약한 전투는 무엇입니까?"
],
"Output": [
"나관중",
"현덕",
"맹덕",
"와룡",
"손부인",
"청룡언월도",
"장팔사모",
"손권",
"조비",
"자룡",
"이릉대전",
"원소",
"맥성",
"여포",
"관우, 장비",
"공성계",
"이릉대전"
]
}
df = pd.DataFrame(data)
df.to_csv('qa_dataset_match.csv', index=False, encoding='utf-8')
In [ ]:
Copied!
import csv
qa_dataset = [
{"Input": "유비는 누구의 후손인가?", "Output": "유비는 한나라 경제의 후손입니다."},
{"Input": "도원결의는 무엇인가?", "Output": "도원결의는 유비, 관우, 장비가 의형제를 맺은 사건입니다."},
{"Input": "삼국지연의의 주요 세력 세 가지는?", "Output": "촉나라, 위나라, 오나라입니다."},
{"Input": "제갈량이 유비에게 제시한 세 가지 전략은 무엇인가?", "Output": "형주를 차지하고, 익주를 취하고, 천하를 경영하라는 전략입니다."},
{"Input": "조조가 제일 처음 출사한 관직은?", "Output": "낙양 북부도위입니다."},
{"Input": "적벽대전에서 누가 화공을 사용했는가?", "Output": "주유와 황개가 화공을 사용했습니다."},
{"Input": "장비의 별명은 무엇인가?", "Output": "장비의 별명은 익덕입니다."},
{"Input": "관우가 살해된 장소는?", "Output": "관우는 맥성에서 살해되었습니다."},
{"Input": "유비가 죽은 장소는?", "Output": "백제성에서 죽었습니다."},
{"Input": "삼국지연의의 저자는?", "Output": "나관중입니다."},
{"Input": "유비가 초기에 세운 나라는?", "Output": "유비는 촉한을 세웠습니다."},
{"Input": "조조가 세운 나라는?", "Output": "조조는 위나라를 세웠습니다."},
{"Input": "손권이 세운 나라는?", "Output": "손권은 오나라를 세웠습니다."},
{"Input": "관우의 무기는 무엇인가?", "Output": "관우의 무기는 청룡언월도입니다."},
{"Input": "황건적의 난을 진압한 인물은?", "Output": "황건적의 난을 진압한 인물은 황보숭과 주준입니다."},
{"Input": "제갈량의 아내 이름은?", "Output": "제갈량의 아내는 황씨입니다."},
{"Input": "유비가 제갈량을 세 번 찾아간 일화는 무엇인가?", "Output": "삼고초려입니다."},
{"Input": "조조의 아들 중 황제가 된 인물은?", "Output": "조비입니다."},
{"Input": "제갈량의 별명은?", "Output": "제갈량의 별명은 와룡입니다."},
{"Input": "삼국지연의에서 마지막으로 멸망한 나라는?", "Output": "오나라입니다."}
]
with open('qa_dataset_sentence.csv', 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = ['Input', 'Output']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for qa in qa_dataset:
writer.writerow(qa)
import csv
qa_dataset = [
{"Input": "유비는 누구의 후손인가?", "Output": "유비는 한나라 경제의 후손입니다."},
{"Input": "도원결의는 무엇인가?", "Output": "도원결의는 유비, 관우, 장비가 의형제를 맺은 사건입니다."},
{"Input": "삼국지연의의 주요 세력 세 가지는?", "Output": "촉나라, 위나라, 오나라입니다."},
{"Input": "제갈량이 유비에게 제시한 세 가지 전략은 무엇인가?", "Output": "형주를 차지하고, 익주를 취하고, 천하를 경영하라는 전략입니다."},
{"Input": "조조가 제일 처음 출사한 관직은?", "Output": "낙양 북부도위입니다."},
{"Input": "적벽대전에서 누가 화공을 사용했는가?", "Output": "주유와 황개가 화공을 사용했습니다."},
{"Input": "장비의 별명은 무엇인가?", "Output": "장비의 별명은 익덕입니다."},
{"Input": "관우가 살해된 장소는?", "Output": "관우는 맥성에서 살해되었습니다."},
{"Input": "유비가 죽은 장소는?", "Output": "백제성에서 죽었습니다."},
{"Input": "삼국지연의의 저자는?", "Output": "나관중입니다."},
{"Input": "유비가 초기에 세운 나라는?", "Output": "유비는 촉한을 세웠습니다."},
{"Input": "조조가 세운 나라는?", "Output": "조조는 위나라를 세웠습니다."},
{"Input": "손권이 세운 나라는?", "Output": "손권은 오나라를 세웠습니다."},
{"Input": "관우의 무기는 무엇인가?", "Output": "관우의 무기는 청룡언월도입니다."},
{"Input": "황건적의 난을 진압한 인물은?", "Output": "황건적의 난을 진압한 인물은 황보숭과 주준입니다."},
{"Input": "제갈량의 아내 이름은?", "Output": "제갈량의 아내는 황씨입니다."},
{"Input": "유비가 제갈량을 세 번 찾아간 일화는 무엇인가?", "Output": "삼고초려입니다."},
{"Input": "조조의 아들 중 황제가 된 인물은?", "Output": "조비입니다."},
{"Input": "제갈량의 별명은?", "Output": "제갈량의 별명은 와룡입니다."},
{"Input": "삼국지연의에서 마지막으로 멸망한 나라는?", "Output": "오나라입니다."}
]
with open('qa_dataset_sentence.csv', 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = ['Input', 'Output']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for qa in qa_dataset:
writer.writerow(qa)
Dataset 을 Langsmith에 올리기¶
- web interface 에서 직접 해도 됩니다.
- 코드로도 올려봅시다.
- 수정을 하면 version 이 생기고, tag 를 달 수도 있습니다.
- "유비의 의형제" 문제를 정답이 하나의 단어가 되도록 수정하고 태그를 달아봅시다. (LangSmith Web Interface 로만 가능합니다.)
In [ ]:
Copied!
!pip install -U langsmith
!pip install -U langsmith
In [ ]:
Copied!
import os
os.environ["LANGCHAIN_TRACING_V2"]="true"
os.environ["LANGCHAIN_API_KEY"]=""
import os
os.environ["LANGCHAIN_TRACING_V2"]="true"
os.environ["LANGCHAIN_API_KEY"]=""
In [ ]:
Copied!
from langsmith import Client
import os
client = Client()
from langsmith import Client
import os
client = Client()
In [ ]:
Copied!
csv_file = './qa_dataset_match.csv'
input_keys = ["Input"] # replace with your input column names
output_keys = ["Output"] # replace with your output column names
dataset = client.upload_csv(
csv_file=csv_file,
input_keys=input_keys,
output_keys=output_keys,
name="threekingdoms-qa-words",
description="",
data_type="kv"
)
csv_file = './qa_dataset_match.csv'
input_keys = ["Input"] # replace with your input column names
output_keys = ["Output"] # replace with your output column names
dataset = client.upload_csv(
csv_file=csv_file,
input_keys=input_keys,
output_keys=output_keys,
name="threekingdoms-qa-words",
description="",
data_type="kv"
)
Evaluate various models¶
- 삼국지 퀴즈를 데이터셋으로 자동 평가 테스트를 구축합니다
- 평가할 모델 (LLM) 을 생성합니다.
- 평가 방법 (= 채점 함수) 을 생성합니다.
- 자동 평가를 수행하고, 결과를 관찰합니다.
In [ ]:
Copied!
!pip install openai
!pip install openai
In [ ]:
Copied!
os.environ["OPENAI_API_KEY"]=""
os.environ["OPENAI_API_KEY"]=""
In [ ]:
Copied!
from langsmith import traceable, wrappers
from openai import Client
openai = wrappers.wrap_openai(Client())
@traceable
def label_text(text, model="gpt-4o-mini"):
messages = [
{
"role": "system",
"content": "Please read the user query below and answer the question in 1 word.",
},
{"role": "user", "content": text},
]
result = openai.chat.completions.create(
messages=messages, model=model, temperature=0
)
return result.choices[0].message.content
from langsmith import traceable, wrappers
from openai import Client
openai = wrappers.wrap_openai(Client())
@traceable
def label_text(text, model="gpt-4o-mini"):
messages = [
{
"role": "system",
"content": "Please read the user query below and answer the question in 1 word.",
},
{"role": "user", "content": text},
]
result = openai.chat.completions.create(
messages=messages, model=model, temperature=0
)
return result.choices[0].message.content
In [ ]:
Copied!
In [ ]:
Copied!
from langsmith.schemas import Example, Run
def correct_label(root_run: Run, example: Example) -> dict:
score = root_run.outputs.get("output") == example.outputs.get("Output")
return {"score": int(score), "key": "correct_label"}
from langsmith.schemas import Example, Run
def correct_label(root_run: Run, example: Example) -> dict:
score = root_run.outputs.get("output") == example.outputs.get("Output")
return {"score": int(score), "key": "correct_label"}
In [ ]:
Copied!
from langsmith.evaluation import evaluate
dataset_name = "threekingdoms-qa-words"
results = evaluate(
lambda inputs: label_text(inputs["Input"], "gpt-4o-mini"),
data=dataset_name,
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[correct_label],
experiment_prefix="threekingdoms-qa-words",
description="Testing the system.", # optional
)
from langsmith.evaluation import evaluate
dataset_name = "threekingdoms-qa-words"
results = evaluate(
lambda inputs: label_text(inputs["Input"], "gpt-4o-mini"),
data=dataset_name,
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[correct_label],
experiment_prefix="threekingdoms-qa-words",
description="Testing the system.", # optional
)
In [ ]:
Copied!
Evalutaion Functions¶
LangChain 에서 제공하는 평가 방법들을 사용해 봅시다.
참조: https://docs.smith.langchain.com/reference/sdk_reference/langchain_evaluators
QA evaluators : Correctness 평가
- qa, context_qa, cot_qa 3가지의 qa 평가 함수가 있습니다.
- 정답과 오답 그 사이에 있는 답변들을 각각의 evaluator 들이 어떻게 매겼는지 살펴봅시다.
In [ ]:
Copied!
!pip install langchain langchain-openai langchain-community
!pip install langchain langchain-openai langchain-community
In [ ]:
Copied!
from langsmith.evaluation import LangChainStringEvaluator, evaluate
from langchain_openai import ChatOpenAI
# default 는 gpt-4지만, 비용 문제로 교체.
eval_llm = ChatOpenAI(temperature=0.0, model="gpt-4o-mini")
qa_evaluator = LangChainStringEvaluator("qa", config={"llm": eval_llm})
context_qa_evaluator = LangChainStringEvaluator("context_qa", config={"llm": eval_llm})
cot_qa_evaluator = LangChainStringEvaluator("cot_qa", config={"llm": eval_llm})
results = evaluate(
lambda inputs: label_text(inputs["Input"], "gpt-4o-mini"),
data=dataset_name,
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[correct_label, qa_evaluator, context_qa_evaluator, cot_qa_evaluator],
experiment_prefix="threekingdoms-qa-words",
description="Testing the system.", # optional
)
from langsmith.evaluation import LangChainStringEvaluator, evaluate
from langchain_openai import ChatOpenAI
# default 는 gpt-4지만, 비용 문제로 교체.
eval_llm = ChatOpenAI(temperature=0.0, model="gpt-4o-mini")
qa_evaluator = LangChainStringEvaluator("qa", config={"llm": eval_llm})
context_qa_evaluator = LangChainStringEvaluator("context_qa", config={"llm": eval_llm})
cot_qa_evaluator = LangChainStringEvaluator("cot_qa", config={"llm": eval_llm})
results = evaluate(
lambda inputs: label_text(inputs["Input"], "gpt-4o-mini"),
data=dataset_name,
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[correct_label, qa_evaluator, context_qa_evaluator, cot_qa_evaluator],
experiment_prefix="threekingdoms-qa-words",
description="Testing the system.", # optional
)
In [ ]:
Copied!
Sentence Q&A Evaluation¶
- 단답형이 아닌 주관식 답변에 대해서도 채점을 해봅시다!
- (선택) 더 구현해 봅시다!
- Metadata 추가
- 채점 모델 변경
- 수행 모델 변경 후 비교
In [ ]:
Copied!
csv_file = './qa_dataset_sentence.csv'
input_keys = ["Input"] # replace with your input column names
output_keys = ["Output"] # replace with your output column names
dataset = client.upload_csv(
csv_file=csv_file,
input_keys=input_keys,
output_keys=output_keys,
name="threekingdoms-qa-sentences",
description="",
data_type="kv"
)
eval_llm = ChatOpenAI(temperature=0.0, model="gpt-4o-mini")
qa_evaluator = LangChainStringEvaluator("qa", config={"llm": eval_llm})
context_qa_evaluator = LangChainStringEvaluator("context_qa", config={"llm": eval_llm})
cot_qa_evaluator = LangChainStringEvaluator("cot_qa", config={"llm": eval_llm})
results = evaluate(
lambda inputs: label_text(inputs["Input"], "gpt-4o-mini"),
data="threekingdoms-qa-sentences",
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[ qa_evaluator, context_qa_evaluator, cot_qa_evaluator],
experiment_prefix="threekingdoms-qa-sentences",
metadata={
"version": "1.0.0",
"revision_id": "beta",
"model": "gpt-4o-mini"
},
description="Testing the system.", # optional
)
csv_file = './qa_dataset_sentence.csv'
input_keys = ["Input"] # replace with your input column names
output_keys = ["Output"] # replace with your output column names
dataset = client.upload_csv(
csv_file=csv_file,
input_keys=input_keys,
output_keys=output_keys,
name="threekingdoms-qa-sentences",
description="",
data_type="kv"
)
eval_llm = ChatOpenAI(temperature=0.0, model="gpt-4o-mini")
qa_evaluator = LangChainStringEvaluator("qa", config={"llm": eval_llm})
context_qa_evaluator = LangChainStringEvaluator("context_qa", config={"llm": eval_llm})
cot_qa_evaluator = LangChainStringEvaluator("cot_qa", config={"llm": eval_llm})
results = evaluate(
lambda inputs: label_text(inputs["Input"], "gpt-4o-mini"),
data="threekingdoms-qa-sentences",
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[ qa_evaluator, context_qa_evaluator, cot_qa_evaluator],
experiment_prefix="threekingdoms-qa-sentences",
metadata={
"version": "1.0.0",
"revision_id": "beta",
"model": "gpt-4o-mini"
},
description="Testing the system.", # optional
)
In [ ]:
Copied!
eval_llm = ChatOpenAI(temperature=0.0, model="gpt-4o-mini")
qa_evaluator = LangChainStringEvaluator("qa", config={"llm": eval_llm})
context_qa_evaluator = LangChainStringEvaluator("context_qa", config={"llm": eval_llm})
cot_qa_evaluator = LangChainStringEvaluator("cot_qa", config={"llm": eval_llm})
results = evaluate(
lambda inputs: label_text(inputs["Input"], "gpt-4o-mini"),
data="threekingdoms-qa-sentences",
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[ qa_evaluator, context_qa_evaluator, cot_qa_evaluator],
experiment_prefix="threekingdoms-qa-sentences",
metadata={
"version": "1.0.0",
"revision_id": "beta",
"model": "gpt-4o-mini"
},
description="Testing the system.", # optional
)
eval_llm = ChatOpenAI(temperature=0.0, model="gpt-4o-mini")
qa_evaluator = LangChainStringEvaluator("qa", config={"llm": eval_llm})
context_qa_evaluator = LangChainStringEvaluator("context_qa", config={"llm": eval_llm})
cot_qa_evaluator = LangChainStringEvaluator("cot_qa", config={"llm": eval_llm})
results = evaluate(
lambda inputs: label_text(inputs["Input"], "gpt-4o-mini"),
data="threekingdoms-qa-sentences",
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[ qa_evaluator, context_qa_evaluator, cot_qa_evaluator],
experiment_prefix="threekingdoms-qa-sentences",
metadata={
"version": "1.0.0",
"revision_id": "beta",
"model": "gpt-4o-mini"
},
description="Testing the system.", # optional
)
RAG 를 이용한 개선 작업 & 중간 단계 평가¶
- 원문 번역본을 데이터베이스로 보고 RAG를 해봅시다.
- 검색이 문제인지, 대답이 문제인지 각 과정을 나눠서 평가를 해봅시다.
- (추가 개선 작업) RAG variation
- 후보: 침착맨 삼국지, 앞선 번역본, 웹 서칭
- vector similarity search, keyword searching ...
- vector similarity 도 evaluation
In [ ]:
Copied!
!pip install --quiet langchain_experimental langchain_openai chromadb
!pip install --quiet langchain_experimental langchain_openai chromadb
In [ ]:
Copied!
#unzip ./3kingdoms.zip
!unzip ./jinho_3kingdoms.zip -d ./3kingdoms
#unzip ./3kingdoms.zip
!unzip ./jinho_3kingdoms.zip -d ./3kingdoms
In [ ]:
Copied!
import glob
# Use glob to find files matching the pattern
files = glob.glob('./3kingdoms/[0-9]*.txt')
# Print the collected files
for file in files:
print(file)
import glob
# Use glob to find files matching the pattern
files = glob.glob('./3kingdoms/[0-9]*.txt')
# Print the collected files
for file in files:
print(file)
In [ ]:
Copied!
import openai
import os
from langsmith import traceable
from langsmith.wrappers import wrap_openai
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
texts = []
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
for file in files:
with open(file, 'r', encoding='utf-8') as f:
# split the documents into chunks
texts.append(text_splitter.create_documents([f.read()], metadatas=[{"source": str(file)}]))
import openai
import os
from langsmith import traceable
from langsmith.wrappers import wrap_openai
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
texts = []
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
for file in files:
with open(file, 'r', encoding='utf-8') as f:
# split the documents into chunks
texts.append(text_splitter.create_documents([f.read()], metadatas=[{"source": str(file)}]))
In [ ]:
Copied!
texts[0][0]
texts[0][0]
In [ ]:
Copied!
!pip install transformers
!pip install sentence-transformers
!pip install transformers
!pip install sentence-transformers
In [ ]:
Copied!
from langchain.embeddings import HuggingFaceEmbeddings
modelPath = "BAAI/bge-small-en-v1.5"
# Create a dictionary with model configuration options, specifying to use the CPU for computations
model_kwargs = {'device':'cpu'}
# Create a dictionary with encoding options, specifically setting 'normalize_embeddings' to False
encode_kwargs = {'normalize_embeddings': True}
# Initialize an instance of HuggingFaceEmbeddings with the specified parameters
embeddings = HuggingFaceEmbeddings(
model_name=modelPath, # Provide the pre-trained model's path
model_kwargs=model_kwargs, # Pass the model configuration options
encode_kwargs=encode_kwargs # Pass the encoding options
)
from langchain.embeddings import HuggingFaceEmbeddings
modelPath = "BAAI/bge-small-en-v1.5"
# Create a dictionary with model configuration options, specifying to use the CPU for computations
model_kwargs = {'device':'cpu'}
# Create a dictionary with encoding options, specifically setting 'normalize_embeddings' to False
encode_kwargs = {'normalize_embeddings': True}
# Initialize an instance of HuggingFaceEmbeddings with the specified parameters
embeddings = HuggingFaceEmbeddings(
model_name=modelPath, # Provide the pre-trained model's path
model_kwargs=model_kwargs, # Pass the model configuration options
encode_kwargs=encode_kwargs # Pass the encoding options
)
In [ ]:
Copied!
doc_list = [item for sublist in texts for item in sublist]
# Use Chroma with local embeddings
db = Chroma.from_documents(doc_list, embedding=embeddings)
#embeddings = OpenAIEmbeddings()
#db = Chroma.from_documents(doc_list, embeddings)
doc_list = [item for sublist in texts for item in sublist]
# Use Chroma with local embeddings
db = Chroma.from_documents(doc_list, embedding=embeddings)
#embeddings = OpenAIEmbeddings()
#db = Chroma.from_documents(doc_list, embeddings)
In [ ]:
Copied!
query = "유비가 삼고초려를 할 때 모시고자 한 인물은 누구인가?"
docs = db.similarity_search(query)
print(docs[0].page_content)
query = "유비가 삼고초려를 할 때 모시고자 한 인물은 누구인가?"
docs = db.similarity_search(query)
print(docs[0].page_content)
LangChain 으로 RAG 구현¶
- 일반적인 LangChain 사용법을 소개합니다
- 직접 구현해도 되지만, 이를 편하게 구현해 봅시다
- Prompting Hub 도 사용해 봅시다.
- 모델도 교체해가며 비교해봅시다.
In [ ]:
Copied!
!pip install --upgrade --quiet langchain langchain-community langchainhub langchain-openai langchain-chroma
!pip install --upgrade --quiet langchain langchain-community langchainhub langchain-openai langchain-chroma
In [ ]:
Copied!
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
llm = ChatOpenAI(model="gpt-4o-mini")
#llm = ChatOpenAI(model="gpt-4o")
retriever = db.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
#prompt = hub.pull("rag-prompt-fork")
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
llm = ChatOpenAI(model="gpt-4o-mini")
#llm = ChatOpenAI(model="gpt-4o")
retriever = db.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
#prompt = hub.pull("rag-prompt-fork")
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
In [ ]:
Copied!
rag_chain.invoke("유비가 삼고초려를 할 때 모시고자 한 인물은 누구인가?")
rag_chain.invoke("유비가 삼고초려를 할 때 모시고자 한 인물은 누구인가?")
In [ ]:
Copied!
results = evaluate(
lambda inputs: rag_chain.invoke(inputs["Input"]),
data=dataset_name,
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[correct_label, qa_evaluator, context_qa_evaluator, cot_qa_evaluator],
experiment_prefix="threekingdoms-qa-words",
description="Testing the system.", # optional
)
results = evaluate(
lambda inputs: rag_chain.invoke(inputs["Input"]),
data=dataset_name,
#data=client.list_examples(dataset_name=dataset_name, as_of="test_v1.0"),
evaluators=[correct_label, qa_evaluator, context_qa_evaluator, cot_qa_evaluator],
experiment_prefix="threekingdoms-qa-words",
description="Testing the system.", # optional
)
In [ ]:
Copied!
오픈 모델 직접 서빙하도록 바꾸기¶
- API 가 아닌 로컬 모델로 변경
- ollama
In [ ]:
Copied!
!pip install colab-xterm #https://pypi.org/project/colab-xterm/
%load_ext colabxterm
!pip install colab-xterm #https://pypi.org/project/colab-xterm/
%load_ext colabxterm
In [ ]:
Copied!
%xterm
#curl -fsSL https://ollama.com/install.sh | sh
#ollama serve
#ollama pull llama3.2:1b
#ollama pull llama3.2:3b
%xterm
#curl -fsSL https://ollama.com/install.sh | sh
#ollama serve
#ollama pull llama3.2:1b
#ollama pull llama3.2:3b
In [ ]:
Copied!
# Import Ollama module from Langchain
from langchain_community.llms import Ollama
# Initialize an instance of the Ollama model
llm = Ollama(model="llama3.2:1b")
# Invoke the model to generate responses
response = llm.invoke("Tell me a joke")
print(response)
# Import Ollama module from Langchain
from langchain_community.llms import Ollama
# Initialize an instance of the Ollama model
llm = Ollama(model="llama3.2:1b")
# Invoke the model to generate responses
response = llm.invoke("Tell me a joke")
print(response)
In [ ]:
Copied!
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
In [ ]:
Copied!
rag_chain.invoke("유비가 삼고초려를 할 때 모시고자 한 인물은 누구인가?")
rag_chain.invoke("유비가 삼고초려를 할 때 모시고자 한 인물은 누구인가?")
In [ ]:
Copied!
Chatbot UI 를 만들어 서비스하고, 유저 피드백 받기¶
- Streamlit
- User Feedback
- Online Evaluator on LangSmith
In [ ]:
Copied!
!pip install -q streamlit streamlit-feedback
!pip install -q streamlit streamlit-feedback
In [ ]:
Copied!
%%writefile app.py
import streamlit as st
st.write('Hello, *World!* :sunglasses:')
%%writefile app.py
import streamlit as st
st.write('Hello, *World!* :sunglasses:')
In [ ]:
Copied!
!npm install localtunnel
!npm install localtunnel
In [ ]:
Copied!
!streamlit run app.py &>/content/logs.txt & npx localtunnel --port 8501 & curl ipv4.icanhazip.com
!streamlit run app.py &>/content/logs.txt & npx localtunnel --port 8501 & curl ipv4.icanhazip.com
In [ ]:
Copied!
In [ ]:
Copied!
%%writefile app.py
import streamlit as st
from langchain import memory as lc_memory
from langsmith import Client
from streamlit_feedback import streamlit_feedback
from langchain_core.tracers.context import collect_runs
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
import os
llm = ChatOpenAI(model="gpt-4o-mini")
chain = (
llm
| StrOutputParser()
)
# Langsmith project change
os.environ["LANGCHAIN_PROJECT"] = "Three Kingdoms Chatbot Tracing & Feedback"
client = Client()
st.set_page_config(
page_title="Capturing User Feedback",
page_icon="🦜️️🛠️",
)
st.subheader("🦜🛠️ Chatbot with Feedback in LangSmith")
st.sidebar.info(
"""
An example of a Streamlit Chat UI capturing user feedback.
- [LangSmith Documentation](https://docs.smith.langchain.com/)
- Streamlit's [chat elements Documentation](https://docs.streamlit.io/library/api-reference/chat)
- Trubrics' [Streamlit-Feedback](https://github.com/trubrics/streamlit-feedback) component
"""
)
st.sidebar.markdown("## Feedback Scale")
feedback_option = (
"thumbs" if st.sidebar.toggle(label="`Faces` ⇄ `Thumbs`", value=False) else "faces"
)
with st.form("form"):
text = st.text_area("Enter text:", "Ask me a question!")
submitted = st.form_submit_button("Submit")
if submitted:
# get run_id from chain or lanchain run
with collect_runs() as cb:
st.info(chain.invoke(text))
st.session_state.run_id = cb.traced_runs[0].id
if st.session_state.get("run_id"):
run_id = st.session_state.run_id
feedback = streamlit_feedback(
feedback_type=feedback_option,
optional_text_label="[Optional] Please provide an explanation",
key=f"feedback_{run_id}",
)
# Define score mappings for both "thumbs" and "faces" feedback systems
score_mappings = {
"thumbs": {"👍": 1, "👎": 0},
"faces": {"😀": 1, "🙂": 0.75, "😐": 0.5, "🙁": 0.25, "😞": 0},
}
# Get the score mapping based on the selected feedback option
scores = score_mappings[feedback_option]
if feedback:
# Get the score from the selected feedback option's score mapping
score = scores.get(feedback["score"])
if score is not None:
# Formulate feedback type string incorporating the feedback option
# and score value
feedback_type_str = f"{feedback_option} {feedback['score']}"
# Record the feedback with the formulated feedback type string
# and optional comment
feedback_record = client.create_feedback(
run_id,
feedback_type_str,
score=score,
comment=feedback.get("text"),
)
st.session_state.feedback = {
"feedback_id": str(feedback_record.id),
"score": score,
}
else:
st.warning("Invalid feedback score.")
%%writefile app.py
import streamlit as st
from langchain import memory as lc_memory
from langsmith import Client
from streamlit_feedback import streamlit_feedback
from langchain_core.tracers.context import collect_runs
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
import os
llm = ChatOpenAI(model="gpt-4o-mini")
chain = (
llm
| StrOutputParser()
)
# Langsmith project change
os.environ["LANGCHAIN_PROJECT"] = "Three Kingdoms Chatbot Tracing & Feedback"
client = Client()
st.set_page_config(
page_title="Capturing User Feedback",
page_icon="🦜️️🛠️",
)
st.subheader("🦜🛠️ Chatbot with Feedback in LangSmith")
st.sidebar.info(
"""
An example of a Streamlit Chat UI capturing user feedback.
- [LangSmith Documentation](https://docs.smith.langchain.com/)
- Streamlit's [chat elements Documentation](https://docs.streamlit.io/library/api-reference/chat)
- Trubrics' [Streamlit-Feedback](https://github.com/trubrics/streamlit-feedback) component
"""
)
st.sidebar.markdown("## Feedback Scale")
feedback_option = (
"thumbs" if st.sidebar.toggle(label="`Faces` ⇄ `Thumbs`", value=False) else "faces"
)
with st.form("form"):
text = st.text_area("Enter text:", "Ask me a question!")
submitted = st.form_submit_button("Submit")
if submitted:
# get run_id from chain or lanchain run
with collect_runs() as cb:
st.info(chain.invoke(text))
st.session_state.run_id = cb.traced_runs[0].id
if st.session_state.get("run_id"):
run_id = st.session_state.run_id
feedback = streamlit_feedback(
feedback_type=feedback_option,
optional_text_label="[Optional] Please provide an explanation",
key=f"feedback_{run_id}",
)
# Define score mappings for both "thumbs" and "faces" feedback systems
score_mappings = {
"thumbs": {"👍": 1, "👎": 0},
"faces": {"😀": 1, "🙂": 0.75, "😐": 0.5, "🙁": 0.25, "😞": 0},
}
# Get the score mapping based on the selected feedback option
scores = score_mappings[feedback_option]
if feedback:
# Get the score from the selected feedback option's score mapping
score = scores.get(feedback["score"])
if score is not None:
# Formulate feedback type string incorporating the feedback option
# and score value
feedback_type_str = f"{feedback_option} {feedback['score']}"
# Record the feedback with the formulated feedback type string
# and optional comment
feedback_record = client.create_feedback(
run_id,
feedback_type_str,
score=score,
comment=feedback.get("text"),
)
st.session_state.feedback = {
"feedback_id": str(feedback_record.id),
"score": score,
}
else:
st.warning("Invalid feedback score.")
In [ ]:
Copied!
In [ ]:
Copied!
Furthermore¶
- Tavily 와 같은 웹브라우징 추가하기
- GGUF file 을 Ollama로 돌리기 (Huggingface 에서 많은 튜닝 모델을 돌릴 수 있다!)
- Unsloth 를 이용해 Fine Tuning 하기 (GGUF 파일로 만들어 직접 튜닝 모델을 실험/평가하자)
- LLM Application 을 멀티모달리티로 확장하기
- LangGraph와 같은 Agent framework 활용하여 더 복잡한 LLM Application 활용하기
In [ ]:
Copied!
In [ ]:
Copied!
In [ ]:
Copied!