본문으로 건너뛰기

prompter

prompter는 XML 프롬프트 계약을 기준으로 LLM 요청을 실행하는 모듈입니다. OpenAI, Claude, Gemini, Ollama, LM Studio 같은 제공자를 LLMSource로 등록하고, transact에서는 CommandType=P로 라우팅합니다.

책임 범위

  • 프롬프트 계약을 읽어 provider, model, 메시지, body, tool 사용 범위를 구성합니다.
  • 요청 파라미터를 프롬프트 본문과 헤더, 인증 정보, body 속성에 바인딩합니다.
  • KernelPlugin, MCP 서버, CLI 도구, body 파일 경로 사용을 allowlist로 제한합니다.
  • LLM 응답을 HandStack 거래 응답 형식으로 변환합니다.
  • 요청/응답 로그와 채팅 이력 출력 여부를 설정으로 제어합니다.

주요 API

메서드경로용도
GET/prompter/api/query/has프롬프트 계약 존재 여부를 확인합니다.
GET/prompter/api/query/refresh프롬프트 계약 캐시를 갱신합니다.
GET/prompter/api/query/retrieve계약 원문 또는 상세 정보를 조회합니다.
GET/prompter/api/query/meta입력/출력 메타 정보를 반환합니다.
GET/prompter/api/query/reports계약 기반 보고용 정보를 조회합니다.
POST/prompter/api/query프롬프트 계약을 실행합니다.

핵심 구현

  • Areas/prompter/Controllers/QueryController.cs: query API 진입점입니다.
  • DataClient/PromptClient.cs: 프롬프트 계약 실행과 LLM provider 호출을 담당합니다.
  • Extensions/PromptMapper.cs: XML 계약 로드와 refresh를 담당합니다.
  • Entity/ModuleConfigJson.cs: LLMSource와 도구 allowlist 설정 스키마입니다.
  • Events/PrompterRequestHandler.cs: 모듈 내부 MediatR 실행 요청(prompter.Events.PrompterRequest)을 처리합니다.

계약과 식별자

계약은 기본적으로 다음 위치에 둡니다.

contracts/prompter/{ApplicationID}/{ProjectID}/{TransactionID}.xml

프롬프트 ID는 다음 형식으로 조회됩니다.

ApplicationID|ProjectID|TransactionID|PromptID

프롬프트 본문은 ${ParameterName} 형태로 요청 값을 치환합니다. authorization, headers, body 속성처럼 값 전체를 파라미터로 받을 때는 @ParameterName 형식을 사용합니다. statement의 role 기본값은 user이며, 시스템 지시문으로 전달할 계약만 role="system"을 명시합니다. <message>role을 생략하면 statement role을 상속합니다.

이미지·오디오 입력

계약의 <media>QueryObject.Parameters에 담긴 Base64 원문을 텍스트와 분리하여 provider별 멀티모달 메시지로 전달합니다.

<statement id="GP02" seq="0" role="system">
<message role="user"><![CDATA[
${UserMessage}
]]></message>
<param id="@UserMessage" type="String" length="-1" value="" />
<media id="@Image1" type="Image" mimeType="image/png" required="N" />
<media id="@Audio1" type="Audio" mimeType="audio/wav" required="N" />
</statement>
  • id<param>과 중복될 수 없으며 대소문자를 구분하지 않습니다.
  • typeImage, Audio만 허용합니다.
  • mimeTypeimage/png, image/jpeg, audio/wav, audio/mpeg 같은 구체적인 값이어야 하며 wildcard는 허용하지 않습니다.
  • required="Y"인 값이 없거나 값이 유효한 Base64가 아니면 provider 호출 전에 실패합니다. required="N"의 빈 값은 생략합니다.
  • 파라미터 값에는 URL이나 data:...;base64, 접두사를 넣지 않고 Base64 데이터만 넣습니다.
  • media 파라미터는 프롬프트, authorization, headers, body, pretransaction 텍스트 치환에서 제외되고 현재 statement가 만든 마지막 user 메시지에 첨부됩니다. user 메시지가 없으면 media 전용 메시지를 만듭니다.
