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
Week

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.