<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>geoffyoon-dev.log</title>
        <link>https://velog.io/</link>
        <description>뇌피셜에 근거한 뻘소리에 약간의 테크를 가미합니다.</description>
        <lastBuildDate>Fri, 05 Apr 2024 09:19:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>geoffyoon-dev.log</title>
            <url>https://velog.velcdn.com/images/geoffyoon-dev/profile/92bd357e-68ac-456e-a28d-a9cec2df9a9d/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. geoffyoon-dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/geoffyoon-dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[데이터는 못 보내지만 Cloud LLM은 쓰고싶어]]></title>
            <link>https://velog.io/@geoffyoon-dev/cloud-LLM-in-data-security-policy</link>
            <guid>https://velog.io/@geoffyoon-dev/cloud-LLM-in-data-security-policy</guid>
            <pubDate>Fri, 05 Apr 2024 09:19:01 GMT</pubDate>
            <description><![CDATA[<p>바로 데모를 실행해보고 싶으신 분은  <a href="https://colab.research.google.com/drive/12AvHi10g4krezB3zNzW0S7D5HpKaMjTk"><img alt="Open In Colab" src="https://colab.research.google.com/assets/colab-badge.svg" style="display:inline;"></a> 이쪽으로 들어가시면 됩니다.</p>
<h1 id="들어가며">들어가며</h1>
<p>기업 내부의 데이터를 LLM에게 전송하지 않고도 클라우드 LLM의 파워를 최대한 사용하는 방법이 있을까요?</p>
<p>클라우드메이트에서는 이를 위해 기본적으로 <code>NL2SQL</code>기법과 함께, 나아가 프롬프트를 통해 데이터를 은닉하는 <code>masked data prompting</code>기법을 제안합니다.</p>
<h1 id="데이터-보안-정책">데이터 보안 정책</h1>
<p>많은 기업에서는 정보보안을 위해 내부 데이터가 네트워크를 통해 밖으로 나가는 것을 정책적으로 철저히 막고 있습니다. </p>
<p>일부 조직은 해당 데이터 거버너스에 대해 자유롭거나 정책조정이 가능하지만 특정 조직은 매우 민감한 데이터를 다루고 있어 이러한 점에 있어서 조심스럽습니다.</p>
<p>하지만 이러한 데이터 보안 정책에 묶여있는 조직도 Azure의 OpenAI GPT나 GCP의 Gemini, Anthopic(AWS)의 Claude 등의 클라우드 LLM(Large Language Model: 초거대언어모델)을 사용하고 싶어합니다.
<img src="https://velog.velcdn.com/images/geoffyoon-dev/post/9565aa7a-ff78-4fcd-a07e-125c166d12ad/image.jpg" alt="데이터는 못 보내지만 Cloud LLM은 쓰고싶어"></p>
<p>그래서 이들에게 필요한 것은 내부의 데이터를 내보내지 않더라도 최대한 클라우드 LLM의 파워를 사용하도록 하는 것입니다.</p>
<h1 id="정책-안에서-클라우드-llm-사용하기">정책 안에서 클라우드 LLM 사용하기</h1>
<p>기업차원에서 LLM을 사용하는 가장 대표적인 방법이면서 수요가 가장 높은 방식은 기업 자체의 데이터와 LLM을 결합하는 방식입니다. 하지만 기업 내부의 그 어떤 데이터도 LLM으로 보낼 수 없다면 방법이 없을까요?</p>
<p>사실 이를 우회하거나 해결할 수 있는 방법은 있습니다. 다음과 같은 방법들이죠</p>
<ul>
<li>Open source LLM을 On-premise에서 가동</li>
<li>NL2SQL</li>
<li>masked data prompting</li>
</ul>
<p>Open source LLM는 추후에 이야기하도록 하고 이번 시간에는 <code>NL2SQL</code>과 클라우드메이트의 <code>masked data prompting</code>을 위주로 이야기하려 합니다.</p>
<h2 id="nl2sql">NL2SQL</h2>
<p>자연어를 SQL문으로 바꾸는 개념인 NL2SQL은 본래 데이터 정책을 위해 만들어진 개념은 아니었습니다. </p>
<p>LLM이 등장하기 전부터 자연어를 통해 프로그래밍 언어 코드를 작성하려는 시도와 함꼐 프로그래밍과 SQL작성의 편의를 위해 연구되었습니다.</p>
<p>그리고 GPT, Claude, Gemini 등의 클라우드 LLM이 등장하면서 이러한 시도는 프롬프트 엔지니어링 레벨로 넘어가 좀 더 좋은 결과를 얻을 수 있었습니다.</p>
<h3 id="기존의-sql작성-방식">기존의 SQL작성 방식</h3>
<p>의사결정을 위해 데이터를 조회할 때, 기존의 방식은 개발자나 DB관련 엔지니어가 SQL을 작성하고 그 결과를 주는 방식이었습니다.</p>
<p><img src="https://velog.velcdn.com/images/geoffyoon-dev/post/4d56ac86-e7ba-4333-add3-4e3865080f76/image.jpg" alt=""></p>
<h3 id="llm을-이용한-sql작성-방식">LLM을 이용한 SQL작성 방식</h3>
<p>기존의 방식은 데이터 모델과 SQL을 잘 이해하는 사람만이 작성하여 데이터를 조회할 수 있었습니다.
히자만 실제 데이터를 조회하는 사람은 이러한 개발자나 엔지니어가 아닐 수 있습니다. </p>
<p>이러한 사람들을 위해 LLM으로 자연어 형태의 질의를 하면 LLM이 SQL로 변환하여 데이터를 조회하는 방식을 사용할 수 있습니다.
<img src="https://velog.velcdn.com/images/geoffyoon-dev/post/5b09775c-47d3-47c6-82dd-d8e072f47bb6/image.jpg" alt="LLM을 이용해 SQL을 작성하는 방식 이미지"></p>
<h3 id="데이터-정책과-nl2sql">데이터 정책과 NL2SQL</h3>
<p>그렇다면 이러한 ML2SQL로 어떻게 데이터 보안 정책상에서 클라우드 LLM과 기업 데부 데이터를 결합할 수 있다는 것일까요?</p>
<p>기업마다 데이터 거버넌스가 다르겠지만 일반적으로 기업 데이터 자체의 유출은 철저하게 막습니다. 하지만 데이터 자체가 아닌 데이터 스키마가 외부로 나가는 것은 부분적으로 혀용하고 있는 곳이 많습니다. 
<img src="https://velog.velcdn.com/images/geoffyoon-dev/post/8baede3d-dc7d-4f76-bb98-c2ac606500bd/image.jpg" alt="LLM을 이용해 SQL을 작성하는 방식 이미지"></p>
<p>이렇게 데이터 스키마를 전송하고 SQL을 받게 되면 그 이후에는 해당 SQL로 데이터를 조회만 하면 되는 것입니다. 이렇게 되면 클라우드 LLM이 직접적으로 내부 데이터를 받지 않더라도 처리가 가능합니다.</p>
<h3 id="nl2sql-데모">NL2SQL 데모</h3>
<p>여러분의 이해를 돕기 위해 <a href="https://colab.research.google.com/drive/12AvHi10g4krezB3zNzW0S7D5HpKaMjTk"><img alt="Open In Colab" src="https://colab.research.google.com/assets/colab-badge.svg" style="display:inline;"></a>에서 데모를 제공하고 있습니다.</p>
<h4 id="데이터-준비">데이터 준비</h4>
<p>데이터는 <a href="https://rt.molit.go.kr/pt/xls/xls.do?mobileAt=">국토교통부 실거래가 공개시스템</a>의 2024년 3월 한달간의 아파트 매매 데이터를 이용하였습니다.</p>
<p><img src="https://velog.velcdn.com/images/geoffyoon-dev/post/0a8ca62b-3460-4411-b884-206cce6138b8/image.png" alt=""></p>
<p>이 데이터를 편의상 sqlite3에 저장하고 쿼리하는 예제로 준비했습니다.</p>
<h4 id="프롬프트">프롬프트</h4>
<p>자연어를 SQL로 변환하기 위해서는 해당 task를 수행하도록 프롬프트로 LLM에 전달해야 합니다. </p>
<p>프롬프트에 들어갈 사항은 다음과 같습니다.</p>
<ul>
<li>role : LLM에게 역할을 부여해서 해당 task를 잘 수행하도록 지시합니다.</li>
<li>context : 도메인에 대한 특수한 정보나 작업 방식들을 알려줘야 합니다.</li>
<li>schemas : SQL을 만들기 위한 DB table의 정보를 제공해줘야 합니다.</li>
<li>step : CoT(Chain of Thought)를 위해 LLM이 수행해야 하는 생각(작업)을 단계적으로 명시할 수 있습니다.</li>
<li>output : LLM이 응답할 데이터 포멧이나 언어를 지시할 수 있습니다.</li>
<li>instruction : 실제로 LLM이 어떤 명령을 수행해야 하는지 지시합니다.</li>
<li>example : 질의와 LLM 답변에 대한 예시를 제공합니다.</li>
</ul>
<p>아래는 역할부여, single-turn CoT, few-shot등의 기법이 적용된 NL2SQL의 프롬프트입니다.</p>
<pre><code class="language-prompt">[ROLE]
You are the world&#39;s best database engineer and sqlite expert.

[CONTEXT]
You have actual apartment price data.
Based on this data, we can provide tailored answers to user questions.
In order to write SQL in SQLite3, you must refer to [SCHEMAS] and process it according to the processing order defined in [STEP].
&#39;평&#39; calculates the square meter area divided by 3.3.

[SCHEMAS]
{schemas}

[STEP]
1. keywords: Extract key keywords from user queries.
2. columns: Refer to [SCHEMA] and extract the column names corresponding to the main keywords extracted in 1. At this time, the column name must be extracted as {{{{table_name}}}}.{{{{column_name}}}} and must be a column name that exists in the table.
3. tables: Refer to 1 and 2 to extract the required tables.
4. conditions: Write conditions to answer the question. If not found, null is output.
5. group: Write data grouping column and column aggregration. If not found, null is output.
6. order_by: Write conditions for data output order. If not found, null is output.
7. prepared_sql: Write SQL for sqlite based on items 1 to 6.

[OUTPUT]
The output format is as follows:
{{
    &quot;keywords&quot; : {{{{keywords:list(str)}}}},
    &quot;columns&quot; : {{{{columns:list(str)}}}},
    &quot;tables&quot; : {{{{tables:list(str)}}}},
    &quot;conditions&quot; : {{{{conditions:list(str) | null}}}},
    &quot;group&quot; : {{{{ {{
        &quot;group_by&quot; : {{{{group_by_columns:list(str)}}}},
        &quot;aggregations&quot; : {{
            {{{{column1}}}} : {{{{operations1}}}},
            {{{{column2}}}} : {{{{operations2}}}}
        }}
    }} | null}}}},
    &quot;order_by&quot; : {{
        {{{{column1}}}} : {{{{ ASC | DESC }}}},
        {{{{column2}}}} : {{{{ ASC | DESC }}}}
    }},
    &quot;prepared_sql&quot; : {{{{prepared_sql}}}}
}}

[INSTRUCTION]
Refer to [SCHEMA] and create sql statements that can answer the following user questions in the manner described in [CONTEXT].
---
question : 지역별 거래금액 평균을 알려줘
answer : {{
    &quot;keywords&quot; : [&quot;지역별&quot;,&quot;거래금액&quot;, &quot;평균&quot;],
    &quot;columns&quot; : [&quot;real_transaction.시군구&quot;,&quot;real_transaction.거래금액_만원&quot;],
    &quot;tables&quot; : [&quot;real_transaction&quot;],
    &quot;conditions&quot; : null,
    &quot;group&quot; : {{
        &quot;group_by&quot; : [&quot;시군구&quot;],
        &quot;aggregations&quot; : {{
            &quot;거래금액_만원&quot; : &quot;AVG&quot;
        }}
    }},
    &quot;order_by&quot; : null,
    &quot;prepared_sql&quot; : &quot;SELECT 시군구,AVG(거래금액_만원) AS 평균_거래금액 FROM real_transaction GROUP BY 시군구&quot;
}}
---
question : 서울특별시 강남구 대치동의 평당 가격 평균이 가장 높은 아파트 5건을 보여줘
answer : {{
    &quot;keywords&quot; : [&quot;서울특별시 강남구 대치동&quot;,&quot;평당&quot;, &quot;가격&quot;, &quot;평균&quot;, &quot;가장 높은&quot;, &quot;아파트&quot;, &quot;5건&quot;],
    &quot;columns&quot; : [&quot;real_transaction.시군구&quot;,&quot;real_transaction.전용면적_m2&quot;,&quot;real_transaction.거래금액_만원&quot;,&quot;real_transaction.단지명&quot;],
    &quot;tables&quot; : [&quot;real_transaction&quot;],
    &quot;conditions&quot; : &quot;시군구 is 서울특별시 강남구 대치동&quot;,
    &quot;group&quot; : {{
        &quot;group_by&quot; : [&quot;단지명&quot;],
        &quot;aggregations&quot; : {{
            &quot;거래금액/(전용면적_m2/3.3)&quot; : &quot;AVG&quot;
        }}
    }},
    &quot;order_by&quot; : {{
        &quot;AVG(거래금액/(전용면적_m2/3.3))&quot; : &quot;DESC&quot;
    }},
    &quot;prepared_sql&quot; : &quot;SELECT 단지명, AVG(거래금액_만원/(전용면적_m2/3.3)) AS 평균_평당거래금액_만원 FROM real_transaction WHERE 시군구 = &#39;서울특별시 강남구 대치동&#39;  GROUP BY 단지명 ORDER BY  평균_평당거래금액_만원 DESC&quot;
}}
---
question : {user_question}
answer :</code></pre>
<p>위 프롬프트는 헨즈온 데모를 위한 간단한 형태의 NL2SQL 프롬프트입니다.
실제 기업 데이터와 결합하기 위해서는 몇가지 추가적인 기법들을 더 사용해야 합니다.</p>
<h4 id="llm-답변">LLM 답변</h4>
<p>헨즈온 데모에서는</p>
<blockquote>
<p>서울특별시 성동구 옥수동에서 가장 비싸게 거래되는 아파트 상위 3개를 알려줘</p>
</blockquote>
<p>라는 질의를 해보았습니다. (질의는 다른 것으로 변경이 가능합니다.)</p>
<p>그 결과 LLM의 답변은 다음과 같이 나오게 됩니다.</p>
<pre><code class="language-json">{
    &quot;keywords&quot; : [&quot;서울특별시 성동구 옥수동&quot;,&quot;가장 비싸게 거래되는&quot;, &quot;아파트&quot;, &quot;상위 3개&quot;],
    &quot;columns&quot; : [&quot;real_transaction.단지명&quot;,&quot;real_transaction.거래금액_만원&quot;],
    &quot;tables&quot; : [&quot;real_transaction&quot;],
    &quot;conditions&quot; : &#39;시군구 = &quot;서울특별시 성동구 옥수동&quot;&#39;,
    &quot;group&quot; : null,
    &quot;order_by&quot; : {
        &quot;거래금액_만원&quot; : &quot;DESC&quot;
    },
    &quot;prepared_sql&quot; : &#39;SELECT 단지명,거래금액_만원 FROM real_transaction WHERE 시군구 = &quot;서울특별시 성동구 옥수동&quot; ORDER BY 거래금액_만원 DESC LIMIT 3&#39;
}</code></pre>
<p>여기서 sql만 추출하면 <code>SELECT 단지명,거래금액_만원 FROM real_transaction WHERE 시군구 = &quot;서울특별시 성동구 옥수동&quot; ORDER BY 거래금액_만원 DESC LIMIT 3</code>가 되고 이를 sqlite3에 넣어서 데이터를 조회하면 다음과 같은 결과를 얻을 수 있습니다.
<img src="https://velog.velcdn.com/images/geoffyoon-dev/post/a799c3b3-8041-4928-bbad-8dd691a175bf/image.png" alt=""></p>
<h2 id="masked-data-prompting">masked data prompting</h2>
<p>이렇게 쿼리 결과를 얻고 나면 다 되었다고 생각할 수 있겠지만, 아직 한가지 문제가 남아있습니다. </p>
<p>일반적으로 쳇봇의 UX는 텍스트 형태로 응답을 받길 기대합니다. 그래서 일반적으로는 이렇게 조회된 데이터를 LLM으로 전송하여 정제된 택스트 형태로 응답을 받습니다.
<img src="https://velog.velcdn.com/images/geoffyoon-dev/post/6164c632-611d-4435-b45a-dbb4ed62b59a/image.jpg" alt="일반적인 NL2SQL 플로우"></p>
<p>하지만 이렇게 되는 경우, 내부 데이터가 외부로 나가면 안된다는 데이터 정책을 위반하게 됩니다.</p>
<p>그래서 저희는 별도로 데이터를 은닉한 후 전달하고 데이터가 은닉된 답변을 원 데이터로 바꾸는 과정이 추가로 필요합니다.
<img src="https://velog.velcdn.com/images/geoffyoon-dev/post/61a014c7-1ff9-4f42-a06e-5a193c32b50c/image.jpg" alt="마스킹된 NL2SQL 플로우"></p>
<h3 id="데이터-마스킹">데이터 마스킹</h3>
<p><img src="https://velog.velcdn.com/images/geoffyoon-dev/post/761676bb-0bf4-470d-80b5-af4e62218788/image.png" alt="데이터를 마스킹하는 방법"></p>
<p>쿼리 결과는 다음과 같이 <code>[[hidden_value_{{row}}_{{col}}]]</code>의 규칙에 따라 LLM이 실제 데이터를 알지 못하도록 은닉화를 합니다.</p>
<h3 id="프롬프트-1">프롬프트</h3>
<p>프롬프트의 컨텍스트와 지시 사항을 짧게 정리하면 다음과 같습니다.</p>
<ul>
<li><code>[[hidden_value_{{row}}_{{col}}]]</code>로 되어있는 것은 실제데이터를 은닉화한 것이다.</li>
<li><code>[[hidden_value_{{row}}_{{col}}]]</code>으로 처리된 데이터는 임의로 값을 대입하지 말고 그대로 <code>[[hidden_value_{{row}}_{{col}}]]</code>로 출력한다.</li>
<li>출력 언어는 한국어이고 포멧은 markdown 형태로 출력한다.</li>
</ul>
<h3 id="데이터-마스킹된-응답-복원">데이터 마스킹된 응답 복원</h3>
<p>해당 프롬프트로 마스킹된 쿼리 결과를 LLM으로 전송할 경우 다음과 같은 데이터가 마스킹된 응답을 얻을 수 있습니다.</p>
<blockquote>
<p>서울특별시 성동구 옥수동에서 가장 비싸게 거래되는 아파트 상위 3개는 다음과 같습니다.\n1. 1위는 [[hidden_value_1_단지명]]으로 거래금액은 [[hidden_value_1_거래금액_만원]]만원입니다.\n2. 2위는 [[hidden_value_2_단지명]]으로 거래금액은 [[hidden_value_2_거래금액_만원]]만원입니다.\n3. 3위는 [[hidden_value_3_단지명]]으로 거래금액은 [[hidden_value_3_거래금액_만원]]만원입니다.</p>
</blockquote>
<p>이러한 응답의 마스킹되어있는 영역에 실제 값을 대입하면 다음과 같은 실제 데이터가 반영된 LLM의 응답을 얻을 수 있습니다.</p>
<blockquote>
<p>서울특별시 성동구 옥수동에서 가장 비싸게 거래되는 아파트 상위 3개는 다음과 같습니다.\n1. 1위는 옥수하이츠으로 거래금액은 191000만원입니다.\n2. 2위는 옥수파크힐스101동<del>116동으로 거래금액은 180000만원입니다.\n3. 3위는 옥수파크힐스101동</del>116동으로 거래금액은 173000만원입니다.</p>
</blockquote>
<h3 id="masked-data-prompting-데모">masked data prompting 데모</h3>
<h4 id="데이터-마스킹-1">데이터 마스킹</h4>
<p>데이터를 <code>[[hidden_value_{{row}}_{{col}}]]</code>로 마스킹 하기 위해 다음과 같은 함수를 사용합니다.</p>
<pre><code class="language-python">def mask_query_result(query_result):
    # 이 함수는 쿼리 결과를 LLM에게 전달하지 않기 위해 값을 hidden_value_{{row}}_{{col}}으로 마스킹합니다.
    return [{ col : f&quot;[[hidden_value_{i+1}_{col}]]&quot;  for j, col in enumerate(row)} for i, row in enumerate(query_result)]</code></pre>
<p>이 함수를 호출하여 실제 데이터를 마스킹하면 다음과 같은 결과를 얻을 수 있습니다.</p>
<pre><code class="language-python"># 쿼리 결과를 gemini에게 전달하지 않기 위해 hidden_value로 마스킹처리를 합니다.
hidden_query_result = mask_query_result(query_result)</code></pre>
<pre><code class="language-json">[{&#39;단지명&#39;: &#39;[[hidden_value_1_단지명]]&#39;, &#39;거래금액_만원&#39;: &#39;[[hidden_value_1_거래금액_만원]]&#39;},
 {&#39;단지명&#39;: &#39;[[hidden_value_2_단지명]]&#39;, &#39;거래금액_만원&#39;: &#39;[[hidden_value_2_거래금액_만원]]&#39;},
 {&#39;단지명&#39;: &#39;[[hidden_value_3_단지명]]&#39;, &#39;거래금액_만원&#39;: &#39;[[hidden_value_3_거래금액_만원]]&#39;}]</code></pre>
<h4 id="프롬프트-2">프롬프트</h4>
<p>마스킹된 데이터를 받아 마스킹된 응답을 얻기 위해서는 해당 task를 수행하도록 프롬프트로 LLM에 전달해야 합니다. </p>
<p>프롬프트에 들어갈 사항은 다음과 같습니다.</p>
<ul>
<li>SQL : 이 데이터를 얻기 위한 sql 정보를 제공합니다.</li>
<li>masked_data : 실제 조회된 데이터를 마스킹한 결과를 제공합니다.</li>
<li>context : <code>[[hidden_value_{{row}}_{{col}}]]</code>의 의미와 그대로 은닉화된 응답을 해야 한다는 정보를 제공합니다.</li>
<li>output : 마크다운 포멧으로 한국어로 응답해야 한다고 지시합니다.</li>
<li>instruction : 마스크된 데이터를 바탕으로 LLM이 응답을 하도록 지시합니다.</li>
<li>example : 질의와 데이터 마스킹된 LLM 답변에 대한 예시를 제공합니다.</li>
</ul>
<p>아래는  masked data prompting, few-shot등의 기법이 적용된 프롬프트입니다.</p>
<pre><code class="language-prompt">[SQL]
{gemini_sql}

[DATA]
{hidden_query_result}

[CONTEXT]
You created the following [SQL] to query the data in sqlite3:
[DATA] above is a query result whose value is [[hidden_value_{{{{row}}}}_{{{{col}}}}]] to hide the actual data.
Therefore, when responding, the value set as [[hidden_value_{{{{row}}}}_{{{{col}}}}]] must be responded as [[hidden_value_{{{{row}}}}_{{{{col}}}}]].

[OUTPUT]
language : korean
format : markdown

[INSTRUCTION]
Please refer to [DATA] above and respond to the user&#39;s questions below.
---
question : 지역별 거래금액 평균 중 가장 높은 3곳을 알려줘
answer : 지역별 거래금액 평균이 가장 높은 곳 3곳은
1. 1위는  [[hidden_value_1_시군구]]으로 평균거래가는 [[hidden_value_0_평균_거래금액_만원]]만원입니다.
2. 2위는  [[hidden_value_1_시군구]]으로 평균거래가는 [[hidden_value_1_평균_거래금액_만원]]만원입니다.
2. 3위는  [[hidden_value_2_시군구]]으로 평균거래가는 [[hidden_value_2_평균_거래금액_만원]]만원입니다.
---
question : 평당 가격이 가장 높게 거래된 아파트는 어디야?
answer : 평당 가격이 가장 높게 거래된 아파트는 [[hidden_value_1_시군구]]에 있는 [[hidden_value_1_단지명]]로 전용면적은 [[hidden_value_1_전용면적_m2]]이고 거래가는 [[hidden_value_1_거래금액_만원]], 평당 거래금액은  [[hidden_value_1_평당거래금액_만원]]에 거래되었습니다.
---
question : {user_question}
answer :</code></pre>
<h4 id="llm-답변-1">LLM 답변</h4>
<p>헨즈온 데모에서는</p>
<blockquote>
<p>서울특별시 성동구 옥수동에서 가장 비싸게 거래되는 아파트 상위 3개를 알려줘</p>
</blockquote>
<p>라는 질의를 해보았습니다. (질의는 다른 것으로 변경이 가능합니다.)
그리고 같이 들어간 데이터는 다음과 같습니다.
<img src="https://velog.velcdn.com/images/geoffyoon-dev/post/c88d5a48-a583-4279-878d-fd0b93088d4d/image.png" alt=""></p>
<p>그 결과 LLM의 답변은 다음과 같이 나오게 됩니다.</p>
<blockquote>
<p>서울특별시 성동구 옥수동에서 가장 비싸게 거래되는 아파트 상위 3개는 다음과 같습니다.\n1. 1위는 [[hidden_value_1_단지명]]으로 거래금액은 [[hidden_value_1_거래금액_만원]]만원입니다.\n2. 2위는 [[hidden_value_2_단지명]]으로 거래금액은 [[hidden_value_2_거래금액_만원]]만원입니다.\n3. 3위는 [[hidden_value_3_단지명]]으로 거래금액은 [[hidden_value_3_거래금액_만원]]만원입니다.</p>
</blockquote>
<h4 id="데이터-마스킹된-응답-복원-1">데이터 마스킹된 응답 복원</h4>
<p><code>[[hidden_value_{{row}}_{{col}}]]</code>로 마스킹된 부분을 다시 실 데이터로 치환하기 위해 다음과 같은 포멧팅함수를 사용합니다. </p>
<pre><code class="language-python">def format_hidden_value(message:str, real_values:list[dict]) -&gt; str:
    # 마스킹 되어있는 LLM의 값을 실제 값으로 포멧팅하는 함수입니다.
    for i, real_value in enumerate(real_values):
        for key, value in real_value.items():
            message = message.replace(f&quot;[[hidden_value_{i+1}_{key}]]&quot;, f&quot;{value}&quot;)
    return message</code></pre>
<p>이 함수를 호출하여 마스킹되어 있는 부분을 실제 데이터로 포멧팅하면 다음과 같은 결과를 얻을 수 있습니다.</p>
<pre><code class="language-python"># 마스킹 처리 되어있는 LLM의 응답을 실제 데이터로 치환
real_response = format_hidden_value(response.text, query_result)</code></pre>
<pre><code class="language-markdown">서울특별시 성동구 옥수동에서 가장 비싸게 거래되는 아파트 상위 3개는 다음과 같습니다.\n1. 1위는 옥수하이츠으로 거래금액은 191000만원입니다.\n2. 2위는 옥수파크힐스101동~116동으로 거래금액은 180000만원입니다.\n3. 3위는 옥수파크힐스101동~116동으로 거래금액은 173000만원입니다.</code></pre>
<h1 id="나가며">나가며</h1>
<p>기업 내부의 민감한 데이터를 외부로 나가지 않게 정책적으로 막는 것은 매우 중요한 일압니다. </p>
<p>하지만 이 정책으로 인하여 Google Gemini와 같은 클라우드 LLM을 제대로 사용하지 못하고 내부 데이터와 결합하지 못한다면 클라우드 LLM을 사용하는 의미가 없을 것입니다.</p>
<p>저희 클라우드메이트는 고객사의 내부데이터를 지키면서도 클라우드 LLM의 성능을 최대한 이끌어내는 여러가지 기법들을 만들고 사용하고 있습니다.</p>
<p>클라우드메이트는 데이터 보안과 클라우드 LLM와의 결합 이 두마리 토끼를 모두 잡고 있습니다.</p>
<p>또한 클라우드 LLM 도입을 위한 컨설팅, 아키텍처 설계 등의 기술지원에 있어서 지속적으로 역량을 강화하고 있습니다.</p>
<p>비즈니스에 클라우드 LLM을 도입하는데 문의가 있으시면 언제든 연락주시기 바랍니다.
문의 : <a href="https://www.cloudmt.co.kr/contact">https://www.cloudmt.co.kr/contact</a></p>
<p>저희 클라우드메이트는 고객님의 LLM을 통한 생산성 혁신에 함께하겠습니다.</p>
]]></description>
        </item>
    </channel>
</rss>