diff --git a/.agents/skills/aiq-configure-workflow/assets/config-scaffold.yml b/.agents/skills/aiq-configure-workflow/assets/config-scaffold.yml index 8539744f2..a987d763c 100644 --- a/.agents/skills/aiq-configure-workflow/assets/config-scaffold.yml +++ b/.agents/skills/aiq-configure-workflow/assets/config-scaffold.yml @@ -17,25 +17,29 @@ general: # Web/API: copy general.front_end from config_web_default_llamaindex.yml llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -68,11 +72,11 @@ functions: intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm deep_research_agent: _type: deep_research_agent diff --git a/.agents/skills/aiq-configure-workflow/references/config-profiles.md b/.agents/skills/aiq-configure-workflow/references/config-profiles.md index d80f3f0ad..ae5c82b5b 100644 --- a/.agents/skills/aiq-configure-workflow/references/config-profiles.md +++ b/.agents/skills/aiq-configure-workflow/references/config-profiles.md @@ -17,7 +17,7 @@ the file from `configs/`. For the full nine-profile table, see 3. **Model family** - Nemotron → most profiles - GPT-5.2 orchestration/planning/writing → `config_frontier_models.yml` (`OPENAI_API_KEY`) - - Default split → existing Super profiles for intent/shallow, with Ultra for deep research and a larger writer budget + - Default split → Nemotron 3.5 Lightning for intent/shallow; Ultra for clarification/deep research, with a larger writer budget 4. **Optional features** — copy blocks from: - Guardrails → `config_web_default_guardrails.yml` diff --git a/README.md b/README.md index 8b2f939a1..31de51b62 100644 --- a/README.md +++ b/README.md @@ -108,8 +108,8 @@ The checked-in default CLI and web profiles use these core components: - [NVIDIA NeMo Agent Toolkit 1.8.0](https://docs.nvidia.com/nemo/agent-toolkit/latest/) - [LangChain Deep Agents](https://docs.langchain.com/oss/python/deepagents/overview) 0.6.5 or newer -- [NVIDIA Nemotron 3 Super](https://build.nvidia.com/nvidia/nemotron-3-super-120b-a12b) for intent classification and shallow research in the default profiles -- [NVIDIA Nemotron 3 Ultra](https://build.nvidia.com/nvidia/nemotron-3-ultra-550b-a55b) for clarification and every deep-research role in the default profiles +- NVIDIA Nemotron 3.5 Lightning for intent classification and shallow research in the default profiles +- [NVIDIA Nemotron 3 Ultra](https://build.nvidia.com/nvidia/nemotron-3-ultra-550b-a55b) for clarification and every deep-research role - [Google Gemma 4 31B IT](https://build.nvidia.com/google/gemma-4-31b-it) (document summary, if used) - [NVIDIA Nemotron 3 Embed 1B](https://build.nvidia.com/nvidia/nemotron-3-embed-1b) (embedding model for the knowledge layer, if used) - [NVIDIA Nemotron 3 Nano Omni 30B A3B Reasoning](https://build.nvidia.com/nvidia/nemotron-3-nano-omni-30b-a3b-reasoning) (vision-language model for the LlamaIndex knowledge layer, if used) @@ -152,7 +152,7 @@ When using [NVIDIA API Catalog](https://build.nvidia.com/) (the default), infere | Component | Default Model | Self-Hosted Hardware Reference | |-----------|---------------|-------------------------------| -| LLM (intent classifier, shallow researcher) | `nvidia/nemotron-3-super-120b-a12b` | [Nemotron 3 Super](https://build.nvidia.com/nvidia/nemotron-3-super-120b-a12b) | +| LLM (intent classifier, shallow researcher) | `nvidia/nemotron-3.5-lightning-30b-a3b` | [Nemotron 3.5 Lightning](https://build.nvidia.com/nvidia/nemotron-3.5-lightning-30b-a3b/modelcard) | | LLM (clarifier and all deep-research roles) | `nvidia/nemotron-3-ultra-550b-a55b` | [Nemotron 3 Ultra](https://build.nvidia.com/nvidia/nemotron-3-ultra-550b-a55b) | | Document summary (optional) | `google/gemma-4-31b-it` | [Gemma 4 31B IT](https://build.nvidia.com/google/gemma-4-31b-it) | | Text embedding | `nvidia/nemotron-3-embed-1b` | [NeMo Retriever embedding support matrix](https://docs.nvidia.com/nim/nemo-retriever/text-embedding/latest/support-matrix.html) | @@ -289,17 +289,17 @@ The `configs/` directory holds YAML workflow configs that define agents, tools, | Config | Models | Description | |--------|--------|-------------| -| `config_cli_default.yml` | Nemotron 3 Super/Ultra | CLI chat pipeline with Tavily and clarification; no knowledge backend. Paper search is a commented opt-in. | -| `config_web_default_llamaindex.yml` | Nemotron 3 Super/Ultra; Gemma 4 summary | Default web/API chat pipeline with LlamaIndex/ChromaDB and Tavily. Paper search is commented out. | -| `config_web_frag.yml` | Nemotron 3 Super/Ultra | Web/API and Helm base with Foundational RAG plus Tavily. Requires separately deployed RAG query and ingestion services. | -| `config_web_opensearch.yml` | Nemotron 3 Super/Ultra; Nemotron 3 Embed | Web/API with built-in OpenSearch knowledge retrieval plus Tavily; supports self-hosted, `es`, and `aoss` authentication modes. | -| `config_web_azure_ai_search.yml` | Nemotron 3 Super/Ultra; Nemotron 3 Embed | Web/API with Azure AI Search knowledge retrieval plus Tavily; supports API-key and Azure identity authentication. | -| `config_frontier_models.yml` | GPT Sol/Luna; Nemotron 3 Super; Gemma 4 summary | LlamaIndex profile using GPT Sol/Luna for deep research and Super for intent/shallow. Requires `OPENAI_API_KEY` and `NVIDIA_API_KEY`. | -| `config_web_default_guardrails.yml` | Nemotron 3 Super/Ultra; Gemma 4 summary | LlamaIndex profile with workflow Guardrails explicitly attached, shallow-agent Guardrails dynamically attached through `workflow_functions`, and async deep-agent Guardrails applied by the AI-Q runner from the same target configuration. | -| `config_web_frag_mcp_auth.yml` | Nemotron 3 Super/Ultra | Foundational RAG plus an opt-in protected per-user OAuth MCP source example. Requires a real MCP endpoint and shared token store. | +| `config_cli_default.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra | CLI chat pipeline with Tavily and clarification; no knowledge backend. Paper search is a commented opt-in. | +| `config_web_default_llamaindex.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra; Gemma 4 summary | Default web/API chat pipeline with LlamaIndex/ChromaDB and Tavily. Paper search is commented out. | +| `config_web_frag.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra | Web/API and Helm base with Foundational RAG plus Tavily. Requires separately deployed RAG query and ingestion services. | +| `config_web_opensearch.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra; Nemotron 3 Embed | Web/API with built-in OpenSearch knowledge retrieval plus Tavily; supports self-hosted, `es`, and `aoss` authentication modes. | +| `config_web_azure_ai_search.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra; Nemotron 3 Embed | Web/API with Azure AI Search knowledge retrieval plus Tavily; supports API-key and Azure identity authentication. | +| `config_frontier_models.yml` | GPT Sol/Luna; Nemotron 3.5 Lightning; Gemma 4 summary | LlamaIndex profile using GPT Sol/Luna for deep research and Nemotron 3.5 Lightning for intent/shallow. Requires `OPENAI_API_KEY` and `NVIDIA_API_KEY`. | +| `config_web_default_guardrails.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra; Gemma 4 summary | LlamaIndex profile with workflow Guardrails explicitly attached, shallow-agent Guardrails dynamically attached through `workflow_functions`, and async deep-agent Guardrails applied by the AI-Q runner from the same target configuration. | +| `config_web_frag_mcp_auth.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra | Foundational RAG plus an opt-in protected per-user OAuth MCP source example. Requires a real MCP endpoint and shared token store. | | `config_domain_routing_and_skills.yml` | Nemotron 3 Ultra; Gemma 4 summary | Direct deep-research profile with domain routing, DuckDuckGo news, Polymarket, enabled Serper paper search, LlamaIndex, built-in skills, and a fresh per-job Modal sandbox. | -| `config_openshell.yml` | Nemotron 3 Super/Ultra; Gemma 4 summary | Experimental web/API skills profile with artifact capture, fail-closed policy attestation, and one OpenShell sandbox per deep-research job. | -| `config_mcp.yml` | Nemotron 3 Super/Ultra | Standalone MCP server. Public NIM + Tavily research with PostgreSQL-backed stateless submit/poll/report. Requires `NVIDIA_API_KEY`, `TAVILY_API_KEY`, and `AIQ_CHECKPOINT_DB`. | +| `config_openshell.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra; Gemma 4 summary | Experimental web/API skills profile with artifact capture, fail-closed policy attestation, and one OpenShell sandbox per deep-research job. | +| `config_mcp.yml` | Nemotron 3.5 Lightning; Nemotron 3 Ultra | Standalone MCP server. Public NIM + Tavily research with PostgreSQL-backed stateless submit/poll/report. Requires `NVIDIA_API_KEY`, `TAVILY_API_KEY`, and `AIQ_CHECKPOINT_DB`. | ## Ways to Run the Agents diff --git a/configs/config_cli_default.yml b/configs/config_cli_default.yml index 76913b37a..a89889af8 100644 --- a/configs/config_cli_default.yml +++ b/configs/config_cli_default.yml @@ -16,25 +16,29 @@ general: # project: nvidia-aiq llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -115,7 +119,7 @@ functions: # ========================================================================= intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm # tools: omitted -> inherits all from data_source_registry # exclude_tools: [] # llm_timeout: 90 # optional; seconds for intent LLM call (default 90) @@ -131,7 +135,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm # tools: omitted -> inherits all from data_source_registry exclude_tools: - advanced_web_search_tool diff --git a/configs/config_frontier_models.yml b/configs/config_frontier_models.yml index f66f21123..ebbf623eb 100644 --- a/configs/config_frontier_models.yml +++ b/configs/config_frontier_models.yml @@ -51,25 +51,29 @@ general: - "*" llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.1 - top_p: 0.3 - max_tokens: 16384 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 + top_p: 0.7 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -137,7 +141,7 @@ functions: intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm verbose: true tools: - web_search_tool @@ -156,7 +160,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm verbose: true tools: - web_search_tool diff --git a/configs/config_mcp.yml b/configs/config_mcp.yml index 69b0019bc..d4bff8770 100644 --- a/configs/config_mcp.yml +++ b/configs/config_mcp.yml @@ -26,25 +26,29 @@ general: level: INFO llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -95,7 +99,7 @@ functions: intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm # Defined for workflow compatibility but disabled at the workflow boundary. clarifier_agent: @@ -107,7 +111,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm exclude_tools: - advanced_web_search_tool max_llm_turns: 10 diff --git a/configs/config_openshell.yml b/configs/config_openshell.yml index c48bc9977..e0f3384df 100644 --- a/configs/config_openshell.yml +++ b/configs/config_openshell.yml @@ -28,25 +28,29 @@ general: - "*" llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -120,7 +124,7 @@ functions: intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm verbose: true clarifier_agent: @@ -132,7 +136,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm exclude_tools: - advanced_web_search_tool verbose: true diff --git a/configs/config_web_azure_ai_search.yml b/configs/config_web_azure_ai_search.yml index acc5331eb..524693b6a 100644 --- a/configs/config_web_azure_ai_search.yml +++ b/configs/config_web_azure_ai_search.yml @@ -47,25 +47,29 @@ general: - "*" llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -187,7 +191,7 @@ functions: # ========================================================================= intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm # tools: omitted -> inherits all from data_source_registry # exclude_tools: [] verbose: true @@ -205,7 +209,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm # tools: omitted -> inherits all from data_source_registry exclude_tools: # Remove advanced variant; shallow uses web_search_tool - advanced_web_search_tool diff --git a/configs/config_web_default_guardrails.yml b/configs/config_web_default_guardrails.yml index a8d43f3c9..7ebe273b7 100644 --- a/configs/config_web_default_guardrails.yml +++ b/configs/config_web_default_guardrails.yml @@ -28,25 +28,29 @@ general: - "*" llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -225,7 +229,7 @@ functions: intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm verbose: true clarifier_agent: @@ -237,7 +241,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm exclude_tools: - advanced_web_search_tool verbose: true diff --git a/configs/config_web_default_llamaindex.yml b/configs/config_web_default_llamaindex.yml index 872497407..f860a241d 100644 --- a/configs/config_web_default_llamaindex.yml +++ b/configs/config_web_default_llamaindex.yml @@ -47,25 +47,29 @@ general: - "*" llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -188,7 +192,7 @@ functions: # ========================================================================= intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm # tools: omitted -> inherits all from data_source_registry # exclude_tools: [] verbose: true @@ -204,7 +208,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm # tools: omitted -> inherits all from data_source_registry exclude_tools: # Remove advanced variant; shallow uses web_search_tool - advanced_web_search_tool diff --git a/configs/config_web_frag.yml b/configs/config_web_frag.yml index 99f593ce5..8f3c97599 100644 --- a/configs/config_web_frag.yml +++ b/configs/config_web_frag.yml @@ -49,25 +49,29 @@ general: - "*" llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -158,7 +162,7 @@ functions: # ========================================================================= intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm # tools: omitted -> inherits all from data_source_registry # exclude_tools: [] @@ -173,7 +177,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm # tools: omitted -> inherits all from data_source_registry exclude_tools: - advanced_web_search_tool diff --git a/configs/config_web_frag_mcp_auth.yml b/configs/config_web_frag_mcp_auth.yml index 780b91882..9d63fe98d 100644 --- a/configs/config_web_frag_mcp_auth.yml +++ b/configs/config_web_frag_mcp_auth.yml @@ -56,25 +56,29 @@ general: - "*" llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -207,7 +211,7 @@ functions: # ========================================================================= intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm # tools: omitted -> inherits all from data_source_registry # exclude_tools: [] @@ -222,7 +226,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm # tools: omitted -> inherits all from data_source_registry exclude_tools: - advanced_web_search_tool diff --git a/configs/config_web_opensearch.yml b/configs/config_web_opensearch.yml index 7b7452fe7..4eeedbeeb 100644 --- a/configs/config_web_opensearch.yml +++ b/configs/config_web_opensearch.yml @@ -48,25 +48,29 @@ general: - "*" llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -165,7 +169,7 @@ functions: # ========================================================================= intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm # tools: omitted -> inherits all from data_source_registry # exclude_tools: [] @@ -180,7 +184,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm # tools: omitted -> inherits all from data_source_registry exclude_tools: - advanced_web_search_tool diff --git a/docs/notebooks/0_Getting_Started_with_AIQ.ipynb b/docs/notebooks/0_Getting_Started_with_AIQ.ipynb index 56c04385d..8fc5c72ce 100644 --- a/docs/notebooks/0_Getting_Started_with_AIQ.ipynb +++ b/docs/notebooks/0_Getting_Started_with_AIQ.ipynb @@ -71,7 +71,7 @@ "The following are used by this project:\n", "\n", "- [NVIDIA NeMo Agent toolkit](https://docs.nvidia.com/nemo/agent-toolkit/latest/)\n", - "- [NIM of nvidia/nemotron-3-super-120b-a12b](https://build.nvidia.com/nvidia/nemotron-3-super-120b-a12b) for intent classification and shallow research\n", + "- [NIM of nvidia/nemotron-3.5-lightning-30b-a3b](https://build.nvidia.com/nvidia/nemotron-3.5-lightning-30b-a3b/modelcard) for intent classification and shallow research\n", "- [NIM of nvidia/nemotron-3-ultra-550b-a55b](https://build.nvidia.com/nvidia/nemotron-3-ultra-550b-a55b) for every deep-research role\n", "- [NIM of nvidia/nemotron-3-embed-1b](https://build.nvidia.com/nvidia/nemotron-3-embed-1b) (Optional)\n", "- [NIM of nvidia/nemotron-3-nano-omni-30b-a3b-reasoning](https://build.nvidia.com/nvidia/nemotron-3-nano-omni-30b-a3b-reasoning) (Optional)\n", @@ -94,7 +94,7 @@ "If you are deploying this blueprint without the NVIDIA RAG knowledge layer backend, there are **no GPU requirements** for this blueprint on its own.\n", "\n", "- **Self-hosting NIMs:**\n", - "To self-host the default LLM stack, see the model cards for `nvidia/nemotron-3-super-120b-a12b` and `nvidia/nemotron-3-ultra-550b-a55b`. \n", + "See the model cards for current deployment options for `nvidia/nemotron-3.5-lightning-30b-a3b` and the deep-research model `nvidia/nemotron-3-ultra-550b-a55b`. \n", "If using NVIDIA RAG knowledge layer backend, please see [NVIDIA RAG Documentation Pages](https://docs.nvidia.com/rag/latest/support-matrix.html)\n", "\n" ] @@ -303,25 +303,29 @@ " level: INFO\n", "\n", "llms:\n", - " nemotron_llm_intent:\n", + " nemotron_lightning_intent_llm:\n", " _type: nim\n", - " model_name: nvidia/nemotron-3-super-120b-a12b\n", + " model_name: nvidia/nemotron-3.5-lightning-30b-a3b\n", " base_url: \"https://integrate.api.nvidia.com/v1\"\n", - " temperature: 0.5\n", + " api_key: ${NVIDIA_API_KEY}\n", + " temperature: 0.1\n", " top_p: 0.9\n", - " max_tokens: 4096\n", + " max_tokens: 1024\n", " num_retries: 5\n", + " parallel_tool_calls: false\n", " chat_template_kwargs:\n", - " enable_thinking: true\n", + " enable_thinking: false\n", "\n", - " nemotron_super_llm:\n", + " nemotron_lightning_agent_llm:\n", " _type: nim\n", - " model_name: nvidia/nemotron-3-super-120b-a12b\n", + " model_name: nvidia/nemotron-3.5-lightning-30b-a3b\n", " base_url: \"https://integrate.api.nvidia.com/v1\"\n", - " temperature: 0.7\n", + " api_key: ${NVIDIA_API_KEY}\n", + " temperature: 0.2\n", " top_p: 0.7\n", - " max_tokens: 65536\n", + " max_tokens: 8192\n", " num_retries: 5\n", + " parallel_tool_calls: false\n", " chat_template_kwargs:\n", " enable_thinking: true\n", "\n", @@ -362,13 +366,13 @@ "\n", " intent_classifier:\n", " _type: intent_classifier\n", - " llm: nemotron_llm_intent\n", + " llm: nemotron_lightning_intent_llm\n", " tools:\n", " - web_search_tool\n", "\n", " shallow_research_agent:\n", " _type: shallow_research_agent\n", - " llm: nemotron_super_llm\n", + " llm: nemotron_lightning_agent_llm\n", " tools:\n", " - web_search_tool\n", "\n", @@ -401,7 +405,7 @@ "\n", "**`general.front_end`** wires the Web API (AI-Q API Worker), async job store, and CORS for the chat UI.\n", "\n", - "**`llms`** retains Nemotron Super for intent and shallow research, and uses role-specific Nemotron Ultra profiles for every deep-research role.\n", + "**`llms`** wires Nemotron 3.5 Lightning for intent and shallow research, and uses role-specific Nemotron Ultra profiles for every deep-research role.\n", "\n", "**`functions`** register tools (Tavily web search, plus advanced search), the intent classifier, and the shallow and deep research agents with their assigned tools and LLMs.\n", " \n", @@ -800,13 +804,13 @@ "\n", "You can swap the LLM provider in `config_simple_researcher.yml` with any OpenAI-compatible API.\n", "\n", - "For example, to use [Together.ai](https://www.together.ai/) with the [Nemotron model](https://www.together.ai/models/nvidia-nemotron-3-super) — sign up at [together.ai](https://www.together.ai/), generate an API key, and update the relevant Nemotron LLM blocks. The default config uses `nemotron_super_llm` and `nemotron_ultra_llm`; the pattern below shows the provider change for one block:\n", + "For example, to use [Together.ai](https://www.together.ai/) with a supported model — sign up at [together.ai](https://www.together.ai/), generate an API key, and update the relevant Lightning or Ultra LLM block. The pattern below shows the provider change for one block:\n", "\n", "```yaml\n", "llms:\n", - " nemotron_super_llm:\n", + " nemotron_ultra_llm:\n", " _type: openai\n", - " model_name: nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-BF16\n", + " model_name: ${TOGETHER_MODEL_NAME}\n", " base_url: \"https://api.together.ai/v1\"\n", " api_key: ${TOGETHER_API_KEY}\n", " temperature: 0.1\n", diff --git a/docs/source/customization/configuration-reference.md b/docs/source/customization/configuration-reference.md index c40df97ad..19a1bef99 100644 --- a/docs/source/customization/configuration-reference.md +++ b/docs/source/customization/configuration-reference.md @@ -119,7 +119,7 @@ llms: | `top_p` | `float` | `None` | Nucleus sampling threshold. When `None`, the API uses its server-side default. | | `max_tokens` | `int` | `300` | Maximum tokens in the response. Set higher values (for example, `16384` or `128000`) for research agents. | | `num_retries` | `int` | `5` | Number of retry attempts on API failure. | -| `parallel_tool_calls` | `bool` | Provider default | Whether the provider can emit parallel tool calls. | +| `parallel_tool_calls` | `bool` | Provider default | Whether the provider can emit parallel tool calls. The default intent and shallow profiles set this to `false`. | | `chat_template_kwargs` | `object` | -- | Extra arguments passed to the chat template. Use `enable_thinking: true` to activate the model's chain-of-thought reasoning. | ### Common LLM Configurations @@ -128,8 +128,8 @@ Different agents benefit from different parameter profiles: | Role | Temperature | Top-p | Max Tokens | Notes | |------|------------|-------|------------|-------| -| Intent classifier (Super) | `0.5` | `0.9` | `4096` | Existing classification profile; thinking enabled | -| Shallow researcher (Super) | `0.7` | `0.7` | `65536` | Existing research profile; thinking enabled | +| Intent classifier (Nemotron 3.5 Lightning) | `0.1` | `0.9` | `1024` | Short deterministic classification; thinking disabled | +| Shallow researcher (Nemotron 3.5 Lightning) | `0.2` | `0.7` | `8192` | Tool-calling profile; parallel tool calls disabled and thinking enabled | | Deep research roles (Ultra) | `0.2` | `0.7` | `16384` | Source routing, orchestration, planning, and research | | Deep research writer (Ultra) | `0.2` | `0.7` | `32768` | Larger report-writing budget | | Summary LLM (Gemma) | `0.1` | -- | `100` | Conservative, short document summaries | @@ -379,7 +379,7 @@ Classifies user queries as meta (conversational) or research, and determines res functions: intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm tools: - web_search_tool - paper_search_tool @@ -588,25 +588,29 @@ general: # LLM definitions llms: - super_intent_llm: # Used by intent classifier + lightning_intent_llm: # Used by intent classifier _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - super_agent_llm: # Used by shallow researcher + lightning_agent_llm: # Used by shallow researcher _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -653,7 +657,7 @@ functions: intent_classifier: # Classifies queries, routes depth _type: intent_classifier - llm: super_intent_llm + llm: lightning_intent_llm tools: - web_search_tool - paper_search_tool @@ -668,7 +672,7 @@ functions: shallow_research_agent: # Fast single-pass research _type: shallow_research_agent - llm: super_agent_llm + llm: lightning_agent_llm tools: - web_search_tool max_llm_turns: 10 @@ -706,7 +710,7 @@ only the additional sections you need. | `configs/config_web_azure_ai_search.yml` | Web API | Azure AI Search knowledge retrieval and web search | | `configs/config_web_frag.yml` | Web API / Helm base | Foundational RAG plus Tavily. Requires separately deployed RAG query and ingestion services. Paper search is commented out. | | `configs/config_web_opensearch.yml` | Web API | Built-in OpenSearch knowledge backend plus Tavily. Supports unauthenticated or basic self-hosted OpenSearch and SigV4 (`es` or `aoss`); infrastructure and credentials are deployment opt-ins. | -| `configs/config_frontier_models.yml` | Web API | Shipped LlamaIndex frontier profile: Nemotron 3 Super for intent/shallow, GPT-5.6 Sol for clarification/orchestration/planning/writing, GPT-5.6 Luna for source routing/research, and Gemma 4 for summaries. Requires `NVIDIA_API_KEY`, `OPENAI_API_KEY`, and `TAVILY_API_KEY` for the enabled Tavily tools; the commented paper-search opt-in requires `SERPER_API_KEY` when enabled. Validate the complete workflow against the configured provider endpoints before deployment. | +| `configs/config_frontier_models.yml` | Web API | Shipped LlamaIndex frontier profile: Nemotron 3.5 Lightning for intent/shallow, GPT-5.6 Sol for clarification/orchestration/planning/writing, GPT-5.6 Luna for source routing/research, and Gemma 4 for summaries. Requires `NVIDIA_API_KEY`, `OPENAI_API_KEY`, and `TAVILY_API_KEY` for the enabled Tavily tools; the commented paper-search opt-in requires `SERPER_API_KEY` when enabled. Validate the complete workflow against the configured provider endpoints before deployment. | | `configs/config_web_default_guardrails.yml` | Web API | LlamaIndex with workflow Guardrails attached explicitly, shallow-agent Guardrails dynamically attached through `workflow_functions`, and async deep-agent Guardrails applied by the AI-Q runner from the same target configuration. | | `configs/config_web_frag_mcp_auth.yml` | Web API | Foundational RAG plus a protected per-user OAuth MCP source example. Requires a real protected MCP endpoint and shared token-store configuration; it is not a zero-config default. | | `configs/config_domain_routing_and_skills.yml` | Direct deep-research workflow | Automatic domain routing, Tavily, DuckDuckGo news, Polymarket, LlamaIndex, enabled Serper paper search, built-in skills, and a Modal sandbox. Requires the corresponding service credentials and Modal setup. | diff --git a/docs/source/customization/mcp-tools.md b/docs/source/customization/mcp-tools.md index d2597d6d1..97a50a968 100644 --- a/docs/source/customization/mcp-tools.md +++ b/docs/source/customization/mcp-tools.md @@ -114,7 +114,7 @@ Use `exclude_tools` to specialize individual agents: functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm exclude_tools: - mcp_financial_tools__expensive_long_running_tool ``` diff --git a/docs/source/customization/swapping-models.md b/docs/source/customization/swapping-models.md index a043e0e57..675192d3f 100644 --- a/docs/source/customization/swapping-models.md +++ b/docs/source/customization/swapping-models.md @@ -12,8 +12,8 @@ AI-Q 2.2 ships these exact model assignments and parameters: | Configuration | Intent and shallow roles | Clarification and deep-research roles | Optional summary role | | --- | --- | --- | --- | -| `configs/config_cli_default.yml`, `configs/config_web_default_llamaindex.yml` | `nvidia/nemotron-3-super-120b-a12b` | `nvidia/nemotron-3-ultra-550b-a55b` for clarification, orchestration, source routing, research, planning, and writing | `google/gemma-4-31b-it` in the web profile | -| `configs/config_frontier_models.yml` | `nvidia/nemotron-3-super-120b-a12b` | `gpt-5.6-sol` for clarification, orchestration, planning, and writing; `gpt-5.6-luna` for source routing and research | `google/gemma-4-31b-it` | +| `configs/config_cli_default.yml`, `configs/config_web_default_llamaindex.yml` | `nvidia/nemotron-3.5-lightning-30b-a3b` | `nvidia/nemotron-3-ultra-550b-a55b` for clarification, orchestration, source routing, research, planning, and writing | `google/gemma-4-31b-it` in the web profile | +| `configs/config_frontier_models.yml` | `nvidia/nemotron-3.5-lightning-30b-a3b` | `gpt-5.6-sol` for clarification, orchestration, planning, and writing; `gpt-5.6-luna` for source routing and research | `google/gemma-4-31b-it` | The checked-in files define the documented compatibility boundary; they are not a substitute for an end-to-end run against your provider endpoints and credentials. Changing a model, endpoint, role assignment, prompt, or inference @@ -26,14 +26,18 @@ evaluated in that exact configuration. ```yaml llms: - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false + chat_template_kwargs: + enable_thinking: true ``` **Example: NIM with thinking (for example, for deep research)** @@ -52,7 +56,7 @@ llms: enable_thinking: true ``` -**Model roles:** The workflow maps LLMs to roles (orchestrator, researcher, planner, etc.) through the `LLMProvider`. In YAML you assign which named LLM each agent uses (for example, `orchestrator_llm: nemotron_ultra_llm`, `llm: nemotron_super_llm`). Use different keys in `llms` and point agents at them to swap models per role. +**Model roles:** The workflow maps LLMs to roles (orchestrator, researcher, planner, etc.) through the `LLMProvider`. In YAML you assign which named LLM each agent uses (for example, `orchestrator_llm: nemotron_ultra_llm`, `llm: nemotron_lightning_agent_llm`). Use different keys in `llms` and point agents at them to swap models per role. ## Using Downloadable NIMs (Self-Hosted) @@ -88,7 +92,7 @@ llms: ``` ```{note} -**Hosted Endpoint Availability:** The default profiles retain Nemotron 3 Super for intent and shallow research, and use Nemotron 3 Ultra for clarification and every deep-research role. Shared hosted endpoints can have limited availability during high demand (HTTP 429 or 503 responses). For production deployments requiring consistent throughput, refer to the [self-hosting guidance](../resources/troubleshooting.md#nemotron-hosted-endpoint-availability). +**Hosted Endpoint Availability:** The default profiles use Nemotron 3.5 Lightning for intent and shallow research, and Nemotron 3 Ultra for clarification and every deep-research role. Shared hosted endpoints can have limited availability during high demand (HTTP 429 or 503 responses). For production deployments requiring consistent throughput, refer to the [self-hosting guidance](../resources/troubleshooting.md#nemotron-hosted-endpoint-availability). ``` You can mix hosted and local NIMs in the same config -- for example, use a hosted endpoint for shallow research and a local downloadable Ultra NIM for deep research: @@ -97,11 +101,15 @@ You can mix hosted and local NIMs in the same config -- for example, use a hoste llms: hosted_shallow_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" api_key: ${NVIDIA_API_KEY} - temperature: 0.7 - max_tokens: 65536 + temperature: 0.2 + top_p: 0.7 + max_tokens: 8192 + parallel_tool_calls: false + chat_template_kwargs: + enable_thinking: true local_ultra_llm: _type: nim diff --git a/docs/source/customization/tools-and-sources.md b/docs/source/customization/tools-and-sources.md index e0412b604..f69b86848 100644 --- a/docs/source/customization/tools-and-sources.md +++ b/docs/source/customization/tools-and-sources.md @@ -137,7 +137,7 @@ functions: # Agents with no tools list inherit all registry tools intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm clarifier_agent: _type: clarifier_agent diff --git a/docs/source/examples/full-pipeline-llamaindex.md b/docs/source/examples/full-pipeline-llamaindex.md index d1e940fdf..c639b2a9c 100644 --- a/docs/source/examples/full-pipeline-llamaindex.md +++ b/docs/source/examples/full-pipeline-llamaindex.md @@ -43,25 +43,29 @@ general: # LLMs # =========================================================================== llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.1 - top_p: 0.3 - max_tokens: 16384 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 + top_p: 0.7 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -137,7 +141,7 @@ functions: intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm verbose: true tools: - web_search_tool @@ -156,7 +160,7 @@ functions: shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm verbose: true tools: - web_search_tool diff --git a/docs/source/examples/full-pipeline-web.md b/docs/source/examples/full-pipeline-web.md index 3e5acdf82..f678552f1 100644 --- a/docs/source/examples/full-pipeline-web.md +++ b/docs/source/examples/full-pipeline-web.md @@ -61,34 +61,35 @@ general: # LLMs # =========================================================================== # Role-specific LLM configurations: -# - Super for intent classification and shallow research +# - Nemotron 3.5 Lightning for intent classification and shallow research # - Ultra for clarification and every deep-research role llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.5 # Moderate: needs to reason about intent + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 top_p: 0.9 - max_tokens: 4096 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: - enable_thinking: true + enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.1 # Low: factual research output - top_p: 0.3 - max_tokens: 16384 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 + top_p: 0.7 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true -# =========================================================================== -# Functions (tools and agents) -# =========================================================================== nemotron_ultra_llm: _type: nim model_name: nvidia/nemotron-3-ultra-550b-a55b @@ -156,7 +157,7 @@ functions: # Has access to tools for context-aware routing decisions. intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm tools: - web_search_tool - paper_search_tool @@ -183,7 +184,7 @@ functions: # Single-turn ReAct agent for quick queries. shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm tools: - web_search_tool - knowledge_search diff --git a/docs/source/examples/hybrid-frontier-model.md b/docs/source/examples/hybrid-frontier-model.md index e416165c8..20a4c3ca7 100644 --- a/docs/source/examples/hybrid-frontier-model.md +++ b/docs/source/examples/hybrid-frontier-model.md @@ -12,7 +12,7 @@ shallow research with GPT Sol/Luna for clarification and deep research. | Role | Model | | --- | --- | -| Intent classification and shallow research | `nvidia/nemotron-3-super-120b-a12b` | +| Intent classification and shallow research | `nvidia/nemotron-3.5-lightning-30b-a3b` | | Clarification, orchestration, and planning | `gpt-5.6-sol` | | Source routing and research | `gpt-5.6-luna` | | Report writing | `gpt-5.6-sol` with the writer token budget from the checked-in config | diff --git a/docs/source/examples/minimal-shallow-only.md b/docs/source/examples/minimal-shallow-only.md index 6f80af2c6..0656caeff 100644 --- a/docs/source/examples/minimal-shallow-only.md +++ b/docs/source/examples/minimal-shallow-only.md @@ -25,18 +25,19 @@ general: # --------------------------------------------------------------------------- # LLMs # --------------------------------------------------------------------------- -# A single role-specific Super LLM is sufficient for shallow research. The NIM type connects +# A single role-specific Lightning LLM is sufficient for shallow research. The NIM type connects # to NVIDIA API Catalog. llms: research_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" api_key: ${NVIDIA_API_KEY} - temperature: 0.7 + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 # Max output length per LLM call + max_tokens: 8192 # Max output length per LLM call num_retries: 5 # Retry on transient API failures + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true diff --git a/docs/source/extending/adding-a-tool.md b/docs/source/extending/adding-a-tool.md index d548d0879..9b25fd3a0 100644 --- a/docs/source/extending/adding-a-tool.md +++ b/docs/source/extending/adding-a-tool.md @@ -279,7 +279,7 @@ Reference your tool in any workflow configuration: llms: research_llm: _type: nim - model_name: nvidia/nemotron-3-ultra-550b-a55b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b functions: my_search: diff --git a/docs/source/get-started/installation.md b/docs/source/get-started/installation.md index 8acf44784..19152ccd5 100644 --- a/docs/source/get-started/installation.md +++ b/docs/source/get-started/installation.md @@ -25,7 +25,7 @@ When using [NVIDIA API Catalog](https://build.nvidia.com/) (the default), infere | Component | Default Model | Self-Hosted Hardware Reference | |-----------|---------------|-------------------------------| -| LLM (intent classifier, shallow researcher) | `nvidia/nemotron-3-super-120b-a12b` | [Nemotron 3 Super](https://build.nvidia.com/nvidia/nemotron-3-super-120b-a12b) | +| LLM (intent classifier, shallow researcher) | `nvidia/nemotron-3.5-lightning-30b-a3b` | [Nemotron 3.5 Lightning](https://build.nvidia.com/nvidia/nemotron-3.5-lightning-30b-a3b/modelcard) | | LLM (clarifier and all deep-research roles) | `nvidia/nemotron-3-ultra-550b-a55b` | [Nemotron 3 Ultra](https://build.nvidia.com/nvidia/nemotron-3-ultra-550b-a55b) | | Document summary (optional) | `google/gemma-4-31b-it` | [Gemma 4 31B IT](https://build.nvidia.com/google/gemma-4-31b-it) | | Text embedding | `nvidia/nemotron-3-embed-1b` | [NeMo Retriever embedding support matrix](https://docs.nvidia.com/nim/nemo-retriever/text-embedding/latest/support-matrix.html) | diff --git a/docs/source/resources/troubleshooting.md b/docs/source/resources/troubleshooting.md index 5afcc2cda..438d89bf1 100644 --- a/docs/source/resources/troubleshooting.md +++ b/docs/source/resources/troubleshooting.md @@ -44,19 +44,18 @@ Common issues and solutions for the AI-Q blueprint. ## Nemotron Hosted Endpoint Availability -Nemotron 3 Super (`nvidia/nemotron-3-super-120b-a12b`) and Nemotron 3 Ultra (`nvidia/nemotron-3-ultra-550b-a55b`) are compatible and tested with AIQ, but their NVIDIA-hosted endpoints can have limited availability during high demand. During peak periods you may observe: +Nemotron 3.5 Lightning (`nvidia/nemotron-3.5-lightning-30b-a3b`) and Nemotron 3 Ultra (`nvidia/nemotron-3-ultra-550b-a55b`) are compatible and tested with AIQ, but their NVIDIA-hosted endpoints can have limited availability during high demand. During peak periods you may observe: - Elevated latency or timeouts on LLM inference calls - HTTP 429 (rate-limited) or 503 (service unavailable) responses from the Build API - Degraded agent workflow performance due to upstream model availability -**Default Configuration:** The default configs retain Nemotron 3 Super for intent classification and shallow research, and use Nemotron 3 Ultra for clarification and all deep-research roles. If either hosted endpoint is saturated, retry after a short delay, reduce concurrency, or self-host a downloadable model for consistent throughput. +**Default Configuration:** The default configs use Nemotron 3.5 Lightning for intent classification and shallow research, and Nemotron 3 Ultra for clarification and all deep-research roles. If a hosted endpoint is saturated, retry after a short delay, reduce concurrency, or self-host a downloadable model for consistent throughput. ### Recommended Mitigation: Self-Host the Affected Model For production and staging deployments that require consistent throughput and low-latency inference, self-host a downloadable NVIDIA NIM rather than relying on shared endpoints. Preview endpoint availability and downloadable NIM availability do not necessarily move in lockstep; verify the current model card before choosing an image. -- [Self-host Nemotron 3 Super 120B A12B](https://build.nvidia.com/nvidia/nemotron-3-super-120b-a12b/deploy?nim=self-hosted) for the default intent and shallow-research roles - [Self-host Nemotron 3 Ultra 550B A55B](https://build.nvidia.com/nvidia/nemotron-3-ultra-550b-a55b?nim=self-hosted) for the default clarification and deep-research roles Once your self-hosted endpoint is running, update the corresponding `base_url` in your config to point at it. AIQ's configuration validator currently requires `NVIDIA_API_KEY` for every `_type: nim` profile, even when a local NIM does not enforce client authentication. Set a non-secret placeholder for the local deployment before starting AIQ: diff --git a/frontends/aiq_api/src/aiq_api/jobs/callbacks.py b/frontends/aiq_api/src/aiq_api/jobs/callbacks.py index 1ecd320fe..789a8ca65 100644 --- a/frontends/aiq_api/src/aiq_api/jobs/callbacks.py +++ b/frontends/aiq_api/src/aiq_api/jobs/callbacks.py @@ -42,6 +42,7 @@ from pydantic import ConfigDict from pydantic import Field +from aiq_agent.common.callbacks import SUPPRESS_OUTPUT_ARTIFACT_TAG from aiq_agent.common.citation_verification import extract_http_urls from aiq_agent.common.citation_verification import get_session_registry @@ -740,7 +741,7 @@ def on_llm_start(self, serialized: dict, prompts: list, **kwargs) -> None: def on_llm_new_token(self, token: str, **kwargs) -> None: """Emit a streaming llm.chunk event for each non-empty token.""" - if token: + if token and SUPPRESS_OUTPUT_ARTIFACT_TAG not in (kwargs.get("tags") or []): self._emit( IntermediateStepEvent( category=EventCategory.LLM, @@ -784,6 +785,7 @@ def on_llm_end(self, response, **kwargs) -> None: and len(content) >= self.OUTPUT_MIN_LENGTH and not has_tool_calls and not self._contains_tool_call_syntax(content) + and SUPPRESS_OUTPUT_ARTIFACT_TAG not in (kwargs.get("tags") or []) ): output_category = self._get_output_category(agent_info) self._emit_artifact( diff --git a/frontends/benchmarks/freshqa/configs/config_full_workflow.yml b/frontends/benchmarks/freshqa/configs/config_full_workflow.yml index af1cbc247..33a629c49 100644 --- a/frontends/benchmarks/freshqa/configs/config_full_workflow.yml +++ b/frontends/benchmarks/freshqa/configs/config_full_workflow.yml @@ -9,25 +9,29 @@ general: level: INFO llms: - nemotron_llm_intent: + nemotron_lightning_intent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 - top_p: 0.7 - max_tokens: 8192 + api_key: ${NVIDIA_API_KEY} + temperature: 0.1 + top_p: 0.9 + max_tokens: 1024 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: false - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -63,17 +67,26 @@ llms: temperature: 0.1 functions: + data_sources: + _type: data_source_registry + sources: + - id: web_search + name: "Web Search" + description: "Search the web for real-time information." + tools: + - web_search_tool + web_search_tool: - _type: tavily_internet_search + _type: tavily_web_search max_results: 5 intent_classifier: _type: intent_classifier - llm: nemotron_llm_intent + llm: nemotron_lightning_intent_llm shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm tools: - web_search_tool max_llm_turns: 10 diff --git a/frontends/benchmarks/freshqa/configs/config_shallow_research_only.yml b/frontends/benchmarks/freshqa/configs/config_shallow_research_only.yml index b2900c1b4..9db321278 100644 --- a/frontends/benchmarks/freshqa/configs/config_shallow_research_only.yml +++ b/frontends/benchmarks/freshqa/configs/config_shallow_research_only.yml @@ -1,5 +1,5 @@ # FreshQA shallow-research-only -# Nemotron Ultra on NVIDIA API Catalog; add judge (OpenAI or Gemini) for evaluator. +# Nemotron 3.5 Lightning on NVIDIA API Catalog; add judge (OpenAI or Gemini) for evaluator. general: telemetry: @@ -13,14 +13,16 @@ general: project: "AIQ_v2_freshqa" llms: - nemotron_super_llm: + nemotron_lightning_agent_llm: _type: nim - model_name: nvidia/nemotron-3-super-120b-a12b + model_name: nvidia/nemotron-3.5-lightning-30b-a3b base_url: "https://integrate.api.nvidia.com/v1" - temperature: 0.7 + api_key: ${NVIDIA_API_KEY} + temperature: 0.2 top_p: 0.7 - max_tokens: 65536 + max_tokens: 8192 num_retries: 5 + parallel_tool_calls: false chat_template_kwargs: enable_thinking: true @@ -31,13 +33,22 @@ llms: temperature: 0.1 functions: + data_sources: + _type: data_source_registry + sources: + - id: web_search + name: "Web Search" + description: "Search the web for real-time information." + tools: + - web_search_tool + web_search_tool: - _type: tavily_internet_search + _type: tavily_web_search max_results: 5 shallow_research_agent: _type: shallow_research_agent - llm: nemotron_super_llm + llm: nemotron_lightning_agent_llm max_llm_turns: 20 tools: - web_search_tool diff --git a/frontends/ui/package-lock.json b/frontends/ui/package-lock.json index 72afdb34c..b3064174b 100644 --- a/frontends/ui/package-lock.json +++ b/frontends/ui/package-lock.json @@ -6882,9 +6882,9 @@ "license": "MIT" }, "node_modules/dompurify": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", - "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.13.tgz", + "integrity": "sha512-2vmYIoqjze2d+kakP8S/nS5shfsl587kzwEjcGlTdiksUVgFHnFCsLYDVj/JNqJVOQZGSYBTmuycv0PodwmnMQ==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -10863,9 +10863,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "funding": [ { "type": "github", diff --git a/mcp/tests/test_preclassification_integration.py b/mcp/tests/test_preclassification_integration.py index 315b5f50e..1cf2b4292 100644 --- a/mcp/tests/test_preclassification_integration.py +++ b/mcp/tests/test_preclassification_integration.py @@ -27,7 +27,7 @@ from nat.builder.workflow_builder import WorkflowBuilder _REPO_ROOT = Path(__file__).resolve().parents[2] -_INTENT_LLM_NAME = "nemotron_llm_intent" +_INTENT_LLM_NAME = "nemotron_lightning_intent_llm" class _CountingIntentLLM: diff --git a/src/aiq_agent/agents/shallow_researcher/agent.py b/src/aiq_agent/agents/shallow_researcher/agent.py index 92b117d70..f1fa7ca4a 100644 --- a/src/aiq_agent/agents/shallow_researcher/agent.py +++ b/src/aiq_agent/agents/shallow_researcher/agent.py @@ -38,6 +38,7 @@ from aiq_agent.common import get_source_id_for_tool from aiq_agent.common import load_prompt from aiq_agent.common import render_prompt_template +from aiq_agent.common.callbacks import SUPPRESS_OUTPUT_ARTIFACT_TAG from aiq_agent.common.citation_verification import EmptySourceRegistryError from aiq_agent.common.citation_verification import SourceEntry from aiq_agent.common.citation_verification import SourceRegistry @@ -190,6 +191,8 @@ def _get_llm(self) -> BaseChatModel: def _build_graph(self) -> CompiledStateGraph: """Build the LangGraph StateGraph.""" + source_tool_names = {tool.name for tool in self.tools} + async def agent_node(state: ShallowResearchAgentState) -> dict[str, Any]: """Execute the agent with parallel call tracking and context anchoring.""" messages = state.messages @@ -244,9 +247,30 @@ async def agent_node(state: ShallowResearchAgentState) -> dict[str, Any]: return {"messages": [response], "tool_iterations": iterations} llm = self._get_llm() - llm_with_tools = llm.bind_tools(self.tools, parallel_tool_calls=True) if self.tools else llm + llm_with_tools = llm.bind_tools(self.tools) if self.tools else llm full_messages = [system_message] + processed_history - response = await llm_with_tools.ainvoke(full_messages) + pre_evidence_config = {"tags": [SUPPRESS_OUTPUT_ARTIFACT_TAG]} if iterations == 0 else None + response = await llm_with_tools.ainvoke(full_messages, config=pre_evidence_config) + + if self.tools and iterations == 0 and not getattr(response, "tool_calls", None): + logger.warning("Shallow researcher returned an answer before collecting evidence; retrying once") + tool_required = HumanMessage( + content=( + "Research is required before answering. Call exactly one available research tool now. " + "Do not provide a final answer until the tool result is available." + ) + ) + retry_llm = llm.bind_tools(self.tools, parallel_tool_calls=False) + response = await retry_llm.ainvoke( + full_messages + [response, tool_required], + config=pre_evidence_config, + ) + retry_tool_calls = getattr(response, "tool_calls", None) or [] + if len(retry_tool_calls) != 1 or retry_tool_calls[0].get("name") not in source_tool_names: + raise RuntimeError( + "shallow_research_tool_required: model did not call exactly one allowed research tool " + "after one retry" + ) new_iterations = iterations if hasattr(response, "tool_calls") and response.tool_calls: @@ -275,8 +299,6 @@ async def agent_node(state: ShallowResearchAgentState) -> dict[str, Any]: # data_source_registry then decides which of those are configured # data sources. Having both gates keeps behavior consistent across # agents and safe even if the global registry is ever polluted. - source_tool_names = {t.name for t in self.tools} - async def tool_node_with_source_capture(state: ShallowResearchAgentState) -> dict[str, Any]: """Execute tools and capture source URLs/citations for verification. diff --git a/src/aiq_agent/agents/shallow_researcher/prompts/researcher.j2 b/src/aiq_agent/agents/shallow_researcher/prompts/researcher.j2 index 72c10cd53..eba305767 100644 --- a/src/aiq_agent/agents/shallow_researcher/prompts/researcher.j2 +++ b/src/aiq_agent/agents/shallow_researcher/prompts/researcher.j2 @@ -1,5 +1,13 @@ You are a Shallow Research Agent. Your role is to provide rapid, citation-backed answers using available tools. +## MANDATORY: Research Before Answering +When at least one research tool is available, your first response MUST be a tool call. Never answer directly from memory. + +- This rule applies even when the question looks simple, familiar, or based on a false premise. Search to verify the answer or premise. +- Do not produce a final answer until at least one research tool call has completed. +- If the first search is empty or irrelevant, rewrite the query and search once more before synthesizing. +- After receiving useful results, answer promptly. Do not keep searching when one call provides enough evidence. + ## CRITICAL: Source Hierarchy Prioritize sources based on the query intent: diff --git a/src/aiq_agent/common/callbacks.py b/src/aiq_agent/common/callbacks.py index f3031f962..f68e90abb 100644 --- a/src/aiq_agent/common/callbacks.py +++ b/src/aiq_agent/common/callbacks.py @@ -26,6 +26,9 @@ logger = logging.getLogger(__name__) +SUPPRESS_OUTPUT_ARTIFACT_TAG = "aiq:suppress-output-artifact" + + YELLOW = "\033[33m" CYAN = "\033[36m" GREEN = "\033[32m" diff --git a/tests/aiq_agent/agents/shallow_researcher/test_agent.py b/tests/aiq_agent/agents/shallow_researcher/test_agent.py index 6144a3e1d..00e9d96f6 100644 --- a/tests/aiq_agent/agents/shallow_researcher/test_agent.py +++ b/tests/aiq_agent/agents/shallow_researcher/test_agent.py @@ -17,6 +17,7 @@ from unittest.mock import AsyncMock from unittest.mock import MagicMock +from unittest.mock import call from unittest.mock import patch import pytest @@ -29,6 +30,7 @@ from aiq_agent.agents.shallow_researcher.models import ShallowResearchAgentState from aiq_agent.common import LLMProvider from aiq_agent.common import LLMRole +from aiq_agent.common.callbacks import SUPPRESS_OUTPUT_ARTIFACT_TAG from aiq_agent.common.citation_verification import EmptySourceRegistryError from aiq_agent.common.citation_verification import EmptySourceRegistryReason from aiq_agent.common.citation_verification import SourceEntry @@ -200,7 +202,7 @@ async def test_run_basic_query(self, mock_llm_provider, mock_llm, real_tool): agent = ShallowResearcherAgent( llm_provider=mock_llm_provider, - tools=[real_tool], + tools=[], ) state = ShallowResearchAgentState(messages=[HumanMessage(content="What is CUDA?")]) @@ -219,7 +221,7 @@ async def test_run_with_callbacks(self, mock_llm_provider, mock_llm, real_tool): mock_callback = MagicMock() agent = ShallowResearcherAgent( llm_provider=mock_llm_provider, - tools=[real_tool], + tools=[], callbacks=[mock_callback], ) @@ -239,7 +241,7 @@ async def test_run_with_user_info(self, mock_llm_provider, mock_llm, real_tool): custom_prompt = "You are an assistant. User: {{ user_info }}." agent = ShallowResearcherAgent( llm_provider=mock_llm_provider, - tools=[real_tool], + tools=[], system_prompt=custom_prompt, ) @@ -260,7 +262,7 @@ async def test_run_with_tools_info_in_state(self, mock_llm_provider, mock_llm, r agent = ShallowResearcherAgent( llm_provider=mock_llm_provider, - tools=[real_tool], + tools=[], ) custom_tools_info = [ @@ -299,6 +301,77 @@ def test_default_prompt_requires_tool_result_references(self, mock_llm_provider, assert "exact tool name" in agent.system_prompt assert "- [1] mcp_time__get_current_time" in agent.system_prompt + @pytest.mark.asyncio + async def test_initial_answer_without_tool_call_is_retried(self, mock_llm_provider, mock_llm, real_tool): + """An initial memory-only answer is retried and replaced by a tool call.""" + initial_answer = AIMessage(content="Memory-only answer") + tool_call = AIMessage( + content="", + tool_calls=[{"name": "web_search_tool", "args": {"query": "CUDA"}, "id": "retry-tool"}], + ) + final_answer = AIMessage(content="Evidence-backed answer") + mock_llm.ainvoke = AsyncMock(side_effect=[initial_answer, tool_call, final_answer]) + + agent = ShallowResearcherAgent(llm_provider=mock_llm_provider, tools=[real_tool]) + result = await agent.run(ShallowResearchAgentState(messages=[HumanMessage(content="What is CUDA?")])) + + assert result.messages[-1].content == "Evidence-backed answer" + assert mock_llm.ainvoke.await_count == 3 + assert mock_llm.bind_tools.call_args_list[:2] == [ + call([real_tool]), + call([real_tool], parallel_tool_calls=False), + ] + for invocation in mock_llm.ainvoke.await_args_list[:2]: + assert invocation.kwargs["config"] == {"tags": [SUPPRESS_OUTPUT_ARTIFACT_TAG]} + + @pytest.mark.asyncio + async def test_repeated_answer_without_tool_call_fails_closed(self, mock_llm_provider, mock_llm, real_tool): + """A model that ignores the bounded tool-use retry cannot synthesize an answer.""" + mock_llm.ainvoke = AsyncMock( + side_effect=[AIMessage(content="First answer"), AIMessage(content="Second answer")] + ) + agent = ShallowResearcherAgent(llm_provider=mock_llm_provider, tools=[real_tool]) + + with pytest.raises(RuntimeError, match="shallow_research_tool_required"): + await agent.run(ShallowResearchAgentState(messages=[HumanMessage(content="What is CUDA?")])) + + @pytest.mark.asyncio + async def test_retry_with_multiple_tool_calls_fails_closed(self, mock_llm_provider, mock_llm, real_tool): + """The bounded retry cannot schedule multiple tools or exceed its one-call contract.""" + multiple_tool_calls = AIMessage( + content="", + tool_calls=[ + {"name": "web_search_tool", "args": {"query": "CUDA"}, "id": "retry-tool-1"}, + {"name": "web_search_tool", "args": {"query": "GPU"}, "id": "retry-tool-2"}, + ], + ) + mock_llm.ainvoke = AsyncMock(side_effect=[AIMessage(content="Memory-only answer"), multiple_tool_calls]) + agent = ShallowResearcherAgent(llm_provider=mock_llm_provider, tools=[real_tool]) + + with pytest.raises(RuntimeError, match="exactly one allowed research tool"): + await agent.run(ShallowResearchAgentState(messages=[HumanMessage(content="What is CUDA?")])) + + assert mock_llm.ainvoke.await_count == 2 + assert mock_llm.bind_tools.call_args_list == [ + call([real_tool]), + call([real_tool], parallel_tool_calls=False), + ] + + @pytest.mark.asyncio + async def test_retry_with_unknown_tool_fails_closed(self, mock_llm_provider, mock_llm, real_tool): + """The bounded retry cannot schedule a tool outside the agent's allowlist.""" + unknown_tool_call = AIMessage( + content="", + tool_calls=[{"name": "unavailable_tool", "args": {}, "id": "retry-tool"}], + ) + mock_llm.ainvoke = AsyncMock(side_effect=[AIMessage(content="Memory-only answer"), unknown_tool_call]) + agent = ShallowResearcherAgent(llm_provider=mock_llm_provider, tools=[real_tool]) + + with pytest.raises(RuntimeError, match="exactly one allowed research tool"): + await agent.run(ShallowResearchAgentState(messages=[HumanMessage(content="What is CUDA?")])) + + assert mock_llm.ainvoke.await_count == 2 + @pytest.mark.asyncio async def test_tool_iterations_incremented_on_tool_calls(self, mock_llm_provider, mock_llm, real_tool): """Test tool_iterations counter increments when LLM makes tool calls.""" @@ -377,7 +450,7 @@ async def test_run_returns_updated_tool_iterations(self, mock_llm_provider, mock agent = ShallowResearcherAgent( llm_provider=mock_llm_provider, - tools=[real_tool], + tools=[], ) state = ShallowResearchAgentState( @@ -868,7 +941,7 @@ async def test_run_uses_session_registry_when_set(self, mock_llm_provider, mock_ agent = ShallowResearcherAgent( llm_provider=mock_llm_provider, - tools=[web_search_tool], + tools=[], ) set_session_registry(session_reg) @@ -895,7 +968,7 @@ async def test_run_clears_registry_in_standalone_mode(self, mock_llm_provider, m agent = ShallowResearcherAgent( llm_provider=mock_llm_provider, - tools=[web_search_tool], + tools=[], ) # Pre-populate the instance registry (simulating stale data) agent.source_registry.add(SourceEntry(url="https://stale.example.com")) @@ -922,7 +995,7 @@ async def test_empty_registry_classification_preserves_sanitized_answer( expected_reason, ): mock_llm.ainvoke = AsyncMock(return_value=AIMessage(content="Draft answer with https://private.example/path")) - agent = ShallowResearcherAgent(llm_provider=mock_llm_provider, tools=[web_search_tool]) + agent = ShallowResearcherAgent(llm_provider=mock_llm_provider, tools=[]) state = ShallowResearchAgentState( messages=[HumanMessage(content="Test")], data_sources=data_sources, @@ -1003,7 +1076,7 @@ async def test_session_registry_does_not_mutate_shared_instance(self, mock_llm_p agent = ShallowResearcherAgent( llm_provider=mock_llm_provider, - tools=[web_search_tool], + tools=[], ) original_registry = agent.source_registry diff --git a/tests/aiq_agent/jobs/test_runner.py b/tests/aiq_agent/jobs/test_runner.py index 52566fe30..3a7c441b7 100644 --- a/tests/aiq_agent/jobs/test_runner.py +++ b/tests/aiq_agent/jobs/test_runner.py @@ -73,6 +73,7 @@ from aiq_agent.agents.deep_researcher.custom_middleware import FinalReportCommitTracker from aiq_agent.auth import Principal +from aiq_agent.common.callbacks import SUPPRESS_OUTPUT_ARTIFACT_TAG from aiq_api.jobs.callbacks import ArtifactType from aiq_api.jobs.callbacks import DeepResearchEventCallback from aiq_api.jobs.callbacks import EventCategory @@ -373,6 +374,19 @@ def test_on_chat_model_start_emits_event(self): assert call_args["type"] == "llm.start" assert call_args["name"] == "gpt-4" + def test_suppressed_llm_output_keeps_lifecycle_without_publishing_content(self): + """Pre-evidence answers retain telemetry but cannot reach output artifacts or chunks.""" + mock_store = MagicMock() + callback = DeepResearchEventCallback(event_store=mock_store) + tags = [SUPPRESS_OUTPUT_ARTIFACT_TAG] + + callback.on_llm_new_token("rejected draft", tags=tags) + callback._extract_llm_response = MagicMock(return_value=("x" * 200, None, None, False)) + callback.on_llm_end(MagicMock(), run_id="pre-evidence", tags=tags) + + events = [stored.args[0] for stored in mock_store.store.call_args_list] + assert [event["type"] for event in events] == ["llm.end"] + class TestSubmitDeepResearchJob: """Tests for the submit_deep_research_job function.""" diff --git a/tests/aiq_agent/test_default_model_profiles.py b/tests/aiq_agent/test_default_model_profiles.py index 3372111bb..39baa4f50 100644 --- a/tests/aiq_agent/test_default_model_profiles.py +++ b/tests/aiq_agent/test_default_model_profiles.py @@ -9,7 +9,8 @@ REPO_ROOT = Path(__file__).resolve().parents[2] ULTRA_MODEL = "nvidia/nemotron-3-ultra-550b-a55b" -SUPER_MODEL = "nvidia/nemotron-3-super-120b-a12b" +LIGHTNING_MODEL = "nvidia/nemotron-3.5-lightning-30b-a3b" +BUILD_BASE_URL = "https://integrate.api.nvidia.com/v1" CONFIG_GLOBS = ( ".agents/skills/aiq-configure-workflow/assets/config-scaffold.yml", @@ -17,11 +18,10 @@ "frontends/benchmarks/**/configs/*.yml", ) CONFIG_PATHS = tuple(sorted(path for pattern in CONFIG_GLOBS for path in REPO_ROOT.glob(pattern))) +FRESHQA_CONFIG_PATHS = tuple(sorted(REPO_ROOT.glob("frontends/benchmarks/freshqa/configs/*.yml"))) -# Super remains intentionally pinned for intent and shallow research until the -# separately gated Nano 3.5 follow-up is available. Every other deprecated -# reference must be removed by this migration. -REPLACED_REFERENCES = ( +DEPRECATED_REFERENCES = ( + "/".join(("nvidia", "nemotron-3-super-120b-a12b")), "/".join(("nvidia", "nemotron-3-nano-30b-a3b")), "/".join(("nvidia", "nemotron-mini-4b-instruct")), "/".join(("nvidia", "llama-nemotron-embed-vl-1b-v2")), @@ -63,6 +63,22 @@ def _model_for_alias(config: dict, alias: str) -> str: return config["llms"][alias]["model_name"] +def _thinking_enabled(config: dict, alias: str) -> bool: + return bool(config["llms"][alias].get("chat_template_kwargs", {}).get("enable_thinking", False)) + + +def _registered_source_tools(config: dict) -> set[str]: + functions = config.get("functions", {}) + registries = ( + function + for function in functions.values() + if isinstance(function, dict) and function.get("_type") == "data_source_registry" + ) + return { + tool for registry in registries for source in registry.get("sources", []) for tool in source.get("tools", []) + } + + @pytest.mark.parametrize("config_path", CONFIG_PATHS, ids=lambda path: str(path.relative_to(REPO_ROOT))) def test_default_profiles_use_role_appropriate_models(config_path: Path): config = _load_config(config_path) @@ -74,9 +90,27 @@ def test_default_profiles_use_role_appropriate_models(config_path: Path): function_type = function.get("_type") if function_type == "intent_classifier": - assert _model_for_alias(config, function["llm"]) == SUPER_MODEL + alias = function["llm"] + assert alias == "nemotron_lightning_intent_llm" + assert _model_for_alias(config, alias) == LIGHTNING_MODEL + assert config["llms"][alias]["base_url"] == BUILD_BASE_URL + assert config["llms"][alias]["api_key"] == "${NVIDIA_API_KEY}" + assert config["llms"][alias]["temperature"] == 0.1 + assert config["llms"][alias]["top_p"] == 0.9 + assert config["llms"][alias]["max_tokens"] == 1024 + assert not config["llms"][alias]["parallel_tool_calls"] + assert not _thinking_enabled(config, alias) elif function_type == "shallow_research_agent": - assert _model_for_alias(config, function["llm"]) == SUPER_MODEL + alias = function["llm"] + assert alias == "nemotron_lightning_agent_llm" + assert _model_for_alias(config, alias) == LIGHTNING_MODEL + assert config["llms"][alias]["base_url"] == BUILD_BASE_URL + assert config["llms"][alias]["api_key"] == "${NVIDIA_API_KEY}" + assert config["llms"][alias]["temperature"] == 0.2 + assert config["llms"][alias]["top_p"] == 0.7 + assert config["llms"][alias]["max_tokens"] == 8192 + assert not config["llms"][alias]["parallel_tool_calls"] + assert _thinking_enabled(config, alias) elif config_path.name != "config_frontier_models.yml" and function_type == "clarifier_agent": assert _model_for_alias(config, function["llm"]) == ULTRA_MODEL elif config_path.name != "config_frontier_models.yml" and function_type == "deep_research_agent": @@ -91,7 +125,20 @@ def test_default_profiles_use_role_appropriate_models(config_path: Path): assert _model_for_alias(config, function[role]) == ULTRA_MODEL -def test_replaced_model_and_endpoint_references_are_absent(): +@pytest.mark.parametrize("config_path", FRESHQA_CONFIG_PATHS, ids=lambda path: path.name) +def test_freshqa_research_tools_are_registered_data_sources(config_path: Path): + config = _load_config(config_path) + source_tools = _registered_source_tools(config) + + for function in config.get("functions", {}).values(): + if isinstance(function, dict) and function.get("_type") in { + "shallow_research_agent", + "deep_research_agent", + }: + assert set(function.get("tools", [])) <= source_tools + + +def test_deprecated_model_and_endpoint_references_are_absent(): violations: list[str] = [] for path in REPO_ROOT.rglob("*"): @@ -99,8 +146,8 @@ def test_replaced_model_and_endpoint_references_are_absent(): continue text = path.read_text(encoding="utf-8") - for reference in REPLACED_REFERENCES: + for reference in DEPRECATED_REFERENCES: if reference in text: violations.append(f"{path.relative_to(REPO_ROOT)}: {reference}") - assert not violations, "Replaced references remain:\n" + "\n".join(violations) + assert not violations, "Deprecated references remain:\n" + "\n".join(violations)