-
chain에 대한 나만의 구현AI 2024. 7. 12. 22:07
# 본문
랭체인을 공부하다가 LCEL이라는 내용을 보게 되었는데, LCEL 안에 chain과 관련된 코드를 보고 타입 유추가 잘 안돼서 나만의 방식을 고민해 보았다.
from typing import TypeVar, Generic Input = TypeVar('Input') Output = TypeVar('Output') Mid = TypeVar('Mid') NextOutput = TypeVar('NextOutput') class RawConverter (Generic[Input, Output]): def convert (self, input: Input) -> Output: return input class Converter (RawConverter[Input, Output]): def __or__ (self, next_converter: RawConverter[Output, NextOutput]): return CombinedConverter[Input, NextOutput, Output](self, next_converter) class CombinedConverter (Converter[Input, Output], Generic[Input, Mid, Output]): def __init__ (self, input_side_converter: Converter[Input, Mid], output_side_converter: Converter[Mid, Output]): self.input_side_converter = input_side_converter self.output_side_converter = output_side_converter def convert (self, input: Input) -> Output: return self.output_side_converter.convert(self.input_side_converter.convert(input))
from converter import Converter class Converter1 (Converter[int, str]): def convert (self, input: int): return str(input * 2) class Converter2 (Converter[str, str]): def convert (self, input: str): return input * 2 converter = Converter1() | Converter2() converter.convert(3) # -> '66'
내 생각인데, Generic으로는 다형성은 지양해야 되지 않을까 싶다.
Generic으로 다형성을 만든다는 것은 다음과 같은 상황을 의미한다.
(LECL의 __or__ 연산자 오버로딩이 이런 식으로 구현되어 있다.)
from typing import Generic, TypeVar, Any Input = TypeVar('Input') Output = TypeVar('Output') class Converter (Generic[Input, Output]): def convert (self, input: Input) -> Output: pass class Converter1 (Converter[int, str]): def convert (self, input: int): return str(input * 2) class Converter2 (Converter[str, str]): def convert (self, input: str): return input * 2 converter: Converter[Any, Any] converter = Converter1() converter = Converter2()
즉 Generic으로 생성될 모든 Converter class들에 대한 다형성을 갖는 어떤 타입을 만드는 것을 말한다.
문제는 이렇게 하면 지금 내가 관심이 있는 이 converter의 Input과 Output 타입이 무엇인지 알기가 힘든 상황이 찾아올 수 있다는 것이다. 즉 가독성을 떨어 뜨린다.
# 사담
사실 나는 Any타입이나 type operation도 별로 안 좋아한다.
왠만하면 Any타입은 귀찮을 때만 사용하고 (귀찮은 건 어쩔 수 없지...)
type operation은 다형성을 만들지 않을 때만 사용하는 게 좋지 않을까?
(대표적인 예는 간단한 자료구조들에만 사용하는 것.)
(type operation을 class에 사용하는 것은 손해가 더 많다고 생각한다.)
다만, 코딩 스타일에는 정답이 없다는 것을 알아줬으면 좋겠다.
"# 사담"은 그냥 나의 코딩스타일을 완성하기 위해 나에게 내리는 매뉴얼 정도이지 타인에게 강요되어서는 안된다.
# 생각 변화
Any type이 cpp의 (void *)같은 곳에서 온 자연스러운 것 이라고 생각이 들었다.
사실상 Any type을 쓰지 않으면 구현할 수 없는 몇 가지 어플리케이션들이 떠올랐다.
Generic에 의한 다형성도 허용해야 한다고 생각이 들었다.
내가 너무 모든 에러를 compile time에서 type 추론으로 미리 예방하고자 했던 거 같다.
하지만 어떤 에러들은 런타임에 발생할 수 밖에 없음을 깨달았다.
런타임에서 에러를 처리하는 로직을 개발하는 것이 최선인 경우도 있다.
'AI' 카테고리의 다른 글
email 사무 자동화 test (0) 2024.07.16 langchain agent로 사용할 때 llm 모델들 테스트 (0) 2024.07.15 앞으로 한 동안 추론용 AI 반도체(NPU)가 중요한 이유 (openai의 시각으로 본) (0) 2024.07.05 ubuntu에서 그래픽카드 사용 상황 보는 법 (0) 2024.06.29 transformers로 model loading 할 때 gpu vram이 model size 보다 큰데 cuda memory out이 발생할 경우 (0) 2024.06.29