728x90
반응형

의미 계층을 통해 Graph Database Neo4j와 상호작용하는 Mixtral 에이전트를 구현하는 방법을 알아볼까요?

예를 들어 ChatGPT도 유료 버전에서는 Bing Search 및 Python 인터프리터를 바로 사용할 수 있죠. OpenAI는 한발 앞서 도구 사용을 위한 Fine-tuning된 LLM 모델을 제공하고 있어요. 여기서 사용 가능한 도구를 프롬프트와 함께 API 엔드포인트에 전달할 수 있죠. 그러면 LLM은 직접 응답을 제공할 수 있는지, 아니면 사용 가능한 도구 중 하나를 먼저 사용해야 하는지 결정하게 돼요.

도구는 추가 정보 검색에만 사용될 필요는 없어요. LLM이 저녁 식사 예약을 할 수 있도록 허용하는 등 무엇이든 가능하죠. 이전에 프로젝트를 구현한 적이 있는데, LLM이 사전 정의된 도구 세트를 통해 Graph Database와 상호 작용할 수 있도록 허용하는 것이었고, 저는 이를 의미 계층이라고 불렀어요.

본질적으로 이러한 도구는 정보에 대한 동적 실시간 액세스, 메모리를 통한 개인화, Knowledge Graph를 통한 관계에 대한 정교한 이해를 제공함으로써 GPT-4와 같은 LLM을 강화해요. 이를 통해 LLM은 보다 정확한 권장 사항을 제공하고, 시간이 지남에 따라 사용자 선호도를 이해하고, 보다 광범위한 최신 정보에 액세스하여 더욱 상호 작용적이고 적응력이 뛰어난 사용자 경험을 제공할 수 있어요. 언급한 바와 같이, 쿼리 시 추가 정보를 검색하는 기능 외에도 달력에서 회의를 예약하는 등 LLM에게 환경에 영향을 미칠 수 있는 옵션도 제공하는 거죠.

OpenAI가 도구 사용을 위한 Fine-tuning 모델로 우리를 망쳤지만, 실제로는 대부분의 다른 LLM이 함수 호출 및 도구 사용과 관련하여 OpenAI 수준에 미치지 못한다는 점이에요. 저는 Ollama에서 사용 가능한 대부분의 모델을 시도했지만 대부분 에이전트를 구동하는 데 사용할 수 있는 미리 정의된 구조화된 출력을 일관되게 생성하는 데 어려움을 겪었어요. 반면에 함수 호출에 맞게 Fine-tuning된 일부 모델이 있긴 해요. 그러나 이러한 모델에는 함수 호출을 위한 사용자 정의 Prompt Engineering 스키마가 있는데, 이는 잘 문서화되어 있지 않거나 함수 호출 이외의 용도로 사용할 수 없어요.

궁극적으로 저는 Mixtral 8x7b LLM을 사용하여 JSON 기반 에이전트의 기존 LangChain 구현을 따르기로 결정했어요. 저는 Mixtral 8x7b를 영화 에이전트로 사용하여 시맨틱 레이어를 통해 기본 Graph Database인 Neo4j와 상호 작용했어요. 코드는 Langchain 템플릿으로 제공되고, 주피터 노트북도 제공돼요. 도구가 어떻게 구현되는지에 관심이 있다면 이전 블로그 게시물을 참조하세요. 여기에서는 JSON 기반 LLM 에이전트를 구현하는 방법을 설명하고 있어요.

의미 계층의 도구

LangChain 문서의 예(JSON 에이전트, 포옹얼굴 예시)에서는 단일 문자열 입력이 있는 도구를 사용하고 있어요. 의미 계층의 도구는 약간 더 복잡한 입력을 사용하므로 좀 더 자세히 살펴봐야 해요. 다음은 추천 도구에 대한 입력 예시입니다.

all_genres = [
    "Action",
    "Adventure",
    "Animation",
    "Children",
    "Comedy",
    "Crime",
    "Documentary",
    "Drama",
    "Fantasy",
    "Film-Noir",
    "Horror",
    "IMAX",
    "Musical",
    "Mystery",
    "Romance",
    "Sci-Fi",
    "Thriller",
    "War",
    "Western",
]


class RecommenderInput(BaseModel):
    movie: Optional[str] = Field(description="movie used for recommendation")
    genre: Optional[str] = Field(
        description=(
            "genre used for recommendation. Available options are:" f"{all_genres}"
        )
    )

