Ollama & LangChain.js: 로컬, 강력한 AI 앱 만들기
Source: Dev.to
번역을 진행하려면 번역하고자 하는 전체 텍스트(본문)를 제공해 주시겠어요?
본문을 주시면 원본 포맷과 마크다운을 유지하면서 한국어로 번역해 드리겠습니다.
개요
Ollama와 LangChain.js의 통합은 지능형 애플리케이션을 구축하는 방식에 큰 변화를 가져옵니다.
이제 클라우드 기반 LLM API에만 의존하는 것이 아니라, 다음과 같은 모듈식, 로컬 호스팅 생태계에서 작업할 수 있습니다:
- 프라이버시 – 데이터가 절대 머신을 떠나지 않습니다.
- 성능 – 추론이 로컬에서 실행되어 지연 시간이 크게 감소합니다.
- 결정론 – 구조화된 파이프라인이 즉흥적인 스크립트를 대체합니다.
이 글에서는 이 강력한 조합을 구현하는 데 필요한 핵심 개념, 비유, 실용적인 코드 예제를 자세히 살펴봅니다.
핵심 개념
1. Direct Ollama API vs. LangChain.js
| 측면 | Direct Ollama API | LangChain.js |
|---|---|---|
| 상호작용 방식 | 저수준 소켓 – 원시 문자열 입출력 | 고수준 추상화 (LLM, Embeddings, Runnable) |
| 타입 안전성 | 없음 | 인터페이스 및 파서에 의해 강제 |
| 구성 가능성 | 수동 체이닝 | 결정론적 파이프라인 (Chains) |
2. LangChain.js를 LLM을 위한 “Express/Next”로
원시 모델 호출을 표준화된 인터페이스로 감싸 재사용 가능하고 테스트 가능한 파이프라인을 구현합니다.
핵심 구성 요소
| 구성 요소 | 역할 | LangChain.js Type |
|---|---|---|
| OllamaLLM | 텍스트 생성 (프롬프트 → 완성) | Runnable (can be composed) |
| OllamaEmbeddings | 텍스트를 의미 벡터로 변환 | Embeddings |
비유: 현대적인 풀스택 웹 앱
| 웹‑앱 개념 | LangChain.js 대응 |
|---|---|
| 데이터베이스 | OllamaEmbeddings – 원시 텍스트에서 벡터 인덱스를 생성합니다 (검색 인덱스를 구축하는 것과 유사). |
| API 라우트 | OllamaLLM – 프롬프트를 받아 응답을 반환하는 서버리스 함수입니다. |
| 오케스트레이터 / 미들웨어 | Chain – 검색 → 프롬프트 포맷팅 → 생성 → 출력 파싱을 연결합니다. |
왜 Ollama를 LangChain.js에 래핑할까요?
- Latency – 클라우드 제공업체로의 네트워크 홉이 없으며, 추론이 동일한 머신에서 실행됩니다.
- Privacy – 민감한 데이터(PII, 독점 문서)가 환경을 떠나지 않습니다.
- Structured Output – 출력 파서는 타입 안전성을 보장하고 잘못된 응답으로 인한 충돌을 방지합니다.
Source:
제품 카탈로그를 위한 시맨틱 검색 엔진 구축
전제 조건
-
Ollama 가 설치되어 로컬에서 실행 중이어야 합니다.
-
임베딩 모델을 다운로드합니다:
ollama pull nomic-embed-text -
다음 패키지가 설치된 Node.js 환경:
npm i langchain @langchain/community
코드 예시 (src/ollama-langchain-basic.ts)
// src/ollama-langchain-basic.ts
import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama";
import { Ollama } from "@langchain/community/llms/ollama";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { Document } from "langchain/document";
/* ---------- Initialize Embeddings & LLM ---------- */
const embeddings = new OllamaEmbeddings({
model: "nomic-embed-text",
baseUrl: "http://localhost:11434",
});
const llm = new Ollama({
model: "llama3.1",
baseUrl: "http://localhost:11434",
});
/* ---------- Sample Documents ---------- */
const documents: Document[] = [
new Document({
pageContent:
"The QuickStart Pro running shoes feature advanced cushioning technology for long-distance runners.",
metadata: { category: "Footwear", price: 120, id: "prod_001" },
}),
// ... add more documents as needed
];
/* ---------- Helper: Semantic Search ---------- */
async function searchProducts(query: string): Promise {
const vectorStore = await MemoryVectorStore.fromDocuments(
documents,
embeddings
);
// Return the top‑2 most similar documents
return vectorStore.similaritySearch(query, 2);
}
/* ---------- Helper: Generate Response ---------- */
async function generateResponse(query: string, context: Document[]) {
const contextText = context
.map(
(doc) =>
`Product: ${doc.pageContent} (Price: $${doc.metadata.price})`
)
.join("\n");
const prompt = `
User Question: ${query}
Context Products:
${contextText}
Based on the context above, recommend the best product for the user.
Be concise and friendly.
`;
const response = await llm.invoke(prompt);
return response;
}
/* ---------- Main Execution ---------- */
async function main() {
const userQuery = "I need shoes for running marathons";
const relevantDocs = await searchProducts(userQuery);
const aiResponse = await generateResponse(userQuery, relevantDocs);
console.log("\n=== FINAL RESULT ===");
console.log("Recommended Product:", aiResponse);
}
main();
이 예제가 수행하는 작업
- 임베딩 – 각 제품 설명을 벡터로 변환합니다.
- 유사도 검색 – 사용자 질의에 가장 관련성이 높은 제품을 찾습니다.
- 생성 – 검색된 컨텍스트를
OllamaLLM에 전달하여 친절한 추천을 생성합니다.
프로덕션 준비 아키텍처
보다 큰 워크로드의 경우, 인‑메모리 스토어 대신 지속적인 벡터 스토어(예: Supabase의 pgvector)를 사용하는 것이 좋습니다.
고수준 흐름
- Server Action – 사용자 쿼리를 받음 (예: API 라우트를 통해).
- Embedding Generation –
OllamaEmbeddings가 쿼리의 벡터를 생성합니다. - pgvector Search – 벡터를 사용해 PostgreSQL
documents테이블을 조회하여 유사한 항목을 가져옵니다. - Context Injection – 검색된 문서를
OllamaLLM에 전달하여 컨텍스트를 고려한 응답을 생성합니다.
성능 및 운영 팁
| 관심사 | 권장 사항 |
|---|---|
| 메모리 관리 | 유휴 상태일 때 리소스를 해제하도록 Ollama의 keep_alive 매개변수를 조정합니다. |
| 동시성 | 작업자 풀이나 큐(예: p‑queue)를 사용하여 로컬 모델이 과부하되지 않도록 합니다. |
| 배치 임베딩 | 실시간이 아니라 오프라인 인덱싱 단계에서 문서를 대량으로 임베딩합니다. |
| 결과 캐시 | 자주 사용하는 쿼리 임베딩 및 검색 결과를 캐시하여 반복 작업을 줄입니다. |
결론
Ollama를 LangChain.js와 함께 사용하면 두 세계의 장점을 모두 누릴 수 있습니다:
- 로컬, 프라이빗 추론을 온‑디바이스 실행 속도로 제공합니다.
- 구조화된, 조합 가능한 파이프라인을 통해 복잡한 AI 애플리케이션을 유지보수하고 테스트하기 쉬워집니다.
위 코드를 실험해보고, 준비가 되면 영구적인 벡터 스토어와 견고한 API 레이어로 확장하세요. 즐거운 개발 되세요!
Ollama와 LangChain.js를 이용한 로컬 추론
핵심 팁
- 싱글‑스레드 –
RunnableLambda또는 비동기 작업을 사용해 무거운 처리를 오프로드합니다. - 토큰 제한 – 로컬 모델은 컨텍스트 윈도우가 작습니다. 스플리터를 사용하고 검색된 청크를 제한하세요.
- Ollama 타임아웃 – CPU‑집약적인 모델의 경우 타임아웃을 늘립니다.
- JSON 파싱 – LLM 출력 파싱 시 발생할 수 있는 오류를 처리합니다.
Ollama와 LangChain.js를 결합하는 이유
Ollama와 LangChain.js를 통합하면 로컬, 분산 시스템을 구축할 수 있으며 다음과 같은 장점을 제공합니다:
- 프라이버시 – 모든 데이터가 온‑프레미스에 머무릅니다.
- 성능 – 자체 하드웨어에서 낮은 지연 시간으로 추론합니다.
- 제어권 – 모델 설정 및 워크플로우 오케스트레이션에 대한 완전한 접근이 가능합니다.
이 접근 방식은 AI 개발의 새로운 시대를 열어 주며, 자체 인프라만으로 강력한 애플리케이션을 구축할 수 있게 합니다. 로컬 추론과 구조화된 워크플로우의 힘을 활용해 차세대 지능형 애플리케이션을 만들어 보세요.
추가 읽을거리
여기서 시연된 개념과 코드는 책 The Edge of AI 에서 제시한 포괄적인 로드맵을 직접 인용한 것입니다 (Local LLMs – Ollama, Transformers.js, WebGPU, 그리고 성능 최적화).
무료 자료
👉 무료 액세스 지금 바로 Programming Central의 TypeScript & AI 시리즈를 이용하세요. 포함 내용:
- 8권
- 160개 챕터
- 각 챕터마다 수백 개의 퀴즈
오늘 바로 탐색을 시작하세요!