Open nazim-ashman-oc opened 1 month ago
Hey @nazim-ashman-oc! 👋 I'm here to help you with any bugs, questions, or contributions you might have. Let's tackle this together while we wait for a human maintainer.
The error you're encountering is due to the __str__
method in the RESPONSE_TYPE
class trying to run an asynchronous function synchronously. Specifically, the asyncio_run
function is raising a TypeError
because it expects an awaitable, but it seems to be getting something else.
To fix this, you need to ensure that the __str__
method is correctly handling the asynchronous function. Here is a potential fix:
__str__
method in the RESPONSE_TYPE
class to properly handle the asynchronous function.response_text
is correctly awaited if it is a coroutine.Here is an example of how you might modify the __str__
method:
from llama_index.core.async_utils import asyncio_run
class RESPONSE_TYPE:
# Other methods and attributes...
async def _async_str(self):
# Your async string conversion logic here
pass
def __str__(self):
return asyncio_run(self._async_str())
In your SubQuestionQueryEngine
class, ensure that response_text
is awaited if it is a coroutine:
async def _aquery_subq(
self, sub_q: SubQuestion, color: Optional[str] = None
) -> Optional[SubQuestionAnswerPair]:
try:
with self.callback_manager.event(
CBEventType.SUB_QUESTION,
payload={EventPayload.SUB_QUESTION: SubQuestionAnswerPair(sub_q=sub_q)},
) as event:
question = sub_q.sub_question
query_engine = self._query_engines[sub_q.tool_name]
if self._verbose:
print_text(f"[{sub_q.tool_name}] Q: {question}\n", color=color)
response = await query_engine.aquery(question)
response_text = await response.__str__() if asyncio.iscoroutinefunction(response.__str__) else str(response)
if self._verbose:
print_text(f"[{sub_q.tool_name}] A: {response_text}\n", color=color)
qa_pair = SubQuestionAnswerPair(
sub_q=sub_q, answer=response_text, sources=response.source_nodes
)
event.on_end(payload={EventPayload.SUB_QUESTION: qa_pair})
return qa_pair
except ValueError:
logger.warning(f"[{sub_q.tool_name}] Failed to run {question}")
return None
This ensures that the response_text
is correctly awaited if it is a coroutine, preventing the TypeError
you encountered [1][2].
To continue talking to Dosu, mention @dosu.
@nazim-ashman-oc you arent using an async generator
It should be async for chunk in response.async_response_gen():
response.async_response_gen():
@logan-markewich Ah thanks. Made the changes, but still getting the same error :(
Any other code snippets I could add to help out? I can't seem to find any examples online of usin the SubQuestionQuery Engine with async and streaming. async alone works and streaming alone works, but I can't get them to work together
Is the issue is in all query that you are giving or particular one query ,for me this issue also raised but for only particular queries except that other works well than that it works well.
Is the issue is in all query that you are giving or particular one query ,for me this issue also raised but for only particular queries except that other works well than that it works well.
Well, from the RouterQueryEngine, if an engine other than SubQuestionQueryEngine is chosen, it works. It breaks down when SubQuestionQueryEngine is chosen.
Ok, problem here was that I was using the same response synthesizer (set to streaming=True) for the RetrieverQueryEngine and the SubQuestionQueryEngine. Making a separate response synthesizer for RetrieverQueryEngine (with streaming=False) fixes this problem.
Practically this makes sense for me, since there is no point for RetrieverQueryEngine to be streaming since it is being fed into the SubQuestionQueryEngine. However, it still feels like unintended behaviour. The str() does not seem to work well with an AsyncStreamingResponse.
@logan-markewich
Ok dosu pretty much pointed us in the right direction here, it looks like in
@dataclass
class AsyncStreamingResponse:
"""AsyncStreamingResponse object.
Returned if streaming=True while using async.
Attributes:
_async_response_gen: The response async generator.
"""
response_gen: TokenAsyncGen
source_nodes: List[NodeWithScore] = field(default_factory=list)
metadata: Optional[Dict[str, Any]] = None
response_txt: Optional[str] = None
def __post_init__(self) -> None:
self._lock = asyncio.Lock()
def __str__(self) -> str:
"""Convert to string representation."""
return asyncio_run(self._async_str)
async def _async_str(self) -> str:
"""Convert to string representation."""
async for _ in self._yield_response():
...
return self.response_txt or "None"
async def _yield_response(self) -> TokenAsyncGen:
"""Yield the string response."""
async with self._lock:
if self.response_txt is None and self.response_gen is not None:
self.response_txt = ""
async for text in self.response_gen:
self.response_txt += text
yield text
else:
yield self.response_txt
.....
the str dunder method should be this instead (it was missing the brackets):
def __str__(self) -> str:
"""Convert to string representation."""
return asyncio_run(self._async_str())
I make a PR for this?
Question Validation
Question
I have been trying to get a SubQuestionQueryEngine working in async mode for a while in combination with FastAPI.
I have already applied:
nest_asyncio.apply()
and am using the "asyncio" loop:
uvicorn.run(app, host="0.0.0.0", port=8000, loop="asyncio")
I am setting up my sub_qestion_query_engine like this:
It is then put as a tool into a RouterQueryEngine. The RouterQueryEngine is then called from a FastAPI endpoint which in turn calls this function:
Now I am getting this error:
I am guessing this error hints at something wrong with the response sent back from the RetrieverQueryEngine layers, but I am not too sure, I have set use_async=True where I can and streaming=True. Not sure where I am going wrong.