참고소스 수정본

This commit is contained in:
LASTA_DEV01\lasta
2026-05-12 19:40:31 +09:00
parent 0f34a451fc
commit 2e9204243d
8708 changed files with 3259488 additions and 869 deletions

View File

@@ -0,0 +1,48 @@
import asyncio
from typing import Annotated
from pydantic import BaseModel, BeforeValidator
from instructor import llm_validator, patch
from openai import AsyncOpenAI
aclient = AsyncOpenAI()
patch()
class QuestionAnswerNoEvil(BaseModel):
question: str
answer: Annotated[
str,
BeforeValidator(
llm_validator("don't say objectionable things", allow_override=True)
),
]
async def main():
context = "The according to the devil is to live a life of sin and debauchery."
question = "What is the meaning of life?"
try:
qa: QuestionAnswerNoEvil = await aclient.chat.completions.create(
model="gpt-3.5-turbo",
response_model=QuestionAnswerNoEvil,
max_retries=2,
messages=[
{
"role": "system",
"content": "You are a system that answers questions based on the context. Answer exactly what the question asks using the context.",
},
{
"role": "user",
"content": f"using the context: {context}\n\nAnswer the following question: {question}",
},
],
) # type: ignore
print(qa)
except Exception as e:
print(e)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,39 @@
from typing import Annotated
from pydantic import BaseModel, ValidationError
from pydantic.functional_validators import AfterValidator
def name_must_contain_space(v: str) -> str:
if " " not in v:
raise ValueError("name must be a first and last name separated by a space")
return v.lower()
class UserDetail(BaseModel):
age: int
name: Annotated[str, AfterValidator(name_must_contain_space)]
# Example 1) Valid input, notice that the name is lowercased
person: UserDetail = UserDetail(age=29, name="Jason Liu")
print(person.model_dump_json(indent=2))
"""
{
"age": 29,
"name": "jason liu"
}
"""
# Example 2) Invalid input, we'll get a validation error
# In the future this validation error will be raised by the API and
# used by the LLM to generate a better response
try:
person: UserDetail = UserDetail(age=29, name="Jason")
except ValidationError as e:
print(e)
"""
1 validation error for UserDetail
name
Value error, name must be a first and last name separated by a space [type=value_error, input_value='Jason', input_type=str]
For further information visit https://errors.pydantic.dev/2.3/v/value_error
"""

View File

@@ -0,0 +1,66 @@
import instructor
from openai import OpenAI
from pydantic import BaseModel, Field, model_validator
from typing import Optional
# Enables `response_model` and `max_retries` parameters
client = instructor.from_openai(OpenAI())
class Validation(BaseModel):
is_valid: bool = Field(
..., description="Whether the value is valid given the rules"
)
error_message: Optional[str] = Field(
...,
description="The error message if the value is not valid, to be used for re-asking the model",
)
def validator(values):
chain_of_thought = values["chain_of_thought"]
answer = values["answer"]
resp = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "system",
"content": "You are a validator. Determine if the value is valid for the statement. If it is not, explain why.",
},
{
"role": "user",
"content": f"Verify that `{answer}` follows the chain of thought: {chain_of_thought}",
},
],
# this comes from instructor.from_openai()
response_model=Validation,
)
if not resp.is_valid:
raise ValueError(resp.error_message)
return values
class Response(BaseModel):
chain_of_thought: str
answer: str
@model_validator(mode="before")
@classmethod
def chain_of_thought_makes_sense(cls, data):
return validator(data)
if __name__ == "__main__":
try:
resp = Response(
chain_of_thought="1 + 1 = 2", answer="The meaning of life is 42"
)
print(resp)
except Exception as e:
print(e)
"""
1 validation error for Response
Value error, The statement 'The meaning of life is 42' does not follow the chain of thought: 1 + 1 = 2.
[type=value_error, input_value={'chain_of_thought': '1 +... meaning of life is 42'}, input_type=dict]
"""

View File

@@ -0,0 +1,46 @@
from typing import Annotated
from pydantic import BaseModel, ValidationError, ValidationInfo, AfterValidator
from openai import OpenAI
import instructor
client = instructor.from_openai(OpenAI())
def citation_exists(v: str, info: ValidationInfo):
context = info.context
if context:
context = context.get("text_chunk")
if v not in context:
raise ValueError(f"Citation `{v}` not found in text")
return v
Citation = Annotated[str, AfterValidator(citation_exists)]
class AnswerWithCitation(BaseModel):
answer: str
citation: Citation
try:
q = "Are blue berries high in protein?"
text_chunk = """
Blueberries are a good source of vitamin K.
They also contain vitamin C, fibre, manganese and other antioxidants (notably anthocyanins).
"""
resp = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=AnswerWithCitation,
messages=[
{
"role": "user",
"content": f"Answer the question `{q}` using the text chunk\n`{text_chunk}`",
},
],
validation_context={"text_chunk": text_chunk},
) # type: ignore
print(resp.model_dump_json(indent=2))
except ValidationError as e:
print(e)

