langchain-ai / langchain

🦜🔗 Build context-aware reasoning applications
https://python.langchain.com
MIT License
94.46k stars 15.28k forks source link

conlist: Call expression not allowed in type expression #25535

Open austinmw opened 2 months ago

austinmw commented 2 months ago

Checked other resources

Example Code

from langchain.pydantic_v1 import BaseModel, Field, conlist

class Day(BaseModel):
    day_of_week: str = Field(..., description="Day of the week")
    activities: list[str] = Field(..., description="List of 1-3 high-level workout descriptions or rest day activities")

class Week(BaseModel):
    monday: Day
    tuesday: Day
    wednesday: Day
    thursday: Day
    friday: Day
    saturday: Day
    sunday: Day

class WorkoutProgram(BaseModel):
    """Generate a workout program for an individual"""

    # This works, although it results in a warning: Call expression not allowed in type expression
    weeks: conlist(Week, min_items=4, max_items=4) = Field(
        description=f'List of 4weeks to structure the workout program.'
    )

    # This fails (returns a response that does not follow the schema)
    # weeks: Annotated[List, conlist(Week, min_items=NUM_WEEKS, max_items=NUM_WEEKS)] = Field(
    #     ...,
    #     description=f'List of {NUM_WEEKS} weeks to structure the workout program.'
    # )

Error Message and Stack Trace (if applicable)

Call expression not allowed in type expression PylancereportInvalidTypeForm

Description

Just generally confused about how to both make my program work and prevent type checking errors.

Is this because langchain_core requires pydantic (>=2.7.4,<3.0.0)? So if I need to install pydantic v2, but LangChain uses pydantic v1, is there no clean way to prevent this issue?

I search and found several semi-related threads, but nothing seemed to directly address this issue.

System Info

langchain==0.2.14
langchain-aws==0.1.16
langchain-community==0.0.31
langchain-core==0.2.32
langchain-text-splitters==0.2.2
langchainplus-sdk==0.0.8
gbaian10 commented 2 months ago

Many models support using Pydantic v2 as the schema input for tools. If using v2 can solve your problem, you might consider using v2.

Langchain is also actively migrating its internal objects to Pydantic v2.

Returning to your question, you can try using:

    weeks: Annotated[
        list[Week],
        Field(
            ...,
            description=f"List of {NUM_WEEKS} weeks to structure the workout program.",
            min_items=NUM_WEEKS,
            max_items=NUM_WEEKS,
        ),
    ]

Complete code:

from typing import Annotated

from flask.cli import load_dotenv
from langchain.pydantic_v1 import BaseModel, Field, conlist
from langchain_openai import ChatOpenAI

load_dotenv()

class Day(BaseModel):
    day_of_week: str = Field(..., description="Day of the week")
    activities: list[str] = Field(
        ...,
        description="List of 1-3 high-level workout descriptions or rest day activities",
    )

class Week(BaseModel):
    monday: Day
    tuesday: Day
    wednesday: Day
    thursday: Day
    friday: Day
    saturday: Day
    sunday: Day

NUM_WEEKS = 4

class WorkoutProgram(BaseModel):
    """Generate a workout program for an individual"""

    weeks: conlist(Week, min_items=4, max_items=4) = Field(
        description="List of 4weeks to structure the workout program."
    )

# print(WorkoutProgram.schema())
model = ChatOpenAI()
schema_a = model.bind_tools([WorkoutProgram]).get_input_schema().schema()

class WorkoutProgram(BaseModel):
    """Generate a workout program for an individual"""

    weeks: Annotated[
        list[Week],
        Field(
            ...,
            description=f"List of {NUM_WEEKS} weeks to structure the workout program.",
            min_items=NUM_WEEKS,
            max_items=NUM_WEEKS,
        ),
    ]

schema_b = model.bind_tools([WorkoutProgram]).get_input_schema().schema()

print(schema_a == schema_b)

If you only need to verify the format and not convert it into a tool, it should be fine. But if you need convert tool (use @tool) seems to have issues, at least in v1.