추천 도구에는 영화와 장르라는 두 가지 선택적 입력이 있어요. 또한 장르 매개변수에 사용 가능한 값의 열거형을 사용하고 있죠. 입력이 크게 복잡하지는 않지만 여전히 단일 문자열 입력보다 더 고급이므로 구현이 약간 달라야 해요.

LLM 에이전트에 대한 JSON 기반 프롬프트

제 구현은 LangChain Hub에서 제공하는 hwchase17/react-json 프롬프트에서 많은 영감을 받았어요. 프롬프트는 다음과 같은 시스템 메시지를 사용하죠.

Answer the following questions as best you can. You have access to the following tools:

{tools}

The way you use the tools is by specifying a json blob.
Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here).

The only values that should be in the "action" field are: {tool_names}

The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB:

```
{{
  "action": $TOOL_NAME,
  "action_input": $INPUT
}}
```

ALWAYS use the following format:

Question: the input question you must answer
Thought: you should always think about what to do
Action:
```
$JSON_BLOB
```
Observation: the result of the action
... (this Thought/Action/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

Begin! Reminder to always use the exact characters `Final Answer` when responding.

프롬프트는 사용 가능한 도구를 정의하는 것으로 시작하는데, 이 부분은 잠시 후에 더 자세히 살펴볼게요. 프롬프트에서 가장 중요한 부분은 LLM에게 어떤 형식으로 출력을 해야 하는지 알려주는 부분이에요. LLM이 함수를 호출해야 한다면, 다음과 같은 JSON 구조를 사용해야 하죠.

{{
  "action": $TOOL_NAME,
  "action_input": $INPUT
}}

이것이 바로 JSON 기반 에이전트라고 불리는 이유랍니다. 우리는 LLM이 사용 가능한 도구를 사용하려고 할 때 JSON을 생성하도록 지시하는 거예요. 하지만 이건 출력 정의의 일부분일 뿐이고, 전체 출력 구조는 다음과 같아야 해요.

Thought: you should always think about what to do
Action:
```
$JSON_BLOB
```
Observation: the result of the action
... (this Thought/Action/Observation can repeat N times)
Final Answer: the final answer to the original input question

LLM은 항상 출력의 "Thought" 부분에서 자신이 무엇을 하고 있는지 설명해야 해요. 사용 가능한 도구를 사용하려면 "action_input"을 JSON Blob 형태로 제공해야 하고요. "Observation" 부분은 도구의 출력을 담는 곳이고, 에이전트가 사용자에게 답변을 반환할 수 있다고 판단되면 "Final Answer" 키를 사용해야 하죠. 다음은 이 구조를 사용하는 영화 에이전트의 예시예요.

이 예시에서는 에이전트에게 좋은 코미디 영화를 추천해 달라고 요청했어요. 에이전트가 사용할 수 있는 도구 중 하나가 추천 도구이기 때문에, 입력을 정의하기 위해 JSON 구문을 사용해서 추천 도구를 활용하기로 결정한 거죠. 다행히 LangChain에는 JSON 에이전트를 위한 내장 출력 파서가 있어서 구현에 대해 크게 걱정할 필요가 없어요. 다음으로, LLM은 도구로부터 응답을 받아서 프롬프트에서 "Observation"으로 사용해요. 도구가 필요한 모든 정보를 제공했기 때문에, LLM은 사용자에게 반환될 수 있는 최종 답변을 구성하기에 충분한 정보가 있다고 판단한 거죠.

저는 엔지니어 Mixtral이 도구를 사용해야 할 때만 JSON 구문을 사용하도록 유도하는 것이 꽤 어렵다는 것을 알게 되었어요. 제가 실험했을 때, 어떤 도구도 사용하고 싶지 않을 때 다음과 같은 JSON 액션 입력을 사용하는 경우가 있었죠.

{{
  "action": Null,
  "action_input": ""
}}

LangChain의 출력 파싱 기능은 null이나 이와 비슷한 액션을 무시하지 않고, null 도구가 정의되지 않았다는 오류를 반환해요. 저는 엔지니어에게 이 문제에 대한 해결책을 제시하려고 노력했지만, 일관된 방식으로 해결할 수는 없었어요. 그래서 사용자가 스몰토크를 원할 때 에이전트가 호출할 수 있는 더미 스몰토크 도구를 추가하기로 결정했답니다.

response = (
    "Create a final answer that says if they "
    "have any questions about movies or actors"
)


class SmalltalkInput(BaseModel):
    query: Optional[str] = Field(description="user query")


class SmalltalkTool(BaseTool):
    name = "Smalltalk"
    description = "useful for when user greets you or wants to smalltalk"
    args_schema: Type[BaseModel] = SmalltalkInput

    def _run(
        self,
        query: Optional[str] = None,
        run_manager: Optional[CallbackManagerForToolRun] = None,
    ) -> str:
        """Use the tool."""
        return response

이렇게 하면 에이전트는 사용자가 인사할 때 더미 Smalltalk 도구를 사용하기로 결정할 수 있고, 더 이상 null 또는 누락된 도구 이름을 파싱하는 데 어려움을 겪지 않아도 돼요.

이 해결 방법이 꽤 효과적이어서 그대로 유지하기로 했어요. 앞서 언급했듯이 대부분의 모델은 작업이 필요하지 않은 경우 작업 입력이나 텍스트를 생성하도록 훈련되지 않았기 때문에 현재 사용 가능한 작업을 수행해야 하죠. 하지만 가끔은 모델이 첫 번째 시도에서 어떤 도구도 성공적으로 호출하지 못하는 경우가 있어요. 스몰토크 도구처럼 탈출구를 만들어주면 예외를 방지할 수 있는 것 같아요.

시스템 프롬프트에서 도구 입력 정의

앞서 언급했듯이 LLM이 올바르게 해석할 수 있도록 조금 더 복잡한 도구 입력을 정의하는 방법을 찾아야 했어요. 재밌게도 사용자 정의 함수를 구현한 후에, 사용자 정의 Pydantic 도구 입력 정의를 Mixtral이 인식하는 JSON 객체로 변환하는 기존 LangChain 함수를 발견했어요.

from langchain.tools.render import render_text_description_and_args

tools = [RecommenderTool(), InformationTool(), Smalltalk()]

tool_input = render_text_description_and_args(tools)
print(tool_input)

다음 문자열 설명을 생성합니다.

"Recommender":"useful for when you need to recommend a movie",
"args":{
   {
      "movie":{
         {
            "title":"Movie",
            "description":"movie used for recommendation",
            "type":"string"
         }
      },
      "genre":{
         {
            "title":"Genre",
            "description":"genre used for recommendation. Available options are:['Action', 'Adventure', 'Animation', 'Children', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy', 'Film-Noir', 'Horror', 'IMAX', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War', 'Western']",
            "type":"string"
         }
      }
   }
},
"Information":"useful for when you need to answer questions about various actors or movies",
"args":{
   {
      "entity":{
         {
            "title":"Entity",
            "description":"movie or a person mentioned in the question",
            "type":"string"
         }
      },
      "entity_type":{
         {
            "title":"Entity Type",
            "description":"type of the entity. Available options are 'movie' or 'person'",
            "type":"string"
         }
      }
   }
},
"Smalltalk":"useful for when user greets you or wants to smalltalk",
"args":{
   {
      "query":{
         {
            "title":"Query",
            "description":"user query",
            "type":"string"
         }
      }
   }
}

시스템 프롬프트에서 이 도구 설명을 복사하기만 하면 Mixtral이 정의된 도구를 사용할 수 있어요. 정말 멋지죠?

결론

JSON 기반 에이전트를 구현하기 위한 대부분의 작업은 Harrison Chase와 LangChain 팀에서 진행했는데, 정말 감사드려요. 저는 그저 퍼즐 조각을 찾아서 맞추는 역할만 했을 뿐이에요. 앞서 언급했듯이 GPT-4와 동일한 수준의 에이전트 성능을 기대하긴 어렵지만, Mixtral처럼 더 강력한 OSS LLM을 오늘날 에이전트로 사용할 수 있다고 생각해요 (GPT-4보다 예외 처리가 조금 더 필요하긴 하지만요). 앞으로 더 많은 오픈소스 LLM이 에이전트로서 Fine-tuning되기를 기대하고 있어요.

The 코드는 Langchain 템플릿으로 제공돼요. 그리고 주피터 노트북도 준비되어 있답니다.


  • Agent
  • ChatGPT
  • JSON
  • LangChain
  • Mixtral
  • Ollama

에이치시스템즈LogTree는 Neo4j 기반 GraphRAG 플랫폼으로, 데이터를 자동으로 지식그래프화하고 자연어 질의로 즉시 답을 제공합니다.

👉 에이치시스템즈 홈페이지

728x90
반응형

+ Recent posts