"create_structured_output_chain" creates awful schema, deteriorates performance and should be fixed or removed
Labels: name: area: embeddings, name: auto:bug, name: auto:improvement

### System Info

Langchain v0.0.235

### Who can help?

@hwchase17 @agola11 

### Information

- [X] The official example notebooks/scripts
- [ ] My own modified scripts

### Related Components

- [X] LLMs/Chat Models
- [ ] Embedding Models
- [ ] Prompts / Prompt Templates / Prompt Selectors
- [X] Output Parsers
- [ ] Document Loaders
- [ ] Vector Stores / Retrievers
- [ ] Memory
- [ ] Agents / Agent Executors
- [ ] Tools / Toolkits
- [ ] Chains
- [ ] Callbacks/Tracing
- [ ] Async

### Reproduction

Trying out the new [create_structured_output_chain](https://github.com/hwchase17/langchain/blame/9d7e57f5c01f9ac5c8caa439ff083de98f96fdde/langchain/chains/openai_functions/base.py#L267) introduced in #7270 with the setup like described in the [docs](https://python.langchain.com/docs/modules/chains/popular/openai_functions) I wondered about the bad performance. Then I looked at the function call....

Using a very simple example:

```python
class LanguageCode(BaseModel):
    """"A single language code in ISO 639-1 format"""
    language_code: str = Field(..., description="Language code (e.g. 'en', 'de', 'fr')")

class LanguageClassification(BaseModel):
    """Classify the languages of a user prompt."""
    
    language_codes: list[LanguageCode] = Field(default_factory=list, description="A list of all languages present in the whole text. Exclude code sections, loanwords and technical terms in the text when deciding on the language codes. You have to output at least one language code, even if you are not certain or the text is very short!")
    main_language_code: LanguageCode = Field(..., description="Main Language of the text.")

chat_prompt_language = ChatPromptTemplate.from_messages(
    [
        SystemMessagePromptTemplate.from_template("You are a world-class linguist and fluent in all major languages. Your job is to determine which languages are present in the user text and which one is the main language."),
        HumanMessagePromptTemplate.from_template("{text}"),
    ]
)

chain = create_structured_output_chain(LanguageClassification, llm, chat_prompt_language, verbose=True)
```

Looking at `chain.llm_kwargs['functions']`:
```python
[{'name': '_OutputFormatter',
  'description': 'Output formatter. Should always be used to format your response to the user.',
  'parameters': {'title': '_OutputFormatter',
   'description': 'Output formatter. Should always be used to format your response to the user.',
   'type': 'object',
   'properties': {'output': {'$ref': '#/definitions/LanguageClassification'}},
   'required': ['output'],
   'definitions': {'LanguageCode': {'title': 'LanguageCode',
     'description': '"A single language code in ISO 639-1 format',
     'type': 'object',
     'properties': {'language_code': {'title': 'Language Code',
       'description': "Language code (e.g. 'en', 'de', 'fr')",
       'type': 'string'}},
     'required': ['language_code']},
    'LanguageClassification': {'title': 'LanguageClassification',
     'description': 'Classify the languages of a user prompt.',
     'type': 'object',
     'properties': {'language_codes': {'title': 'Language Codes',
       'description': 'A list of all languages present in the whole text. Exclude code sections, loanwords and technical terms in the text when deciding on the language codes. You have to output at least one language code, even if you are not certain or the text is very short!',
       'type': 'array',
       'items': {'$ref': '#/definitions/LanguageCode'}},
      'main_language_code': {'title': 'Main Language Code',
       'description': 'Main Language of the text.',
       'allOf': [{'$ref': '#/definitions/LanguageCode'}]}},
     'required': ['main_language_code']}}}}]
```

What? I can barely parse this monstrosity, how should GPT3.5 do this?

It is very well known by now, that the function- and variable names as well as the structure and simplicity/unambiguousness (and even the order of arguments) is very important for the performance of function calls. 
This implementation wastes a lot of tokens and is detrimental for performance (especially for users who put their trust in langchain and don't benchmark results); and that for a key feature. 

Maybe there are features that some additional complexity but this should never introduce a significant performance/token tax for completely unrelated and important use cases?

### Expected behavior

Just as an example, using the exact same model/code with @jxnl s [OpenAISchema](https://github.com/jxnl/openai_function_call) and nothing else:

```python
llm_kwargs={"functions": [LanguageClassification.openai_schema], "function_call": {'name':"LanguageClassification"}}
chain = LLMChain(llm=llm, prompt=chat_prompt_language, verbose=True, llm_kwargs=llm_kwargs)
```

we get the following schema:
```python
{'name': 'LanguageClassification',
 'description': 'Classify the languages of a user prompt.',
 'parameters': {'type': 'object',
  'properties': {'language_codes': {'description': 'A list of all languages present in the whole text. Exclude code sections, loanwords and technical terms in the text when deciding on the language codes. You have to output at least one language code, even if you are not certain or the text is very short!',
    'type': 'array',
    'items': {'$ref': '#/definitions/LanguageCode'}},
   'main_language_code': {'description': 'Main Language of the text.',
    'allOf': [{'$ref': '#/definitions/LanguageCode'}]}},
  'required': ['language_codes', 'main_language_code'],
  'definitions': {'LanguageCode': {'description': '"A single language code in ISO 639-1 format',
    'type': 'object',
    'properties': {'language_code': {'description': "Language code (e.g. 'en', 'de', 'fr')",
      'type': 'string'}},
    'required': ['language_code']}}}}
```
Half the tokens and way easier to read/understand which leads to way better performance and robustness.

This can be parsed in a single line:
```python
res=chain.generate([{'text':"..."}])
LanguageClassification(**json.loads(res.generations[0][0].message.additional_kwargs['function_call']["arguments"])
```

And thus there isn't even more code necessary compared to the native langchain implementation.

I didn't do any extensive benchmarks, but for the usecase above, the Langchain implementation was slower and returned wrong results way more often; which doesn't surprise me, given well-known function_call best practices.

Sorry if I might sound slightly offensive here, but I love to use langchain due to the many integrations and my familarity with it, but problems/implementations like this will really, really hurt adoption in the longterm imho. Hidden complexity can have itsreasons, but hidden complexity that deteriorates results significantly for important use cases without obvious reasons is really the worst.

EDIT

The `create_extraction_chain_pydantic` is better, but still unnecessary bloated (and as often, it´s not clear from the documentation, what the differences are and which one is preferred for which use case... - `create_structured_output_chain` seems to be advertised as "Popular"):
```python
[{'name': 'information_extraction',
  'description': 'Extracts the relevant information from the passage.',
  'parameters': {'type': 'object',
   'properties': {'info': {'type': 'array',
     'items': {'type': 'object',
      'properties': {'language_codes': {'title': 'language_codes',
        'description': 'A list of all languages present in the whole text. Exclude code sections, loanwords and technical terms in the text when deciding on the language codes. You have to output at least one language code, even if you are not certain or the text is very short!',
        'type': 'array',
        'items': {'description': '"A single language code in ISO 639-1 format',
         'type': 'object',
         'properties': {'language_code': {'description': "Language code (e.g. 'en', 'de', 'fr')",
           'type': 'string'}},
         'required': ['language_code']}},
       'main_language_code': {'title': 'main_language_code',
        'description': 'Main Language of the text.',
        'allOf': [{'description': '"A single language code in ISO 639-1 format',
          'type': 'object',
          'properties': {'language_code': {'description': "Language code (e.g. 'en', 'de', 'fr')",
            'type': 'string'}},
          'required': ['language_code']}]}},
      'required': ['main_language_code']}}},
   'required': ['info']}}]
``