오늘날 AI 기능을 추가하는 대부분의 .NET 팀은 동일한 기본 작업을 작성하게 됩니다: HTTP 클라이언트, 재시도 정책, API 키에 대한 비밀 관리, 그리고 누군가의 신용카드에 대한 토큰당 청구 라인. Aspose.LLM은 다른 경로를 선택합니다. 이것은 자신의 프로세스 내부에서 대형 언어 모델 추론을 실행하는 NuGet 패키지이며, 호출할 서비스도 없고, 회전시킬 키도 없으며, 머신을 떠나는 요청도 없습니다.

이 문서는 라이브러리를 소개하고, API가 기반하고 있는 세 가지 개념을 설명하며, 작동하는 채팅 애플리케이션을 단계별로 안내합니다. 패키지 참조를 추가할 수 있다면, 몇십 줄만으로 프롬프트를 보낼 수 있습니다.

왜 로컬 모델이 중요한가

모델을 인프로세스로 실행하면 구축할 수 있는 것이 달라집니다.

  • 데이터가 그대로 유지됩니다. 프롬프트는 호스트를 떠나지 않으며, 이는 계약서, 의료 기록, 소스 코드 또는 데이터 거주 정책에 해당하는 기타 모든 작업을 할 때 중요합니다.
  • 토큰당 비용이 없습니다. 모델이 디스크에 있으면 추론은 이미 보유하고 있는 CPU 또는 GPU 비용이며, 측정된 API 호출이 아닙니다.
  • 런타임에 네트워크 의존성이 없습니다. 데스크톱 도구, 온프레미스 서비스 및 에어갭 환경 모두 동일하게 작동합니다.
  • 배포 아티팩트 하나. 모델 구성은 별도의 계정 대시보드에 존재하는 것이 아니라 애플리케이션과 함께 제공됩니다.

이 절충점은 솔직하며 미리 밝히는 것이 가치가 있습니다: 하드웨어를 제공해야 합니다. 로컬에서 실행되는 모델은 로컬 메모리가 필요하고, 첫 실행 시 몇 기가바이트를 다운로드해야 합니다.

Aspose.LLM for .NET 세 가지 개념으로

표면적은 의도적으로 작게 설계되었습니다. Aspose.LLM을 사용하여 수행하는 거의 모든 작업은 이 세 가지 유형과 관련됩니다.

ConceptTypeRole
라이선스Aspose.LLM.License라이브러리를 활성화합니다. 다른 API 사용 전에 SetLicense를 호출하십시오.
프리셋e.g. Qwen25Preset모델 파일을 샘플러 온도와 같은 생성 매개변수와 함께 번들링합니다.
API 인스턴스AsposeLLMApi진입점입니다. 프리셋에서 생성되며, 대화를 보관하고 SendMessageAsync를 노출합니다.

프리셋이 흥미로운 부분입니다. 모델 경로, 토크나이저 설정 및 샘플러 값을 직접 연결하는 대신, 프리셋은 검증된 조합을 패키징합니다. Qwen25Preset은 기본 시작점이며, 나중에 코드를 건드리지 않고도 매개변수를 조정하거나 다른 프리셋으로 교체할 수 있습니다.

전제 조건

코드를 작성하기 전에:

  1. 패키지 설치 - Install-Package Aspose.LLM
  2. 라이선스 배치 - 실행 파일이 런타임에 읽을 수 있는 위치에 Aspose.LLM.lic을 넣습니다.
  3. 메모리 예산 확인 - Qwen25 프리셋은 최소 8 GB의 자유 RAM이 필요합니다.

제품 세부 정보는 Aspose.LLM for .NET 제품 페이지를 확인하십시오.

첫 번째 채팅

실제 대화를 유지하는 가장 짧은 프로그램입니다. 두 번째와 세 번째 호출을 주목하세요: API 인스턴스가 자체적으로 컨텍스트를 추적하므로 모델은 여전히 Alice가 누구인지 알고 있습니다.

코드가 수행하는 작업

  1. License를 생성하고 라이선스 파일을 가리키도록 설정합니다.
  2. 기본 구성으로 Qwen25Preset을 인스턴스화합니다.
  3. 해당 프리셋에서 AsposeLLMApi 인스턴스를 하나 생성합니다.
  4. 동일한 대화를 공유하는 여러 프롬프트를 보냅니다.
using Aspose.LLM;
using Aspose.LLM.Abstractions.Parameters.Presets;

var license = new Aspose.LLM.License();
license.SetLicense("Aspose.LLM.lic");

var preset = new Qwen25Preset();
using var api = AsposeLLMApi.Create(preset);

string reply = await api.SendMessageAsync("What is 2 + 2?");
Console.WriteLine(reply);
// Output: 2 + 2 equals 4.

await api.SendMessageAsync("My name is Alice.");
string reply2 = await api.SendMessageAsync("What is my name?");
Console.WriteLine(reply2);
// Output: Your name is Alice.

AsposeLLMApi.Create(preset)은 세션 인식 클라이언트를 반환합니다. 각 SendMessageAsync 호출은 프롬프트를 현재 대화에 추가하므로 상태를 직접 관리하지 않아도 다중 턴 동작을 얻을 수 있습니다. using 선언이 중요합니다 — 인스턴스는 네이티브 리소스를 소유하고 있으며 해제되어야 합니다.

참고: 이 샘플은 공식 Aspose 문서를 따르며 샌드박스에서 실행되지 않았습니다. 배포하기 전에 자체 환경에서 확인하십시오.

단일 요청에 대한 동작 튜닝

대화형 답변은 약간의 무작위성을 활용하면 좋습니다. 산술은 그렇지 않습니다. 인스턴스를 다시 구성하는 대신 두 번째 프리셋을 만들고 필요한 호출에 전달하십시오.

코드가 수행하는 작업

  1. 기본 프리셋과 API 인스턴스를 평소와 같이 생성합니다.
  2. 낮은 샘플러 온도로 strictPreset을 빌드합니다.
  3. preset 인수를 통해 SendMessageAsync에 전달합니다.
  4. 이후 호출은 원래 기본값을 그대로 둡니다.
using Aspose.LLM.Abstractions.Parameters.Presets;

// Default preset used by the API instance
var defaultPreset = new Qwen25Preset();
using var api = AsposeLLMApi.Create(defaultPreset);

// A more deterministic preset, for this question only
var strictPreset = new Qwen25Preset();
strictPreset.SamplerParameters.Temperature = 0.1f;

string reply = await api.SendMessageAsync(
    "What is the square root of 144?",
    preset: strictPreset);

Console.WriteLine(reply);
// Output: The square root of 144 is 12.

SamplerParameters.Temperature는 샘플러가 도입하는 무작위성 정도를 제어합니다. 0.1에 가까운 값은 거의 결정론적인 출력을 생성하고, 더 높은 값은 보다 다양한 표현을 생성합니다. 프리셋이 호출에만 적용되기 때문에, 오버라이드는 대화의 나머지 부분에 누출되지 않습니다.

취소 및 타임아웃

생성 길이는 완전히 예측할 수 없으며, 오래 실행되는 요청은 이를 기다리는 모든 작업을 차단합니다. SendMessageAsync는 CancellationToken을 받아들이므로, 이를 제공하십시오.

코드가 수행하는 작업

  1. 30초 예산으로 CancellationTokenSource를 생성합니다.
  2. cts.Token을 SendMessageAsync에 전달합니다.
  3. OperationCanceledException을 잡고 정상적으로 처리합니다.
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

try
{
    string reply = await api.SendMessageAsync(
        "Write a 500-word essay about migration patterns of the Arctic tern.",
        cancellationToken: cts.Token);
    Console.WriteLine(reply);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Generation timed out.");
}

취소는 세션 상태를 그대로 유지하므로 다음 호출에서 대화가 정상적으로 계속됩니다. ASP.NET Core 핸들러에서 여기에도 요청 자체의 RequestAborted 토큰을 전달하십시오 — 이미 연결이 끊긴 클라이언트를 위해 계속 생성할 이유가 없습니다.

전체 콘솔 애플리케이션

전체를 합치면: 프로세스가 실행되는 동안 하나의 세션을 유지하고 메시지당 실패에서 복구하는 REPL.

코드가 수행하는 작업

  1. 시작 시 라이선스와 기본 프리셋을 한 번 설정합니다.
  2. 전체 프로그램에 대해 단일 AsposeLLMApi 인스턴스를 생성합니다.
  3. 사용자가 quit를 입력할 때까지 사용자 입력을 반복합니다.
  4. 각 줄을 전송하고 응답을 출력합니다.
  5. 메시지마다 예외를 잡아 하나의 실패가 세션을 종료하지 않도록 합니다.
using Aspose.LLM;
using Aspose.LLM.Abstractions.Parameters.Presets;

internal class SimpleChatDemo
{
    public static async Task Main()
    {
        var license = new Aspose.LLM.License();
        license.SetLicense("Aspose.LLM.lic");

var preset = new Qwen25Preset();
        using var api = AsposeLLMApi.Create(preset);

Console.WriteLine("Ask me anything. Type 'quit' to exit.");
        while (true)
        {
            Console.Write("> ");
            string? line = Console.ReadLine();
            if (line == null || line.Equals("quit", StringComparison.OrdinalIgnoreCase))
                break;

try
            {
                string reply = await api.SendMessageAsync(line);
                Console.WriteLine(reply);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }
        }
    }
}

