본문 바로가기
카테고리 없음

ollama

by keisoft 2025. 5. 13.

네, Model Context Protocol(MCP)을 사용하는 C# 예제를 만들어 드리겠습니다. MCP는 다양한 LLM 모델 간에 컨텍스트와 상태를 공유하고 관리하기 위한 프로토콜입니다.

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace ModelContextProtocolExample
{
    class Program
    {
        // Ollama API 기본 URL
        private static readonly string OllamaBaseUrl = "http://localhost:11434/api";

        static async Task Main(string[] args)
        {
            Console.WriteLine("Model Context Protocol (MCP) 사용 예제 시작");

            var mcpClient = new McpClient(OllamaBaseUrl);

            try
            {
                // 사용 가능한 모델 리스트 가져오기
                Console.WriteLine("사용 가능한 모델 목록 가져오기:");
                var models = await mcpClient.ListModelsAsync();
                foreach (var model in models.Models)
                {
                    Console.WriteLine($"- {model.Name} ({model.Size})");
                }
                Console.WriteLine();

                // MCP 세션 시작하기
                string modelName = "llama3"; // 사용할 모델 이름 (설치된 모델로 변경 필요)
                Console.WriteLine($"'{modelName}' 모델로 MCP 세션 시작하기");

                // 초기 컨텍스트 설정
                var context = new McpContext
                {
                    Messages = new List<McpMessage>
                    {
                        new McpMessage { Role = "system", Content = "당신은 한국어에 능통한 유용한 AI 비서입니다." }
                    }
                };

                // 첫 번째 메시지 처리
                await SendMessageAndDisplayResponse(mcpClient, modelName, context, "안녕하세요! 당신은 누구인가요?");

                // 후속 메시지 처리 (컨텍스트 유지)
                await SendMessageAndDisplayResponse(mcpClient, modelName, context, "자연어 처리에 대해 간단히 설명해주세요.");

                // 컨텍스트 수정 (시스템 메시지 변경)
                Console.WriteLine("\n컨텍스트 수정: 시스템 메시지 변경");
                context.Messages[0] = new McpMessage { Role = "system", Content = "당신은 전문적인 데이터 과학자입니다." };
                
                // 수정된 컨텍스트로 메시지 처리
                await SendMessageAndDisplayResponse(mcpClient, modelName, context, "머신러닝 알고리즘 중 랜덤 포레스트에 대해 설명해주세요.");

                // 컨텍스트 리셋 예제
                Console.WriteLine("\n컨텍스트 리셋하기");
                context = new McpContext
                {
                    Messages = new List<McpMessage>
                    {
                        new McpMessage { Role = "system", Content = "당신은 창의적인 스토리텔러입니다." }
                    }
                };
                
                await SendMessageAndDisplayResponse(mcpClient, modelName, context, "우주를 배경으로 한 짧은 이야기를 만들어주세요.");

                // 함수 호출 예제
                Console.WriteLine("\n함수 호출 예제 (Tool 사용)");
                context = new McpContext
                {
                    Messages = new List<McpMessage>
                    {
                        new McpMessage { Role = "system", Content = "당신은 날씨 정보를 제공하는 AI 비서입니다. get_weather 함수를 사용하여 날씨 정보를 조회할 수 있습니다." },
                    },
                    Tools = new List<McpTool>
                    {
                        new McpTool
                        {
                            Type = "function",
                            Function = new McpFunction
                            {
                                Name = "get_weather",
                                Description = "지정된 위치의 현재 날씨 정보를 가져옵니다.",
                                Parameters = new
                                {
                                    Type = "object",
                                    Properties = new
                                    {
                                        Location = new
                                        {
                                            Type = "string",
                                            Description = "도시 이름, 예: 서울, 부산, 뉴욕"
                                        }
                                    },
                                    Required = new[] { "location" }
                                }
                            }
                        }
                    }
                };
                
                await SendMessageAndDisplayResponse(mcpClient, modelName, context, "서울의 날씨가 어떤가요?");
                
                // 함수 호출 결과 제공
                context.Messages.Add(new McpMessage { Role = "assistant", Content = null, ToolCalls = new List<McpToolCall>
                {
                    new McpToolCall
                    {
                        Id = "call_123",
                        Type = "function",
                        Function = new McpToolCallFunction
                        {
                            Name = "get_weather",
                            Arguments = "{\"location\":\"서울\"}"
                        }
                    }
                }});
                
                context.Messages.Add(new McpMessage
                {
                    Role = "tool",
                    ToolCallId = "call_123",
                    Content = "{\"temperature\":23.5,\"condition\":\"맑음\",\"humidity\":65}"
                });
                
                await SendMessageAndDisplayResponse(mcpClient, modelName, context, "");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"오류 발생: {ex.Message}");
            }

            Console.WriteLine("\n프로그램 종료. 아무 키나 누르세요...");
            Console.ReadKey();
        }

        // 메시지 전송 및 응답 표시를 위한 헬퍼 메서드
        private static async Task SendMessageAndDisplayResponse(McpClient client, string model, McpContext context, string userMessage)
        {
            if (!string.IsNullOrEmpty(userMessage))
            {
                Console.WriteLine($"\n사용자: {userMessage}");
                // 사용자 메시지를 컨텍스트에 추가
                context.Messages.Add(new McpMessage { Role = "user", Content = userMessage });
            }

            // 모델에 요청 전송
            var response = await client.GenerateWithMcpAsync(model, context);
            
            // 응답 표시
            Console.WriteLine($"AI: {response.Message.Content}");
            
            // 응답을 컨텍스트에 추가하여 대화 기록 유지
            context.Messages.Add(response.Message);
        }
    }

    // MCP 클라이언트 클래스
    public class McpClient
    {
        private readonly HttpClient _httpClient;
        private readonly string _baseUrl;
        private readonly JsonSerializerOptions _jsonOptions;

        public McpClient(string baseUrl)
        {
            _baseUrl = baseUrl;
            _httpClient = new HttpClient();
            _jsonOptions = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
            };
        }

        // 사용 가능한 모델 목록 가져오기
        public async Task<ModelsResponse> ListModelsAsync()
        {
            var response = await _httpClient.GetAsync($"{_baseUrl}/tags");
            response.EnsureSuccessStatusCode();
            
            var content = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<ModelsResponse>(content, _jsonOptions);
        }

        // MCP를 사용하여 텍스트 생성
        public async Task<McpResponse> GenerateWithMcpAsync(string model, McpContext context, float temperature = 0.7f)
        {
            var requestBody = new
            {
                model = model,
                messages = context.Messages,
                tools = context.Tools,
                temperature = temperature
            };

            var json = JsonSerializer.Serialize(requestBody, _jsonOptions);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
            
            var response = await _httpClient.PostAsync($"{_baseUrl}/chat", content);
            response.EnsureSuccessStatusCode();
            
            var responseContent = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<McpResponse>(responseContent, _jsonOptions);
        }
    }

    // MCP 응답 클래스
    public class McpResponse
    {
        public string Model { get; set; }
        public long Created { get; set; }
        public McpMessage Message { get; set; }
        public bool Done { get; set; }
        public long TotalDuration { get; set; }
        public long LoadDuration { get; set; }
        public long PromptEvalCount { get; set; }
        public long PromptEvalDuration { get; set; }
        public long EvalCount { get; set; }
        public long EvalDuration { get; set; }
    }

    // MCP 컨텍스트 클래스
    public class McpContext
    {
        public List<McpMessage> Messages { get; set; } = new List<McpMessage>();
        public List<McpTool> Tools { get; set; } = new List<McpTool>();
    }

    // MCP 메시지 클래스
    public class McpMessage
    {
        public string Role { get; set; }
        public string Content { get; set; }
        public List<McpToolCall> ToolCalls { get; set; }
        public string ToolCallId { get; set; }
    }

    // MCP 도구 클래스
    public class McpTool
    {
        public string Type { get; set; }
        public McpFunction Function { get; set; }
    }

    // MCP 함수 클래스
    public class McpFunction
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public object Parameters { get; set; }
    }

    // MCP 도구 호출 클래스
    public class McpToolCall
    {
        public string Id { get; set; }
        public string Type { get; set; }
        public McpToolCallFunction Function { get; set; }
    }

    // MCP 도구 호출 함수 클래스
    public class McpToolCallFunction
    {
        public string Name { get; set; }
        public string Arguments { get; set; }
    }

    // 모델 응답 클래스
    public class ModelsResponse
    {
        public List<ModelInfo> Models { get; set; }
    }

    public class ModelInfo
    {
        public string Name { get; set; }
        public string Modified { get; set; }
        public string Size { get; set; }
        public string Digest { get; set; }
    }
}

