Azure-Samples / azure-search-openai-demo

A sample app for the Retrieval-Augmented Generation pattern running in Azure, using Azure AI Search for retrieval and Azure OpenAI large language models to power ChatGPT-style and Q&A experiences.
https://azure.microsoft.com/products/search
MIT License
6.02k stars 4.12k forks source link

General SearchClient using azure.search.documents.aio and Vector search question/issue #917

Open TroyHostetter opened 11 months ago

TroyHostetter commented 11 months ago

This issue is for a: (mark with an x)

- [ ] bug report -> please search issues before submitting
- [ ] feature request
- [x] documentation issue or request
- [ ] regression (a behavior that used to work and stopped in a new release)

Minimal steps to reproduce

I am attempting to replicate one of the Cognitive Search queries used by the cookbook, and have this line of code that is nearly identical to the cookbook:

    r =  await search_client.search(query_text, 
                            filter=None,
                            top=3, 
                            vector=query_vector, 
                            top_k=50 if query_vector else None, 
                            vector_fields="embedding" if query_vector else None,
                            logging_enable=True)

I have verified that query_vector does indeed contain a valid embeddings object returned from the openai Embeddings call.

my imports looks like this:

import os
import traceback
import sys
import logging
import asyncio
import openai
from azure.identity.aio import AzureDeveloperCliCredential
from azure.search.documents.aio import SearchClient
from modules.MessageBuilder import MessageBuilder

As an aside, I am able to get the document count in Search by calling this search method:

async def get_count(search_client: SearchClient):
    count = await search_client.get_document_count()
    return count

Any log messages given by the failure

I am receiving this error, which seems to indicate "vector" is not a valid parameter for search.

TypeError: ClientSession._request() got an unexpected keyword argument 'vector'

Expected/desired behavior

Search should execute the query

OS and Version?

Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) Windows 11 + Python 3.11.3

azd version?

run azd version and copy paste here. azd version 1.0.1

Versions

Name: openai Version: 0.28.1 Name: azure-identity Version: 1.15.0 Name: azure-search-documents Version: 11.3.0

Mention any other details that might be useful

I realize this is not an official bug with your code, but was curious if you knew what may cause this issue? Thanks for any help you are willing to provide.


Thanks! We'll be in touch soon.

pamelafox commented 11 months ago

Where's the cookbook? To use vectors, you need to be very exact with the version of azure-search-documents that you bring in, and you need to bring in a beta version. The code we have here looks similar to that one and works with "11.4.0b6" not "11.3.0" However, there are even more recent versions of the beta that have a slightly different interface, so our code and version will be updated in this repo soon.

Please let me know where cookbook is so that their code can be updated.

TroyHostetter commented 11 months ago

Here's the file in the OpenAI cookbook .. line 107-113.

So sorry, I did NOT look at the requirements.txt for the app. I will look there and try again!!!

Thanks so much!

TroyHostetter commented 11 months ago

One other follow-up .. the query is now executing, but is not returning a dict AsyncSearchItemPaged[dict] .. the debugger shows this instead:

r
<azure.search.documents.aio._paging.AsyncSearchItemPaged object at 0x00000219D1DFADD0>

and the line of code that iterates the content returned from search fails:

results = [doc["sourcepage"] + ": " + nonewlines(doc["content"]) async for doc in r]

any ideas?

anyway, i ended up installing all the pre-reqs from the cookbook requirements.txt file, which eliminated the original issue.

pamelafox commented 11 months ago

What's the error that you see? The r object is an AsyncSearchItemPaged object, and that line of code uses an "asynchronous comprehension" to iterate through the results and create a new list.

TroyHostetter commented 11 months ago

Here's the beginning and end of the stack trace:

Request URL: 'https://gptkb-xxx.search.windows.net/indexes('gptkbindex')/docs/search.post.search?api-version=REDACTED'
Request method: 'POST'
Request headers:
    'Content-Type': 'application/json'
    'Content-Length': '34741'
    'Accept': 'application/json'
    'x-ms-client-request-id': '9fe2939f-7ce9-11ee-bb1d-f8e4e3e9f5ab'
    'User-Agent': 'azsdk-python-search-documents/11.4.0b6 Python/3.11.3 (Windows-10-10.0.22621-SP0)'
    'Authorization': 'REDACTED'
