랭체인 체인 마무리

- 병렬 처리, 비동기 병렬 처리
랭그래프
- 워크플로 프리임워크 state, Node, Edge 구조
- 조건부 엣지, 루프, 자가 검토
This commit is contained in:
2026-06-08 20:10:28 +09:00
parent 30a049c5e1
commit 13b756911f
8 changed files with 1546 additions and 108 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
<excludeFolder url="file://$MODULE_DIR$/.venv" /> <excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/ollama/.venv" /> <excludeFolder url="file://$MODULE_DIR$/ollama/.venv" />
</content> </content>
<orderEntry type="jdk" jdkName="~/Source/.venv" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.12 (Source)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings"> <component name="PyDocumentationSettings">
Binary file not shown.
+350 -107
View File
@@ -6,13 +6,14 @@
"metadata": { "metadata": {
"collapsed": true, "collapsed": true,
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T06:07:18.527729458Z", "end_time": "2026-06-08T01:08:35.194596809Z",
"start_time": "2026-06-05T06:07:18.518264605Z" "start_time": "2026-06-08T01:08:35.179927221Z"
} }
}, },
"source": [ "source": [
"import os\n", "import os\n",
"\n", "\n",
"from cohere.types import summarize_request_extractiveness\n",
"from google.protobuf.timestamp import from_current_time\n", "from google.protobuf.timestamp import from_current_time\n",
"from langchain_classic.chains.sequential import SequentialChain\n", "from langchain_classic.chains.sequential import SequentialChain\n",
"from langchain_openai import ChatOpenAI\n", "from langchain_openai import ChatOpenAI\n",
@@ -31,16 +32,18 @@
"from langchain_core.prompts import PromptTemplate, ChatPromptTemplate, MessagesPlaceholder\n", "from langchain_core.prompts import PromptTemplate, ChatPromptTemplate, MessagesPlaceholder\n",
"from langchain_core.output_parsers import StrOutputParser, JsonOutputParser, PydanticOutputParser\n", "from langchain_core.output_parsers import StrOutputParser, JsonOutputParser, PydanticOutputParser\n",
"from langchain_core.runnables import RunnablePassthrough, RunnableParallel, RunnableLambda\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" "from sklearn import pipeline"
], ],
"outputs": [], "outputs": [],
"execution_count": 6 "execution_count": 8
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T06:07:18.540816647Z", "end_time": "2026-06-08T01:08:35.209192873Z",
"start_time": "2026-06-05T06:07:18.529482429Z" "start_time": "2026-06-08T01:08:35.196033782Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -59,13 +62,13 @@
], ],
"id": "c2c64c7967231118", "id": "c2c64c7967231118",
"outputs": [], "outputs": [],
"execution_count": 7 "execution_count": 9
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T06:07:22.476243454Z", "end_time": "2026-06-08T01:08:38.814068577Z",
"start_time": "2026-06-05T06:07:18.541903550Z" "start_time": "2026-06-08T01:08:35.210314784Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -104,13 +107,13 @@
], ],
"id": "560df17d1a798650", "id": "560df17d1a798650",
"outputs": [], "outputs": [],
"execution_count": 8 "execution_count": 10
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T06:07:22.498652432Z", "end_time": "2026-06-08T01:08:38.836015704Z",
"start_time": "2026-06-05T06:07:22.487631249Z" "start_time": "2026-06-08T01:08:38.823821493Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -128,7 +131,7 @@
], ],
"id": "abfd826c1b3e2703", "id": "abfd826c1b3e2703",
"outputs": [], "outputs": [],
"execution_count": 9 "execution_count": 11
}, },
{ {
"metadata": {}, "metadata": {},
@@ -147,8 +150,8 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T06:46:44.553396205Z", "end_time": "2026-06-08T01:08:38.851746574Z",
"start_time": "2026-06-05T06:46:44.544122014Z" "start_time": "2026-06-08T01:08:38.839267469Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -192,13 +195,13 @@
], ],
"id": "1e18698dde2e75b5", "id": "1e18698dde2e75b5",
"outputs": [], "outputs": [],
"execution_count": 13 "execution_count": 12
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T06:53:39.704503264Z", "end_time": "2026-06-08T01:09:39.818869100Z",
"start_time": "2026-06-05T06:52:54.753636702Z" "start_time": "2026-06-08T01:08:38.852667199Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -225,23 +228,67 @@
"\n", "\n",
"a, b, c의 변을 가진 직각삼각형이 있다고 가정합니다. 삼각형 안에 변의 길이가 a, b, c인 정사각형을 그립니다. 다음은 그 증명입니다:\n", "a, b, c의 변을 가진 직각삼각형이 있다고 가정합니다. 삼각형 안에 변의 길이가 a, b, c인 정사각형을 그립니다. 다음은 그 증명입니다:\n",
"\n", "\n",
"1. 삼각형 안에 변의 길이가 a, b, c인 정사각형의 넓이는 a^2 + b^2입니다.\n", "1. 삼각형 안에 변의 길이가 a, b, c인 정사각형의 넓이는 a^2 + b^2 + 2ab입니다.\n",
"\n", "\n",
"2. 삼각형을 두 개의 작은 직각삼각형으로 나누기 위해 빗변(c)에 수직선을 그립니다.\n", "2. 삼각형의 넓이는 (1/2)ab입니다.\n",
"\n", "\n",
"3. 수직선이 전에 있었던 빗변이가 c인 두 개의 작은 직각삼각형의 넓이는 각각 (a^2)와 (b^2)입니다.\n", "3. 삼각형이가 정사각형의 넓이의 절반과 같다는 것은 다음과 같습니다:\n",
"\n", "\n",
"4. 전체 삼각형의 넓이는 작은 직각삼각형의 넓이의 합이어야 합니다. 따라서, 삼각형의 넓이는 (a^2) + (b^2)입니다.\n", "a^2 + b^2 + 2ab = (1/2)(a^2 + b^2)\n",
"\n", "\n",
"5. 삼각형이 직각삼각형이므로, 빗변의 길이는 c입니다. 따라서, 삼각형의 넓이는 (1/2)c^2입니다.\n", "4. 양변에 2를 곱하면 다음과 같습니다:\n",
"\n", "\n",
"6. 넓이가 같다는 것을 결론지을 수 있으므로, (a^2) + (b^2) = (1/2)c^2입니다.\n", "2a^2 + 2b^2 + 4ab = a^2 + b^2\n",
"\n", "\n",
"7. 양변에 2를 곱하면 a^2 + b^2 = c^2가 됩니다.\n", "5. 양변에 a^2 + b^2를 빼면 다음과 같습니다:\n",
"\n", "\n",
"8. 이것이 피타고라스의 정리입니다.\n", "a^2 + b^2 = 2ab\n",
"\n", "\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", "A: 피타고라스 정리는 직각삼각형에서 빗변의 길이의 제곱이 나머지 두 변의 길이의 제곱의 합과 같다는 정리입니다. 이 정리를 증명해 드리겠습니다.\n",
"\n", "\n",
"가정: 직각삼각형 ABC에서 각 A가...\n", "가정: 직각삼각형 ABC에서 각 A가...\n",
@@ -249,7 +296,7 @@
"Q: 오늘 저녁 메뉴 추천해줘\n", "Q: 오늘 저녁 메뉴 추천해줘\n",
" => 븐류결과 질문 유형: general\n", " => 븐류결과 질문 유형: general\n",
"\n", "\n",
"오늘 저녁 메뉴로는 간단하면서도 맛있는 \"치킨과 샐러드\"를 추천해드릴게요. 치킨은 구운 닭고기를 사용하고, 샐러드는 신선한 채소와 드레싱을 곁들여서 영양가 있고 가벼운 식사를 즐길 수 있습니다. 또한, 필요에 따라 사이드 디시로 감자 샐러드나 빵을 추가할 수도 있습니다. 이 메뉴는 준비하기도 쉽고, 가족이나 친구들과 함께 즐기기에 좋은 선택이 될 것 같아요.\n", "오늘 저녁 메뉴로는 간단하면서도 맛있는 \"치킨과 샐러드\"를 추천해드릴게요. 치킨은 구운 닭고기를 사용하고, 샐러드는 신선한 채소와 드레싱을 곁들여서 영양가 있고 가벼운 식사를 즐길 수 있습니다. 또한, 사이드로 감자튀김이나 빵을 추가하면 더욱 만족스러운 식사가 될 거예요.\n",
"A: 저녁 메뉴로는 다양한 선택지가 있습니다. 건강하고 맛있는 한국 요리를 추천해 드리겠습니다.\n", "A: 저녁 메뉴로는 다양한 선택지가 있습니다. 건강하고 맛있는 한국 요리를 추천해 드리겠습니다.\n",
"\n", "\n",
"1. 비빔밥: 밥에 다양한 채소와 고기를 넣고 고추장 소스를 섞어 먹는 한국의 대표적인...\n", "1. 비빔밥: 밥에 다양한 채소와 고기를 넣고 고추장 소스를 섞어 먹는 한국의 대표적인...\n",
@@ -277,50 +324,43 @@
"\n", "\n",
"3. 외부 루프 `for i in range(n - 1)`는 배열을 `n - 1`번 반복하며, 각 반복에서 가장 큰 원소를 배열의 끝쪽으로 이동시킵니다.\n", "3. 외부 루프 `for i in range(n - 1)`는 배열을 `n - 1`번 반복하며, 각 반복에서 가장 큰 원소를 배열의 끝쪽으로 이동시킵니다.\n",
"\n", "\n",
"4. 내부 루프 `for j in range(n - i - 1)`는 현재 루프에서 비교해야 할 인접한 원소 쌍을 탐색합니다. `n - i - 1`은 이미 정렬된 원소를 제외한 나머지 원소들을 비교하기 위해 사용됩니다.\n", "4. 내부 루프 `for j in range(n - i - 1)`는 현재 루프에서 비교해야 할 원소의 개수만큼 반복합니다. `i`가 증가함에 따라 이미 정렬된 원소의 개수만큼 내부 루프의 범위가 줄어듭니다.\n",
"\n", "\n",
"5. `if arr[j] > arr[j + 1]` 조건문은 현재 원소와 다음 원소를 비교하여, 현재 원소가 다음 원소보다 크다면 두 원소를 교환합니다. 이 과정을 통해 큰 원소가 뒤로 이동하게 됩니다.\n", "5. 내부 루프 내에서 현재 원소 `arr[j]`와 다음 원소 `arr[j + 1]`를 비교합니다. 만약 현재 원소가 다음 원소보다 크다면, 두 원소를 서로 교환합니다.\n",
"\n", "\n",
"6. 모든 루프가 완료되면 정렬된 배열을 반환합니다.\n", "6. 외부 루프가 모두 완료되면 정렬된 배열을 반환합니다.\n",
"\n", "\n",
"이 함수를 사용하는 예제는 다음과 같습니다.\n", "이 함수를 사용하는 예제는 다음과 같습니다.\n",
"\n", "\n",
"```python\n", "```python\n",
"# 예제 사용\n",
"arr = [64, 34, 25, 12, 22, 11, 90]\n", "arr = [64, 34, 25, 12, 22, 11, 90]\n",
"print(\"정렬 전:\", arr)\n",
"\n",
"sorted_arr = bubble_sort(arr)\n", "sorted_arr = bubble_sort(arr)\n",
"print(\"정렬 후:\", sorted_arr)\n", "print(sorted_arr)\n",
"```\n", "```\n",
"\n", "\n",
"출력 결과는 다음과 같습니다.\n", "출력 결과:\n",
"\n",
"```\n", "```\n",
"정렬 전: [64, 34, 25, 12, 22, 11, 90]\n", "[11, 12, 22, 25, 34, 64, 90]\n",
"정렬 후: [11, 12, 22, 25, 34, 64, 90]\n",
"```\n", "```\n",
"\n", "\n",
"버블 정렬은 간단하고 직관적인 정렬 알고리즘이지만, 시간 복잡도 o(n^2)로 비효율적인 편입니다. 대규모 데이터에 대해서는 다른 정렬 알고리즘을 고려하는 것이 좋습니다.\n", "버블 정렬은 인접한 두 원소를 비교하며 정렬하는 간단한 알고리즘입니다. 시간 복잡도 o(n^2)로, 큰 규모 데이터에는 적합하지 않습니다. 그러나 구현이 간단하고 이해하기 쉬워 교육용으로 자주 사용됩니다.\n",
"A: 물론입니다! 파이썬으로 버블 정렬을 구현해드리겠습니다. 버블 정렬은 인접한 두 원소를 비교하며 정렬하는 간단한 정렬 알고리즘입니다. 다음은 파이썬 코드입니다:\n", "A: 물론입니다! 파이썬으로 버블 정렬을 구현해드리겠습니다. 버블 정렬은 인접한 두 원소를 비교하고, 순서가 바르지 않으면 서로 교환하는 정렬 알고리즘입니다. 다음은 파이썬 코드입니다:...\n",
"```python\n",
"d...\n",
"\n", "\n",
"Q: 피타고라스 정리를 코드로 짜줘\n", "Q: 피타고라스 정리를 코드로 짜줘\n",
" => 븐류결과 피타고라스 정리를 코드로 구현하려면, 먼저 피타고라스 정리가 무엇인지 이해해야 합니다. 피타고라스 정리는 직각삼각형에서 빗변의 길이의 제곱이 나머지 두 변의 길이의 제곱의 합과 같다는 정리입니다. 수식으로 표현하면 다음과 같습니다.\n", " => 븐류결과 피타고라스 정리를 코드로 구현하려면, 먼저 피타고라스 정리가 무엇인지 이해해야 합니다. 피타고라스 정리는 직각삼각형에서 빗변의 길이의 제곱이 나머지 두 변의 길이의 제곱의 합과 같다는 정리입니다. 수식으로 표현하면 다음과 같습니다.\n",
"\n", "\n",
"```\n", "c^2 = a^2 + b^2\n",
"c² = a² + b²\n",
"```\n",
"\n", "\n",
"여기서 c는 빗변의 길이이고, a와 b는 나머지 두 변의 길이입니다.\n", "여기서 c는 빗변의 길이이고, a와 b는 나머지 두 변의 길이입니다.\n",
"\n", "\n",
"이제 이 정리를 코드로 구현해 보겠습니다. 여기서는 python을 사용하여 구현하겠습니다.\n", "이제 이 정리를 코드로 구현해 보겠습니다. 여기서는 python을 사용하겠습니다.\n",
"\n", "\n",
"```python\n", "```python\n",
"import math\n",
"\n",
"def pythagorean_theorem(a, b):\n", "def pythagorean_theorem(a, b):\n",
" c_squared = a**2 + b**2\n", " c_squared = a**2 + b**2\n",
" c = c_squared ** 0.5\n", " c = math.sqrt(c_squared)\n",
" return c\n", " return c\n",
"\n", "\n",
"# 예시 사용\n", "# 예시 사용\n",
@@ -330,16 +370,17 @@
"print(f\"빗변의 길이는: {c}\")\n", "print(f\"빗변의 길이는: {c}\")\n",
"```\n", "```\n",
"\n", "\n",
"이 코드에서는 `pythagorean_theorem`이라는 함수를 정의하고, 두 개의 인자 `a`와 `b`를 받습니다. 이 함수는 피타고라스 정리를 사용하여 빗변의 길이 `c`를 계산하고 반환합니다. 예시 사용에서 `a`와 `b`에 각각 3과 4를 할당하고, `pythagorean_theorem` 함수를 호출하여 빗변의 길이를 계산한 후 출력합니다.\n", "이 코드에서는 `pythagorean_theorem`이라는 함수를 정의하고, 두 개의 인자 `a`와 `b`를 받습니다. 이 함수는 피타고라스 정리를 사용하여 빗변의 길이 `c`를 계산하고 반환합니다. 마지막으로, 예시 사용 부분에서 `a`와 `b`의 값을 설정하고, `pythagorean_theorem` 함수를 호출하여 빗변의 길이를 계산하고 출력합니다.\n",
"A: 피타고라스 정리를 코드로 작성하려면, 파이썬을 사용하여 다음과 같이 작성할 수 있습니다.\n", "A: 피타고라스 정리는 직각삼각형에서 빗변의 길이의 제곱이 나머지 두 변의 길이의 제곱의 합과 같다는 정리입니다. 수식으로 표현하면 다음과 같습니다:\n",
"```python\n", "\n",
"def pythagorean_theorem(a, b):\n", "a^2 + b^2 = c^2\n",
" c = (...\n", "\n",
"여...\n",
"\n" "\n"
] ]
} }
], ],
"execution_count": 19 "execution_count": 13
}, },
{ {
"metadata": {}, "metadata": {},
@@ -350,8 +391,8 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T07:11:06.032073974Z", "end_time": "2026-06-08T01:10:01.596120962Z",
"start_time": "2026-06-05T07:10:36.542912312Z" "start_time": "2026-06-08T01:09:39.839322931Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -373,7 +414,7 @@
"print(branch.invoke({'topic':'math', 'question':'미분이란?'}))\n", "print(branch.invoke({'topic':'math', 'question':'미분이란?'}))\n",
"print(branch.invoke({'topic':'code', 'question':'미적분 코드 구현'}))\n", "print(branch.invoke({'topic':'code', 'question':'미적분 코드 구현'}))\n",
"print(branch.invoke({'topic':'cooking', 'question':'김치찌개 레시피?'}))\n", "print(branch.invoke({'topic':'cooking', 'question':'김치찌개 레시피?'}))\n",
"print(branch.invoke({'topic':'other', 'question':'안녕하세요?'}))\n" "print(branch.invoke({'topic':'other', 'question':'안녕하세요?'}))"
], ],
"id": "7e5d342621ece0b0", "id": "7e5d342621ece0b0",
"outputs": [ "outputs": [
@@ -385,21 +426,25 @@
"\n", "\n",
"미분의 과정을 단계별로 설명하겠습니다.\n", "미분의 과정을 단계별로 설명하겠습니다.\n",
"\n", "\n",
"1. 함수 f(x)를 주어진다고 가정합니다.\n", "1. 함수 정의: 먼저 미분하고자 하는 함수 f(x)를 정의합니다. 예를 들어, f(x) = x^2 + 3x + 1과 같은 함수를 생각해보겠습니다.\n",
"2. 미분을 구하기 위해 독립변수 x에 대한 미소변화을 나타내는 기호 'dx'를 사용합니다. 이때, 함수 값의 미소변화량을 'dy'로 나타냅니다.\n", "2. 미분 계수 정의: 미분 계수는 함수 f(x)의 변화을 나타내는 값으로, 기호로는 f'(x) 또는 df/dx로 표기합니다. 미분 계수는 다음과 같이 정의됩니다.\n",
"3. 함수 f(x)의 미분은 다음과 같이 정의됩니다: dy/dx = f'(x) = lim(h→0) (f(x+h) - f(x))/h\n",
"4. 이 식에서 lim(h→0)은 h가 0에 가까워질 때의 극한을 의미합니다. 이 극한을 구하면 함수 f(x)의 미분, 즉 도함수 f'(x)를 얻을 수 있습니다.\n",
"5. 도함수 f'(x)는 함수 f(x)의 그래프에서 접선의 기울기를 나타냅니다. 이를 통해 함수의 변화율을 파악할 수 있습니다.\n",
"\n", "\n",
"예를 들어, 함수 f(x) = x^2를 미분해보겠습니다.\n", "f'(x) = lim(h→0) [(f(x + h) - f(x)) / h]\n",
"\n", "\n",
"1. f(x) = x^2\n", "여기서 h는 아주 작은 양수 값입니다.\n",
"2. dy/dx = f'(x) = lim(h→0) (f(x+h) - f(x))/h\n", "3. 미분 계수 계산: 미분 계수를 구하기 위해 위 식에 함수 f(x)를 대입하고, h가 0에 가까워질 때의 극한 값을 계산합니다. 위의 예시에서 f(x) = x^2 + 3x + 1이므로, 미분 계수를 구하는 과정은 다음과 같습니다.\n",
"3. f(x+h) = (x+h)^2 = x^2 + 2xh + h^2\n",
"4. f'(x) = lim(h→0) ((x^2 + 2xh + h^2) - x^2)/h = lim(h→0) (2xh + h^2)/h\n",
"5. h를 제외한 항으로 나누면 f'(x) = lim(h→0) (2x + h) = 2x\n",
"\n", "\n",
"따라서, 함수 f(x) = x^2의 미분은 f'(x) = 2x입니다. 이 도함수는 함수의 그래프에서 접선의 기울기를 나타내며, 함수의 변화율을 파악하는 데 사용됩니다.\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", "미적분 코드를 구현하려면, 파이썬의 `sympy` 라이브러리를 사용할 수 있습니다. 이 라이브러리는 기호 수학을 다루는 데 사용되며, 미적분 계산에도 적합합니다. 아래는 파이썬 코드와 주석을 함께 제공한 미적분 코드 구현 예시입니다.\n",
"```python\n", "```python\n",
"# 필요한 라이브러리를 임포트합니다.\n", "# 필요한 라이브러리를 임포트합니다.\n",
@@ -409,7 +454,7 @@
"x = sp.symbols('x')\n", "x = sp.symbols('x')\n",
"\n", "\n",
"# 함수를 정의합니다.\n", "# 함수를 정의합니다.\n",
"f = x**3 - 3*x**2 + 2*x\n", "f = x**3 + 2*x**2 - 5*x + 1\n",
"\n", "\n",
"# 함수의 도함수를 계산합니다.\n", "# 함수의 도함수를 계산합니다.\n",
"f_prime = sp.diff(f, x)\n", "f_prime = sp.diff(f, x)\n",
@@ -426,54 +471,56 @@
"\n", "\n",
"1. `sympy` 라이브러리를 임포트합니다.\n", "1. `sympy` 라이브러리를 임포트합니다.\n",
"2. 기호 변수 `x`를 정의합니다.\n", "2. 기호 변수 `x`를 정의합니다.\n",
"3. 함수 `f`를 정의합니다. 이 예시에서는 `f(x) = x^3 - 3x^2 + 2x`입니다.\n", "3. 함수 `f`를 정의합니다. 이 예시에서는 `f(x) = x^3 + 2x^2 - 5x + 1`입니다.\n",
"4. `sp.diff()` 함수를 사용하여 함수 `f`의 도함수 `f_prime`를 계산합니다.\n", "4. `sp.diff()` 함수를 사용하여 함수 `f`의 도함수 `f_prime`를 계산합니다.\n",
"5. `sp.integrate()` 함수를 사용하여 함수 `f`의 적분 `f_integral`을 계산합니다.\n", "5. `sp.integrate()` 함수를 사용하여 함수 `f`의 적분 `f_integral`을 계산합니다.\n",
"6. 결과를 출력합니다.\n", "6. 결과를 출력합니다.\n",
"\n", "\n",
"이 코드를 실행하면 다음과 같은 결과가 나옵니다.\n", "이 코드를 실행하면 다음과 같은 결과가 출력됩니다.\n",
"```yaml\n", "```yaml\n",
"함수: x**3 - 3*x**2 + 2*x\n", "함수: x**3 + 2*x**2 - 5*x + 1\n",
"도함수: 3*x**2 - 6*x + 2\n", "도함수: 3*x**2 + 4*x - 5\n",
"적분: x**4/4 - x**3 + x**2\n", "적분: x**4/4 + 2*x**3/3 - 5*x**2/2 + x\n",
"```\n", "```\n",
"이 예시는 파이썬과 `sympy` 라이브러리를 사용하여 미적분 계산을 수행하는 기본적인 방법을 보여줍니다. 더 복잡한 미적분 문제를 해결하려면, `sympy` 라이브러리의 다양한 기능을 활용할 수 있습니다.\n", "이 예시는 파이썬과 `sympy` 라이브러리를 사용하여 미적분 계산을 수행하는 기본적인 방법을 보여줍니다. 실제로는 더 복잡한 함수와 계산을 다루어야 할 수 있습니다.\n",
"김치찌개 레시피를 알려드리겠습니다. 기본적인 재료와 조리법을 소개하겠습니다.\n", "김치찌개 레시피를 알려드리겠습니다. 기본적인 재료와 조리법을 소개하겠습니다.\n",
"\n", "\n",
"재료:\n", "재료:\n",
"\n", "\n",
"* 김치 2컵\n", "* 김치 2컵\n",
"* 돼지고기 목살 200g (또는 소고기 대신 사용 가능)\n", "* 돼지고기 목살 200g (선택 사항)\n",
"* 두부 1/2모\n", "* 두부 1/2모\n",
"* 양파 1개\n", "* 양파 1/2개\n",
"* 대파 1대\n", "* 대파 1대\n",
"* 마늘 3쪽\n", "* 마늘 3쪽\n",
"* 고추장 1큰술\n", "* 고추장 1큰술\n",
"* 고춧가루 1큰술 (선택 사항)\n", "* 고춧가루 1큰술 (선택 사항)\n",
"* 된장 1작은술\n",
"* 물 2컵\n", "* 물 2컵\n",
"* 참기름 약간\n", "* 참기름 1큰술\n",
"* 소금 약간\n", "* 소금 약간\n",
"* 찹쌀 (선택 사항)\n", "* 찹쌀가루 또는 전분 1큰술 (선택 사항)\n",
"\n", "\n",
"조리법:\n", "조리법:\n",
"\n", "\n",
"1. 돼지고기를 적당한 크기로 썰어 물에 헹궈 물기를 제거한 후, 소금 약간을 뿌려 두세요.\n", "1. 돼지고기를 적당한 크기로 썰어 물에 헹궈 놓습니다. (선택 사항)\n",
"2. 양파와 대파를 적당한 크기로 썰어 두세요. 마늘은 다진 후 준비합니다.\n", "2. 양파와 대파를 적당한 크기로 썰어 놓습니다.\n",
"3. 냄비에 물을 넣고 끓인 후, 고기를 넣어 익을 때까지 끓입니다.\n", "3. 마늘을 다져 놓습니다.\n",
"4. 고기가 익으면 김치를 넣고 함께 끓입니다. 김치가 익으면 두부를 넣고 끓입니다.\n", "4. 냄비에 물을 넣고 끓입니다.\n",
"5. 고추장, 고춧가루, 된장을 넣어 간을 맞춥니다. 고추가루를 넣지 않고 맵지 않은 김치찌개를 원한다면 생략할 수 있습니다.\n", "5. 끓는 물에 김치를 넣고 함께 끓입니다.\n",
"6. 양파, 대파, 마늘을 넣고 끓여줍니다. 소금으로 간을 맞춥니다.\n", "6. 김치가 물에 잘 녹아들면 돼지고기를 넣고 익을 때까지 끓입니다. (선택 사항)\n",
"7. 끓는 김치찌개에 참기름을 넣어 향을 더해줍니다.\n", "7. 두부를 넣고 끓입니다.\n",
"8. 찹쌀떡을 넣고 싶다면 이 단계에서 넣어 끓여주세요.\n", "8. 고추장, 고춧가루, 참기름, 소금을 넣고 간을 맞춥니다.\n",
"9. 김치찌개가 끓으면 불을 끄고 대파를 다시 잘게 썰어 뿌려 준비가 완료됩니다.\n", "9. 양파와 대파를 넣고 함께 끓입니다.\n",
"10. 마늘을 넣고 5분 정도 더 끓입니다.\n",
"11. (선택 사항) 찹쌀가루 또는 전분을 물에 타서 김치찌개에 넣고 끓여 끈적한 진하게 만듭니다.\n",
"12. 김치찌개가 완성되면 불을 끄고 대파를 다시 썰어 장식합니다.\n",
"\n", "\n",
"이제 맛있는 김치찌개가 완성되었습니다. 밥과 함께 드시면 더욱 맛있습니다. 맛있게 드세요!\n", "이제 김치찌개가 완성되었습니다. 밥과 함께 드시면 맛있습니다. 맛있게 드세요!\n",
"안녕하세요! 어떻게 도와드릴까요?\n" "안녕하세요! 어떻게 도와드릴까요?\n"
] ]
} }
], ],
"execution_count": 20 "execution_count": 14
}, },
{ {
"metadata": {}, "metadata": {},
@@ -491,8 +538,8 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T07:53:53.154055958Z", "end_time": "2026-06-08T01:10:04.773900667Z",
"start_time": "2026-06-05T07:53:48.801194749Z" "start_time": "2026-06-08T01:10:01.609764299Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -545,13 +592,13 @@
] ]
} }
], ],
"execution_count": 25 "execution_count": 15
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T08:09:12.487615584Z", "end_time": "2026-06-08T01:10:21.181364706Z",
"start_time": "2026-06-05T08:09:07.590760841Z" "start_time": "2026-06-08T01:10:04.790041636Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -594,7 +641,7 @@
] ]
} }
], ],
"execution_count": 35 "execution_count": 16
}, },
{ {
"metadata": {}, "metadata": {},
@@ -609,8 +656,8 @@
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T08:41:41.441802415Z", "end_time": "2026-06-08T01:10:42.023077203Z",
"start_time": "2026-06-05T08:41:21.259025964Z" "start_time": "2026-06-08T01:10:21.201615707Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
@@ -656,24 +703,220 @@
"text": [ "text": [
"총 청크 수 41\n", "총 청크 수 41\n",
"총 정크 수 41 개 요약 생성\n", "총 정크 수 41 개 요약 생성\n",
"삼성E&A는 2026년 대학생 인턴 모집에서 기술직(설계/조달)과 기술직(사업관리/시공관리/품질) 두 가지 직군을 운영하며, 주요 전공 분야로는 화학/화공, 기계, 재료/금속, 전기전자(HW), 토목, 건축을 포함다. 기술직(설계/조달)은 프로젝트의 최적화 설계와 기자재 구매, 공정 관리 등을 담당하고, 기술직(사업관리/시공관리/품질)은 프로젝트 종료 단계의 수행 관리와 품질 보증, 안전 관리를 수행다. 삼성E&A는 석유화학, 산업·환경, 바이오 의약품, 재생에너지와 수전해 기술 등 다양한 사업 분야에서 환경 기술과 지속 가능한 솔루션을 제공하며, 신입사원들은 각 분야에서 전문성을 쌓아 사업 관리, 기술 전문가, 프로젝트 관리으로 성장할 수 있는 기회를 제공한다.\n" "삼성E&A는 2026년 대학생 인턴 모집에서 기술직(설계/조달)과 기술직(사업관리/시공관리/품질) 두 가지 직군을 운영하며, 주요 전공 분야로는 화학/화공, 기계, 재료/금속, 전기전자(HW), 토목, 건축을 포함합니다. 기술직(설계/조달)은 프로젝트의 최적화 설계와 기자재 구매, 공정 관리 등을 담당하고, 기술직(사업관리/시공관리/품질)은 프로젝트 종료 단계의 수행 관리와 품질 보증/관리를 수행합니다. 삼성E&A는 석유화학, 산업·환경, 바이오 의약품, 재생에너지와 수전해 기술 등 다양한 사업 분야에서 글로벌 수준의 엔지니어링 솔루션을 제공하며, 안전보건, 경영지원, 인사관리 등 다양한 분야에서도 전문적인 역할을 수행합니다.\n"
] ]
} }
], ],
"execution_count": 44 "execution_count": 17
}, },
{ {
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2026-06-05T08:21:18.906741845Z", "end_time": "2026-06-08T01:39:06.093531606Z",
"start_time": "2026-06-05T08:21:18.888749584Z" "start_time": "2026-06-08T01:38:16.022293710Z"
} }
}, },
"cell_type": "code", "cell_type": "code",
"source": "", "source": [
"id": "a82774f4d34a1306", "# map_reduce + QA\n",
"outputs": [], "\n",
"execution_count": 41 "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": { "metadata": {
File diff suppressed because it is too large Load Diff