mirror of
https://github.com/hwchase17/langchain.git
synced 2025-06-21 22:29:51 +00:00
community[patch]: Update YandexGPT API (#14773)
Update LLMand Chat model to use new api version --------- Co-authored-by: Dmitry Tyumentsev <dmitry.tyumentsev@raftds.com>
This commit is contained in:
parent
eca89f87d8
commit
dcead816df
@ -42,13 +42,20 @@
|
||||
"Next, you have two authentication options:\n",
|
||||
"- [IAM token](https://cloud.yandex.com/en/docs/iam/operations/iam-token/create-for-sa).\n",
|
||||
" You can specify the token in a constructor parameter `iam_token` or in an environment variable `YC_IAM_TOKEN`.\n",
|
||||
"\n",
|
||||
"- [API key](https://cloud.yandex.com/en/docs/iam/operations/api-key/create)\n",
|
||||
" You can specify the key in a constructor parameter `api_key` or in an environment variable `YC_API_KEY`."
|
||||
" You can specify the key in a constructor parameter `api_key` or in an environment variable `YC_API_KEY`.\n",
|
||||
"\n",
|
||||
"In the `model_uri` parameter, specify the model used, see [the documentation](https://cloud.yandex.com/en/docs/yandexgpt/concepts/models#yandexgpt-generation) for more details.\n",
|
||||
"\n",
|
||||
"To specify the model you can use `model_uri` parameter, see [the documentation](https://cloud.yandex.com/en/docs/yandexgpt/concepts/models#yandexgpt-generation) for more details.\n",
|
||||
"\n",
|
||||
"By default, the latest version of `yandexgpt-lite` is used from the folder specified in the parameter `folder_id` or `YC_FOLDER_ID` environment variable."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 1,
|
||||
"id": "eba2d63b-f871-4f61-b55f-f6092bdc297a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@ -59,7 +66,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 2,
|
||||
"id": "75905d9a-dfae-43aa-95b9-a160280e43f7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@ -69,17 +76,17 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"execution_count": 3,
|
||||
"id": "40844fe7-7fe5-4679-b6c9-1b3238807bdc",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"AIMessage(content=\"Je t'aime programmer.\")"
|
||||
"AIMessage(content='Je adore le programmement.')"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -113,7 +120,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
"version": "3.10.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
@ -29,13 +29,20 @@
|
||||
"Next, you have two authentication options:\n",
|
||||
"- [IAM token](https://cloud.yandex.com/en/docs/iam/operations/iam-token/create-for-sa).\n",
|
||||
" You can specify the token in a constructor parameter `iam_token` or in an environment variable `YC_IAM_TOKEN`.\n",
|
||||
"\n",
|
||||
"- [API key](https://cloud.yandex.com/en/docs/iam/operations/api-key/create)\n",
|
||||
" You can specify the key in a constructor parameter `api_key` or in an environment variable `YC_API_KEY`."
|
||||
" You can specify the key in a constructor parameter `api_key` or in an environment variable `YC_API_KEY`.\n",
|
||||
"\n",
|
||||
"In the `model_uri` parameter, specify the model used, see [the documentation](https://cloud.yandex.com/en/docs/yandexgpt/concepts/models#yandexgpt-generation) for more details.\n",
|
||||
"\n",
|
||||
"To specify the model you can use `model_uri` parameter, see [the documentation](https://cloud.yandex.com/en/docs/yandexgpt/concepts/models#yandexgpt-generation) for more details.\n",
|
||||
"\n",
|
||||
"By default, the latest version of `yandexgpt-lite` is used from the folder specified in the parameter `folder_id` or `YC_FOLDER_ID` environment variable."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 246,
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -46,7 +53,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 247,
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -56,7 +63,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 248,
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -65,7 +72,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 249,
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@ -74,16 +81,16 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 250,
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'Moscow'"
|
||||
"'The capital of Russia is Moscow.'"
|
||||
]
|
||||
},
|
||||
"execution_count": 250,
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -111,7 +118,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
"version": "3.10.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""Wrapper around YandexGPT chat models."""
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional, Tuple, cast
|
||||
from typing import Any, Dict, List, Optional, cast
|
||||
|
||||
from langchain_core.callbacks import (
|
||||
AsyncCallbackManagerForLLMRun,
|
||||
@ -25,14 +25,13 @@ def _parse_message(role: str, text: str) -> Dict:
|
||||
return {"role": role, "text": text}
|
||||
|
||||
|
||||
def _parse_chat_history(history: List[BaseMessage]) -> Tuple[List[Dict[str, str]], str]:
|
||||
def _parse_chat_history(history: List[BaseMessage]) -> List[Dict[str, str]]:
|
||||
"""Parse a sequence of messages into history.
|
||||
|
||||
Returns:
|
||||
A tuple of a list of parsed messages and an instruction message for the model.
|
||||
A list of parsed messages.
|
||||
"""
|
||||
chat_history = []
|
||||
instruction = ""
|
||||
for message in history:
|
||||
content = cast(str, message.content)
|
||||
if isinstance(message, HumanMessage):
|
||||
@ -40,8 +39,8 @@ def _parse_chat_history(history: List[BaseMessage]) -> Tuple[List[Dict[str, str]
|
||||
if isinstance(message, AIMessage):
|
||||
chat_history.append(_parse_message("assistant", content))
|
||||
if isinstance(message, SystemMessage):
|
||||
instruction = content
|
||||
return chat_history, instruction
|
||||
chat_history.append(_parse_message("system", content))
|
||||
return chat_history
|
||||
|
||||
|
||||
class ChatYandexGPT(_BaseYandexGPT, BaseChatModel):
|
||||
@ -84,9 +83,14 @@ class ChatYandexGPT(_BaseYandexGPT, BaseChatModel):
|
||||
try:
|
||||
import grpc
|
||||
from google.protobuf.wrappers_pb2 import DoubleValue, Int64Value
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_pb2 import GenerationOptions, Message
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_service_pb2 import ChatRequest
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_service_pb2_grpc import (
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_pb2 import (
|
||||
CompletionOptions,
|
||||
Message,
|
||||
)
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_service_pb2 import ( # noqa: E501
|
||||
CompletionRequest,
|
||||
)
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_service_pb2_grpc import ( # noqa: E501
|
||||
TextGenerationServiceStub,
|
||||
)
|
||||
except ImportError as e:
|
||||
@ -97,25 +101,20 @@ class ChatYandexGPT(_BaseYandexGPT, BaseChatModel):
|
||||
raise ValueError(
|
||||
"You should provide at least one message to start the chat!"
|
||||
)
|
||||
message_history, instruction = _parse_chat_history(messages)
|
||||
message_history = _parse_chat_history(messages)
|
||||
channel_credentials = grpc.ssl_channel_credentials()
|
||||
channel = grpc.secure_channel(self.url, channel_credentials)
|
||||
request = ChatRequest(
|
||||
model=self.model_name,
|
||||
generation_options=GenerationOptions(
|
||||
request = CompletionRequest(
|
||||
model_uri=self.model_uri,
|
||||
completion_options=CompletionOptions(
|
||||
temperature=DoubleValue(value=self.temperature),
|
||||
max_tokens=Int64Value(value=self.max_tokens),
|
||||
),
|
||||
instruction_text=instruction,
|
||||
messages=[Message(**message) for message in message_history],
|
||||
)
|
||||
stub = TextGenerationServiceStub(channel)
|
||||
if self.iam_token:
|
||||
metadata = (("authorization", f"Bearer {self.iam_token}"),)
|
||||
else:
|
||||
metadata = (("authorization", f"Api-Key {self.api_key}"),)
|
||||
res = stub.Chat(request, metadata=metadata)
|
||||
text = list(res)[0].message.text
|
||||
res = stub.Completion(request, metadata=self._grpc_metadata)
|
||||
text = list(res)[0].alternatives[0].message.text
|
||||
text = text if stop is None else enforce_stop_tokens(text, stop)
|
||||
message = AIMessage(content=text)
|
||||
return ChatResult(generations=[ChatGeneration(message=message)])
|
||||
@ -127,6 +126,75 @@ class ChatYandexGPT(_BaseYandexGPT, BaseChatModel):
|
||||
run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
|
||||
**kwargs: Any,
|
||||
) -> ChatResult:
|
||||
raise NotImplementedError(
|
||||
"""YandexGPT doesn't support async requests at the moment."""
|
||||
)
|
||||
"""Async method to generate next turn in the conversation.
|
||||
|
||||
Args:
|
||||
messages: The history of the conversation as a list of messages.
|
||||
stop: The list of stop words (optional).
|
||||
run_manager: The CallbackManager for LLM run, it's not used at the moment.
|
||||
|
||||
Returns:
|
||||
The ChatResult that contains outputs generated by the model.
|
||||
|
||||
Raises:
|
||||
ValueError: if the last message in the list is not from human.
|
||||
"""
|
||||
try:
|
||||
import asyncio
|
||||
|
||||
import grpc
|
||||
from google.protobuf.wrappers_pb2 import DoubleValue, Int64Value
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_pb2 import (
|
||||
CompletionOptions,
|
||||
Message,
|
||||
)
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_service_pb2 import ( # noqa: E501
|
||||
CompletionRequest,
|
||||
CompletionResponse,
|
||||
)
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_service_pb2_grpc import ( # noqa: E501
|
||||
TextGenerationAsyncServiceStub,
|
||||
)
|
||||
from yandex.cloud.operation.operation_service_pb2 import GetOperationRequest
|
||||
from yandex.cloud.operation.operation_service_pb2_grpc import (
|
||||
OperationServiceStub,
|
||||
)
|
||||
except ImportError as e:
|
||||
raise ImportError(
|
||||
"Please install YandexCloud SDK" " with `pip install yandexcloud`."
|
||||
) from e
|
||||
if not messages:
|
||||
raise ValueError(
|
||||
"You should provide at least one message to start the chat!"
|
||||
)
|
||||
message_history = _parse_chat_history(messages)
|
||||
operation_api_url = "operation.api.cloud.yandex.net:443"
|
||||
channel_credentials = grpc.ssl_channel_credentials()
|
||||
async with grpc.aio.secure_channel(self.url, channel_credentials) as channel:
|
||||
request = CompletionRequest(
|
||||
model_uri=self.model_uri,
|
||||
completion_options=CompletionOptions(
|
||||
temperature=DoubleValue(value=self.temperature),
|
||||
max_tokens=Int64Value(value=self.max_tokens),
|
||||
),
|
||||
messages=[Message(**message) for message in message_history],
|
||||
)
|
||||
stub = TextGenerationAsyncServiceStub(channel)
|
||||
operation = await stub.Completion(request, metadata=self._grpc_metadata)
|
||||
async with grpc.aio.secure_channel(
|
||||
operation_api_url, channel_credentials
|
||||
) as operation_channel:
|
||||
operation_stub = OperationServiceStub(operation_channel)
|
||||
while not operation.done:
|
||||
await asyncio.sleep(1)
|
||||
operation_request = GetOperationRequest(operation_id=operation.id)
|
||||
operation = await operation_stub.Get(
|
||||
operation_request, metadata=self._grpc_metadata
|
||||
)
|
||||
|
||||
instruct_response = CompletionResponse()
|
||||
operation.response.Unpack(instruct_response)
|
||||
text = instruct_response.alternatives[0].message.text
|
||||
if stop is not None:
|
||||
text = enforce_stop_tokens(text, stop)
|
||||
return text
|
||||
|
@ -14,13 +14,19 @@ from langchain_community.llms.utils import enforce_stop_tokens
|
||||
|
||||
class _BaseYandexGPT(Serializable):
|
||||
iam_token: str = ""
|
||||
"""Yandex Cloud IAM token for service account
|
||||
"""Yandex Cloud IAM token for service or user account
|
||||
with the `ai.languageModels.user` role"""
|
||||
api_key: str = ""
|
||||
"""Yandex Cloud Api Key for service account
|
||||
with the `ai.languageModels.user` role"""
|
||||
model_name: str = "general"
|
||||
folder_id: str = ""
|
||||
"""Yandex Cloud folder ID"""
|
||||
model_uri: str = ""
|
||||
"""Model uri to use."""
|
||||
model_name: str = "yandexgpt-lite"
|
||||
"""Model name to use."""
|
||||
model_version: str = "latest"
|
||||
"""Model version to use."""
|
||||
temperature: float = 0.6
|
||||
"""What sampling temperature to use.
|
||||
Should be a double number between 0 (inclusive) and 1 (inclusive)."""
|
||||
@ -45,8 +51,27 @@ class _BaseYandexGPT(Serializable):
|
||||
values["iam_token"] = iam_token
|
||||
api_key = get_from_dict_or_env(values, "api_key", "YC_API_KEY", "")
|
||||
values["api_key"] = api_key
|
||||
folder_id = get_from_dict_or_env(values, "folder_id", "YC_FOLDER_ID", "")
|
||||
values["folder_id"] = folder_id
|
||||
if api_key == "" and iam_token == "":
|
||||
raise ValueError("Either 'YC_API_KEY' or 'YC_IAM_TOKEN' must be provided.")
|
||||
|
||||
if values["iam_token"]:
|
||||
values["_grpc_metadata"] = [
|
||||
("authorization", f"Bearer {values['iam_token']}")
|
||||
]
|
||||
if values["folder_id"]:
|
||||
values["_grpc_metadata"].append(("x-folder-id", values["folder_id"]))
|
||||
else:
|
||||
values["_grpc_metadata"] = (
|
||||
("authorization", f"Api-Key {values['api_key']}"),
|
||||
)
|
||||
if values["model_uri"] == "" and values["folder_id"] == "":
|
||||
raise ValueError("Either 'model_uri' or 'folder_id' must be provided.")
|
||||
if not values["model_uri"]:
|
||||
values[
|
||||
"model_uri"
|
||||
] = f"gpt://{values['folder_id']}/{values['model_name']}/{values['model_version']}"
|
||||
return values
|
||||
|
||||
|
||||
@ -62,18 +87,23 @@ class YandexGPT(_BaseYandexGPT, LLM):
|
||||
- You can specify the key in a constructor parameter `api_key`
|
||||
or in an environment variable `YC_API_KEY`.
|
||||
|
||||
To use the default model specify the folder ID in a parameter `folder_id`
|
||||
or in an environment variable `YC_FOLDER_ID`.
|
||||
|
||||
Or specify the model URI in a constructor parameter `model_uri`
|
||||
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_community.llms import YandexGPT
|
||||
yandex_gpt = YandexGPT(iam_token="t1.9eu...")
|
||||
yandex_gpt = YandexGPT(iam_token="t1.9eu...", folder_id="b1g...")
|
||||
"""
|
||||
|
||||
@property
|
||||
def _identifying_params(self) -> Mapping[str, Any]:
|
||||
"""Get the identifying parameters."""
|
||||
return {
|
||||
"model_name": self.model_name,
|
||||
"model_uri": self.model_uri,
|
||||
"temperature": self.temperature,
|
||||
"max_tokens": self.max_tokens,
|
||||
"stop": self.stop,
|
||||
@ -103,9 +133,14 @@ class YandexGPT(_BaseYandexGPT, LLM):
|
||||
try:
|
||||
import grpc
|
||||
from google.protobuf.wrappers_pb2 import DoubleValue, Int64Value
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_pb2 import GenerationOptions
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_service_pb2 import InstructRequest
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_service_pb2_grpc import (
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_pb2 import (
|
||||
CompletionOptions,
|
||||
Message,
|
||||
)
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_service_pb2 import ( # noqa: E501
|
||||
CompletionRequest,
|
||||
)
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_service_pb2_grpc import ( # noqa: E501
|
||||
TextGenerationServiceStub,
|
||||
)
|
||||
except ImportError as e:
|
||||
@ -114,21 +149,21 @@ class YandexGPT(_BaseYandexGPT, LLM):
|
||||
) from e
|
||||
channel_credentials = grpc.ssl_channel_credentials()
|
||||
channel = grpc.secure_channel(self.url, channel_credentials)
|
||||
request = InstructRequest(
|
||||
model=self.model_name,
|
||||
request_text=prompt,
|
||||
generation_options=GenerationOptions(
|
||||
request = CompletionRequest(
|
||||
model_uri=self.model_uri,
|
||||
completion_options=CompletionOptions(
|
||||
temperature=DoubleValue(value=self.temperature),
|
||||
max_tokens=Int64Value(value=self.max_tokens),
|
||||
),
|
||||
messages=[Message(role="user", text=prompt)],
|
||||
)
|
||||
stub = TextGenerationServiceStub(channel)
|
||||
if self.iam_token:
|
||||
metadata = (("authorization", f"Bearer {self.iam_token}"),)
|
||||
else:
|
||||
metadata = (("authorization", f"Api-Key {self.api_key}"),)
|
||||
res = stub.Instruct(request, metadata=metadata)
|
||||
text = list(res)[0].alternatives[0].text
|
||||
res = stub.Completion(request, metadata=metadata)
|
||||
text = list(res)[0].alternatives[0].message.text
|
||||
if stop is not None:
|
||||
text = enforce_stop_tokens(text, stop)
|
||||
return text
|
||||
@ -154,12 +189,15 @@ class YandexGPT(_BaseYandexGPT, LLM):
|
||||
|
||||
import grpc
|
||||
from google.protobuf.wrappers_pb2 import DoubleValue, Int64Value
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_pb2 import GenerationOptions
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_service_pb2 import (
|
||||
InstructRequest,
|
||||
InstructResponse,
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_pb2 import (
|
||||
CompletionOptions,
|
||||
Message,
|
||||
)
|
||||
from yandex.cloud.ai.llm.v1alpha.llm_service_pb2_grpc import (
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_service_pb2 import ( # noqa: E501
|
||||
CompletionRequest,
|
||||
CompletionResponse,
|
||||
)
|
||||
from yandex.cloud.ai.foundation_models.v1.foundation_models_service_pb2_grpc import ( # noqa: E501
|
||||
TextGenerationAsyncServiceStub,
|
||||
)
|
||||
from yandex.cloud.operation.operation_service_pb2 import GetOperationRequest
|
||||
@ -173,20 +211,16 @@ class YandexGPT(_BaseYandexGPT, LLM):
|
||||
operation_api_url = "operation.api.cloud.yandex.net:443"
|
||||
channel_credentials = grpc.ssl_channel_credentials()
|
||||
async with grpc.aio.secure_channel(self.url, channel_credentials) as channel:
|
||||
request = InstructRequest(
|
||||
model=self.model_name,
|
||||
request_text=prompt,
|
||||
generation_options=GenerationOptions(
|
||||
request = CompletionRequest(
|
||||
model_uri=self.model_uri,
|
||||
completion_options=CompletionOptions(
|
||||
temperature=DoubleValue(value=self.temperature),
|
||||
max_tokens=Int64Value(value=self.max_tokens),
|
||||
),
|
||||
messages=[Message(role="user", text=prompt)],
|
||||
)
|
||||
stub = TextGenerationAsyncServiceStub(channel)
|
||||
if self.iam_token:
|
||||
metadata = (("authorization", f"Bearer {self.iam_token}"),)
|
||||
else:
|
||||
metadata = (("authorization", f"Api-Key {self.api_key}"),)
|
||||
operation = await stub.Instruct(request, metadata=metadata)
|
||||
operation = await stub.Completion(request, metadata=self._grpc_metadata)
|
||||
async with grpc.aio.secure_channel(
|
||||
operation_api_url, channel_credentials
|
||||
) as operation_channel:
|
||||
@ -195,12 +229,12 @@ class YandexGPT(_BaseYandexGPT, LLM):
|
||||
await asyncio.sleep(1)
|
||||
operation_request = GetOperationRequest(operation_id=operation.id)
|
||||
operation = await operation_stub.Get(
|
||||
operation_request, metadata=metadata
|
||||
operation_request, metadata=self._grpc_metadata
|
||||
)
|
||||
|
||||
instruct_response = InstructResponse()
|
||||
instruct_response = CompletionResponse()
|
||||
operation.response.Unpack(instruct_response)
|
||||
text = instruct_response.alternatives[0].text
|
||||
text = instruct_response.alternatives[0].message.text
|
||||
if stop is not None:
|
||||
text = enforce_stop_tokens(text, stop)
|
||||
return text
|
||||
|
Loading…
Reference in New Issue
Block a user