llama_index [Bug]:无法在聊天响应中使用json

x0fgdtte  于 5个月前  发布在  其他
关注(0)|答案(7)|浏览(56)

问题描述

聊天响应中包含 ChoiceUsage,它们可以被序列化为 JSON。

版本

任何版本

重现步骤

response = llm.chat(messages=[
  ChatMessage(role="system", content="You are a helpful assistant."),
  ChatMessage(role="user", content="Hi, how are you?")
])
print(response)

{'id': 'chatcmpl-9hTPLBEbQZ2FCGSBMkrrBxR3VvESE',
 'choices': [Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content="Hello! I'm just a computer program, so I don't have feelings, but I'm here and ready to help you. How can I assist you today?", role='assistant', function_call=None, tool_calls=None))],
 'created': 1720148175,
 'model': 'gpt-3.5-turbo-0125',
 'object': 'chat.completion',
 'system_fingerprint': None,
 'usage': CompletionUsage(completion_tokens=33, prompt_tokens=23, total_tokens=56)}
response.json()

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[53], line 1
----> 1 response.json()

File [~/upstage/projects/upstage-cookbook/.venv/lib/python3.10/site-packages/pydantic/v1/main.py:504](http://localhost:8888/lab/workspaces/auto-T/tree/~/upstage/projects/upstage-cookbook/.venv/lib/python3.10/site-packages/pydantic/v1/main.py#line=503), in BaseModel.json(self, include, exclude, by_alias, skip_defaults, exclude_unset, exclude_defaults, exclude_none, encoder, models_as_dict, **dumps_kwargs)
    502 if self.__custom_root_type__:
    503     data = data[ROOT_KEY]
--> 504 return self.__config__.json_dumps(data, default=encoder, **dumps_kwargs)

File [/usr/local/Cellar/python](http://localhost:8888/usr/local/Cellar/python)@3.10[/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/json/__init__.py:238](http://localhost:8888/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/json/__init__.py#line=237), in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw)
    232 if cls is None:
    233     cls = JSONEncoder
    234 return cls(
    235     skipkeys=skipkeys, ensure_ascii=ensure_ascii,
    236     check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    237     separators=separators, default=default, sort_keys=sort_keys,
--> 238     **kw).encode(obj)

File [/usr/local/Cellar/python](http://localhost:8888/usr/local/Cellar/python)@3.10[/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/json/encoder.py:199](http://localhost:8888/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/json/encoder.py#line=198), in JSONEncoder.encode(self, o)
    195         return encode_basestring(o)
    196 # This doesn't pass the iterator directly to ''.join() because the
    197 # exceptions aren't as detailed.  The list call should be roughly
    198 # equivalent to the PySequence_Fast that ''.join() would do.
--> 199 chunks = self.iterencode(o, _one_shot=True)
    200 if not isinstance(chunks, (list, tuple)):
    201     chunks = list(chunks)

File [/usr/local/Cellar/python](http://localhost:8888/usr/local/Cellar/python)@3.10[/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/json/encoder.py:257](http://localhost:8888/3.10.13_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/json/encoder.py#line=256), in JSONEncoder.iterencode(self, o, _one_shot)
    252 else:
    253     _iterencode = _make_iterencode(
    254         markers, self.default, _encoder, self.indent, floatstr,
    255         self.key_separator, self.item_separator, self.sort_keys,
    256         self.skipkeys, _one_shot)
--> 257 return _iterencode(o, 0)

File [~/upstage/projects/upstage-cookbook/.venv/lib/python3.10/site-packages/pydantic/v1/json.py:90](http://localhost:8888/lab/workspaces/auto-T/tree/~/upstage/projects/upstage-cookbook/.venv/lib/python3.10/site-packages/pydantic/v1/json.py#line=89), in pydantic_encoder(obj)
     88     return encoder(obj)
     89 else:  # We have exited the for loop without finding a suitable encoder
---> 90     raise TypeError(f"Object of type '{obj.__class__.__name__}' is not JSON serializable")

TypeError: Object of type 'Choice' is not JSON serializable

相关日志/回溯

  • 无响应*
t9eec4r0

t9eec4r01#

将包含 ChoiceUsage 对象的聊天响应序列化为 JSON,而不遇到 TypeError,你需要实现一个自定义的 JSON 编码器。以下是如何实现这个功能的示例:

import json
from typing import Any

class CustomJSONEncoder(json.JSONEncoder):
    def default(self, obj: Any) -> Any:
        if isinstance(obj, Choice):
            return obj.__dict__
        if isinstance(obj, Usage):
            return obj.__dict__
        return super().default(obj)

# Assuming `response` is the chat response object containing `Choice` and `Usage` objects
response_json = json.dumps(response, cls=CustomJSONEncoder)
print(response_json)

在这个示例中,CustomJSONEncoder 使用它们的 __dict__ 属性将 ChoiceUsage 对象转换为字典,使它们可被 JSON 序列化。

  • 要继续与 Dosu 交谈,请提及 @dosu。*
elcex8rz

elcex8rz2#

对于ChatMessage类,我们可以应用类似的修复方法来解决这个问题。

jhiyze9q

jhiyze9q3#

(但是,一个简单的解决方法就是只获取你想要的字段)

9rbhqvlz

9rbhqvlz4#

首先,我不建议直接调用 response.json() 。它的返回值是 LlamaIndex 的 ChatResponse ,如果你想记录类似接口日志的内容,这不是最佳选择。
其次,如果有必要,你可以自己实现编码,如下所示:

import os
import json
from typing import Any

from llama_index.core.base.llms.types import ChatMessage
from llama_index.llms.openai import OpenAI
from openai.types.chat.chat_completion import Choice
from openai.types.completion_usage import CompletionUsage

def openai_json_encoder(obj: Any) -> Any:
    if isinstance(obj, (Choice, CompletionUsage)):
        return obj.model_dump()
    return json.JSONEncoder().default(obj)

llm = OpenAI()

response = llm.chat(messages=[
  ChatMessage(role="system", content="You are a helpful assistant."),
  ChatMessage(role="user", content="Hi, how are you?")
])

response.json(encoder=openai_json_encoder)

最后,如果你有任何其他问题,我们可以继续讨论。
@JuHyung-Son@logan-markewich

i7uaboj4

i7uaboj45#

当然,我们可以从ChatResponse扩展,实现OpenAIChatResponse,然后使用pydantic配置如下:

class OpenAIChatResponse(ChatResponse):

    class Config:
        json_encoders = {
            Choice: lambda x: x.dict(),
            CompletionUsage: lambda x: x.dict()
        }

然而,我认为这并不必要。

yyyllmsg

yyyllmsg6#

好的,我明白了。谢谢。
但是如果json方法实际上不起作用,也不建议使用,我们是否还需要一个json方法?

4ngedf3f

4ngedf3f7#

方法jsonBaseModelpydantic中的方法。我的第一React是在Java中添加一个全局转换器,如Spring框架。

相关问题