Ⅰ. 오전 수업
A. 1교시
1. 지난 시간 복습
2. fetch api
B. 2교시
1. fetch api (cont.)
2. 카카오지도 api
C. 3교시
1. TIPS / FEEDBACK
2. JS 수업 전체 복습
Ⅱ. 오후 수업
A. 4교시: LangChain
1. 지난 시간 복습
2. 메시지 출력 양식 설정
3. 한 개의 변수에 두 개 이상의 값을 넣고 싶을 때
B. 5교시: LangChain
1. 문서 요약 시스템 만들어보기
2. 데이터를 효과적으로 전달하는 방법
C. 6교시: LangChain
1. 간단 챗봇 만들어 보기
2. LangChain의 다양한 활용법
Ⅲ. CAREER UP
A. Goal Tracker, TIL 정리
B. 포트폴리오 특강
Ⅳ. 하루 돌아보기
동기 통신은 요청 후 응답을 기다려 다음 작업을 수행하는 반면, 비동기 통신은 요청을 보내놓고 응답을 기다리지 않고 다음 작업을 계속 수행하는 방식입니다(현재 실행중인 작업을 멈추지 않고 다른 작업을 병렬적으로 수행). 동기 통신은 순차적인 진행으로 작업이 끝날 때까지 기다려야 하는 반면, 비동기 통신은 작업이 동시에 진행될 수 있어 효율적입니다.
→ 더 자세한 내용은 inpa 블로그 읽어보기
function taskA(a, b) {
return setTimeout(() => {
const res = a + b;
return res;
}, 2000);
}
const res = taskA(10, 20);
console.log(res); // Timeout { _idleTimeout: 2000, .. }
function taskA(a, b, cb) {
// 2. 비동기 작업으로 setTimeout 내부 코드가 2초 뒤에 실행된다. (Non-Blocking)
setTimeout(() => {
// 4. 비동기 작업을 수행한다.
const res = a + b;
// 5. 비동기 작업이 완료되면 콜백 함수를 호출해 연산의 결과값을 인수로 전달한다.
cb(res);
}, 2000);
}
// 1. taskA 함수를 호출한다. 이때 인수로 화살표 함수로 만든 콜백 함수를 전달한다.
taskA(10, 20, (res) => {
// 6. taskA의 비동기 작업이 종료되고, 콜백 함수가 호출되어 실행된다.
console.log("TASK A RESULT: ", res); // 30
});
// 3. taskA 내부 함수가 비동기 작업이므로 해당 작업의 종료를 기다리지 않고 먼저 출력된다.
console.log("task B RESULT");

