Skip to content

Update internal_instructor.py MISSING API_KEY issue #2786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

amitgeed
Copy link

@amitgeed amitgeed commented May 8, 2025

In case when we do not add API KEY in env and pass it manually from LLM object, it fails to convert the output data to pydantic mode.

Error:

Failed to convert text into a Pydantic model due to error: litellm.AuthenticationError: Missing Anthropic API Key - A call is being made to anthropic but no key is set either in the environment variables or via params. Please set `ANTHROPIC_API_KEY` in your environment vars

In case when we do not add API KEY in env and pass it manually from LLM object, it fails to convert the output data to pydantic mode.

Error:
```
Failed to convert text into a Pydantic model due to error: litellm.AuthenticationError: Missing Anthropic API Key - A call is being made to anthropic but no key is set either in the environment variables or via params. Please set `ANTHROPIC_API_KEY` in your environment vars
```
@joaomdmoura
Copy link
Collaborator

Disclaimer: This review was made by a crew of AI Agents.

Code Review Comment for PR #2786

Overview

The pull request modifies internal_instructor.py to resolve an authentication issue related to API key handling when using the LLM object. This is an important fix as it allows users to authenticate more flexibly without being limited to environment variables.

Code Analysis

1. API Key Handling

  • The modification successfully integrates the api_key parameter in the API call, addressing the failure to pass the API key when using the LLM object.

    model = self._client.chat.completions.create(
        model=self.llm.model,
        response_model=self.model,
        messages=messages,
        api_key=self.llm.api_key
    )

Suggested Improvements

a. Error Handling

  • Recommendation: Introduce explicit error handling in to_pydantic(), ensuring clear feedback when no API key is available.

    def to_pydantic(self):
        if not self.llm.api_key and not os.getenv("ANTHROPIC_API_KEY"):
            raise ValueError("API key must be provided either through LLM object or ANTHROPIC_API_KEY environment variable")
        ...

b. API Key Validation

  • Recommendation: Add an _validate_api_key() method to centralize API key validation and improve code readability.

    def _validate_api_key(self):
        env_key = os.getenv("ANTHROPIC_API_KEY")
        if hasattr(self.llm, 'api_key') and self.llm.api_key:
            return self.llm.api_key
        elif env_key:
            return env_key
        raise ValueError("No API key found in LLM object or environment variables")

c. Documentation

  • Recommendation: Enhance docstring documentation for the to_pydantic() method to facilitate better understanding and maintainability.

    def to_pydantic(self):
        """
        Convert the instruction to a Pydantic model using the LLM.
    
        Returns:
            Pydantic model: The response model from the LLM.
            
        Raises:
            ValueError: If no API key is provided or is invalid.
            RuntimeError: If chat completion creation fails.
        """

Security Considerations

  • Ensure the handling of sensitive API keys adheres to security best practices by:
    • Implementing API key encryption.
    • Adding logging with appropriate data masking.
    • Considering rate limiting mechanisms to avoid API abuse.

Testing Recommendations

  • Implement unit tests for:
    • API key validation scenarios.
    • Error handling conditions, particularly with missing API keys.
    • Various authentication methods including environment and direct API key passing.

Code Quality Metrics

  • ✅ Functionality: Successfully fixes the identified issue.
  • ⚠️ Error Handling: Requires enhancement.
  • ⚠️ Documentation: Needs improvement.
  • ⚠️ Testing: Additional test coverage required.

Conclusion

The pull request effectively resolves the API key handling issue. However, adopting the suggested improvements will enhance the code's robustness and maintainability. The changes are approved with recommendations for implementation in future iterations.

This review emphasizes the importance of proactive error management and proper documentation, which are essential for maintaining code quality in collaborative environments.

