| title | emoji | colorFrom | colorTo | sdk | suggested_hardware | disable_embedding | license |
|---|---|---|---|---|---|---|---|
dqa |
🐳 |
purple |
blue |
docker |
cpu-basic |
true |
mit |
The DQA aka difficult questions attempted project utilises large language model (LLM) agent(s) to perform multi-hop question answering (MHQA).
Note that this repository is undergoing a complete overhaul of the older, now obsolete, version of DQA. The purpose of this overhaul is to standardise agent communication using the A2A protocol and to use the Dapr virtual actors to manage the backend logic.
DQA - Difficult Questions Attempted - is an agentic chatbot that attempts to answer non-trivial multi-hop questions using (large) language models (LLM) and tools available over the Model Context Protocol (MCP). The functionality of DQA is basic. As of late 2025, the functionality of DQA is available in most commercial chatbots.
However, DQA is experimental with the emphasis on standardising agentic communication and managing backend functionality using Dapr-managed virtual actors. Although the instructions below explain the deployment of DQA on a single machine, it can be deployed and run on a Kubernetes cluster, with minimal modifications to the configuration.
- Install
uvpackage manager. - Install project dependencies by running
uv sync --all-groups.
- Install a self-hosted, with Docker, Arize Phoenix observability system by running
docker run -d --restart unless-stopped -p 6006:6006 -p 4317:4317 --name arizephoenix -i -t arizephoenix/phoenix:latest. Alternatively, use Arize Phoenix cloud.
- Install a self-hosted, (with Docker), Prefect server by running
docker run -p 4200:4200 -d --restart unless-stopped --name prefect prefecthq/prefect:3-latest -- prefect server start --host 0.0.0.0. This is only necessary for Durable Agents connecting to a self-hosted Prefect server. Note that Durable Agents support is experimental and may be dropped in the future.
- Install and configure Dapr to run with docker.
- Run
dapr initto initialisedaprdand the relevant containers.
If deployment over Kubernetes is desired then check these deployment instructions.
Coming soon.
There are two main configuration files.
- LLM configuration at
conf/llm.json. - MCP configuration at
conf/mcp.json.
There is already a default configuration provided for either of these.
There are Dapr related configuration files too.
- The main Dapr application configuration at
dapr.yaml. Change the various hosts and ports in this configuration if you want to use ports that are not the default ones. - Dapr telemetry configuration at
.dapr/config.yaml. - Dapr hot-swappable component configuration files at
.dapr/components/.
The following environment variables are mandatory.
DQA_SECRETS_REDIS_HOST: Use this to specify your Redis host that Dapr will use for its statestore and pubsub components, e.g.,localhost:6379orhost.internal.docker:6379.DQA_SECRETS_REDIS_USERNAME: Use this to specify your Redis username that Dapr will use to connect to the Redis host specified above, e.g.,default.DQA_SECRETS_REDIS_PASSWORD: Use this to specify your Redis password that Dapr will use to connect to the Redis host specified above. The password for local installations is typically blank.
The following API keys are optional but maybe provided for additional functionality. If not provided, the corresponding functionality will not be available.
OLLAMA_API_KEY: The Ollama API key is required for MCP-based web search, web fetch and cloud hosted models on Ollama. MCP features include 2 tools. Create an API key from your Ollama account.ALPHAVANTAGE_API_KEY: The API key to MCP-based Alpha Vantage finance related functions. MCP features include 118 tools. Obtain your free API key from Alpha Vantage. Note that basic finance tools are available through the yfinance MCP even if Alpha Vantage MCP is not loaded.TAVILY_API_KEY: The API key for Tavily search and research services. MCP features include 4 tools. Get your API key from your Tavily account.
The following environment variables are all optional.
APP_LOG_LEVEL: The general log level of the DQA app. Defaults toINFO.DQA_MCP_SERVER_TRANSPORT,FASTMCP_HOSTandFASTMCP_PORT: These specify the transport type, the host and port for the built-in MCP server of DQA. The default values arestdio,localhostand8000respectively.HTTPX_TIMEOUT: This specifies the timeout value in seconds a HTTP client will wait for the server to respond before raising an error. This applies, for example, to the communication timeout between the web frontend or CLI frontend to the A2A endpoint(s). Default value is 120 (seconds).LLM_CONFIG_FILEandMCP_CONFIG_FILE: These specify where the LLM and MCP configurations These default toconf/llm.jsonandconf/mcp.jsonrespectively.- Gradio environment variables to configure the DQA web app. However, MCP server (not to be confused with DQA's built-in MCP server), server-side rendering (SSR) mode, API, Progressive Web App (PWA), analytics and public sharing will be disabled, irrespective of what is specified through the environment variables.
PREFECT_API_URL: This can be used to specify the Prefect Cloud API URL (in which case, you must set thePREFECT_API_KEY, see details) or the local self-hosted API URL athttp://localhost:4200/api. The default value is None, which will turn off Durable Agents!PHOENIX_COLLECTOR_ENDPOINT: This is used to specify the collector endpoint of an Arize Phoenix installation. The default value ishttp://localhost:6006. If you specify a remote endpoint that requires an API key, such as Phoenix cloud then you must also specify the environment variablePHOENIX_API_KEYand also specifyOTEL_EXPORTER_OTLP_HEADERSwith the value'Authorization=Bearer <your-phoenix-api-key>'.BROWSER_STATE_SECRET: This is the secret used by Gradio to encrypt the browser state data. The default value isa2a_dapr_bstate_secret.BROWSER_STATE_CHAT_HISTORIES: This is the key in browser state used by Gradio to store the chat histories (local values). The default value isa2a_dapr_chat_histories.APP_DAPR_SVC_HOSTandAPP_DAPR_SVC_PORT: The host and port at which Dapr actor service will listen on. These default to127.0.0.1and32768. Should you change these, you must change the corresponding information indapr.yaml.APP_DAPR_PUBSUB_STALE_MSG_SECS: This specifies how old a message should be on the Dapr publish-subscribe topic queue before it will be considered too old, and dropped. The default value is 60 seconds.APP_DAPR_PUBSUB_MEMORY_STREAM_BUFFER_SIZE: This specifies the internal memory object stream buffer size that is used to receive messages through the Dapr publish-subscribe subscription and pass it on to the A2A executor. Default value is 65536.APP_DAPR_ACTOR_RETRY_ATTEMPTS: This specifies the number of times an agent executor will try to invoke a method on an actor, if it fails to succeed. The default value is 3.DAPR_PUBSUB_NAME: The configured name of the publish-subscribe component at.dapr/components/pubsub.yaml. Change this environment variable only if you change the corresponding pub-sub component configuration.APP_A2A_SRV_HOSTandAPP_MHQA_A2A_SRV_PORT: The host and port at which A2A endpoint will be available. These default to127.0.0.1and32770. Should you change these, you must change the corresponding information indapr.yaml.APP_MHQA_A2A_REMOTE_URL: This environment variable can be used to specify the full remote URL including the protocol, i.e.,httporhttpswhere the MHQA A2A endpoint is available. This is useful in a scenario where the web app is deployed on a machine that is different from where the MHQA A2A endpoint and Dapr service are. Default value isNone.
- Start the Dapr actor service and the A2A endpoints by running
./start_dapr_multi.sh. (This will send the Dapr sidecar processes in the background.) - Invoke the A2A agent using JSON-RPC by calling
uv run dqa-cli --helpto learn about the various skills-based A2A endpoint invocations. - Or, start the Gradio web app by running
uv run dqa-web-appand then browse to http://localhost:7860. - Once done, stop the dapr sidecars by running
./stop_dapr_multi.sh. - Alternatively, you could also run
./unified_start.shto run the Dapr sidecars as well as the web app, which will be available at http://localhost:7860. Press Ctrl+C to abort the server and the unified runner script will also shutdown the Dapr sidecars. - Further to exposing the web app on localhost, you could also call
./run_ngrok.sh(which requires you to havengroksetup, see instructions) with an optional parameter--domain your-ngrok-FQDNto make your app available throughngrokpublicly at https://your-ngrok-FQDN/.- Note that a feature of exposing the app over
ngrokis that the configured traffic policy forngrokwill require any user accessing the app to authenticate themselves using an OAuth provider (GitHub). This is necessary to transparently create a user namespace such that two users concurrently each naming a chat ID astest-chat(for instance) will not have a chat ID collision because each chat will be effectively handled by a different actor ID in the namespace based on the underlying OAuth provider supplied user ID. Thus,user1__test-chatis different fromuser2__test-chat. - Also note that the same OAuth-authenticated user using more than one separate browsers will not have the same list of chat IDs visible on each browser. This is because the chat IDs list is local to each browser. However, the user will be able to load a specific chat ID on one browser in another browser by manually adding that chat ID. Since those chat IDs are in their OAuth-authenticated user namespaces, an authenticated user will only be able to add their own chat ID, not someone else's.
- Note that a feature of exposing the app over
Run ./run_tests.sh to execute multiple tests and obtain coverage information. The script can accept additional arguments (e.g., -k to filter specific tests), which will be passed to pytest.