Add 122 Python example scripts + .env.example
Each of the 122 code slides now has a standalone .py script in examples/slide-NNN/script.py with the LLM provider pattern from bro-js/agents/teacher/assistant/src/angry_teacher/llm.py: - load_dotenv() + ChatOpenAI with base_url=https://llm.brojs.ru/v1 - OPENAI_API_KEY from .env (with safe (or '' or None) pattern) - Same comment block with alternative model/base_url choices Layout: - sec1/sec5: code extracted from slide-NN.js (addCodeBlock) - sec2/sec3/sec4: code extracted from sectionN.pptx via python-pptx (JetBrains Mono font shapes) 100 scripts contain runnable code, 22 are visual-only (dividers, intro, recap) and just print the slide title. Setup: cp .env.example .env # fill OPENAI_API_KEY (or symlink to your # teacher/assistant/.env) pip install -r requirements.txt python examples/slide-005/script.py
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 1: Untitled
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-01.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-001/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 1: Untitled')
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 2: Что такое LangChain в 2025+
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-02.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-002/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 2: Что такое LangChain в 2025+')
|
||||
@@ -0,0 +1,49 @@
|
||||
"""
|
||||
Slide 3: pip install -- и сразу в дело
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-03.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-003/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 3 ===
|
||||
# 1. Core -- обÑзаÑелÑно Ð´Ð»Ñ Ð²ÑеÑ
оÑÑалÑнÑÑ
пакеÑов
|
||||
pip install langchain
|
||||
|
||||
# 2. Provider-инÑегÑаÑии -- ÑÑавим ÑолÑко Ñе, ÑÑо нÑжнÑ
|
||||
pip install langchain-openai
|
||||
pip install langchain-anthropic
|
||||
pip install langchain-google
|
||||
|
||||
# 3. (опÑионалÑно) дополниÑелÑнÑе инÑегÑаÑии
|
||||
pip install langchain-community # ~700 community-пакеÑов
|
||||
pip install langchain-classic # legacy chains/AgentExecutor
|
||||
@@ -0,0 +1,49 @@
|
||||
"""
|
||||
Slide 4: Первый вызов модели
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-04.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-004/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 4 ===
|
||||
# Ðдин ÑнивеÑÑалÑнÑй иниÑиализаÑÐ¾Ñ Ð´Ð»Ñ Ð²ÑеÑ
пÑовайдеÑов
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
# ФоÑмаÑ: "<provider>:<model>"
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
|
||||
# invoke -> BaseMessage; нам нÑжен .content
|
||||
result = model.invoke("Say hello in one sentence")
|
||||
print(result.content)
|
||||
|
||||
# >>> "Hello! How can I help you today?"
|
||||
@@ -0,0 +1,52 @@
|
||||
"""
|
||||
Slide 5: Переключение провайдера -- одна строка
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-05.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-005/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 5 ===
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
# OpenAI
|
||||
m_openai = init_chat_model("openai:gpt-4.1-mini")
|
||||
|
||||
# Anthropic
|
||||
m_anthropic = init_chat_model("anthropic:claude-3-7-sonnet-latest")
|
||||
|
||||
# Google Vertex AI
|
||||
m_google = init_chat_model("google_vertexai:gemini-2.0-flash")
|
||||
|
||||
# ÐÑе ÑÑи -- обÑекÑÑ BaseChatModel. Ðдин и ÑÐ¾Ñ Ð¶Ðµ .invoke()
|
||||
for m in [m_openai, m_anthropic, m_google]:
|
||||
print(type(m).__name__, ":", m.invoke("ping").content[:30])
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Slide 6: Стандартизированные сообщения
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-06.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-006/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 6 ===
|
||||
from langchain.messages import (
|
||||
HumanMessage, AIMessage, SystemMessage, ToolMessage,
|
||||
)
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
|
||||
messages = [
|
||||
SystemMessage(content="You are a concise assistant."),
|
||||
HumanMessage(content="What is LCEL?"),
|
||||
AIMessage(content="LCEL = pipe-based composition in LangChain."),
|
||||
HumanMessage(content="Show a one-line example."),
|
||||
]
|
||||
|
||||
response = model.invoke(messages)
|
||||
print(response.content)
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Slide 7: Потоковый вывод -- token за токеном
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-07.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-007/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 7 ===
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
|
||||
# .stream() -> иÑеÑаÑÐ¾Ñ Ð¿Ð¾ AIMessageChunk
|
||||
for chunk in model.stream("Write a haiku about Python"):
|
||||
# У каждого chunk-а еÑÑÑ .content (ÑекÑÑ) и .response_metadata
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
print() # пеÑевод ÑÑÑоки поÑле поÑока
|
||||
|
||||
# Async-ваÑианÑ: model.astream() -- Ñо же Ñамое в async-конÑекÑÑе
|
||||
import asyncio
|
||||
|
||||
async def main():
|
||||
async for chunk in model.astream("Write a haiku about async"):
|
||||
print(chunk.content, end="", flush=True)
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Slide 8: ChatPromptTemplate -- декларативно
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-08.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-008/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 8 ===
|
||||
from langchain_core.prompts import ChatPromptTemplate
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
prompt = ChatPromptTemplate.from_messages([
|
||||
("system", "Translate the following text to {language}."),
|
||||
("human", "{text}"),
|
||||
])
|
||||
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
|
||||
# .invoke() пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ dict и подÑÑавлÑÐµÑ Ð¿ÐµÑеменнÑе
|
||||
messages = prompt.invoke({"language": "French", "text": "Hello world"})
|
||||
print(messages.to_messages())
|
||||
|
||||
# -> [SystemMessage(...), HumanMessage(...)] -- гоÑов к model.invoke()
|
||||
@@ -0,0 +1,62 @@
|
||||
"""
|
||||
Slide 9: MessagesPlaceholder + few-shot
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-09.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-009/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 9 ===
|
||||
from langchain_core.prompts import (
|
||||
ChatPromptTemplate, MessagesPlaceholder, FewShotChatMessagePromptTemplate,
|
||||
)
|
||||
|
||||
# Few-shot блок: пÑимеÑÑ "вопÑÐ¾Ñ -> оÑвеÑ"
|
||||
examples = [
|
||||
{"input": "2+2", "output": "4"},
|
||||
{"input": "3*3", "output": "9"},
|
||||
]
|
||||
example_prompt = ChatPromptTemplate.from_messages([
|
||||
("human", "{input}"),
|
||||
("ai", "{output}"),
|
||||
])
|
||||
few_shot = FewShotChatMessagePromptTemplate(
|
||||
example_prompt=example_prompt, examples=examples,
|
||||
)
|
||||
|
||||
# СбоÑка: system + few-shot + иÑÑоÑÐ¸Ñ + ÑекÑÑий вопÑоÑ
|
||||
prompt = ChatPromptTemplate.from_messages([
|
||||
("system", "You are a math assistant."),
|
||||
few_shot,
|
||||
MessagesPlaceholder("history"),
|
||||
("human", "{question}"),
|
||||
])
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Slide 10: StrOutputParser -- самый частый
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-10.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-010/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 10 ===
|
||||
from langchain_core.prompts import ChatPromptTemplate
|
||||
from langchain_core.output_parsers import StrOutputParser
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
prompt = ChatPromptTemplate.from_messages([
|
||||
("system", "Translate to French."),
|
||||
("human", "{text}"),
|
||||
])
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
|
||||
# Склеиваем ÑеÑез LCEL: prompt | model | parser
|
||||
chain = prompt | model | StrOutputParser()
|
||||
|
||||
# ТепеÑÑ Ð½Ð° вÑÑ
оде str, а не AIMessage
|
||||
result = chain.invoke({"text": "Hello world"})
|
||||
print(type(result).__name__, "->", result)
|
||||
# >>> str -> "Bonjour le monde"
|
||||
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
Slide 11: PydanticOutputParser -- типизированный выход
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-11.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-011/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 11 ===
|
||||
from pydantic import BaseModel, Field
|
||||
from langchain_core.prompts import ChatPromptTemplate
|
||||
from langchain_core.output_parsers import PydanticOutputParser
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
class MovieReview(BaseModel):
|
||||
title: str = Field(description="Movie title")
|
||||
rating: int = Field(description="Rating from 1 to 10")
|
||||
summary: str = Field(description="One-sentence summary")
|
||||
|
||||
parser = PydanticOutputParser(pydantic_object=MovieReview)
|
||||
|
||||
prompt = ChatPromptTemplate.from_messages([
|
||||
("system", "Extract review fields.\n{format_instructions}"),
|
||||
("human", "{review_text}"),
|
||||
]).partial(format_instructions=parser.get_format_instructions())
|
||||
|
||||
chain = prompt | init_chat_model("openai:gpt-4.1-mini") | parser
|
||||
review = chain.invoke({"review_text": "Inception was brilliant. 9/10."})
|
||||
print(review.title, review.rating, review.summary)
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Slide 12: with_structured_output -- рекомендованный путь
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-12.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-012/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 12 ===
|
||||
from pydantic import BaseModel, Field
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
class Weather(BaseModel):
|
||||
city: str = Field(description="City name")
|
||||
temperature_c: float = Field(description="Temperature in Celsius")
|
||||
conditions: str = Field(description="Weather summary")
|
||||
|
||||
# Ðдин вÑзов -- и Ð¼Ð¾Ð´ÐµÐ»Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ ÑипизиÑованнÑй Pydantic-обÑекÑ
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
structured = model.with_structured_output(Weather)
|
||||
|
||||
result: Weather = structured.invoke("Weather in Paris?")
|
||||
print(result.city, result.temperature_c, result.conditions)
|
||||
|
||||
# method="json_mode" -- еÑли пÑÐ¾Ð²Ð°Ð¹Ð´ÐµÑ Ð½Ðµ поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ tool calling
|
||||
# structured_json = model.with_structured_output(Weather, method="json_mode")
|
||||
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
Slide 13: | -- декларативная композиция
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-13.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-013/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 13 ===
|
||||
from langchain_core.prompts import ChatPromptTemplate
|
||||
from langchain_core.output_parsers import StrOutputParser
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
prompt = ChatPromptTemplate.from_messages([
|
||||
("system", "You are a {style} assistant."),
|
||||
("human", "{question}"),
|
||||
])
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
|
||||
# prompt, model, parser -- вÑе ÑÑи ÑеализÑÑÑ Runnable
|
||||
# ÐпеÑаÑÐ¾Ñ | ÑÐºÐ»ÐµÐ¸Ð²Ð°ÐµÑ Ð¸Ñ
в один chain
|
||||
chain = prompt | model | StrOutputParser()
|
||||
|
||||
# type(chain) -> RunnableSequence
|
||||
print(type(chain).__name__)
|
||||
|
||||
# invoke -> dict на вÑ
од, str на вÑÑ
од
|
||||
print(chain.invoke({"style": "concise", "question": "What is LCEL?"}))
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Slide 14: invoke / batch / stream -- без смены кода
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-14.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-014/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 14 ===
|
||||
chain = prompt | model | StrOutputParser()
|
||||
|
||||
# 1. invoke -- один вÑ
од, один вÑÑ
од
|
||||
out_one = chain.invoke({"language": "French", "text": "Good morning"})
|
||||
|
||||
# 2. batch -- ÑпиÑок вÑ
одов, ÑпиÑок вÑÑ
одов (паÑаллелÑно)
|
||||
out_many = chain.batch([
|
||||
{"language": "French", "text": "Good morning"},
|
||||
{"language": "German", "text": "Good morning"},
|
||||
{"language": "Spanish", "text": "Good morning"},
|
||||
])
|
||||
print(out_many) # ["Bonjour", "Guten Morgen", "Buenos dias"]
|
||||
|
||||
# 3. stream -- иÑеÑаÑÐ¾Ñ Ð¿Ð¾ Ñанкам (ÑÑÑÐ¸Ð¼Ð¸Ñ Ð¿Ð¾Ñледний Runnable)
|
||||
for chunk in chain.stream({"language": "French", "text": "Stream me"}):
|
||||
print(chunk, end="", flush=True)
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Slide 15: async + config -- полный контроль
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-15.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-015/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 15 ===
|
||||
import asyncio
|
||||
from langchain_core.runnables import ConfigurableField
|
||||
|
||||
# ÐÑбой Runnable Ð¸Ð¼ÐµÐµÑ ainvoke / astream / abatch
|
||||
async def main():
|
||||
# Ðдин async-вÑзов
|
||||
result = await chain.ainvoke({"language": "French", "text": "Hi"})
|
||||
|
||||
# Async stream
|
||||
async for chunk in chain.astream({"language": "French", "text": "Hi"}):
|
||||
print(chunk, end="", flush=True)
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
# configurable_fields -- паÑамеÑÑÑ, коÑоÑÑе можно пеÑеопÑеделÑÑÑ
|
||||
# на леÑÑ ÑеÑез config={"configurable": {...}}
|
||||
configurable_chain = init_chat_model("openai:gpt-4.1-mini",
|
||||
temperature=0.7).configurable_fields(
|
||||
temperature=ConfigurableField(id="temperature"),
|
||||
)
|
||||
# configurable_chain.invoke(messages, config={"configurable": {"temperature": 0.0}})
|
||||
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
Slide 16: RunnableLambda + RunnablePassthrough
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-16.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-016/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 16 ===
|
||||
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
|
||||
|
||||
# RunnableLambda -- обоÑаÑÐ¸Ð²Ð°ÐµÑ Ð¿ÑоизволÑнÑÑ ÑÑнкÑиÑ
|
||||
upper = RunnableLambda(lambda x: x.upper())
|
||||
word_count = RunnableLambda(lambda text: {"text": text, "words": len(text.split())})
|
||||
|
||||
# RunnablePassthrough -- пÑопÑÑÐºÐ°ÐµÑ Ð²Ñ
од далÑÑе (Ð´Ð»Ñ branching)
|
||||
passthrough = RunnablePassthrough()
|
||||
|
||||
# ÐÑимеÑ: ÑекÑÑ -> uppercase -> поÑÑиÑаÑÑ Ñлова -> ÑмÑÑджиÑÑ Ñ Ð¾Ñигиналом
|
||||
chain = (
|
||||
word_count
|
||||
| RunnablePassthrough.assign(upper=upper)
|
||||
)
|
||||
|
||||
result = chain.invoke("hello world from langchain")
|
||||
print(result)
|
||||
# {"text": "hello world from langchain",
|
||||
# "words": 4, "upper": "HELLO WORLD FROM LANGCHAIN"}
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Slide 17: Parallel + Branch -- fan-out и роутинг
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-17.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-017/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 17 ===
|
||||
from langchain_core.runnables import RunnableParallel, RunnableBranch
|
||||
|
||||
# Parallel -- один вÑ
од, неÑколÑко паÑаллелÑнÑÑ
Runnable-ов, dict на вÑÑ
оде
|
||||
joke_chain = ChatPromptTemplate.from_template("Tell a joke about {topic}") | model
|
||||
poem_chain = ChatPromptTemplate.from_template("Write a poem about {topic}") | model
|
||||
|
||||
parallel = RunnableParallel(joke=joke_chain, poem=poem_chain)
|
||||
result = parallel.invoke({"topic": "cats"})
|
||||
print(result.keys()) # dict_keys(["joke", "poem"])
|
||||
|
||||
# Branch -- if/else ÑоÑÑинг по ÑÑловиÑ
|
||||
branch = RunnableBranch(
|
||||
(lambda x: "code" in x["topic"].lower(), code_chain),
|
||||
(lambda x: "math" in x["topic"].lower(), math_chain),
|
||||
general_chain, # default
|
||||
)
|
||||
print(branch.invoke({"topic": "code review"}))
|
||||
@@ -0,0 +1,63 @@
|
||||
"""
|
||||
Slide 18: Vector store -> retriever -> RAG-цепочка
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-18.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-018/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 18 ===
|
||||
from langchain_openai import OpenAIEmbeddings
|
||||
from langchain_community.vectorstores import FAISS
|
||||
from langchain_core.runnables import RunnablePassthrough
|
||||
|
||||
# 1. Ðмбеддинги и индекÑ
|
||||
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
|
||||
docs = ["Cats are mammals.", "Python is a programming language.",
|
||||
"LangChain helps build LLM apps."]
|
||||
vectorstore = FAISS.from_texts(docs, embedding=embeddings)
|
||||
|
||||
# 2. .as_retriever() пÑевÑаÑÐ°ÐµÑ store в Runnable
|
||||
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
|
||||
|
||||
# 3. RAG-ÑепоÑка ÑеÑез LCEL: context + question -> answer
|
||||
from langchain_core.prompts import ChatPromptTemplate
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
prompt = ChatPromptTemplate.from_template(
|
||||
"Answer based on context.\nContext: {context}\nQ: {question}"
|
||||
)
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
rag = (
|
||||
{"context": retriever, "question": RunnablePassthrough()}
|
||||
| prompt | model | StrOutputParser()
|
||||
)
|
||||
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
Slide 19: @tool -- любая функция становится инструментом
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-19.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-019/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 19 ===
|
||||
from langchain.tools import tool
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
@tool
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get the current weather for a given city."""
|
||||
return f"Sunny, 22C in {city}"
|
||||
|
||||
@tool
|
||||
def search_docs(query: str, top_k: int = 3) -> list[str]:
|
||||
"""Search internal documentation. Returns top_k snippets."""
|
||||
return [f"doc about {query} #{i}" for i in range(top_k)]
|
||||
|
||||
# bind_tools -- Ð¼Ð¾Ð´ÐµÐ»Ñ Ð·Ð½Ð°ÐµÑ, какие ÑÑнкÑии можно вÑзваÑÑ
|
||||
model = init_chat_model("openai:gpt-4.1-mini")
|
||||
bound = model.bind_tools([get_weather, search_docs])
|
||||
|
||||
result = bound.invoke("What is the weather in Paris?")
|
||||
print(result.tool_calls)
|
||||
# [{"name": "get_weather", "args": {"city": "Paris"}, "id": "..."}]
|
||||
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
Slide 20: create_agent -- один вход для всех агентов
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-20.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-020/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 20 ===
|
||||
from langchain.agents import create_agent
|
||||
from langchain.tools import tool
|
||||
|
||||
@tool
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get weather for a city."""
|
||||
return f"Sunny, 22C in {city}"
|
||||
|
||||
# Ðдин вÑзов вмеÑÑо create_react_agent / create_openai_functions_agent / ...
|
||||
agent = create_agent(
|
||||
model="openai:gpt-4.1",
|
||||
tools=[get_weather],
|
||||
system_prompt="You are a weather assistant.",
|
||||
)
|
||||
|
||||
# invoke -> dict {"messages": [...]}; поÑледнее ÑообÑение = оÑвеÑ
|
||||
result = agent.invoke({"messages": [{"role": "user",
|
||||
"content": "weather in Paris?"}]})
|
||||
print(result["messages"][-1].content)
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Slide 21: Краткосрочная память: thread + checkpointer
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-21.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-021/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 21 ===
|
||||
from langchain.agents import create_agent
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
|
||||
checkpointer = InMemorySaver()
|
||||
|
||||
agent = create_agent(
|
||||
model="openai:gpt-4.1-mini",
|
||||
tools=[...],
|
||||
checkpointer=checkpointer, # <-- persistent state
|
||||
)
|
||||
|
||||
config = {"configurable": {"thread_id": "user-42"}}
|
||||
|
||||
# ÐеÑвÑй turn
|
||||
agent.invoke({"messages": [{"role": "user",
|
||||
"content": "My name is Alice."}]}, config=config)
|
||||
|
||||
# ÐÑоÑой turn -- Ð¼Ð¾Ð´ÐµÐ»Ñ Ð¿Ð¾Ð¼Ð½Ð¸Ñ Ð¸Ð¼Ñ
|
||||
result = agent.invoke({"messages": [{"role": "user",
|
||||
"content": "What is my name?"}]}, config=config)
|
||||
print(result["messages"][-1].content) # "Alice"
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Slide 22: Долгосрочная память: store + namespace
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-22.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-022/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 22 ===
|
||||
from langgraph.store.memory import InMemoryStore
|
||||
from langchain.agents import create_agent
|
||||
from langchain.embeddings import init_embeddings
|
||||
|
||||
# Store Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ in-memory (dev) или Postgres (prod)
|
||||
store = InMemoryStore(
|
||||
index={"embed": init_embeddings("openai:text-embedding-3-small"),
|
||||
"dims": 1536},
|
||||
)
|
||||
|
||||
agent = create_agent(
|
||||
model="openai:gpt-4.1-mini",
|
||||
tools=[...],
|
||||
store=store,
|
||||
)
|
||||
|
||||
# Namespace = ("user-id", "facts") -- Ñазделение по полÑзоваÑелÑм
|
||||
ns = ("user-42", "facts")
|
||||
store.put(ns, "pref-1", {"text": "User prefers concise answers."})
|
||||
|
||||
# Рновой ÑеÑÑии store.search(ns, query="preferences") веÑнÑÑ ÑакÑÑ
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Slide 23: Cross-cutting concerns одной строкой
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-23.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-023/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 23 ===
|
||||
from langchain.agents import create_agent
|
||||
from langchain.agents.middleware import (
|
||||
HumanInTheLoopMiddleware,
|
||||
PIIRedactionMiddleware,
|
||||
SummarizationMiddleware,
|
||||
)
|
||||
from langchain.tools import tool
|
||||
|
||||
@tool
|
||||
def send_email(to: str, body: str) -> str:
|
||||
"""Send an email to recipient."""
|
||||
return f"sent to {to}"
|
||||
|
||||
agent = create_agent(
|
||||
model="openai:gpt-4.1",
|
||||
tools=[send_email],
|
||||
middleware=[
|
||||
HumanInTheLoopMiddleware(interrupt_on={"send_email": True}),
|
||||
PIIRedactionMiddleware(redact_emails=True, redact_phones=True),
|
||||
SummarizationMiddleware(trigger=("tokens", 4000)),
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 24: Что нового в 1.0 vs 0.3
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-24.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-024/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 24: Что нового в 1.0 vs 0.3')
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Slide 25: JS-аналог: что есть, чего нет
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-25.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-025/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 25 ===
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
import { createAgent } from "langchain/agents";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const getWeather = tool(
|
||||
async ({ city }) => `Sunny, 22C in ${city}`,
|
||||
{ name: "get_weather", description: "Get weather",
|
||||
schema: z.object({ city: z.string() }) },
|
||||
);
|
||||
|
||||
const model = await initChatModel("openai:gpt-4.1");
|
||||
const agent = createAgent({ model, tools: [getWeather] });
|
||||
const result = await agent.invoke({
|
||||
messages: [{ role: "user", content: "weather in Paris?" }],
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 26: Когда LangChain 1.0 -- правильный выбор
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-26.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-026/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 26: Когда LangChain 1.0 -- правильный выбор')
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 27: Дальше: LangGraph -- явный control flow
|
||||
Section 1: LangChain 1.0
|
||||
Source: slides/section1-chains/slide-27.js
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-027/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 27: Дальше: LangGraph -- явный control flow')
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 28: LangGraph 1.0: stateful runtime
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-028/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 28: LangGraph 1.0: stateful runtime')
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 29: Slide 2
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-029/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 29: Slide 2')
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Slide 30: Slide 3
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-030/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 30 ===
|
||||
pip install -U langgraph
|
||||
|
||||
# extras: postgres / sqlite checkpointers -- отдельные пакеты
|
||||
pip install -U langgraph langgraph-checkpoint-postgres
|
||||
pip install -U langgraph langgraph-checkpoint-sqlite
|
||||
|
||||
# JS / TypeScript
|
||||
npm install @langchain/langgraph @langchain/langgraph-checkpoint
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Slide 31: Slide 4
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-031/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 31 ===
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
|
||||
> class State(TypedDict):
|
||||
> question: str
|
||||
> answer: str
|
||||
steps: int
|
||||
|
||||
def answer(state: State) -> dict:
|
||||
return {"answer": f"echo: {state['question']}", "steps": 1}
|
||||
|
||||
builder = StateGraph(State)
|
||||
builder.add_node("answer", answer)
|
||||
builder.add_edge(START, "answer")
|
||||
builder.add_edge("answer", END)
|
||||
graph = builder.compile()
|
||||
>
|
||||
> print(graph.invoke({"question": "hi", "steps": 0}))
|
||||
> # -> {'question': 'hi', 'answer': 'echo: hi', 'steps': 1}
|
||||
|
||||
// note: snippet has 19 lines, card fits ~17
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Slide 32: Slide 5
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-032/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 32 ===
|
||||
from typing import Annotated
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.graph.message import add_messages
|
||||
|
||||
class State(TypedDict):
|
||||
# reducer add_messages склеивает списки сообщений по правилам
|
||||
> messages: Annotated[list, add_messages]
|
||||
|
||||
def echo(state: State):
|
||||
last = state["messages"][-1]
|
||||
> return {"messages": [{"role": "assistant", "content": f"echo: {last.content}"}]}
|
||||
>
|
||||
g = StateGraph(State)
|
||||
g.add_node("echo", echo)
|
||||
g.add_edge(START, "echo")
|
||||
g.add_edge("echo", END)
|
||||
app = g.compile()
|
||||
|
||||
print(app.invoke({"messages": [{"role": "user", "content": "hi"}]}))
|
||||
|
||||
// note: snippet has 20 lines, card fits ~18
|
||||
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
Slide 33: Slide 6
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-033/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 33 ===
|
||||
import operator
|
||||
from typing import Annotated
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
|
||||
class State(TypedDict):
|
||||
# каждый узел возвращает кусок списка, operator.add склеивает
|
||||
log: Annotated[list[str], operator.add]
|
||||
> tokens: Annotated[int, operator.add]
|
||||
>
|
||||
def step(state: State):
|
||||
return {"log": ["step-1"], "tokens": 12}
|
||||
|
||||
def another(state: State):
|
||||
return {"log": ["step-2"], "tokens": 7}
|
||||
|
||||
g = StateGraph(State)
|
||||
g.add_node("a", step)
|
||||
g.add_node("b", another)
|
||||
g.add_edge(START, "a")
|
||||
g.add_edge("a", "b")
|
||||
g.add_edge("b", END)
|
||||
app = g.compile()
|
||||
print(app.invoke({"log": [], "tokens": 0}))
|
||||
# -> {'log': ['step-1', 'step-2'], 'tokens': 19}
|
||||
|
||||
// note: snippet has 25 lines, card fits ~18
|
||||
@@ -0,0 +1,61 @@
|
||||
"""
|
||||
Slide 34: Slide 7
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-034/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 34 ===
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Annotated
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.graph.message import add_messages
|
||||
|
||||
@dataclass
|
||||
class State:
|
||||
question: str = ""
|
||||
> # dataclass + Annotated -- каналы работают точно так же
|
||||
> messages: Annotated[list, add_messages] = field(default_factory=list)
|
||||
approved: bool = False
|
||||
|
||||
def greet(state: State):
|
||||
return {"messages": [{"role": "assistant", "content": f"hi, {state.question}"}]}
|
||||
|
||||
g = StateGraph(State)
|
||||
g.add_node("greet", greet)
|
||||
g.add_edge(START, "greet")
|
||||
g.add_edge("greet", END)
|
||||
app = g.compile()
|
||||
print(app.invoke(State(question="alex")))
|
||||
|
||||
// note: snippet has 21 lines, card fits ~18
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Slide 35: Slide 8
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-035/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 35 ===
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
|
||||
class State(TypedDict):
|
||||
n: int
|
||||
|
||||
def inc(state: State):
|
||||
return {"n": state["n"] + 1}
|
||||
|
||||
builder = StateGraph(State)
|
||||
builder.add_node("inc", inc) # регистрируем узел
|
||||
> builder.add_edge(START, "inc") # поток входа
|
||||
> builder.add_edge("inc", END) # поток выхода
|
||||
>
|
||||
graph = builder.compile() # компиляция -- граф готов к invoke
|
||||
|
||||
> print(graph.invoke({"n": 0})) # -> {'n': 1}
|
||||
@@ -0,0 +1,61 @@
|
||||
"""
|
||||
Slide 36: Slide 9
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-036/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 36 ===
|
||||
# START и END -- это специальные sentinel-узлы, не callable
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
>
|
||||
class State(TypedDict):
|
||||
text: str
|
||||
|
||||
def upper(state: State):
|
||||
return {"text": state["text"].upper()}
|
||||
|
||||
def exclaim(state: State):
|
||||
return {"text": state["text"] + "!"}
|
||||
|
||||
g = StateGraph(State)
|
||||
> g.add_node("upper", upper)
|
||||
g.add_node("exclaim", exclaim)
|
||||
> g.add_edge(START, "upper") # вход в граф
|
||||
> g.add_edge("upper", "exclaim") # внутреннее ребро
|
||||
g.add_edge("exclaim", END) # выход из графа
|
||||
|
||||
app = g.compile()
|
||||
print(app.invoke({"text": "hi"})) # -> {'text': 'HI!'}
|
||||
|
||||
// note: snippet has 21 lines, card fits ~18
|
||||
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
Slide 37: Slide 10
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-037/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 37 ===
|
||||
import asyncio
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
|
||||
class State(TypedDict):
|
||||
out: str
|
||||
|
||||
def sync_node(state: State): # обычная функция
|
||||
return {"out": "sync-ok"}
|
||||
|
||||
> async def async_node(state: State): # async тоже работает
|
||||
await asyncio.sleep(0)
|
||||
> return {"out": "async-ok"}
|
||||
|
||||
g = StateGraph(State)
|
||||
g.add_node("s", sync_node)
|
||||
g.add_node("a", async_node)
|
||||
g.add_edge(START, "s")
|
||||
g.add_edge("s", "a")
|
||||
g.add_edge("a", END)
|
||||
app = g.compile()
|
||||
|
||||
print(app.invoke({"out": ""}))
|
||||
print(asyncio.run(app.ainvoke({"out": ""})))
|
||||
|
||||
// note: snippet has 24 lines, card fits ~18
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Slide 38: Slide 11
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-038/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 38 ===
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.types import Command
|
||||
from typing_extensions import TypedDict
|
||||
from typing import Literal
|
||||
class State(TypedDict):
|
||||
n: int
|
||||
> def decide(state: State) -> Command[Literal["inc", "halt"]]:
|
||||
> # Command(update, goto) -- обновляет state и сам выбирает узел
|
||||
if state["n"] < 3:
|
||||
> return Command(update={"n": state["n"] + 1}, goto="inc")
|
||||
return Command(update={}, goto="halt")
|
||||
g = StateGraph(State)
|
||||
g.add_node("decide", decide)
|
||||
g.add_node("inc", inc)
|
||||
g.add_node("halt", lambda s: s)
|
||||
g.add_edge(START, "decide")
|
||||
g.add_edge("inc", "decide")
|
||||
g.add_edge("halt", END)
|
||||
app = g.compile()
|
||||
print(app.invoke({"n": 0}))
|
||||
|
||||
// note: snippet has 20 lines, card fits ~18
|
||||
@@ -0,0 +1,68 @@
|
||||
"""
|
||||
Slide 39: Slide 12
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-039/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 39 ===
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
|
||||
class State(TypedDict):
|
||||
needs_tool: bool
|
||||
answer: str
|
||||
|
||||
def agent(state: State) -> dict:
|
||||
return {"answer": "model-output"}
|
||||
|
||||
def tool_node(state: State) -> dict:
|
||||
return {"answer": "tool-output"}
|
||||
|
||||
def route(state: State) -> str:
|
||||
# возвращаем ключ, который есть в path_map ниже
|
||||
return "tool_node" if state["needs_tool"] else END
|
||||
|
||||
g = StateGraph(State)
|
||||
> g.add_node("agent", agent)
|
||||
> g.add_node("tool_node", tool_node)
|
||||
> g.add_edge(START, "agent")
|
||||
> g.add_conditional_edges("agent", route, {
|
||||
> "tool_node": "tool_node",
|
||||
END: END,
|
||||
})
|
||||
g.add_edge("tool_node", END)
|
||||
app = g.compile()
|
||||
print(app.invoke({"needs_tool": True, "answer": ""}))
|
||||
|
||||
// note: snippet has 28 lines, card fits ~18
|
||||
@@ -0,0 +1,61 @@
|
||||
"""
|
||||
Slide 40: Slide 13
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-040/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 40 ===
|
||||
# агентный цикл: agent <-> tools, выход когда done=true
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
|
||||
class State(TypedDict):
|
||||
done: bool
|
||||
iter: int
|
||||
|
||||
def agent(state: State) -> dict:
|
||||
return {"iter": state["iter"] + 1, "done": state["iter"] >= 3}
|
||||
|
||||
def maybe_continue(state: State) -> str:
|
||||
return "agent" if not state["done"] else END
|
||||
|
||||
> g = StateGraph(State)
|
||||
> g.add_node("agent", agent)
|
||||
g.add_edge(START, "agent")
|
||||
g.add_conditional_edges("agent", maybe_continue, {"agent": "agent", END: END})
|
||||
app = g.compile()
|
||||
print(app.invoke({"done": False, "iter": 0}))
|
||||
# agent крутится 3 раза, потом уходит в END
|
||||
|
||||
// note: snippet has 21 lines, card fits ~18
|
||||
@@ -0,0 +1,66 @@
|
||||
"""
|
||||
Slide 41: Slide 14
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-041/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 41 ===
|
||||
from typing import Annotated
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.graph.message import add_messages
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
|
||||
class State(TypedDict):
|
||||
messages: Annotated[list, add_messages]
|
||||
|
||||
def echo(state: State):
|
||||
last = state["messages"][-1]
|
||||
return {"messages": [{"role": "assistant", "content": f"echo: {last.content}"}]}
|
||||
|
||||
g = StateGraph(State)
|
||||
g.add_node("echo", echo)
|
||||
g.add_edge(START, "echo")
|
||||
g.add_edge("echo", END)
|
||||
|
||||
# checkpointer -- обязателен для thread persistence
|
||||
checkpointer = InMemorySaver()
|
||||
app = g.compile(checkpointer=checkpointer)
|
||||
>
|
||||
> cfg = {"configurable": {"thread_id": "user-1"}}
|
||||
app.invoke({"messages": [{"role": "user", "content": "hi"}]}, cfg)
|
||||
> app.invoke({"messages": [{"role": "user", "content": "again"}]}, cfg)
|
||||
> # второй вызов видит все сообщения первого: thread persistence работает
|
||||
|
||||
// note: snippet has 26 lines, card fits ~18
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Slide 42: Slide 15
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-042/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 42 ===
|
||||
> # SQLite -- файл на диске, идеален для dev / small-prod
|
||||
from langgraph.checkpoint.sqlite import SqliteSaver
|
||||
>
|
||||
> with SqliteSaver.from_conn_string("./checkpoints.db") as cp:
|
||||
> app = g.compile(checkpointer=cp)
|
||||
cfg = {"configurable": {"thread_id": "u1"}}
|
||||
app.invoke({"messages": []}, cfg)
|
||||
|
||||
# данные переживают рестарт процесса.
|
||||
# Для asyncio-варианта -- aiosqlite.
|
||||
|
||||
> # Postgres -- production-grade, multi-instance
|
||||
from langgraph.checkpoint.postgres import PostgresSaver
|
||||
>
|
||||
DB = "postgresql://user:pass@host:5432/lg"
|
||||
with PostgresSaver.from_conn_string(DB) as cp:
|
||||
> # первый запуск создаст schema
|
||||
cp.setup()
|
||||
app = g.compile(checkpointer=cp)
|
||||
cfg = {"configurable": {"thread_id": "u1"}}
|
||||
app.invoke({"messages": []}, cfg)
|
||||
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
Slide 43: Slide 16
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-043/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 43 ===
|
||||
# После invoke можно достать текущий snapshot:
|
||||
> snapshot = app.get_state(cfg)
|
||||
|
||||
# snapshot -- это StateSnapshot с полями:
|
||||
> # .config -- thread_id + checkpoint_id
|
||||
> # .metadata -- step, source, writes
|
||||
> # .values -- текущие значения всех каналов state
|
||||
> # .next -- tuple узлов, которые будут выполняться следующими
|
||||
> # .tasks -- PregelTask с pending/result/error
|
||||
|
||||
print(snapshot.next) # () -- граф завершён
|
||||
print(snapshot.values["messages"][-1].content)
|
||||
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
Slide 44: Slide 17
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-044/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 44 ===
|
||||
# Каждый super-step -- отдельный checkpoint в thread
|
||||
> history = list(app.get_state_history(cfg))
|
||||
>
|
||||
> # history[0] -- последний шаг (самый свежий)
|
||||
# history[-1] -- самый первый (начало сессии)
|
||||
|
||||
> for i, snap in enumerate(history):
|
||||
print(i, snap.metadata.get("step"), snap.values.get("iter"))
|
||||
|
||||
> # replays = форк от любого прошлого snapshot:
|
||||
> old = history[2].config
|
||||
app.invoke(None, old) # переигрывает только следующие шаги
|
||||
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
Slide 45: Slide 18
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-045/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 45 ===
|
||||
# patch значения канала прямо в snapshot -- создаётся новый checkpoint
|
||||
> app.update_state(
|
||||
> cfg,
|
||||
> values={"messages": [{"role": "user", "content": "rewind"}]},
|
||||
> as_node="user_input", # от имени какого узла пишем
|
||||
)
|
||||
|
||||
# Дальше invoke(None, cfg) переигрывает граф с нового состояния
|
||||
app.invoke(None, cfg)
|
||||
>
|
||||
> # Типичный приём: "что если пользователь сказал не X, а Y?" --
|
||||
# ответвляемся, смотрим альтернативный прогон без потери истории.
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Slide 46: Slide 19
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-046/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 46 ===
|
||||
from langgraph.types import interrupt, Command
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
from typing_extensions import TypedDict
|
||||
class State(TypedDict):
|
||||
question: str
|
||||
approved: bool
|
||||
def ask(state: State):
|
||||
# interrupt() -- пауза. Возвращает значение из Command(resume=...)
|
||||
> answer = interrupt({"question": "Approve sending this message?"})
|
||||
return {"approved": answer == "yes"}
|
||||
g = StateGraph(State)
|
||||
g.add_node("ask", ask)
|
||||
g.add_edge(START, "ask")
|
||||
g.add_edge("ask", END)
|
||||
app = g.compile(checkpointer=InMemorySaver())
|
||||
> cfg = {"configurable": {"thread_id": "approval-1"}}
|
||||
> app.invoke({"question": "send email", "approved": False}, cfg) # пауза
|
||||
> result = app.invoke(Command(resume="yes"), cfg) # resume
|
||||
print(result["approved"]) # -> True
|
||||
|
||||
// note: snippet has 20 lines, card fits ~18
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 47: Slide 20
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-047/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 47: Slide 20')
|
||||
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Slide 48: Slide 21
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-048/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 48 ===
|
||||
# Узел review -- маршрутизация по ответу человека
|
||||
from langgraph.types import interrupt, Command
|
||||
from typing_extensions import TypedDict
|
||||
class State(TypedDict):
|
||||
plan: str
|
||||
executed: bool
|
||||
def plan(state: State):
|
||||
return {"plan": "step-A; step-B; step-C"}
|
||||
> def review(state: State) -> Command:
|
||||
> # interrupt() возвращает ответ из Command(resume=...)
|
||||
> decision = interrupt({"plan": state["plan"]})
|
||||
> if decision == "approve":
|
||||
> return Command(goto="execute")
|
||||
> if decision == "abort":
|
||||
> return Command(goto=END)
|
||||
return Command(goto="plan") # перепланировать
|
||||
def execute(state: State):
|
||||
return {"executed": True}
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Slide 49: Slide 22
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-049/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 49 ===
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
# plan, review, execute -- из предыдущего слайда
|
||||
g = StateGraph(State)
|
||||
> g.add_node("plan", plan)
|
||||
> g.add_node("review", review)
|
||||
g.add_node("execute", execute)
|
||||
> g.add_edge(START, "plan")
|
||||
g.add_edge("plan", "review")
|
||||
g.add_edge("execute", END)
|
||||
app = g.compile(checkpointer=InMemorySaver())
|
||||
|
||||
# Цикл: каждый review -- это пауза; Command(goto=...) -- ответвление
|
||||
> # plan -> review -> (approve: execute | abort: END | else: plan)
|
||||
> cfg = {"configurable": {"thread_id": "u1"}}
|
||||
app.invoke({"plan": "", "executed": False}, cfg) # пауза 1
|
||||
app.invoke(Command(resume="approve"), cfg) # resume -> execute
|
||||
@@ -0,0 +1,66 @@
|
||||
"""
|
||||
Slide 50: Slide 23
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-050/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 50 ===
|
||||
from typing_extensions import TypedDict
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
|
||||
class SubState(TypedDict):
|
||||
internal: str
|
||||
|
||||
def inner(state: SubState):
|
||||
return {"internal": "sub-output"}
|
||||
|
||||
# Собираем subgraph -- у него свой state
|
||||
> sub = StateGraph(SubState)
|
||||
> sub.add_node("inner", inner)
|
||||
> sub.add_edge(START, "inner")
|
||||
> sub.add_edge("inner", END)
|
||||
sub_compiled = sub.compile()
|
||||
|
||||
# Вставляем как обычный узел в родительский граф
|
||||
class ParentState(TypedDict):
|
||||
out: str
|
||||
|
||||
> parent = StateGraph(ParentState)
|
||||
> parent.add_node("sub_block", sub_compiled) # <- subgraph целиком
|
||||
parent.add_edge(START, "sub_block")
|
||||
parent.add_edge("sub_block", END)
|
||||
app = parent.compile()
|
||||
print(app.invoke({"out": ""}))
|
||||
|
||||
// note: snippet has 26 lines, card fits ~18
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Slide 51: Slide 24
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-051/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 51 ===
|
||||
cfg = {"configurable": {"thread_id": "u1"}}
|
||||
# values -- весь state после каждого super-step
|
||||
> for snap in app.stream({"messages": []}, cfg, stream_mode="values"):
|
||||
print(snap["messages"][-1].content)
|
||||
# updates -- delta: только что вернул каждый узел
|
||||
> for upd in app.stream({"messages": []}, cfg, stream_mode="updates"):
|
||||
print(upd)
|
||||
# events -- низкоуровневые события (start, end, error, interrupt)
|
||||
> for ev in app.stream({"messages": []}, cfg, stream_mode="events"):
|
||||
print(ev["event"], ev["name"])
|
||||
# messages -- токены LLM по мере генерации
|
||||
> for tok, meta in app.stream({"messages": []}, cfg, stream_mode="messages"):
|
||||
print(tok.content, end="|")
|
||||
# custom -- только то, что узлы пишут через get_stream_writer()
|
||||
> for chunk in app.stream({"messages": []}, cfg, stream_mode="custom"):
|
||||
print(chunk)
|
||||
@@ -0,0 +1,62 @@
|
||||
"""
|
||||
Slide 52: Slide 25
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-052/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 52 ===
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.config import get_stream_writer
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
class State(TypedDict):
|
||||
total: int
|
||||
|
||||
def progress(state: State):
|
||||
writer = get_stream_writer() # доступен только во время выполнения узла
|
||||
> for i in range(3):
|
||||
> writer({"progress": i, "phase": "thinking"})
|
||||
> return {"total": 3}
|
||||
|
||||
g = StateGraph(State)
|
||||
g.add_node("progress", progress)
|
||||
g.add_edge(START, "progress")
|
||||
g.add_edge("progress", END)
|
||||
app = g.compile()
|
||||
>
|
||||
> # в UI -- только custom-чанки, без промежуточного state
|
||||
for chunk in app.stream({"total": 0}, stream_mode="custom"):
|
||||
print(chunk)
|
||||
|
||||
// note: snippet has 22 lines, card fits ~18
|
||||
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Slide 53: Slide 26
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-053/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 53 ===
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langchain.tools import tool
|
||||
from langgraph.graph.message import add_messages
|
||||
from typing import Annotated
|
||||
from typing_extensions import TypedDict
|
||||
@tool
|
||||
def add(a: int, b: int) -> int:
|
||||
"Add two numbers."
|
||||
return a + b
|
||||
tools = [add]
|
||||
> llm = ChatOpenAI(model="gpt-4o-mini").bind_tools(tools)
|
||||
class State(TypedDict):
|
||||
messages: Annotated[list, add_messages]
|
||||
def agent(state: State):
|
||||
return {"messages": [llm.invoke(state["messages"])]}
|
||||
def route(state: State) -> str:
|
||||
> last = state["messages"][-1]
|
||||
return "tools" if getattr(last, "tool_calls", None) else END
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Slide 54: Slide 27
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-054/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 54 ===
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.prebuilt import ToolNode
|
||||
# tools, llm, agent, route -- из предыдущего слайда
|
||||
g = StateGraph(State)
|
||||
g.add_node("agent", agent)
|
||||
> g.add_node("tools", ToolNode(tools))
|
||||
g.add_edge(START, "agent")
|
||||
g.add_conditional_edges("agent", route, {"tools": "tools", END: END})
|
||||
g.add_edge("tools", "agent")
|
||||
> app = g.compile()
|
||||
|
||||
# Цикл: agent решает -> tools исполняет -> agent снова читает результат
|
||||
> result = app.invoke({
|
||||
> "messages": [{"role": "user", "content": "What is 2 + 3?"}]
|
||||
})
|
||||
print(result["messages"][-1].content)
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 55: Slide 28
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-055/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 55 ===
|
||||
# запуск: langgraph dev -- поднимает Studio на http://localhost:8123
|
||||
@@ -0,0 +1,49 @@
|
||||
"""
|
||||
Slide 56: Slide 29
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-056/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 56 ===
|
||||
# langgraph.json -- declarative config
|
||||
> {
|
||||
"graphs": {"agent": "./agent.py:graph"},
|
||||
"env": "./.env",
|
||||
"python_version": "3.11"
|
||||
}
|
||||
|
||||
# CLI: локальный dev-сервер и deploy
|
||||
langgraph dev # локальный API + Studio
|
||||
> langgraph up # Docker-compose stack (Redis + API + Studio)
|
||||
langgraph deploy # пуш в LangGraph Platform (managed)
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 57: Slide 30
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-057/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 57: Slide 30')
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Slide 58: Slide 31
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-058/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 58 ===
|
||||
> import { StateGraph, START, END, Annotation } from "@langchain/langgraph";
|
||||
> import { MemorySaver } from "@langchain/langgraph-checkpoint";
|
||||
|
||||
const State = Annotation.Root({
|
||||
messages: Annotation({
|
||||
reducer: (a, b) => a.concat(b),
|
||||
default: () => [],
|
||||
}),
|
||||
});
|
||||
|
||||
const g = new StateGraph(State)
|
||||
.addNode("echo", (s) => ({
|
||||
messages: [{ role: "assistant", content: "echo: " + s.messages.at(-1).content }],
|
||||
}))
|
||||
.addEdge(START, "echo")
|
||||
.addEdge("echo", END);
|
||||
|
||||
const app = g.compile({ checkpointer: new MemorySaver() });
|
||||
> const cfg = { configurable: { thread_id: "t1" } };
|
||||
const result = await app.invoke({ messages: [{ role: "user", content: "hi" }] }, cfg);
|
||||
|
||||
// note: snippet has 20 lines, card fits ~18
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 59: Slide 32
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-059/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 59: Slide 32')
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 60: Slide 33
|
||||
Section 2: LangGraph 1.0
|
||||
Source: slides/section2-langgraph/section2.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-060/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 60: Slide 33')
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 61: Deep Agents 1.0
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-061/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 61: Deep Agents 1.0')
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 62: Slide 2
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-062/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 62: Slide 2')
|
||||
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Slide 63: Slide 3
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-063/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 63 ===
|
||||
// examples/hello.py:1-14
|
||||
|
||||
# One import, one call -- you get:
|
||||
# - write_todos planning tool
|
||||
# - ls / read_file / write_file / edit_file
|
||||
# - glob, grep, execute (bash)
|
||||
# - task tool for subagents
|
||||
# - summarization middleware
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
>
|
||||
> agent = create_deep_agent(
|
||||
> model="openai:gpt-4.1",
|
||||
> tools=[my_tool],
|
||||
> system_prompt="...",
|
||||
> )
|
||||
|
||||
// note: snippet has 14 lines, card fits ~10
|
||||
@@ -0,0 +1,47 @@
|
||||
"""
|
||||
Slide 64: Slide 4
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-064/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 64 ===
|
||||
// setup.sh:1-5
|
||||
|
||||
pip install deepagents
|
||||
# or, with uv:
|
||||
uv add deepagents
|
||||
# JS analogue:
|
||||
npm install deepagents
|
||||
|
||||
// note: snippet has 5 lines, card fits ~3
|
||||
@@ -0,0 +1,52 @@
|
||||
"""
|
||||
Slide 65: Slide 5
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-065/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 65 ===
|
||||
// examples/hello.py:1-12
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
|
||||
> agent = create_deep_agent(
|
||||
> model="openai:gpt-4.1",
|
||||
> tools=[],
|
||||
> system_prompt="You are a helpful assistant.",
|
||||
)
|
||||
|
||||
result = agent.invoke({
|
||||
"messages": "Write a haiku about Python"
|
||||
})
|
||||
print(result["messages"][-1].content)
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Slide 66: Slide 6
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-066/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 66 ===
|
||||
// examples/full_api.py:1-15
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
from deepagents.backends import FilesystemBackend
|
||||
|
||||
> agent = create_deep_agent(
|
||||
> model="anthropic:claude-sonnet-4-5",
|
||||
> tools=[my_tool],
|
||||
> system_prompt="...",
|
||||
> subagents=[researcher, writer],
|
||||
> skills=["./skills/review.md"],
|
||||
> backend=FilesystemBackend("./ws"),
|
||||
> middleware=[my_hitl, my_logger],
|
||||
> checkpointer=InMemorySaver(),
|
||||
> store=InMemoryStore(),
|
||||
> interrupt_on={"bash": True},
|
||||
)
|
||||
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Slide 67: Slide 7
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-067/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 67 ===
|
||||
// examples/system_prompt.py:1-16
|
||||
|
||||
SYSTEM_PROMPT = """
|
||||
You are a senior backend engineer.
|
||||
|
||||
> WORKFLOW:
|
||||
> 1. Plan with write_todos before non-trivial work.
|
||||
> 2. Explore the codebase via ls / glob / grep first.
|
||||
> 3. Use edit_file for surgical changes, write_file for new files.
|
||||
> 4. Delegate research tasks to the "researcher" subagent.
|
||||
5. Run tests via execute; never claim success without output.
|
||||
|
||||
CONSTRAINTS:
|
||||
> - Do not modify files outside ./src.
|
||||
> - Stop and ask the user if requirements are ambiguous.
|
||||
"""
|
||||
|
||||
agent = create_deep_agent(model=..., system_prompt=SYSTEM_PROMPT)
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Slide 68: Slide 8
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-068/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 68 ===
|
||||
write_todos
|
||||
|
||||
ls
|
||||
|
||||
read_file
|
||||
|
||||
write_file
|
||||
|
||||
edit_file
|
||||
|
||||
glob
|
||||
|
||||
grep
|
||||
|
||||
execute
|
||||
|
||||
task
|
||||
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
Slide 69: Slide 9
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-069/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 69 ===
|
||||
// examples/fs_tools.py:1-11
|
||||
|
||||
# The agent calls these tools by name;
|
||||
# you describe the goal in the prompt.
|
||||
|
||||
> PROMPT = """
|
||||
> 1. Write src/hello.py with a greet(name) function.
|
||||
> 2. Use edit_file to add a docstring to greet().
|
||||
> 3. Use write_file to add tests/test_hello.py.
|
||||
"""
|
||||
|
||||
agent = create_deep_agent(model="openai:gpt-4.1")
|
||||
agent.invoke({"messages": PROMPT})
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Slide 70: Slide 10
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-070/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 70 ===
|
||||
// examples/write_todos.py:1-12
|
||||
|
||||
write_todos(
|
||||
> todos=[
|
||||
> {"content": "Read repo structure", "status": "in_progress",
|
||||
> "activeForm": "Reading repo structure"},
|
||||
> {"content": "Implement greet()", "status": "pending",
|
||||
> "activeForm": "Implementing greet()"},
|
||||
> {"content": "Add pytest cases", "status": "pending",
|
||||
> "activeForm": "Adding pytest cases"},
|
||||
> ]
|
||||
)
|
||||
# Status: pending | in_progress | completed
|
||||
# activeForm: present-continuous shown in UI
|
||||
|
||||
// note: snippet has 12 lines, card fits ~10
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 71: Slide 11
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-071/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 71: Slide 11')
|
||||
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
Slide 72: Slide 12
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-072/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 72 ===
|
||||
// examples/task_call.py:1-10
|
||||
|
||||
# When the main agent emits a tool call like:
|
||||
> task(
|
||||
> subagent_type="researcher",
|
||||
> description="Find papers on RAG evaluation",
|
||||
> prompt="Search arXiv for 2025-2026 RAG evaluation surveys.
|
||||
> Return a 150-word summary with 3 citations.",
|
||||
)
|
||||
|
||||
# Deep Agents spins up a fresh deep agent with the researcher profile,
|
||||
# runs it to completion, and returns only the final message.
|
||||
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
Slide 73: Slide 13
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-073/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 73 ===
|
||||
// examples/subagents.py:1-23
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
|
||||
researcher = {
|
||||
> "name": "researcher",
|
||||
> "description": "Does deep web research, returns citations",
|
||||
> "system_prompt": "You are a research specialist. Always cite sources.",
|
||||
> "tools": [web_search], # optional, can be []
|
||||
}
|
||||
|
||||
writer = {
|
||||
> "name": "writer",
|
||||
> "description": "Polishes prose into a final report",
|
||||
> "system_prompt": "You are a writing specialist.",
|
||||
> "tools": [],
|
||||
}
|
||||
|
||||
agent = create_deep_agent(
|
||||
model="openai:gpt-4.1",
|
||||
> tools=[],
|
||||
> subagents=[researcher, writer],
|
||||
> )
|
||||
>
|
||||
agent.invoke({"messages": "Research quantum computing and write a 200-word summary."})
|
||||
|
||||
// note: snippet has 23 lines, card fits ~16
|
||||
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
Slide 74: Slide 14
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-074/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 74 ===
|
||||
context = [
|
||||
user task,
|
||||
summary from researcher,
|
||||
summary from writer
|
||||
]
|
||||
|
||||
task("researcher")
|
||||
|
||||
context = [
|
||||
full web_search results,
|
||||
all 14 sources,
|
||||
notes, drafts, citations
|
||||
]
|
||||
return: 150-word summary
|
||||
|
||||
context = [
|
||||
researcher summary,
|
||||
original user task
|
||||
]
|
||||
return: polished 200-word report
|
||||
@@ -0,0 +1,49 @@
|
||||
"""
|
||||
Slide 75: Slide 15
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-075/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 75 ===
|
||||
// examples/virtual_fs.py:1-9
|
||||
|
||||
# Inspect the virtual filesystem after a run:
|
||||
result = agent.invoke({"messages": "Summarize repo"})
|
||||
>
|
||||
> files = result.get("files", {})
|
||||
> for path, doc in files.items():
|
||||
> print(f"{path}: {len(doc.get('content', []))} bytes")
|
||||
|
||||
# /repo/src/main.py: 421 bytes
|
||||
# /repo/README.md: 1804 bytes
|
||||
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
Slide 76: Slide 16
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-076/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 76 ===
|
||||
before_model
|
||||
|
||||
after_model
|
||||
|
||||
before_tool
|
||||
|
||||
after_tool
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Slide 77: Slide 17
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-077/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 77 ===
|
||||
// examples/middleware.py:1-18
|
||||
|
||||
from langchain.agents.middleware import AgentMiddleware
|
||||
from deepagents import create_deep_agent
|
||||
|
||||
class LoggerMiddleware(AgentMiddleware):
|
||||
> def before_model(self, state, runtime):
|
||||
> print(f"[model] {len(state['messages'])} msgs in")
|
||||
> return state
|
||||
>
|
||||
> def after_tool(self, state, runtime, tool_result):
|
||||
> print(f"[tool] {tool_result.tool_call_id} -> {len(str(tool_result.content))} chars")
|
||||
return state
|
||||
|
||||
agent = create_deep_agent(
|
||||
model="openai:gpt-4.1",
|
||||
middleware=[LoggerMiddleware(), HumanInTheLoopMiddleware(
|
||||
> interrupt_on={"execute": True}, # ask before running bash
|
||||
> )],
|
||||
> )
|
||||
|
||||
// note: snippet has 18 lines, card fits ~16
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 78: Slide 18
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-078/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 78: Slide 18')
|
||||
@@ -0,0 +1,62 @@
|
||||
"""
|
||||
Slide 79: Slide 19
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-079/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 79 ===
|
||||
// examples/composite_backend.py:1-20
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
from deepagents.backends import (
|
||||
CompositeBackend, FilesystemBackend, StoreBackend
|
||||
)
|
||||
from langgraph.store.memory import InMemoryStore
|
||||
|
||||
store = InMemoryStore() # or PostgresStore in prod
|
||||
|
||||
backend = CompositeBackend(
|
||||
default=FilesystemBackend(root_dir="./workspace"),
|
||||
routes={
|
||||
> "/memory/": StoreBackend(store=store, namespace=("agent", "kb")),
|
||||
> "/scratch/": FilesystemBackend(root_dir="/tmp/scratch"),
|
||||
> },
|
||||
> )
|
||||
|
||||
agent = create_deep_agent(model=..., backend=backend)
|
||||
# /workspace/notes.md -> local disk
|
||||
# /memory/lessons.md -> Postgres, shared across sessions
|
||||
> # /scratch/tmp.py -> ephemeral tmpfs
|
||||
|
||||
// note: snippet has 20 lines, card fits ~16
|
||||
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
Slide 80: Slide 20
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-080/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 80 ===
|
||||
// examples/hitl.py:1-23
|
||||
|
||||
from langchain.agents.middleware import HumanInTheLoopMiddleware
|
||||
from deepagents import create_deep_agent
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
from langgraph.types import Command
|
||||
|
||||
agent = create_deep_agent(
|
||||
model="openai:gpt-4.1",
|
||||
checkpointer=InMemorySaver(),
|
||||
> middleware=[HumanInTheLoopMiddleware(
|
||||
> interrupt_on={
|
||||
> "execute": True, # bash -- always ask
|
||||
> "write_file": True, # disk writes -- always ask
|
||||
> "task": False, # subagents -- run unattended
|
||||
> },
|
||||
)],
|
||||
)
|
||||
|
||||
cfg = {"configurable": {"thread_id": "user-42"}}
|
||||
try:
|
||||
agent.invoke({"messages": "deploy to staging"}, cfg)
|
||||
except InterruptedError:
|
||||
decision = ask_user("Approve execute()?") # your UI
|
||||
agent.invoke(Command(resume=decision), cfg)
|
||||
|
||||
// note: snippet has 23 lines, card fits ~15
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
Slide 81: Slide 21
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-081/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 81 ===
|
||||
// examples/streaming.py:1-18
|
||||
|
||||
cfg = {"configurable": {"thread_id": "user-42"}}
|
||||
|
||||
# 1. Stream model tokens as they arrive
|
||||
> for token, meta in agent.stream(
|
||||
> {"messages": "..."}, cfg,
|
||||
> stream_mode="messages",
|
||||
):
|
||||
print(token.content, end="", flush=True)
|
||||
|
||||
# 2. Stream state updates per node
|
||||
for chunk in agent.stream(
|
||||
> {"messages": "..."}, cfg,
|
||||
> stream_mode="updates",
|
||||
> ):
|
||||
print(chunk) # {"model": {...}, "tools": {...}}
|
||||
|
||||
# 3. Subagent streams are surfaced as
|
||||
# {"subagent": {"name": "researcher", "chunk": ...}}
|
||||
|
||||
// note: snippet has 18 lines, card fits ~16
|
||||
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
Slide 82: Slide 22
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-082/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 82 ===
|
||||
// examples/langsmith.sh:1-8
|
||||
|
||||
export LANGSMITH_TRACING=true
|
||||
export LANGSMITH_API_KEY=lsv2_...
|
||||
export LANGSMITH_PROJECT=deepagents-evals
|
||||
|
||||
python my_deep_agent.py
|
||||
# -> all runs visible in smith.langchain.com
|
||||
# -> subagent runs nested under the parent
|
||||
# -> token usage, latency, tool errors captured
|
||||
@@ -0,0 +1,66 @@
|
||||
"""
|
||||
Slide 83: Slide 23
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-083/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 83 ===
|
||||
// examples/research_agent.py:1-24
|
||||
|
||||
from langchain.tools import tool
|
||||
from deepagents import create_deep_agent
|
||||
|
||||
@tool
|
||||
def arxiv_search(query: str, max_results: int = 5) -> str:
|
||||
"""Search arXiv for papers matching the query."""
|
||||
import arxiv
|
||||
client = arxiv.Client()
|
||||
results = list(client.results(arxiv.Search(query=query, max_results=max_results)))
|
||||
return "\n\n".join(
|
||||
f"{r.title}\n{r.summary[:300]}..." for r in results
|
||||
)
|
||||
|
||||
agent = create_deep_agent(
|
||||
model="openai:gpt-4.1",
|
||||
tools=[arxiv_search],
|
||||
system_prompt=("You are a research assistant. Always cite paper titles and arXiv IDs."),
|
||||
> subagents=[{
|
||||
> "name": "summarizer",
|
||||
> "description": "Compresses paper abstracts into a paragraph",
|
||||
> "system_prompt": "You are a precise summarizer.",
|
||||
> "tools": [],
|
||||
> }],
|
||||
> )
|
||||
|
||||
// note: snippet has 24 lines, card fits ~16
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Slide 84: Slide 24
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-084/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 84 ===
|
||||
// examples/coding_agent.py:1-17
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
from deepagents.backends import SandboxBackend
|
||||
|
||||
> agent = create_deep_agent(
|
||||
> model="anthropic:claude-sonnet-4-5",
|
||||
> backend=SandboxBackend(
|
||||
> provider="daytona", # or modal / runloop
|
||||
> api_key=os.environ["DAYTONA_API_KEY"],
|
||||
> image="python:3.12-slim",
|
||||
> ),
|
||||
> system_prompt=("You are a coding agent. Always run tests after edits. Stop and ask if requirements are ambiguous."),
|
||||
)
|
||||
|
||||
agent.invoke({"messages": "Add a /healthz endpoint to the FastAPI app, with tests."})
|
||||
|
||||
# Daytona/Modal/Runloop execute code in an isolated container;
|
||||
# the local process never sees a stray rm -rf.
|
||||
|
||||
// note: snippet has 17 lines, card fits ~16
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Slide 85: Slide 25
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-085/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 85 ===
|
||||
// examples/deepagentsjs.ts:1-13
|
||||
|
||||
// TypeScript analogue (deepagentsjs)
|
||||
import { createDeepAgent } from "deepagents";
|
||||
import { tool, z } from "@langchain/core/tools";
|
||||
|
||||
const search = tool(
|
||||
async ({ q }) => fetch("/api/search?q=" + q).then(r => r.text()),
|
||||
{ name: "search", schema: z.object({ q: z.string() }) },
|
||||
);
|
||||
|
||||
> const agent = await createDeepAgent({
|
||||
> model: "openai:gpt-4.1",
|
||||
> tools: [search],
|
||||
> });
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 86: Slide 26
|
||||
Section 3: Deep Agents
|
||||
Source: slides/section3-deepagents/section3.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-086/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 86: Slide 26')
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slide 87: Open SWE: async coding agent
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-087/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# (No extractable code on this slide — visual-only or section divider)
|
||||
print('Slide 87: Open SWE: async coding agent')
|
||||
@@ -0,0 +1,52 @@
|
||||
"""
|
||||
Slide 88: Slide 2
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-088/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 88 ===
|
||||
// meta: open-swe repo:1-12
|
||||
|
||||
# github.com/langchain-ai/open-swe
|
||||
|
||||
stars: ~10k
|
||||
commits: 971+
|
||||
license: MIT
|
||||
language: Python + TypeScript
|
||||
announce: 08.2025
|
||||
rewrite: 03.2026
|
||||
|
||||
# blog.langchain.com/open-swe
|
||||
# INSTALLATION.md
|
||||
# CUSTOMIZATION.md
|
||||
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
Slide 89: Slide 3
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-089/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 89 ===
|
||||
Slack / Linear / GitHub / Web UI
|
||||
|
||||
prompt + middleware (HITL, approval)
|
||||
|
||||
subagents + middleware
|
||||
|
||||
AGENTS.md из репозитория
|
||||
|
||||
execute, fetch_url, linear_comment, slack_thread_reply
|
||||
|
||||
Modal / Daytona / Runloop / LangSmith
|
||||
|
||||
create_deep_agent (Deep Agents)
|
||||
|
||||
// open_swe/__init__.py:1-11
|
||||
|
||||
from open_swe.agent import create_agent
|
||||
from open_swe.middleware import (
|
||||
check_message_queue_before_model,
|
||||
notify_step_limit_reached,
|
||||
open_pr_if_needed,
|
||||
ToolErrorMiddleware,
|
||||
)
|
||||
from open_swe.sandbox import (
|
||||
SandboxBackend,
|
||||
ModalBackend, DaytonaBackend,
|
||||
)
|
||||
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
Slide 90: Slide 4
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-090/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 90 ===
|
||||
// examples/minimal_agent.py:1-11
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
from open_swe.sandbox import DaytonaBackend
|
||||
|
||||
> agent = create_deep_agent(
|
||||
model="anthropic:claude-opus-4-6",
|
||||
tools=[execute, fetch_url,
|
||||
linear_comment,
|
||||
> slack_thread_reply],
|
||||
> backend=DaytonaBackend(api_key="..."),
|
||||
middleware=[open_pr_if_needed],
|
||||
)
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Slide 91: Slide 5
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-091/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 91 ===
|
||||
// open_swe/prompts.py:1-9
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
def construct_system_prompt(
|
||||
repo_dir, base_prompt
|
||||
):
|
||||
agents_md = Path(repo_dir) / "AGENTS.md"
|
||||
extra = agents_md.read_text() if
|
||||
agents_md.exists() else ""
|
||||
return base_prompt + extra
|
||||
|
||||
// note: snippet has 9 lines, card fits ~6
|
||||
|
||||
// AGENTS.md:1-5
|
||||
|
||||
# AGENTS.md (repo root)
|
||||
|
||||
- use uv, not pip
|
||||
- run pytest before commit
|
||||
- never push to main directly
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Slide 92: Slide 6
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-092/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 92 ===
|
||||
// examples/audit_middleware.py:1-13
|
||||
|
||||
from langchain.agents.middleware import (
|
||||
AgentMiddleware,
|
||||
)
|
||||
|
||||
> class AuditMiddleware(AgentMiddleware):
|
||||
> def after_model(self, state, runtime):
|
||||
> runtime.logger.info(
|
||||
> f"step={state.get("step")}"
|
||||
)
|
||||
return state
|
||||
|
||||
def before_model(self, state, runtime):
|
||||
return state # inject reminder
|
||||
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
Slide 93: Slide 7
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-093/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 93 ===
|
||||
ModalBackend
|
||||
|
||||
token_id + token_secret
|
||||
|
||||
per-second + GB-s
|
||||
|
||||
yes (volume)
|
||||
|
||||
Python-first, GPU-доступный
|
||||
|
||||
DaytonaBackend
|
||||
|
||||
api_key
|
||||
|
||||
per-session
|
||||
|
||||
yes (volume)
|
||||
|
||||
default в README
|
||||
|
||||
RunloopBackend
|
||||
|
||||
api_key
|
||||
|
||||
per-second
|
||||
|
||||
yes (volume)
|
||||
|
||||
dev-цикл, snapshot/restart
|
||||
|
||||
LangSmithBackend
|
||||
|
||||
LANGSMITH_API_KEY
|
||||
|
||||
через LangSmith
|
||||
|
||||
через LS
|
||||
|
||||
уже платите за LangSmith
|
||||
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
Slide 94: Slide 8
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-094/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 94 ===
|
||||
// open_swe/sandbox/__init__.py:1-12
|
||||
|
||||
from open_swe.sandbox import (
|
||||
ModalBackend,
|
||||
DaytonaBackend,
|
||||
RunloopBackend,
|
||||
LangSmithBackend,
|
||||
)
|
||||
|
||||
# Modal (Python-first, GPU)
|
||||
backend = ModalBackend(
|
||||
token_id="..."
|
||||
token_secret="..."
|
||||
)
|
||||
|
||||
// examples/my_internal_backend.py:1-11
|
||||
|
||||
# свой backend: devbox-пул
|
||||
from open_swe.sandbox import (
|
||||
SandboxBackend,
|
||||
)
|
||||
>
|
||||
class MyInternalBackend(SandboxBackend):
|
||||
def execute(self, cmd):
|
||||
> return self._run(cmd)
|
||||
>
|
||||
def read_file(self, p):
|
||||
> return self._fetch(p)
|
||||
|
||||
// examples/my_internal_backend.py:1-16
|
||||
|
||||
# свой backend: devbox-пул
|
||||
from open_swe.sandbox import (
|
||||
SandboxBackend,
|
||||
)
|
||||
|
||||
class MyInternalBackend(
|
||||
SandboxBackend
|
||||
):
|
||||
def __init__(self, conn):
|
||||
self.conn = conn
|
||||
>
|
||||
> def execute(self, cmd):
|
||||
> return self._run(cmd)
|
||||
>
|
||||
> def read_file(self, p):
|
||||
> return self._fetch(p)
|
||||
|
||||
// note: snippet has 16 lines, card fits ~15
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Slide 95: Slide 9
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-095/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 95 ===
|
||||
// INSTALLATION.md: step 1:1-5
|
||||
|
||||
# 1. prerequisites
|
||||
python --version # >= 3.11
|
||||
node --version # >= 20
|
||||
uv --version # или pip
|
||||
docker --version # для dev
|
||||
|
||||
// INSTALLATION.md: step 2:1-5
|
||||
|
||||
# 2. clone + install
|
||||
git clone https://github.com/
|
||||
langchain-ai/open-swe.git
|
||||
cd open-swe
|
||||
uv sync # или pip install -e .
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Slide 96: Slide 10
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-096/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 96 ===
|
||||
// INSTALLATION.md: steps 3-5:1-13
|
||||
|
||||
# 3. backend (FastAPI)
|
||||
uv run apps/open-swe/main.py
|
||||
# -> :8000
|
||||
|
||||
# 4. UI (TanStack Start + Vite)
|
||||
cd apps/open-swe-ui
|
||||
pnpm install && pnpm dev
|
||||
# -> :3000
|
||||
|
||||
# 5. smoke-test
|
||||
curl -X POST :8000/webhooks/slack \
|
||||
-d '{"text":"@open-swe hello"}'
|
||||
# -> {"thread_id": "..."}
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Slide 97: Slide 11
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-097/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 97 ===
|
||||
// config/github-app-manifest.yaml:1-13
|
||||
|
||||
# github-app-manifest.yaml
|
||||
name: open-swe-internal
|
||||
> url: https://open-swe.example.com
|
||||
> hook_attributes:
|
||||
> url: https://open-swe.example.com/
|
||||
> webhooks/github
|
||||
> events:
|
||||
> - issue_comment
|
||||
> - pull_request
|
||||
- pull_request_review
|
||||
default_permissions:
|
||||
contents: write
|
||||
pull_requests: write
|
||||
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
Slide 98: Slide 12
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-098/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 98 ===
|
||||
// .env:1-10
|
||||
|
||||
# .env (НЕ коммитить)
|
||||
LANGSMITH_TRACING=true
|
||||
LANGSMITH_ENDPOINT=https://
|
||||
api.smith.langchain.com
|
||||
LANGSMITH_API_KEY=lsv2_...
|
||||
LANGSMITH_PROJECT=open-swe-prod
|
||||
LANGSMITH_SNAPSHOT=true
|
||||
|
||||
# для sandbox-прокси:
|
||||
LANGSMITH_SANDBOX_BACKEND=true
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Slide 99: Slide 13
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-099/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 99 ===
|
||||
@open-swe fix the auth bug
|
||||
repo:acme/api
|
||||
|
||||
@openswe implement the
|
||||
acceptance criteria
|
||||
|
||||
@openswe address
|
||||
the review comments
|
||||
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
Slide 100: Slide 14
|
||||
Section 4: Open SWE
|
||||
Source: slides/section4-openswe/section4.pptx
|
||||
|
||||
Сгенерировано автоматически из slide-NN.js / sectionN.pptx.
|
||||
Паттерн провайдера скопирован из
|
||||
bro-js/agents/teacher/assistant/src/angry_teacher/llm.py.
|
||||
|
||||
Запуск:
|
||||
cd langchain-evolution-deck
|
||||
cp .env.example .env # заполни OPENAI_API_KEY
|
||||
python examples/slide-100/script.py
|
||||
"""
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
load_dotenv()
|
||||
|
||||
llm = ChatOpenAI(
|
||||
# model="openrouter/free",
|
||||
# model="qwen/qwen3.5-35b-a3b",
|
||||
model="openai/gpt-oss-20b",
|
||||
# model="nvidia/nemotron-3-nano",
|
||||
# model="qwen/qwen3.5-9b",
|
||||
base_url="https://llm.brojs.ru/v1",
|
||||
# base_url="https://api.minimax.io/v1",
|
||||
# base_url="http://0.0.0.0:8090/v1",
|
||||
# base_url="https://openrouter.ai/api/v1",
|
||||
# api_key=os.getenv("MINIMAX_API_KEY"),
|
||||
api_key=(os.getenv("OPENAI_API_KEY") or "").strip() or None,
|
||||
temperature=0.7,
|
||||
stream_usage=True,
|
||||
)
|
||||
|
||||
|
||||
# === Code from slide 100 ===
|
||||
// open_swe/triggers/router.py:1-11
|
||||
|
||||
# open_swe/triggers/router.py
|
||||
> def thread_id_for(source, ref, comment_id):
|
||||
> # Deterministic thread_id:
|
||||
> # все follow-up попадают в один run.
|
||||
> if source == "slack":
|
||||
> return f"slack:{ref}"
|
||||
> if source == "linear":
|
||||
> return f"linear:{ref}"
|
||||
> if source == "github":
|
||||
return f"github:{ref}:{comment_id}"
|
||||
raise ValueError(source)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user