- added validation error logic
@lucasgomide lucasgomide self-requested a review May 8, 2025 11:27
ValueError: If no API key is provided or is invalid.
RuntimeError: If chat completion creation fails.
"""
if not self.llm.api_key and not os.getenv("ANTHROPIC_API_KEY"):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think checking the ANTROPIC_API_KEY can be changed, to check os.getenv('OPENAI_API_KEY')
default crewai use openai model gpt-4

RuntimeError: If chat completion creation fails.
"""
if not self.llm.api_key and not os.getenv("ANTHROPIC_API_KEY"):
raise ValueError("API key must be provided either through LLM object or ANTHROPIC_API_KEY environment variable")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again the ANTHROPIC_API_KEY error can be changed, as the user can use any llm provider.

I think that we can get the api_key from the LLM object, but what if base_url is also set, does instructor accepts that arguement?
a

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are correct this should not be thrown from here, as the key will be validated internally by LiteLLM for all type of providers

Comment on lines +45 to +47
Raises:
ValueError: If no API key is provided or is invalid.
RuntimeError: If chat completion creation fails.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not raising it anymore, right?

@lucasgomide
Copy link
Contributor

@amitgeed That's makes sens! Would you mind to share the code to reproduce this issues?

@amitgeed
Copy link
Author

@lucasgomide
To reproduce the issue

  1. Remove .env file
  2. Create agent and use configure LLM and provide API_KEY from there
    LLM(model="your_model",max_completion_tokens=4200, api_key=your_api_key)
  3. Use pydantic model as output_pydantic in your Task
Task(
            name="",
            description="",
            expected_output="",
            agent=agent,
            output_pydantic=PydanticModel,
        )
  1. You might not get this output format issue (incomplete data/json), to manually reproduce that use this to remove the last bracket from JSON output
    File path: venv/lib/python3.12/site-packages/crewai/utilities/converter.py
def convert_to_model(
    result: str,
    output_pydantic: Optional[Type[BaseModel]],
    output_json: Optional[Type[BaseModel]],
    agent: Any,
    converter_cls: Optional[Type[Converter]] = None,
) -> Union[dict, BaseModel, str]:
    
    #remove last char from restult
    result = result[:-1]
    model = output_pydantic or output_json
    if model is None:
        return result
    try:
        escaped_result = json.dumps(json.loads(result, strict=False))
        return validate_model(escaped_result, model, bool(output_json))
    except json.JSONDecodeError:
        return handle_partial_json(
            result, model, bool(output_json), agent, converter_cls
        )

    except ValidationError:
        return handle_partial_json(
            result, model, bool(output_json), agent, converter_cls
        )

    except Exception as e:
        Printer().print(
            content=f"Unexpected error during model conversion: {type(e).__name__}: {e}. Returning original result.",
            color="red",
        )
        return result

@lucasgomide
Copy link
Contributor

@amitgeed Should I try with another model?

from crewai import LLM, Agent, Crew, Task
from pydantic import BaseModel

llm = LLM(
    model="openai/gpt-4o-mini",
    max_completion_tokens=4200,
    api_key="sk-proj-***",
)


class PydanticModel(BaseModel):
    name: str
    age: int


agent = Agent(
    role="",
    goal="",
    backstory="",
    llm=llm,
)

task = Task(
    name="",
    description="",
    expected_output="",
    agent=agent,
    output_pydantic=PydanticModel,
)

crew = Crew(
    agents=[agent],
    tasks=[task],
)

result = crew.kickoff()
print(result)
Screenshot 2025-05-12 at 2 10 26 PM

@amitgeed
Copy link
Author

@lucasgomide Have you tried step 4 with Anthropic?
As if there is an incomplete response from llm in large JSON, default json parsing does not work.
And it goes directly to the LLM to fix that JSON.

messages = [{"role": "user", "content": self.content}]
model = self._client.chat.completions.create(
model=self.llm.model, response_model=self.model, messages=messages
model=self.llm.model, response_model=self.model, messages=messages, api_key=self.llm.api_key
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also send the api.base here as well.

Issue #2753
what do you think @lucasgomide?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants