Delphi와 .NET을 위한 AI 문서 추출

· 컴포넌트
Delphi와 .NET을 위한 AI 문서 추출

대부분의 업무용 소프트웨어에는 여전히 PDF를 읽고 그 숫자를 손으로 폼에 입력하는 사람이 있습니다. 공급업체 청구서, 매장 영수증, 접수처에서 스캔하는 신분증까지 다양합니다. 오늘날 대형 언어 모델은 이런 문서를 잘 읽어내지만, 모델에게 "청구서 데이터"를 요청하면 산문 형태의 답이 나오거나, 모델이 그때그때 떠오른 형태로 만든 JSON이 나오며, 어떤 값을 확신하지 못했는지 알 방법이 없습니다.

sgcWebSockets 2026.10은 Delphi, C++Builder, .NET용 TsgcAIDocumentExtractor를 추가합니다. PDF나 이미지를 주면, 이미 사용 중인 TsgcAIChat을 통해 모델에게 질의하고, 스키마에 대해 검증된 JSON을 각 필드의 신뢰도와 함께 돌려줍니다. 이 컴포넌트는 현재 다운로드 버전에는 포함되어 있지 않습니다. 2026.10 릴리스와 함께 제공됩니다.

TsgcAIDocumentExtractor가 Anthropic Claude로 실제 청구서 PDF를 읽고 필드별 신뢰도가 포함된 검증된 JSON을 반환하는 모습입니다. YouTube에서도 보기.

PDF를 입력하면 JSON이 출력됩니다

폼에 TsgcAIChat과 TsgcAIDocumentExtractor를 배치하고, 추출기가 채팅을 가리키도록 설정한 다음 프리셋을 선택하고 ExtractFile을 호출합니다. OpenAI, Anthropic, Gemini는 PDF 파일을 그대로 읽습니다. DeepSeek, Grok, Mistral, Ollama는 이미지만 받으므로, 이 제공자들의 경우 페이지를 PNG나 JPEG로 전송합니다.

uses
  sgcAI, sgcAI_Chat, sgcAI_DocumentExtractor;

procedure TForm1.btnExtractClick(Sender: TObject);
begin
  oChat := TsgcAIChat.Create(Self);
  oChat.Provider := aicpAnthropic;
  oChat.ChatOptions.ApiKey := 'your-api-key';

  oExtractor := TsgcAIDocumentExtractor.Create(Self);
  oExtractor.AIChat := oChat;
  oExtractor.Preset := dpInvoice;

  Memo1.Lines.Text := oExtractor.ExtractFile('invoice.pdf');
end;

이것이 동영상에서 보여준 흐름이며, 실제 청구서 PDF로 Anthropic Claude를 대상으로 실시간 검증을 거쳤습니다. ExtractFiles는 한 문서의 여러 페이지를 한 번의 요청으로 전송하고, ExtractAttachments는 이미 메모리에 base64로 보관 중인 문서를 받습니다.

추출기는 TsgcAIChat을 통해 작업을 수행하며, 이 컴포넌트도 여러분의 프롬프트를 위해 동일한 기능을 갖게 됩니다. ChatWithDocument는 메시지와 함께 PDF나 이미지를 전송하고, ChatWithAttachments는 여러 개를 한 번에 전송하며, ChatJSONWithAttachments는 그것들에 대한 JSON 답변을 요청합니다. 새로운 TLSOptions 속성은 모든 제공자에서 사용되는 OpenSSL 버전, IOHandler, 인증서를 설정합니다.

Memo1.Lines.Text := oChat.ChatWithDocument('Summarize this contract', 'contract.pdf');

oFiles := TsgcAIChatAttachments.Create;
try
  oFiles.AddFile('page1.png');
  oFiles.AddFile('page2.png');
  Memo1.Lines.Text := oChat.ChatJSONWithAttachments(
    'List every line item as JSON', oFiles);
finally
  oFiles.Free;
end;

프리셋과 사용자 정의 스키마

세 가지 프리셋이 일반적인 문서를 처리합니다. dpInvoice, dpReceipt, dpIDCard입니다. 각각 고유한 JSON 스키마와 추출 지침을 포함하므로 별도로 설정할 것이 없습니다. 그 외의 문서는 Preset을 dpCustom으로 설정하고 스키마를 직접 작성하면 됩니다.

oExtractor.Preset := dpCustom;
oExtractor.SchemaName := 'purchase_order';
oExtractor.Schema.Text :=
  '{"type": "object", "additionalProperties": false,' +
  ' "required": ["order_number", "supplier", "total"],' +
  ' "properties": {' +
  '   "order_number": {"type": "string"},' +
  '   "supplier": {"type": ["string", "null"]},' +
  '   "total": {"type": "number"}}}';
oExtractor.Instructions.Text := 'Write every amount without a currency symbol.';

OpenAI에서는 스키마가 strict 모드로 전송되므로 엄격한 규칙을 따라야 합니다. 모든 객체는 "additionalProperties": false를 선언해야 하고, 모든 속성은 required에 나열되어야 하며, 선택적 값은 ["string", "null"]처럼 null을 허용하는 타입을 사용해야 합니다. 내장 프리셋은 이미 이 규칙을 따릅니다. 그중 하나를 기반으로 필드를 추가하려면 TsgcAIDocumentExtractor.GetPresetSchema(dpInvoice)로 복사하면 됩니다.

검증과 재시도

응답은 검증 없이 코드에 전달되는 법이 없습니다. 추출기는 스키마를 기준으로 로컬에서 검증합니다. 타입, 필수 속성, 중첩된 객체와 배열, 열거형까지 확인합니다. 일치하지 않으면 컴포넌트가 모델에 무엇이 잘못되었는지 알리고 다시 한번 요청합니다. ValidationRetries는 재시도 횟수를 설정하며 기본값은 1입니다.

재시도 후에도 데이터가 여전히 유효하지 않으면 추출기는 예외를 발생시킵니다. RaiseOnInvalid를 False로 설정하면 그래도 데이터를 받을 수 있고, 문제는 LastResult.ValidationErrors에서 확인할 수 있으며, 각 줄은 path: message 형식입니다.

oExtractor.ValidationRetries := 1;
oExtractor.RaiseOnInvalid := False;

Memo1.Lines.Text := oExtractor.ExtractFile('invoice.pdf');
if not oExtractor.LastResult.Valid then
  Memo1.Lines.AddStrings(oExtractor.LastResult.ValidationErrors);

신뢰도와 사람의 검토

유효한 JSON이 올바른 JSON과 같은 것은 아닙니다. 흐릿한 합계나 번진 날짜도 형식은 올바른 숫자를 만들어낼 수 있습니다. 그래서 모델은 추출한 모든 필드에 대해 얼마나 확신하는지도 함께 보고하며, 추출기는 그 값들을 제공합니다. LastResult.Confidence는 그중 가장 낮은 값이고, LastResult.FieldConfidence('total')은 특정 경로의 값을 반환하며, OnLowConfidence는 MinConfidence 미만인 필드마다 한 번씩 발생합니다.

oExtractor.MinConfidence := 0.8;
oExtractor.OnLowConfidence := OnLowConfidenceEvent;
Memo1.Lines.Text := oExtractor.ExtractFile('invoice.pdf');

if oExtractor.LastResult.FieldConfidence('total') < 0.8 then
  ShowMessage('Check the total by hand');

procedure TForm1.OnLowConfidenceEvent(Sender: TObject; const aField: string;
  aConfidence: Double);
begin
  lstReview.Items.Add(Format('%s: %.2f', [aField, aConfidence]));
end;

덕분에 검토 대기열을 사람이 실제로 처리할 수 있는 수준으로 바꿀 수 있습니다. 청구서 전체가 아니라 모델이 확신하지 못한 두 필드만 확인하면 됩니다.

로컬 OCR, 아무것도 외부로 나가지 않습니다

일부 문서는 클라우드 서비스로 전혀 보내서는 안 됩니다. OCR 컴포넌트를 추출기에 연결하고 원하는 엔진을 선택하세요. TsgcAIOCRTesseract는 머신에 설치된 Tesseract OCR 엔진을 실행합니다. TsgcAIOCRWindows는 Windows 10 이상에 내장된 텍스트 인식 기능을 사용하므로 별도로 설치할 것이 없습니다. OCRMode를 domAlways로 설정하면 이미지는 절대 모델로 전송되지 않습니다. OCR 엔진이 로컬에서 텍스트를 읽고, Ollama 같은 텍스트 모델이 추출을 수행하므로 전체 파이프라인이 여러분의 하드웨어에서만 실행됩니다.

oOCR := TsgcAIOCRTesseract.Create(Self);
oOCR.Language := 'eng';

oChat.Provider := aicpOllama;
oChat.ChatOptions.Model := 'llama3.1';

oExtractor.OCR := oOCR;
oExtractor.OCRMode := domAlways;
oExtractor.Preset := dpReceipt;
Memo1.Lines.Text := oExtractor.ExtractFile('receipt.png');

Windows 엔진은 en-US와 같은 BCP-47 언어 태그를 받으며, Language를 비워두면 사용자 프로필의 언어를 사용합니다.

oWinOCR := TsgcAIOCRWindows.Create(Self);
oWinOCR.Language := 'en-US';

oExtractor.OCR := oWinOCR;
oExtractor.OCRMode := domFallback;
Memo1.Lines.Text := oExtractor.ExtractFile('invoice.png');

이 두 번째 예제에서 사용된 domFallback은 또 다른 선택지입니다. 추출기는 먼저 비전 요청을 시도하고, 그 요청이 실패했을 때만 인식된 텍스트를 사용하며, 이때 OnOCRFallback을 발생시켜 알려줍니다. LastResult.UsedOCR과 LastResult.OCRText는 나중에 어느 경로가 데이터를 만들어냈는지 알려줍니다. OCR 단계는 이미지를 읽으므로 스캔된 PDF는 페이지 이미지로 입력됩니다.

닷넷을 위한 C#

sgcWebSockets의 .NET 버전은 esegece.sgcWebSockets 네임스페이스에 동일한 이름의 동일한 컴포넌트를 제공합니다. 프리셋, 신뢰도 값, 이벤트 모두 동일한 방식으로 동작하며, 두 OCR 엔진인 TsgcAIOCRTesseract와 TsgcAIOCRWindows 역시 제공됩니다.

using esegece.sgcWebSockets;

var chat = new TsgcAIChat();
chat.Provider = TsgcAIChatProvider.aicpAnthropic;
chat.ChatOptions.ApiKey = "your-api-key";

var extractor = new TsgcAIDocumentExtractor();
extractor.AIChat = chat;
extractor.Preset = TsgcAIDocumentPreset.dpInvoice;
extractor.MinConfidence = 0.8;
extractor.OnLowConfidence += (sender, field, confidence) =>
    Console.WriteLine($"review {field}: {confidence:0.00}");

string json = extractor.ExtractFile("invoice.pdf");
Console.WriteLine(json);
Console.WriteLine($"valid: {extractor.LastResult.Valid}, confidence: {extractor.LastResult.Confidence:0.00}");

제공 시기

TsgcAIDocumentExtractor, TsgcAIOCRTesseract, TsgcAIOCRWindows, 그리고 새로운 TsgcAIChat 메서드들은 sgcWebSockets 2026.10에서 Delphi, C++Builder, .NET용으로 제공됩니다. 현재 다운로드할 수 있는 버전에는 포함되어 있지 않습니다. 2026.10이 출시되면 다운로드 페이지에서 받을 수 있습니다.

모든 속성과 이벤트, 그리고 청구서 처리 단계별 가이드를 포함한 전체 레퍼런스는 TsgcAIDocumentExtractor 도움말에서 확인할 수 있습니다. AI 컴포넌트가 제공하는 그 밖의 기능은 sgcAI 제품 페이지와 sgcWebSockets AI 페이지를 참고하세요.

다음 읽을거리

질문이나 피드백, 마이그레이션 관련 도움이 필요하신가요? 문의하기. 코드를 직접 작성한 사람들이 답변해 드립니다.