위 코드는 C#에서 Model Context Protocol(MCP)을 사용하는 예제입니다. MCP는 대화형 AI 모델과의 상호작용에서 컨텍스트를 관리하는 프로토콜로, Ollama API와 같은 LLM 서비스와 함께 사용됩니다.

### 주요 기능

1. **컨텍스트 관리**: 대화 내역을 메시지 목록으로 관리하여 대화의 연속성을 유지합니다.
2. **역할 기반 메시지**: system, user, assistant, tool 등 다양한 역할의 메시지를 지원합니다.
3. **도구 호출 (Function Calling)**: 모델이 외부 함수를 호출하여 추가 정보를 얻을 수 있습니다.
4. **컨텍스트 수정**: 대화 중 시스템 메시지나 컨텍스트를 동적으로 변경할 수 있습니다.

### 예제 시나리오

이 예제는 다음과 같은 시나리오를 포함합니다:

1. **기본 대화**: 시스템 메시지 설정 후 기본적인 질의응답 대화를 진행합니다.
2. **컨텍스트 수정**: 대화 중간에 시스템 메시지를 변경하여 모델의 역할을 변경합니다.
3. **컨텍스트 리셋**: 이전 대화를 버리고 새로운 컨텍스트로 시작합니다.
4. **함수 호출**: 날씨 정보 조회와 같은 외부 함수를 정의하고 모델이 이를 호출하는 과정을 시뮬레이션합니다.

### 사용 방법

1. Ollama가 로컬에 설치되어 있고 실행 중이어야 합니다.
2. Ollama API는 기본적으로 `http://localhost:11434`에서 제공됩니다.
3. `modelName` 변수를 설치된 모델 이름(예: "llama3")으로 변경해야 합니다.
4. 코드를 실행하면 여러 시나리오에 따른 MCP 사용 예제가 순차적으로 실행됩니다.

### 참고 사항

- 이 예제는 Ollama의 `/chat` 엔드포인트를 사용하며, 이는 MCP와 호환됩니다.
- MCP는 OpenAI의 Chat Completion API와 유사한 형식을 가지고 있어, 대부분의 LLM 서비스와 호환됩니다.
- 함수 호출 결과는 실제 API 호출 대신 하드코딩된 값을 사용하고 있습니다. 실제 애플리케이션에서는 외부 서비스와 연동하여 실제 데이터를 가져와야 합니다.

이 코드는 MCP를 사용하여 대화형 AI 시스템을 구축하는 기본적인 프레임워크를 제공합니다. 필요에 따라 확장하여 다양한 애플리케이션에 활용할 수 있습니다.