A body is sent with the request
Error: Traceback (most recent call last):
  File "C:\Temp\Python\OpenAIStuff\AzureOpenAI.py", line 104, in <module>
    response = asyncio.run(get_doc_info(search_client, query_text, openai, "embedding"))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "C:\Temp\Python\OpenAIStuff\AzureOpenAI.py", line 27, in get_doc_info
    results = [doc["sourcepage"] + ": " + nonewlines(doc["content"]) async for doc in r]
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Temp\Python\OpenAIStuff\AzureOpenAI.py", line 27, in <listcomp>
    results = [doc["sourcepage"] + ": " + nonewlines(doc["content"]) async for doc in r]

...

  [Previous line repeated 2 more times]
  File "c:\Temp\Python\OpenAIStuff\myenv\Lib\site-packages\azure\core\pipeline\_base_async.py", line 106, in send
    await self._sender.send(request.http_request, **request.context.options),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Temp\Python\OpenAIStuff\myenv\Lib\site-packages\azure\core\pipeline\transport\_aiohttp.py", line 263, in send
    result = await self.session.request(  # type: ignore
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Temp\Python\OpenAIStuff\myenv\Lib\site-packages\aiohttp\client.py", line 547, in _request
    conn.protocol.set_response_params(
  File "c:\Temp\Python\OpenAIStuff\myenv\Lib\site-packages\aiohttp\client_proto.py", line 150, in set_response_params
    self._reschedule_timeout()
  File "c:\Temp\Python\OpenAIStuff\myenv\Lib\site-packages\aiohttp\client_proto.py", line 178, in _reschedule_timeout
    self._read_timeout_handle = self._loop.call_later(
                                ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 727, in call_later
    timer = self.call_at(self.time() + delay, callback, *args,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 740, in call_at
    self._check_closed()
  File "C:\Users\x\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 519, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x000001367CC1A310>
pamelafox commented 11 months ago

It says "Event loop is closed" which usually mean there's something off about how you're using asyncio to call the code. Are you wrapping your call in asyncio.run()?

TroyHostetter commented 11 months ago

Yea .. have the call to search wrapped in this call to asyncio.run()

    count = asyncio.run(get_count(search_client))
    print(f"Count: {count}")
    response = asyncio.run(get_doc_info(search_client, query_text, openai, "embedding"))

Here's the entire async function def. The query_vector looks fine.

async def get_doc_info(search_client: SearchClient, query_text: str, openai: openai, model: str):
    query_vector = (await openai.Embedding.acreate(engine=model, input=query_text))["data"][0]["embedding"]
    r =  await search_client.search(query_text, 
                            filter=None,
                            top=1, 
                            vector=query_vector, 
                            top_k=50 if query_vector else None, 
                            vector_fields="embedding" if query_vector else None,)

    results = [doc["sourcepage"] + ": " + nonewlines(doc["content"]) async for doc in r]
    content = "\n".join(results)

    message_builder = MessageBuilder(system_chat_template, "gpt-35-turbo")
    user_content = query_text + "\n" + f"Sources:\n {content}"
    message_builder.append_message('user', user_content)

    message_builder.append_message('assistant', answer)
    message_builder.append_message('user', question)

    messages = message_builder.messages

    chat_completion = await openai.ChatCompletion.acreate(
        deployment_id="embedding",
        model=model,
        messages=messages,
        temperature=0.3,
        max_tokens=1024,
        n=1,
    )

    return chat_completion
pamelafox commented 11 months ago

I am not an asyncio expert yet, but could you try this pattern instead:

    loop = asyncio.get_event_loop()
    loop.run_until_complete(get_doc_info(search_client, query_text, openai, "embedding")
    loop.close()
TroyHostetter commented 11 months ago

Hi Pamela .. so I've tried a number of different things, including your recommendation, and am still getting that same error. I think the primary difference between that cookbook and my test script is I'm running python on Windows 11 and the cookbook app is running on Linux. I'll let you know if I get a solution.

github-actions[bot] commented 9 months ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this issue will be closed.