$.ajax({
type: 'POST',
url: 'your_server_url',
data: { param1: 'value1' },
success: function(response) {
console.log('성공:', response);
},
error: function(jqXHR, textStatus, errorThrown) {
console.error('AJAX 오류 발생:');
console.error('jqXHR:', jqXHR);
console.error('textStatus:', textStatus);
console.error('errorThrown:', errorThrown);
// jqXHR.status 등을 통해 HTTP 상태 코드 확인 가능
}
const getData2 = () => {
let url = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=★발급받은 KEY 넣기★&targetDt=20250825";
fetch(url)
.then((res)=>res.json())
.then((data)=>getMovieName(data))
}


.then((data)=>getMovieName(data))의 data는 어디서 오는 건가요?.then((res)=>res.json())이 끝났을 때 json으로 바뀐 데이터를 자동적으로 매개 변수로 넘겨준 것! (위에서 만든 res.json()이 자동으로 data에 연결된다고 함)Live Server 실행하면 콘솔창에 나오는 경고문은 왜 나오는 건가요?
→ 웹 페이지는 기본적으로 만들 때 '아이콘'이 있음 (네이버 이름 옆 N 로고 같은 거) → 로컬 환경은 원래 해당 아이콘 경로 설정이 안 되어 있어서 뜨는 것임: 오류 아니니까 신경 쓰지 말기!
const getMovieName = (res) => {
let data = res.boxOfficeResult.dailyBoxOfficeList
// json 데이터는 key와 index만 생각하자
for(let i=0;i<data.length;i++){
console.log(data[i].movieNm);
}
}
const getData2 = () => {
let url = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=aab94063cb3a3a547ae3602a83b8a2de&targetDt=20250825";
fetch(url)
.then((res)=>res.json())
.then((data)=>getMovieName(data)) // 콜백 함수 기법
}
document.getElementById("btn").addEventListener("click",getData2);
http://127.0.0.1:5500 입력 → 로컬이라는 뜻임
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY를 사용하세요"></script>에서 '발급받은 APP KEY를 사용하세요' 위치에 발급 받은 API KEY 넣기


const socket = io();
document.getElementById("searchForm").addEventListener("submit",function(e) {
e.preventDefault();
document.getElementById("resultDiv").style.display = "block";
const formData = new FormData(e.target);
const data = Object.fromEntries(formData.entries());
socket.emit("start_analysis", data);
});
color: var(--muted) in CSS sets the color property of an element to the value of a custom CSS variable named --muted.dev로 변환해 숨기는 걸 추천
.ts TypeScript: 타입이 붙은 자바스크립트 ← 자바의 장점을 가져온 것
var의 문제점let은 변수명이 중복되지 않음 → let을 쓰는 게 표준안const는 한 번 값을 넣으면 수정 불가능(재할당 불가능) & 재선언 불가능Number().length| vanila JS | jQuery | |
|---|---|---|
| 요소 접근 | document.getElementById("id"); | $("#id"); |
| 컨텐츠 접근 | document.getElementById("id").innerText; | $("#id").text(); |
| 컨텐츠 수정 | document.getElementById("id").innerText = "수정"; | $("#id").text("수정"); |
| 스타일 변경 1 | document.getElementById("id").style.color = "red"; | $("#id").css("color", "red"); |
| 스타일 변경 2 | document.getElementById("id").style.cssText = "color: blue; font-size: 100px;"; | $("#id").css({color: "blue", fontSize: "100px"}); |
| 함수 연결 | document.getElementById("btn").addEventListener("click",print); | $("#btn").on("click", print); |

HuggingFacePipeline.from_model_id classChatPromptTemplate# 구글 마운트 및 경로 설정
%cd /content/drive/MyDrive/Colab Notebooks/LangChain
# api key 설정
import os
with open("./key/.openai_api_key",'r') as f:
api_key = f.read().strip()
os.environ["OPENAI_API_KEY"] = api_key
!pip install langchain_openai
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
llm4=ChatOpenAI(model = 'gpt-4o-mini', max_tokens = 500)
# 출력 형식 지정하기
prompt_template = ChatPromptTemplate.from_messages([
('system', "너는 여행 전문가이고 여행지의 맛있는 음식에 대해 전문적으로 대답할 수 있어"),
('human', '{area}에서 유명한 {topic} {num}가지를 추천해 줘~'),
('ai',""" 아래의 형식처럼 답변을 작성해주세요
======================
타이틀
======================
- 응답 1
- 설명
- 응답 2
- 설명
- 응답 3
- 설명
""")
])
# 체인 생성
travel_chain2 = prompt_template | llm4
# 결과 출력(invoke 함수에서 바로 작성)
res = travel_chain2.invoke({
"area": "일본"
, "topic": "스시"
, "num": 5
})
print(res.content)
======================
일본에서 유명한 스시 5가지
======================
- 니기리 스시 (Nigiri Sushi)
- 신선한 생선을 얇게 썰어 얹은 쌀 덩어리로, 스시에 가장 기본적인 형태입니다. 일반적으로 간장, 와사비와 함께 제공되며, 생선의 신선함이 가장 중요합니다.
- 마키 스시 (Maki Sushi)
- 해조류(김)로 감싸진 쌀과 다양한 재료가 들어있는 스시입니다. 소스나 야채, 해산물 등을 넣어 롤 형태로 만들어지며, 다양한 맛과 질감을 즐길 수 있습니다.
- 우에바리 스시 (Aburi Sushi)
- 생선의 표면을 불에 구워서 약간 익히는 스시입니다. 불에 구워서 생선의 맛과 향을 더욱 깊게 만들며, 팬이 많은 인기 메뉴입니다.
- 하카마 스시 (Hakama Sushi)
- 횟감으로 주로 고등어, 연어 등을 사용하여 생성된 스시로, 신선한 해산물과 밥의 조화가 일품입니다. 주로 지역 특산물로 만들어지는 경우가 많습니다.
- 오마카세 스시 (Omakase Sushi)
- 셰프에게 요리를 맡기는 스타일의 스시로, 매 시즌, 매 입회마다 신선한 재료로 즉석에서 준비되어 제공됩니다. 특별한 경험을 원하는 이들에게 추천합니다.
prompt_template = ChatPromptTemplate.from_messages([
('system', "너는 여행 전문가이고 여행지의 여러 가지 정보에 대해 전문적으로 대답할 수 있어"),
('human', '{area}에서 유명한 {topic} {num}가지를 추천해 줘~'),
('ai',""" 아래의 형식처럼 답변을 작성해주세요
======================
타이틀
======================
- 응답 1
- 설명
- 응답 2
- 설명
- 응답 3
- 설명
""")
])
travel_chain = prompt_template|llm4
res = travel_chain.invoke({
"area": "일본"
, "topic": "겨울 여행지"
, "num": 5
})
print(res.content)
======================
일본의 유명한 겨울 여행지 5곳
======================
- 홋카이도 (Hokkaido)
- 일본의 가장 북쪽에 위치한 홋카이도는 겨울철 스키와 스노보드의 명소로 유명합니다. 특히 니세코(Notches)와 후라노(Furano)는 세계적인 수준의 스키 리조트로, 아름다운 눈국경과 함께 다양한 겨울 스포츠를 즐길 수 있습니다. 또한, 삿포로에서는 매년 개최되는 삿포로 눈축제(Sapporo Snow Festival)도 놓칠 수 없는 매력입니다.
- 오사카 (Osaka)
- 겨울철 오사카에서는 특별한 겨울 조명과 축제가 많이 열립니다. 특히 다카시마야 백화점과 우메다 스카이 빌딩 주변에서는 환상적인 겨울 조명이 반짝이며, 맛있는 겨울음식인 오코노미야키와 타코야키를 즐길 수 있습니다. 겨울철 한정 이벤트로는 크리스마스 마켓과 뉴 연 소음 등이 있습니다.
- 나고야 (Nagoya)
- 나고야는 겨울철 가족 단위 여행객들에게 적합한 다양한 장소를 제공합니다. 특히 레고랜드 재팬에서는 겨울 특별 이벤트가 열리며, 누가 단체 스케이팅을 경험할 수 있는 핫코리. 나고야 성에서는 겨울 조명이 빛나며 고즈넉한 분위기를 즐길 수 있습니다.
- 교토 (Kyoto)
- 겨울철 교토는 조용하고 고즈넉한 분위기로 일본 전통문화를 경험할 수 있는 멋진 장소입니다. 특히 독특한 겨울 풍경을 담은 사찰과 정원들은 더욱 아름다워지는 시기입니다. 기온 거리를 거닐며 전통 가옥과 함께 찻집에서 따뜻한 차 한 잔을 즐기는 시간을 가진다면 잊지 못할 겨울 여행이 될 것입니다.
- 삿포로 (Sapporo)
- 홋카이도의 수도인 삿포로는 겨울철에 특히 많은 관광객이 몰리는 곳입니다. 삿포로 눈축제(Sapporo Snow Festival)는 세계적으로
→ max-token을 500으로 설정했기 때문에 삿포로는 문장 중간에 끝남
batch() 함수invoke() 대신 사용하여 한 개의 변수에 여러 개의 값을 전달prompt = ChatPromptTemplate.from_template("{country}의 수도는 어디일까요?")
chain = prompt | llm4
input_list = [
{"country": "미국"}
, {"country": "호주"}
, {"country": "안드로메다"}
]
res2 = chain.batch(input_list)
# content만 출력하기
for text in res2:
print(text.content)
미국의 수도는 워싱턴 D.C.입니다.
호주의 수도는 캔버라(Canberra)입니다. 캔버라는 호주 연방 정부의 중심지로, 국가의 주요 정부 기관들이 위치하고 있습니다.
안드로메다는 별자리이자 우리 은하인 Milky Way와는 다른 별계에 위치한 은하입니다. 따라서 "안드로메다의 수도"라는 개념은 실제로 존재하지 않습니다. 안드로메다 은하는 M31이라는 이름을 가지며, 지구에서 가장 가까운 대형 은하 중 하나입니다. 과학적 및 천문학적 관점에서 볼 때, 안드로메다에는 인간이 살거나 수도가 존재하지 않지만, 우주 탐사나 SF 소설에서 상상으로 만들어진 세계에서는 다양한 설정이 있을 수 있습니다.
→ chain.batch(input_list)의 결과는 AIMessage 객체 배열(리스트 안에 AIMessage 객체 3개가 들어 있음) → for 문을 통해 AIMessage 객체를 하나씩 꺼내고 거기에 .content를 해서 내용만 출력 가능
| 역할 | 권장 지시 사항 위치 | 주요 효과 |
|---|---|---|
| system | 대화 전체에 적용할 규칙 | 항상 일관성 유지, 전역 규칙 적용 |
| human | 개별 질문/입력에 적용 | 요청별로 다르게 제어, 유연성 |
| ai | 출력 예시, 템플릿 | 포맷/형식 직접 제시, 따라 쓰게 유도 |
.invoke(document)llm_model = ChatOpenAI(model="gpt-4o-mini", temperature=0, max_tokens=500)
summary_prompt = ChatPromptTemplate.from_messages([
("system","당신은 장문을 요약하는 시스템입니다.") # role
, ("human","입력된 document를 요약하세요: {document}") # 사용자의 입력
, ("ai","요약 결과는 50 단어 이하로 해주세요. 반드시 필요한 내용을 포함시켜주세요") # 출력 → 출력 관련 내용 넣기
])
document = """
(서울=연합뉴스) 김경희 기자 = '디지털 전환'(DX)에서 '인공지능 전환'(AX)으로 정보통신(ITC) 패러다임 이동이 이뤄지는 가운데 산업계의 이 같은 변화를 실행하는 시스템 통합(SI) 업계 내부에서부터 AI 전진 배치가 급격히 진행되고 있다.
2일 관련업계에 따르면 대기업 계열 SI 기업 대부분이 코딩 등 영역에 AI를 폭넓게 이용하는 가운데 최근에는 업무 전반으로 이를 확산해 업계 화두인 'AI 에이전트'에 선제적으로 대비하는 움직임을 보이고 있다.
LG CNS는 최근 코딩 단계에서만 활용해 온 AI 코딩 플랫폼을 고도화해 분석부터 설계, 코딩, 테스트, 품질진단 전 과정으로 확대했다고 밝혔다.
업그레이드한 플랫폼에는 개발자들이 만들고자 하는 기능에 대한 명령어를 입력하는 것만으로 생성형 AI가 소스코드 생성부터 테스트, 검증까지 자동으로 수행하는 '코딩 에이전트' 기능도 탑재했다.
테스트와 검증 과정에서 오류가 발생할 경우 코딩 에이전트가 자동으로 소스코드를 수정하고 이를 반복 수행해 고품질의 결과물을 얻을 수 있도록 했다.
현대오토에버[307950] 역시 지난해 하반기부터 자체 개발한 생성형 AI 기반 대화형 서비스 '에이치 챗'을 업무에 활용 중이다.
마이크로소프트의 '애저 오픈AI'를 기반으로 임직원의 업무를 보좌한다. 대표적으로는 단위 테스트 코드를 수행해 개발자들이 신뢰성 높은 코드를 쉽게 만들 수 있게 돕는다.
단위 테스트는 작성한 코드가 의도대로 작동하는지 검증하는 절차로, 상당한 시간이 소요되고 작업 난도 역시 높다.
소프트웨어 오류의 원인을 찾아내고 해결 방법까지 제시하는 '트러블 슈팅' 기능도 수행한다. 코드 마이그레이션, 코드 리뷰 기능도 가능하다.
최근 AI를 전면에 내세워 사명을 바꾼 SK AX(옛 SK C&C)는 아예 'AI 퍼스트' 전략을 내세워 개발 현장에 AX 개발 플랫폼 '솔루어'는 물론 다양한 AI코딩 설루션을 활용 중이다.
분석과 설계 단계에서 AI가 방대한 정보를 자연어로 정리하고 복잡한 업무 흐름을 구조화하면, 개발자가 본질적 설계 논리에 집중할 수 있게 하는 식이다.
코딩 단계에서는 AI가 반복적 작업을 대신하고, 개발자의 의도를 반영해 필요한 코드 조각을 제안하는 식의 협업이 이뤄진다.
삼성SDS는 생성형 AI 서비스인 '패브릭스'(FabriX), '브리티 코파일럿'(Brity Copilot), '브리티 오토메이션'(Brity Automation) 등 시스템을 구현 중이다.
삼성SDS는 디지털 물류 플랫폼 첼로스퀘어에도 AI를 적용하고 있다. 분석형 AI를 활용한 '출항일 및 도착 예정일 예측', '환적 및 하역 항구 이슈 조기 감지' 등 기능이 가능하다.
CJ올리브네트웍스 역시 지난해부터 AI 기반 시스템 개발 체계를 도입해 개발 생산성 향상이라는 성과를 거두고 있다고 밝혔다.
회사 측은 AI 코딩 기술을 설계·개발·테스트·품질 검토 등 개발 라이프사이클 전반에 적용하고 있으며, 코드 작성과 리뷰, 테스트 코드 개발까지 전 영역에 AI를 활용하는 방식으로 전환 중이라고 설명했다.
특히 단일 AI가 아닌 글로벌 AI 모델들을 동시에 활용하고, 생성된 코드에 대한 교차 검증(Cross check)까지 진행해 품질을 높이고 있다고 강조했다.
"""
summary_chain = summary_prompt | llm_model
res3 = summary_chain.invoke({"document":document})
print(res3.content)
산업계에서 '디지털 전환'에서 '인공지능 전환'으로의 변화가 진행 중이며, SI 기업들이 AI를 업무 전반에 활용하고 있다. LG CNS, 현대오토에버, SK AX, 삼성SDS, CJ올리브네트웍스 등은 AI 기반 시스템을 도입해 개발 효율성을 높이고 있다.
❓ '요약 결과는 50 단어 이하로 해주세요'를 human에 넣는 것과 ai에 넣는 것의 차이
❗ 출력 결과는 비슷할 수 있지만 모델이 받아들이는 의미가 조금씩 달라짐
→ 출력 형식 지시를 system, human, ai 메시지 각각 어디에 넣느냐에 따라 의미적 역할과 LLM의 반응 방식이 달라짐!메시지 역할별 차이
system 메시지
- 목적: 모델 전체 동작의 기본 규칙이나 행동 양식을 지정.
- 지시어를 넣으면: LLM이 모든 대화에 걸쳐 일관된 요약 방식(예: 언제나 50단어 이하로)을 유지하려고 함.
- 예시: "항상 요약은 50단어 이하로 해 주세요."
human 메시지
- 목적: 사용자(즉, 프롬프트 작성자)가 모델에 제공하는 실제 입력이나 요청.
- 지시어를 넣으면: LLM이 ‘요약해 달라’는 요청과 함께 제한 조건(50단어 이하)을 ‘질문’의 일부로 인식.
- 예시: “입력된 문서를 50단어 이하로 요약해 주세요.”
ai 메시지
- 목적: LLM이 예시 답변을 보거나, 원하는 답변 형식을 따르라고 안내(초거시적 output template 역할).
- 지시어를 넣으면: LLM이 예시 답변의 형식과 원하는 제약(50단어 이하)에 맞춰 출력.
- 예시: “요약 결과는 50 단어 이하로 해주세요. 반드시 필요한 내용을 포함시켜주세요.”
실제 출력 차이
- system에 넣으면: 전체 대화에서 일관된 응답 스타일을 원할 때 적합. 한 번에 여러 작업을 하거나 장기적인 일관성이 중요할 때 사용.
- human에 넣으면: 해당 질문에만 적용되는 제한(예외적인 지시)이 명확히 전달됨. 다양한 요청에 따라 다르게 동작하도록 유연하게 제어할 때 알맞음.
- ai에 넣으면: 원하는 형식의 샘플 답변(혹은 답안의 포맷 및 제약 조건)을 ‘따라 쓰기’ 방식으로 쉽게 유도함. 출력 예시 효과가 큰 상황에 적합.
결론
- 일관된 룰 지정: system이 적합.
- 특정 요청마다 다르게 적용: human이 적합.
- 출력 예시와 직접 명시: ai가 효과적.
실제 차이는 크게 드러나지 않을 수 있지만, 복잡한 프롬프트 구조나 다양한 작업을 조합할 때 메시지 배치에 따라 LLM 응답 품질과 일관성이 달라질 수 있습니다.
RunnablePassthrough()과RunnableParallel()
from langchain_core.runnables import RunnablePassthrough
# 입력값을 별도 처리 없이 다음 단계로 전달할 때 사용
# 1. 모델 생성 → 위에서 만든 llm_mode 사용
# 2. 프롬프트 생성
prompt = ChatPromptTemplate.from_template("{obj}의 주요 기능에 대해서 설명해 줘")
# 3. chain 구성
chain = {"obj":RunnablePassthrough()} | prompt | llm4
# 4. chain 실행
result = chain.invoke("사과")
print(result.content)
사과는 여러 가지 주요 기능과 효과를 가지고 있는 과일입니다. 다음은 사과의 주요 기능에 대한 설명입니다:
1. **영양소 공급**: 사과는 비타민 C, 식이섬유, 항산화 물질인 폴리페놀 등이 풍부하여 면역력을 증진하고 건강에 도움을 줍니다.
2. **소화 개선**: 사과에 함유된 식이섬유는 소화를 촉진하고 장 건강을 개선하는 데 기여합니다. 특히 펙틴이라는 식이섬유는 장내 유익한 세균의 성장을 도와줍니다.
3. **체중 관리**: 사과는 칼로리가 낮고 식이섬유가 많아 포만감을 주어 체중 관리에 유리합니다. 간식으로 섭취하기 좋은 선택입니다.
4. **심혈관 건강**: 사과의 항산화 물질은 심혈관 질환의 위험을 줄이는 데 도움을 줍니다. 또한, 식이섬유는 콜레스테롤 수치를 낮추는 데 기여할 수 있습니다.
5. **혈당 조절**: 사과는 혈당 지수가 낮아 혈당을 안정적으로 유지하는 데 도움이 됩니다. 특히 당뇨 환자에게 좋은 과일로 알려져 있습니다.
6. **항산화 효과**: 사과에 포함된 다양한 항산화 물질은 세포의 손상을 예방하고 노화 방지에 도움을 줄 수 있습니다.
이 외에도 사과는 다양한 요리에 활용되며, 간편하게 섭취할 수 있는 과일로 많은 사람들에게 사랑받고 있습니다.
obj에게 RunnablePassthrough가 dictionary 형태로 전달해 주기 때문에(RunnablePassthrough를 통해 obj로 들어가기 때문에) 체인을 사용할 때
chain.invoke("사과")와 같이 딕셔너리 형태가 아닌 단순 키워드(문자열)만 사용하면 됨
RunnableParallel() 함수
from langchain_core.runnables import RunnableParallel
# 모델 생성 → model_llm 그대로 사용
# 프롬프트 작성
prompt1=ChatPromptTemplate.from_template("{capital}의 수도는 어디일까요?")
prompt2=ChatPromptTemplate.from_template("{area}의 면적은?")
# 여러 개의 체인을 작성
chain1 = {"capital": RunnablePassthrough()}|prompt1|llm4
chain2 = {"area": RunnablePassthrough()}|prompt2|llm4
# 체인 사용하기
combined_chain = RunnableParallel({"capital":chain1, "area":chain2})
combined_chain.invoke("대한민국")
{'capital': AIMessage(content='대한민국의 수도는 서울입니다.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 8, 'prompt_tokens': 16, 'total_tokens': 24, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_560af6e559', 'id': 'chatcmpl-C9PtdHm5Kwh7NuHLh4y2YI1eCK3rw', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None}, id='run--de52952a-0eab-4ac2-a68a-691dce12e415-0', usage_metadata={'input_tokens': 16, 'output_tokens': 8, 'total_tokens': 24, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}),
'area': AIMessage(content='대한민국의 면적은 약 100,210 제곱킬로미터입니다. 이는 한반도의 남쪽에 위치한 국가로, 대략적인 크기는 미국의 테네시주와 비슷합니다.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 48, 'prompt_tokens': 14, 'total_tokens': 62, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_560af6e559', 'id': 'chatcmpl-C9PtdosWSmONi3lFIxts9xjQZbRcu', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None}, id='run--f8db0686-828a-43a9-80aa-e35605f59639-0', usage_metadata={'input_tokens': 14, 'output_tokens': 48, 'total_tokens': 62, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})}
from langchain_community.vectorstores import FAISS from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_openai import ChatOpenAI, OpenAIEmbeddings # 텍스트로부터 FAISS 벡터 저장소를 생성합니다. vectorstore = FAISS.from_texts( [ "테디는 랭체인 주식회사에서 근무를 하였습니다.", "셜리는 테디와 같은 회사에서 근무하였습니다.", "테디의 직업은 개발자입니다.", "셜리의 직업은 디자이너입니다.", ], embedding=OpenAIEmbeddings(), ) # 벡터 저장소를 검색기로 사용합니다. retriever = vectorstore.as_retriever() # 템플릿을 정의합니다. template = """Answer the question based only on the following context: {context} Question: {question} """ # 템플릿으로부터 채팅 프롬프트를 생성합니다. prompt = ChatPromptTemplate.from_template(template) # ChatOpenAI 모델을 초기화합니다. model = ChatOpenAI(model_name="gpt-4o-mini") # 문서를 포맷팅하는 함수 def format_docs(docs): return "\n".join([doc.page_content for doc in docs]) # 검색 체인을 구성합니다. retrieval_chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | prompt | model | StrOutputParser() ) # 검색 체인을 실행하여 질문에 대한 답변을 얻습니다. retrieval_chain.invoke("테디의 직업은 무엇입니까?") # '테디의 직업은 개발자입니다.' # 검색 체인을 실행하여 질문에 대한 답변을 얻습니다. retrieval_chain.invoke("셜리의 직업은 무엇입니까?") # '셜리의 직업은 디자이너입니다.'
→ 'context'의 값(== 입력 값)이 그대로 답변으로 나옴!
from langchain_core.output_parsers import StrOutputParser
# llm_model: 템플릿 지정 → 여행전문가
prompt_template = ChatPromptTemplate.from_messages([
('system', "너는 여행 전문가이고 여행지에 대해 전문적으로 대답할 수 있어"),
('human', '{area}에서 유명한 {topic} {num}가지를 추천해줘~'),
('ai',""" 아래의 형식처럼 답변을 작성해주세요
======================
타이틀
======================
- 응답 1
- 설명
- 응답 2
- 설명
- 응답 3
- 설명
""")
])
# 체인연결
travel_chain3 = prompt_template | llm_model | StrOutputParser()
res3 = travel_chain3.invoke({"area":"일본","topic":"시리카와고","num":5})
print(res3)
# StrOutputParser()를 사용했기 때문에 .content 하지 않아도 바로 string 형태로 예쁘게 나온다!
======================
시리카와고의 매력적인 명소 5가지
======================
- 응답 1: 고샤쿠지 (合掌造り集落)
- 설명: 시리카와고의 대표적인 전통 마을로, UNESCO 세계문화유산으로 지정되어 있습니다. 독특한 '합장 건축' 양식의 집들이 모여 있어, 아름다운 경관을 자랑합니다. 특히 겨울철에는 눈 덮인 풍경이 환상적입니다.
- 응답 2: 시리카와고 민속촌 (白川郷民俗館)
- 설명: 이곳은 시리카와고의 전통적인 생활 방식을 체험할 수 있는 장소입니다. 다양한 전통 가옥과 농기구, 생활용품들이 전시되어 있어, 일본의 농촌 문화를 깊이 이해할 수 있습니다.
- 응답 3: 시리카와고 전망대 (白川郷展望台)
- 설명: 시리카와고의 전경을 한눈에 볼 수 있는 최고의 장소입니다. 특히 일출이나 일몰 시간에 방문하면, 아름다운 경치를 감상할 수 있어 사진 촬영에 적합합니다.
- 응답 4: 시리카와고 온천 (白川郷温泉)
- 설명: 시리카와고 지역에는 여러 온천이 있어, 여행 중 피로를 풀기에 좋습니다. 자연 속에서 온천욕을 즐기며, 편안한 시간을 보낼 수 있습니다.
- 응답 5: 시리카와고 겨울 축제 (白川郷冬まつり)
- 설명: 매년 겨울에 열리는 이 축제는 시리카와고의 아름다운 겨울 풍경을 즐길 수 있는 기회입니다. 전통적인 조명과 함께 눈으로 덮인 마을의 경관이 환상적이며, 다양한 문화 행사도 함께 진행됩니다.

