Tworzenie pierwszego agenta LangGraph – Praktyczny przewodnik dla początkujących
Pierwszy agent LangGraph dla początkujących: dlaczego agenci są ważni, co LangGraph dodaje do LangChain, konfiguracja projektu, a następnie stan, węzły, krawędzie oraz działający cykl LLM.
Źródła: Building Your First LangGraph Agent: A Practical Beginner’s Guide
To przewodnik odtwarza ścieżkę od surowców do gotowego systemu w ramach: Budowanie pierwszego agenta LangGraph: Praktyczny przewodnik dla początkujących. Główny nacisk kładziony jest na konkretne kroki, wyraźne sprawdzenia oraz kod, który można bez problemu umieścić w repozytorium, bez konieczności domyślania się intencji. Na etapie przeglądu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Obok wyników funkcjonalnych należy rejestrować czas trwania oraz koszt tokenów lub zapytań. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z środowiska demonstracyjnego do współdzielonych środowisk.
Dlaczego agenci są ważni
Gdy przechodzisz przez etap „Dlaczego agenci są ważni”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ustaw punkty kontrolne po kosztownych krokach. System powrotu nie powinien ponownie naliczać opłat za tę samą wywołanie LLM, gdy operator ponawia próbę z późniejszym węzłem.
User question → LLM → Answer
User question → Retrieve context → LLM → Answer
User question → Agent decides what to do → Calls tools → Updates state → Produces answer
Co to jest LangGraph?
Gdy przechodzisz przez etap „Co to jest LangGraph”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponowne, kontrola przez ludzi oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później. Ustaw punkty kontrolne po kosztownych krokach. Narzędzie do kontynuacji pracy nie powinno ponownie naliczać opłat za tę samą wywołanie LLM, gdy operator próbuje ponownie uruchomić późniejszy węzeł.
Ustawienie projektu
Podczas przechodzenia przez etap konfiguracji projektu najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Ustalaj punkty kontrolne po kosztownych krokach. System powinien unikać ponownego naliczania opłat za tę samą funkcję LLM, gdy operator próbuje ponownie uruchomić późniejszy element. Podczas przechodzenia przez etap konfiguracji projektu najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z wersji demonstracyjnej do środowisk współdzielonych.
pip install langgraph langchain langchain-openai langchain-community python-dotenv pydantic
pip install jupyter notebook ipython
OPENAI_API_KEY=your_api_key_here
import os
import json
from typing import Optional, List
from dotenv import load_dotenv
from pydantic import BaseModel
from langgraph.graph import StateGraph, START, END
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage
from langchain.tools import tool
load_dotenv()
llm = init_chat_model("openai:gpt-4o-mini")
Krok 1: Określenie stanu agenta
Krok 1 polegający na określeniu stanu działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, składysek z danymi poufnymi oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całego grafu. Utrzymuj stan grafu w formie prostej i z typami danych. Wplecione struktury ukrywają informację o tym, który węzeł zapisał dane do którego pola, co utrudnia kontynuację pracy po przerwach.
class PlayerState(BaseModel):
question: str
selected_tools: Optional[List[str]] = None
name: Optional[str] = None
club: Optional[str] = None
country: Optional[str] = None
number: Optional[int] = None
rating: Optional[int] = None
goals: Optional[List[int]] = None
minutes_played: Optional[List[int]] = None
summary: Optional[str] = None
Krok 2: Stworzenie narzędzi
Etap nr 2, polegający na tworzeniu narzędzi, funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia do analizy. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres pracy. Zdokumentuj zarówno prawidłowy przebieg operacji, jak i ścieżkę przywracania do stanu poprzedniego. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później. Ujawnij narzędzia o wąskich schematach i wyraźnych etykietach dotyczących efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan systemu, zanim dokonają automatycznej aprobaty.
Narzędzie 1: Pobieranie informacji o graczu
Etap Tool 1 Fetch Player funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Używaj narzędzi o wąskich schematach oraz z wyraźnymi etykietami efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan, zanim automatycznie je zatwierdzą. Etap Tool 1 Fetch Player funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z wersji demonstracyjnej do środowisk współdzielonych.
@tool
def fetch_player_information_tool(name: str):
"""
Returns the football club and country of a player.
"""
data = {
"Haaland": {
"club": "Manchester City",
"country": "Norway"
},
"Kane": {
"club": "Bayern Munich",
"country": "England"
},
"Lautaro": {
"club": "Inter Milan",
"country": "Argentina"
},
"Ronaldo": {
"club": "Al-Nassr",
"country": "Portugal"
}
}
return data.get(name, {
"club": "unknown",
"country": "unknown"
})
def fetch_player_information(state: PlayerState):
return fetch_player_information_tool.invoke({
"name": state.name
})
Narzędzie 2: Pobieranie numeru koszulki
W fazie Tool 2 Fetch Jersey należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Autoryzacja powinna odbywać się przy bramce, a ponowna autoryzacja – na poziomie warstwy danych. Sam token nośny nie stanowi granicy między poszczególnymi użytkownikami.
@tool
def fetch_player_jersey_number_tool(name: str):
"""
Returns the jersey number of a football player.
"""
data = {
"Haaland": 9,
"Kane": 9,
"Lautaro": 10,
"Ronaldo": 7
}
return {
"number": data.get(name, 0)
}
def fetch_player_jersey_number(state: PlayerState):
return fetch_player_jersey_number_tool.invoke({
"name": state.name
})
Tool 3: Pobieranie oceny gracza
Dla etapu Tool 3 Fetch Player należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Autoryzacja powinna odbywać się przy bramce wejściowej, a ponowna autoryzacja – na poziomie warstwy danych. Sam token nośny nie stanowi granicy między poszczególnymi użytkownikami.
@tool
def fetch_player_rating_tool(name: str):
"""
Returns the player's football video game rating.
"""
data = {
"Haaland": 92,
"Kane": 89,
"Lautaro": 88,
"Ronaldo": 90
}
return {
"rating": data.get(name, 0)
}
def fetch_player_rating(state: PlayerState):
return fetch_player_rating_tool.invoke({
"name": state.name
})
Krok 3: Dodanie węzłów pobierania danych
W etapie Krok 3 – Dodawanie danych należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy krok się nie powiedzie, przyczyna powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany proces. Należy podawać fragmenty tekstu, które faktycznie stanowią podstawę odpowiedzi. Bez tych odniesień operatorzy nie będą w stanie odróżnić fałszywych informacji od braków w indeksowaniu. W etapie Krok 3 – Dodawanie danych należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Obok wyników funkcjonalnych należy rejestrować czas trwania oraz koszt tokenów lub zapytań. Jasna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk.
Pobieranie celów
Podczas przechodzenia przez etap pobierania celów najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Zmierz stopę odzyskiwania informacji na ustalonej serii pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko naprawiają słabe możliwości wyszukiwania.
def retrieve_goals(state: PlayerState):
data = {
"Haaland": [25, 40, 28, 33, 36],
"Kane": [33, 37, 41, 38, 29],
"Lautaro": [19, 25, 27, 24, 25],
"Ronaldo": [27, 32, 28, 30, 36]
}
return {
"goals": data.get(state.name, [0])
}
Pobieranie informacji o rozegranych minutach
Gdy przechodzisz przez etap pobierania danych o rozegranych minutach, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędowych są częścią produktu, a nie elementem późniejszej optymalizacji. Zmierz stopień przywoływania informacji na podstawie ustalonego zestawu pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko naprawiają słabe mechanizmy wyszukiwania.
def retrieve_minutes_played(state: PlayerState):
data = {
"Haaland": [2108, 3102, 3156, 2617, 2758],
"Kane": [2924, 2850, 3133, 2784, 2680],
"Lautaro": [2445, 2498, 2519, 2773],
"Ronaldo": [3001, 2560, 2804, 2487, 2771]
}
return {
"minutes_played": data.get(state.name, [0])
}
Krok 4: Wyodrębnienie imienia gracza
Gdy przechodzisz przez etap 4 „Wyciągnięcie danych”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Ustalaj punkty kontrolne po kosztownych krokach. System powinien unikać ponownego naliczania opłat za tę samą funkcję LLM, gdy operator próbuje ponownie uruchomić późniejszy element. Gdy przechodzisz przez etap 4 „Wyciągnięcie danych”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do wspólnych środowisk.
def extract_name(state: PlayerState):
prompt = f"""
You are a football name extraction assistant.
Extract only the surname of the football player mentioned in the question.
Question:
{state.question}
Return only one word.
"""
response = llm.invoke([
HumanMessage(content=prompt)
]).content.strip()
return {
"name": response
}
Will Erling Haaland win the World Cup with Norway?
{"name": "Haaland"}
Krok 5: Stworzenie węzła planera
Etap Krok 5: Stworzenie funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań przed rozszerzeniem zakresu. Utrzymuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całego grafu. Utrzymuj stan grafu w formie prostych, typowanych struktur. Wplecione bloki danych ukrywają informację o tym, który węzeł zapisał dane do którego pola, co utrudnia kontynuację pracy po przerwach.
def planner(state: PlayerState):
prompt = f"""
You are a football assistant planner.
Available tools:
[
"fetch_player_jersey_number",
"fetch_player_information",
"fetch_player_rating"
]
User question:
{state.question}
Choose which tools are needed to answer the question.
Return only a valid JSON array of tool names.
Example:
["fetch_player_information", "fetch_player_rating"]
"""
response = llm.invoke([
HumanMessage(content=prompt)
]).content.strip()
try:
selected_tools = json.loads(response)
except Exception:
selected_tools = []
return {
"selected_tools": selected_tools
}
Krok 6: Napisanie ostatecznego podsumowania
Etap nr 6, polegający na zapisaniu procedury, działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię do analizy. Zapisz jeden idealny przypadek działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres projektu. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę przywracania do stanu poprzedniego. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości nieodebranych stanowią część produktu, a nie elementy dodawane później w celu udoskonalenia. Utrzymuj strukturę grafu w prostym formacie i z określonym typem danych. Wложone elementy ukrywają informację o tym, który węzeł zapisał dane do którego pola, co powoduje przerwanie kontynuacji działania po zakłóceniach.
def write_summary(state: PlayerState):
player_data = {
"name": state.name,
"club": state.club,
"country": state.country,
"number": state.number,
"rating": state.rating,
"goals": state.goals,
"minutes_played": state.minutes_played
}
prompt = f"""
You are a football journalist.
Using the data below, write a concise markdown summary about the player.
Player data:
{json.dumps(player_data, indent=4)}
The summary should include:
- Full player name if it can be inferred
- Country with a flag emoji if available
- Club if available
- Jersey number if available
- Rating if available
- Total goals in the last three seasons
- Average minutes per goal over the available data
- A direct answer to the user's question
User question:
{state.question}
"""
response = llm.invoke([
HumanMessage(content=prompt)
]).content
return {
"summary": response
}
Krok 7: Budowa procesu LangGraph
Etap 7 „Budowa sceny” funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Utrzymuj stan grafu w prostej formie i z określonym typem danych. Wtórne struktury ukrywają informację o tym, który węzeł zapisał dane do którego pola, i powodują przerwę w kontynuacji działania po zakłóceniach. Etap 7 „Budowa sceny” funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do wspólnych środowisk.
graph_builder = StateGraph(PlayerState)
graph_builder.add_node("extract_name", extract_name)
graph_builder.add_node("planner", planner)
graph_builder.add_node("fetch_player_jersey_number", fetch_player_jersey_number)
graph_builder.add_node("fetch_player_information", fetch_player_information)
graph_builder.add_node("fetch_player_rating", fetch_player_rating)
graph_builder.add_node("retrieve_goals", retrieve_goals)
graph_builder.add_node("retrieve_minutes_played", retrieve_minutes_played)
graph_builder.add_node("write_summary", write_summary)
Krok 8: Dodawanie krawędzi
W etapie nr 8 „Dodawanie krawędzi” należy najpierw zdefiniować dane wejściowe, osobę odpowiedzialną za ten etap oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten etap na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Konfigurację należy przechowywać oddzielnie od kodu aplikacji. Pliki środowiskowe, magazyny tajemnic oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury. Zatwierdzenie przez człowieka powinno być wymagane dla krawędzi, które powodują wydatki lub zmieniają dane produkcyjne. Połączenia skompilowane w czasie kompilacji nie gwarantują pełnej kompletności biznesowej.
graph_builder.add_edge(START, "extract_name")
graph_builder.add_edge("extract_name", "planner")
def route_tools(state: PlayerState):
if state.selected_tools:
return state.selected_tools
return ["retrieve_goals"]
graph_builder.add_conditional_edges(
"planner",
route_tools,
{
"fetch_player_jersey_number": "fetch_player_jersey_number",
"fetch_player_information": "fetch_player_information",
"fetch_player_rating": "fetch_player_rating",
"retrieve_goals": "retrieve_goals"
}
)
graph_builder.add_edge("fetch_player_jersey_number", "retrieve_goals")
graph_builder.add_edge("fetch_player_information", "retrieve_goals")
graph_builder.add_edge("fetch_player_rating", "retrieve_goals")
graph_builder.add_edge("retrieve_goals", "retrieve_minutes_played")
graph_builder.add_edge("retrieve_minutes_played", "write_summary")
graph_builder.add_edge("write_summary", END)
graph = graph_builder.compile()
Etap 9: Uruchomienie agenta
W kroku 9, przed zmianą kodu, należy zdefiniować dane wejściowe, osobę odpowiedzialną za ten krok oraz kryteria zakończenia jego wykonywania. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg procesu, jak i ścieżki naprawcze. Próby ponownego wykonania, kontrolne punkty ludzkie oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później. Konieczne jest uzyskanie zatwierdzenia człowieka w przypadkach, gdy dochodzi do wydawania pieniędzy lub zmiany danych produkcyjnych. Połączenia realizowane w czasie kompilacji nie równają się pełnej kompletności rozwiązania biznesowego.
result = graph.invoke({
"question": "Will Haaland be able to win the FIFA World Cup for Norway based on his recent performance?"
})
print(result["summary"])
## Erling Haaland Performance Summary
- **Player:** Erling Haaland
- **Country:** Norway 🇳🇴
- **Club:** Manchester City
- **FIFA-style rating:** 92
- **Recent goals:** 28, 33, and 36 in the last three seasons
- **Total goals in last three seasons:** 97
- **Average minutes per goal:** Around 88 minutes per goal
Haaland’s individual numbers are outstanding. His scoring rate, consistency, and elite rating show that he is one of the most dangerous forwards in world football.
However, winning the FIFA World Cup depends on much more than one player. Norway would need strong squad depth, tactical discipline, defensive quality, and consistent performances throughout the tournament.
So, based on recent performance, Haaland can significantly improve Norway’s chances, but a World Cup title would still be difficult to predict from individual statistics alone.
result
Dlaczego ten przykład jest ważny
W etapie „Dlaczego ten przykład jest ważny” należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy dany krok zawiedzie, powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany proces. Konieczne jest ludzkie zatwierdzenie w przypadkach, gdy dochodzi do wydatków lub zmian w danych produkcyjnych. Połączenia realizowane w czasie kompilacji nie równają się kompletności rozwiązania biznesowego. W etapie „Dlaczego ten przykład jest ważny” należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić dany krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy proces przechodzi z wersji demonstracyjnej do środowiska współdzielonego.
1. Stan
Podczas przechodzenia przez etap 1 „Stan”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Ustaw punkty kontrolne po kosztownych krokach. Narzędzie do kontynuacji pracy nie powinno ponownie naliczać opłat za tę samą wywołanie LLM, gdy operator próbuje ponownie uruchomić późniejszy węzeł.
2. Wykorzystanie narzędzi
Gdy przechodzisz przez etap 2 „Użycie narzędzia”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponowne, kontrolne punkty ludzkie oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdego wywołania. Bez tego śladu debugowanie agenta trwa godzinami.
3. Planowanie
Podczas przechodzenia przez 3 etapy planowania, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co się dzieje w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Ustalaj punkty kontrolne po kosztownych krokach. System powinien unikać ponownego naliczania opłat za tę samą funkcję LLM, gdy operator próbuje ponownie uruchomić późniejszy element. Podczas przechodzenia przez 3 etapy planowania, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co się dzieje w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk.
4. Warunkowe routowanie
Faza 4 Conditional Routing działa najlepiej, gdy traktuje się ją jako mierzalną powierzchnię. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres badania. Trzymaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny poufnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całego schematu.
5. Ostateczne wnioski
Potencjalne ulepszenia
Ostateczne refleksje
Bardzo dziękuję za przeczytanie tego tekstu.
Jeśli chcesz pozostać w kontakcie lub zobaczyć więcej informacji o mojej pracy, możesz znaleźć mnie tutaj:
Listwa kontrolna operacyjna
Powiązane materiały
- Praktyczne notatki: Budowanie systemu przeglądania kodu multi-agentowego z LangGraph — Szczegółowy przewodnik po Praktycznych notatkach: Budowanie systemu przeglądania kodu multi-agentowego z LangGraph: kontrakty, sprawdzanie oraz miejsca na kod do wklejenia dla zespołów stosujących ten model.
- Praktyczne notatki: 10 frameworki agentów AI, które należy znać w 2026 roku: LangGraph — Szczegółowy przewodnik po Praktycznych notatkach: 10 frameworki agentów AI, które należy znać w 2026 roku: LangGraph: kontrakty, sprawdzanie oraz miejsca na kod do wklejenia dla zespołów stosujących ten model.