Model Context Protocol(MCP)은 호환성 문제를 해결하기 위해 등장했습니다. 일상생활에서도 호환성 문제는 다양한 불편을 초래합니다.
해외여행을 갔을 때 헤어 기기나 전자기기를 가져갔는데 플러그가 현지 콘센트와 맞지 않아 난감했던 경험이 있나요? 개발자의 관점에서는 AI 에이전트를 위해 API와 개발 툴을 구축했는데도 연결하거나 올바르게 호출하지 못하는 상황만큼 답답한 문제입니다. MCP는 바로 이러한 호환성 문제를 해결해 줍니다.
2024년 Anthropic이 발표한 Model Context Protocol(MCP)은 AI 애플리케이션이 툴, 데이터 소스/데이터세트, 미리 정의된 템플릿과 같은 외부 서비스와 효과적으로 통신할 수 있도록 하는 표준화 계층 역할을 합니다. MCP는 AI와 툴 간 상호작용을 위한 개방형 표준이자 커넥터 역할을 합니다. MCP 아키텍처는 다음과 같은 세 가지 핵심 구성 요소로 이루어져 있습니다.
먼저 IBM® Bob이 무엇인지 살펴보겠습니다. IBM Bob은 생성형 AI 기반의 통합 개발 환경(IDE)이자 현대화 지원 도우미입니다. Bob은 사용자의 의도와 코드베이스, 조직의 표준을 이해하는 AI 중심 IDE이자 페어 개발자라고 생각하면 됩니다.
특히 초보 개발자의 경우 MCP 서버를 처음부터 직접 구축하는 데는 많은 시간이 소요될 수 있습니다. 이 튜토리얼에서는 몇 가지 간단한 자연어 프롬프트만으로 IBM Bob을 사용해 이 워크플로를 빠르게 시작하는 방법을 살펴보겠습니다.
MCP 통합은 외부 툴 및 서비스와 연결하여 Bob의 기능을 확장합니다. 이 통합은 글로벌 수준(모든 워크스페이스에 적용) 또는 프로젝트 수준(.Bob/mcp.json을 통해 팀과 공유 가능)에서 구성할 수 있습니다. MCP는 두 가지 전송 방식을 지원합니다. 하나는 로컬의 저지연 서버를 위한 표준 입출력(STDIO)이고, 다른 하나는 HTTP/HTTPS를 통해 액세스하는 원격 MCP 서버를 위한 서버 전송 이벤트(SSE)입니다. 사용자는 Bob 설정 메뉴에서 JSON 파일을 사용해 서버를 구성하고, 명령, 환경 변수 및 자동 승인할 툴을 정의할 수 있습니다. 두 전송 방식 모두 Bob의 MCP 설정 패널에서 서버를 활성화하거나 비활성화하고, 특정 툴을 자동 승인하며, 서버 운영을 관리할 수 있습니다.
시작해 보겠습니다. GitHub에서 이 튜토리얼을 따라 하고 싶다면 리포지터리를 확인하세요.
1. 먼저 사전 요구 사항으로 설치한 IBM Bob IDE를 열고 새로운 AI 코딩 도우미의 레이아웃을 살펴봅니다.
2. MCP 설정 패널에 액세스하려면 채팅 창 오른쪽 상단의 톱니바퀴 아이콘 옆에 있는 점 3개를 클릭합니다. 그런 다음 드롭다운 메뉴에서 MCP servers 를 선택합니다.
여기에서는 MCP를 전역 또는 서버별로 활성화하거나 비활성화하고, 툴(예: 자동 승인, 삭제, 다시 시작)을 관리할 수 있습니다. 또한 Bob Marketplace에서 커뮤니티 서버를 살펴보거나 MCP SDK를 사용하여 직접 서버를 구축할 수도 있습니다.
Bob Marketplace에서 서버를 설치한 경우 구성은 두 가지 수준으로 설정할 수 있습니다. 전역(모든 워크스페이스에 적용되며
프로젝트 수준 설정은 전역 설정보다 우선 적용되므로 다양한 사용 사례에 맞게 MCP 동작을 유연하게 조정할 수 있습니다. 이러한 구성을 관리하려면 Bob 설정 메뉴에서 JSON 파일을 직접 편집하여 명령, 환경 변수, 자동 승인할 툴 등의 서버 세부 정보를 정의할 수 있습니다. 이 튜토리얼에서는 SDK를 사용합니다.
3. Bob으로 사용자 지정 MCP 서버를 생성할 수 있도록 Enable MCP Server Creation 설정이 활성화되어 있는지 확인합니다.
4. 프로젝트를 설정할 디렉터리가 있다면 IDE에서 직접 열거나 채팅 창에서 Bob에게 열도록 요청할 수 있습니다.
3. 프로젝트 간 종속성이 서로 충돌하지 않도록 프로젝트의 종속성을 격리하기 위해 Python 가상 환경을 생성하는 것이 일반적입니다. 이를 위해 다음 프롬프트를 입력합니다. “In this directory, activate a Python virtual environment”.
4. Bob이 일련의 터미널 명령을 실행하는 것을 확인할 수 있습니다. 실행되는 명령은 다음과 비슷합니다.
Bob이 각 명령을 실시간으로 실행하기 전에 검토하고 승인하거나 거부할 수 있도록 자동 승인 토글은 비활성화된 상태로 유지하는 것이 좋습니다.
잘 되었습니다. Bob이
이제 가상 환경이 준비되었으므로 MCP 서버 생성을 시작하겠습니다. Bob이나 다른 AI 모델 또는 AI 도우미에게 코드 생성을 요청할 때는 중요한 세부 정보를 함께 제공하는 것이 좋습니다. Bob이 어떻게 동작하는지 확인하기 위해 다음 프롬프트를 입력해 보겠습니다.
"arXiv에 대한 읽기 전용 액세스를 제공하는 MCP 서버를 생성해 줘." 서버는 다음 요구 사항을 충족해야 합니다.
이 간단한 프롬프트 하나만으로도 Bob은 작업을 이해하고 작업을 완료하기 위한 'to-do list'를 작성하는 데 필요한 충분한 정보를 얻을 수 있습니다. 이 목록에는 MCP 서버 생성뿐만 아니라 구성 및 테스트까지 포함되어 있다는 점에 주목하세요. 정말 편리하죠.
참고로 이 튜토리얼에서는 API 키나 인증 없이 바로 사용할 수 있는 간단한 예제로 arXiv API를 사용합니다. 하지만 이는 하나의 예시일 뿐이며, Bob은 필요한 권한이 필요한 더 복잡한 서버도 충분히 처리할 수 있습니다.
각 명령이 실행되기 전에 해당 작업을 승인하거나 거부할 수 있습니다. 명령이 자동으로 실행된다면 자동 승인 토글이 활성화되어 있는지 확인하세요.
2. 다음으로 Bob은
{
"name": "arxiv-server",
"version": "0.1.0",
"description": "MCP server for read-only access to arXiv papers",
"type": "module",
"bin": {
"arxiv-server": "./build/index.js"
},
"files": [
"build"
],
"scripts": {
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
"prepare": "npm run build",
"watch": "tsc --watch"
},
"keywords": [
"mcp",
"arxiv",
"research",
"papers"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.4",
"axios": "^1.7.9",
"zod": "^3.24.1"
},
"devDependencies": {
"@types/node": "^22.10.5",
"typescript": "^5.7.3"
}
}
arxiv-server/tsconfig.json{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "build"]
}
4. 다음으로 arXiv 검색 기능을 구현한 기본 서버는
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import axios from 'axios';
// Define types for arXiv API responses
interface ArxivEntry {
id: string;
title: string;
summary: string;
authors: Array<{ name: string }>;
published: string;
updated: string;
categories: string[];
primary_category: string;
links: Array<{ href: string; rel: string; type?: string }>;
}
interface ArxivSearchResult {
entries: ArxivEntry[];
totalResults: number;
startIndex: number;
itemsPerPage: number;
}
// Create an MCP server
const server = new McpServer({
name: "arxiv-server",
version: "0.1.0"
});
// Create axios instance for arXiv API
const arxivApi = axios.create({
baseURL: 'http://export.arxiv.org/api',
timeout: 30000,
});
/**
* Parse arXiv API XML response to JSON
*/
function parseArxivXML(xmlData: string): ArxivSearchResult {
const entries: ArxivEntry[] = [];
// Extract total results
const totalResultsMatch = xmlData.match(/<opensearch:totalResults[^>]*>(\d+)<\/opensearch:totalResults>/);
const totalResults = totalResultsMatch ? parseInt(totalResultsMatch[1]) : 0;
const startIndexMatch = xmlData.match(/<opensearch:startIndex[^>]*>(\d+)<\/opensearch:startIndex>/);
const startIndex = startIndexMatch ? parseInt(startIndexMatch[1]) : 0;
const itemsPerPageMatch = xmlData.match(/<opensearch:itemsPerPage[^>]*>(\d+)<\/opensearch:itemsPerPage>/);
const itemsPerPage = itemsPerPageMatch ? parseInt(itemsPerPageMatch[1]) : 0;
// Extract entries
const entryRegex = /<entry>([\s\S]*?)<\/entry>/g;
let entryMatch;
while ((entryMatch = entryRegex.exec(xmlData)) !== null) {
const entryXml = entryMatch[1];
// Extract ID
const idMatch = entryXml.match(/<id>([^<]+)<\/id>/);
const id = idMatch ? idMatch[1] : '';
// Extract title
const titleMatch = entryXml.match(/<title>([^<]+)<\/title>/);
const title = titleMatch ? titleMatch[1].trim().replace(/\s+/g, ' ') : '';
// Extract summary
const summaryMatch = entryXml.match(/<summary>([^<]+)<\/summary>/);
const summary = summaryMatch ? summaryMatch[1].trim().replace(/\s+/g, ' ') : '';
// Extract authors
const authors: Array<{ name: string }> = [];
const authorRegex = /<author>\s*<name>([^<]+)<\/name>/g;
let authorMatch;
while ((authorMatch = authorRegex.exec(entryXml)) !== null) {
authors.push({ name: authorMatch[1].trim() });
}
// Extract published date
const publishedMatch = entryXml.match(/<published>([^<]+)<\/published>/);
const published = publishedMatch ? publishedMatch[1] : '';
// Extract updated date
const updatedMatch = entryXml.match(/<updated>([^<]+)<\/updated>/);
const updated = updatedMatch ? updatedMatch[1] : '';
// Extract categories
const categories: string[] = [];
const categoryRegex = /<category[^>]+term="([^"]+)"/g;
let categoryMatch;
while ((categoryMatch = categoryRegex.exec(entryXml)) !== null) {
categories.push(categoryMatch[1]);
}
const primary_category = categories[0] || '';
// Extract links
const links: Array<{ href: string; rel: string; type?: string }> = [];
const linkRegex = /<link[^>]+href="([^"]+)"[^>]+rel="([^"]+)"(?:[^>]+type="([^"]+)")?/g;
let linkMatch;
while ((linkMatch = linkRegex.exec(entryXml)) !== null) {
links.push({
href: linkMatch[1],
rel: linkMatch[2],
type: linkMatch[3]
});
}
entries.push({
id,
title,
summary,
authors,
published,
updated,
categories,
primary_category,
links
});
}
return {
entries,
totalResults,
startIndex,
itemsPerPage
};
}
/**
* Format search results for display
*/
function formatSearchResults(result: ArxivSearchResult): string {
let output = `Found ${result.totalResults} results (showing ${result.entries.length})\n\n`;
result.entries.forEach((entry, index) => {
output += `${index + 1}. ${entry.title}\n`;
output += ` ID: ${entry.id}\n`;
output += ` Authors: ${entry.authors.map(a => a.name).join(', ')}\n`;
output += ` Published: ${entry.published}\n`;
output += ` Categories: ${entry.categories.join(', ')}\n`;
output += ` Abstract: ${entry.summary.substring(0, 300)}${entry.summary.length > 300 ? '...' : ''}\n`;
// Find abstract link (not PDF)
const abstractLink = entry.links.find(l => l.rel === 'alternate');
if (abstractLink) {
output += ` URL: ${abstractLink.href}\n`;
}
output += '\n';
});
return output;
}
// Add a tool for searching arXiv papers
server.tool(
"search_arxiv",
{
query: z.string().describe("Search query (supports arXiv query syntax)"),
max_results: z.number().min(1).max(50).optional().describe("Maximum number of results to return (1-50, default: 10)"),
start: z.number().min(0).optional().describe("Starting index for pagination (default: 0)"),
sort_by: z.enum(["relevance", "lastUpdatedDate", "submittedDate"]).optional().describe("Sort order (default: relevance)"),
sort_order: z.enum(["ascending", "descending"]).optional().describe("Sort direction (default: descending)")
},
async ({ query, max_results = 10, start = 0, sort_by = "relevance", sort_order = "descending" }) => {
try {
// Enforce reasonable limits
const limitedMaxResults = Math.min(max_results, 50);
const limitedStart = Math.max(start, 0);
// Build query parameters
const params: Record<string, string | number> = {
search_query: query,
start: limitedStart,
max_results: limitedMaxResults,
};
if (sort_by) {
params.sortBy = sort_by;
}
if (sort_order) {
params.sortOrder = sort_order;
}
const response = await arxivApi.get('/query', { params });
// Parse XML response
const result = parseArxivXML(response.data);
// Format results
const formattedResults = formatSearchResults(result);
return {
content: [
{
type: "text",
text: formattedResults,
},
],
};
} catch (error) {
if (axios.isAxiosError(error)) {
return {
content: [
{
type: "text",
text: `arXiv API error: ${error.response?.data?.message ?? error.message}`,
},
],
isError: true,
};
}
throw error;
}
}
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('arXiv MCP server running on stdio');
// Bob으로 생성됨
이 단계에서 서버에 API 키가 필요한 경우 Bob이 해당 정보를 요청합니다.
5. 다음으로 Bob은 다음 명령을 실행하여 arxiv-server 디렉터리에 필요한 종속성을 설치합니다.
mcp_settings.json.Bob/mcp.json{
"mcpServers": {}
"mcpServers": {
"arxiv": {
"command": "node",
"args": [ "/here/is/the/path/to/arxiv-server/build/index.js"
],
"disabled": false,
"alwaysAllow": [],
"disabledTools": []
}
}
}
이로써 Bob의 MCP 서버 설정 과정이 완료됩니다.
'to-do list' 작업 시리즈를 완료하기 위해 Bob은 MCP 서버를 테스트합니다. 앞의 스크린샷에서 볼 수 있듯이 Bob은 MCP 서버의
아래쪽 캐럿을 클릭해 창을 펼치면 성공적으로 실행된 것을 확인할 수 있으며, Bob은 이어서 또 다른 테스트를 수행합니다. 이번에는 제출일 내림차순으로 정렬된 머신 러닝 논문 2편을 검색합니다. 다른 매개변수를 사용했음에도 이 MCP 툴 호출 역시 성공적으로 실행되었습니다.
테스트가 모두 성공적으로 완료되었으므로 Bob은 이제 모든 하위 작업을 완료했습니다.
Bob은 이미 MCP 서버를 테스트해 두었습니다. 이제 채팅 창에서 직접 몇 가지 검색을 수행해 보면서 Bob이 적절한 검색어와 필요한 매개변수를 스스로 도출하는지 확인해 보겠습니다.
Bob에게 "LLM 에이전트 추적에 관한 최신 논문을 찾아줘."라고 요청합니다.
Bob은 프롬프트에서 적절한 검색어를 스스로 추출하고, 검색 품질을 높이기 위해 추가 키워드를 덧붙였습니다. 또한 검색 결과의 최대 개수를 10개로 설정하고 논문을 관련성순으로 정렬했습니다. 잘 되었습니다.
검색을 한 번 더 수행해 보겠습니다.
흥미롭게도 Bob은 원하지 않는 검색 결과를 확인하자 검색어를 자동으로 수정했습니다. Bob은 툴 호출을 무작정 실행하는 것이 아니라, 도움을 주는 에이전트로서 사용자와 협력합니다. 이러한 과정을 두 차례 반복한 끝에 Bob은 처음 의도한 작업에 잘 부합하는 여러 논문을 찾아주었습니다.
많은 오픈 소스 MCP 서버에는 다른 사용자도 쉽게 시작할 수 있도록 문서가 함께 제공됩니다. 다음 프롬프트를 채팅 창에 붙여 넣습니다.
"이 디렉터리에 이 MCP 서버를 설명하는 README.md 파일을 생성해 줘. 설정 및 사용 방법도 포함해."
간단한 프롬프트 하나만으로 Bob은 arXiv MCP 서버를 이해하고, 설치하고, 구성하고, 문제를 해결하고, 사용하는 데 필요한 모든 내용을 담은 포괄적인
이 MCP 서버에 액세스할 수 있는 연구 특화 AI 에이전트를 watsonx Orchestrate로 구축해 보고 싶으신가요? Bob은 간단한 프롬프트 하나만으로 에이전트를 생성할 수 있습니다. 먼저 1단계에서 살펴본 MCP 설정 패널의 Marketplace에서 미리 빌드된 watsonx Orchestrate ADK 서버를 설치합니다. 그런 다음 다음 명령을 입력합니다.
"이 arXiv MCP 서버를 사용하는 watsonx Orchestrate 에이전트를 생성해 줘."
로컬에서 watsonx Orchestrate 서비스가 실행 중이라면 Bob이 필요한 명령을 대신 실행해 줍니다. 나중에 직접 명령을 실행하고 싶다면 Bob이 필요한 스크립트를 작성하고 필요한 명령도 함께 문서화해 줍니다.
Bob이 생성한 내용을 더 잘 이해하기 위해 각 파일을 살펴보겠습니다. 먼저 toolkit-config.yaml
kind: mcp
name: arxiv-toolkit
description: Toolkit for searching arXiv research papers. arXiv 데이터베이스의 논문 메타데이터, 초록 및 출판 정보에 액세스할 수 있도록 합니다.package_root: /local/path/to/arxiv-serverlanguage: nodecommand: node /local/path/to/arxiv-server/arxiv-server/build/index.jstools:- "*"# Bob으로 생성
다음으로 research-assistant-agent.yaml
name: research-assistant
kind: native
description: arXiv에서 학술 논문을 찾고 요약하는 데 도움을 주는 AI 연구 도우미입니다. 학술 문헌 검색, 연구 결과 설명 및 인용 정보 제공에 특화되어 있습니다.
title: 연구 도우미
instructions: |
당신은 arXiv의 학술 문헌 검색을 전문으로 하는 연구 도우미입니다.
## 주요 기능
- 모든 과학 분야의 주제에 대해 arXiv 논문을 검색합니다.
- 초록을 바탕으로 연구 결과를 이해하기 쉬운 언어로 요약합니다.
- 주요 저자와 연구 동향을 파악합니다.
- 관련 논문과 연구 주제를 제안합니다.
- arXiv ID와 URL을 포함한 올바른 인용 정보를 제공합니다.
## 사용자에게 응답할 때
1. 항상 arXiv ID와 논문의 직접 URL을 제공합니다.
2. 초록을 이해하기 쉬운 언어로 요약합니다.
3. 주요 기여와 연구 성과를 강조합니다.
4. 관련이 있는 경우 후속 검색을 제안합니다.
5. 간결하면서도 충분한 정보를 제공합니다.
## search_arxiv 툴 사용
사용 가능한 매개변수:
- query (필수): arXiv 검색 구문을 사용하는 검색어
- max_results (선택 사항): 검색할 논문 수(1~50, 기본값: 10)
- start (선택 사항): 페이지 매김을 위한 시작 인덱스(기본값: 0)
- sort_by (선택 사항): "relevance", "submittedDate" 또는 "lastUpdatedDate"
- sort_order (선택 사항): "ascending" 또는 "descending"
## 고급 검색 구문
검색어에서 다음 연산자를 사용할 수 있습니다.
- ti:keyword
- 제목에서 검색
- au:author
- 저자 이름으로 검색- abs:keyword
- 초록에서 검색
- cat:category
- 카테고리로 필터링(예: cs.AI, quant-ph, math.CO)
- AND, OR, ANDNOT
- 불리언 연산자
예시:
- "ti:transformer AND cat:cs.LG"
- 머신 러닝 분야의 Transformer 논문
- "au:Hinton" - Geoffrey Hinton의 논문
- "quantum computing AND cat:quant-ph"
- 양자물리학 분야의 양자 컴퓨팅 논문
## 주요 카테고리
- cs.AI
- 인공지능
- cs.LG - 머신 러닝
- cs.CL - 자연어 처리
- cs.CV - 컴퓨터 비전
- quant-ph - 양자물리학
- math.CO - 조합론
- stat.ML - 머신 러닝(통계)
## 응답 형식논문를 소개할 때는 다음 형식을 사용합니다.
**"논문 제목"**
- 저자: [저자 이름]
- 출판일: [날짜]
- 카테고리: [카테고리]
- 요약: [초록의 간략한 요약]
- [논문 보기](arXiv URL)## 예외 상황 처리
- 검색 결과가 없는 경우: 대체 검색어나 더 포괄적인 검색어를 제안합니다.
- 검색 결과가 너무 많은 경우: 카테고리나 날짜 필터를 사용하여 검색 범위를 좁히도록 권장합니다.
- 사용자가 PDF를 요청하는 경우: 메타데이터만 제공할 수 있음을 설명하고, 논문에 접근할 수 있는 URL을 함께 제공합니다.
- 검색어가 불명확한 경우: 연구 분야나 구체적인 관심사에 대해 확인 질문을 합니다.
tools:
- search_arxivconfig:hidden: falseenable_cot: true
tags:
- research
- academic
- papers
- arxiv
- literature
-search
# Bob으로 생성됨
이 YAML 파일은 arXiv를 검색하고, 논문을 요약하며, 구조화된 형식으로 인용 정보를 제공하여 학술 연구를 간소화하는 전문 AI 에이전트인 Research Assistant를 구성합니다. 질의 구문과 툴 사용법부터 응답 형식과 예외 상황 처리까지 에이전트의 동작을 안내하는 자세한 지침이 포함되어 있습니다. 또한 search_arxivsetup-instructions.md
이 튜토리얼에서는 AI 중심 IDE이자 페어 개발자인 IBM Bob을 사용하여 학술 연구를 위한 MCP 통합 과정을 간소화했습니다. arXiv.org 리포지터리에서 논문을 검색하고 가져올 수 있는 확장 가능한 MCP 서버를 효율적으로 구축했습니다. 이제 이 솔루션은 연구 커뮤니티를 위해 오픈 소스로 공개하거나, 지식 탐색을 강화하기 위해 엔터프라이즈 애플리케이션에 배포할 수 있을 만큼 프로덕션 환경에 사용할 준비가 되었습니다.
IBM Bob의 진정한 강점은 복잡한 개발 작업을 직관적인 프롬프트 기반 워크플로로 전환하는 능력에 있습니다. 몇 가지 전략적인 프롬프트만으로 Bob은 프로토타입 개발을 가속화하고, 반복적인 코드를 줄이며, 최적화 방안까지 제안하여 구현보다 혁신에 집중할 수 있도록 지원합니다.
Bob의 기능을 계속 살펴보면서 MCP 서버를 어떻게 더욱 개선할 수 있을지 생각해 보세요. 예를 들어 고급 필터링, 실시간 업데이트 또는 PubMed나 IEEE Xplore와 같은 다른 학술 데이터베이스와의 통합 기능을 추가할 수 있습니다. 이 모든 기능과 그 이상의 작업도 IBM Bob에 몇 가지 간단한 프롬프트를 입력하는 것만으로 구현할 수 있습니다.
다음 단계로 나아갈 준비가 되셨나요? MCP 서버를 직접 사용자 지정해 보거나 Bob의 기능을 더 깊이 살펴보며 더 많은 자동화 가능성을 활용해 보세요. 즐거운 코딩 되세요!
생성형 AI로 워크플로와 프로세스를 자동화하는 강력한 AI 어시스턴트 및 에이전트를 구축, 배포, 관리하세요.
믿을 수 있는 AI 솔루션으로 비즈니스의 미래를 설계하세요.
IBM Consulting AI 서비스는 기업이 AI 활용 방식을 재구상하여 혁신을 달성하도록 지원합니다.