3. 고쳐도 안 깨지는 코드
아홉 영역 규칙표
이 차시를 마치면
아홉 개 영역별로 무엇을 지키고 무엇을 바꿔도 되는지 찾아봅니다.
아홉 개 영역마다 A, B, C 를 정리했습니다. 코드를 고치기 전에 해당 영역 표를 먼저 봅니다.
1. State
State 는 그래프의 현재 스냅샷입니다. 공식 Graph API 의 핵심 구성요소는 State, Nodes, Edges 입니다.
| 구분 | 내용 |
|---|---|
| A | Node 와 routing 이 참조하는 key 이름 일치 · Reducer 를 붙인 필드는 의미를 이해하고 변경 · 운영 시스템에서는 기존 Checkpoint 와의 호환을 신중히 검토 |
| B | 목적에 맞는 field 추가 · field 이름 변경(단, 전체 참조를 함께 수정) · TypedDict 대신 dataclass 나 Pydantic 사용 여부 |
| C | 한 파일에서 query, 다른 파일에서 question 처럼 이름만 바꾸기 · Reducer 를 이해하지 않고 삭제 · 병렬 업데이트되는 필드를 단순 overwrite 로 변경 · Checkpoint 호환성 검토 없이 type 변경 |
설계 질문 세 가지 — ① 다음 Node 가 정말 이 값을 필요로 하는가? ② 계산해서 다시 만들 수 있는 값을 굳이 State 에 저장하는가? ③ 대용량 원문 대신 ID 나 reference 만 저장할 수 있는가?
2. Tools
Tool 은 LLM 과 Agent 가 외부 기능을 사용하도록 연결하는 함수입니다. 검색, 계산, DB 조회, API 요청, 파일 읽기가 여기 해당합니다.
from langchain.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two integers."""
return a * b
| 구분 | 내용 |
|---|---|
| A | Tool 입출력 contract · 실제 side effect 가 있는지 명확하게 구분 · Tool description 을 실제 기능과 일치 |
| B | Tool 이름 · description · 내부 API · return shape(단, caller 와 schema 를 함께 변경) |
| C | read-only Tool 을 write Tool 로 몰래 변경 · 설명은 '조회'인데 내부에서 삭제나 수정 수행 · Agent 가 의존하는 argument 이름을 다른 곳 수정 없이 변경 |
실무 권장 — Tool 에 business logic 전체를 넣지 않고 얇게 유지하면 테스트가 쉬워집니다.
3. Nodes
| 구분 | 내용 |
|---|---|
| A | 입력으로 State schema 를 따름 · 반환 키가 State schema 와 일치 · Node 의 side effect 를 명확히 함 |
| B | 내부 알고리즘 · 호출 model · prompt · helper function |
| C | 반환해야 하는 키를 제거하면서 downstream Node 를 수정하지 않음 · 하나의 Node 에 여러 책임을 계속 추가 · Interrupt 이전에 되돌릴 수 없는 side effect 추가 |
좋은 Node 이름 — retrieve_documents, grade_documents, rewrite_query, generate_answer, approve_answer, save_answer
피해야 할 Node — retrieve_grade_rewrite_generate_save_send()
4. Routing
| 구분 | 내용 |
|---|---|
| A | 반환되는 route 이름이 실제 등록된 Node 이름과 일치 · 모든 가능한 branch 처리 · loop 에는 종료 조건이 존재 |
| B | threshold · routing criteria · branch 추가와 삭제(그래프와 test 를 함께 수정) |
| C | router 가 "retry" 를 반환하는데 그래프에 retry Node 가 없는 상태 · max retry 제거 · 정상 Edge 와 dynamic routing 을 같은 Node 에서 무분별하게 혼합 |
공식 Graph API 문서는 한 Node 에서 routing mechanism 을 명확히 선택하도록 권고하며, 정적 Edge 와 dynamic routing 을 섞으면 둘 다 실행될 수 있어 추론이 어려워질 수 있다고 설명합니다. 확인 필요 해당 문서는 이번 작업에서 접속 확인하지 않았습니다.
5. Graph
| 구분 | 내용 |
|---|---|
| A | 등록된 Node 이름과 Edge 및 routing 반환값 일치 · START 와 종료 조건 존재 · Persistence 나 HITL 이 필요하면 compile 시 Checkpointer 설정 |
| B | Node 순서 · branch · subgraph 구성 · Checkpointer implementation |
| C | Node 함수 이름만 바꾸고 graph 등록을 그대로 둠 · HITL 그래프에서 Checkpointer 제거 · 실제 사용 중인 Thread semantics 를 검토하지 않고 Persistence 제거 |
6. Schemas / Structured Output
| 구분 | 내용 |
|---|---|
| A | downstream code 가 기대하는 schema · validation 범위 |
| B | field description · optional field · Pydantic, TypedDict, dataclass 선택 |
| C | DB 나 API 계약에 쓰는 필드를 migration 없이 이름 변경 · validation 을 이유 없이 제거 · Structured Output 을 갑자기 자유형 text 로 바꿔 downstream parsing 을 깨뜨림 |
7. Prompts
Prompt 는 graph topology 보다 자주 수정되는 영역입니다. 그래서 이 영역만 3단으로 나눕니다.
| 구분 | 내용 |
|---|---|
| B — 바꿔도 되는 것 | 문체 · 설명 수준 · few-shot example · 역할 설명 |
| 주의해서 바꿀 것 | classification label · Structured Output 필드와 연결되는 지시 · Tool 사용 조건 · safety rule |
| C | 시스템이 의존하는 label 을 설명 없이 변경(예: PASS/FAIL → YES/NO) · prompt 에서는 JSON 을 요구하면서 schema 는 다른 필드를 요구 |
safety rule 이 "주의" 칸에 있다는 점이 중요합니다. 앞 차시의 A-2 와 함께 읽으면, prompt 안의 safety rule 은 문체가 아니라 계약으로 다뤄야 합니다. 분석
8. Config / Environment
{
"dependencies": ["."],
"graphs": {
"main": "./src/my_agent/graph.py:graph"
},
"env": ".env"
}
| 구분 | 내용 |
|---|---|
| A — 절대 하면 안 되는 것 | API 키를 Git 에 commit · production 키를 예제 코드에 하드코딩 · 실제 graph export path 와 langgraph.json 경로 불일치 |
| B | graph 이름 · env file 위치 · dependency 방식 — 단, 실제 파일 구조와 함께 수정 |
9. Tests
LLM app 은 prompt 만 바꿔도 다른 부분이 깨질 수 있습니다.
| 층 | 대상 |
|---|---|
| Unit test | Tool, router, helper |
| Graph test | 특정 입력이 예상 경로를 타는지 |
| Integration test | LLM, DB, API 와 실제 연결 |
| Evaluation test | 정답 품질, groundedness, Tool 선택 |
def test_router_sends_high_score_to_generate():
state = {"relevance_score": 0.9}
assert route_after_grade(state) == "generate"
| 구분 | 내용 |
|---|---|
| A | 핵심 business rule 을 검증하는 regression test |
| B | 테스트 프레임워크 · fixture 구조 |
| C | 실패하는 테스트를 원인 수정 없이 삭제해서 'PASS' 로 만드는 것 |
이 차시의 파이썬 코드는 개념을 보이려고 떼어 놓은 예시 조각입니다. 문법 검사는 통과하지만 그대로 돌려서 결과를 확인한 코드는 아닙니다. 실행까지 검증한 코드는 4번과 6번 트랙에 있으며, 그 차시에는 무엇을 어떻게 확인했는지 따로 적어 두었습니다.