AI Agent 학습: 메모리와 Function Calling 구현


AI Agent란 무엇인가?

기본 개념

AI Agent는 단순히 LLM(Large Language Model)이 아닙니다. 정확한 정의는 다음과 같습니다:

1
AI Agent = LLM + 도구(함수) + 실행 루프

중요한 사실: LLM은 텍스트를 예측하는 엔진일 뿐이며, 실제로 코드를 실행하거나 외부 시스템과 상호작용할 수 없습니다.

그렇다면 ChatGPT가 계산을 하거나 웹 검색을 하는 것처럼 보이는 이유는? 바로 Function Calling 덕분입니다.

자세히 보기

함수 빌더 패턴(Function Builder Pattern): React 테이블 셀 렌더링을 “설정 가능한 함수”로 표준화하기

“컬럼마다 조건이 다르고, 스켈레톤/빈값/포맷팅도 섞여 있는데… 매번 컴포넌트를 새로 짜야 할까?”

실무에서 테이블·리스트 셀을 많이 다룰수록 공감하셨을 질문입니다.

아래 원본 문서를 바탕으로 옵션을 받아 ‘특화된 렌더링 함수’를 만들어내는 함수 빌더 패턴을 그대로 정리해 드립니다.


패턴 개요

함수 빌더 패턴은 설정(config)을 받아 특정 목적에 맞게 구성된 함수를 반환하는 고차함수(HOF) 패턴입니다. 전통적 팩토리 패턴의 함수형 버전으로, 객체 대신 ‘함수’를 생성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 함수 빌더 시그니처
type FunctionBuilder<TConfig, TFunction> = (config: TConfig) => TFunction;

// 실제 구현
const createGenericTextRenderer = <TRow extends BaseRowWithSkeleton>(
defaultOptions: Partial<RendererOptions> = {},
): SkeletonAwareRenderer<TRow, string | undefined> => {
// 설정을 클로저에 캡처
return (value, row, options = {}) => {
const mergedOptions = {...defaultOptions, ...options};
// 실제 렌더링 로직
};
};

핵심 개념

  • 두 단계 실행: (1) 빌드 단계에서 옵션을 고정 → (2) 실행 단계에서 값/행을 받아 렌더
  • 클로저 활용: 빌드시 캡처한 설정을 실행 시점에도 사용
  • 부분 적용: 매개변수 일부를 미리 고정하고, 나머지는 실행 시 주입
자세히 보기

함수형도 싱글톤 되잖아요? 그럼에도 클래스를 택한 이유

“함수형도 싱글톤 만들 수 있는데요?”
맞습니다. 기술적으로 가능합니다.
하지만 저는 단순히 ‘싱글 인스턴스’를 만드는 것만으로는 부족했습니다.
본 글은 지난 “왜 클래스 기반 ZebraLabelService를 선택했는가” 글에 이은 후속 글 입니다.


함수형도 싱글톤이 될 수 있습니다

사실 함수형으로도 싱글톤은 만들 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 함수형 싱글톤 패턴 (즉시 실행 함수)
const PrinterService = (() => {
let isInitialized = false;

return {
async initialize() {
if (!isInitialized) {
// 초기화 작업
isInitialized = true;
}
},
async print() {
if (!isInitialized) throw new Error('초기화 필요');
// 인쇄 작업
},
cleanup() {
isInitialized = false;
},
};
})();

이렇게 구현하면 모듈 자체가 싱글 인스턴스처럼 동작하므로 기본적인 싱글톤 조건은 충족합니다.


자세히 보기

왜 클래스 기반 ZebraLabelService를 선택했는가

Zebra 라벨 프린터 통합: 왜 클래스 기반 ZebraLabelService를 선택했는가

“React 생태계에서 굳이 클래스를?”
하드웨어(프린터)를 다룰 때는 이야기가 달라집니다. 단일 연결, 복잡한 초기화, 상태/리소스 수명 주기… 이 모든 것을 안전하고 일관되게 관리해야 합니다.
본 글은 실제 프로덕션에서 Zebra 라벨 프린터를 통합하며 내린 결정—클래스 기반 싱글톤 서비스—의 이유와 구현을 원문 코드 중심으로 정리한 내용입니다.


문제 정의와 선택 배경

Zebra 라벨 프린터 통합은 하드웨어라는 단일·희소 자원을 다룹니다. 동시에 웹 앱(특히 React)에서는 화면 전환/재렌더링, 비동기 초기화, 중복 호출이 일어나기 쉽죠.
다음 요구사항이 핵심이었습니다:

  • 싱글 연결: 물리 프린터는 사실상 단일 연결/세션 가정이 안전
  • 상태 일관성: 앱 전역에서 동일한 프린터/연결 상태 공유
  • 초기화 중복 방지: 비동기 초기화 경쟁 조건(Race Condition) 제거
  • 명확한 라이프사이클: 초기화 → 사용(출력) → 정리의 수명 주기 캡슐화

따라서 클래스 기반 싱글톤 서비스가 자연스러운 해법.

자세히 보기

FECConf 2025 다녀와서, 드디어 블로그를 시작하기로 했다

발표가 끝나자마자 노트북을 꺼내 메모장을 열었다. “이제 정말 시작해야겠다”는 생각이 머리를 스쳤다.
2025년 8월 23일 토요일, 처음으로 찾은 FECConf 2025 현장은 에너지와 열정으로 가득했다. 발표를 듣는 순간보다도, 세션이 끝나고 스피커 혹은 리더분들과 이야기를 나누는 순간순간이 더 오래 남았다.

