📚 Agentic AI - 기업용 자율 에이전트 개발 2장 · LLM API 기초 Agentic AI란

LLM 호출은 함수다 — 무엇을 넣고 무엇을 받나

한 줄 요약

LLM 호출은 신비로운 무언가가 아니라 값을 입력하면 출력이 나오는 함수 하나입니다. 이 절에서 넣는 것 세 가지와 받는 것 두 가지를 정리하면, 앞으로 나올 모든 코드가 이 틀의 변형으로 보입니다.


1. 1장에서 쓴 그 두 줄

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

resp = client.models.generate_content(model=GEMINI_MODEL, contents=question)
return (resp.text or "")

이게 전부였습니다. 그림으로 그리면 이렇습니다.

입력응답model사용할 모델contents질문config설정구글 서버.text답변.usage_metadata토큰(그 외 여러 가지)API 호출은 다음과 같습니다. 인자 세 개를 넣고, 객체 하나를 받습니다.
호출 한 번은 인자 세 개를 넣고 객체 하나를 받는 일이다

1장에서는 modelcontents 만 썼습니다. 이번 장에서 config 를 배웁니다.


2. 넣는 것 세 가지

model — 어떤 모델을 쓸지

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

model="gemini-2.5-flash"

이 과정은 계속 gemini-2.5-flash 를 씁니다. 코드에는 직접 안 적고 common.pyGEMINI_MODEL 을 가져다 씁니다.

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

from common import GEMINI_MODEL

이렇게 해 두면 나중에 .envGEMINI_MODEL 한 줄만 바꿔도 8개 파일 전부에 반영됩니다.

contents — 무엇을 물을지

여기가 이번 장의 핵심입니다. 두 가지 형태로 넣을 수 있습니다.

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

# 형태 1 — 문자열 하나 (한 번 묻고 한 번 답받기)
contents="스마트워치 추천해 주세요"

# 형태 2 — 대화 목록 (지금까지의 대화를 통째로)
contents=[
    Content(role="user",  parts=[Part(text="제 이름은 김민준입니다")]),
    Content(role="model", parts=[Part(text="김민준 고객님, 안녕하세요")]),
    Content(role="user",  parts=[Part(text="제 이름이 뭐라고 했죠?")]),
]

형태 2가 "멀티턴"의 정체입니다. 나중에 자세히 봅니다. 지금은 "대화 목록도 넣을 수 있다" 정도만 알아 두세요.

config — 어떻게 답할지

설정을 담는 객체입니다. 이번 장에서 두 가지를 배웁니다.

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

from google.genai import types

config = types.GenerateContentConfig(
    system_instruction="너는 승승장구몰의 CS 상담원이다.",   # 역할·규칙
    temperature=0.3,                                    # 답의 다양성
)
설정 무엇을 정하나 배우는 절
system_instruction 모델의 역할·말투·규칙 다음 절
temperature 매번 같은 답 ↔ 다양한 답 3절
tools 쥐여 줄 도구 목록 3장

3. 받는 것 두 가지

resp.text — 답변 문자열

거의 항상 이것만 씁니다.

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

print(resp.text)

resp.usage_metadata — 얼마나 썼는지

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

print(resp.usage_metadata)
prompt_token_count=42  candidates_token_count=115  total_token_count=157

토큰(token) 은 LLM이 글을 세는 단위입니다. 요금이 이 숫자로 매겨집니다. 7절에서 자세히 봅니다.

resp 안에는 이것 말고도 여러 가지가 들어 있습니다. 안전성 판정, 답변 후보 목록, 그리고 3장에서 결정적으로 중요해질 resp.function_calls — "모델이 어떤 함수를 부르고 싶어 하는지" 가 담긴 자리입니다. 지금은 .text 만 씁니다.


4. 호출은 '상태가 없다'

이번 장에서 가장 중요한 성질입니다. 미리 분명히 짚어 둡니다.

generate_content 를 두 번 부르면, 두 번째 호출은 첫 번째 호출을 전혀 모릅니다.

아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.

ask("제 이름은 김민준입니다.")     # 호출 ①
ask("제 이름이 뭐라고 했죠?")      # 호출 ② — ①을 모른다

②는 ①과 아무 관계 없는, 완전히 새로운 요청입니다. 사람으로 치면 매번 처음 만나는 사람에게 말을 거는 것과 같습니다.

이 성질을 무상태(stateless) 라고 부릅니다. 5절에서 직접 확인하고, 6절에서 이걸 우회하는 방법을 만듭니다.

"그럼 ChatGPT는 어떻게 기억하죠?" — ChatGPT도 기억하지 않습니다. 내부에서 지금까지의 대화 전체를 매번 다시 보내고 있을 뿐입니다. 우리가 6절에서 손으로 하게 될 그 일을, ChatGPT는 대신 해 주고 있는 것입니다.


5. 왜 이 틀을 외워야 하나

앞으로 나올 코드는 전부 이 틀의 변형입니다.

무엇이 달라지나
2장 configsystem_instructiontemperature 를 넣는다
3장 configtools 를 넣는다 → 에이전트가 된다
4장 contents도구 실행 결과를 쌓아 다시 보낸다 → 루프가 된다
5장 이 호출을 LangChain이 대신 해 준다
7장 contents 쌓기를 LangGraph가 대신 해 준다
1장generate_contentmodelcontents 문자열2장generate_contentmodelcontents 문자열config 지시 · 온도3장generate_contentmodelcontents 문자열config 지시 · 온도tools = [함수]4장generate_contentmodelcontents = historyconfig 지시 · 온도tools = [함수]5장generate_contentmodelcontents = historyconfig 지시 · 온도tools = [함수]history가 계속 쌓임장이 넘어갈수록 인자 칸이 한 줄씩 늘어납니다create_agent( )라이브러리 안이것만 밖에 남습니다도구 구성독스트링반복 횟수 상한4장까지는 라이브러리 내부의 동작을 직접 구현하며 익힙니다. 5장부터는 이 과정을 라이브러리가 처리합니다.
같은 호출에 인자가 한 줄씩 늘어나고, 5장에서는 라이브러리가 이 호출 전체를 처리한다

5장부터는 이 코드가 눈에 안 보이게 됩니다. 라이브러리가 감춰 주기 때문입니다. 그래서 4장까지는 일부러 손으로 씁니다. 감춰진 것이 무엇인지 알아야, 나중에 문제가 생겼을 때 어디를 볼지 알 수 있습니다.


핵심 정리

  • LLM 호출은 generate_content(model, contents, config) 함수 하나입니다.
  • model 은 어떤 모델, contents 는 무엇을 물을지, config 는 어떻게 답할지입니다.
  • contents 에는 문자열 하나를 넣을 수도, 대화 목록을 넣을 수도 있습니다. 후자가 멀티턴입니다.
  • 받은 응답에서 .text 로 답변을, .usage_metadata 로 사용량을 꺼냅니다.
  • 호출은 무상태입니다 — 두 번째 호출은 첫 번째를 모릅니다. ChatGPT가 기억하는 것처럼 보이는 이유는 매번 대화 전체를 다시 보내기 때문입니다.
  • 앞으로 나올 모든 코드는 이 틀에 config 를 채우고 contents 를 쌓는 이야기입니다.
  다음 절 →02. 시스템 지시로 역할 입히기