.content를 사용해야 함from langchain_core.output_parsers import JsonOutputParser
prompt3 = """
광주의 유명한 {topic} 5가지를 추천해 주세요.
아래 키 값에 따라 JSON 형태로 응답해 주세요.
* 답변 1
* 답변 2
* 답변 3
* 답변 4
* 답변 5
"""
chain = {"topic": RunnablePassthrough()} | ChatPromptTemplate.from_template(prompt3)|llm_model|JsonOutputParser()
chain.invoke("음식")
{'답변 1': '광주 비빔밥',
'답변 2': '무등산 막걸리',
'답변 3': '광주 떡갈비',
'답변 4': '전라도식 김치찌개',
'답변 5': '광주 순대'}

res = chain.invoke("음식")
res["답변 1"]
광주 비빔밥
while (True):
human_in = input("입력:")
if human_in == "exit":
break
print(llm_model.invoke(human_in).content)
입력:밴드 토킹 헤드에 대해 알려주세요.
토킹 헤드(Talking Heads)는 1975년에 결성된 미국의 록 밴드로, 뉴 웨이브와 아트 록 장르에서 큰 영향을 미친 그룹입니다. 밴드는 데이비드 번(David Byrne), 티나 웨이머스(Tina Weymouth), 제리 해리슨(Jerry Harrison), 크리스 프랜시스(Chris Frantz)로 구성되어 있습니다.
토킹 헤드는 독특한 음악 스타일과 실험적인 사운드로 유명하며, 그들의 음악은 펑크 록, 아프리카 리듬, 전자 음악 등 다양한 요소를 혼합한 특징이 있습니다. 대표적인 앨범으로는 "Talking Heads: 77", "Fear of Music", "Remain in Light" 등이 있으며, 이들 앨범은 비평가들로부터 높은 평가를 받았습니다.
특히 "Once in a Lifetime"와 "Psycho Killer"와 같은 곡은 그들의 대표적인 히트곡으로, 지금까지도 많은 사랑을 받고 있습니다. 토킹 헤드는 1980년대 초반에 활동을 중단했지만, 그들의 음악은 여전히 많은 아티스트들에게 영향을 미치고 있습니다. 2002년에는 록의 명예의 전당에 헌액되었습니다.
입력:여행지 세 곳 추천해 주세요. 대한민국과 가까운 나라로 부탁해요.
대한민국과 가까운 나라에서 여행하기 좋은 세 곳을 추천해 드릴게요.
1. **일본 (도쿄)**:
- 도쿄는 현대적인 도시와 전통적인 문화가 조화를 이루는 곳입니다. 신주쿠, 시부야, 아사쿠사 등 다양한 지역에서 쇼핑과 맛있는 음식을 즐길 수 있습니다. 또한, 도쿄 타워와 스카이트리 같은 랜드마크도 방문할 만합니다.
2. **중국 (상하이)**:
- 상하이는 중국의 경제 중심지로, 현대적인 스카이라인과 전통적인 건축물이 어우러져 있습니다. 번화한 난징루 거리와 유서 깊은 유원지인 위안민가든을 방문해 보세요. 또한, 상하이의 다양한 미식도 놓치지 마세요.
3. **대만 (타이베이)**:
- 타이베이는 맛있는 길거리 음식과 친절한 사람들로 유명합니다. 타이베이 101, 국립고궁박물관, 스린 야시장 등 다양한 명소가 있습니다. 대만의 자연 경관도 아름다우니 근교 여행도 추천합니다.
이 세 곳은 모두 비행기로 쉽게 접근할 수 있으며, 각기 다른 매력을 가지고 있어 즐거운 여행이 될 것입니다!
입력:아까 물어봤던 밴드 이름이 뭐였죠?
출력: 죄송하지만, 이전 대화 내용을 기억할 수 없어요. 어떤 이름을 말씀하셨는지 다시 알려주실 수 있나요?
입력:exit
history로 메모리 기능이 없는 부분을 어느 정도 보완 가능
LangChain에서 예시와 스트리밍은 프롬프트 단순화(제로샷, 퓨샷) 그 이상의 실제적인 예시 데이터와 실시간 사용자 피드백을 포함하여, 현실적인 LLM 앱 구현에 매우 자주 사용되는 패턴
# 구글 마운트 및 경로 설정
%cd /content/drive/MyDrive/Colab Notebooks/LangChain
# api key 설정
import os
with open("./key/.openai_api_key",'r') as f:
api_key = f.read().strip()
os.environ["OPENAI_API_KEY"] = api_key
# 패키지 설치 (대략 3분 소요)
!pip install -qU openai langchain-openai langchain langchain_community
!pip install -qU tiktoken pypdf chromadb faiss-cpu
!pip install -qU langchain-teddynote
!pip install -qU huggingface_hub langchain_huggingface
# -q : 설치 진행 메시지 최소화
# -U : 이미 설치된 패키지가 있으면 최신 버전으로 업그레이드(아니면 최신 버전 설치)
모든 문서/자료/설명문에는 기·승·전·결이 꼭 필요함
중요 포인트
이미지 위주로 편집 및 설명!
면접관은 내가 어떻게 했는지는 안 궁금함! 결과만 말하기!