LLMProviderImageAudioprovider 요청 형식
OpenAI지원지원 (audio/wav, audio/mpeg)Chat Completions content parts
Claude지원미지원Messages base64 image source
Gemini지원지원GenerateContent inlineData
Ollama지원미지원Chat message images
LM Studio지원미지원OpenAI 호환 image_url content part

provider뿐 아니라 선택한 모델도 해당 modality를 지원해야 합니다. 미지원 media는 네트워크 요청 전에 오류로 처리됩니다. prompter 내부 로그는 media 값을 [media:유형;base64-length:길이]로 마스킹하지만, 앞단 transact와 프록시 로그에도 원문을 저장하지 않도록 별도 정책을 적용해야 합니다.

실행 가능한 예시는 CLS010.xmlrequest.json에서 확인할 수 있습니다. 계약을 contracts/prompter/HDS/LLM/CLS010.xml에 배치하고 LLM1을 OpenAI 또는 Gemini의 멀티모달 모델로 설정한 뒤 request.json/prompter/api/query에 POST합니다.

주요 설정

설정설명
LLMSourceprovider, model, endpoint, API Key, stream/think 옵션을 정의합니다.
AllowedKernelPlugins계약에서 호출 가능한 커널 플러그인과 함수 allowlist입니다.
AllowedMcpServers계약에서 사용할 수 있는 MCP 서버 allowlist입니다.
AllowedCliTools프롬프트 실행 중 사용할 수 있는 CLI 도구 allowlist입니다.
AllowedBodyFileBasePathsbody 파일을 읽을 수 있는 기준 경로입니다.
IsChatHistoryConsoleShow채팅 이력을 콘솔에 출력할지 결정합니다.
EventAction기본값은 prompter.Events.ManagedRequest입니다.

LLMSource 예시는 다음과 같습니다.

{
"ApplicationID": "HDS",
"ProjectID": "*",
"DataSourceID": "LLM1",
"LLMProvider": "OpenAI",
"ApiKey": "<api-key>",
"ModelID": "gpt-5.4-mini",
"Endpoint": "",
"Think": false,
"Stream": false
}

ack 또는 rdyAppSettings:IsConfigurationWatchingtrue이면 실행 중 실제로 로드된 module.jsonLLMSource 변경을 감지해 PromptMapper.DataSourceMappings를 다시 구성합니다. 새 목록 전체가 유효할 때만 기존 캐시를 교체하며, provider 변환이나 API Key 복호화 오류가 있으면 이전 설정과 캐시를 유지합니다. 교체 완료 후 시작하는 요청부터 새 LLM 설정을 사용하고 빈 배열은 캐시 삭제로 반영됩니다.

LLMProvider 별로 사용 가능한 ModelID 목록

transact 연동

transact 거래 계약에서는 CommandTypeP로 둡니다.

{
"ServiceID": "GPT010",
"CommandType": "P",
"ReturnType": "Json"
}

라우팅 예시는 다음과 같습니다.

{
"HDS|*|P|D": "http://localhost:8421/prompter/api/query",
"HDS|*|P|P": "http://localhost:8421/prompter/api/query",
"HDS|*|P|T": "http://localhost:8421/prompter/api/query"
}

운영 주의사항

  • API Key, endpoint, 로컬 모델 경로는 실제 값으로 계약이나 공개 문서에 남기지 않습니다.
  • Ollama의 일부 qwen3 계열 모델은 비어 있지 않은 user role이 없는 요청을 거부합니다. prompter는 <message>가 없는 기존 system-only 계약을 Ollama로 호출할 때 마지막 유효한 system 메시지를 user로 정규화하며, 메시지 본문은 복제하지 않습니다.
  • 도구 호출은 계약 선언과 module.json allowlist가 모두 일치할 때만 허용되도록 관리합니다.
  • MCP, CLI, 파일 body 기능은 외부 시스템이나 파일 시스템에 접근할 수 있으므로 운영 환경에서는 최소 권한 원칙을 적용합니다.
  • LLM 응답은 비결정적일 수 있으므로 업무 거래에서는 후속 검증, 스키마 검사, 실패 시 fallback 전략을 함께 설계합니다.