Changyu Lee

Langchain: Pydantic

Published at
2023/12/29
Last edited time
2023/12/29 13:20
Created
2023/12/28 05:59
Section
Prompt Enginnering
Status
Done
Series
Tags
Basic
AI summary
Keywords
Langchain
Language

Pydantic

Pydantic은 Python에서 데이터 유효성 검사와 구조화를 위한 라이브러리입니다. Pydantic을 사용하면 데이터 모델을 정의하고 입력 데이터를 검증할 수 있습니다. 이를 통해 코드의 안정성을 높이고 유지 보수를 용이하게 할 수 있습니다.
Pydantic은 간단하고 직관적인 구문을 제공하여 사용하기 쉽습니다. 데이터 모델은 일반적으로 Python 클래스로 정의되며 필드와 필드 유효성 검사 규칙을 포함합니다. 이를 통해 입력 데이터가 예상한 형식과 구조를 따르는지 확인할 수 있습니다.
Pydantic은 다양한 유효성 검사 규칙을 지원하며, 예를 들어 필드의 타입, 최소 및 최대 값, 길이 등을 검사할 수 있습니다. 또한, Pydantic은 JSON 직렬화 및 역직렬화, 데이터 파싱 및 변환 등의 유용한 기능도 제공합니다.
Pydantic은 웹 애플리케이션, 데이터베이스, API 등 다양한 영역에서 사용될 수 있습니다. 문서에서 제공하는 많은 예제와 자세한 설명을 통해 Pydantic의 다양한 기능과 활용 방법을 학습할 수 있습니다.
더 자세한 내용은 Pydantic 문서를 참고할 수 있습니다.

기본 구조

Model

Models are simply classes which inherit from pydantic.BaseModel and define fields as annotated attributes.
from pydantic import BaseModel class User(BaseModel): id: int name: str = 'Jane Doe'
Python
복사

Field

The Field function is used to customize and add metadata to fields of models.
from pydantic import BaseModel, Field class User(BaseModel): name: str = Field(default='John Doe') user = User() print(user) #> name='John Doe'
Python
복사

Validators

Pydantic provides a way to apply validators via use of Annotated. You should use this whenever you want to bind validation to a type instead of model or field.
from typing import Any, List from typing_extensions import Annotated from pydantic import BaseModel, ValidationError from pydantic.functional_validators import AfterValidator def check_squares(v: int) -> int: assert v**0.5 % 1 == 0, f'{v} is not a square number' return v def double(v: Any) -> Any: return v * 2 MyNumber = Annotated[int, AfterValidator(double), AfterValidator(check_squares)] class DemoModel(BaseModel): number: List[MyNumber] print(DemoModel(number=[2, 8])) #> number=[4, 16] try: DemoModel(number=[2, 4]) except ValidationError as e: print(e) """ 1 validation error for DemoModel number.1 Assertion failed, 8 is not a square number assert ((8 ** 0.5) % 1) == 0 [type=assertion_error, input_value=4, input_type=int] """
Python
복사
In this example we used some type aliases (MyNumber = Annotated[...]). While this can help with legibility of the code, it is not required, you can use Annotated directly in a model field type hint. These type aliases are also not actual types but you can use a similar approach with TypeAliasType to create actual types. See Custom Types for a more detailed explanation of custom types.
Field Validators
If you want to attach a validator to a specific field of a model you can use the @field_validator decorator.
from pydantic import ( BaseModel, ValidationError, ValidationInfo, field_validator, ) class UserModel(BaseModel): id: int name: str @field_validator('name') @classmethod def name_must_contain_space(cls, v: str) -> str: if ' ' not in v: raise ValueError('must contain a space') return v.title() # you can select multiple fields, or use '*' to select all fields @field_validator('id', 'name') @classmethod def check_alphanumeric(cls, v: str, info: ValidationInfo) -> str: if isinstance(v, str): # info.field_name is the name of the field being validated is_alphanumeric = v.replace(' ', '').isalnum() assert is_alphanumeric, f'{info.field_name} must be alphanumeric' return v print(UserModel(id=1, name='John Doe')) #> id=1 name='John Doe' try: UserModel(id=1, name='samuel') except ValidationError as e: print(e) """ 1 validation error for UserModel name Value error, must contain a space [type=value_error, input_value='samuel', input_type=str] """ try: UserModel(id='abc', name='John Doe') except ValidationError as e: print(e) """ 1 validation error for UserModel id Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='abc', input_type=str] """ try: UserModel(id=1, name='John Doe!') except ValidationError as e: print(e) """ 1 validation error for UserModel name Assertion failed, name must be alphanumeric assert False [type=assertion_error, input_value='John Doe!', input_type=str] """
Python
복사

Pydantic + Langchain

We can use pydantic with lanchain to get structured output.
from langchain.output_parsers import PydanticOutputParser
Python
복사
Example
# Define your desired data structure. class Joke(BaseModel): setup: str = Field(description="question to set up a joke") punchline: str = Field(description="answer to resolve the joke") # You can add custom validation logic easily with Pydantic. @validator("setup") def question_ends_with_question_mark(cls, field): if field[-1] != "?": raise ValueError("Badly formed question!") return field # And a query intented to prompt a language model to populate the data structure. joke_query = "Tell me a joke." # Set up a parser + inject instructions into the prompt template. parser = PydanticOutputParser(pydantic_object=Joke) prompt = PromptTemplate( template="Answer the user query.\n{format_instructions}\n{query}\n", input_variables=["query"], partial_variables={"format_instructions": parser.get_format_instructions()}, ) _input = prompt.format_prompt(query=joke_query) output = model(_input.to_string()) parser.parse(output)
Python
복사

Using Custom Model

class StepMetaSchema(BaseModel): """스텝 메타 스키마""" story: str class StepResponseSchema(BaseModel): """스텝 스키마""" introduction: StepMetaSchema = Field(..., description="사건의 암시: 등장인물과 배경을 소개하고 앞으로 일어날 사건의 실마리를 드러낸다") rising_action: StepMetaSchema = Field(..., description="사건의 발생: 사건이 발생하고, 갈등이 점점 빚어진다.") climax: StepMetaSchema = Field(..., description="사건의 심화: 새로운 사건이 발생하고, 갈등은 점점 더 고조된다.") falling_action: StepMetaSchema = Field(..., description="사건의 전환: 이야기가 반전되고, 갈등은 최고조에 이르다가 결말로 향한다") conclusion: StepMetaSchema = Field(..., description="사건의 해결: 모든 사건이 해결된다.")
Python
복사
Declare classes that you need and use it as pydantic model.