일보 작성 후 준비로 연결하기
지금까지는 Jeff를 사용해 조명 조작을 선택하는 예나, Clef를 사용해 이미지 속 고양이를 판단하는 예 등을 시도해 왔습니다.
이번에는 영업 일보에서 다음 액션 후보들을 정리해 보겠습니다.
사용할 것은 공개 가중치(open weights)의 판단 모델인 「Kev」입니다.
예를 들어, 일보에 다음과 같이 작성되었다고 가정하겠습니다.
A사를 방문했다. 제품에는 흥미가 있지만, 기존 CRM과 연동이 가능한지 걱정된다고 한다. 현장 IT 담당자를 포함하여 다음 주 기술적인 설명을 듣고 싶다. CRM의 제품명과 버전은 아직 불분명하다. 가격 이야기는 나오지 않았다.
이 일보를 통해 「기술 미팅 조율하기」「기술 담당자에게 협력 요청하기」「기존 시스템명 및 버전 확인하기」와 같은 후보들을 얻을 수 있다면, 다음 날 준비에 활용할 수 있을 것 같습니다.
일보 8건을 준비하고 각각에 대해 4가지 질문을 주었습니다.
이번에는 Google Colab의 CPU로 모델 로드부터 판단, 결과 저장까지 실행할 수 있었습니다.
GPU를 사용하지 않고 시도해 볼 수 있기 때문에, 무료 Colab에서 Decision Model을 체험하는 교재로 구성하기 좋습니다.
한편, 데모 요청을 놓치거나 「견적 준비하기」라고 답하면서도 준비 자료는 「지금은 준비하지 않는다」고 답하는 경우 등도 있었습니다.
작동한 부분과 아직 사람의 확인이 필요한 부분을 실제 출력과 함께 소개하겠습니다.
이번에 만들 것
만드는 것은 담당자가 확인하기 위한 「다음 액션 후보 목록」입니다.
| 일보에서 판단하는 항목 | 선택 후보 예시 |
|---|
| 다음 액션 | 기술 미팅, 견적서, 사내 설명 자료, 제품 데모, 연락 대기, 다음 대응 확인 |
| ... | |
| 후보는 프로그램으로 정의합니다. | |
Kev는 일보와 후보 설명을 읽고 어떤 후보를 선택할지 판단합니다.
메일 전송이나 일정 등록은 하지 않습니다.
이번 실험에서 추가 학습은 진행하지 않았습니다.
회사명과 일보는 모두 교재용으로 작성한 가상의 것이며, 실존 기업의 상담 기록이 아닙니다.
Kev는 어떤 모델인가요
Kev에는 상황을 나타내는 state와 그 상황에 대한 질문을 전달합니다.
이번의 state는 한 회사 분량의 일보입니다.
질문마다 선택된 후보와 후보별 확률을 받습니다.
공식 모델 카드에서는 Kev-0.8B가 Qwen3.5-0.8B-Base를 기반으로 하며, LoRA와 후보를 채점하는 포인터 헤드(pointer head)를 사용하는 모델로 설명되어 있습니다.
문장을 순차적으로 생성하기보다는 입력에 포함된 후보들을 채점하는 방식입니다.
모델 카드에는 어댑터, 헤드, 베이스 모델의 라이선스가 Apache-2.0으로 기재되어 있습니다.
API에는 Choice, Score, Noul이라는 타입이 있습니다.
이번에는 후보 중에서 선택하는 choice만 사용합니다.
같은 일보에 대해 4가지 질문을 모아서 보냅니다.
일반적인 LLM(대규모 언어 모델)으로도 일보에서 다음 액션을 문장으로 작성하게 할 수는 있습니다.
이번에 시도하고 싶은 것은 미리 정해둔 업무 후보의 ID와 확률을 받아 그대로 표나 후속 처리에 전달하는 사용 방식입니다.
자유 형식 답변에서 「이것은 기술 상담일 것이다」라고 읽어내는 처리 과정을 출력 후에 추가할 필요가 없습니다.
다만, 후보 형식을 지켜서 반환할 수 있는 것과 적절한 후보를 선택할 수 있는 것은 별개입니다.
실제 결과에서도 이 차이가 보였습니다.
한국어 표시와 영어 모델 입력 분리하기
Kev-0.8B의 공식 대상 언어는 영어입니다.
따라서, 이 교재에서는 영어 일보를 모델에 전달하고, 한국어 번역을 화면에 표시합니다.
report = {
"id": "S01",
"company": "A사",
...
이것은 데이터 구조를 설명하기 위한 짧은 예시입니다.
실행용 샘플에서는 한국어 번역도 생략하지 않고 넣었습니다.
모델에 보내는 것은 report_en이며, 회사명, 한국어 번역, 교재 작성자가 기대하는 답은 보내지 않습니다.
자동 번역 처리도 넣지 않았습니다.
한국어를 그대로 전달하는 실험은 할 수 있지만, 이번 결과를 한국어 일보의 성능으로 소개할 수는 없습니다.
이 기사에서 확인하는 것은 영어 입력에 대한 판단과 한국어 업무 화면에 대한 표시입니다.
실행한 환경
실행된 노트북에 기록된 환경은 다음과 같습니다.
| 항목 | 실행 시 값 |
|---|
| 실행 장소 | Google Colab |
| ... | |
PyTorch 이름에 cu126이 붙어 있지만, 이는 CUDA 대응 배포 패키지를 설치했기 때문입니다. | |
| GPU로 계산했다는 의미가 아닙니다. | |
이번 모델 실행지는 cpu였습니다.
노트북의 출력만으로는 CPU 제품명이나 사용 플랜, 최대 RAM 사용량을 확인할 수 없습니다.
여기서는 'Colab의 CPU로 실행할 수 있었다'는 기록을 바탕으로 GPU를 사용하지 않는 절차를 소개합니다.
무료 버전에서도 시도해 볼 수 있는 구성이지만, 이용 가능한 자원이나 실행 시간에는 제한이 있습니다.
모델은 Colab에 다운로드하여 실행합니다.
외부 추론 API는 사용하지 않으며, 통상적으로 API 키나 Hugging Face 토큰도 필요 없습니다.
모델 제공자에게 추론 API 비용은 발생하지 않습니다.
Colab에서 위에서부터 실행하기
새로운 Colab 노트북을 열고, '런타임'에서 '런타임 유형 변경'을 선택합니다.
하드웨어 가속기는 '없음'으로 진행합니다.
Python은 3.12 또는 3.13을 사용합니다.
이 기사의 끝에 실행용 전체 셀을 게재했습니다.
각 접힌 부분을 열고, 코드를 별도의 Colab 셀에 붙여넣어 위에서부터 순서대로 실행할 수 있습니다.
본문에서는 해당 코드의 역할을 발췌하여 설명합니다.
본문의 발췌 내용과 끝의 전체 코드를 중첩해서 실행할 필요는 없습니다.
처리는 다음 순서입니다.
- 전용 Python 환경을 준비한다.
- 일보와 질문 후보를 정의한다.
- Kev를 한 번만 로드한다.
- 1건의 일보로 입력과 출력을 확인한다.
- 8건을 목록으로 만든다.
- 자신의 일보를 수정하여 시도한다.
- 기사용 결과를 ZIP에 저장한다.
전용 Python 환경 준비하기
Kev가 필요로 하는 라이브러리와 Colab에 처음부터 들어있는 라이브러리의 간섭을 줄이기 위해, 모델용 전용 환경을 만듭니다.
일반적인 Colab 셀은 표시와 저장을 담당하고, 모델은 다른 Python 프로세스에서 구동합니다.
모델과 공식 코드의 버전도 고정합니다.
MODEL_SIZE = "0.8b"
MODEL_ID = "jaredpalmer/kev-" + MODEL_SIZE
MODEL_REVISION = "bf75a6a8848ea6960ff2ed108d9ed44c2941174f"
...
모델의 리비전과 코드의 커밋은 별도의 식별자입니다.
리포지토리 업데이트에 따라 나중에 다른 가중치나 구현을 가져오지 않도록 합니다.
의존성 설치 시에는 전용 환경의 Python을 지정합니다.
다음은 실행용 코드에서 발췌한 내용입니다.
install([
PYTHON, "-m", "pip", "install", "-q",
"kev @ git+https://github.com/jaredpalmer/kev.git@" + CODE_REVISION,
...
install()은 처리명을 표시하고 오류의 상세를 로그에 남기는 보조 함수입니다.
첫 실행 시 라이브러리와 모델을 가져오는 데 시간이 걸립니다.
이번 약 32.2초라는 로딩 시간에는, 설치 셀의 실행 시간은 포함하지 않았습니다.
또한, 로딩 처리 중 다운로드가 포함될 수 있으므로, 순수한 가중치 전개 속도와는 구분합니다.
모델을 매번 로드하지 않기
일보 1건을 판단할 때마다 모델을 로드하면, 그 대기 시간이 반복적으로 발생합니다.
이번에는 모델을 로드한 프로세스를 남겨서 사용합니다.
공식의 로딩 처리는 보조 프로세스 내에서 다음과 같이 호출하고 있습니다.
checkpoint = Checkpoint(model_reference)
tokenizer, model = checkpoint.load(
device,
...
이것은 0.8B 버전의 로드 부분을 설명하는 발췌입니다.
실행용 코드에서는 체크포인트에 기록된 온도를 그대로 사용하고, 확률을 독자적으로 보정하지 않습니다.
속도 향상을 위한 추가 커널이 필수적이지 않은 구성입니다.
노트북의 KevClient는 JSON을 표준 입력으로 보내고, 모델의 JSON 출력을 받는 보조 클래스입니다.
여기서 다루는 '통신'은 Colab 내 Python 프로세스 간의 주고받음입니다.
일보를 외부 추론 서비스로 보내는 처리가 아닙니다.
이번 출력에서는 8건 모두에서 모델의 프로세스 ID가 2985였습니다.
로드된 모델을 재활용할 수 있었습니다.
일보와 선택 후보 전달하기
질문은 instructions, 후보는 criteria에 작성합니다.
예를 들어, '다음 액션'은 다음 정의입니다.
{
"type": "choice",
"instructions": (
...
A부터 F는 후보의 식별자입니다.
그 뒤의 영어 설명이 후보 의미를 설명하고 있습니다.
같은 글자가 다른 질문에서도 나오지만, 질문마다 다른 후보입니다.
예를 들어, 준비 자료의 A는 '연계 설명 자료'를 가리킵니다.
후보를 준비하는 것은 사람이고, 후보를 선택하는 것은 모델입니다.
여기서는 새로운 영업 활동을 자유롭게 구상하게 하는 것이 아닙니다.
기존 업무에 대응하는 후보를 정의하고, 그중 어떤 것이 일일 보고서와 맞는지 조사하고 있습니다.
후보 설계에는 '요청이 없는데도 멋대로 다음 일정을 잡지 않는 것'도 필요합니다.
따라서 다음 대응이 미결정인 경우나 관계자의 희망이 엇갈리는 경우의 후보를 넣었습니다.
모델이 그 후보를 올바르게 사용하는지는 별도로 확인합니다.
하나의 요청에 네 가지 질문을 모으기
표시명과 영어 후보 설명을 SPECS라는 딕셔너리에 모았습니다.
다음 함수는 이 정의로부터 실제 입력 JSON을 만듭니다.
def make_request(report_en):
if not isinstance(report_en, str) or not report_en.strip():
raise ValueError("report_en에 영어 일일 보고서를 입력해 주세요.")
...
이 함수에는 '일일 보고서에 CRM이라는 단어가 있으면 기술 담당자로 한다' 같은 판별 규칙은 없습니다.
단순히 일일 보고서와 선택 후보를 조합할 뿐입니다.
또한, 교재 작성자의 기대 예시를 모델에게 전달하는 처리도 없습니다.
실행용 셀에서는 판정 전에 JSON 전체를 표시합니다.
print(json.dumps(
make_request(REPORTS[0]["report_en"]),
sure_ascii=False,
...)
어떤 문장과 후보로 모델을 호출했는지 확인할 수 있도록 했습니다.
후보별 확률 받기
보조 프로세스에서는 공식 API 형식을 모델 내부 형식으로 변환하여, 후보를 채점합니다.
다음은 핵심 부분의 발췌입니다.
request = SystemOneRequest(**request_json)
record, metadata = to_record(request)
encoded = model.encode(
...
strict=True로 설정했기 때문에, 너무 긴 일일 보고서를 조용히 잘라내지 않고 에러를 발생시킵니다.
이번에는 회사당 한 건의 짧은 일일 보고서를 상정하고 있습니다.
model.probs()가 판단용 헤드(head) 출력에서 확률을 계산하고, to_answers()가 후보 ID 등을 붙인 형태로 되돌립니다.
표준 generate()로 설명문을 생성하고 거기서 답을 추출하는 처리가 아닙니다.
4문제를 1 요청에 모았지만, 내부적으로 몇 번의 순전파(forward propagation)가 될지는 구현이나 분할 방식에 따라 다릅니다.
'반드시 물리적으로 1회의 계산만으로 4문제가 끝난다'고 설명하지 않습니다.
공유된 일일 보고서에 대해 질문별 후보를 채점하는 구성입니다.
첫 번째 건 시도하기
준비가 되면 A사의 일일 보고서를 전달합니다.
first = decide_report(REPORTS[0])
show_detail(first)
decide_report()는 입력 JSON을 만들고, 로드된 모델에 전달하여 입출력을 저장하는 함수입니다.
show_detail()은 각 후보의 확률을 표시합니다.
A사의 실제 결과는 다음과 같았습니다.
| 질문 | 선택된 후보 | 선택 확률 |
|---|
| 다음 액션 | 기술 회의 조정 | 54.51% |
| ... | | |
| 기술 회의와 기술 담당자, 기존 시스템 확인은 일일 보고서 내용과 일치합니다. | | |
반면, 준비 자료에서는 기대했던 '연계 설명 자료'를 선택할 수 없었습니다.
'협력을 부탁하는 상대'는 37.24%로 다른 후보보다 높기 때문에 선택되었습니다.
이 교재는 50%가 넘으면 채택하는 설계가 아니라, 후보 중에서 가장 높은 확률을 가진 것을 표시합니다.
선택된 후보의 확률을 그대로 정답률이나 성약률(成約率)로 읽을 수는 없습니다.
8건을 액션 후보 목록으로 만들기
첫 번째 건의 결과는 그대로 사용하고, 나머지를 순차적으로 판정합니다.
records = [first]
for report in REPORTS[1:]:
print(report["id"], report["company"] + "를 판정 중…", flush=True)
...
준비된 일일 보고서는 다음 8건입니다.
⚠️ [IMG:N] 형식 토큰은 이미지 placeholder 입니다. 번역하지 말고 원래 위치에 그대로 유지하세요.
| ID | 일보 내용 |
|---|
| S01 | 기존 CRM과의 연동에 대한 기술 설명을 희망 |
| ... | |
| 다음 그림은 이번 실행된 노트북의 표시 결과를 표로 다시 그린 것입니다. | |
모델을 재실행하여 만든 결과가 아닙니다.
옅은 주황색은 교재에서 예상한 답과 다른 부분입니다.
'다음 액션'만 추출했을 때, 다음 결과였습니다.
C사의 사내 설명 자료 요청, E사의 연락 자제 요청, F사의 정보 부족은 4개 항목 모두 기대 예시에 부합했습니다.
G사에서는 처음에 나온 기술 상담이 아니라 마지막에 합의한 견적을 선택할 수 있습니다.
H사도 다음 액션에 대해서는 '다음 대응 확인'을 선택했습니다.
다음 액션은 8건 중 7건, 4문항을 맞추자 32개 항목 중 25개 항목이 교재 작성자의 기대 예시와 일치했습니다.
다만, 이 8건은 질문 문구를 조정할 때 사용한 예시입니다.
독립적인 평가용 데이터가 아니므로, 이 수치를 영업일보 일반의 정확도로 간주할 수는 없습니다.
데모 요청을 놓침
D사의 일보에는 다음 미팅에서 제품 데모를 희망한다고 명기되어 있습니다.
한편, 데모로 시도하고 싶은 업무의 상세 내용은 미확인입니다.
모델은 '추가 확인 사항'에서는 '데모로 시도할 업무'를 선택했지만, '다음 액션'은 '다음 대응 확인'이었습니다.
'데모는 진행하기로 결정되었고, 상세 내용만 미확인'이라는 구분을 기대했던 형태로 처리하지 못했습니다.
자유 입력 셀에서도 다음 짧은 영어 문구로 시도해 보았습니다.
CUSTOM_REPORT_EN = (
"The customer asked for a product demo. "
"Their desired workflows are not yet recorded."
...
이 입력에서도 '다음 대응 확인'이 47.77%, '제품 데모 조정'이 16.27%였습니다.
'추가 확인 사항'은 '데모로 시도할 업무'를 78.88%로 선택하고 있습니다.
세부 내용이 미확인이라는 것을, 다음 활동 자체가 미결정이라는 것과 혼동하는 것처럼 보입니다.
이는 출력으로부터의 해석이며, 모델 내부의 이유를 확인한 것은 아닙니다.
각기 다른 질문에 대한 답이 상충됨
G사는 마지막에 '우선 영업 측에서 견적을 받고 싶다'고 희망 변경을 한 예시입니다.
다음 액션에서는 '견적 준비'를 선택했습니다.
하지만, 준비 자료는 '지금은 준비하지 않는다'였습니다.
준비 자료 질문에서는 '지금은 준비하지 않는다'가 38.60%, '견적서'가 37.00%로 근접한 값입니다.
참고로, '지금은 준비하지 않는다'의 영어 정의는 고객이 연락 일시 정지를 요청했을 경우입니다.
G사는 이용 인원이 미확인이지만, 연락 중단을 요청하지 않았습니다.
후보 설명으로 비추어 보아도 이 선택은 기대와 맞지 않습니다.
이번 4문항은 같은 일보를 읽는 독립적인 질문입니다.
준비 자료 질문에, 이전 질문에서 선택한 '견적 준비'라는 답변을 추가로 제공하는 것이 아닙니다.
질문 간의 출력 일관성은 자동으로 보장되지 않습니다.
개선을 시도하려면, 처음에 다음 액션을 판단하고 그 답변을 덧붙여 준비 자료를 재판단하는 방법이 있습니다.
다만, 그 경우에는 첫 번째 오류가 후속 판단에도 영향을 미칠 수 있습니다.
또한, '견적을 선택하면 자료는 견적서'와 같이 프로그램으로 고정하는 방법도 있지만, 이 부분은 모델의 판단이 아니라 업무 규칙입니다.
본 기사에서는 그러한 후처리로 결과를 수정하지 않았습니다.
CPU에서 얼마나 기다렸는지
이번에 8건 각각의 모델 처리 시간은 다음과 같았습니다.
| ID | 모델 처리 시간 |
|---|
| S01 | 12.68초 |
| ... | |
| 첫 번째 건을 포함하여, 모델 처리 부분의 합계는 약 94.4초였습니다. | |
모델 로딩은 약 32.2초이며, 환경 설치 시간은 별개입니다.
이 측정은 모델의 채점 처리를 대상으로 하며, 화면 표시나 ZIP 저장까지 포함하는 업무 전체 시간은 아닙니다.
대화하면서 즉각적으로 연달아 사용하려면 CPU에서는 대기 시간이 있습니다.
한편, 몇 건의 일보를 모아서 시도하는 교재로는 GPU가 없어도 결과를 확인할 수 있었습니다.
CPU라서 판단 내용이 나빠질 것이라고 단정할 수는 없습니다.
속도와 판단의 타당성은 나누어 확인합니다.
결과 저장하기
실행용 코드에는 다음 파일을 출력하는 처리를 넣었습니다.
| 파일 | 내용 |
|---|
action_candidates.csv | 4개 항목의 후보와 확률 목록 |
human_review.csv | 담당자의 확인과 수정 내용을 기입할 수 있는 빈칸이 있는 목록 |
decisions.jsonl | 실제로 전송한 입력과 모델 출력의 이력 |
results.json | 저장 대상으로 선택된 결과 |
report.html | 일본어로 일보와 판단을 나열하여 표시 |
next_actions.png | 다음 액션 후보의 확률 그림 |
article_results.md | 실행 환경과 결과의 마크다운 기록 |
runtime.json | 장치, 유형, 로드 시간, 프로세스 ID 등 |
environment.txt | 모델 측의 Python 환경 라이브러리 목록 |
마지막 저장 셀을 실행하면 ZIP 다운로드가 시작됩니다.
/content
폴더는 세션 종료 후에도 남아있지 않을 수 있으므로, 직접 보관해야 합니다.
본인이 입력한 일보도 ZIP에 포함됩니다.
교재를 공유할 때는 가상의 내용이나 익명화된 내용으로 대체해 주세요.
자신의 업무에 맞추려면
예를 들어, '제품 데모' 대신 '시제품을 보내기', '샘플 데이터를 받기' 등의 후보로 변경할 수 있습니다.
후보를 추가할 때는 후보 이름뿐만 아니라 어떤 상황에서 선택하는지를 설명합니다.
후보 추가에 반드시 추가 학습이 필요하다는 설계는 아닙니다.
다만, 추가한 후보를 모델이 올바르게 사용할 수 있는지는 실제 입력으로 확인해야 합니다.
이번에도 자연스럽게 읽히는 일보라고 해서 모든 항목이 올바르게 선택된 것은 아닙니다.
공식 모델 카드도 0.8B 버전의 일반화에 한계가 있음을 기재하며, 특히 도구 호출 라우팅을 대상에서 제외하고 있습니다.
이 실험은 일보 내용을 업무 후보에 대응시키는 시제품이며, 외부 도구를 자율적으로 사용하는 성능을 보여준 것이 아닙니다.
모델을 크게 하는 4B로 전환하는 것도 노트북에는 남아있지만, 이 기사의 결과는 모두 0.8B 버전입니다.
4B에서 개선되는지는 이번에 확인하지 않았습니다.
시도해 본 것들
Kev를 사용하니 일보를 입력하고, 결정된 업무 후보와 확률을 Python으로 받을 수 있었습니다.
Google Colab의 CPU로 완주했으며, 모델도 매번 다시 로드할 필요 없이 사용할 수 있습니다.
연락을 자제해 달라는 요청이나, 상담 마지막에 변경된 희망 사항을 포착하는 장면이 있었습니다.
반면에 데모 희망을 놓치거나, 서로 다른 질문의 답변이 충돌하는 장면도 있었습니다.
이번에 만든 것은 담당자가 일보를 다시 읽어보는 때의 후보 목록입니다.
판단을 바로 자동 실행하기 전에, 원본 일보, 선택되지 않은 후보의 확률, 질문 간의 정합성을 확인할 수 있도록 해두면, 모델이 어디에서 도움이 되고 어디에서 틀리는지를 구체적으로 조사할 수 있습니다.
실행용 전체 코드
아래 각 코드를 별도의 Colab 셀에 붙여넣고 순서대로 실행해 주세요.
모델용 보조 코드도 포함되어 있어, 이 기사만으로 노트북을 구성할 수 있습니다.
코드는 이미 실행된 노트북의 것입니다.
0.8B 버전을 CPU로 시도하는 경우에는 첫 번째 MODEL_SIZE = '0.8b'
를 변경하지 않습니다.
4B 버전으로 전환하는 것은 본 기사에서는 실행하지 않았습니다.
셀 1: 전용 환경 준비하기
from pathlib import Path
from datetime import datetime
import sys, os, json, subprocess, shutil, uuid
...
셀 2: 일보와 질문 정의하기
REPORTS = [{'id': 'S01',
'company': 'A사',
'title': '연계 상담',
...
셀 3: 모델 로드 및 유지하기
WORKER_CODE = r'''
import os, sys, json, time, traceback, platform
import torch
...
셀 4: 입력, 표시, 저장 함수 정의하기
셀 5: 실제 입력 JSON 확인하기
print(json.dumps(make_request(REPORTS[0]['report_en']),ensure_ascii=False,indent=2))
셀 6: 첫 번째 건 판별하기
first = decide_report(REPORTS[0])
show_detail(first)
print('모델 처리 시간:',round(first['output']['model_seconds'],3),'초')
...
셀 7: 8건을 목록으로 만들기
records = [first]
for report in REPORTS[1:]:
print(report['id'],report['company'],'를 판별 중…',flush=True)
...
셀 8: 자세히 볼 일보 선택하기
DETAIL_ID = 'S07'
show_detail(next(r for r in records if r['report']['id']==DETAIL_ID))
셀 9: 직접 일보 수정하기
CUSTOM_REPORT_EN = "The customer asked for a product demo. Their desired workflows are not yet recorded."
CUSTOM_REPORT_JA = "お客様は製品デモを希望。試したい業務は未確認。"
custom = decide_report(dict(id='CUSTOM',company='시제품 입력',report_en=CUSTOM_REPORT_EN,report_ja=CUSTOM_REPORT_JA))
...
셀 10: 결과를 저장하고 다운로드하기
selected_records = records + [custom]
doc = save_outputs(selected_records)
display(HTML(doc))
...
셀 11: 필요할 때만 모델 종료하기
STOP_MODEL = False
if STOP_MODEL:
kev.close()
...
논의 (Discussion)