컨퍼런스에서 얻은 가장 큰 깨달음

FECConf는 항상 개발자로서 한 단계 성장할 수 있는 계기를 주지만, 이번에는 조금 달랐다. 좋은 경험을 가진 리더분들과 대화하면서 느낀 건 꾸준히 쌓아가는 습관이 결국 나를 만든다는 것이었다.
기술 스택이나 최신 트렌드보다도 매일 조금씩 기록하고 나누고 돌아보는 과정이 진짜 성장을 만든다는 점을 실감했다.

누군가는 “짧은 글이라도 꾸준히 쓰다 보면 어느 순간 내 글이 다른 사람에게 힘이 된다”고 했다. 그 말이 크게 와 닿았다. 나 역시 지난 몇 년간 다양한 경험을 쌓아왔지만, 그 경험을 흘려보내는 데 그치지 않고 기록으로 남겼다면 지금쯤은 더 단단한 기반을 만들 수 있었을 거다.

블로그를 시작하는 이유

그래서 나는 결심했다. 내 경험과 지식을 글로 정리해보자.

  • 그동안 프로젝트에서 겪은 시행착오
  • 새로운 기술을 도입하며 배운 점
  • 개발자로서 성장하며 느낀 고민들
자세히 보기
[JS] ES2022 신기능 중 4가지

[JS] ES2022 신기능 중 4가지

이채현

노션에서 보기

Top level await

기존 await를 사용하려면 async 함수 내에서만 가능했다.

1
2
3
(async function () {
await foo();
})();

하지만, ES2022부터 이러한 규칙이 사라지고, awaitasync함수없이 모듈에서 아래와 같이 작성가능해졌다.

자세히 보기
[JS] ESLint 알고쓰기 : 설정 설명

[JS] ESLint 알고쓰기 : 설정 설명

이채현

노션 링크

이 문서는 eslint.org를 참고하여 eslint 7.32.0 버전에서 작성되었으며, 아래 프로젝트를 기반으로 작성했습니다.

https://github.com/chlee1001/react-typescript-simple-boilerplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"airbnb",
"airbnb-typescript",
"airbnb/hooks",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:import/recommended",
"plugin:import/typescript",
"plugin:jsx-a11y/recommended",
"plugin:prettier/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": [
"./tsconfig.json"
],
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint",
"import"
],
"rules": {
"import/prefer-default-export": "off",
"import/no-unresolved": 0,
"import/extensions": [
"off"
],
"react/function-component-definition": [
2,
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
]
},
"ignorePatterns": [
"paths.js",
"webpack.*.js",
"dist/*",
"node_modules/*"
],
"settings": {
"react": {
"version": "detect"
}
}
}

자세히 보기
[JS] 선언한 모듈로 이동하기 (alias) - Go to declaration

[JS] 선언한 모듈로 이동하기 (alias) - Go to declaration

이채현

문제

많은 사람들은 선언한 모듈들을 command/ctrl + click으로 해당 파일로 바로 이동하거나 자동완성이 되게하는 IDE나 Editor의 기능을 사용할 것이다. 그리고 babel-plugin-module-resolver을 통해 모듈의 경로를 별칭으로 바꿔서 사용할 것이다. 하지만 별칭으로 바꾸면서 위 기능이 깨지는 문제가 종종 있다. 그리고 이 문제는 플러그인쪽에서는 해결되지 않고 있다. npm에 올라온 최신버전은 이미 2년이 지났다.

babel-plugin-module-resolver

해결

우리는 jsconfig.json을 사용하여 IDE가 사용자 지정 resolve규칙을 따르도록 하는 것이 좋다. 이 접근 방식은 WebstormVS Code 모두 작동한다.

자세히 보기
[JS] babelrc와 webpack.config

[JS] babelrc와 webpack.config

이채현

Webpack으로 React 프로젝트를 초기 설정하다가 ,

1
2
3
4
5
6
7
8
9
10
11
12
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: ['> 5% in KR', 'last 2 chrome versions'],
},
debug: true,
},
],
'@babel/preset-react',
],

위 코드의 presets가 과연 .babelrc에 있어야 하는지, webpack.config.js에 있어야하는지 잘 모르겠어서 각 파일의 목적을 정리해보았다.

babelrc

.babelrcbabel의 설정을 위해 사용한다.

자세히 보기
[JS] Babel로 별칭 경로 설정하기

[JS] Babel로 별칭 경로 설정하기

이채현

프로젝트의 규모가 커지면 디렉토리 구조도 복잡해진다. 그 때문에 아래와 같이 컴포넌트의 위치를 찾기 어려워진다.

1
import { whereIsThis } from "../../../../../aaa/bbb/ccc";

위와 같이 작성한 것을 상대경로라고 한다. 상대 경로를 사용해서 모듈을 불러오면 모듈이 어느 경로에 위치하는지 파악하기가 난해해지는 경우가 생긴다. 뿐만 아니라, 이 자바스크립트 파일을 다른 디렉토리로 옮기려면 상대 경로를 그에 따라 모두 수정해줘야 해서 코드 리펙토링(refactoring)이 상당히 불편하다.

물론 절대경로를 사용하면 되지 않을까 생각할 수 있지만, 개발자들마다 해당 프로젝트를 다른 디렉토리에 저장해놓을 것이기 때문에 현실적으로 적용하기 어려운 방법이다.

별칭 경로

자세히 보기