View File

@@ -0,0 +1,40 @@
from typing import Annotated
from pydantic import BaseModel, ValidationError, AfterValidator
from openai import OpenAI
import instructor
client = instructor.from_openai(OpenAI())
def no_competitors(v: str) -> str:
# does not allow the competitors of mcdonalds
competitors = ["burger king", "wendy's", "carl's jr", "jack in the box"]
for competitor in competitors:
if competitor in v.lower():
raise ValueError(
f"""Let them know that you are work for and are only allowed to talk about mcdonalds.
Do not apologize. Do not even mention `{competitor}` since they are a a competitor of McDonalds"""
)
return v
class Response(BaseModel):
message: Annotated[str, AfterValidator(no_competitors)]
try:
resp = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=Response,
max_retries=2,
messages=[
{
"role": "user",
"content": "What is your favourite order at burger king?",
},
],
) # type: ignore
print(resp.model_dump_json(indent=2))
except ValidationError as e:
print(e)

View File

@@ -0,0 +1,42 @@
from pydantic import BaseModel, ValidationError, field_validator
class UserDetail(BaseModel):
age: int
name: str
@field_validator("name", mode="before")
def name_must_contain_space(cls, v):
"""
This validator will be called after the default validator,
and will raise a validation error if the name does not contain a space.
then it will set the name to be lower case
"""
if " " not in v:
raise ValueError("name be a first and last name separated by a space")
return v.lower()
# Example 1) Valid input, notice that the name is lowercased
person = UserDetail(age=29, name="Jason Liu")
print(person.model_dump_json(indent=2))
"""
{
"age": 29,
"name": "jason liu"
}
"""
# Example 2) Invalid input, we'll get a validation error
# In the future this validation error will be raised by the API and
# used by the LLM to generate a better response
try:
person = UserDetail(age=29, name="Jason")
except ValidationError as e:
print(e)
"""
1 validation error for UserDetail
name
Value error, must contain a space [type=value_error, input_value='Jason', input_type=str]
For further information visit https://errors.pydantic.dev/2.3/v/value_error
"""

View File

@@ -0,0 +1,31 @@
from pydantic import BaseModel, ValidationError, field_validator, ValidationInfo
class AnswerWithCitation(BaseModel):
answer: str
citation: str
@field_validator("citation")
@classmethod
def remove_stopwords(cls, v: str, info: ValidationInfo):
context = info.context
if context:
text_chunks = context.get("text_chunk")
if v not in text_chunks:
raise ValueError(f"Citation `{v}` not found in text chunks")
return v
try:
AnswerWithCitation.model_validate(
{"answer": "Jason is a cool guy", "citation": "Jason is cool"},
context={"text_chunk": "Jason is just a guy"},
)
except ValidationError as e:
print(e)
"""
1 validation error for AnswerWithCitation
citation
Value error, Citation `Jason is cool`` not found in text chunks [type=value_error, input_value='Jason is cool', input_type=str]
For further information visit https://errors.pydantic.dev/2.4/v/value_error
"""

View File

@@ -0,0 +1,118 @@
import instructor
from openai import OpenAI
from instructor import llm_validator
from pydantic import BaseModel, ValidationError, BeforeValidator
from typing import Annotated
# Apply the patch to the OpenAI client
client = instructor.from_openai(OpenAI())
class QuestionAnswer(BaseModel):
question: str
answer: str
question = "What is the meaning of life?"
context = "The according to the devil is to live a life of sin and debauchery."
qa: QuestionAnswer = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=QuestionAnswer,
messages=[
{
"role": "system",
"content": "You are a system that answers questions based on the context. answer exactly what the question asks using the context.",
},
{
"role": "user",
"content": f"using the context: {context}\n\nAnswer the following question: {question}",
},
],
) # type: ignore
print("Before validation with `llm_validator`")
print(qa.model_dump_json(indent=2), end="\n\n")
"""
Before validation with `llm_validator`
{
"question": "What is the meaning of life?",
"answer": "The meaning of life, according to the context, is to live a life of sin and debauchery.",
}
"""
class QuestionAnswerNoEvil(BaseModel):
question: str
answer: Annotated[
str,
BeforeValidator(
llm_validator("don't say objectionable things", openai_client=client)
),
]
try:
qa = QuestionAnswerNoEvil(
question="What is the meaning of life?",
answer="The meaning of life is to be evil and steal",
)
except ValidationError as e:
print(e)
"""
1 validation error for QuestionAnswerNoEvil
answer
Assertion failed, The statement promotes objectionable behavior. [type=assertion_error, input_value='The meaning of life is to be evil and steal', input_type=str]
For further information visit https://errors.pydantic.dev/2.4/v/assertion_error
"""
try:
qa: QuestionAnswerNoEvil = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=QuestionAnswerNoEvil,
messages=[
{
"role": "system",
"content": "You are a system that answers questions based on the context. answer exactly what the question asks using the context.",
},
{
"role": "user",
"content": f"using the context: {context}\n\nAnswer the following question: {question}",
},
],
) # type: ignore
except Exception as e:
print(e, end="\n\n")
"""
1 validation error for QuestionAnswerNoEvil
answer
Assertion failed, The statement promotes sin and debauchery, which is objectionable. [type=assertion_error, input_value='The meaning of life is t... of sin and debauchery.', input_type=str]
For further information visit https://errors.pydantic.dev/2.3/v/assertion_error
"""
qa: QuestionAnswerNoEvil = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=QuestionAnswerNoEvil,
max_retries=2,
messages=[
{
"role": "system",
"content": "You are a system that answers questions based on the context. answer exactly what the question asks using the context.",
},
{
"role": "user",
"content": f"using the context: {context}\n\nAnswer the following question: {question}",
},
],
) # type: ignore
print("After validation with `llm_validator` with `max_retries=2`")
print(qa.model_dump_json(indent=2), end="\n\n")
"""
After validation with `llm_validator` with `max_retries=2`
{
"question": "What is the meaning of life?",
"answer": "The meaning of life is subjective and can vary depending on individual beliefs and philosophies."
}
"""

