13b756911f
- 병렬 처리, 비동기 병렬 처리 랭그래프 - 워크플로 프리임워크 state, Node, Edge 구조 - 조건부 엣지, 루프, 자가 검토
944 lines
41 KiB
Plaintext
944 lines
41 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"id": "initial_id",
|
|
"metadata": {
|
|
"collapsed": true,
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:08:35.194596809Z",
|
|
"start_time": "2026-06-08T01:08:35.179927221Z"
|
|
}
|
|
},
|
|
"source": [
|
|
"import os\n",
|
|
"\n",
|
|
"from cohere.types import summarize_request_extractiveness\n",
|
|
"from google.protobuf.timestamp import from_current_time\n",
|
|
"from langchain_classic.chains.sequential import SequentialChain\n",
|
|
"from langchain_openai import ChatOpenAI\n",
|
|
"from langchain_ibm import WatsonxEmbeddings\n",
|
|
"from langchain_ibm import ChatWatsonx\n",
|
|
"from langchain.agents import create_agent\n",
|
|
"from langchain_ollama import OllamaEmbeddings\n",
|
|
"from langchain_ollama import ChatOllama\n",
|
|
"from langchain_ollama import OllamaEmbeddings, ChatOllama\n",
|
|
"from dotenv import load_dotenv\n",
|
|
"\n",
|
|
"from langchain_community.utilities import GoogleSerperAPIWrapper\n",
|
|
"from langchain_core.tools import Tool\n",
|
|
"from langchain_core.tools import tool\n",
|
|
"\n",
|
|
"from langchain_core.prompts import PromptTemplate, ChatPromptTemplate, MessagesPlaceholder\n",
|
|
"from langchain_core.output_parsers import StrOutputParser, JsonOutputParser, PydanticOutputParser\n",
|
|
"from langchain_core.runnables import RunnablePassthrough, RunnableParallel, RunnableLambda\n",
|
|
"from langgraph import graph\n",
|
|
"from pygments.unistring import combine\n",
|
|
"from sklearn import pipeline"
|
|
],
|
|
"outputs": [],
|
|
"execution_count": 8
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:08:35.209192873Z",
|
|
"start_time": "2026-06-08T01:08:35.196033782Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"# .env 내용 가져오기\n",
|
|
"load_dotenv()\n",
|
|
"\n",
|
|
"apikey = os.getenv(\"WATSONX_API_KEY\")\n",
|
|
"project_id = os.getenv(\"WATSONX_PROJECT_ID\")\n",
|
|
"watsonx_ai_url = os.getenv(\"WATSONX_URL\")\n",
|
|
"hf_token = os.getenv(\"HF_TOKEN\")\n",
|
|
"COHERE_API_KEY = os.getenv(\"COHERE_API_KEY\")\n",
|
|
"SERPER_API_KEY = os.getenv(\"SERPER_API_KEY\")\n",
|
|
"GEMINI_API_KEY = os.getenv(\"GEMINI_API_KEY\")\n",
|
|
"LANGSMITH_API_KEY = os.getenv(\"LANGSMITH_API_KEY\")"
|
|
],
|
|
"id": "c2c64c7967231118",
|
|
"outputs": [],
|
|
"execution_count": 9
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:08:38.814068577Z",
|
|
"start_time": "2026-06-08T01:08:35.210314784Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"watson_llm = ChatWatsonx(\n",
|
|
" model_id=\"ibm/granite-4-h-small\",\n",
|
|
" url=f\"{watsonx_ai_url}\",\n",
|
|
" api_key=f\"{apikey}\",\n",
|
|
" project_id=f\"{project_id}\",\n",
|
|
" max_tokens=2000,\n",
|
|
" params={\n",
|
|
" \"temperature\": 0\n",
|
|
" }\n",
|
|
")\n",
|
|
"\n",
|
|
"watson_embedding = WatsonxEmbeddings(\n",
|
|
" model_id=\"ibm/granite-embedding-278m-multilingual\",\n",
|
|
" url=f\"{watsonx_ai_url}\",\n",
|
|
" api_key=f\"{apikey}\",\n",
|
|
" project_id=f\"{project_id}\"\n",
|
|
")\n",
|
|
"\n",
|
|
"hugging_llm = ChatOpenAI(\n",
|
|
" model=\"Qwen/Qwen2.5-7B-Instruct:together\",\n",
|
|
" api_key=hf_token,\n",
|
|
" base_url=\"https://router.huggingface.co/v1\",\n",
|
|
" temperature=0,\n",
|
|
")\n",
|
|
"\n",
|
|
"ollama_embedding = OllamaEmbeddings(model=\"nomic-embed-text-v2-moe\")\n",
|
|
"\n",
|
|
"# 로컬 LLM\n",
|
|
"qwen_llm = ChatOllama(model=\"qwen3.5:4b\", temperature=0)\n",
|
|
"exaone_llm = ChatOllama(model=\"exaone3.5:2.4b\", temperature=0)\n",
|
|
"gemma_llm = ChatOllama(model=\"gemma4:e2b\")"
|
|
],
|
|
"id": "560df17d1a798650",
|
|
"outputs": [],
|
|
"execution_count": 10
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:08:38.836015704Z",
|
|
"start_time": "2026-06-08T01:08:38.823821493Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"def print_result(result):\n",
|
|
" for i, msg in enumerate(result['messages']):\n",
|
|
" print(f\"\\n===== {i} =====\")\n",
|
|
" print(type(msg).__name__)\n",
|
|
"\n",
|
|
" if hasattr(msg, 'content'):\n",
|
|
" print(msg.content)\n",
|
|
"\n",
|
|
" if hasattr(msg, \"tool_calls\"):\n",
|
|
" print(msg.tool_calls)"
|
|
],
|
|
"id": "abfd826c1b3e2703",
|
|
"outputs": [],
|
|
"execution_count": 11
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"### RouterChain(LCEL Router : 조건부 분기 패턴\n",
|
|
"- Router 패턴 : 입력에 따라 적절한 체인 or Runnable 로 분기\n",
|
|
"- 분류기(LLM기반 or 규칙기반)가 입력을 분석 -> 적절한 체인을 라우팅\n",
|
|
"- |\n",
|
|
"- ex) 질문 유형(코딩 / 수학 / 일반 ....)에 따른 전문 프롬프트를 적용\n",
|
|
"- 동작흐름\n",
|
|
" (1) 입력 => (2) 분류기 => (3) 라우팅 => (4) 실행 => (5) 반환"
|
|
],
|
|
"id": "fb42bec3088a485e"
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:08:38.851746574Z",
|
|
"start_time": "2026-06-08T01:08:38.839267469Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"parser = StrOutputParser()\n",
|
|
"\n",
|
|
"# 수학체인\n",
|
|
"math_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"당신은 수학 전문가입니다. 풀이 과정을 단계별로 설명하세요.\"),\n",
|
|
" (\"human\", \"{question}\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"# 코드 체인\n",
|
|
"code_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"당신은 시니어 개발자입니다. 코드와 주석을 함께 제공하세요.\"),\n",
|
|
" (\"human\", \"{question}\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"# 일반 체인\n",
|
|
"general_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"당신은 친절한 AI 어시스턴트입니다. 한국어로 답변하세요.\"),\n",
|
|
" (\"human\", \"{question}\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"# 분류기 : 질문을 읽고 유형을 반환\n",
|
|
"classify_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"질문 유형을 math/code/general 중 하나로만 답하세요.\"),\n",
|
|
" (\"human\", \"{question}\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"def route(inputs:dict):\n",
|
|
" category = classify_chain.invoke(inputs).strip().lower()\n",
|
|
"\n",
|
|
" print(f\" => 븐류결과 {category}\")\n",
|
|
"\n",
|
|
" if \"math\" in category: return math_chain\n",
|
|
" elif \"code\" in category: return code_chain\n",
|
|
" else: return general_chain\n",
|
|
"\n",
|
|
"# router_chain = RunnableLambda(route) | RunnableLambda(lamda chain: chain)\n",
|
|
"router_chain = RunnableLambda(lambda x:route(x).invoke(x))"
|
|
],
|
|
"id": "1e18698dde2e75b5",
|
|
"outputs": [],
|
|
"execution_count": 12
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:09:39.818869100Z",
|
|
"start_time": "2026-06-08T01:08:38.852667199Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"questions = [\n",
|
|
" { 'question': '피타고라스 정리를 증명해줘'},\n",
|
|
" { 'question': '오늘 저녁 메뉴 추천해줘'},\n",
|
|
" { 'question': '파이썬으로 버블 정렬 구현해줘'},\n",
|
|
" { 'question': '피타고라스 정리를 코드로 짜줘'},\n",
|
|
"]\n",
|
|
"\n",
|
|
"for q in questions:\n",
|
|
" print(f\"Q: {q['question']}\")\n",
|
|
" print(f\"A: {router_chain.invoke(q)[:100]}...\\n\")\n"
|
|
],
|
|
"id": "c9fa6cb3d73bc4e7",
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Q: 피타고라스 정리를 증명해줘\n",
|
|
" => 븐류결과 네, 다음은 피타고라스의 정리 증명입니다:\n",
|
|
"\n",
|
|
"a, b, c의 변을 가진 직각삼각형이 있다고 가정합니다. 삼각형 안에 변의 길이가 a, b, c인 정사각형을 그립니다. 다음은 그 증명입니다:\n",
|
|
"\n",
|
|
"1. 삼각형 안에 변의 길이가 a, b, c인 정사각형의 넓이는 a^2 + b^2 + 2ab입니다.\n",
|
|
"\n",
|
|
"2. 삼각형의 넓이는 (1/2)ab입니다.\n",
|
|
"\n",
|
|
"3. 삼각형의 넓이가 정사각형의 넓이의 절반과 같다는 것은 다음과 같습니다:\n",
|
|
"\n",
|
|
"a^2 + b^2 + 2ab = (1/2)(a^2 + b^2)\n",
|
|
"\n",
|
|
"4. 양변에 2를 곱하면 다음과 같습니다:\n",
|
|
"\n",
|
|
"2a^2 + 2b^2 + 4ab = a^2 + b^2\n",
|
|
"\n",
|
|
"5. 양변에서 a^2 + b^2를 빼면 다음과 같습니다:\n",
|
|
"\n",
|
|
"a^2 + b^2 = 2ab\n",
|
|
"\n",
|
|
"6. 양변에 c를 곱하면 다음과 같습니다:\n",
|
|
"\n",
|
|
"c(a^2 + b^2) = 2abc\n",
|
|
"\n",
|
|
"7. 왼쪽 항의 c를 분배하면 다음과 같습니다:\n",
|
|
"\n",
|
|
"ca^2 + cb^2 = 2abc\n",
|
|
"\n",
|
|
"8. 양변에서 2abc를 빼면 다음과 같습니다:\n",
|
|
"\n",
|
|
"ca^2 + cb^2 - 2abc = 0\n",
|
|
"\n",
|
|
"9. 왼쪽 항에서 c를 공약으로 빼면 다음과 같습니다:\n",
|
|
"\n",
|
|
"c(a^2 + b^2 - 2ab) = 0\n",
|
|
"\n",
|
|
"10. 양변을 c로 나누면 다음과 같습니다:\n",
|
|
"\n",
|
|
"a^2 + b^2 - 2ab = 0\n",
|
|
"\n",
|
|
"11. 양변에 2ab를 더하면 다음과 같습니다:\n",
|
|
"\n",
|
|
"a^2 + b^2 = 2ab\n",
|
|
"\n",
|
|
"12. 양변에 c를 곱하면 다음과 같습니다:\n",
|
|
"\n",
|
|
"c(a^2 + b^2) = 2abc\n",
|
|
"\n",
|
|
"13. 왼쪽 항의 c를 분배하면 다음과 같습니다:\n",
|
|
"\n",
|
|
"ca^2 + cb^2 = 2abc\n",
|
|
"\n",
|
|
"14. 양변에서 2abc를 빼면 다음과 같습니다:\n",
|
|
"\n",
|
|
"ca^2 + cb^2 - 2abc = 0\n",
|
|
"\n",
|
|
"15. 왼쪽 항에서 c를 공약으로 빼면 다음과 같습니다:\n",
|
|
"\n",
|
|
"c(a^2 + b^2 - 2ab) = 0\n",
|
|
"\n",
|
|
"16. 양변을 c로 나누면 다음과 같습니다:\n",
|
|
"\n",
|
|
"a^2 + b^2 = 2ab\n",
|
|
"\n",
|
|
"17. 이것은 증명이 완료되었습니다.\n",
|
|
"A: 피타고라스 정리는 직각삼각형에서 빗변의 길이의 제곱이 나머지 두 변의 길이의 제곱의 합과 같다는 정리입니다. 이 정리를 증명해 드리겠습니다.\n",
|
|
"\n",
|
|
"가정: 직각삼각형 ABC에서 각 A가...\n",
|
|
"\n",
|
|
"Q: 오늘 저녁 메뉴 추천해줘\n",
|
|
" => 븐류결과 질문 유형: general\n",
|
|
"\n",
|
|
"오늘 저녁 메뉴로는 간단하면서도 맛있는 \"치킨과 샐러드\"를 추천해드릴게요. 치킨은 구운 닭고기를 사용하고, 샐러드는 신선한 채소와 드레싱을 곁들여서 영양가 있고 가벼운 식사를 즐길 수 있습니다. 또한, 사이드로 감자튀김이나 빵을 추가하면 더욱 만족스러운 식사가 될 거예요.\n",
|
|
"A: 저녁 메뉴로는 다양한 선택지가 있습니다. 건강하고 맛있는 한국 요리를 추천해 드리겠습니다.\n",
|
|
"\n",
|
|
"1. 비빔밥: 밥에 다양한 채소와 고기를 넣고 고추장 소스를 섞어 먹는 한국의 대표적인...\n",
|
|
"\n",
|
|
"Q: 파이썬으로 버블 정렬 구현해줘\n",
|
|
" => 븐류결과 다음은 파이썬으로 구현한 버블 정렬 코드입니다.\n",
|
|
"\n",
|
|
"```python\n",
|
|
"def bubble_sort(arr):\n",
|
|
" n = len(arr)\n",
|
|
" \n",
|
|
" for i in range(n - 1):\n",
|
|
" for j in range(n - i - 1):\n",
|
|
" if arr[j] > arr[j + 1]:\n",
|
|
" arr[j], arr[j + 1] = arr[j + 1], arr[j]\n",
|
|
" \n",
|
|
" return arr\n",
|
|
"```\n",
|
|
"\n",
|
|
"이 코드는 다음과 같이 동작합니다.\n",
|
|
"\n",
|
|
"1. `bubble_sort` 함수는 정렬할 배열 `arr`을 입력으로 받습니다.\n",
|
|
"\n",
|
|
"2. 배열의 길이 `n`을 변수에 저장합니다.\n",
|
|
"\n",
|
|
"3. 외부 루프 `for i in range(n - 1)`는 배열을 `n - 1`번 반복하며, 각 반복에서 가장 큰 원소를 배열의 끝쪽으로 이동시킵니다.\n",
|
|
"\n",
|
|
"4. 내부 루프 `for j in range(n - i - 1)`는 현재 루프에서 비교해야 할 원소의 개수만큼 반복합니다. `i`가 증가함에 따라 이미 정렬된 원소의 개수만큼 내부 루프의 범위가 줄어듭니다.\n",
|
|
"\n",
|
|
"5. 내부 루프 내에서 현재 원소 `arr[j]`와 다음 원소 `arr[j + 1]`를 비교합니다. 만약 현재 원소가 다음 원소보다 크다면, 두 원소를 서로 교환합니다.\n",
|
|
"\n",
|
|
"6. 외부 루프가 모두 완료되면 정렬된 배열을 반환합니다.\n",
|
|
"\n",
|
|
"이 함수를 사용하는 예제는 다음과 같습니다.\n",
|
|
"\n",
|
|
"```python\n",
|
|
"arr = [64, 34, 25, 12, 22, 11, 90]\n",
|
|
"sorted_arr = bubble_sort(arr)\n",
|
|
"print(sorted_arr)\n",
|
|
"```\n",
|
|
"\n",
|
|
"출력 결과:\n",
|
|
"```\n",
|
|
"[11, 12, 22, 25, 34, 64, 90]\n",
|
|
"```\n",
|
|
"\n",
|
|
"버블 정렬은 인접한 두 원소를 비교하며 정렬하는 간단한 알고리즘입니다. 시간 복잡도는 o(n^2)로, 큰 규모의 데이터에는 적합하지 않습니다. 그러나 구현이 간단하고 이해하기 쉬워 교육용으로 자주 사용됩니다.\n",
|
|
"A: 물론입니다! 파이썬으로 버블 정렬을 구현해드리겠습니다. 버블 정렬은 인접한 두 원소를 비교하고, 순서가 바르지 않으면 서로 교환하는 정렬 알고리즘입니다. 다음은 파이썬 코드입니다:...\n",
|
|
"\n",
|
|
"Q: 피타고라스 정리를 코드로 짜줘\n",
|
|
" => 븐류결과 피타고라스 정리를 코드로 구현하려면, 먼저 피타고라스 정리가 무엇인지 이해해야 합니다. 피타고라스 정리는 직각삼각형에서 빗변의 길이의 제곱이 나머지 두 변의 길이의 제곱의 합과 같다는 정리입니다. 수식으로 표현하면 다음과 같습니다.\n",
|
|
"\n",
|
|
"c^2 = a^2 + b^2\n",
|
|
"\n",
|
|
"여기서 c는 빗변의 길이이고, a와 b는 나머지 두 변의 길이입니다.\n",
|
|
"\n",
|
|
"이제 이 정리를 코드로 구현해 보겠습니다. 여기서는 python을 사용하겠습니다.\n",
|
|
"\n",
|
|
"```python\n",
|
|
"import math\n",
|
|
"\n",
|
|
"def pythagorean_theorem(a, b):\n",
|
|
" c_squared = a**2 + b**2\n",
|
|
" c = math.sqrt(c_squared)\n",
|
|
" return c\n",
|
|
"\n",
|
|
"# 예시 사용\n",
|
|
"a = 3\n",
|
|
"b = 4\n",
|
|
"c = pythagorean_theorem(a, b)\n",
|
|
"print(f\"빗변의 길이는: {c}\")\n",
|
|
"```\n",
|
|
"\n",
|
|
"이 코드에서는 `pythagorean_theorem`이라는 함수를 정의하고, 두 개의 인자 `a`와 `b`를 받습니다. 이 함수는 피타고라스 정리를 사용하여 빗변의 길이 `c`를 계산하고 반환합니다. 마지막으로, 예시 사용 부분에서 `a`와 `b`의 값을 설정하고, `pythagorean_theorem` 함수를 호출하여 빗변의 길이를 계산하고 출력합니다.\n",
|
|
"A: 피타고라스 정리는 직각삼각형에서 빗변의 길이의 제곱이 나머지 두 변의 길이의 제곱의 합과 같다는 정리입니다. 수식으로 표현하면 다음과 같습니다:\n",
|
|
"\n",
|
|
"a^2 + b^2 = c^2\n",
|
|
"\n",
|
|
"여...\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 13
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": "#### RunnableBranch(선언형 분기)",
|
|
"id": "6d1f541fb236bfd9"
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:10:01.596120962Z",
|
|
"start_time": "2026-06-08T01:09:39.839322931Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"from langchain_core.runnables import RunnableBranch\n",
|
|
"\n",
|
|
"# RunnableBranch((조건1, 체인1), (조건2, 체인2), (조건3, 체인3))\n",
|
|
"\n",
|
|
"branch = RunnableBranch(\n",
|
|
" (lambda x:\"math\" in x.get(\"topic\", ''), math_chain),\n",
|
|
" (lambda x:\"code\" in x.get(\"topic\", ''), code_chain),\n",
|
|
" (lambda x:\"cooking\" in x.get(\"topic\", ''), ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"당신은 요리전문가 AI 어시스턴트입니다. 한국어로 답변하세요.\"),\n",
|
|
" (\"human\", \"{question}\"),\n",
|
|
" ]) | watson_llm | parser),\n",
|
|
" general_chain\n",
|
|
")\n",
|
|
"\n",
|
|
"print(branch.invoke({'topic':'math', 'question':'미분이란?'}))\n",
|
|
"print(branch.invoke({'topic':'code', 'question':'미적분 코드 구현'}))\n",
|
|
"print(branch.invoke({'topic':'cooking', 'question':'김치찌개 레시피?'}))\n",
|
|
"print(branch.invoke({'topic':'other', 'question':'안녕하세요?'}))"
|
|
],
|
|
"id": "7e5d342621ece0b0",
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"미분은 수학에서 함수의 변화율을 나타내는 개념입니다. 미분은 함수의 그래프에서 접선의 기울기를 구하는 과정으로, 함수의 변화율을 정확하게 파악할 수 있게 해줍니다. 미분은 미적분학의 핵심 개념 중 하나이며, 미분을 통해 함수의 최대값, 최소값, 변곡점 등을 찾을 수 있습니다.\n",
|
|
"\n",
|
|
"미분의 과정을 단계별로 설명하겠습니다.\n",
|
|
"\n",
|
|
"1. 함수 정의: 먼저 미분하고자 하는 함수 f(x)를 정의합니다. 예를 들어, f(x) = x^2 + 3x + 1과 같은 함수를 생각해보겠습니다.\n",
|
|
"2. 미분 계수 정의: 미분 계수는 함수 f(x)의 변화율을 나타내는 값으로, 기호로는 f'(x) 또는 df/dx로 표기합니다. 미분 계수는 다음과 같이 정의됩니다.\n",
|
|
"\n",
|
|
"f'(x) = lim(h→0) [(f(x + h) - f(x)) / h]\n",
|
|
"\n",
|
|
"여기서 h는 아주 작은 양수 값입니다.\n",
|
|
"3. 미분 계수 계산: 미분 계수를 구하기 위해 위 식에 함수 f(x)를 대입하고, h가 0에 가까워질 때의 극한 값을 계산합니다. 위의 예시에서 f(x) = x^2 + 3x + 1이므로, 미분 계수를 구하는 과정은 다음과 같습니다.\n",
|
|
"\n",
|
|
"f'(x) = lim(h→0) [((x + h)^2 + 3(x + h) + 1 - (x^2 + 3x + 1)) / h]\n",
|
|
"= lim(h→0) [(x^2 + 2xh + h^2 + 3x + 3h + 1 - x^2 - 3x - 1) / h]\n",
|
|
"= lim(h→0) [(2xh + h^2 + 3h) / h]\n",
|
|
"= lim(h→0) [2x + h + 3]\n",
|
|
"\n",
|
|
"h가 0에 가까워지면, h^2와 h 항은 무시할 수 있으므로, 미분 계수는 다음과 같이 구해집니다.\n",
|
|
"\n",
|
|
"f'(x) = 2x + 3\n",
|
|
"4. 해석: 미분 계수 f'(x) = 2x + 3은 함수 f(x) = x^2 + 3x + 1의 변화율을 나타냅니다. 이를 통해 함수의 그래프에서 특정 지점에서의 접선의 기울기를 알 수 있습니다. 예를 들어, x = 1일 때의 미분 계수는 f'(1) = 2(1) + 3 = 5이므로, 그 지점에서의 접선의 기울기는 5입니다.\n",
|
|
"\n",
|
|
"이와 같이 미분은 함수의 변화율을 계산하는 과정으로, 함수의 그래프에서 접선의 기울기를 구하는 것이 주요 목적입니다. 미분을 통해 함수의 특성을 분석하고, 최적화 문제를 해결하는 데 활용할 수 있습니다.\n",
|
|
"미적분 코드를 구현하려면, 파이썬의 `sympy` 라이브러리를 사용할 수 있습니다. 이 라이브러리는 기호 수학을 다루는 데 사용되며, 미적분 계산에도 적합합니다. 아래는 파이썬 코드와 주석을 함께 제공한 미적분 코드 구현 예시입니다.\n",
|
|
"```python\n",
|
|
"# 필요한 라이브러리를 임포트합니다.\n",
|
|
"import sympy as sp\n",
|
|
"\n",
|
|
"# 기호 변수를 정의합니다.\n",
|
|
"x = sp.symbols('x')\n",
|
|
"\n",
|
|
"# 함수를 정의합니다.\n",
|
|
"f = x**3 + 2*x**2 - 5*x + 1\n",
|
|
"\n",
|
|
"# 함수의 도함수를 계산합니다.\n",
|
|
"f_prime = sp.diff(f, x)\n",
|
|
"\n",
|
|
"# 함수의 적분을 계산합니다.\n",
|
|
"f_integral = sp.integrate(f, x)\n",
|
|
"\n",
|
|
"# 결과를 출력합니다.\n",
|
|
"print(\"함수:\", f)\n",
|
|
"print(\"도함수:\", f_prime)\n",
|
|
"print(\"적분:\", f_integral)\n",
|
|
"```\n",
|
|
"위 코드에서는 다음과 같은 작업을 수행합니다.\n",
|
|
"\n",
|
|
"1. `sympy` 라이브러리를 임포트합니다.\n",
|
|
"2. 기호 변수 `x`를 정의합니다.\n",
|
|
"3. 함수 `f`를 정의합니다. 이 예시에서는 `f(x) = x^3 + 2x^2 - 5x + 1`입니다.\n",
|
|
"4. `sp.diff()` 함수를 사용하여 함수 `f`의 도함수 `f_prime`를 계산합니다.\n",
|
|
"5. `sp.integrate()` 함수를 사용하여 함수 `f`의 적분 `f_integral`을 계산합니다.\n",
|
|
"6. 결과를 출력합니다.\n",
|
|
"\n",
|
|
"이 코드를 실행하면 다음과 같은 결과가 출력됩니다.\n",
|
|
"```yaml\n",
|
|
"함수: x**3 + 2*x**2 - 5*x + 1\n",
|
|
"도함수: 3*x**2 + 4*x - 5\n",
|
|
"적분: x**4/4 + 2*x**3/3 - 5*x**2/2 + x\n",
|
|
"```\n",
|
|
"이 예시는 파이썬과 `sympy` 라이브러리를 사용하여 미적분 계산을 수행하는 기본적인 방법을 보여줍니다. 실제로는 더 복잡한 함수와 계산을 다루어야 할 수도 있습니다.\n",
|
|
"김치찌개 레시피를 알려드리겠습니다. 기본적인 재료와 조리법을 소개하겠습니다.\n",
|
|
"\n",
|
|
"재료:\n",
|
|
"\n",
|
|
"* 김치 2컵\n",
|
|
"* 돼지고기 목살 200g (선택 사항)\n",
|
|
"* 두부 1/2모\n",
|
|
"* 양파 1/2개\n",
|
|
"* 대파 1대\n",
|
|
"* 마늘 3쪽\n",
|
|
"* 고추장 1큰술\n",
|
|
"* 고춧가루 1큰술 (선택 사항)\n",
|
|
"* 물 2컵\n",
|
|
"* 참기름 1큰술\n",
|
|
"* 소금 약간\n",
|
|
"* 찹쌀가루 또는 전분 1큰술 (선택 사항)\n",
|
|
"\n",
|
|
"조리법:\n",
|
|
"\n",
|
|
"1. 돼지고기를 적당한 크기로 썰어 물에 헹궈 놓습니다. (선택 사항)\n",
|
|
"2. 양파와 대파를 적당한 크기로 썰어 놓습니다.\n",
|
|
"3. 마늘을 다져 놓습니다.\n",
|
|
"4. 냄비에 물을 넣고 끓입니다.\n",
|
|
"5. 끓는 물에 김치를 넣고 함께 끓입니다.\n",
|
|
"6. 김치가 물에 잘 녹아들면 돼지고기를 넣고 익을 때까지 끓입니다. (선택 사항)\n",
|
|
"7. 두부를 넣고 끓입니다.\n",
|
|
"8. 고추장, 고춧가루, 참기름, 소금을 넣고 간을 맞춥니다.\n",
|
|
"9. 양파와 대파를 넣고 함께 끓입니다.\n",
|
|
"10. 마늘을 넣고 5분 정도 더 끓입니다.\n",
|
|
"11. (선택 사항) 찹쌀가루 또는 전분을 물에 타서 김치찌개에 넣고 끓여 끈적한 진하게 만듭니다.\n",
|
|
"12. 김치찌개가 완성되면 불을 끄고 대파를 다시 썰어 장식합니다.\n",
|
|
"\n",
|
|
"이제 김치찌개가 완성되었습니다. 밥과 함께 드시면 맛있습니다. 맛있게 드세요!\n",
|
|
"안녕하세요! 어떻게 도와드릴까요?\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 14
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"### SequentialChain(단계별 순차 파이프라인)\n",
|
|
"\n",
|
|
"- 앞 단계 출력이 뒷단계의 입력으로 흘러 들어감\n",
|
|
"- | => SequentialChain\n",
|
|
"- .assign() : 중간 결과를 보존하여 여러 단계를 누적할 수 있음\n",
|
|
"- 각 단계의 출력 타입과 입력 타입이 일치해야 함"
|
|
],
|
|
"id": "ec0ad7ad57ee2a01"
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:10:04.773900667Z",
|
|
"start_time": "2026-06-08T01:10:01.609764299Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"# 체인 정의\n",
|
|
"translate_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 텍스트를 한국어로 번역하세요. 번역문만 출력:\\n{text}.\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"summarize_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 텍스트를 3문장으로 번역하세요.:\\n{text}.\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"sentiment_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 텍스트를 의 감정을 긍정/부정/중립 중 하나로만 답하세요.:\\n{summary}.\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"report_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"아래 분석 결과를 바탕으로 한 줄 최종 보고서를 작성하세요.:\\n\"\n",
|
|
" \"원문 : {text}\\n번역 : {translated}\\n요약 : {summary}\\n감정 : {sentiment}\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"# 원문 => 번역 => 요약 => 감정 => 보고서\n",
|
|
"# assign() : 단계별 결과 누적\n",
|
|
"# translate_chain | sentiment_chain | report_chain\n",
|
|
"pipeline = (RunnablePassthrough\n",
|
|
" .assign(translated = translate_chain)\n",
|
|
" .assign(summary = summarize_chain)\n",
|
|
" .assign(sentiment = sentiment_chain)\n",
|
|
" .assign(report = report_chain)\n",
|
|
" )\n",
|
|
"\n",
|
|
"result = pipeline.invoke({\"text\":\"Python is a versatile language loved by developers worldwide.\"})\n",
|
|
"\n",
|
|
"print(\"번역 :\", result['translated'])\n",
|
|
"print(\"요약 :\", result['summary'])\n",
|
|
"print(\"감정 :\", result['sentiment'])\n",
|
|
"print(\"보고서 :\", result['report'])\n"
|
|
],
|
|
"id": "f487a481ff7683bd",
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"번역 : 파이썬은 개발자들에게 사랑받는 다용도의 언어입니다.\n",
|
|
"요약 : 파이썬은 개발자들에게 사랑받는 다용도의 언어입니다.\n",
|
|
"감정 : 긍정\n",
|
|
"보고서 : 파이썬은 개발자들에게 사랑받는 다용도의 언어입니다.\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 15
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:10:21.181364706Z",
|
|
"start_time": "2026-06-08T01:10:04.790041636Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"# 조건무 단계 삽입\n",
|
|
"\n",
|
|
"detect_lang_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 텍스트 언어 korea/english/other 중 하나로만 답하세요: \\n{text}\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"def maybe_translate(inputs):\n",
|
|
" lang = detect_lang_chain.invoke(inputs).strip().lower()\n",
|
|
"\n",
|
|
" if 'english' in lang or 'other' in lang:\n",
|
|
" translated = translate_chain.invoke(inputs)\n",
|
|
" return {**inputs, 'text':translated, 'was_translated' : True}\n",
|
|
" return {**inputs, 'was_translated' : False}\n",
|
|
"\n",
|
|
"# smart_pipeline = RunnableLambda(maybe_translate) | RunnablePassthrough.assign(summary = summarize_chain) | RunnablePassthrough.assign(sentiment = sentiment_chain) | RunnablePassthrough(report = report_chain)\n",
|
|
"smart_pipeline = RunnableLambda(maybe_translate) | RunnablePassthrough.assign(summary = summarize_chain) | RunnablePassthrough.assign(sentiment = sentiment_chain)\n",
|
|
"\n",
|
|
"r1 = smart_pipeline.invoke({'text' : 'Python is grate!'})\n",
|
|
"r2 = smart_pipeline.invoke({'text' : '파이썬은 최고야'})\n",
|
|
"\n",
|
|
"print(r1['was_translated'], r1['summary'][:50])\n",
|
|
"print(r2['was_translated'], r2['summary'][:50])"
|
|
],
|
|
"id": "9270dcb00e6daa5f",
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"True Here is the translation in 3 sentences:\n",
|
|
"\n",
|
|
"파이썬은 정말 대\n",
|
|
"False Here is the translation in 3 sentences:\n",
|
|
"\n",
|
|
"파이썬은 최고야.\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 16
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"### MapReduceChain(대용량 문서 처리)\n",
|
|
"- Map : 문서를 청크로 나눠 각각 처리(요약, 추출..) => 병렬 실행 가능\n",
|
|
"- Reduce : Map 결과들을 하나로 합쳐 최종 답변 생성"
|
|
],
|
|
"id": "2d31dbaf7136c98c"
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:10:42.023077203Z",
|
|
"start_time": "2026-06-08T01:10:21.201615707Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"from langchain_community.document_loaders import PyPDFLoader\n",
|
|
"from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
|
|
"\n",
|
|
"map_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 텍스트를 2문장으로 요약하세요.\"),\n",
|
|
" (\"user\", \"{chunk}\")\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"reduce_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음은 긴 문서의 섹션별 요약입니다. 전체를 5문장으로 통합 요약하세요.\"),\n",
|
|
" (\"user\", \"{summaries}\")\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"def map_reduce_summarize(file_path):\n",
|
|
" loader = PyPDFLoader(file_path)\n",
|
|
" splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)\n",
|
|
" chunks = splitter.split_documents(loader.load())\n",
|
|
" print(f\"총 청크 수 {len(chunks)}\")\n",
|
|
"\n",
|
|
" #---- Map : 청크별 요약\n",
|
|
" chunk_inputs = [{'chunk':c.page_content} for c in chunks]\n",
|
|
" summaries = map_chain.batch(chunk_inputs, config={'max_concurrency': 5})\n",
|
|
" print(f\"총 정크 수 {len(summaries)} 개 요약 생성\")\n",
|
|
"\n",
|
|
" #---- Reduce : 요약 통합\n",
|
|
" # 문서 결합\n",
|
|
" combined = \"\\n\\n\".join(f\"[섹션 {i+1}] {s}\" for i, s in enumerate(summaries))\n",
|
|
" final = reduce_chain.invoke({'summaries' : combined})\n",
|
|
" return final\n",
|
|
"\n",
|
|
"result = map_reduce_summarize('./data/직무기술서/2026 상 삼성E&A 직무기술서.pdf')\n",
|
|
"print(result)"
|
|
],
|
|
"id": "239a2e466b376541",
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"총 청크 수 41\n",
|
|
"총 정크 수 41 개 요약 생성\n",
|
|
"삼성E&A는 2026년 대학생 인턴 모집에서 기술직(설계/조달)과 기술직(사업관리/시공관리/품질) 두 가지 직군을 운영하며, 주요 전공 분야로는 화학/화공, 기계, 재료/금속, 전기전자(HW), 토목, 건축을 포함합니다. 기술직(설계/조달)은 프로젝트의 최적화 설계와 기자재 구매, 공정 관리 등을 담당하고, 기술직(사업관리/시공관리/품질)은 프로젝트 종료 단계의 수행 관리와 품질 보증/관리를 수행합니다. 삼성E&A는 석유화학, 산업·환경, 바이오 의약품, 재생에너지와 수전해 기술 등 다양한 사업 분야에서 글로벌 수준의 엔지니어링 솔루션을 제공하며, 안전보건, 경영지원, 인사관리 등 다양한 분야에서도 전문적인 역할을 수행합니다.\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 17
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T01:39:06.093531606Z",
|
|
"start_time": "2026-06-08T01:38:16.022293710Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"# map_reduce + QA\n",
|
|
"\n",
|
|
"parser = StrOutputParser()\n",
|
|
"\n",
|
|
"# 질문과 관련된 정보 추출\n",
|
|
"extract_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 텍스트에서 질문과 관련된 정보만 추출하세요. 없으면 '없음'으로 답하세요\"),\n",
|
|
" (\"user\", \"질문 : {question}\\n\\n텍스트:\\n{chunk}\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"answer_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 추출된 정보를 바탕으로 질문에 답하세요.\"),\n",
|
|
" (\"user\", \"질문 : {question}\\n\\n추출 정보:\\n{extracts}\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"chunks = None\n",
|
|
"\n",
|
|
"def extract_chunks(file_path):\n",
|
|
" global chunks\n",
|
|
"\n",
|
|
" loader = PyPDFLoader(file_path)\n",
|
|
" splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)\n",
|
|
" chunks = splitter.split_documents(loader.load())\n",
|
|
" print(f\"총 청크 수 {len(chunks)}\")\n",
|
|
"\n",
|
|
"def map_reduce_qa(chunks, question):\n",
|
|
" # Map\n",
|
|
" inputs = [{'question':question, 'chunk':c.page_content} for c in chunks]\n",
|
|
" extracts = extract_chain.batch(inputs, config={\"max_concurrency\":5})\n",
|
|
"\n",
|
|
" # '없음' 으로 넘어온 청크 필터링\n",
|
|
" relevant = [e for e in extracts if '없음' not in e]\n",
|
|
" print(f\"관련 청크 : {len(relevant)} / {len(chunks)}\")\n",
|
|
"\n",
|
|
" # Reduce\n",
|
|
" combined = \"\\n\\n\".join(relevant)\n",
|
|
" return answer_chain.invoke({'question': question, 'extracts': combined})\n",
|
|
"\n",
|
|
"extract_chunks('./data/직무기술서/2026 상 삼성E&A 직무기술서.pdf')\n",
|
|
"result = map_reduce_qa(chunks, '삼성 E&A Career Visition은 뭐야?')\n",
|
|
"print(result)"
|
|
],
|
|
"id": "1ff7884243daec14",
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"총 청크 수 41\n",
|
|
"관련 청크 : 18 / 41\n",
|
|
"삼성 E&A Career Visition은 다양한 분야에서 전문가로 성장할 수 있는 기회를 제공하는 프로그램입니다. 이 프로그램은 기술직으로 설계, 조달, 사업관리, 시공관리, 품질 분야 등 다양한 분야를 포함하고 있으며, 주요 전공으로는 화학/화공, 기계, 재료/금속, 전기전자(HW), 토목, 건축 등이 있습니다. 각 분야에서는 다음과 같은 역할과 성장 기회를 제공합니다:\n",
|
|
"\n",
|
|
"1. **설계 분야**: 기본설계부터 상세설계까지 프로젝트 목적과 규모, 사양에 따른 공종별 최적화 설계를 수행합니다.\n",
|
|
"2. **조달 분야**: 주요 기자재 구매, 공정관리, 검사, 물류ㆍ통관업무를 수행합니다.\n",
|
|
"3. **사업관리 분야**: 계약·설계·조달·시공 등 전 분야에 걸쳐 프로젝트의 모든 과정을 계획하고 최종 목표를 달성할 수 있도록 관리합니다.\n",
|
|
"4. **공사 분야**: 시공관리와 프로젝트 종료단계(Mechanical) 업무를 수행합니다.\n",
|
|
"\n",
|
|
"이 프로그램은 설계/공사/조달/사업 간 직무 순환을 통한 사업 관리 등 전문가로 성장할 수 있는 기회도 제공합니다. 또한, 고도의 직무 전문성을 키워 해당 분야의 기술전문가(Expert)로 성장하거나, 다양한 프로젝트 수행 경험을 축적하여 EM(Engineering Manager) 및 PM(Project Manager)으로 성장할 수 있는 경로를 제공합니다.\n",
|
|
"\n",
|
|
"각 분야의 구체적인 역할과 성장 기회는 다음과 같습니다:\n",
|
|
"\n",
|
|
"- **설계 분야**: Piping Design/Material/Stress 관련 기술 전문가, Layout 전문가, Lead Engineer 및 기술 전문가(Expert)로 성장.\n",
|
|
"- **전기 설계**: 전기설계 Lead Engineer로 성장, Plant 전기설계 전문가로 발돋움.\n",
|
|
"- **토목 분야**: 건축설계, 배관, 기계, 전기, 제어 장비를 지지하기 위한 구조물 설계 및 빌딩 설계를 수행.\n",
|
|
"- **조달 분야**: 조달, 플랜트, 기자재의 가격, 납기, 품질 등 다양한 요소를 고려하여 최적의 가격으로 구매하고, 적기에 자재를 확보, 납품하기 위한 공정관리, 검사, 운송 등의 업무를 수행.\n",
|
|
"- **품질 관리 분야**: 프로젝트 품질 관리 Specialist로 성장, 고객 및 관련 부서와 원활한 소통으로 협업 가능, 신기술과 새로운 혁신 과제를 적극적으로 개발하고 적용하고자 하는 탐구 정신을 가진 분.\n",
|
|
"- **안전보건 분야**: 안전관리와 안전보건경영시스템 구축 및 운영, 현장안전점검/HSE Audit/지도지원, 사고예방관리, 리더십 교육, 안전체험교육 및 법정교육 등 안전전보건 교육, 중장비/전기/구조 등 기술지원, 프로젝트의 사고 예방 계획 및 재발방지대책 수립/운영, 중대재해 처벌법 및 산업안전보건법 등 관련 법규에 따른 Risk 관리 및 대응체계 운영 등의 업무를 수행.\n",
|
|
"\n",
|
|
"이 프로그램은 각 분야에서 전문가로 성장할 수 있는 기회를 제공하며, 다양한 경험을 통해 사업관리 등 전문가로 성장할 수 있는 기회도 제공합니다.\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 23
|
|
},
|
|
{
|
|
"metadata": {},
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"#### ParallelChain (비동기 병렬 처리)\n",
|
|
"- RunnableParallel : 여러 체인을 동시에 실행하고 결과를 dict 결홥\n",
|
|
"- 서로 독립립적인 작업을 동시에 처리해 시간을 절약\n",
|
|
"- batch()\n",
|
|
"- 독립적인 LLM 호출이 3개였고 순차 호출이 30초가 걸렸다면 병렬 10초로 단축\n"
|
|
],
|
|
"id": "a766990e45af368d"
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T02:01:26.851581073Z",
|
|
"start_time": "2026-06-08T02:01:22.279822071Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"import time\n",
|
|
"from langchain_core.runnables import RunnableParallel\n",
|
|
"\n",
|
|
"translate_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 텍스트를 한국어로 번역하세요. 번역문만 출력:\\n{text}.\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"summarize_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"다음 텍스트를 3문장으로 번역하세요.:\\n{text}.\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"keyword_chain = ChatPromptTemplate.from_messages([\n",
|
|
" (\"system\", \"키워드 5개 추출:\\n{text}.\"),\n",
|
|
"]) | watson_llm | parser\n",
|
|
"\n",
|
|
"text = {'text' : 'Python is a versatile language used in AI and web development'}\n",
|
|
"\n",
|
|
"start = time.time()\n",
|
|
"t = translate_chain.invoke(text)\n",
|
|
"s = summarize_chain.invoke(text)\n",
|
|
"k = keyword_chain.invoke(text)\n",
|
|
"print(f\"순차 실행 시간 : {time.time() - start:.1f}초\")\n",
|
|
"\n",
|
|
"# 병렬 실행\n",
|
|
"parallel = RunnableParallel(translated = translate_chain, summary = summarize_chain, keyword = keyword_chain)\n",
|
|
"\n",
|
|
"start = time.time()\n",
|
|
"result = parallel.invoke(text)\n",
|
|
"print(f\"병렬 실행 시간 : {time.time() - start:.1f}초\")\n",
|
|
"\n",
|
|
"print(\"번역\", result['translated'][:100])\n",
|
|
"print(\"요약\", result['summary'][:100])\n",
|
|
"print(\"키워드\", result['keyword'][:100])"
|
|
],
|
|
"id": "a965d9ac34b2388d",
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"순차 실행 시간 : 2.9초\n",
|
|
"병렬 실행 시간 : 1.7초\n",
|
|
"번역 파이썬은 AI와 웹 개발에 사용되는 다용도의 언어입니다.\n",
|
|
"요약 파이썬은 AI와 웹 개발에 사용되는 다용도 언어입니다.\n",
|
|
"키워드 1. Python\n",
|
|
"2. versatile\n",
|
|
"3. language\n",
|
|
"4. AI\n",
|
|
"5. web development\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 27
|
|
},
|
|
{
|
|
"metadata": {
|
|
"ExecuteTime": {
|
|
"end_time": "2026-06-08T02:01:56.678134975Z",
|
|
"start_time": "2026-06-08T02:01:49.773633233Z"
|
|
}
|
|
},
|
|
"cell_type": "code",
|
|
"source": [
|
|
"# 병렬로 만들어진 체인을 비동기식으로 처리\n",
|
|
"\n",
|
|
"import asyncio\n",
|
|
"\n",
|
|
"async def analyze_multiple(texts):\n",
|
|
" \"\"\"\n",
|
|
" 각 문장마다 번역, 요약, 키워드 추출을 한꺼번에 실행\n",
|
|
" \"\"\"\n",
|
|
" tasks = [parallel.ainvoke({'text':t}) for t in texts]\n",
|
|
" results = await asyncio.gather(*tasks)\n",
|
|
" return results\n",
|
|
"\n",
|
|
"texts = [\n",
|
|
" 'Python is grate for data science.',\n",
|
|
" 'Javascript dominated frontend development',\n",
|
|
" 'Rust i known for memory safety'\n",
|
|
"]\n",
|
|
"\n",
|
|
"start = time.time()\n",
|
|
"result = await analyze_multiple(texts)\n",
|
|
"print(f\"비동기 병렬 {len(texts)}개 : {time.time() - start:.1f}초\")\n",
|
|
"\n",
|
|
"for i, r in enumerate(result):\n",
|
|
" print(f\"[{i+1}] 번역 : {r['translated'][:40]}....\")\n",
|
|
"\n",
|
|
"result = summarize_chain.batch([{'text':t} for t in texts * 3], config={'max_concurrency': 3})"
|
|
],
|
|
"id": "d0a16cd661d47ea5",
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"비동기 병렬 3개 : 1.9초\n",
|
|
"[1] 번역 : 파이썬은 데이터 사이언스에 훌륭합니다.....\n",
|
|
"[2] 번역 : 자바스크립트가 프론트엔드 개발을 지배했습니다.....\n",
|
|
"[3] 번역 : 러스트는 메모리 안전성으로 유명합니다.....\n"
|
|
]
|
|
}
|
|
],
|
|
"execution_count": 28
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 2
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython2",
|
|
"version": "2.7.6"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|