오늘은 본격적으로 프롬프트 엔지니어링에 사용되는 langchain 개념과 다양한 사용법을 배웠다.
그리고 vscode에서 langchain과 bedrock을 통해서 서비스 모델을 만들어보는 실습을 시작하였다.
체인(LangChain) - LLM Agent Engineering
- 경쟁 제품 : 라마인덱스(RAG 특화)
- 정의
- 대규모 언어 모델(LLM)을 활용한 애플리케이션 개발을 쉽게 만들어주는 오픈소스 프레임워크
- 특징
- LLM 연동: OpenAI, Google 등 다양한 언어 모델과 쉽게 연결하고 사용할 수 있도록 돕습니다.
- 1개의 단일 코드로 다양한 모델 사용 가능함
- 데이터 연결: 외부 데이터(문서, 데이터베이스 등)를 불러와 LLM이 활용할 수 있도록 처리하는 기능(RAG 등)을 제공합니다.
- 체인(Chain): 여러 단계의 작업을 순서대로 연결하여 복잡한 워크플로우를 만듭니다 (예: 질문 -> 데이터 검색 -> 답변 생성).
- 에이전트(Agent): LLM이 스스로 생각하고 행동하며 도구(검색, 계산기 등)를 사용해 문제를 해결하도록 만듭니다.
- 문맥 관리: 대화의 기록을 저장하고 기억하게 하여 맥락이 있는 대화를 가능하게 합니다. 단기기억
- 장기기억 : 벡터 디비 담당
- 예시 : 채팅 내용을 기억하여 -> 자연스러운 대화 진행
- 장기기억 : 벡터 디비 담당
- LLM 연동: OpenAI, Google 등 다양한 언어 모델과 쉽게 연결하고 사용할 수 있도록 돕습니다.
- 설치
!pip install -q langchain-aws langchain-community boto3 langchain-core
# 랭체인 패키지 불러오기
import langchain
import langchain_core
#('1.2.0', '1.2.1')
langchain.__version__, langchain_core.__version__
--------------------------------------------------
('1.2.0', '1.2.1')
# 랭체인 aws 연결 라이브러리 불러오기
import langchain_aws
# 1.1.0
!pip show langchain_aws
-------------------------
Name: langchain-aws
Version: 1.1.0
Summary: An integration package connecting AWS and LangChain
Home-page:
Author:
Author-email:
License: MIT
Location: /usr/local/lib/python3.12/dist-packages
Requires: boto3, langchain-core, numpy, pydantic
Required-by:
PromptTemplate
- 기본 형태, 변수를 채워 넣어서 하나의 완성된 문자열(프럼프트) 구성
PromptTemplate + f-string
1. 입력 변수가 없는 형태
# langchain_core.prompts 하위에 프롬프트를 쉽게 구성할수 있는 템플릿 클래스들 존재함
from langchain_core.prompts import PromptTemplate
no_input_prompt = PromptTemplate(
input_variables= [], # 입력 변수가 없는 템플릿 형태
template= '유니버셜 스튜디오에서 가장 재미있는 놀이 기구는?'
)
no_input_prompt.format()
----------------------------------------
'유니버셜 스튜디오에서 가장 재미있는 놀이 기구는?'
2. 입력 변수가 1개인 형태
# 한개의 입력을 추가
from langchain_core.prompts import PromptTemplate
# 파이썬의 문자열 포맷팅 중 f-string과 유사함
input_prompt = PromptTemplate(
input_variables= ['place'],
template= '{place} 에서 가장 재미있는 놀이 기구는?'
)
# 다양한 놀이기구가 있는 공간은 모두 입력 가능해짐
input_prompt.format(place='에버랜드')
----------------------------------------
'에버랜드 에서 가장 재미있는 놀이 기구는?'
3. 입력 변수가 n개인 형태
# n개의 입력을 추가
from langchain_core.prompts import PromptTemplate
# 파이썬의 문자열 포맷팅 중 f-string과 유사함
input_prompt = PromptTemplate(
input_variables= ['place', 'content'],
template= '{place} 에서 가장 {content} 놀이 기구는?'
)
# 다양한 놀이기구가 있는 공간은 모두 입력 가능해짐
input_prompt.format(place='에버랜드', content='대기줄이 가장 긴')
---------------------------------------------------------------
'에버랜드 에서 가장 대기줄이 가장 긴 놀이 기구는?'
PromptTemplate + jinja2(템플릿엔진)
# jinja2의 형식 또한 PromptTemplate에 적용할 수 있다.
from langchain_core.prompts import PromptTemplate
input_prompt = PromptTemplate(
input_variables = ['items'],
template_format = 'jinja2',
template = '''
{% for item in items %}
Q : {{ item.q }}
A : {{ item.a }}
{% endfor %}
'''
)
items = [
{'q':'오늘 점심은', 'a':'호떡'},
{'q':'오늘 저녁은', 'a':'치킨'},
{'q':'오늘 저녁은', 'a':'치킨'}
]
print(input_prompt.format(items=items))
----------------------------------------
Q : 오늘 점심은
A : 호떡
Q : 오늘 저녁은
A : 치킨
Q : 오늘 저녁은
A : 치킨
from langchain_core.prompts import PromptTemplate
input_prompt = PromptTemplate(
input_variables = ['items', 'user_q'],
template_format = 'jinja2',
template = '''
다음 예시를 보고 참고하여 마지막질문에 대한 답변을 제시해줘.
{% for item in items %}
Q : {{ item.q }}
A : {{ item.a }}
{% endfor %}
Q : {{user_q}}
A : {{user_a}}
'''
)
items = [
{'q':'오늘 점심은', 'a':'호떡'},
{'q':'오늘 저녁은', 'a':'치킨'}
]
print(input_prompt.format(items=items, user_q='내일 아침은?'))
--------------------------------------------------------
다음 예시를 참고하여, 마지막 질문에 대한 답변을 제시해줘.
Q: 오늘 점심은?
A: 호떡
Q: 오늘 저녁은?
A: 치킨
Q: 내일 아침은?
A:
응용
# 1. 템플릿 정의 (f-string)
template_base = '당신은 {expert_type}입니다. {topic}에 대해 3줄로 쉽게 설명해주세요'
# 2. 템플릿 베이스 기반으로 구성
prompt = PromptTemplate.from_template(template_base)
# 3. 데이터 주입, 포맷팅 적용
formatted_prompt = prompt.format(
expert_type = '대통령',
topic = '공공 교육 정책'
)
# 4. 완성된 프롬프트 추력
formatted_prompt
---------------------
'당신은 대통령입니다. 공공 교육 정책에 대해 3줄로 쉽게 설명해주세요'
ChatPromptTemplate
- 대화형 모델을 위한 프롬프트
- 목표
- 단순 문자열 구성이 아니라, 메세지 리스트 생성
- Bedrock에서 Claude, Gemma 모델 사용 시 유리하다.
- 구조
- system : AI의 페르소나 / 역할 정의
- human : 사용자 입력
- AI : AI의 예시 답변 (선택적)
- 사용
- 챗봇, 복잡한 지시가 잡힌 작업등..
from langchain_core.prompts import ChatPromptTemplate
# 1. 메세지 구조 정의
chat_template = ChatPromptTemplate.from_messages([
# 그간의 대화내용 (history)를 삽입 =>
# 단기/장기 기억 유지 => 일관성있게 나를 기억하고 응답할 수 있음
('system', '당신은 {style} 스타일의 고용센터의 고용관리 상담사입니다.'),
('human', '안녕하세요. 오랜만입니다, 저는 {name}입니다.'),
('system', '네 반갑습니다.'),
('human', '제 고민은 {topic}입니다. 조언해주세요'),
])
# 2. 데이터 주입
messages = chat_template.format_messages(
style = '친절하지만 빈틈없는 행정능력을 가진', #'독설가'
name = '김군',
topic = '잠도 안 자고 너무 많은 공부를 하는 것'
)
# 3. 메세지 출력
for msg in messages:
print(f'[ { msg.type } ] : {msg.content} ')
# 대화 내용이나 -> 너무 많다면 -> 요약(LLM 사용)해서 제시하고 최근 대화 내용을 붙여서 구성
-----------------------------------------------------------------
[ system ] : 당신은 친절하지만 빈틈없는 행정능력을 가진 스타일의 고용센터의 고용관리 상담사입니다.
[ human ] : 안녕하세요. 오랜만입니다, 저는 김군입니다.
[ system ] : 네 반갑습니다.
[ human ] : 제 고민은 잠도 안 자고 너무 많은 공부를 하는 것입니다. 조언해주세요
FewShot
FewShotPromptTemplate
- LLM 모델에게 '이런식으로 답변해(하라)' 라고 예시를 미리 보여주고(few-shot learning) 템플릿
- 예시를 통해 LLM이 학습이 되면 성능이 비약적으로 상승하게 됨(해당 분야에 대해서)
- 구조
- 예시 리스트
- 예시 포맷터
- 접두사/접미사
- 예시
- 반대말 예시, 특수 포맷, 사투리 변환, ...
from langchain_core.prompts import FewShotPromptTemplate
# 1. 모델에게 제시한 샘플 -> 모델에게 few-shot learning 진행
examples = [
# 반대어
{'input' : '높다', 'output' : '낮다'},
{'input' : '빠르다', 'output' : '느리다'},
{'input' : '밝다', 'output' : '어둡다'}
]
# 2. 샘플을 보여주는 형태(포맷) 정의
example_format = PromptTemplate.from_template(
'단어: {input}\n반대말:{output}'
)
# 3. FewShot 템플릿 구성
few_shot_prompt = FewShotPromptTemplate(
examples = examples,
example_prompt = example_format,
# 접두사
prefix = '다음 단어의 반대말을 알려줘,',
# 접미사
suffix = '단어: {user_input}\n반대말:',
# 변수 정의
input_variables = ['user_input']
)
# 4. 프롬프트 완성
final_prompt = few_shot_prompt.format(user_input = '삼성')
print(final_prompt)
--------------------------
다음 단어의 반대말을 알려줘,
단어: 높다
반대말:낮다
단어: 빠르다
반대말:느리다
단어: 밝다
반대말:어둡다
단어: 삼성
반대말:
FewShotChatMessagePromptTemplate
- Bedrock에서 Claude, Gemma 같은 채팅모델에서는 xxxChatMessagexxx 형태가 더 유리함.
- 실제 대화 기록처럼 주입함
from langchain_core.prompts import FewShotChatMessagePromptTemplate
# 1. 예시
examples = [
# 반대어
{'input' : '안녕', 'output' : '반갑습니다, 마스터'},
{'input' : '점심시간이야', 'output' : '돈까스 추천드립니다'}
]
# 2. 샘플을 보여주는 형태(포맷) 정의 -> human과 ai 대화간 쌍으로 구성
example_format = ChatPromptTemplate.from_messages([
('human', '{input}'),
('ai', '{output}')
])
# 3. FewShot 템플릿 구성
few_shot_prompt = FewShotChatMessagePromptTemplate(
examples = examples,
example_prompt = example_format
)
# 4. 프롬프트 결합
final_prompt = ChatPromptTemplate.from_messages([
('system','당신의 충실한 개인 비서입니다.'),
few_shot_prompt,
('human','{user_input}')
])
print(final_prompt.format(user_input= '밥먹자'))
------------------------------------------------
System: 당신의 충실한 개인 비서입니다.
Human: 안녕
AI: 반갑습니다, 마스터
Human: 점심시간이야
AI: 돈까스 추천드립니다
Human: 밥먹자
Bedrock 연동, 프롬프트 -> 추론(응답)
이제 본격적으로 bedrock을 연동시켜서 대답을 받아본다.
# 기본 세팅
# bedrock 관련
import boto3 # aws 연동
import os
from dotenv import load_dotenv
from google.colab import userdata
import json
# langchain 관련
from langchain_aws import ChatBedrock
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.prompts import ChatPromptTemplate
# 1. 환경설정 -> bedrock 단기key 발급 -> 키 업데이트
# 환경변수에 bedrock 키 세팅
# 환경변수 로드
load_dotenv()
if not os.getenv('AWS_BEARER_TOKEN_BEDROCK'):
os.environ['AWS_BEARER_TOKEN_BEDROCK']=userdata.get('AWS_BEARER_TOKEN_BEDROCK')
# 리전
REGION = 'eu-west-2' # 런던
# LLM 모델 ID
openai_id = 'openai.gpt-oss-120b-1:0'
claude_id = 'anthropic.claude-3-sonnet-20240229-v1:0'
gemma_id = 'google.gemma-3-27b-it'
# bedrock 클라이언트 객체
bedrock = boto3.client(service_name='bedrock-runtime',
region_name = REGION)
# 모델id 쉽게 뽑는 함수
'''
벤더 혹은 모델명으로 필요한 bedrock에 설정된 모델 id 획득
'''
def get_model_id(id='anthropic'):
if id == 'openai': return openai_id
# elif id == 'anthropic': return claude_id
elif id == 'google' : return gemma_id
return claude_id # 기본값으로 적용
get_model_id()
# 2. bedrock 클라이언트 구성
bedrock_client = boto3.client(
service_name = 'bedrock-runtime',
region_name=REGION
)
기본 세팅이 끝났다.
ChatBedrock
# 내꺼
# 추론/생성 등 LLM이 api 호출하여 처리하는 함수
def run_bedrock_llm(model_id, p_style, user_query):
# 예외처리 기번
try:
# 1. ChatBedrock 생성 => LLM
llm = ChatBedrock(
client = bedrock_client,
model_id = model_id,
model_kwargs = {
"temperature": 0.7,
"max_tokens" : 1024
}
)
# 2. ChatPromptTemplate 구성 -> 페르소나, 사용자 질의 세팅
prompt = chat_template = ChatPromptTemplate.from_messages([
('system', '당신은 {style} 스타일의 20년차 카피라이터입니다.'),
('human', '{input}')
])
# 3. chain 연결(파이프라인 구성)
# 순서대로 배치 : 프롬프트 | llm | ...
chain = prompt | llm
# 4. 실행 => bedrock => claude => 요청 => 응답
chain.invoke({
'input' : user_query,
'style' : p_style
})
# 5. 응답 결과 출력
return res.content
pass
except Exception as e:
print('에러 발생', e)
return '잠시후 다시 이용해주세요'
pass
query = '20대 직장인을 타겟으로 한 24시간 얼음이 녹지 않는 셀럽형 신제품 텀블러 홍보를 위한 카피라이터 3개 추천해줘'
p_style = '유머러스하고 위트있는'
ai_ment = run_bedrock_llm(get_model_id(), p_style, query)
print(ai_ment)
--------------
1. "당신의 24시간, 얼음처럼 시원한 하루를 선사합니다."
- 얼음이 녹지 않는 텀블러의 핵심 기능을 강조하면서, 직장인들의 바쁜 하루를 시원하게 만들어 줄 것이라는 메시지를 전달합니다.
2. "셀럽이라도 부러워할 스타일리시한 당신의 동반자"
- 20대 직장인들이 셀럽처럼 스타일리시하고 싶어 하는 욕구를 자극하면서, 텀블러가 그들의 스타일을 완성시켜 줄 것이라고 암시합니다.
3. "하루 종일 얼음 같은 시원함, 당신의 24시간 에너지 충전기"
- 하루 종일 시원한 음료를 즐길 수 있다는 실용적인 장점과 함께, 텀블러가 직장인들의 활력소가 될 것이라는 메시지를 전달합니다.
ChatBedrockConverse
- ChatBedrock 클래스에서 미지원되는 llm회사를 커버하기 위해 공급자부분 조정
- 추가 사항
- 현재 ChatBedrock 보다 ChatBedrockConverse를 더 많이 사용하고 이제 ChatBedrock 는 구식으로 생각되는 개념이라고 한다, ChatBedrockConverse가 더 신식이다
from langchain_aws import ChatBedrockConverse
# 추론/생성 등 LLM이 api 호출하여 처리하는 함수
def run_bedrock_llm_converse(model_id, p_style, user_query):
# 예외처리 기번
try:
# (*변경) 1. ChatBedrockConverse 생성 => LLM
llm = ChatBedrockConverse(
client = bedrock_client,
model_id = model_id,
temperature = 0.7,
max_tokens = 1024
)
# 2. ChatPromptTemplate 구성 -> 페르소나, 사용자 질의 세팅
prompt = chat_template = ChatPromptTemplate.from_messages([
('system', '당신은 {style} 스타일의 20년차 카피라이터입니다.'),
('human', '{input}')
])
# 3. chain 연결(파이프라인 구성)
# 순서대로 배치 : 프롬프트 | llm | ...
chain = prompt | llm
# 4. 실행 => bedrock => claude => 요청 => 응답
res = chain.invoke({
'input' : user_query,
'style' : p_style
})
# 5. 응답 결과 출력
return res.content
pass
except Exception as e:
print('에러 발생', e)
return '잠시후 다시 이용해주세요'
pass
query = '20대 직장인을 타겟으로 한 24시간 얼음이 녹지 않는 셀럽형 신제품 텀블러 홍보를 위한 카피라이터 3개 추천해줘'
p_style = '유머러스하고 위트있는'
ai_ment = run_bedrock_llm_converse(get_model_id(), p_style, query)
print(ai_ment)
--------------
1. 아이스 아메리카노는 여전히 뜨겁고, 당신은 여전히 시원해!
우리의 셀럽형 텀블러로 하루종일 얼음이 녹지 않아 시원한 음료를 마실 수 있습니다. 지치지 않는 당신처럼 끝까지 시원해지세요.
2. 얼음 녹는 소리가 없다면? 그건 당신의 인생이 잘 흘러가고 있다는 증거!
우리 셀럽형 텀블러는 24시간 얼음을 지켜주니 녹는 소리 대신 당신의 인생 스토리에 집중하세요.
3. 아름다운 외모 안에 강력한 능력이 숨어있죠. 우리 텀블러처럼 말이에요!
셀럽 못지않은 스타일리시한 디자인과 24시간 얼음 보존 기능을 모두 갖춘 텀블러, 지금 만나보세요.
거의 비슷하긴 하다, 이걸 이제 구글 gemini로 돌려보면?
ai_ment = run_bedrock_llm_converse( get_model_id('google'), p_style, query )
print(ai_ment)
--------------
네, 20년 차 카피라이터의 내공을 담아 20대 직장인을 저격할 만한 텀블러 카피 3개를 추천해 드리겠습니다. 유머와 위트를 잃지 않으면서, 제품의 핵심 강점(24시간 얼음 유지)을 살리는 데 집중했습니다.
**1. 출근길 내 심정 변화 그래프**
* **이미지:** 🤯 → 😐 → 😎 (출근 전, 출근 중, 텀블러 사용 후)
* **카피:**
* "출근길, 🤯에서 😐 되는 건 텀블러 때문 아니겠지? 😉"
* "24시간 얼음 텀블러, 내 정신 건강 지킴이 🛡️"
* "월요병도 얼려버리는 마법, 지금 경험해 보세요! ✨"
* **타겟:** 월요병, 출근 스트레스에 지친 20대 직장인
* **설명:** 공감대를 형성하는 이모티콘과 함께, 텀블러가 단순한 보온병이 아닌 '정신 건강템'이라는 점을 강조합니다.
**2. 퇴근 후 나의 온도 변화**
* **이미지:** 🔥 (퇴근 전) → 🧊 (텀블러 사용 후)
* **카피:**
* "퇴근 전 나 = 🔥, 퇴근 후 나 = 🧊, 이 온도 차이, 텀블러가 책임진다."
* "오늘 하루, 힘든 일은 얼음처럼 녹여버리고 시원하게 마무리! 🧊"
* "24시간 얼음 보장, 내일의 나를 위해 지금 바로 득템하세요! 🛒"
* **타겟:** 퇴근 후 힐링을 갈망하는 20대 직장인
* **설명:** 극명한 온도 변화를 통해 텀블러의 효능을 직관적으로 보여주고, '힐링'이라는 키워드를 연결하여 구매 욕구를 자극합니다.
**3. 솔직히 말해서...**
* **이미지:** 텀블러를 들고 있는 세련된 모습의 셀럽
* **카피:**
* "솔직히 말해서, 이 텀블러 없이는 인싸 못 해 😎"
* "24시간 얼음 유지? 그거 완전 내 스타일 아니냐? 😍"
* "예쁜 텀블러는 덤, 24시간 얼음은 기본! 지금 바로 겟!"
* **타겟:** 트렌드에 민감하고, SNS 활동을 즐기는 20대 직장인
* **설명:** 솔직하고 거침없는 말투로 20대들의 공감을 얻고, '인싸템', '스타일' 등의 키워드를 활용하여 소유욕을 자극합니다. 셀럽을 활용하여 제품의 이미지를 더욱 매력적으로 어필합니다.
**추가 팁:**
* 각 카피에 맞는 재치 있는 해시태그를 활용하여 SNS 확산을 유도하세요. (#24시간얼음텀블러 #인싸템 #월요병극복 #퇴근후힐링 등)
* 20대들이 즐겨 사용하는 밈(meme)이나 유행어를 적절히 활용하면 더욱 효과적입니다.
* 제품의 디자인과 색상을 강조하여 시각적인 매력을 더하세요.
이 3가지 카피를 바탕으로, 20대 직장인들의 마음을 사로잡는 멋진 광고 캠페인을 만들어 보세요! 😊
확 달라진다, 모델별로 결과값이 이렇게 달라진다.
그런데 openai는
# 출력형태가 다름 => openai 출력값에 대한 예외처리 필요
# openai는 이전 형식이 더 적절
ai_ment = run_bedrock_llm_converse( get_model_id('openai'), p_style, query )
print(ai_ment)
-----------------
[{'type': 'reasoning_content', 'reasoning_content': {'text': 'The user asks for 3 copywriter recommendations? Actually they want "카피라이터 3개 추천" maybe they mean three copy lines (copy) for promoting a new tumbler that doesn\'t melt ice for 24 hours, targeting 20s office workers. So provide three witty, humorous copy lines. Should be in Korean, with style. Provide maybe tagline and short body. Let\'s produce.', 'signature': ''}}, {'type': 'text', 'text': '### 1. “얼음이 사라지는 건 회의실에만 한정! \n24시간 딱‑딱 고정, ‘얼음‑고정’ 텀블러와 함께라면 점심 내내 시원함이 내 일과가 된다.” \n\n---\n\n### 2. “‘오늘도 땀 뻘뻘’? 아니, ‘얼음 얼음’! \n‘얼음 영원’ 텀블러 하나면 ‘퇴근까지 시원하게’ 라는 슬로건이 실현됩니다. 20대 직장인들의 ‘시원한 야근’ 비법, 여기 있습니다.” \n\n---\n\n### 3. “‘아직도 물을 따르나요?’ \n우리 텀블러는 24시간 내내 ‘얼음 파티’를 열어줍니다. \n‘얼음이 안 녹는 이유? 내가 셀럽이라서!’ – 이제 회식도, 회의도, 인스타그램 스토리도 시원하게 즐겨보세요. '}]
예전 방식이 더 낫다고 한다.
- 정리
- LLM 모델별로 모델 호출 함수를 적절하게 분배하는것이 유리
- 모델 id로 구분 필요
- ChatBedrock
- claude, openai
- ChatBedrockConverse
- claude, google
- ChatBedrock
이렇게 코랩에서 프롬프트엔지니어링 bedrock 파트가 끝났고 이제 실습으로 넘어갔다.
- LLM langchain bedrock
- llm 기반 서비스
- 키워드
- bedrock 사용
- llm 호출 담당
- llm model
- claude, openai, gemma 모델 사용
- streamlit을 이용하여 UI구성 (프론트엔드 담당)
- 파이썬으로만 구성 (html, css, js 모두 사용 x )
- fastapi를 이용하여 bedrock 호출
- 화면 x
- 백엔드에서 api역할만 담당
- langchain
- 프롬프트 엔지니어링 담당
- 프롬프트 + llm 호출 chain 으로 연결해서 파이프라인 구축
- 서비스 주제
- 점심 / 저녁 등 메뉴 해결사 (메뉴 추천)
- bedrock 사용
# 구조
/
L .env : 각종 키, bedrock 단기 키
L .gitignore : 깃허브에 업로드 x 파일, 디렉토리 명시
L requirements.txt : 패키지 설치 내용 -> 추후 버전 표기
L app.py : 프론트 담당, streamlit 주로 구성
L sever.py : 백엔드 담당, fastapi 주로 사용
설치
- 가상환경 구축 (경로 주의:현재 작업 디렉토리)
- python -m venv llm_venv
- 가상환경 활성화
- 윈도우기준
```
.\llm_venv\Scripts\activate
or
..\llm_venv\Scripts\activate
```
- 패키지 설치
- (llm_venv) llm> pip install -r requirements.txt
- .gitignore 가상환경폴더 추가
```
...
# 가상환경제외
llm_venv
```
- 패키지 설치
- pip install -r requirements.txt
```
# bedrock 호출 API 구성
fastapi
uvicorn
# 프런트 UI 구성
streamlit
# 프런트 -> fastapi로 요청(채팅 메세지) -> 응답처리
requests
# AWS 엑세스, bedrock 사용
boto3
# 랭체인 AWS용도, 코어(프럼프트 기능만 사용)
langchain-aws
langchain-core
# 환경변수 로드 하여 OS단에 세팅
python-dotenv
```
구동
- 백엔드 : server.py
```
uvicorn server:app --reload --port 8000
```
- 프런트 : app.py
```
streamlit run app.py
```
app.py
import streamlit as st
import requests as req
# a = 1
# print('사용자 입력후 엔터치면 계속 전체가 구동되는지 점검')#, a)
# 전역설정
API_URL = 'http://localhost:8000/llm' # fastapi 주소
st.set_page_config(page_title='식사 메뉴 해결사', page_icon='🍔')
st.title('AI 식사 메뉴 해결사 - 킹')
st.caption('예상, 점심/저녁 등 시점, 날씨, 기분, 단체여부 등 알려주시면 메뉴를 추천해드립니다.')
# session state 초기화 -> 현재 코드가 몇 번이고 재실행되더라도 데이터를 유지, 전역
if 'messages' not in st.session_state: # 최초에는 아무것도 없음
st.session_state.messages = [
# 페르소나는 백엔드에서 구성
{
'role' : 'assistant',
'content' : '안녕하세요! 오늘 식사는 어떤 것이 땡기나요?(예산, 점심/저녁 등 시점, 날씨, 기분, 단체여부 등 알려주시면 메뉴를 추천해드립니다.)'
}
]
# 이전 대화내용 화면 출력
for msg in st.session_state.messages:
with st.chat_message(msg['role']): # assistant or user
st.markdown(msg['content'])
# ui
# prompt = st.chat_input('현재 상황을 자세히 입력하세요')
# print(prompt)
# a += 1
# if prompt:
# prompt 입력값을 받아서 -> 존재하면 -> 작업 진행
# 대입 표현식(혹은 왈러스 연산자) -> 나오지 않은 문법임
if prompt:= st.chat_input('현재 상황을 자세히 입력하세요'):
# 사용자 질의 처리 진행
# 1. 사용자의 입력 내용을 전역 상태 관리 변수에 추가
st.session_state.messages.append({
'role':'user',
'content' : prompt
})
# 2. 사용자 입력 후 -> 마크다운 표기
# 화면에 방금 추가된 내용을 바로 반영하여 출력해라
with st.chat_message('user'): # user로 고정했음
st.markdown(prompt) # 화면에 텍스트 내용 출력
pass
# 3. LLM에게 문의 -> 서버 요청 -> bedrock 요청 -> bedrock 응답
# 서버 응답 -> assistant의 응답
with st.chat_message('assistant'):
msg_holder = st.empty()
msg_holder.markdown('고민중....ㅡ.ㅡ')
# 3-1. 서버측으로 사용자의 질의 전송
# res = req.post(API_URL,json={'question':prompt})
# 추후, 백엔드 구성 후 교체
import time
time.sleep(3)
res = '더미 응답 : 치킨으로 가보세요!'
# 3-2. 화면 처리
msg_holder.markdown(res)
# 3-3. 전역 상태 관리 변수에 추가
st.session_state.messages.append({
'role':'assistant',
'content':'res'
})
pass
pass
일단 오늘의 수업은 여기까지다, 이후 백엔드 server.py까지 완성한 후 연결해서 저장하는곳까지 갈건데 그 부분은 월요일에 진행할 예정이다.
지금까지의 결과물은 이렇다.
오늘의 수업은 여기까지.
주말에 백엔드 구성 한번 해봐야겠다. 이제 더 열심히 해야되는데 할게 너무 많아서 큰일이다 큰일이야
그리고 다다음주 크리스마스가 지나고 난 후부턴 미니 프로젝트에 들어갈 예정이다.
추후 포트폴리오에도 들어갈 내용이니 각 잡고 해야한다.
오늘 하루도 화이팅