루프를 매번 손으로 짤 필요가 없다
한 줄 요약
4장에서 손으로 짠 ReAct 루프는 어떤 에이전트를 만들어도 거의 똑같습니다. 그래서 라이브러리가 대신 돌려 줍니다. 이 과정에서는 LangChain 을 씁니다.
1. 4장 루프를 다시 봅시다
아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.
history = [types.Content(role="user", parts=[types.Part(text=question)])]
for step in range(1, MAX_STEPS + 1):
resp = client.models.generate_content(model=..., contents=history, config=config)
if not resp.function_calls:
return resp.text.strip()
history.append(resp.candidates[0].content)
for fc in resp.function_calls:
result = TOOLS[fc.name](**dict(fc.args))
history.append(types.Content(role="user", parts=[
types.Part.from_function_response(name=fc.name, response={"result": result})]))
이 코드에서 에이전트마다 달라지는 부분을 표시해 보면 이렇습니다.
history = [질문] ← 항상 같음
for step in range(1, MAX_STEPS + 1): ← 상한값만 다름
resp = generate_content(...) ← 항상 같음
if not resp.function_calls: return ... ← 항상 같음
history.append(...) ← 항상 같음
for fc in resp.function_calls: ← 항상 같음
결과 = TOOLS[fc.name](...) ← ★ 도구가 다름
history.append(...) ← 항상 같음
달라지는 건 도구 목록과 시스템 지시뿐입니다. 나머지 30줄은 CSV 분석 에이전트를 만들든, 문서 검색 에이전트를 만들든 한 글자도 안 바뀝니다.
이런 코드를 매번 복사해 붙여 넣는 것은 좋은 방법이 아닙니다.
- 버그를 고치면 복사한 모든 곳을 고쳐야 한다
- 기능(재시도, 로그, 토큰 계산)을 개선할 때도 모든 곳에 반영해야 한다
- 사람마다 조금씩 다르게 짜서 동작이 미묘하게 달라진다
2. 그래서 LangChain
아래는 개념 설명용 코드입니다 — 실습 파일에 넣지 않습니다.
from langchain.agents import create_agent
agent = create_agent(llm, tools=[run_pandas], system_prompt=SYSTEM)
이 한 줄이 4장의 30줄을 대신합니다.
| 4장에서 손으로 | LangChain이 |
|---|---|
history 만들기 |
자동 |
매번 contents=history 로 보내기 |
자동 |
if not resp.function_calls 판정 |
자동 |
TOOLS[fc.name](...) 실행 |
자동 |
Part.from_function_response 로 기록 |
자동 |
MAX_STEPS 상한 |
설정(recursion_limit)으로 |
하는 일은 똑같습니다. 생각하고, 도구를 부르고, 결과를 보고 다시 판단합니다.
3. LangChain이란
LLM 애플리케이션을 만들 때 반복되는 부분을 모아 둔 라이브러리입니다. 에이전트 루프 말고도 여러 가지를 다룹니다.
| 묶음 | 하는 일 | 이 과정에서 |
|---|---|---|
| 모델 연결 | 여러 회사의 모델을 같은 방식으로 | 5장~ |
| 도구 | 함수를 도구로 등록 | 5장 |
| 에이전트 | ReAct 루프 | 5장 |
| 문서 처리 | PDF 읽기, 자르기 | 6장 |
| 벡터 검색 | 임베딩·검색 | 6장 |
| LangGraph | 상태·기억·그래프 | 7~8장 |
LangGraph 는 LangChain 계열의 다른 라이브러리인데, 7장부터 이게 주역이 됩니다. create_agent 도 사실 내부적으로 LangGraph 위에 만들어져 있습니다 — 7장에서 이 점이 도움이 됩니다.
왜 하필 LangChain인가 — 대안이 여럿 있습니다(LlamaIndex, 각 회사 SDK의 에이전트 기능 등). LangChain을 쓰는 이유는 자료가 가장 많고, 모델을 바꿔 끼우기 쉽고, RAG와 멀티에이전트까지 한 계열로 이어지기 때문입니다.
4. 버전 주의 — 1.0 이상
이 과정은 langchain 1.0 이상을 씁니다.
터미널에서 실행 — 프로젝트 폴더
agentic_ai에서,(agentic)표시를 확인한 뒤.
pip list | grep langchain # macOS
pip list | findstr langchain # Windows
langchain 1.3.15
langchain-core 1.6.0
langchain-google-genai 4.3.4
앞자리가 1. 이어야 합니다.
0.x 버전에는 create_agent 가 아예 없습니다. 대신 initialize_agent, AgentExecutor 같은 옛 방식이 있는데, 쓰는 법이 꽤 다릅니다. 인터넷에서 찾은 예제가 안 돌아간다면 버전이 다른 경우를 먼저 의심하세요.
requirements.txt 로 설치했으면 맞는 버전이 깔려 있습니다. 개별 pip install langchain 은 하지 마세요.
5. 편해지는 대신 안 보이게 됩니다
이게 이 장의 중요한 지점입니다.
단계가 안 보입니다. 잘 돌 때는 문제없지만, 이상하게 굴 때 답답합니다.
그래서 4장을 손으로 해 본 것입니다. 안 보여도 무슨 일이 일어나는지 알기 때문에, 이런 질문을 떠올릴 수 있습니다.
- 도구를 아예 안 부른 건가, 부르고 실패한 건가?
- 몇 번이나 돈 건가?
- 관찰 결과가 제대로 들어갔나?
필요하면 다시 보이게 할 수 있습니다. LangChain에도 중간 단계를 꺼내 보는 방법이 있습니다. 이 장 4절에서 다룹니다.
6. 이번 장에서 만들 에이전트
에이전트 ③ CSV 데이터분석입니다. 3장의 CSV 조회와 무엇이 다른지 분명히 해 둡시다.
| 3장 — 사내 데이터 조회 | 5장 — CSV 데이터분석 | |
|---|---|---|
| 질문 | "주문 O001203 상태는?" | "카테고리별 매출 상위 3개는?" |
| 하는 일 | 정해진 조회 | 매번 다른 계산 |
| 도구 | get_order_status(order_id) |
run_pandas(expr) |
| 인자 | 주문번호 | 계산식 자체 |
| 미리 만들 수 있나 | ✓ 질문 종류가 정해져 있다 | ✗ 질문이 무한하다 |
두 번째 열이 이번 장입니다. 질문이 무한하므로 함수를 미리 만들 수 없고, 계산식을 모델이 만들게 합니다.
핵심 정리
- 4장의 ReAct 루프는 에이전트마다 거의 같습니다. 달라지는 건 도구와 시스템 지시뿐입니다.
- 그래서
create_agent한 줄이 그 30줄을 대신합니다. 하는 일은 똑같습니다. - LangChain 은 LLM 애플리케이션의 반복되는 부분을 모은 라이브러리입니다. 7장의 LangGraph 도 같은 계열입니다.
- 버전 1.0 이상이어야 합니다. 0.x에는
create_agent가 없습니다. - 편해지는 대신 단계가 안 보입니다. 4장을 손으로 해 본 이유가 이것입니다.
- 이번 장의 에이전트는 매번 다른 계산을 합니다. 그래서 계산식을 모델이 만듭니다.