두 가지 설계 포인트는 실제 애플리케이션에 적용할 가치가 있습니다. 첫 번째로, 인스턴스는 once 한 번만 생성되고 재사용됩니다 — 생성 비용이 많이 들며, 다음 섹션에서 설명하듯이 동시에 여러 인스턴스를 사용할 수 없습니다. 두 번째로, try-catch는 루프 안에 위치하고 루프 전체를 감싸지 않으므로, 하나의 잘못된 메시지가 전체 세션이 아니라 한 번의 턴만 소모하게 됩니다.

라이브러리를 임시 라이선스로 평가하려면 Aspose 임시 라이선스 페이지에서 확인하십시오.

먼저 마주칠 가능성이 있는 오류

오류일반적인 원인해결 방법
Not licensed for this method라이선스 파일이 없거나 경로가 잘못되었습니다작업 디렉터리에서 Aspose.LLM.lic 파일을 읽을 수 있는지 확인하고, 다른 API 호출 전에 SetLicense가 실행되는지 확인하십시오.
Only one AsposeLLMApi instance can be created at a time두 인스턴스가 동시에 존재함, 보통 요청당 팩토리에서 발생인스턴스를 싱글톤으로 등록하거나, 새 인스턴스를 만들기 전에 이전 인스턴스를 폐기하십시오.
First response takes minutes엔진이 네이티브 바이너리와 모델 가중치를 다운로드하고 있습니다깨끗한 머신에서 5-15분 정도 소요될 것으로 예상하십시오. Create를 시작 시에 트리거하여 비용이 사용자에게 부과되지 않도록 하십시오.

그 두 번째 행은 서비스 시나리오에서 강조될 필요가 있습니다. Aspose.LLM을 DI 컨테이너에 연결하고 있다면, AsposeLLMApi를 싱글톤으로 등록하고 접근을 직렬화하십시오 — 스코프 또는 트랜지언트 등록은 두 요청이 겹치는 순간 실패합니다.

추가 리소스

결론

Aspose.LLM은 “add an LLM to this .NET application"을 세 가지 유형과 하나의 메서드로 축소합니다. 라이선스는 라이브러리를 활성화하고, 프리셋은 모델과 생성 방식을 정의하며, AsposeLLMApi 인스턴스가 대화를 전달합니다. 여기서 SendMessageAsync는 단일 질문, 다중 턴 세션, 호출당 매개변수 재정의, 그리고 취소 가능한 장기 실행 생성을 처리합니다.

콘솔 샘플부터 시작하여 모델이 기능에 필요한 방식대로 동작하는지 확인한 다음, 기본이 확실해지면 멀티 세션 및 지속성 작업으로 넘어갑니다.

자주 묻는 질문

1. Aspose.LLM for .NET이란?

.NET 프로세스 내에서 대형 언어 모델 추론을 실행하는 NuGet 라이브러리입니다. 프리셋을 만들고, API 인스턴스를 생성한 다음 프롬프트를 전송합니다 — 외부 서비스 없이, API 키도 필요 없습니다.

2. 사용하려면 인터넷 연결이 필요합니까?

첫 번째 실행에만 해당됩니다. 초기 Create 호출은 프리셋에 정의된 네이티브 엔진 및 모델 파일을 다운로드하고, 이후 자산은 로컬에 캐시됩니다.

3. 코드 샘플에 필요한 사전 조건은 무엇인가요?

Aspose.LLM NuGet 패키지, 유효한 Aspose.LLM.lic 파일, 그리고 선택한 프리셋에 충분한 자유 RAM이 필요합니다 — Qwen25의 경우 최소 8 GB를 계획하세요.

4. 단일 요청에 대한 모델의 동작을 어떻게 변경합니까?

두 번째 프리셋을 만들고, 해당 프리셋의 매개변수(예: SamplerParameters.Temperature)를 조정한 다음, preset 인수를 통해 SendMessageAsync에 전달합니다. 이후 호출은 인스턴스의 기본 프리셋으로 되돌아갑니다.

5. 시간이 너무 오래 걸리는 생성 작업을 어떻게 중단하나요?

SendMessageAsync에 CancellationToken을 전달하고 OperationCanceledException을 잡으세요. 세션 상태는 취소 후에도 유지되므로 대화가 정상적으로 계속됩니다.

6. 첫 번째 응답이 왜 이렇게 느린가요?

첫 번째 Create 호출은 네이티브 바이너리와 모델 가중치를 다운로드하며, 이는 깨끗한 머신에서 5~15분 정도 걸릴 수 있습니다. 사용자의 첫 요청이 아니라 애플리케이션 시작 시 인스턴스를 미리 워밍업하세요.

Read More