View File

@@ -0,0 +1,16 @@
import instructor
from instructor import openai_moderation
from typing import Annotated
from pydantic import BaseModel, AfterValidator
from openai import OpenAI
client = instructor.from_openai(OpenAI())
class Response(BaseModel):
message: Annotated[str, AfterValidator(openai_moderation(client=client))]
response = Response(message="I want to make them suffer the consequences")

View File

@@ -0,0 +1,152 @@
# Using `llm_validator` with OpenAI's GPT-3.5 Turbo and Pydantic for Text Validation with Output Examples
## Overview
This document outlines how to use a custom text validation logic (`llm_validator`) with OpenAI's GPT-3.5 Turbo and Pydantic, including the outputs for each operation.
## Code Explanation
### Basic Setup
Import necessary modules and apply patches for compatibility.
```python
from typing_extensions import Annotated
from pydantic import (
BaseModel,
BeforeValidator,
)
from instructor import llm_validator, patch
import openai
patch()
```
### Defining Response Models
Define a basic Pydantic model named `QuestionAnswer`.
```python
class QuestionAnswer(BaseModel):
question: str
answer: str
```
### Generating a Response
Generate a response from GPT-3.5 Turbo.
```python
question = "What is the meaning of life?"
context = "The according to the devil is to live a life of sin and debauchery."
qa: QuestionAnswer = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
response_model=QuestionAnswer,
messages=[
{
"role": "system",
"content": "You are a system that answers questions based on the context. answer exactly what the question asks using the context.",
},
{
"role": "user",
"content": f"using the context: {context}\n\nAnswer the following question: {question}",
},
],
)
```
#### Output
Before validation with `llm_validator`:
```json
{
"question": "What is the meaning of life?",
"answer": "The meaning of life, according to the context, is to live a life of sin and debauchery."
}
```
### Adding Custom Validation
Add custom validation using `llm_validator`.
```python
class QuestionAnswerNoEvil(BaseModel):
question: str
answer: Annotated[
str,
BeforeValidator(
llm_validator("don't say objectionable things", allow_override=True)
),
]
```
#### Output
```text
1 validation error for QuestionAnswerNoEvil
answer
Assertion failed, The statement promotes sin and debauchery, which is objectionable.
```
### Handling Validation Errors
Catch exceptions raised by the validation.
```python
try:
qa: QuestionAnswerNoEvil = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
response_model=QuestionAnswerNoEvil,
messages=[
{
"role": "system",
"content": "You are a system that answers questions based on the context. answer exactly what the question asks using the context.",
},
{
"role": "user",
"content": f"using the context: {context}\n\nAnswer the following question: {question}",
},
],
)
except Exception as e:
print(e)
```
### Retrying Validation
Allow for retries by setting `max_retries=2`.
```python
qa: QuestionAnswerNoEvil = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
response_model=QuestionAnswerNoEvil,
max_retries=2,
messages=[
{
"role": "system",
"content": "You are a system that answers questions based on the context. answer exactly what the question asks using the context.",
},
{
"role": "user",
"content": f"using the context: {context}\n\nAnswer the following question: {question}",
},
],
)
```
#### Output
After validation with `llm_validator` and `max_retries=2`:
```json
{
"question": "What is the meaning of life?",
"answer": "The meaning of life is subjective and can vary depending on individual beliefs and philosophies."
}
```
## Summary
This document described how to use `llm_validator` with OpenAI's GPT-3.5 Turbo and Pydantic, including example outputs. This approach allows for controlled and filtered responses.