mirror of
https://github.com/hwchase17/langchain.git
synced 2026-06-09 18:50:33 +00:00
@@ -100,16 +100,16 @@ docstring-code-format = true
|
|||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"ALL"
|
"ALL"
|
||||||
]
|
]
|
||||||
ignore = [
|
ignore = [
|
||||||
"COM812", # Messes with the formatter
|
"COM812", # Messes with the formatter
|
||||||
"ISC001", # Messes with the formatter
|
"ISC001", # Messes with the formatter
|
||||||
"PERF203", # Rarely useful
|
"PERF203", # Rarely useful
|
||||||
"SLF001", # Private member access
|
"SLF001", # Private member access
|
||||||
"PLC0415", # Imports should be at the top. Not always desirable
|
"PLC0415", # Imports should be at the top. Not always desirable
|
||||||
"PLR0913", # Too many arguments in function definition
|
"PLR0913", # Too many arguments in function definition
|
||||||
"PLC0414", # Inconsistent with how type checkers expect to be notified of intentional re-exports
|
"PLC0414", # Inconsistent with how type checkers expect to be notified of intentional re-exports
|
||||||
]
|
]
|
||||||
unfixable = ["B028"] # People should intentionally tune the stacklevel
|
unfixable = ["B028"] # People should intentionally tune the stacklevel
|
||||||
|
|
||||||
@@ -119,8 +119,8 @@ flake8-annotations.allow-star-arg-any = true
|
|||||||
|
|
||||||
[tool.ruff.lint.per-file-ignores]
|
[tool.ruff.lint.per-file-ignores]
|
||||||
"tests/*" = [
|
"tests/*" = [
|
||||||
"D1", # Documentation rules
|
"D1", # Documentation rules
|
||||||
"PLC0415", # Imports should be at the top. Not always desirable for tests
|
"PLC0415", # Imports should be at the top. Not always desirable for tests
|
||||||
]
|
]
|
||||||
"langchain/agents/*" = [
|
"langchain/agents/*" = [
|
||||||
"ANN401", # we use Any right now, need to narrow
|
"ANN401", # we use Any right now, need to narrow
|
||||||
|
|||||||
@@ -577,14 +577,32 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
messages = [
|
messages = [
|
||||||
("system", "You are a helpful translator. Translate the user sentence to French."),
|
(
|
||||||
|
"system",
|
||||||
|
"You are a helpful translator. Translate the user sentence to French.",
|
||||||
|
),
|
||||||
("human", "I love programming."),
|
("human", "I love programming."),
|
||||||
]
|
]
|
||||||
llm.invoke(messages)
|
llm.invoke(messages)
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
AIMessage(content="J'aime la programmation.", response_metadata={'id': 'msg_01Trik66aiQ9Z1higrD5XFx3', 'model': 'claude-3-7-sonnet-20250219', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 25, 'output_tokens': 11}}, id='run-5886ac5f-3c2e-49f5-8a44-b1e92808c929-0', usage_metadata={'input_tokens': 25, 'output_tokens': 11, 'total_tokens': 36})
|
AIMessage(
|
||||||
|
content="J'aime la programmation.",
|
||||||
|
response_metadata={
|
||||||
|
"id": "msg_01Trik66aiQ9Z1higrD5XFx3",
|
||||||
|
"model": "claude-3-7-sonnet-20250219",
|
||||||
|
"stop_reason": "end_turn",
|
||||||
|
"stop_sequence": None,
|
||||||
|
"usage": {"input_tokens": 25, "output_tokens": 11},
|
||||||
|
},
|
||||||
|
id="run-5886ac5f-3c2e-49f5-8a44-b1e92808c929-0",
|
||||||
|
usage_metadata={
|
||||||
|
"input_tokens": 25,
|
||||||
|
"output_tokens": 11,
|
||||||
|
"total_tokens": 36,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
Stream:
|
Stream:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -594,14 +612,14 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
AIMessageChunk(content='J', id='run-272ff5f9-8485-402c-b90d-eac8babc5b25')
|
AIMessageChunk(content="J", id="run-272ff5f9-8485-402c-b90d-eac8babc5b25")
|
||||||
AIMessageChunk(content="'", id='run-272ff5f9-8485-402c-b90d-eac8babc5b25')
|
AIMessageChunk(content="'", id="run-272ff5f9-8485-402c-b90d-eac8babc5b25")
|
||||||
AIMessageChunk(content='a', id='run-272ff5f9-8485-402c-b90d-eac8babc5b25')
|
AIMessageChunk(content="a", id="run-272ff5f9-8485-402c-b90d-eac8babc5b25")
|
||||||
AIMessageChunk(content='ime', id='run-272ff5f9-8485-402c-b90d-eac8babc5b25')
|
AIMessageChunk(content="ime", id="run-272ff5f9-8485-402c-b90d-eac8babc5b25")
|
||||||
AIMessageChunk(content=' la', id='run-272ff5f9-8485-402c-b90d-eac8babc5b25')
|
AIMessageChunk(content=" la", id="run-272ff5f9-8485-402c-b90d-eac8babc5b25")
|
||||||
AIMessageChunk(content=' programm', id='run-272ff5f9-8485-402c-b90d-eac8babc5b25')
|
AIMessageChunk(content=" programm", id="run-272ff5f9-8485-402c-b90d-eac8babc5b25")
|
||||||
AIMessageChunk(content='ation', id='run-272ff5f9-8485-402c-b90d-eac8babc5b25')
|
AIMessageChunk(content="ation", id="run-272ff5f9-8485-402c-b90d-eac8babc5b25")
|
||||||
AIMessageChunk(content='.', id='run-272ff5f9-8485-402c-b90d-eac8babc5b25')
|
AIMessageChunk(content=".", id="run-272ff5f9-8485-402c-b90d-eac8babc5b25")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@@ -613,7 +631,7 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
AIMessageChunk(content="J'aime la programmation.", id='run-b34faef0-882f-4869-a19c-ed2b856e6361')
|
AIMessageChunk(content="J'aime la programmation.", id="run-b34faef0-882f-4869-a19c-ed2b856e6361")
|
||||||
|
|
||||||
Async:
|
Async:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -628,41 +646,69 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
AIMessage(content="J'aime la programmation.", response_metadata={'id': 'msg_01Trik66aiQ9Z1higrD5XFx3', 'model': 'claude-3-7-sonnet-20250219', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 25, 'output_tokens': 11}}, id='run-5886ac5f-3c2e-49f5-8a44-b1e92808c929-0', usage_metadata={'input_tokens': 25, 'output_tokens': 11, 'total_tokens': 36})
|
AIMessage(
|
||||||
|
content="J'aime la programmation.",
|
||||||
|
response_metadata={
|
||||||
|
"id": "msg_01Trik66aiQ9Z1higrD5XFx3",
|
||||||
|
"model": "claude-3-7-sonnet-20250219",
|
||||||
|
"stop_reason": "end_turn",
|
||||||
|
"stop_sequence": None,
|
||||||
|
"usage": {"input_tokens": 25, "output_tokens": 11},
|
||||||
|
},
|
||||||
|
id="run-5886ac5f-3c2e-49f5-8a44-b1e92808c929-0",
|
||||||
|
usage_metadata={
|
||||||
|
"input_tokens": 25,
|
||||||
|
"output_tokens": 11,
|
||||||
|
"total_tokens": 36,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
Tool calling:
|
Tool calling:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class GetWeather(BaseModel):
|
class GetWeather(BaseModel):
|
||||||
'''Get the current weather in a given location'''
|
'''Get the current weather in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
class GetPopulation(BaseModel):
|
class GetPopulation(BaseModel):
|
||||||
'''Get the current population in a given location'''
|
'''Get the current population in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
llm_with_tools = llm.bind_tools([GetWeather, GetPopulation])
|
llm_with_tools = llm.bind_tools([GetWeather, GetPopulation])
|
||||||
ai_msg = llm_with_tools.invoke("Which city is hotter today and which is bigger: LA or NY?")
|
ai_msg = llm_with_tools.invoke("Which city is hotter today and which is bigger: LA or NY?")
|
||||||
ai_msg.tool_calls
|
ai_msg.tool_calls
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[{'name': 'GetWeather',
|
[
|
||||||
'args': {'location': 'Los Angeles, CA'},
|
{
|
||||||
'id': 'toolu_01KzpPEAgzura7hpBqwHbWdo'},
|
"name": "GetWeather",
|
||||||
{'name': 'GetWeather',
|
"args": {"location": "Los Angeles, CA"},
|
||||||
'args': {'location': 'New York, NY'},
|
"id": "toolu_01KzpPEAgzura7hpBqwHbWdo",
|
||||||
'id': 'toolu_01JtgbVGVJbiSwtZk3Uycezx'},
|
},
|
||||||
{'name': 'GetPopulation',
|
{
|
||||||
'args': {'location': 'Los Angeles, CA'},
|
"name": "GetWeather",
|
||||||
'id': 'toolu_01429aygngesudV9nTbCKGuw'},
|
"args": {"location": "New York, NY"},
|
||||||
{'name': 'GetPopulation',
|
"id": "toolu_01JtgbVGVJbiSwtZk3Uycezx",
|
||||||
'args': {'location': 'New York, NY'},
|
},
|
||||||
'id': 'toolu_01JPktyd44tVMeBcPPnFSEJG'}]
|
{
|
||||||
|
"name": "GetPopulation",
|
||||||
|
"args": {"location": "Los Angeles, CA"},
|
||||||
|
"id": "toolu_01429aygngesudV9nTbCKGuw",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "GetPopulation",
|
||||||
|
"args": {"location": "New York, NY"},
|
||||||
|
"id": "toolu_01JPktyd44tVMeBcPPnFSEJG",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
See ``ChatAnthropic.bind_tools()`` method for more.
|
See ``ChatAnthropic.bind_tools()`` method for more.
|
||||||
|
|
||||||
@@ -673,6 +719,7 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class Joke(BaseModel):
|
class Joke(BaseModel):
|
||||||
'''Joke to tell user.'''
|
'''Joke to tell user.'''
|
||||||
|
|
||||||
@@ -680,12 +727,17 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
punchline: str = Field(description="The punchline to the joke")
|
punchline: str = Field(description="The punchline to the joke")
|
||||||
rating: Optional[int] = Field(description="How funny the joke is, from 1 to 10")
|
rating: Optional[int] = Field(description="How funny the joke is, from 1 to 10")
|
||||||
|
|
||||||
|
|
||||||
structured_llm = llm.with_structured_output(Joke)
|
structured_llm = llm.with_structured_output(Joke)
|
||||||
structured_llm.invoke("Tell me a joke about cats")
|
structured_llm.invoke("Tell me a joke about cats")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
Joke(setup='Why was the cat sitting on the computer?', punchline='To keep an eye on the mouse!', rating=None)
|
Joke(
|
||||||
|
setup="Why was the cat sitting on the computer?",
|
||||||
|
punchline="To keep an eye on the mouse!",
|
||||||
|
rating=None,
|
||||||
|
)
|
||||||
|
|
||||||
See ``ChatAnthropic.with_structured_output()`` for more.
|
See ``ChatAnthropic.with_structured_output()`` for more.
|
||||||
|
|
||||||
@@ -851,7 +903,14 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[{'signature': '...', 'thinking': "To find the cube root of 50.653...", 'type': 'thinking'}, {'text': 'The cube root of 50.653 is ...', 'type': 'text'}]
|
[
|
||||||
|
{
|
||||||
|
"signature": "...",
|
||||||
|
"thinking": "To find the cube root of 50.653...",
|
||||||
|
"type": "thinking",
|
||||||
|
},
|
||||||
|
{"text": "The cube root of 50.653 is ...", "type": "text"},
|
||||||
|
]
|
||||||
|
|
||||||
Citations:
|
Citations:
|
||||||
Anthropic supports a
|
Anthropic supports a
|
||||||
@@ -892,25 +951,39 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[{'text': 'Based on the document, ', 'type': 'text'},
|
[
|
||||||
{'text': 'the grass is green',
|
{"text": "Based on the document, ", "type": "text"},
|
||||||
'type': 'text',
|
{
|
||||||
'citations': [{'type': 'char_location',
|
"text": "the grass is green",
|
||||||
'cited_text': 'The grass is green. ',
|
"type": "text",
|
||||||
'document_index': 0,
|
"citations": [
|
||||||
'document_title': 'My Document',
|
{
|
||||||
'start_char_index': 0,
|
"type": "char_location",
|
||||||
'end_char_index': 20}]},
|
"cited_text": "The grass is green. ",
|
||||||
{'text': ', and ', 'type': 'text'},
|
"document_index": 0,
|
||||||
{'text': 'the sky is blue',
|
"document_title": "My Document",
|
||||||
'type': 'text',
|
"start_char_index": 0,
|
||||||
'citations': [{'type': 'char_location',
|
"end_char_index": 20,
|
||||||
'cited_text': 'The sky is blue.',
|
}
|
||||||
'document_index': 0,
|
],
|
||||||
'document_title': 'My Document',
|
},
|
||||||
'start_char_index': 20,
|
{"text": ", and ", "type": "text"},
|
||||||
'end_char_index': 36}]},
|
{
|
||||||
{'text': '.', 'type': 'text'}]
|
"text": "the sky is blue",
|
||||||
|
"type": "text",
|
||||||
|
"citations": [
|
||||||
|
{
|
||||||
|
"type": "char_location",
|
||||||
|
"cited_text": "The sky is blue.",
|
||||||
|
"document_index": 0,
|
||||||
|
"document_title": "My Document",
|
||||||
|
"start_char_index": 20,
|
||||||
|
"end_char_index": 36,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{"text": ".", "type": "text"},
|
||||||
|
]
|
||||||
|
|
||||||
Token usage:
|
Token usage:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -920,7 +993,7 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{'input_tokens': 25, 'output_tokens': 11, 'total_tokens': 36}
|
{"input_tokens": 25, "output_tokens": 11, "total_tokens": 36}
|
||||||
|
|
||||||
Message chunks containing token usage will be included during streaming by
|
Message chunks containing token usage will be included during streaming by
|
||||||
default:
|
default:
|
||||||
@@ -935,7 +1008,7 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{'input_tokens': 25, 'output_tokens': 11, 'total_tokens': 36}
|
{"input_tokens": 25, "output_tokens": 11, "total_tokens": 36}
|
||||||
|
|
||||||
These can be disabled by setting ``stream_usage=False`` in the stream method,
|
These can be disabled by setting ``stream_usage=False`` in the stream method,
|
||||||
or by setting ``stream_usage=False`` when initializing ChatAnthropic.
|
or by setting ``stream_usage=False`` when initializing ChatAnthropic.
|
||||||
@@ -981,7 +1054,7 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{'cache_read': 0, 'cache_creation': 1458}
|
{"cache_read": 0, "cache_creation": 1458}
|
||||||
|
|
||||||
Alternatively, you may enable prompt caching at invocation time. You may want to
|
Alternatively, you may enable prompt caching at invocation time. You may want to
|
||||||
conditionally cache based on runtime conditions, such as the length of the
|
conditionally cache based on runtime conditions, such as the length of the
|
||||||
@@ -1006,7 +1079,8 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
model="claude-3-7-sonnet-20250219",
|
model="claude-3-7-sonnet-20250219",
|
||||||
)
|
)
|
||||||
|
|
||||||
messages = [{
|
messages = [
|
||||||
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": [
|
"content": [
|
||||||
{
|
{
|
||||||
@@ -1015,7 +1089,8 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
"cache_control": {"type": "ephemeral", "ttl": "1h"},
|
"cache_control": {"type": "ephemeral", "ttl": "1h"},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
|
|
||||||
response = llm.invoke(messages)
|
response = llm.invoke(messages)
|
||||||
|
|
||||||
@@ -1038,7 +1113,7 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
"cache_creation": 1000,
|
"cache_creation": 1000,
|
||||||
"ephemeral_1h_input_tokens": 750,
|
"ephemeral_1h_input_tokens": 750,
|
||||||
"ephemeral_5m_input_tokens": 250,
|
"ephemeral_5m_input_tokens": 250,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
See `Claude documentation <https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching#1-hour-cache-duration-beta>`__
|
See `Claude documentation <https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching#1-hour-cache-duration-beta>`__
|
||||||
@@ -1128,12 +1203,14 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
llm = ChatAnthropic(model="claude-3-5-haiku-latest")
|
llm = ChatAnthropic(model="claude-3-5-haiku-latest")
|
||||||
|
|
||||||
tool = {"type": "web_search_20250305", "name": "web_search", "max_uses": 3}
|
tool = {
|
||||||
|
"type": "web_search_20250305",
|
||||||
|
"name": "web_search",
|
||||||
|
"max_uses": 3,
|
||||||
|
}
|
||||||
llm_with_tools = llm.bind_tools([tool])
|
llm_with_tools = llm.bind_tools([tool])
|
||||||
|
|
||||||
response = llm_with_tools.invoke(
|
response = llm_with_tools.invoke("How do I update a web app to TypeScript 5.5?")
|
||||||
"How do I update a web app to TypeScript 5.5?"
|
|
||||||
)
|
|
||||||
|
|
||||||
.. dropdown:: Web fetch (beta)
|
.. dropdown:: Web fetch (beta)
|
||||||
|
|
||||||
@@ -1146,12 +1223,14 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
betas=["web-fetch-2025-09-10"], # Enable web fetch beta
|
betas=["web-fetch-2025-09-10"], # Enable web fetch beta
|
||||||
)
|
)
|
||||||
|
|
||||||
tool = {"type": "web_fetch_20250910", "name": "web_fetch", "max_uses": 3}
|
tool = {
|
||||||
|
"type": "web_fetch_20250910",
|
||||||
|
"name": "web_fetch",
|
||||||
|
"max_uses": 3,
|
||||||
|
}
|
||||||
llm_with_tools = llm.bind_tools([tool])
|
llm_with_tools = llm.bind_tools([tool])
|
||||||
|
|
||||||
response = llm_with_tools.invoke(
|
response = llm_with_tools.invoke("Please analyze the content at https://example.com/article")
|
||||||
"Please analyze the content at https://example.com/article"
|
|
||||||
)
|
|
||||||
|
|
||||||
.. dropdown:: Code execution
|
.. dropdown:: Code execution
|
||||||
|
|
||||||
@@ -1233,11 +1312,13 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{'id': 'msg_013xU6FHEGEq76aP4RgFerVT',
|
{
|
||||||
'model': 'claude-3-7-sonnet-20250219',
|
"id": "msg_013xU6FHEGEq76aP4RgFerVT",
|
||||||
'stop_reason': 'end_turn',
|
"model": "claude-3-7-sonnet-20250219",
|
||||||
'stop_sequence': None,
|
"stop_reason": "end_turn",
|
||||||
'usage': {'input_tokens': 25, 'output_tokens': 11}}
|
"stop_sequence": None,
|
||||||
|
"usage": {"input_tokens": 25, "output_tokens": 11},
|
||||||
|
}
|
||||||
|
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
|
||||||
@@ -1722,11 +1803,13 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
from langchain_anthropic import ChatAnthropic
|
from langchain_anthropic import ChatAnthropic
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class GetWeather(BaseModel):
|
class GetWeather(BaseModel):
|
||||||
'''Get the current weather in a given location'''
|
'''Get the current weather in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
class GetPrice(BaseModel):
|
class GetPrice(BaseModel):
|
||||||
'''Get the price of a specific product.'''
|
'''Get the price of a specific product.'''
|
||||||
|
|
||||||
@@ -1735,7 +1818,9 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
||||||
llm_with_tools = llm.bind_tools([GetWeather, GetPrice])
|
llm_with_tools = llm.bind_tools([GetWeather, GetPrice])
|
||||||
llm_with_tools.invoke("what is the weather like in San Francisco",)
|
llm_with_tools.invoke(
|
||||||
|
"What is the weather like in San Francisco",
|
||||||
|
)
|
||||||
# -> AIMessage(
|
# -> AIMessage(
|
||||||
# content=[
|
# content=[
|
||||||
# {'text': '<thinking>\nBased on the user\'s question, the relevant function to call is GetWeather, which requires the "location" parameter.\n\nThe user has directly specified the location as "San Francisco". Since San Francisco is a well known city, I can reasonably infer they mean San Francisco, CA without needing the state specified.\n\nAll the required parameters are provided, so I can proceed with the API call.\n</thinking>', 'type': 'text'},
|
# {'text': '<thinking>\nBased on the user\'s question, the relevant function to call is GetWeather, which requires the "location" parameter.\n\nThe user has directly specified the location as "San Francisco". Since San Francisco is a well known city, I can reasonably infer they mean San Francisco, CA without needing the state specified.\n\nAll the required parameters are provided, so I can proceed with the API call.\n</thinking>', 'type': 'text'},
|
||||||
@@ -1752,11 +1837,13 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
from langchain_anthropic import ChatAnthropic
|
from langchain_anthropic import ChatAnthropic
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class GetWeather(BaseModel):
|
class GetWeather(BaseModel):
|
||||||
'''Get the current weather in a given location'''
|
'''Get the current weather in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
class GetPrice(BaseModel):
|
class GetPrice(BaseModel):
|
||||||
'''Get the price of a specific product.'''
|
'''Get the price of a specific product.'''
|
||||||
|
|
||||||
@@ -1765,7 +1852,9 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
||||||
llm_with_tools = llm.bind_tools([GetWeather, GetPrice], tool_choice="any")
|
llm_with_tools = llm.bind_tools([GetWeather, GetPrice], tool_choice="any")
|
||||||
llm_with_tools.invoke("what is the weather like in San Francisco",)
|
llm_with_tools.invoke(
|
||||||
|
"what is the weather like in San Francisco",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
Example — force specific tool call with tool_choice ``'<name_of_tool>'``:
|
Example — force specific tool call with tool_choice ``'<name_of_tool>'``:
|
||||||
@@ -1775,11 +1864,13 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
from langchain_anthropic import ChatAnthropic
|
from langchain_anthropic import ChatAnthropic
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class GetWeather(BaseModel):
|
class GetWeather(BaseModel):
|
||||||
'''Get the current weather in a given location'''
|
'''Get the current weather in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
class GetPrice(BaseModel):
|
class GetPrice(BaseModel):
|
||||||
'''Get the price of a specific product.'''
|
'''Get the price of a specific product.'''
|
||||||
|
|
||||||
@@ -1788,7 +1879,7 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
|
|
||||||
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
||||||
llm_with_tools = llm.bind_tools([GetWeather, GetPrice], tool_choice="GetWeather")
|
llm_with_tools = llm.bind_tools([GetWeather, GetPrice], tool_choice="GetWeather")
|
||||||
llm_with_tools.invoke("what is the weather like in San Francisco",)
|
llm_with_tools.invoke("What is the weather like in San Francisco")
|
||||||
|
|
||||||
Example — cache specific tools:
|
Example — cache specific tools:
|
||||||
|
|
||||||
@@ -1797,16 +1888,19 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
from langchain_anthropic import ChatAnthropic, convert_to_anthropic_tool
|
from langchain_anthropic import ChatAnthropic, convert_to_anthropic_tool
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class GetWeather(BaseModel):
|
class GetWeather(BaseModel):
|
||||||
'''Get the current weather in a given location'''
|
'''Get the current weather in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
class GetPrice(BaseModel):
|
class GetPrice(BaseModel):
|
||||||
'''Get the price of a specific product.'''
|
'''Get the price of a specific product.'''
|
||||||
|
|
||||||
product: str = Field(..., description="The product to look up.")
|
product: str = Field(..., description="The product to look up.")
|
||||||
|
|
||||||
|
|
||||||
# We'll convert our pydantic class to the anthropic tool format
|
# We'll convert our pydantic class to the anthropic tool format
|
||||||
# before passing to bind_tools so that we can set the 'cache_control'
|
# before passing to bind_tools so that we can set the 'cache_control'
|
||||||
# field on our tool.
|
# field on our tool.
|
||||||
@@ -1822,19 +1916,97 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
temperature=0,
|
temperature=0,
|
||||||
)
|
)
|
||||||
llm_with_tools = llm.bind_tools([GetWeather, cached_price_tool])
|
llm_with_tools = llm.bind_tools([GetWeather, cached_price_tool])
|
||||||
llm_with_tools.invoke("what is the weather like in San Francisco",)
|
llm_with_tools.invoke("What is the weather like in San Francisco")
|
||||||
|
|
||||||
This outputs:
|
This outputs:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
AIMessage(content=[{'text': "Certainly! I can help you find out the current weather in San Francisco. To get this information, I'll use the GetWeather function. Let me fetch that data for you right away.", 'type': 'text'}, {'id': 'toolu_01TS5h8LNo7p5imcG7yRiaUM', 'input': {'location': 'San Francisco, CA'}, 'name': 'GetWeather', 'type': 'tool_use'}], response_metadata={'id': 'msg_01Xg7Wr5inFWgBxE5jH9rpRo', 'model': 'claude-3-5-sonnet-latest', 'stop_reason': 'tool_use', 'stop_sequence': None, 'usage': {'input_tokens': 171, 'output_tokens': 96, 'cache_creation_input_tokens': 1470, 'cache_read_input_tokens': 0}}, id='run-b36a5b54-5d69-470e-a1b0-b932d00b089e-0', tool_calls=[{'name': 'GetWeather', 'args': {'location': 'San Francisco, CA'}, 'id': 'toolu_01TS5h8LNo7p5imcG7yRiaUM', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 96, 'total_tokens': 267})
|
AIMessage(
|
||||||
|
content=[
|
||||||
|
{
|
||||||
|
"text": "Certainly! I can help you find out the current weather in San Francisco. To get this information, I'll use the GetWeather function. Let me fetch that data for you right away.",
|
||||||
|
"type": "text",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "toolu_01TS5h8LNo7p5imcG7yRiaUM",
|
||||||
|
"input": {"location": "San Francisco, CA"},
|
||||||
|
"name": "GetWeather",
|
||||||
|
"type": "tool_use",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
response_metadata={
|
||||||
|
"id": "msg_01Xg7Wr5inFWgBxE5jH9rpRo",
|
||||||
|
"model": "claude-3-5-sonnet-latest",
|
||||||
|
"stop_reason": "tool_use",
|
||||||
|
"stop_sequence": None,
|
||||||
|
"usage": {
|
||||||
|
"input_tokens": 171,
|
||||||
|
"output_tokens": 96,
|
||||||
|
"cache_creation_input_tokens": 1470,
|
||||||
|
"cache_read_input_tokens": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id="run-b36a5b54-5d69-470e-a1b0-b932d00b089e-0",
|
||||||
|
tool_calls=[
|
||||||
|
{
|
||||||
|
"name": "GetWeather",
|
||||||
|
"args": {"location": "San Francisco, CA"},
|
||||||
|
"id": "toolu_01TS5h8LNo7p5imcG7yRiaUM",
|
||||||
|
"type": "tool_call",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
usage_metadata={
|
||||||
|
"input_tokens": 171,
|
||||||
|
"output_tokens": 96,
|
||||||
|
"total_tokens": 267,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
If we invoke the tool again, we can see that the "usage" information in the AIMessage.response_metadata shows that we had a cache hit:
|
If we invoke the tool again, we can see that the "usage" information in the AIMessage.response_metadata shows that we had a cache hit:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
AIMessage(content=[{'text': 'To get the current weather in San Francisco, I can use the GetWeather function. Let me check that for you.', 'type': 'text'}, {'id': 'toolu_01HtVtY1qhMFdPprx42qU2eA', 'input': {'location': 'San Francisco, CA'}, 'name': 'GetWeather', 'type': 'tool_use'}], response_metadata={'id': 'msg_016RfWHrRvW6DAGCdwB6Ac64', 'model': 'claude-3-5-sonnet-latest', 'stop_reason': 'tool_use', 'stop_sequence': None, 'usage': {'input_tokens': 171, 'output_tokens': 82, 'cache_creation_input_tokens': 0, 'cache_read_input_tokens': 1470}}, id='run-88b1f825-dcb7-4277-ac27-53df55d22001-0', tool_calls=[{'name': 'GetWeather', 'args': {'location': 'San Francisco, CA'}, 'id': 'toolu_01HtVtY1qhMFdPprx42qU2eA', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 82, 'total_tokens': 253})
|
AIMessage(
|
||||||
|
content=[
|
||||||
|
{
|
||||||
|
"text": "To get the current weather in San Francisco, I can use the GetWeather function. Let me check that for you.",
|
||||||
|
"type": "text",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "toolu_01HtVtY1qhMFdPprx42qU2eA",
|
||||||
|
"input": {"location": "San Francisco, CA"},
|
||||||
|
"name": "GetWeather",
|
||||||
|
"type": "tool_use",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
response_metadata={
|
||||||
|
"id": "msg_016RfWHrRvW6DAGCdwB6Ac64",
|
||||||
|
"model": "claude-3-5-sonnet-latest",
|
||||||
|
"stop_reason": "tool_use",
|
||||||
|
"stop_sequence": None,
|
||||||
|
"usage": {
|
||||||
|
"input_tokens": 171,
|
||||||
|
"output_tokens": 82,
|
||||||
|
"cache_creation_input_tokens": 0,
|
||||||
|
"cache_read_input_tokens": 1470,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id="run-88b1f825-dcb7-4277-ac27-53df55d22001-0",
|
||||||
|
tool_calls=[
|
||||||
|
{
|
||||||
|
"name": "GetWeather",
|
||||||
|
"args": {"location": "San Francisco, CA"},
|
||||||
|
"id": "toolu_01HtVtY1qhMFdPprx42qU2eA",
|
||||||
|
"type": "tool_call",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
usage_metadata={
|
||||||
|
"input_tokens": 171,
|
||||||
|
"output_tokens": 82,
|
||||||
|
"total_tokens": 253,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
formatted_tools = [
|
formatted_tools = [
|
||||||
@@ -1926,11 +2098,14 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
from langchain_anthropic import ChatAnthropic
|
from langchain_anthropic import ChatAnthropic
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class AnswerWithJustification(BaseModel):
|
class AnswerWithJustification(BaseModel):
|
||||||
'''An answer to the user question along with justification for the answer.'''
|
'''An answer to the user question along with justification for the answer.'''
|
||||||
|
|
||||||
answer: str
|
answer: str
|
||||||
justification: str
|
justification: str
|
||||||
|
|
||||||
|
|
||||||
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
||||||
|
|
||||||
@@ -1948,11 +2123,14 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
from langchain_anthropic import ChatAnthropic
|
from langchain_anthropic import ChatAnthropic
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class AnswerWithJustification(BaseModel):
|
class AnswerWithJustification(BaseModel):
|
||||||
'''An answer to the user question along with justification for the answer.'''
|
'''An answer to the user question along with justification for the answer.'''
|
||||||
|
|
||||||
answer: str
|
answer: str
|
||||||
justification: str
|
justification: str
|
||||||
|
|
||||||
|
|
||||||
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(AnswerWithJustification, include_raw=True)
|
structured_llm = llm.with_structured_output(AnswerWithJustification, include_raw=True)
|
||||||
|
|
||||||
@@ -1978,8 +2156,8 @@ class ChatAnthropic(BaseChatModel):
|
|||||||
"answer": {"type": "string"},
|
"answer": {"type": "string"},
|
||||||
"justification": {"type": "string"},
|
"justification": {"type": "string"},
|
||||||
},
|
},
|
||||||
"required": ["answer", "justification"]
|
"required": ["answer", "justification"],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
llm = ChatAnthropic(model="claude-3-5-sonnet-latest", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(schema)
|
structured_llm = llm.with_structured_output(schema)
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ plugins = ['pydantic.mypy']
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
docstring-code-line-length = 100
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -214,10 +214,10 @@ class Chroma(VectorStore):
|
|||||||
|
|
||||||
updated_document = Document(
|
updated_document = Document(
|
||||||
page_content="qux",
|
page_content="qux",
|
||||||
metadata={"bar": "baz"}
|
metadata={"bar": "baz"},
|
||||||
)
|
)
|
||||||
|
|
||||||
vector_store.update_documents(ids=["1"],documents=[updated_document])
|
vector_store.update_documents(ids=["1"], documents=[updated_document])
|
||||||
|
|
||||||
Delete Documents:
|
Delete Documents:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -227,29 +227,31 @@ class Chroma(VectorStore):
|
|||||||
Search:
|
Search:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
results = vector_store.similarity_search(query="thud",k=1)
|
results = vector_store.similarity_search(query="thud", k=1)
|
||||||
for doc in results:
|
for doc in results:
|
||||||
print(f"* {doc.page_content} [{doc.metadata}]")
|
print(f"* {doc.page_content} [{doc.metadata}]")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
* thud [{'baz': 'bar'}]
|
*thud[{"baz": "bar"}]
|
||||||
|
|
||||||
Search with filter:
|
Search with filter:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
results = vector_store.similarity_search(query="thud",k=1,filter={"baz": "bar"})
|
results = vector_store.similarity_search(
|
||||||
|
query="thud", k=1, filter={"baz": "bar"}
|
||||||
|
)
|
||||||
for doc in results:
|
for doc in results:
|
||||||
print(f"* {doc.page_content} [{doc.metadata}]")
|
print(f"* {doc.page_content} [{doc.metadata}]")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
* foo [{'baz': 'bar'}]
|
*foo[{"baz": "bar"}]
|
||||||
|
|
||||||
Search with score:
|
Search with score:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
results = vector_store.similarity_search_with_score(query="qux",k=1)
|
results = vector_store.similarity_search_with_score(query="qux", k=1)
|
||||||
for doc, score in results:
|
for doc, score in results:
|
||||||
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
|
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
|
||||||
|
|
||||||
@@ -270,8 +272,8 @@ class Chroma(VectorStore):
|
|||||||
# results = vector_store.asimilarity_search(query="thud",k=1)
|
# results = vector_store.asimilarity_search(query="thud",k=1)
|
||||||
|
|
||||||
# search with score
|
# search with score
|
||||||
results = await vector_store.asimilarity_search_with_score(query="qux",k=1)
|
results = await vector_store.asimilarity_search_with_score(query="qux", k=1)
|
||||||
for doc,score in results:
|
for doc, score in results:
|
||||||
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
|
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -289,7 +291,7 @@ class Chroma(VectorStore):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[Document(metadata={'baz': 'bar'}, page_content='thud')]
|
[Document(metadata={"baz": "bar"}, page_content="thud")]
|
||||||
|
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ disallow_untyped_defs = true
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -110,16 +110,19 @@ class ChatDeepSeek(BaseChatOpenAI):
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class GetWeather(BaseModel):
|
class GetWeather(BaseModel):
|
||||||
'''Get the current weather in a given location'''
|
'''Get the current weather in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
class GetPopulation(BaseModel):
|
class GetPopulation(BaseModel):
|
||||||
'''Get the current population in a given location'''
|
'''Get the current population in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
llm_with_tools = llm.bind_tools([GetWeather, GetPopulation])
|
llm_with_tools = llm.bind_tools([GetWeather, GetPopulation])
|
||||||
ai_msg = llm_with_tools.invoke("Which city is hotter today and which is bigger: LA or NY?")
|
ai_msg = llm_with_tools.invoke("Which city is hotter today and which is bigger: LA or NY?")
|
||||||
ai_msg.tool_calls
|
ai_msg.tool_calls
|
||||||
@@ -133,6 +136,7 @@ class ChatDeepSeek(BaseChatOpenAI):
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class Joke(BaseModel):
|
class Joke(BaseModel):
|
||||||
'''Joke to tell user.'''
|
'''Joke to tell user.'''
|
||||||
|
|
||||||
@@ -140,6 +144,7 @@ class ChatDeepSeek(BaseChatOpenAI):
|
|||||||
punchline: str = Field(description="The punchline to the joke")
|
punchline: str = Field(description="The punchline to the joke")
|
||||||
rating: Optional[int] = Field(description="How funny the joke is, from 1 to 10")
|
rating: Optional[int] = Field(description="How funny the joke is, from 1 to 10")
|
||||||
|
|
||||||
|
|
||||||
structured_llm = llm.with_structured_output(Joke)
|
structured_llm = llm.with_structured_output(Joke)
|
||||||
structured_llm.invoke("Tell me a joke about cats")
|
structured_llm.invoke("Tell me a joke about cats")
|
||||||
|
|
||||||
@@ -153,7 +158,7 @@ class ChatDeepSeek(BaseChatOpenAI):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{'input_tokens': 28, 'output_tokens': 5, 'total_tokens': 33}
|
{"input_tokens": 28, "output_tokens": 5, "total_tokens": 33}
|
||||||
|
|
||||||
Response metadata
|
Response metadata
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ disallow_untyped_defs = "True"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
docstring-code-line-length = 100
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -39,21 +39,48 @@ class ExaSearchResults(BaseTool): # type: ignore[override]
|
|||||||
Invocation with args:
|
Invocation with args:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
tool.invoke({"query":"what is the weather in SF","num_results":1})
|
tool.invoke({"query": "what is the weather in SF", "num_results": 1})
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
SearchResponse(results=[Result(url='https://www.wunderground.com/weather/37.8,-122.4', id='https://www.wunderground.com/weather/37.8,-122.4', title='San Francisco, CA Weather Conditionsstar_ratehome', score=0.1843988299369812, published_date='2023-02-23T01:17:06.594Z', author=None, text='The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.', highlights=None, highlight_scores=None, summary=None)], autoprompt_string=None)
|
SearchResponse(
|
||||||
|
results=[
|
||||||
|
Result(
|
||||||
|
url="https://www.wunderground.com/weather/37.8,-122.4",
|
||||||
|
id="https://www.wunderground.com/weather/37.8,-122.4",
|
||||||
|
title="San Francisco, CA Weather Conditionsstar_ratehome",
|
||||||
|
score=0.1843988299369812,
|
||||||
|
published_date="2023-02-23T01:17:06.594Z",
|
||||||
|
author=None,
|
||||||
|
text="The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.",
|
||||||
|
highlights=None,
|
||||||
|
highlight_scores=None,
|
||||||
|
summary=None,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
autoprompt_string=None,
|
||||||
|
)
|
||||||
|
|
||||||
Invocation with ToolCall:
|
Invocation with ToolCall:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
tool.invoke({"args": {"query":"what is the weather in SF","num_results":1}, "id": "1", "name": tool.name, "type": "tool_call"})
|
tool.invoke(
|
||||||
|
{
|
||||||
|
"args": {"query": "what is the weather in SF", "num_results": 1},
|
||||||
|
"id": "1",
|
||||||
|
"name": tool.name,
|
||||||
|
"type": "tool_call",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
ToolMessage(content='Title: San Francisco, CA Weather Conditionsstar_ratehome\nURL: https://www.wunderground.com/weather/37.8,-122.4\nID: https://www.wunderground.com/weather/37.8,-122.4\nScore: 0.1843988299369812\nPublished Date: 2023-02-23T01:17:06.594Z\nAuthor: None\nText: The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.\nHighlights: None\nHighlight Scores: None\nSummary: None\n', name='exa_search_results_json', tool_call_id='1')
|
ToolMessage(
|
||||||
|
content="Title: San Francisco, CA Weather Conditionsstar_ratehome\nURL: https://www.wunderground.com/weather/37.8,-122.4\nID: https://www.wunderground.com/weather/37.8,-122.4\nScore: 0.1843988299369812\nPublished Date: 2023-02-23T01:17:06.594Z\nAuthor: None\nText: The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.\nHighlights: None\nHighlight Scores: None\nSummary: None\n",
|
||||||
|
name="exa_search_results_json",
|
||||||
|
tool_call_id="1",
|
||||||
|
)
|
||||||
|
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ disallow_untyped_defs = "True"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -278,8 +278,10 @@ class ChatFireworks(BaseChatModel):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from langchain_fireworks.chat_models import ChatFireworks
|
from langchain_fireworks.chat_models import ChatFireworks
|
||||||
|
|
||||||
fireworks = ChatFireworks(
|
fireworks = ChatFireworks(
|
||||||
model_name="accounts/fireworks/models/llama-v3p1-8b-instruct")
|
model_name="accounts/fireworks/models/llama-v3p1-8b-instruct"
|
||||||
|
)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -825,7 +827,10 @@ class ChatFireworks(BaseChatModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
llm = ChatFireworks(model="accounts/fireworks/models/firefunction-v1", temperature=0)
|
llm = ChatFireworks(
|
||||||
|
model="accounts/fireworks/models/firefunction-v1",
|
||||||
|
temperature=0,
|
||||||
|
)
|
||||||
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke(
|
||||||
@@ -852,7 +857,10 @@ class ChatFireworks(BaseChatModel):
|
|||||||
justification: str
|
justification: str
|
||||||
|
|
||||||
|
|
||||||
llm = ChatFireworks(model="accounts/fireworks/models/firefunction-v1", temperature=0)
|
llm = ChatFireworks(
|
||||||
|
model="accounts/fireworks/models/firefunction-v1",
|
||||||
|
temperature=0,
|
||||||
|
)
|
||||||
structured_llm = llm.with_structured_output(
|
structured_llm = llm.with_structured_output(
|
||||||
AnswerWithJustification, include_raw=True
|
AnswerWithJustification, include_raw=True
|
||||||
)
|
)
|
||||||
@@ -886,7 +894,10 @@ class ChatFireworks(BaseChatModel):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
llm = ChatFireworks(model="accounts/fireworks/models/firefunction-v1", temperature=0)
|
llm = ChatFireworks(
|
||||||
|
model="accounts/fireworks/models/firefunction-v1",
|
||||||
|
temperature=0,
|
||||||
|
)
|
||||||
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke(
|
||||||
@@ -904,19 +915,25 @@ class ChatFireworks(BaseChatModel):
|
|||||||
from langchain_fireworks import ChatFireworks
|
from langchain_fireworks import ChatFireworks
|
||||||
|
|
||||||
oai_schema = {
|
oai_schema = {
|
||||||
'name': 'AnswerWithJustification',
|
"name": "AnswerWithJustification",
|
||||||
'description': 'An answer to the user question along with justification for the answer.',
|
"description": "An answer to the user question along with justification for the answer.",
|
||||||
'parameters': {
|
"parameters": {
|
||||||
'type': 'object',
|
"type": "object",
|
||||||
'properties': {
|
"properties": {
|
||||||
'answer': {'type': 'string'},
|
"answer": {"type": "string"},
|
||||||
'justification': {'description': 'A justification for the answer.', 'type': 'string'}
|
"justification": {
|
||||||
|
"description": "A justification for the answer.",
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'required': ['answer']
|
"required": ["answer"],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
llm = ChatFireworks(model="accounts/fireworks/models/firefunction-v1", temperature=0)
|
llm = ChatFireworks(
|
||||||
|
model="accounts/fireworks/models/firefunction-v1",
|
||||||
|
temperature=0,
|
||||||
|
)
|
||||||
structured_llm = llm.with_structured_output(oai_schema)
|
structured_llm = llm.with_structured_output(oai_schema)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke(
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class FireworksEmbeddings(BaseModel, Embeddings):
|
|||||||
from langchain_fireworks import FireworksEmbeddings
|
from langchain_fireworks import FireworksEmbeddings
|
||||||
|
|
||||||
model = FireworksEmbeddings(
|
model = FireworksEmbeddings(
|
||||||
model='nomic-ai/nomic-embed-text-v1.5'
|
model="nomic-ai/nomic-embed-text-v1.5"
|
||||||
# Use FIREWORKS_API_KEY env var or pass it in directly
|
# Use FIREWORKS_API_KEY env var or pass it in directly
|
||||||
# fireworks_api_key="..."
|
# fireworks_api_key="..."
|
||||||
)
|
)
|
||||||
@@ -44,7 +44,7 @@ class FireworksEmbeddings(BaseModel, Embeddings):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
vectors = embeddings.embed_documents(['hello', 'goodbye'])
|
vectors = embeddings.embed_documents(["hello", "goodbye"])
|
||||||
# Showing only the first 3 coordinates
|
# Showing only the first 3 coordinates
|
||||||
print(len(vectors))
|
print(len(vectors))
|
||||||
print(vectors[0][:3])
|
print(vectors[0][:3])
|
||||||
@@ -59,7 +59,7 @@ class FireworksEmbeddings(BaseModel, Embeddings):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
input_text = "The meaning of life is 42"
|
input_text = "The meaning of life is 42"
|
||||||
vector = embeddings.embed_query('hello')
|
vector = embeddings.embed_query("hello")
|
||||||
print(vector[:3])
|
print(vector[:3])
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ disallow_untyped_defs = "True"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -220,25 +220,32 @@ class ChatGroq(BaseChatModel):
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class GetWeather(BaseModel):
|
class GetWeather(BaseModel):
|
||||||
'''Get the current weather in a given location'''
|
'''Get the current weather in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
class GetPopulation(BaseModel):
|
class GetPopulation(BaseModel):
|
||||||
'''Get the current population in a given location'''
|
'''Get the current population in a given location'''
|
||||||
|
|
||||||
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
|
|
||||||
|
|
||||||
model_with_tools = llm.bind_tools([GetWeather, GetPopulation])
|
model_with_tools = llm.bind_tools([GetWeather, GetPopulation])
|
||||||
ai_msg = model_with_tools.invoke("What is the population of NY?")
|
ai_msg = model_with_tools.invoke("What is the population of NY?")
|
||||||
ai_msg.tool_calls
|
ai_msg.tool_calls
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[{'name': 'GetPopulation',
|
[
|
||||||
'args': {'location': 'NY'},
|
{
|
||||||
'id': 'call_bb8d'}]
|
"name": "GetPopulation",
|
||||||
|
"args": {"location": "NY"},
|
||||||
|
"id": "call_bb8d",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
See ``ChatGroq.bind_tools()`` method for more.
|
See ``ChatGroq.bind_tools()`` method for more.
|
||||||
|
|
||||||
@@ -249,6 +256,7 @@ class ChatGroq(BaseChatModel):
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class Joke(BaseModel):
|
class Joke(BaseModel):
|
||||||
'''Joke to tell user.'''
|
'''Joke to tell user.'''
|
||||||
|
|
||||||
@@ -256,12 +264,17 @@ class ChatGroq(BaseChatModel):
|
|||||||
punchline: str = Field(description="The punchline to the joke")
|
punchline: str = Field(description="The punchline to the joke")
|
||||||
rating: Optional[int] = Field(description="How funny the joke is, from 1 to 10")
|
rating: Optional[int] = Field(description="How funny the joke is, from 1 to 10")
|
||||||
|
|
||||||
|
|
||||||
structured_model = llm.with_structured_output(Joke)
|
structured_model = llm.with_structured_output(Joke)
|
||||||
structured_model.invoke("Tell me a joke about cats")
|
structured_model.invoke("Tell me a joke about cats")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
Joke(setup="Why don't cats play poker in the jungle?", punchline='Too many cheetahs!', rating=None)
|
Joke(
|
||||||
|
setup="Why don't cats play poker in the jungle?",
|
||||||
|
punchline="Too many cheetahs!",
|
||||||
|
rating=None,
|
||||||
|
)
|
||||||
|
|
||||||
See ``ChatGroq.with_structured_output()`` for more.
|
See ``ChatGroq.with_structured_output()`` for more.
|
||||||
|
|
||||||
@@ -273,17 +286,21 @@ class ChatGroq(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{'token_usage': {'completion_tokens': 70,
|
{
|
||||||
'prompt_tokens': 28,
|
"token_usage": {
|
||||||
'total_tokens': 98,
|
"completion_tokens": 70,
|
||||||
'completion_time': 0.111956391,
|
"prompt_tokens": 28,
|
||||||
'prompt_time': 0.007518279,
|
"total_tokens": 98,
|
||||||
'queue_time': None,
|
"completion_time": 0.111956391,
|
||||||
'total_time': 0.11947467},
|
"prompt_time": 0.007518279,
|
||||||
'model_name': 'llama-3.1-8b-instant',
|
"queue_time": None,
|
||||||
'system_fingerprint': 'fp_c5f20b5bb1',
|
"total_time": 0.11947467,
|
||||||
'finish_reason': 'stop',
|
},
|
||||||
'logprobs': None}
|
"model_name": "llama-3.1-8b-instant",
|
||||||
|
"system_fingerprint": "fp_c5f20b5bb1",
|
||||||
|
"finish_reason": "stop",
|
||||||
|
"logprobs": None,
|
||||||
|
}
|
||||||
|
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
|
||||||
@@ -971,9 +988,7 @@ class ChatGroq(BaseChatModel):
|
|||||||
llm = ChatGroq(model="openai/gpt-oss-120b", temperature=0)
|
llm = ChatGroq(model="openai/gpt-oss-120b", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
|
||||||
"What weighs more a pound of bricks or a pound of feathers"
|
|
||||||
)
|
|
||||||
|
|
||||||
# -> AnswerWithJustification(
|
# -> AnswerWithJustification(
|
||||||
# answer='They weigh the same',
|
# answer='They weigh the same',
|
||||||
@@ -996,12 +1011,11 @@ class ChatGroq(BaseChatModel):
|
|||||||
|
|
||||||
llm = ChatGroq(model="openai/gpt-oss-120b", temperature=0)
|
llm = ChatGroq(model="openai/gpt-oss-120b", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(
|
structured_llm = llm.with_structured_output(
|
||||||
AnswerWithJustification, include_raw=True
|
AnswerWithJustification,
|
||||||
|
include_raw=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
|
||||||
"What weighs more a pound of bricks or a pound of feathers"
|
|
||||||
)
|
|
||||||
# -> {
|
# -> {
|
||||||
# 'raw': AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Ao02pnFYXD6GN1yzc0uXPsvF', 'function': {'arguments': '{"answer":"They weigh the same.","justification":"Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ."}', 'name': 'AnswerWithJustification'}, 'type': 'function'}]}),
|
# 'raw': AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Ao02pnFYXD6GN1yzc0uXPsvF', 'function': {'arguments': '{"answer":"They weigh the same.","justification":"Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ."}', 'name': 'AnswerWithJustification'}, 'type': 'function'}]}),
|
||||||
# 'parsed': AnswerWithJustification(answer='They weigh the same.', justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'),
|
# 'parsed': AnswerWithJustification(answer='They weigh the same.', justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'),
|
||||||
@@ -1022,17 +1036,13 @@ class ChatGroq(BaseChatModel):
|
|||||||
'''An answer to the user question along with justification for the answer.'''
|
'''An answer to the user question along with justification for the answer.'''
|
||||||
|
|
||||||
answer: str
|
answer: str
|
||||||
justification: Annotated[
|
justification: Annotated[Optional[str], None, "A justification for the answer."]
|
||||||
Optional[str], None, "A justification for the answer."
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
llm = ChatGroq(model="openai/gpt-oss-120b", temperature=0)
|
llm = ChatGroq(model="openai/gpt-oss-120b", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
|
||||||
"What weighs more a pound of bricks or a pound of feathers"
|
|
||||||
)
|
|
||||||
# -> {
|
# -> {
|
||||||
# 'answer': 'They weigh the same',
|
# 'answer': 'They weigh the same',
|
||||||
# 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
|
# 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
|
||||||
@@ -1090,12 +1100,11 @@ class ChatGroq(BaseChatModel):
|
|||||||
|
|
||||||
llm = ChatGroq(model="openai/gpt-oss-120b", temperature=0)
|
llm = ChatGroq(model="openai/gpt-oss-120b", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(
|
structured_llm = llm.with_structured_output(
|
||||||
AnswerWithJustification, method="json_schema"
|
AnswerWithJustification,
|
||||||
|
method="json_schema",
|
||||||
)
|
)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
|
||||||
"What weighs more a pound of bricks or a pound of feathers"
|
|
||||||
)
|
|
||||||
|
|
||||||
# -> AnswerWithJustification(
|
# -> AnswerWithJustification(
|
||||||
# answer='They weigh the same',
|
# answer='They weigh the same',
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ disallow_untyped_defs = "True"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
docstring-code-line-length = 100
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -326,7 +326,8 @@ class ChatHuggingFace(BaseChatModel):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from huggingface_hub import login
|
from huggingface_hub import login
|
||||||
login() # You will be prompted for your HF key, which will then be saved locally
|
|
||||||
|
login() # You will be prompted for your HF key, which will then be saved locally
|
||||||
|
|
||||||
Key init args — completion params:
|
Key init args — completion params:
|
||||||
llm: `HuggingFaceTextGenInference`, `HuggingFaceEndpoint`, `HuggingFaceHub`, or
|
llm: `HuggingFaceTextGenInference`, `HuggingFaceEndpoint`, `HuggingFaceHub`, or
|
||||||
@@ -447,9 +448,13 @@ class ChatHuggingFace(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[{'name': 'GetPopulation',
|
[
|
||||||
'args': {'location': 'Los Angeles, CA'},
|
{
|
||||||
'id': '0'}]
|
"name": "GetPopulation",
|
||||||
|
"args": {"location": "Los Angeles, CA"},
|
||||||
|
"id": "0",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
Response metadata
|
Response metadata
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -458,10 +463,13 @@ class ChatHuggingFace(BaseChatModel):
|
|||||||
ai_msg.response_metadata
|
ai_msg.response_metadata
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
{'token_usage': ChatCompletionOutputUsage(completion_tokens=100,
|
{
|
||||||
prompt_tokens=8, total_tokens=108),
|
"token_usage": ChatCompletionOutputUsage(
|
||||||
'model': '',
|
completion_tokens=100, prompt_tokens=8, total_tokens=108
|
||||||
'finish_reason': 'length'}
|
),
|
||||||
|
"model": "",
|
||||||
|
"finish_reason": "length",
|
||||||
|
}
|
||||||
|
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ class HuggingFaceEmbeddings(BaseModel, Embeddings):
|
|||||||
from langchain_huggingface import HuggingFaceEmbeddings
|
from langchain_huggingface import HuggingFaceEmbeddings
|
||||||
|
|
||||||
model_name = "sentence-transformers/all-mpnet-base-v2"
|
model_name = "sentence-transformers/all-mpnet-base-v2"
|
||||||
model_kwargs = {'device': 'cpu'}
|
model_kwargs = {"device": "cpu"}
|
||||||
encode_kwargs = {'normalize_embeddings': False}
|
encode_kwargs = {"normalize_embeddings": False}
|
||||||
hf = HuggingFaceEmbeddings(
|
hf = HuggingFaceEmbeddings(
|
||||||
model_name=model_name,
|
model_name=model_name,
|
||||||
model_kwargs=model_kwargs,
|
model_kwargs=model_kwargs,
|
||||||
encode_kwargs=encode_kwargs
|
encode_kwargs=encode_kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class HuggingFaceEndpointEmbeddings(BaseModel, Embeddings):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from langchain_huggingface import HuggingFaceEndpointEmbeddings
|
from langchain_huggingface import HuggingFaceEndpointEmbeddings
|
||||||
|
|
||||||
model = "sentence-transformers/all-mpnet-base-v2"
|
model = "sentence-transformers/all-mpnet-base-v2"
|
||||||
hf = HuggingFaceEndpointEmbeddings(
|
hf = HuggingFaceEndpointEmbeddings(
|
||||||
model=model,
|
model=model,
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class HuggingFaceEndpoint(LLM):
|
|||||||
typical_p=0.95,
|
typical_p=0.95,
|
||||||
temperature=0.01,
|
temperature=0.01,
|
||||||
repetition_penalty=1.03,
|
repetition_penalty=1.03,
|
||||||
huggingfacehub_api_token="my-api-key"
|
huggingfacehub_api_token="my-api-key",
|
||||||
)
|
)
|
||||||
print(llm.invoke("What is Deep Learning?"))
|
print(llm.invoke("What is Deep Learning?"))
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ class HuggingFaceEndpoint(LLM):
|
|||||||
repetition_penalty=1.03,
|
repetition_penalty=1.03,
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
streaming=True,
|
streaming=True,
|
||||||
huggingfacehub_api_token="my-api-key"
|
huggingfacehub_api_token="my-api-key",
|
||||||
)
|
)
|
||||||
print(llm.invoke("What is Deep Learning?"))
|
print(llm.invoke("What is Deep Learning?"))
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ class HuggingFaceEndpoint(LLM):
|
|||||||
provider="novita",
|
provider="novita",
|
||||||
max_new_tokens=100,
|
max_new_tokens=100,
|
||||||
do_sample=False,
|
do_sample=False,
|
||||||
huggingfacehub_api_token="my-api-key"
|
huggingfacehub_api_token="my-api-key",
|
||||||
)
|
)
|
||||||
print(llm.invoke("What is Deep Learning?"))
|
print(llm.invoke("What is Deep Learning?"))
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ class HuggingFacePipeline(BaseLLM):
|
|||||||
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
||||||
model = AutoModelForCausalLM.from_pretrained(model_id)
|
model = AutoModelForCausalLM.from_pretrained(model_id)
|
||||||
pipe = pipeline(
|
pipe = pipeline(
|
||||||
"text-generation", model=model, tokenizer=tokenizer, max_new_tokens=10
|
"text-generation",
|
||||||
|
model=model,
|
||||||
|
tokenizer=tokenizer,
|
||||||
|
max_new_tokens=10,
|
||||||
)
|
)
|
||||||
hf = HuggingFacePipeline(pipeline=pipe)
|
hf = HuggingFacePipeline(pipeline=pipe)
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ disallow_untyped_defs = "True"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
docstring-code-line-length = 100
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ disallow_untyped_defs = "True"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ langchain-tests = { path = "../../standard-tests", editable = true }
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -262,10 +262,10 @@ class ChatOllama(BaseChatModel):
|
|||||||
from langchain_ollama import ChatOllama
|
from langchain_ollama import ChatOllama
|
||||||
|
|
||||||
llm = ChatOllama(
|
llm = ChatOllama(
|
||||||
model = "gpt-oss:20b",
|
model="gpt-oss:20b",
|
||||||
validate_model_on_init = True,
|
validate_model_on_init=True,
|
||||||
temperature = 0.8,
|
temperature=0.8,
|
||||||
num_predict = 256,
|
num_predict=256,
|
||||||
# other params ...
|
# other params ...
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -307,7 +307,22 @@ class ChatOllama(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
AIMessageChunk(content='Je adore le programmation.(Note: "programmation" is the formal way to say "programming" in French, but informally, people might use the phrase "le développement logiciel" or simply "le code")', response_metadata={'model': 'llama3', 'created_at': '2024-07-04T03:38:54.933154Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 1977300042, 'load_duration': 1345709, 'prompt_eval_duration': 159343000, 'eval_count': 47, 'eval_duration': 1815123000}, id='run-3c81a3ed-3e79-4dd3-a796-04064d804890')
|
AIMessageChunk(
|
||||||
|
content='Je adore le programmation.(Note: "programmation" is the formal way to say "programming" in French, but informally, people might use the phrase "le développement logiciel" or simply "le code")',
|
||||||
|
response_metadata={
|
||||||
|
"model": "llama3",
|
||||||
|
"created_at": "2024-07-04T03:38:54.933154Z",
|
||||||
|
"message": {"role": "assistant", "content": ""},
|
||||||
|
"done_reason": "stop",
|
||||||
|
"done": True,
|
||||||
|
"total_duration": 1977300042,
|
||||||
|
"load_duration": 1345709,
|
||||||
|
"prompt_eval_duration": 159343000,
|
||||||
|
"eval_count": 47,
|
||||||
|
"eval_duration": 1815123000,
|
||||||
|
},
|
||||||
|
id="run-3c81a3ed-3e79-4dd3-a796-04064d804890",
|
||||||
|
)
|
||||||
|
|
||||||
Async:
|
Async:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -316,7 +331,23 @@ class ChatOllama(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
AIMessage(content="Hi there! I'm just an AI, so I don't have feelings or emotions like humans do. But I'm functioning properly and ready to help with any questions or tasks you may have! How can I assist you today?", response_metadata={'model': 'llama3', 'created_at': '2024-07-04T03:52:08.165478Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 2138492875, 'load_duration': 1364000, 'prompt_eval_count': 10, 'prompt_eval_duration': 297081000, 'eval_count': 47, 'eval_duration': 1838524000}, id='run-29c510ae-49a4-4cdd-8f23-b972bfab1c49-0')
|
AIMessage(
|
||||||
|
content="Hi there! I'm just an AI, so I don't have feelings or emotions like humans do. But I'm functioning properly and ready to help with any questions or tasks you may have! How can I assist you today?",
|
||||||
|
response_metadata={
|
||||||
|
"model": "llama3",
|
||||||
|
"created_at": "2024-07-04T03:52:08.165478Z",
|
||||||
|
"message": {"role": "assistant", "content": ""},
|
||||||
|
"done_reason": "stop",
|
||||||
|
"done": True,
|
||||||
|
"total_duration": 2138492875,
|
||||||
|
"load_duration": 1364000,
|
||||||
|
"prompt_eval_count": 10,
|
||||||
|
"prompt_eval_duration": 297081000,
|
||||||
|
"eval_count": 47,
|
||||||
|
"eval_duration": 1838524000,
|
||||||
|
},
|
||||||
|
id="run-29c510ae-49a4-4cdd-8f23-b972bfab1c49-0",
|
||||||
|
)
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@@ -332,23 +363,57 @@ class ChatOllama(BaseChatModel):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
messages = [
|
messages = [("human", "Say hello world!"), ("human", "Say goodbye world!")]
|
||||||
("human", "Say hello world!"),
|
|
||||||
("human","Say goodbye world!")
|
|
||||||
]
|
|
||||||
await llm.abatch(messages)
|
await llm.abatch(messages)
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[AIMessage(content='HELLO, WORLD!', response_metadata={'model': 'llama3', 'created_at': '2024-07-04T03:55:07.315396Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 1696745458, 'load_duration': 1505000, 'prompt_eval_count': 8, 'prompt_eval_duration': 111627000, 'eval_count': 6, 'eval_duration': 185181000}, id='run-da6c7562-e25a-4a44-987a-2c83cd8c2686-0'),
|
[
|
||||||
AIMessage(content="It's been a blast chatting with you! Say goodbye to the world for me, and don't forget to come back and visit us again soon!", response_metadata={'model': 'llama3', 'created_at': '2024-07-04T03:55:07.018076Z', 'message': {'role': 'assistant', 'content': ''}, 'done_reason': 'stop', 'done': True, 'total_duration': 1399391083, 'load_duration': 1187417, 'prompt_eval_count': 20, 'prompt_eval_duration': 230349000, 'eval_count': 31, 'eval_duration': 1166047000}, id='run-96cad530-6f3e-4cf9-86b4-e0f8abba4cdb-0')]
|
AIMessage(
|
||||||
|
content="HELLO, WORLD!",
|
||||||
|
response_metadata={
|
||||||
|
"model": "llama3",
|
||||||
|
"created_at": "2024-07-04T03:55:07.315396Z",
|
||||||
|
"message": {"role": "assistant", "content": ""},
|
||||||
|
"done_reason": "stop",
|
||||||
|
"done": True,
|
||||||
|
"total_duration": 1696745458,
|
||||||
|
"load_duration": 1505000,
|
||||||
|
"prompt_eval_count": 8,
|
||||||
|
"prompt_eval_duration": 111627000,
|
||||||
|
"eval_count": 6,
|
||||||
|
"eval_duration": 185181000,
|
||||||
|
},
|
||||||
|
id="run-da6c7562-e25a-4a44-987a-2c83cd8c2686-0",
|
||||||
|
),
|
||||||
|
AIMessage(
|
||||||
|
content="It's been a blast chatting with you! Say goodbye to the world for me, and don't forget to come back and visit us again soon!",
|
||||||
|
response_metadata={
|
||||||
|
"model": "llama3",
|
||||||
|
"created_at": "2024-07-04T03:55:07.018076Z",
|
||||||
|
"message": {"role": "assistant", "content": ""},
|
||||||
|
"done_reason": "stop",
|
||||||
|
"done": True,
|
||||||
|
"total_duration": 1399391083,
|
||||||
|
"load_duration": 1187417,
|
||||||
|
"prompt_eval_count": 20,
|
||||||
|
"prompt_eval_duration": 230349000,
|
||||||
|
"eval_count": 31,
|
||||||
|
"eval_duration": 1166047000,
|
||||||
|
},
|
||||||
|
id="run-96cad530-6f3e-4cf9-86b4-e0f8abba4cdb-0",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
JSON mode:
|
JSON mode:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
||||||
json_llm = ChatOllama(format="json")
|
json_llm = ChatOllama(format="json")
|
||||||
llm.invoke("Return a query for the weather in a random location and time of day with two keys: location and time_of_day. Respond using JSON only.").content
|
llm.invoke(
|
||||||
|
"Return a query for the weather in a random location and time of day with two keys: location and time_of_day. "
|
||||||
|
"Respond using JSON only."
|
||||||
|
).content
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@@ -360,19 +425,25 @@ class ChatOllama(BaseChatModel):
|
|||||||
from langchain_ollama import ChatOllama
|
from langchain_ollama import ChatOllama
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
class Multiply(BaseModel):
|
class Multiply(BaseModel):
|
||||||
a: int = Field(..., description="First integer")
|
a: int = Field(..., description="First integer")
|
||||||
b: int = Field(..., description="Second integer")
|
b: int = Field(..., description="Second integer")
|
||||||
|
|
||||||
|
|
||||||
ans = await chat.invoke("What is 45*67")
|
ans = await chat.invoke("What is 45*67")
|
||||||
ans.tool_calls
|
ans.tool_calls
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[{'name': 'Multiply',
|
[
|
||||||
'args': {'a': 45, 'b': 67},
|
{
|
||||||
'id': '420c3f3b-df10-4188-945f-eb3abdb40622',
|
"name": "Multiply",
|
||||||
'type': 'tool_call'}]
|
"args": {"a": 45, "b": 67},
|
||||||
|
"id": "420c3f3b-df10-4188-945f-eb3abdb40622",
|
||||||
|
"type": "tool_call",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
Thinking / Reasoning:
|
Thinking / Reasoning:
|
||||||
You can enable reasoning mode for models that support it by setting
|
You can enable reasoning mode for models that support it by setting
|
||||||
@@ -394,9 +465,9 @@ class ChatOllama(BaseChatModel):
|
|||||||
from langchain_ollama import ChatOllama
|
from langchain_ollama import ChatOllama
|
||||||
|
|
||||||
llm = ChatOllama(
|
llm = ChatOllama(
|
||||||
model = "deepseek-r1:8b",
|
model="deepseek-r1:8b",
|
||||||
validate_model_on_init = True,
|
validate_model_on_init=True,
|
||||||
reasoning= True,
|
reasoning=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
llm.invoke("how many r in the word strawberry?")
|
llm.invoke("how many r in the word strawberry?")
|
||||||
@@ -1118,18 +1189,15 @@ class ChatOllama(BaseChatModel):
|
|||||||
|
|
||||||
answer: str
|
answer: str
|
||||||
justification: Optional[str] = Field(
|
justification: Optional[str] = Field(
|
||||||
default=..., description="A justification for the answer."
|
default=...,
|
||||||
|
description="A justification for the answer.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
llm = ChatOllama(model="llama3.1", temperature=0)
|
llm = ChatOllama(model="llama3.1", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(
|
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
||||||
AnswerWithJustification
|
|
||||||
)
|
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
|
||||||
"What weighs more a pound of bricks or a pound of feathers"
|
|
||||||
)
|
|
||||||
|
|
||||||
# -> AnswerWithJustification(
|
# -> AnswerWithJustification(
|
||||||
# answer='They weigh the same',
|
# answer='They weigh the same',
|
||||||
@@ -1153,12 +1221,11 @@ class ChatOllama(BaseChatModel):
|
|||||||
|
|
||||||
llm = ChatOllama(model="llama3.1", temperature=0)
|
llm = ChatOllama(model="llama3.1", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(
|
structured_llm = llm.with_structured_output(
|
||||||
AnswerWithJustification, include_raw=True
|
AnswerWithJustification,
|
||||||
|
include_raw=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
|
||||||
"What weighs more a pound of bricks or a pound of feathers"
|
|
||||||
)
|
|
||||||
# -> {
|
# -> {
|
||||||
# 'raw': AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Ao02pnFYXD6GN1yzc0uXPsvF', 'function': {'arguments': '{"answer":"They weigh the same.","justification":"Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ."}', 'name': 'AnswerWithJustification'}, 'type': 'function'}]}),
|
# 'raw': AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Ao02pnFYXD6GN1yzc0uXPsvF', 'function': {'arguments': '{"answer":"They weigh the same.","justification":"Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ."}', 'name': 'AnswerWithJustification'}, 'type': 'function'}]}),
|
||||||
# 'parsed': AnswerWithJustification(answer='They weigh the same.', justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'),
|
# 'parsed': AnswerWithJustification(answer='They weigh the same.', justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'),
|
||||||
@@ -1180,18 +1247,18 @@ class ChatOllama(BaseChatModel):
|
|||||||
|
|
||||||
answer: str
|
answer: str
|
||||||
justification: Optional[str] = Field(
|
justification: Optional[str] = Field(
|
||||||
default=..., description="A justification for the answer."
|
default=...,
|
||||||
|
description="A justification for the answer.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
llm = ChatOllama(model="llama3.1", temperature=0)
|
llm = ChatOllama(model="llama3.1", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(
|
structured_llm = llm.with_structured_output(
|
||||||
AnswerWithJustification, method="function_calling"
|
AnswerWithJustification,
|
||||||
|
method="function_calling",
|
||||||
)
|
)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
|
||||||
"What weighs more a pound of bricks or a pound of feathers"
|
|
||||||
)
|
|
||||||
|
|
||||||
# -> AnswerWithJustification(
|
# -> AnswerWithJustification(
|
||||||
# answer='They weigh the same',
|
# answer='They weigh the same',
|
||||||
@@ -1213,17 +1280,13 @@ class ChatOllama(BaseChatModel):
|
|||||||
'''An answer to the user question along with justification for the answer.'''
|
'''An answer to the user question along with justification for the answer.'''
|
||||||
|
|
||||||
answer: str
|
answer: str
|
||||||
justification: Annotated[
|
justification: Annotated[Optional[str], None, "A justification for the answer."]
|
||||||
Optional[str], None, "A justification for the answer."
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
llm = ChatOllama(model="llama3.1", temperature=0)
|
llm = ChatOllama(model="llama3.1", temperature=0)
|
||||||
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
structured_llm = llm.with_structured_output(AnswerWithJustification)
|
||||||
|
|
||||||
structured_llm.invoke(
|
structured_llm.invoke("What weighs more a pound of bricks or a pound of feathers")
|
||||||
"What weighs more a pound of bricks or a pound of feathers"
|
|
||||||
)
|
|
||||||
# -> {
|
# -> {
|
||||||
# 'answer': 'They weigh the same',
|
# 'answer': 'They weigh the same',
|
||||||
# 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
|
# 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
|
||||||
|
|||||||
@@ -81,9 +81,7 @@ class OllamaEmbeddings(BaseModel, Embeddings):
|
|||||||
|
|
||||||
from langchain_ollama import OllamaEmbeddings
|
from langchain_ollama import OllamaEmbeddings
|
||||||
|
|
||||||
embed = OllamaEmbeddings(
|
embed = OllamaEmbeddings(model="llama3")
|
||||||
model="llama3"
|
|
||||||
)
|
|
||||||
|
|
||||||
Embed single text:
|
Embed single text:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ disallow_untyped_defs = "True"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
docstring-code-line-length = 100
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -62,17 +62,13 @@ ignore_missing_imports = true
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "I", "T201", "UP", "S"]
|
select = ["E", "F", "I", "T201", "UP", "S"]
|
||||||
ignore = [ "UP007", "UP045" ]
|
ignore = [ "UP007", "UP045" ]
|
||||||
|
|
||||||
[tool.ruff.format]
|
|
||||||
docstring-code-format = true
|
|
||||||
skip-magic-trailing-comma = true
|
|
||||||
|
|
||||||
[tool.ruff.lint.isort]
|
|
||||||
split-on-trailing-comma = false
|
|
||||||
|
|
||||||
[tool.coverage.run]
|
[tool.coverage.run]
|
||||||
omit = ["tests/*"]
|
omit = ["tests/*"]
|
||||||
|
|
||||||
|
|||||||
@@ -57,17 +57,13 @@ ignore_missing_imports = true
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "I", "T201", "UP", "S"]
|
select = ["E", "F", "I", "T201", "UP", "S"]
|
||||||
ignore = [ "UP007", "UP045"]
|
ignore = [ "UP007", "UP045"]
|
||||||
|
|
||||||
[tool.ruff.format]
|
|
||||||
docstring-code-format = true
|
|
||||||
skip-magic-trailing-comma = true
|
|
||||||
|
|
||||||
[tool.ruff.lint.isort]
|
|
||||||
split-on-trailing-comma = false
|
|
||||||
|
|
||||||
[tool.coverage.run]
|
[tool.coverage.run]
|
||||||
omit = ["tests/*"]
|
omit = ["tests/*"]
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ langchain-tests = { path = "../../standard-tests", editable = true }
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "I", "T201", "UP", "S"]
|
select = ["E", "F", "I", "T201", "UP", "S"]
|
||||||
ignore = [ "UP007", "UP045" ]
|
ignore = [ "UP007", "UP045" ]
|
||||||
|
|||||||
@@ -99,32 +99,58 @@ class QdrantVectorStore(VectorStore):
|
|||||||
Search:
|
Search:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
results = vector_store.similarity_search(query="thud",k=1)
|
results = vector_store.similarity_search(
|
||||||
|
query="thud",
|
||||||
|
k=1,
|
||||||
|
)
|
||||||
for doc in results:
|
for doc in results:
|
||||||
print(f"* {doc.page_content} [{doc.metadata}]")
|
print(f"* {doc.page_content} [{doc.metadata}]")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
* thud [{'bar': 'baz', '_id': '0d706099-6dd9-412a-9df6-a71043e020de', '_collection_name': 'demo_collection'}]
|
*thud[
|
||||||
|
{
|
||||||
|
"bar": "baz",
|
||||||
|
"_id": "0d706099-6dd9-412a-9df6-a71043e020de",
|
||||||
|
"_collection_name": "demo_collection",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
Search with filter:
|
Search with filter:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from qdrant_client.http import models
|
from qdrant_client.http import models
|
||||||
|
|
||||||
results = vector_store.similarity_search(query="thud",k=1,filter=models.Filter(must=[models.FieldCondition(key="metadata.bar", match=models.MatchValue(value="baz"),)]))
|
results = vector_store.similarity_search(
|
||||||
|
query="thud",
|
||||||
|
k=1,
|
||||||
|
filter=models.Filter(
|
||||||
|
must=[
|
||||||
|
models.FieldCondition(
|
||||||
|
key="metadata.bar",
|
||||||
|
match=models.MatchValue(value="baz"),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
)
|
||||||
for doc in results:
|
for doc in results:
|
||||||
print(f"* {doc.page_content} [{doc.metadata}]")
|
print(f"* {doc.page_content} [{doc.metadata}]")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
* thud [{'bar': 'baz', '_id': '0d706099-6dd9-412a-9df6-a71043e020de', '_collection_name': 'demo_collection'}]
|
*thud[
|
||||||
|
{
|
||||||
|
"bar": "baz",
|
||||||
|
"_id": "0d706099-6dd9-412a-9df6-a71043e020de",
|
||||||
|
"_collection_name": "demo_collection",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
Search with score:
|
Search with score:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
results = vector_store.similarity_search_with_score(query="qux",k=1)
|
results = vector_store.similarity_search_with_score(query="qux", k=1)
|
||||||
for doc, score in results:
|
for doc, score in results:
|
||||||
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
|
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
|
||||||
|
|
||||||
@@ -145,8 +171,8 @@ class QdrantVectorStore(VectorStore):
|
|||||||
# results = vector_store.asimilarity_search(query="thud",k=1)
|
# results = vector_store.asimilarity_search(query="thud",k=1)
|
||||||
|
|
||||||
# search with score
|
# search with score
|
||||||
results = await vector_store.asimilarity_search_with_score(query="qux",k=1)
|
results = await vector_store.asimilarity_search_with_score(query="qux", k=1)
|
||||||
for doc,score in results:
|
for doc, score in results:
|
||||||
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
|
print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -164,7 +190,16 @@ class QdrantVectorStore(VectorStore):
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[Document(metadata={'bar': 'baz', '_id': '0d706099-6dd9-412a-9df6-a71043e020de', '_collection_name': 'demo_collection'}, page_content='thud')]
|
[
|
||||||
|
Document(
|
||||||
|
metadata={
|
||||||
|
"bar": "baz",
|
||||||
|
"_id": "0d706099-6dd9-412a-9df6-a71043e020de",
|
||||||
|
"_collection_name": "demo_collection",
|
||||||
|
},
|
||||||
|
page_content="thud",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
|
||||||
|
|||||||
@@ -1342,6 +1342,7 @@ class Qdrant(VectorStore):
|
|||||||
|
|
||||||
from langchain_qdrant import Qdrant
|
from langchain_qdrant import Qdrant
|
||||||
from langchain_openai import OpenAIEmbeddings
|
from langchain_openai import OpenAIEmbeddings
|
||||||
|
|
||||||
embeddings = OpenAIEmbeddings()
|
embeddings = OpenAIEmbeddings()
|
||||||
qdrant = Qdrant.from_texts(texts, embeddings, "localhost")
|
qdrant = Qdrant.from_texts(texts, embeddings, "localhost")
|
||||||
|
|
||||||
@@ -1583,6 +1584,7 @@ class Qdrant(VectorStore):
|
|||||||
|
|
||||||
from langchain_qdrant import Qdrant
|
from langchain_qdrant import Qdrant
|
||||||
from langchain_openai import OpenAIEmbeddings
|
from langchain_openai import OpenAIEmbeddings
|
||||||
|
|
||||||
embeddings = OpenAIEmbeddings()
|
embeddings = OpenAIEmbeddings()
|
||||||
qdrant = await Qdrant.afrom_texts(texts, embeddings, "localhost")
|
qdrant = await Qdrant.afrom_texts(texts, embeddings, "localhost")
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ langchain-tests = { path = "../../standard-tests", editable = true }
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
@@ -92,14 +92,23 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override]
|
|||||||
AIMessage(
|
AIMessage(
|
||||||
content="J'adore la programmation.",
|
content="J'adore la programmation.",
|
||||||
response_metadata={
|
response_metadata={
|
||||||
'token_usage': {'completion_tokens': 9, 'prompt_tokens': 32, 'total_tokens': 41},
|
"token_usage": {
|
||||||
'model_name': 'grok-4',
|
"completion_tokens": 9,
|
||||||
'system_fingerprint': None,
|
"prompt_tokens": 32,
|
||||||
'finish_reason': 'stop',
|
"total_tokens": 41,
|
||||||
'logprobs': None
|
},
|
||||||
|
"model_name": "grok-4",
|
||||||
|
"system_fingerprint": None,
|
||||||
|
"finish_reason": "stop",
|
||||||
|
"logprobs": None,
|
||||||
},
|
},
|
||||||
id='run-168dceca-3b8b-4283-94e3-4c739dbc1525-0',
|
id="run-168dceca-3b8b-4283-94e3-4c739dbc1525-0",
|
||||||
usage_metadata={'input_tokens': 32, 'output_tokens': 9, 'total_tokens': 41})
|
usage_metadata={
|
||||||
|
"input_tokens": 32,
|
||||||
|
"output_tokens": 9,
|
||||||
|
"total_tokens": 41,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
Stream:
|
Stream:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -136,14 +145,23 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override]
|
|||||||
AIMessage(
|
AIMessage(
|
||||||
content="J'adore la programmation.",
|
content="J'adore la programmation.",
|
||||||
response_metadata={
|
response_metadata={
|
||||||
'token_usage': {'completion_tokens': 9, 'prompt_tokens': 32, 'total_tokens': 41},
|
"token_usage": {
|
||||||
'model_name': 'grok-4',
|
"completion_tokens": 9,
|
||||||
'system_fingerprint': None,
|
"prompt_tokens": 32,
|
||||||
'finish_reason': 'stop',
|
"total_tokens": 41,
|
||||||
'logprobs': None
|
},
|
||||||
|
"model_name": "grok-4",
|
||||||
|
"system_fingerprint": None,
|
||||||
|
"finish_reason": "stop",
|
||||||
|
"logprobs": None,
|
||||||
},
|
},
|
||||||
id='run-09371a11-7f72-4c53-8e7c-9de5c238b34c-0',
|
id="run-09371a11-7f72-4c53-8e7c-9de5c238b34c-0",
|
||||||
usage_metadata={'input_tokens': 32, 'output_tokens': 9, 'total_tokens': 41})
|
usage_metadata={
|
||||||
|
"input_tokens": 32,
|
||||||
|
"output_tokens": 9,
|
||||||
|
"total_tokens": 41,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
Reasoning:
|
Reasoning:
|
||||||
`Certain xAI models <https://docs.x.ai/docs/models#model-pricing>`__ support reasoning,
|
`Certain xAI models <https://docs.x.ai/docs/models#model-pricing>`__ support reasoning,
|
||||||
@@ -179,41 +197,38 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override]
|
|||||||
|
|
||||||
llm = ChatXAI(model="grok-4")
|
llm = ChatXAI(model="grok-4")
|
||||||
|
|
||||||
|
|
||||||
class GetWeather(BaseModel):
|
class GetWeather(BaseModel):
|
||||||
'''Get the current weather in a given location'''
|
'''Get the current weather in a given location'''
|
||||||
|
|
||||||
location: str = Field(
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
..., description="The city and state, e.g. San Francisco, CA"
|
|
||||||
)
|
|
||||||
|
|
||||||
class GetPopulation(BaseModel):
|
class GetPopulation(BaseModel):
|
||||||
'''Get the current population in a given location'''
|
'''Get the current population in a given location'''
|
||||||
|
|
||||||
location: str = Field(
|
location: str = Field(..., description="The city and state, e.g. San Francisco, CA")
|
||||||
..., description="The city and state, e.g. San Francisco, CA"
|
|
||||||
)
|
|
||||||
|
|
||||||
llm_with_tools = llm.bind_tools([GetWeather, GetPopulation])
|
llm_with_tools = llm.bind_tools([GetWeather, GetPopulation])
|
||||||
ai_msg = llm_with_tools.invoke(
|
ai_msg = llm_with_tools.invoke("Which city is bigger: LA or NY?")
|
||||||
"Which city is bigger: LA or NY?"
|
|
||||||
)
|
|
||||||
ai_msg.tool_calls
|
ai_msg.tool_calls
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
'name': 'GetPopulation',
|
"name": "GetPopulation",
|
||||||
'args': {'location': 'NY'},
|
"args": {"location": "NY"},
|
||||||
'id': 'call_m5tstyn2004pre9bfuxvom8x',
|
"id": "call_m5tstyn2004pre9bfuxvom8x",
|
||||||
'type': 'tool_call'
|
"type": "tool_call",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'GetPopulation',
|
"name": "GetPopulation",
|
||||||
'args': {'location': 'LA'},
|
"args": {"location": "LA"},
|
||||||
'id': 'call_0vjgq455gq1av5sp9eb1pw6a',
|
"id": "call_0vjgq455gq1av5sp9eb1pw6a",
|
||||||
'type': 'tool_call'
|
"type": "tool_call",
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
@@ -267,10 +282,14 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override]
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
[{'name': 'GetWeather',
|
[
|
||||||
'args': {'location': 'Los Angeles, CA'},
|
{
|
||||||
'id': 'call_81668711',
|
"name": "GetWeather",
|
||||||
'type': 'tool_call'}]
|
"args": {"location": "Los Angeles, CA"},
|
||||||
|
"id": "call_81668711",
|
||||||
|
"type": "tool_call",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
Parallel tool calling / parallel function calling:
|
Parallel tool calling / parallel function calling:
|
||||||
By default, parallel tool / function calling is enabled, so you can process
|
By default, parallel tool / function calling is enabled, so you can process
|
||||||
@@ -299,9 +318,9 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override]
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
Joke(
|
Joke(
|
||||||
setup='Why was the cat sitting on the computer?',
|
setup="Why was the cat sitting on the computer?",
|
||||||
punchline='To keep an eye on the mouse!',
|
punchline="To keep an eye on the mouse!",
|
||||||
rating=7
|
rating=7,
|
||||||
)
|
)
|
||||||
|
|
||||||
Live Search:
|
Live Search:
|
||||||
@@ -320,7 +339,7 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override]
|
|||||||
"max_search_results": 3,
|
"max_search_results": 3,
|
||||||
"from_date": "2025-05-26",
|
"from_date": "2025-05-26",
|
||||||
"to_date": "2025-05-27",
|
"to_date": "2025-05-27",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
llm.invoke("Provide me a digest of world news in the last 24 hours.")
|
llm.invoke("Provide me a digest of world news in the last 24 hours.")
|
||||||
@@ -337,23 +356,23 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override]
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{'input_tokens': 37, 'output_tokens': 6, 'total_tokens': 43}
|
{"input_tokens": 37, "output_tokens": 6, "total_tokens": 43}
|
||||||
|
|
||||||
Logprobs:
|
Logprobs:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
logprobs_llm = llm.bind(logprobs=True)
|
logprobs_llm = llm.bind(logprobs=True)
|
||||||
messages=[("human","Say Hello World! Do not return anything else.")]
|
messages = [("human", "Say Hello World! Do not return anything else.")]
|
||||||
ai_msg = logprobs_llm.invoke(messages)
|
ai_msg = logprobs_llm.invoke(messages)
|
||||||
ai_msg.response_metadata["logprobs"]
|
ai_msg.response_metadata["logprobs"]
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{
|
{
|
||||||
'content': None,
|
"content": None,
|
||||||
'token_ids': [22557, 3304, 28808, 2],
|
"token_ids": [22557, 3304, 28808, 2],
|
||||||
'tokens': [' Hello', ' World', '!', '</s>'],
|
"tokens": [" Hello", " World", "!", "</s>"],
|
||||||
'token_logprobs': [-4.7683716e-06, -5.9604645e-07, 0, -0.057373047]
|
"token_logprobs": [-4.7683716e-06, -5.9604645e-07, 0, -0.057373047],
|
||||||
}
|
}
|
||||||
|
|
||||||
Response metadata
|
Response metadata
|
||||||
@@ -365,15 +384,15 @@ class ChatXAI(BaseChatOpenAI): # type: ignore[override]
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
{
|
{
|
||||||
'token_usage': {
|
"token_usage": {
|
||||||
'completion_tokens': 4,
|
"completion_tokens": 4,
|
||||||
'prompt_tokens': 19,
|
"prompt_tokens": 19,
|
||||||
'total_tokens': 23
|
"total_tokens": 23,
|
||||||
},
|
},
|
||||||
'model_name': 'grok-4',
|
"model_name": "grok-4",
|
||||||
'system_fingerprint': None,
|
"system_fingerprint": None,
|
||||||
'finish_reason': 'stop',
|
"finish_reason": "stop",
|
||||||
'logprobs': None
|
"logprobs": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ disallow_untyped_defs = "True"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
|
||||||
|
[tool.ruff.format]
|
||||||
|
docstring-code-format = true
|
||||||
|
docstring-code-line-length = 100
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
"A", # flake8-builtins
|
"A", # flake8-builtins
|
||||||
|
|||||||
Reference in New Issue
Block a user