
안녕하세요
벌써 AI 마지막 날이네요,, 그리구 내일부터 3일간 휴일입니다!!!!!
그럼 아침 30분 과제 레츠고,
1. 왜 이걸 하는지 찾아봅니다
1.1 git 으로 올릴 때는 왜 add · commit · push 세 단계로 나눌까요?
> 작업을 선택하고(Add), 기록을 확정하며(Commit), 원격 서버에 공유하는(Push) 역할과 책임이 명확히 분리되어 있기 때문이다.
commit(커밋)은 파일이나 폴더의 변경 사항을 로컬 저장소에 영구적으로 기록하고 저장하는 행위이다.
2. 이 말들이 무슨 뜻인지 찾아봅니다
2.1 commit (커밋)
> commit(커밋)은 파일이나 폴더의 변경 사항을 로컬 저장소에 영구적으로 기록하고 저장하는 행위
깃(Git)에서 커밋(Commit)은 프로젝트의 '스냅샷(특정 시점의 상태)'을 남기는 것
마치 게임을 하다가 중요한 순간에 저장(Save)을 하는 것과 같다. 파일의 추가, 수정, 삭제 등 변경된 모든 내역이 커밋에 기록됨.
커밋을 할 때 메시지(Commit Message)를 함께 적는 이유 1) 변경 이유 기록 2) 원활한 협업 3) 버그 추적 및 관리
2.2 push (푸시)
> push(푸시)는 내 PC(로컬 저장소)에 있는 소스 코드나 파일의 변경 사항을 원격 서버(원격 저장소, 주로 GitHub 등)로 보내는 것
보통 내 PC에서 커밋(Commit)한 변경 사항을 인터넷이나 외부 네트워크에 있는 원격 저장소(Remote Repository)로 보낸다.
오늘의 순서
교시무엇만드는 파일
| 2교시 | 설정 분리 — 바뀌는 값은 파일 하나에 | config.json |
| 3교시 | 알림 연동 — 실패해도 멈추지 않게 | notifier.py |
| 4교시 | 하나로 잇기 — 명령 한 번에 끝까지 | pipeline.py |
| 5교시 | 코드 리뷰와 단위 테스트 | test_agent_core.py |
| 6교시 | 디버깅 — 에러가 있는 코드 고치기 | — |
| 7교시 | 완성과 회고 · 깃허브에 올리기 | docs/day08_retrospective.md |
설정 분리 — config.json
설정 분리
설정값을 분리하는 주요 방법은 설정의 규모와 보안 요구사항에 따라 나뉜다.
- config.py 파일 — 상수 정의
- 환경별 파일 분리 — Development / Production
- 외부 설정 파일 — YAML, JSON, INI
- 환경 변수 — os.environ, .env, python-decouple
코드와 설정(Configuration)을 분리하는 것은 프로그램의 유지보수성과 보안을 높이기 위한 핵심 설계 원칙.
하드코딩
프로그램 소스 코드 내부에 데이터나 값(상수, 파일 경로, API 키 등)을 직접 고정하여 입력하는 방식.
유지보수, 보안, 협업 등 다양한 측면에서 큰 불편함과 리스크가 발생한다.
- 유지보수가 힘들어진다.
- 보안에 치명적.
- 환경 변화에 유연하게 대처할 수 없음.
- 테스트하기 어려움.
왜 필요한가
지금 모델 이름은 llm_client.py 안에, 날짜는 노트북 셀 안에 박혀 있습니다.
하나 바꾸려면 코드를 뒤져야 합니다.
바뀔 수 있는 값을 config.json 한 파일로 모읍니다.
코드는 그대로 두고 이 파일만 바꿉니다.
이미 한 번 해 봤습니다 — API 키를 .env로 뺀 것입니다.
비밀은 .env, 비밀이 아닌 설정은 config.json에 둡니다.
2.1 바뀌는 값은 config.json에, 읽는 법은 json.load
with open("config.json", encoding="utf-8") as f:
config = json.load(f) # 읽으면 딕셔너리가 된다
print(config["model"]) # gemini-3.5-flash-lite
키값무엇을 정하나
| model | gemini-3.5-flash-lite | 어느 LLM을 부르나 |
| approve_severity | high | 어느 위험도부터 사람에게 확인받나 — 값이 아니라 정책이다 |
| report_folder | reports | 보고서를 어느 폴더에 모으나 |
| webhook_url | http://127.0.0.1:5001/alert | 알림을 어디로 보내나 |
파일담는 것깃허브에
| .env | 비밀 — API 키 | 올리지 않는다 |
| config.json | 설정 — 누가 언제 바꿨는지 남아야 하는 값 | 올린다 |
🐍 문법 상자 · 파이썬 딕셔너리와 JSON 파일은 조금 다릅니다
import json
print(json.dumps({"on": True, "url": None}))
# {"on": true, "url": null}
파이썬JSON 파일차이
| True · False | true · false | 소문자 |
| None | null | 이름이 다르다 |
| '작은따옴표'도 된다 | "큰따옴표"만 된다 | json.dump가 알아서 바꾼다 |
⚠ JSON 파일에는 주석(#)을 쓸 수 없습니다.
설명은 코드나 노트북에 둡니다.
🐍 문법 상자 · in은 딕셔너리의 키를 봅니다
config = {"model": "gemini-3.5-flash-lite"}
print(
"model" in config,
"webhook_url" in config,
"webhook_url" not in config
)
# True False True
쓰는 것결과뜻
| "model" in config | True | 그 키가 있다 |
| "webhook_url" not in config | True | 그 키가 없다 |
| 반복 안의 return | 그 자리에서 함수가 끝난다 | 빠진 키 하나를 찾으면 더 보지 않는다 |
⚠ "gemini-3.5-flash-lite" in config는 False입니다.
in은 값이 아니라 키를 봅니다.
🐍 문법 상자 · 위험도는 숫자로 바꿔 비교합니다
RANK = {
"low": 1,
"medium": 2,
"high": 3
}
print(RANK["high"] >= RANK["medium"])
print("high" >= "medium")
# True
# False
비교결과이유
| RANK["high"] >= RANK["medium"] | True | 3 ≥ 2 |
| "high" >= "medium" | False | 글자끼리는 사전 순서로 비교한다. h가 m보다 앞이다 |
⚠ 글자를 그대로 비교하면 뜻과 상관없는 결과가 나옵니다.
순위를 사전(RANK)으로 숫자로 바꾼 뒤 비교합니다.
한눈에
하려는 일쓰는 코드
| 설정을 저장한다 | json.dump(config, f, ensure_ascii=False, indent=2) |
| 설정을 읽는다 | config = json.load(f) → config["model"] |
| 빠진 키를 잡는다 | if key not in config: return None |
| 위험도를 비교한다 | RANK[severity.lower()] >= RANK[config["approve_severity"]] |
값은 파일에, 로직은 코드에 둡니다.
알림 연동 — 실패해도 멈추지 않게
웹훅 알림
웹훅(Webhook)은 특정 이벤트가 발생했을 때 HTTP POST 요청을 보내거나, 외부 서비스로부터 데이터를 받아 처리하는 방식.
파이썬의 requests 라이브러리를 사용해 디스코드나 슬랙 같은 플랫폼으로 웹훅 알림을 보내는 방법.
웹훅을 통해 슬랙이나 팀즈 같은 메신저에 알림을 보내는 방식은 HTTP POST 요청을 이용해 특정 웹훅 URL로 JSON 데이터를 전송하는 구조.
장애 허용
코드나 시스템의 일부에 오류(Exception, Crash, 네트워크 단절 등)가 발생하더라도, 전체 프로그램이 멈추지 않고 계속해서 동작하거나 안전하게 복구되도록 만드는 설계 방식.
한 부분의 에러나 장애가 전체 시스템의 중단으로 이어지지 않도록 하려면 장애 허용 아키텍처를 구축해야 한다.
왜 필요한가
보고서가 만들어져도 아무도 모르면 소용없습니다.
끝나면 담당자에게 알림을 보냅니다.
알림은 10/2에 만든 웹훅 서버로 보냅니다.
실무에서는 같은 자리에 슬랙 · 팀즈 · 메일 주소가 들어갑니다.
주소는 config.json에서만 바꾸면 됩니다.
알림 서버가 꺼져 있을 수 있습니다.
알림 하나 실패했다고 보고서까지 날아가면 안 됩니다.
9/28에 배운 try / except로 버팁니다.
3.1 알림 서버를 켜 둡니다
아래 셀을 실행해 alert_server.py를 만듭니다.
왼쪽 목록에서 agent_core 폴더를 오른쪽 클릭 › Open in Integrated Terminal을 누릅니다.
터미널에 입력합니다.
python alert_server.py
Running on http://127.0.0.1:5001이 보이면 그 터미널은 그대로 둡니다.
알림이 오면 여기에 [알림 받음]이 찍힙니다.
끌 때는 Ctrl + C입니다.
이런 글이 보이면이유할 일
| Address already in use | 10/2에 켠 서버가 아직 5001번을 쓰고 있다 | 그 터미널을 찾아 Ctrl + C |
| No module named 'flask' | 터미널에 가상환경이 켜지지 않았다 | 터미널을 닫고 2번부터 다시 |
%%writefile alert_server.py
from flask import Flask, request # 10/2 에 쓴 웹 서버 도구
app = Flask(__name__) # 서버를 하나 만든다
@app.route("/alert", methods=["POST"]) # /alert 로 POST 가 오면 아래 함수가 받는다
def alert(): # 알림을 받는 함수
data = request.get_json() # 보낸 JSON 을 딕셔너리로 꺼낸다
print("[알림 받음]", data["text"]) # 터미널에 알림 내용을 보여 준다
return {"ok": True} # 받았다고 답한다 (상태 코드 200)
app.run(port=5001) # 5001 번 포트에서 기다린다
🐍 문법 상자 · requests.post의 json=과 timeout=
response = requests.post(
url,
json={"text": "알림"},
timeout=5
)
print(response.status_code) # 200 — 받았다는 뜻
쓰는 것뜻
| url | 보낼 주소. 오늘은 config["webhook_url"]에서 꺼낸다 |
| json={"text": …} | 딕셔너리를 JSON으로 바꿔 요청 몸통에 담는다 |
| timeout=5 | 5초 안에 답이 없으면 기다리지 않고 에러를 낸다 |
⚠ timeout이 없으면 서버가 답을 주지 않을 때 셀이 끝나지 않고 멈춰 있습니다.
🐍 문법 상자 · except Exception as e — 에러를 잡아 이름 보기
try:
int("abc")
except Exception as e:
print("잡음:", type(e).__name__)
# 잡음: ValueError
쓰는 것잡는 것
| except ValueError: | 그 에러 하나만 |
| except Exception as e: | 거의 모든 에러. 잡은 에러가 e에 담긴다 |
| type(e).__name__ | 에러의 이름 — ValueError · ConnectionError |
⚠ 에러를 잡고 아무것도 안 하면 에러가 났다는 사실이 드러나지 않습니다.
[알림 실패]처럼 반드시 출력하거나 기록합니다.
🐍 문법 상자 · try 안의 return
def safe_int(text):
try:
return int(text)
except ValueError:
return None
print(safe_int("5"), safe_int("abc"))
# 5 None
들어온 값실행되는 곳리턴하는 값
| "5" | try 안의 return | 5 |
| "abc" | 에러가 나서 except 안의 return | None |
⚠ 실패해도 함수가 값을 리턴하므로, 부른 쪽은 멈추지 않고 다음 줄로 갑니다.
🐍 문법 상자 · "a" 모드는 뒤에 이어 씁니다
with open("alert_failures.log", "a", encoding="utf-8") as f:
f.write("[보고서] … 저장\n")
모드파일이 있으면오늘 쓰는 곳
| "w" | 지우고 새로 쓴다 | config.json · 보고서 |
| "a" | 뒤에 이어 쓴다 | 실패 기록 — 쌓여야 한다 |
⚠ "a"로 연 파일은 셀을 다시 실행할 때마다 줄이 늘어납니다.
줄 수가 2보다 많아도 맞습니다.
한눈에
하려는 일쓰는 코드
| 알림을 보낸다 | requests.post(url, json={"text": message}, timeout=5) |
| 실패를 잡는다 | try: … except Exception as e: |
| 무엇이 실패했나 | type(e).__name__ |
| 실패해도 이어 간다 | return False — 부른 쪽은 다음 줄로 간다 |
알림 하나가 실패해도 보고서는 남습니다.
실패는 숨기지 않고 출력합니다.
하나로 잇기 — pipeline.py
오케스트레이션
단순히 개별 작업을 자동화하는 것을 넘어, 여러 작업과 시스템의 실행 순서, 종속성, 조건문, 오류 복구 및 전체 워크플로 상태를 유기적으로 조율하고 관리하는 것.
엔트리 포인트
스크립트나 프로그램이 실행될 때 가장 먼저 코드가 시작되는 지점.
해당 파일의 첫 번째 줄(위쪽)부터 순서대로(위에서 아래로) 코드가 실행.
왜 필요한가
지금은 보고서 하나를 만들려면 노트북 셀을 순서대로 여러 개 눌러야 합니다.
하나 빠뜨리면 NameError가 납니다.
단계를 함수로 묶고, 함수 하나(run_pipeline)가 순서대로 부르게 합니다.
이것이 오케스트레이션입니다.
마지막에 pipeline.py 파일로 만들면 노트북 없이 터미널 명령 한 번으로 돕니다.
10/2에 배운 스케줄러로 매일 아침 돌릴 수도 있습니다.
4.1 run_pipeline이 단계를 차례로 부릅니다
run_pipeline("config.json", today)
├─ notifier.load_config 설정 읽기 · 검사
├─ run_report(events, today) 요약 → 정렬 → 총평 → 저장
├─ needs_approval 로 세기 사람 확인이 필요한 건수
└─ notifier.notify 알림 · 실패해도 계속
단계넘겨받는 것넘겨주는 것
| load_config | 파일 이름 | config 딕셔너리 |
| run_report | 경보 · 날짜 | {"filename": …, "summaries": …} |
| notify | 메시지 · 주소 | True / False |
앞 단계가 return한 값이 다음 단계의 입력입니다.
🐍 문법 상자 · print는 화면에, return은 다음 함수에
def show():
print("보고서 저장")
def give():
return "보고서 저장"
x = show()
y = give()
print(x, y)
# 보고서 저장
# None 보고서 저장
함수화면리턴하는 값
| show() | 보고서 저장 | None — 아무것도 넘기지 않는다 |
| give() | 없음 | "보고서 저장" — 변수에 담아 다음 함수에 넘길 수 있다 |
⚠ 함수 사이를 잇는 것은 return입니다.
print만 하면 다음 함수는 None을 받습니다.
🐍 문법 상자 · 값 여러 개는 딕셔너리 하나로 리턴합니다
def run():
return {
"filename": "daily_report_20261008.md",
"count": 6
}
result = run()
print(
result["filename"],
result["count"]
)
# daily_report_20261008.md 6
쓰는 것뜻
| return {"filename": …, "summaries": …} | 결과 두 개를 이름표를 붙여 한 번에 리턴한다 |
| result["filename"] | 받은 쪽에서 이름으로 꺼낸다 |
⚠ return은 한 번만 실행됩니다.
두 줄로 return a · return b를 쓰면 두 번째 줄은 실행되지 않습니다.
🐍 문법 상자 · if __name__ == "__main__": — 직접 실행할 때만
def run_pipeline(config_path, today):
...
if __name__ == "__main__":
run_pipeline(
"config.json",
str(date.today())
)
어떻게 쓰나__name__의 값아래 줄
| 터미널에서 python pipeline.py | "__main__" | 실행된다 |
| 노트북에서 import pipeline | "pipeline" | 실행되지 않는다 — 함수만 불러온다 |
| str(date.today()) | "2026-10-08" 꼴의 오늘 날짜 |
⚠ 이 줄이 없으면 import pipeline만 해도 LLM을 두 번 부르고 알림까지 보냅니다.
🐍 문법 상자 · 폴더 만들기와 경로 잇기
os.makedirs(
"reports",
exist_ok=True
)
print(
os.path.join(
"reports",
"daily_report_20261008.md"
)
)
# Windows: reports\daily_report_20261008.md
# Mac: reports/daily_report_20261008.md
쓰는 것하는 일
| os.makedirs(폴더, exist_ok=True) | 폴더를 만든다. 있으면 그냥 지나간다 |
| os.path.join(폴더, 파일) | 그 컴퓨터에 맞는 구분 기호로 경로를 잇는다 |
| shutil.copy(원본, 새 경로) | 파일을 복사한다 |
⚠ "reports/" + filename처럼 직접 이으면 Windows와 Mac에서 모양이 달라집니다.
os.path.join을 씁니다.
한눈에
단계함수파일
| 설정 읽기 · 검사 | load_config | notifier.py |
| 요약 → 정렬 → 총평 → 저장 | run_report | pipeline.py |
| 확인 건수 세기 | needs_approval | notifier.py |
| 알림 | notify | notifier.py |
| 전체 실행 순서 | run_pipeline | pipeline.py |
오전 산출물은 agent_core/config.json · notifier.py · pipeline.py입니다.
오후에는 이 코드를 리뷰하고, 테스트하고, 에러를 고칩니다.
코드 리뷰와 단위 테스트
코드 리뷰
다른 개발자가 작성한 코드를 체계적으로 검토하여 버그를 찾고, 코드 품질을 높이며, 유지보수성을 강화하는 과정.
다른 사람의 파이썬 코드를 리뷰할 때는 전체적인 구조(작동 여부)에서 시작해 점차 세부적인 스타일과 효율성으로 좁혀 나가는 것.
단위 테스트
코드의 가장 작은 단위(함수나 클래스 등)가 의도한 대로 정확히 동작하는지 자동으로 검증하는 방법.
파이썬의 내장 모듈인 unittest를 사용하면 함수가 올바르게 작동하는지 자동으로 검증할 수 있다.
왜 필요한가
코드가 돌아간다고 맞는 것은 아닙니다.
키가 코드에 적혀 있거나, 실패를 숨기는 코드도 잘 돕니다.
코드 리뷰 — 사람이 체크리스트로 한 줄씩 읽습니다.
매번 같은 항목을 보니 빠뜨리지 않습니다.
단위 테스트 — assert로 「이 입력이면 이 값이 나와야 한다」를 적어 둡니다.
코드를 고친 뒤 한 번 돌리면 망가진 곳을 바로 압니다.
5.1 리뷰 체크리스트 — 이 코드는 다섯 항목 가운데 어디를 어기나
from llm_client import read_api_key, parse_llm_json
api_key = read_api_key() # (가)
body = {
"model": "gemini-3.5-flash-lite",
"messages": messages
} # (나)
response = requests.post(
URL,
headers=headers,
json=body
) # (다)
judgment = parse_llm_json(
response.json()["choices"][0]["message"]["content"]
) # (라)
try:
requests.post(
"http://127.0.0.1:5001/alert",
json={"text": "완료"},
timeout=5
)
except Exception:
pass # (마)
항목확인할 것볼 줄
| 비밀 | API 키가 코드에 직접 적혀 있지 않은가 | (가) |
| 설정 | 모델 이름 · 주소가 config.json에서 오는가 | (나) |
| 검증 | LLM 답을 그대로 믿지 않고 확인하는가 | (라) |
| 실패 | 요청에 timeout이 있는가 | (다) |
| 기록 | 실패를 숨기지 않고 알리는가 | (마) |
🐍 문법 상자 · assert — 참이면 조용히, 거짓이면 멈춘다
assert 1 + 1 == 2, "1 + 1 은 2 여야 한다"
print("첫 번째 검사 통과")
assert 1 + 1 == 3, "1 + 1 은 2 여야 한다"
print("두 번째 검사 통과")
결과:
첫 번째 검사 통과
AssertionError: 1 + 1 은 2 여야 한다
쓰는 것결과
| assert 조건, "메시지" | 조건이 참이면 통과, 거짓이면 AssertionError: 메시지로 멈춘다 |
| assert 함수(입력) == 기대값 | 함수가 기대한 값을 리턴하는지 확인한다 — 이것이 테스트다 |
⚠ 메시지를 빼면 AssertionError만 보여서 무엇이 틀렸는지 모릅니다.
메시지에 「무엇이 어때야 하는지」를 씁니다.
🐍 문법 상자 · None인지는 is None으로 봅니다
result = None
empty = ""
print(
result is None,
empty is None,
result == empty
)
# True False False
값is None뜻
| None | True | 값이 없다 — parse_llm_json이 실패하면 리턴한다 |
| "" | False | 빈 문자열 — call_llm이 실패하면 리턴한다 |
⚠ None과 ""는 다른 값입니다.
어느 함수가 무엇을 리턴하는지 보고 비교합니다.
한눈에
방법하는 일쓰는 것
| 코드 리뷰 | 매번 같은 항목으로 코드를 읽는다 | 비밀 · 설정 · 검증 · 실패 · 기록 |
| 단위 테스트 | 입력과 기대값을 적어 두고 자동으로 확인한다 | assert 함수(입력) == 기대값, "메시지" |
| 테스트 파일 | 고칠 때마다 한 번에 확인한다 | python test_agent_core.py |
디버깅 — 에러가 있는 코드 고치기
디버깅
코드에 숨겨진 오류(버그)를 찾아내고 수정하는 과정.
- TraceBack 읽기
- 가설 설정 및 문제 범위 좁히기
- 중간값 확인하기(Print 디버깅)
트레이스백
프로그램 실행 중 예외(오류)가 발생했을 때, 오류가 발생하기까지 함수들이 호출된 경로(스택)를 역추적하여 보여주는 보고서.
트레이스백(Traceback) 에러 메시지는 아래에서 위로 읽어야됨.
왜 필요한가
지금까지 에러가 나면 정답을 봤습니다.
캡스톤에서는 정답이 없습니다.
원인은 에러 메시지에 적혀 있습니다.
에러는 세 종류입니다.
- 문법 에러 — 실행 전에 막힌다
- 실행 에러 — 실행 중에 멈춘다
- 논리 에러 — 멈추지 않고 틀린 결과를 낸다
6교시 문제는 모두 에러가 있는 코드로 시작합니다.
먼저 그대로 실행해 무엇이 보이는지 읽고, 고칩니다.
6.1 에러가 나면 마지막 줄부터 읽습니다
순서할 일
| 1 | 마지막 줄의 에러 이름과 내용을 읽는다 — KeyError: 'sevrity' |
| 2 | 그 위의 줄 번호로 가서 그 줄을 본다 |
| 3 | 에러가 없는데 결과가 이상하면 의심 가는 줄 위에 print("[디버그]", 값)을 넣는다 |
| 4 | 고친 뒤 다시 실행해 기대한 결과와 비교한다 |
🐍 문법 상자 · 에러의 세 종류
def make_title(today) # 문법 에러 (syntax error) — 한 줄도 실행되지 않는다
print(judgment["sevrity"]) # 실행 에러 (runtime error) — 위 줄까지는 돌고 여기서 멈춘다
if level == "high": # 논리 에러 (logic error) — 에러 없이 틀린 결과가 나온다
종류에러 메시지찾는 법
| 문법 에러 (syntax error) | SyntaxError — 실행 전에 나온다 | ^ 표시가 가리키는 자리를 본다 |
| 실행 에러 (runtime error) | KeyError · NameError 등 | 마지막 줄의 에러 이름과 줄 번호를 본다 |
| 논리 에러 (logic error) | 없음 | print로 실제 값을 찍어 기대와 비교한다 |
⚠ 세 번째가 가장 위험합니다.
에러가 없어서 틀린 보고서가 그대로 나갑니다.
그래서 5교시에 테스트를 붙였습니다.
🐍 문법 상자 · 에러 메시지는 아래에서 위로 읽습니다
함수 안에서 에러가 나면 트레이스백(Traceback · 트레이스백 · 에러가 난 길)이 두 덩어리로 나옵니다.
KeyError Traceback (most recent call last)
Cell In[1], line 8
7 for j in judgments:
----> 8 lines = lines + make_line(j) + "\n"
Cell In[1], line 2, in make_line(j)
1 def make_line(j):
----> 2 return f"- [{j['sevrity']}] {j['rule']} → {j['tool']}"
KeyError: 'sevrity'
읽는 순서보는 것위 예에서
| ③ 맨 아래 줄 | 에러 이름과 문제가 된 값 | KeyError: 'sevrity' — 그런 키가 없다 |
| ② 바로 위 덩어리 | 실제로 멈춘 줄 — 대개 여기를 고친다 | make_line의 2번째 줄 |
| ① 맨 위 덩어리 | 그 함수를 부른 줄 | 반복문의 8번째 줄 — 여기는 잘못이 없다 |
마지막 줄뜻먼저 볼 곳
| KeyError: 'sevrity' | 딕셔너리에 그 키가 없다 | 키 이름의 철자 |
| NameError: name 'x' is not defined | 그 이름을 만든 적이 없다 | 그 줄이 있는 함수 안에서 만들었거나 받았는지 |
| SyntaxError: expected ':' | 문법이 틀렸다 | ^가 가리키는 자리 |
⚠ ----> 8의 화살표가 그 덩어리에서 멈춘 줄입니다.
Cell In[1], line 8은 셀 안의 8번째 줄이라는 뜻입니다.
🐍 문법 상자 · print로 실제 값 찍어 보기
level = " high"
print("[디버그]", level)
print(f"[디버그] [{level}]")
결과:
[디버그] high
[디버그] [ high]
할 일쓰는 것
| 의심 가는 줄 바로 위에 값을 찍는다 | print(f"[디버그] [{변수}]") |
| 기대한 값과 글자 하나씩 비교한다 | [high]를 기대했는데 [High] · [ high]가 찍혔다 |
| 고친 뒤 assert로 다시 생기지 않게 막는다 | assert high_count == 4, "high 건수가 다르다" |
⚠ 대소문자는 .lower(), 앞뒤 공백은 .strip()으로 맞춥니다.
둘을 이어 쓸 수 있습니다.
값.strip().lower()
한눈에
종류보이는 것오늘 고친 것
| 문법 에러 | SyntaxError — 한 줄도 안 돈다. 하나를 고치면 다음 것이 나온다 | def 끝의 : · 닫지 않은 괄호 |
| 실행 에러 | KeyError · NameError — 트레이스백이 두 덩어리로, 아래 덩어리가 멈춘 줄 | 함수 안의 키 철자 · 함수가 받지 않은 이름 |
| 논리 에러 | 에러 없이 틀린 값 | .strip().lower() · >= · 정렬 순서 · \n |
고친 뒤에는 5교시처럼 assert를 붙여 같은 에러가 다시 생기면 바로 멈추게 합니다.
완성과 회고
회고
과거의 경험을 돌아보고 더 나은 방향으로 나아갈 방법을 찾는 과정.
개발 팀이 회고(Retrospective)를 진행할 때 작성하는 내용은 단순히 ‘무엇을 했다’는 보고가 아니라, ‘우리 팀이 어떻게 하면 더 잘 일할 수 있을까?’에 대한 논의와 액션 플랜이다.
장애 허용
코드나 서버 일부에 에러나 중단이 발생해도, 전체 프로그램이 멈추지 않고 계속 실행되거나 안전하게 복구되도록 만드는 설계 방식.
장애 허용(Fault Tolerance) 아키텍처를 설계해야한다.
왜 필요한가
1과목의 마지막 시간입니다.
만든 것을 처음부터 끝까지 한 번 더 돌려 봅니다 — 정상일 때, 알림 서버가 꺼졌을 때.
8일 동안 무엇이 어려웠는지는 오늘이 아니면 잊습니다.
캡스톤에서 막힐 때 다시 열어 볼 기록을 남깁니다.
마지막으로 오늘의 산출물을 깃허브에 올립니다.
7.1 알림 서버를 켜고 시작합니다
오전 3.1처럼 agent_core 폴더를 오른쪽 클릭 › Open in Integrated Terminal을 누릅니다.
터미널에 입력합니다.
python alert_server.py
그 터미널은 그대로 둡니다.
오전에 켠 서버가 아직 떠 있으면 Address already in use가 나옵니다.
그때는 켜진 그대로 쓰면 됩니다.
오늘 확인할 것문제
| 명령 한 번으로 보고서 → 알림까지 간다 | 7-2 |
| 알림 서버가 꺼져도 보고서는 남는다 | 7-3 |
| 설정만 바꾸면 코드를 고치지 않아도 동작이 바뀐다 | ⭐7-6 |
🐍 문법 상자 · %%writefile로 다른 폴더에 저장하기
%%writefile ../docs/day08_retrospective.md
# 1과목 회고 (이름)
경로뜻
| day08_retrospective.md | 지금 폴더(agent_core) 안 |
| ../docs/day08_retrospective.md | 한 칸 위(security-agent-toolkit)의 docs 폴더 안 |
⚠ docs 폴더가 없으면 저장되지 않습니다.
바로 위 셀이 폴더를 먼저 만듭니다.
한눈에
확인한 것어떻게
| 명령 한 번으로 끝까지 | pipeline.run_pipeline("config.json", 날짜) |
| 알림이 실패해도 보고서는 남는다 | config_off.json — 주소만 바꿨다 |
| 설정이 동작을 바꾼다 | config_low.json — 기준만 바꿨다 |
| 기록 | docs/day08_retrospective.md |
1과목에서 만든 것
파일하는 일만든 날
| llm_client.py | LLM을 부르고 답을 JSON으로 읽는다 | 10/6 |
| event_summarizer.py | 경보를 묶음으로 요약하고 위험도순으로 정렬한다 | 10/7 |
| report_generator.py | 총평을 받고 보고서를 만든다 | 10/7 |
| config.json | 모델 · 정책 · 폴더 · 알림 주소 | 10/8 |
| notifier.py | 설정을 검사하며 읽고, 알림을 보낸다. 실패해도 멈추지 않는다 | 10/8 |
| pipeline.py | 위 모두를 명령 한 번으로 잇는다 | 10/8 |
| test_agent_core.py | 고칠 때마다 망가진 곳이 없는지 본다 | 10/8 |
와 드디어 AI자동화 기초가 끝났습니다..
다음주부터는 네트워크를 들어가게 됐는데 설레구,,내일부터 쉬는날이라 기쁘네요
그럼 아됴
'공부 > SKT ALEPH' 카테고리의 다른 글
| AI·자동화 기초(에이전트·API·스크립팅) - 8 (0) | 2026.10.07 |
|---|---|
| AI·자동화 기초(에이전트·API·스크립팅) - 7 (0) | 2026.10.06 |
| AI·자동화 기초(에이전트·API·스크립팅) - 6 (0) | 2026.10.02 |
| AI·자동화 기초(에이전트·API·스크립팅) - 5 (0) | 2026.09.30 |
| AI·자동화 기초(에이전트·API·스크립팅) - 4 (0) | 2026.09.29 |
