langchain-ai / langchain-google

MIT License
104 stars 121 forks source link

ChatVertexAI does not use safety_settings. #252

Closed cw-tjdcks106 closed 4 months ago

cw-tjdcks106 commented 4 months ago

Based on langchain-google-vertexai 1.0.4, ChatVertexAI(safety_settings=blah blah~), safety_settings doesn't work properly.

I solved the problem by adding safety_settings as below. I would appreciate your confirmation. Thank you.

class CustomChatVertexAI(ChatVertexAI):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def invoke(self, input: LanguageModelInput, *args, **kwargs: Any) -> BaseMessage:
        output = super().invoke(
            input, *args, **kwargs, safety_settings=self.safety_settings
        )
        return output
stefanadelbert commented 4 months ago

I'm also having problems with safety settings very recently. I'm creating the model like this,

model = ChatVertexAI(
    model_name="gemini-1.5-pro-preview-0409",
    location="australia-southeast1",
    temperature=0,
    top_p=1,
    top_k=32,
    max_output_tokens=2048,
    safety_settings={
        HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH
    }
)

But I'm getting responses blocked even though the safety probability is only MEDIUM,

{
  "generations": [
    [
      {
        "text": "",
        "generation_info": {
          "is_blocked": true,
          "safety_ratings": [
            {
              "category": "HARM_CATEGORY_HATE_SPEECH",
              "probability_label": "NEGLIGIBLE",
              "blocked": false
            },
            {
              "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
              "probability_label": "MEDIUM",
              "blocked": true
            },
            {
              "category": "HARM_CATEGORY_HARASSMENT",
              "probability_label": "NEGLIGIBLE",
              "blocked": false
            },
            {
              "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
              "probability_label": "NEGLIGIBLE",
              "blocked": false
            }
          ],
          "usage_metadata": {
            "prompt_token_count": 449,
            "total_token_count": 449,
            "candidates_token_count": 0
          }
        },
    ...
tjdcks106 commented 4 months ago

I'm also having problems with safety settings very recently. I'm creating the model like this,

model = ChatVertexAI(
    model_name="gemini-1.5-pro-preview-0409",
    location="australia-southeast1",
    temperature=0,
    top_p=1,
    top_k=32,
    max_output_tokens=2048,
    safety_settings={
        HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH
    }
)

But I'm getting responses blocked even though the safety probability is only MEDIUM,

{
  "generations": [
    [
      {
        "text": "",
        "generation_info": {
          "is_blocked": true,
          "safety_ratings": [
            {
              "category": "HARM_CATEGORY_HATE_SPEECH",
              "probability_label": "NEGLIGIBLE",
              "blocked": false
            },
            {
              "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
              "probability_label": "MEDIUM",
              "blocked": true
            },
            {
              "category": "HARM_CATEGORY_HARASSMENT",
              "probability_label": "NEGLIGIBLE",
              "blocked": false
            },
            {
              "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
              "probability_label": "NEGLIGIBLE",
              "blocked": false
            }
          ],
          "usage_metadata": {
            "prompt_token_count": 449,
            "total_token_count": 449,
            "candidates_token_count": 0
          }
        },
    ...

That’s right. I experienced the exact same situation, so I opened this issue. Try the method I suggested above.

stefanadelbert commented 4 months ago

I've debugged the code and I can see that safety_settings is None at langchain_google_vertexai/chat_models.py(680)_safety_settings_gemini(). Below is the call stack for langchain_google_vertexai at version 1.0.4. This call stack results from calling model.invoke like this,

model = ChatVertexAI(
    model_name="gemini-1.5-pro-preview-0409",
    location="australia-southeast1",
    temperature=0,
    top_p=1,
    top_k=32,
    max_output_tokens=2048,
    safety_settings={
        HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH
    }
)
model.invoke("Why is the sky blue?")
  .venv/lib/python3.11/site-packages/langchain_google_vertexai/chat_models.py(647)_generate()
-> return self._generate_gemini(
  .venv/lib/python3.11/site-packages/langchain_google_vertexai/chat_models.py(734)_generate_gemini()
-> request = self._prepare_request_gemini(messages=messages, stop=stop, **kwargs)
  .venv/lib/python3.11/site-packages/langchain_google_vertexai/chat_models.py(720)_prepare_request_gemini()
-> safety_settings=self._safety_settings_gemini(safety_settings),
> .venv/lib/python3.11/site-packages/langchain_google_vertexai/chat_models.py(680)_safety_settings_gemini()
-> if safety_settings is None:

(Pdb) l
675         ) -> Optional[Sequence[SafetySetting]]:
676             """Prepares SafetySetting part of the request.
677     
678             https://cloud.google.com/vertex-ai/docs/reference/rpc/google.cloud.aiplatform.v1beta1#safetysetting
679             """
680  ->         if safety_settings is None:
681                 return None
682             if isinstance(safety_settings, list):
683                 return safety_settings
684             if isinstance(safety_settings, dict):
685                 formatted_safety_settings = []
(Pdb) pp safety_settings
None

It feels to me like langchain_google_vertexai/chat_models.py(734)_generate_gemini() should pass in self.safety_settings. to the call to _prepare_request_gemini. It's not clear how else safety_settings could be present.

stefanadelbert commented 4 months ago

@tjdcks106 @cw-tjdcks106 Your trick above works because safety_settings gets absorbed into kwargs and hence passed down the stack. So, another way to achieve this behaviour without having to subclass ChatVertexAI would be to bind safety settings to the model. Something like this,

safety_settings={...}
model = ChatVertexAI(..., safety_settings=safety_settings)
model = model.bind(safety_settings=safety_settings)
model.invoke("Why is the sky blue?")

If I do this and then debug, this is what I get in the debugger, i.e. safety_settings are being properly applied when the API request is being created,

.venv/lib/python3.11/site-packages/langchain_google_vertexai/chat_models.py(698)_safety_settings_gemini()
-> return formatted_safety_settings
(Pdb) l
693                         SafetySetting(
694                             category=HarmCategory(category),
695                             threshold=SafetySetting.HarmBlockThreshold(threshold),
696                         )
697                     )
698  ->             return formatted_safety_settings
699             raise ValueError("safety_settings should be either")
700     
701         def _prepare_request_gemini(
702             self,
703             messages: List[BaseMessage],
(Pdb) pp formatted_safety_settings
[category: HARM_CATEGORY_DANGEROUS_CONTENT
threshold: BLOCK_ONLY_HIGH
,
 category: HARM_CATEGORY_HATE_SPEECH
threshold: BLOCK_ONLY_HIGH
,
 category: HARM_CATEGORY_HARASSMENT
threshold: BLOCK_ONLY_HIGH
,
 category: HARM_CATEGORY_SEXUALLY_EXPLICIT
threshold: BLOCK_ONLY_HIGH
]

I can't imagine that this is how it's supposed to be used, but it feels cleaner to me that overriding the invoke method.

lkuligin commented 4 months ago

you don't need the bind call actually, this should work after the recent fix (it's not released yet though, so please install from main):

safety_settings={...}
model = ChatVertexAI(..., safety_settings=safety_settings)
model.invoke("Why is the sky blue?")
stefanadelbert commented 4 months ago

That change looks totally sensible to me. I'm about to try it out. I'm using this functionality in prod. Any idea when the next release will go out (so that I can install from an official release)?

lkuligin commented 4 months ago

We target next week.

zanzaj87 commented 3 months ago

Hello,

I am getting the same issue with VertexAI: I'm getting responses blocked even though the safety setting probability is set exclude HIGH only and the string has a MEDIUM probability for the category HARM_CATEGORY_SEXUALLY_EXPLICIT:

` from langchain.llms import VertexAI from langchain import PromptTemplate, LLMChain from langchain_google_vertexai import HarmBlockThreshold, HarmCategory

safety_settings = { HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH, }

llm = VertexAI(model_name="gemini-pro", temperature=0.50, top_p=0.8, top_k=40, safety_settings=safety_settings )

map_prompt_v2 = PromptTemplate(template=language_prompt_v2, input_variables=["english_translation","target_language","context"])

llm_chain = LLMChain(prompt=map_prompt_v2, llm=llm)

llm_chain.run( { "context": "\n".join(matches), "target_language": target_language, "english_translation": qa_english_string }

{ "finish_reason": "SAFETY", "safety_ratings": [ { "category": "HARM_CATEGORY_HATE_SPEECH", "probability": "NEGLIGIBLE", "probability_score": 0.16995624, "severity": "HARM_SEVERITY_NEGLIGIBLE", "severity_score": 0.08151976 }, { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "probability": "NEGLIGIBLE", "probability_score": 0.20291664, "severity": "HARM_SEVERITY_LOW", "severity_score": 0.21141683 }, { "category": "HARM_CATEGORY_HARASSMENT", "probability": "NEGLIGIBLE", "probability_score": 0.16559312, "severity": "HARM_SEVERITY_NEGLIGIBLE", "severity_score": 0.080069266 }, { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "probability": "MEDIUM", "blocked": true, "probability_score": 0.713731, "severity": "HARM_SEVERITY_MEDIUM", "severity_score": 0.4572579 } ] } `

kulovecc commented 2 months ago

I have the same problem in 1.0.7, safety_settings are not working in ChatVertexAI, the same Prompt to set the safety level in AI Studio is working fine.