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,55 @@
|
|||||||
|
# Скопируй этот файл в .env и заполни реальными значениями:
|
||||||
|
# cp .env.example .env
|
||||||
|
# # открой .env и заполни OPENAI_API_KEY и другие
|
||||||
|
#
|
||||||
|
# Реальный .env НЕ коммитится (см. .gitignore).
|
||||||
|
# Если у тебя есть рабочий .env в bro-js/agents/teacher/assistant/.env --
|
||||||
|
# можешь сделать symlink или просто скопировать его сюда.
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# LLM Provider (используется во всех 122 example-скриптах)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# Endpoint by default: https://llm.brojs.ru/v1
|
||||||
|
# OpenAI-compatible, можно переопределить через OPENAI_BASE_URL
|
||||||
|
OPENAI_BASE_URL=https://llm.brojs.ru/v1
|
||||||
|
OPENAI_API_KEY=
|
||||||
|
|
||||||
|
# Альтернативные провайдеры (раскомментируй нужный, скрипты автоматически подхватят):
|
||||||
|
# MINIMAX_API_KEY=sk-cp-...
|
||||||
|
# GIGACHAT_CREDENTIALS=...
|
||||||
|
# GIGACHAT_SCOPE=GIGACHAT_API_B2B
|
||||||
|
# GIGACHAT_MODEL=GigaChat-MAX
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Observability (LangSmith) -- опционально, для tracing
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# LANGSMITH_API_KEY=lsv2_pt_...
|
||||||
|
# LANGSMITH_ENDPOINT=https://api.smith.langchain.com
|
||||||
|
# LANGSMITH_TRACING_V2=true
|
||||||
|
# LANGSMITH_PROJECT=langchain-evolution-deck
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Search (Tavily) -- нужен для RAG-слайдов про retrievers
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# TAVILY_API_KEY=tvly-dev-...
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Embeddings (HuggingFace) -- опционально для RAG
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# HUGGINGFACEHUB_API_KEY=hf_...
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Не используется в этой колоде, но есть в teacher/assistant/.env
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# SMTP_CONFIG='["mail.itpark.tech", 25, false]'
|
||||||
|
# SMTP_MAIL_LOGIN=academydevops@itpark.tech
|
||||||
|
# SMTP_MAIL_PASSWORD=...
|
||||||
|
# MAIL_TO_1=primakovpro@gmail.com
|
||||||
|
# GITHUB_TOKEN=ghp_...
|
||||||
|
# GITEA_TOKEN=...
|
||||||
|
# JOURNAL_MCP_PAT=jrnl_...
|
||||||
@@ -12,3 +12,7 @@ node_modules/
|
|||||||
# Python
|
# Python
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Parser script and intermediate
|
||||||
|
parse_slides.py
|
||||||
|
|||||||
@@ -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
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user