Thursday, June 26, 2025

What is Agent Mode in Visual Studio code with Co-Pilot

Why use agent mode?

Agent mode is optimized for making autonomous edits across multiple files in your project. It is particularly useful for complex tasks that require not only code edits but also the invocation of tools and terminal commands. You can use agent mode to:


Refactor parts of your codebase, such as "refactor the app to use a Redis cache".

Plan and implement new features, such as "add a login form to the app using OAuth for authentication".

Migrate your codebase to a new framework, such as "migrate the app from React to Vue.js".

Generate an implementation plan for a complex task, such as "create a meal-planning web app using a Swift front-end and a Node.js back-end".

Define a high-level requirement, such as "add social media sharing functionality".

Agent mode is particularly useful for coding tasks when you have a less well-defined task that might also require running terminal commands and tools. Agent mode autonomously determines the relevant context and tasks to accomplish the request. It can also iterate multiple times to resolve intermediate issues, such as syntax errors or test failures.


Examples are:


Enter your prompt for making edits in the chat input field and select Send (Enter) to submit it.


You can specify a high-level requirement, and you don't have to specify which files to work on. In agent mode, the AI determines the relevant context and files to edit autonomously.


Experiment with some of these example prompts to get started:


Create a meal-planning web app using React and Node.js

Add social media sharing functionality

Replace current auth with OAuth


Agent mode might invoke multiple tools to accomplish different tasks. Optionally, select the Tools icon to configure which tools can be used for responding to your request.


If your project has configured tasks in tasks.json, agent mode tries to run the appropriate tasks. For example, if you've defined a build task, agent mode will run the build task before running the application. Enable or disable running workspace tasks with the github.copilot.chat.agent.runTasks setting.



Copilot detects issues and problems in code edits and terminal commands and will iterate and perform additional actions to resolve them.

Enable the github.copilot.chat.agent.autoFix setting to automatically diagnose and fix issues in the generated code changes. This setting is enabled by default.

For example, agent mode might run unit tests as a result of a code edit. If the tests fail, it uses the test outcome to resolve the issue

Copilot Edits agent mode iterates multiple times to resolve issues and problems. The chat.agent.maxRequests setting controls the maximum number of requests that Copilot Edits can make in agent mode.



As Copilot processes your request, notice that Copilot streams the suggested code edits directly in the editor.

The Chat view shows the list of files that were edited in bold text. The editor overlay controls enable you to navigate between the suggested edits.

Review the suggested edits and accept or discard the suggested edits.

Continue to iterate on the code changes to refine the edits or implement additional features.


Agent mode tools

Agent mode uses tools to accomplish specialized tasks while processing a user request. Examples of such tasks are listing the files in a directory, editing a file in your workspace, running a terminal command, getting the output from the terminal, and more.


Agent mode can use the following tools:


Built-in tools

MCP tools

Tools contributed by extensions

You can view and manage the tools that can be used for responding to a request. Select the Tools icon in the Chat view to view and manage the tools that are available in agent mode.



Based on the outcome of a tool, Copilot might invoke other tools to accomplish the overall request. For example, if a code edit results in syntax errors in the file, Copilot might explore another approach and suggest different code changes.


You can enable or disable the use of agent tools by configuring the chat.extensionTools.enabled setting. Learn how to centrally manage this setting in your organization by checking Centrally Manage VS Code Settings in the enterprise documentation.


Define tool sets

A tool set is a collection of tools that you can use in chat. You can use tool sets in the same way as you would use individual tools. For example, select a tool set with the tools picker in agent mode or reference the tool set directly in your prompt by typing # followed by the tool set name.


Tool sets enable you to group related tools together, making it easier to use them in your chat prompts, prompt files, or custom chat modes. This can be particularly useful when you have many installed tools from MCP servers or extensions.



How to create a new Tool set for Co-Pilot? 


To create a tool set, use the Chat: Configure Tool Sets > Create new tool sets file command in the Command Palette. A tool sets file is a .jsonc file that is stored in your user profile.

A tool set has the following structure:


<tool set name>: name of the tool set, which is displayed in the tools picker and when referencing the tool set in your prompt.

tools: list of tool names that are included in the tool set. The tools can be built-in tools, MCP tools, or tools contributed by extensions.

description: brief description of the tool set. This description is displayed alongside the tool set name in the tools picker.

icon: icon for the tool set, values can be found in the Product Icon Reference.


{

  "reader": {

    "tools": [

      "changes",

      "codebase",

      "fetch",

      "findTestFiles",

      "githubRepo",

      "problems",

      "usages"

    ],

    "description": "description",

    "icon": "tag"

  }

}


Manage tool approvals

When a tool is invoked, Copilot requests confirmation to run the tool. This is because tools might run locally on your machine and perform actions that modify files or data.


In the Chat view, after a tool invocation, use the Continue button dropdown options to automatically confirm the specific tool for the current session, workspace, or all future invocations.


In case you want to auto-approve all tools, you can now use the experimental chat.tools.autoApprove setting. This will automatically approve all tool invocations, and VS Code will not ask for confirmation when a language model wishes to run tools. Bear in mind that with this setting enabled, you will not have the opportunity to cancel potentially destructive actions a model wants to take.


As an enhanced boundary, you might choose to set chat.tools.autoApprove only when connected to a remote environment. You'll want to set this as a remote, rather than user-level, setting. Note that remote environments that are part of your local machine (like dev containers) or that have access to your credentials will still pose different levels of risk.




How to use instructions to get AI edits that follow your coding style?

Use instructions to get AI edits that follow your coding style

To get AI-generated code edits that follow your coding style, preferred frameworks, and other preferences, you can use instruction files. Instruction files enable you to describe your coding style and preferences in Markdown files, which the AI uses to generate code edits that match your requirements.


You can manually attach instruction files as context to your chat prompt, or you can configure the instruction files to be automatically applied.

The following code snippet shows an example of an instruction file that describes your coding style and preferences:


---

applyTo: "**"

---

# Project general coding standards


## Naming Conventions

- Use PascalCase for component names, interfaces, and type aliases

- Use camelCase for variables, functions, and methods

- Prefix private class members with underscore (_)

- Use ALL_CAPS for constants


## Error Handling

- Use try/catch blocks for async operations

- Implement proper error boundaries in React components

- Always log errors with contextual information

Wednesday, June 25, 2025

Knowledge Graph, When generating the Nodes and relationship from passages, how to link them to the actual chunks from which these are extracted?

When using a Knowledge Graph (KG) for Retrieval Augmented Generation (RAG), getting the nodes is just the first step. The real power comes from being able to retrieve the original, relevant passages from your documents that back up the facts in your graph. This is crucial for providing the Large Language Model (LLM) with the rich context it needs to generate accurate and grounded answers.


When using a Knowledge Graph (KG) for Retrieval Augmented Generation (RAG), getting the nodes is just the first step. The real power comes from being able to retrieve the original, relevant passages from your documents that back up the facts in your graph. This is crucial for providing the Large Language Model (LLM) with the rich context it needs to generate accurate and grounded answers.


There are a few effective strategies to achieve this, ranging from simpler KG-only methods to more robust hybrid approaches:


When using a Knowledge Graph (KG) for Retrieval Augmented Generation (RAG), getting the nodes is just the first step. The real power comes from being able to retrieve the original, relevant passages from your documents that back up the facts in your graph. This is crucial for providing the Large Language Model (LLM) with the rich context it needs to generate accurate and grounded answers.


There are a few effective strategies to achieve this, ranging from simpler KG-only methods to more robust hybrid approaches:


Strategy 1: Store Content Directly on Paragraph/Chunk Nodes (Simpler KG-Only)

This is a straightforward approach where the actual text content of your document chunks is stored as a property on the Paragraph (or Chunk) nodes within your Neo4j graph.


How it works:


During Ingestion:


When you extract entities and relationships from a text chunk, you also create a Paragraph node for that chunk itself.

Store the page_content of the chunk as a property (e.g., content) on this Paragraph node.

Establish relationships from your extracted entities (like Concept, Person, Organization) back to the Paragraph node that mentions or discusses them (e.g., [:DISCUSSES], [:MENTIONED_IN]).

During Retrieval:


First, perform your multi-hop query on the Knowledge Graph to find the relevant entities and relationships.

As part of the same Cypher query, add a step to traverse from those relevant entities to the Paragraph nodes that are connected to them.

Retrieve the content property from these Paragraph nodes.

Example Cypher Modification for Retrieval:


MATCH (concept:Concept)<-[:DEVELOPED_BY]-(org:Organization)

WHERE org.name = 'Google'

RETURN concept.name AS ConceptDevelopedByGoogle


MATCH (concept:Concept)<-[:DEVELOPED_BY]-(org:Organization)

WHERE org.name = 'Google'

// Now, find paragraphs that discuss this concept

MATCH (p:Paragraph)-[:DISCUSSES]->(concept)

RETURN concept.name AS ConceptDevelopedByGoogle, COLLECT(DISTINCT p.content) AS RelevantPassages


Pros:


All data (structured facts and raw text) is in one place (Neo4j).

Simplifies initial setup if you're already ingesting into Neo4j.

Single query language (Cypher) for both relational facts and text retrieval.

Cons:


Performance and Scalability: Neo4j is optimized for graph traversals, not for storing and retrieving large amounts of raw text. Storing massive text content directly on nodes can lead to a larger database size and potentially slower performance for text-heavy operations if you have a very large corpus.

No Semantic Search on Text: You lose the benefit of vector similarity search on the raw text content itself. If a user asks a question that isn't directly answerable by the graph structure but requires semantic understanding of the passages, you can't easily retrieve relevant chunks based on similarity alone.


Strategy 2: Hybrid Approach (Knowledge Graph + Vector Database) - Recommended

This is generally considered the most robust and scalable approach for production-grade RAG systems. It leverages the strengths of both database types.


How it works:


Separate Storage:


Vector Database (e.g., ChromaDB, Pinecone, Weaviate): Store all your original document chunks here. Each chunk should have a unique identifier (e.g., a UUID or a simple chunk_id). Include useful metadata with each chunk (like document_title, section_title, order, etc.). The vector database is optimized for storing text and performing fast semantic similarity searches.

Knowledge Graph (Neo4j): Store your extracted entities and relationships.

Linking Mechanism:


When your LLM extracts a Concept (or Person, Technology, etc.) from a specific chunk, store the chunk_id (or a list of chunk_ids) as a property on the corresponding Concept node in your Neo4j graph. You can also create explicit relationships like (Concept)-[:MENTIONED_IN]->(ChunkNode) if you want ChunkNodes to be part of the graph (though often just storing the ID as a property is sufficient if the ChunkNode isn't heavily queried for graph traversals).

During Retrieval (RAG Workflow):


Step A: Structured Retrieval from KG:


Take the user's query and use it to formulate a multi-hop Cypher query on your Neo4j graph.

Retrieve the relevant structured facts (e.g., "Transformer architecture developed by Google") AND the chunk_ids associated with those facts/concepts.

Step B: Contextual Retrieval from Vector DB:


Use the retrieved chunk_ids (from Step A) to directly fetch the full, original textual content from your Vector Database.

Optionally, you can also perform a semantic similarity search on the Vector DB using the original user query (or a reformulated query) to get additional, semantically similar chunks that might not have been directly linked by the KG but are still relevant.

Step C: Augmentation for LLM:


Combine the structured facts from the KG (e.g., "Fact: Transformer architecture was developed by Google. Fact: GPT-3 is based on Transformer architecture.")

Concatenate the full, relevant passages retrieved from the Vector Database.

Pass this combined, rich context to your LLM prompt.



Pros:


Optimal Performance: Each database specializes in its strength (graph traversals for KG, semantic search for Vector DB).

Scalability: Can handle very large document corpora and complex knowledge graphs independently.

Flexibility: Allows for sophisticated RAG strategies, combining structured knowledge with unstructured text effectively.

Reduced Duplication: Core text content is stored once in the Vector DB.

Cons:


Increased Complexity: Requires managing and orchestrating two different database systems.

More Involved Workflow: The RAG retrieval pipeline has more steps.

Example Python Sketch for Hybrid Approach:


# (Assuming Neo4j setup as before, and a ChromaDB client initialized)

from langchain_community.vectorstores import Chroma

from langchain_core.documents import Document as LC_Document

import uuid # For unique chunk IDs


# --- Simulated Chunking and Ingestion into Vector DB ---

# In a real scenario, this would come from your document loader/splitter

simulated_chunks = [

    {

        "content": "The Transformer architecture was introduced in the paper 'Attention Is All You Need' by Google researchers.",

        "metadata": {"section": "Architectures", "doc_id": "doc_llm_overview"}

    },

    {

        "content": "Many modern LLMs, like GPT-3, are based on the Transformer architecture.",

        "metadata": {"section": "Architectures", "doc_id": "doc_llm_overview"}

    },

    # ... more chunks

]


# Simulate adding unique IDs and converting to LangChain Document format for Chroma

chroma_docs = []

for i, chunk_data in enumerate(simulated_chunks):

    chunk_id = f"chunk_{uuid.uuid4()}" # Generate a unique ID for each chunk

    chunk_data['metadata']['chunk_id'] = chunk_id # Add chunk_id to metadata

    chroma_docs.append(LC_Document(page_content=chunk_data['content'], metadata=chunk_data['metadata']))


# Initialize a dummy ChromaDB (replace with your actual Chroma client)

# For this example, we won't actually embed, just simulate storing and retrieving by ID

class DummyChromaDB:

    def __init__(self, documents):

        self.documents_by_id = {doc.metadata['chunk_id']: doc.page_content for doc in documents}

        self.metadata_by_id = {doc.metadata['chunk_id']: doc.metadata for doc in documents}


    def get_by_ids(self, ids):

        return {id: self.documents_by_id.get(id) for id in ids}


    def query(self, query_texts, n_results=2):

        # Simulate very basic semantic similarity search

        # In real Chroma, this would be a vector search

        results = []

        for doc_id, content in self.documents_by_id.items():

            if any(qt.lower() in content.lower() for qt in query_texts):

                results.append(LC_Document(page_content=content, metadata=self.metadata_by_id.get(doc_id)))

            if len(results) >= n_results:

                break

        return {"documents": [[doc.page_content for doc in results]], "metadatas": [[doc.metadata for doc in results]]}



vector_db = DummyChromaDB(chroma_docs)

print("Simulated Vector Database initialized with chunks.")


# --- Neo4j Ingestion (Modified to link Concepts to chunk_ids) ---

# ... (Neo4j driver and clear db part - same as previous example) ...


# Ingest data into Neo4j (UPDATED for chunk_ids)

# (Assume concepts_developed_by_google and model_based_on_concept are identified by LLM

#  from specific chunks)

# In a real scenario, your LLM extraction would produce `chunk_id` for each extracted entity

# For this example, we'll manually link:

chunk_id_for_transformer_google = simulated_chunks_with_ids[0]['id']

chunk_id_for_gpt3_transformer = simulated_chunks_with_ids[1]['id']



with driver.session() as session:

    # ... (ingest Document, Organization, Concepts as before) ...


    # Link Concepts to their originating chunk_ids (NEW STEP for Hybrid)

    # This stores the chunk ID on the concept node.

    session.run("""

        MATCH (c:Concept {name: 'Transformer architecture'})

        SET c.originatingChunkIds = CASE

                                    WHEN c.originatingChunkIds IS NULL THEN [$chunk_id]

                                    ELSE c.originatingChunkIds + $chunk_id

                                   END

        """, {"chunk_id": chunk_id_for_transformer_google})


    session.run("""

        MATCH (c:Concept {name: 'GPT-3'})

        SET c.originatingChunkIds = CASE

                                    WHEN c.originatingChunkIds IS NULL THEN [$chunk_id]

                                    ELSE c.originatingChunkIds + $chunk_id

                                   END

        """, {"chunk_id": chunk_id_for_gpt3_transformer})


    # ... (Ingest other relationships as before) ...

print("Neo4j data ingestion (with chunk_ids) complete.")


# --- RAG Workflow: Hybrid Retrieval ---

# User Query

user_query = "What concepts developed by Google are used as a basis for GPT-3 models? Provide details from the document."


# Step 1: Structured Retrieval from KG

target_developer = "Google"

target_user_model = "GPT-3"


kg_query = f"""

MATCH (concept:Concept)<-[:DEVELOPED_BY]-(org:Organization)

WHERE org.name = '{target_developer}'


MATCH (model:Concept)-[:BASED_ON]->(concept)

WHERE model.name = '{target_user_model}'


RETURN concept.name AS BridgingConcept, org.name AS Developer, model.name AS User, concept.originatingChunkIds AS ConceptChunkIds

"""


print(f"\n--- RAG Step 1: Querying Knowledge Graph ---\n{kg_query}")

kg_results = []

all_relevant_chunk_ids = set()


with driver.session() as session:

    result = session.run(kg_query)

    for record in result:

        kg_results.append({

            "BridgingConcept": record["BridgingConcept"],

            "Developer": record["Developer"],

            "User": record["User"]

        })

        if record["ConceptChunkIds"]:

            all_relevant_chunk_ids.update(record["ConceptChunkIds"])


print("\nKG Results (Structured Facts):")

for res in kg_results:

    print(f"- Concept: {res['BridgingConcept']}, Developer: {res['Developer']}, User: {res['User']}")

print(f"Relevant Chunk IDs from KG: {list(all_relevant_chunk_ids)}")



# Step 2: Contextual Retrieval from Vector DB

retrieved_passages = {}

if all_relevant_chunk_ids:

    # Retrieve specific passages identified by KG

    passages_by_id = vector_db.get_by_ids(list(all_relevant_chunk_ids))

    for chunk_id, content in passages_by_id.items():

        if content:

            retrieved_passages[chunk_id] = content

    print(f"\n--- RAG Step 2: Retrieving Specific Passages from Vector DB ---")

    print(f"Passages retrieved by KG-provided IDs: {len(retrieved_passages)} chunks")


# Optional: Add top N semantically similar passages (if not already retrieved by ID)

# This handles cases where the KG doesn't have a direct link but text is relevant

print("\n--- RAG Step 2 (Optional): Retrieving Semantically Similar Passages from Vector DB ---")

semantic_results = vector_db.query(query_texts=[user_query], n_results=2)

for doc_content in semantic_results["documents"][0]:

    # Only add if not already present from direct ID retrieval

    found = False

    for existing_passage in retrieved_passages.values():

        if doc_content == existing_passage: # Simple content match

            found = True

            break

    if not found:

        # In a real setup, you'd get the ID from metadata and add it

        # For this dummy, we just add content.

        retrieved_passages[f"semantic_chunk_{len(retrieved_passages)}"] = doc_content

        print(f"  Added semantically similar passage: \"{doc_content[:50]}...\"")


print(f"\nTotal passages for LLM: {len(retrieved_passages)} chunks")


# Step 3: Augment LLM Prompt

llm_context = ""

llm_context += "Here are structured facts from a knowledge graph:\n"

for res in kg_results:

    llm_context += f"- Concept: {res['BridgingConcept']}, Developed by: {res['Developer']}, Used by: {res['User']}\n"


llm_context += "\nHere are relevant document passages for context:\n"

for chunk_id, passage in retrieved_passages.items():

    llm_context += f"--- Passage {chunk_id} ---\n{passage}\n\n"


llm_context += f"Based on the above information, answer the following question: {user_query}"


print("\n--- RAG Step 3: Combined Context for LLM ---")

print(llm_context)


driver.close()


Summary and Recommendation:

For small, self-contained documents where text content is not excessively large and semantic search on raw text is not a primary concern, Strategy 1 (KG-only with content on Paragraph nodes) can work. It keeps everything in Neo4j and simplifies your toolchain.

For larger document corpuses, or when you need sophisticated semantic search capabilities, the Hybrid Approach (Strategy 2) is highly recommended. It separates concerns, leveraging vector databases for what they do best (text embeddings and similarity search) and knowledge graphs for their strength in structured data and relational querying. This combined power allows your RAG system to answer complex, multi-faceted questions with high accuracy and grounded responses.



Is Mongo Atlas Vector Search an alternative to Graph DB?

 Mongo Vector search, while they are excellent solutions for many RAG use cases and can significantly enhance retrieval, they generally do not fully replace the core strengths of a dedicated Knowledge Graph for all scenarios.


Let's break down where Mongo Atlas Vector Search excels and where a Knowledge Graph still holds a distinct advantage, especially concerning "multi-hop" or complex relational queries.


Where Mongo Atlas Vector Search Excels:


Unified Storage & Management: You store your raw document content, its metadata, and its vector embeddings all within a single database system. This simplifies your architecture, deployment, and operational overhead compared to managing separate vector stores and graph databases.


Hybrid Search Power: Mongo Atlas Vector Search allows you to combine:

Semantic Similarity Search: Finding documents or chunks whose vectors are close to your query vector.

Exact Keyword Matching: Filtering results based on specific terms in your text fields.

Metadata Filtering: Applying filters on indexed metadata fields (e.g., section: "Introduction", author: "John Doe", year: { $gt: 2020 }). This makes searches like "find documents about AI applications in the Healthcare section from 2023" very efficient.


Scalability & Reliability: As a managed service, Mongo Atlas handles horizontal scaling, sharding, backups, and high availability, making it suitable for large-scale production environments.


Developer Familiarity: For teams already familiar with MongoDB, it's a natural extension, leveraging existing skills and tooling.


Where Mongo Atlas Vector Search (and similar solutions) Still Falls Short of a Knowledge Graph:


The fundamental difference lies in how relationships are modeled and queried.


Native Multi-Hop Querying & Graph Traversal:


Knowledge Graph: A KG's primary purpose is to store and query relationships as first-class citizens. You define nodes (entities) and explicit, typed, directed relationships between them. Multi-hop queries are expressed declaratively (e.g., in Cypher or Gremlin) and executed extremely efficiently by graph-optimized algorithms. You can ask: "Show me all concepts DEVELOPED_BY 'Google' that are BASED_ON a Concept that is USED_BY 'GPT-3'." This is a single, direct traversal.


Mongo Atlas Vector Search: While you can store IDs of related documents in metadata (e.g., related_concepts_ids: ["concept_x_id", "concept_y_id"]), querying relationships deeper than one hop requires multiple, sequential database calls and application-level joins.


To answer the multi-hop query above, you'd need to:

Query for Concept documents where developer_org_id is Google's ID. Get their concept_ids.

Take those concept_ids and query for Concept documents where based_on_concept_id is one of the previous IDs. Get those concept_ids.

Take those concept_ids and query for Concept documents where used_by_model_id is one of those IDs.


This iterative process is complex, inefficient, and difficult to generalize for arbitrary depth or new relationship types. MongoDB's $lookup aggregation stage can perform joins, but it's not optimized for arbitrary-depth graph traversals and can become very inefficient for more than a few hops.


Relationship as First-Class Citizens:


Knowledge Graph: Relationships have types and can have properties (e.g., (Document)-[:HAS_SECTION {order: 1}]->(Section)). You can query about relationships themselves.

Mongo Atlas Vector Search: Relationships are implied by IDs stored in document fields or by metadata values. They are not traversable entities with their own properties. Querying "what types of relationships exist between X and Y?" is not native.


Inference and Reasoning:


Knowledge Graph: KGs, especially when combined with ontological models or reasoning engines, are powerful for inferring new facts from existing relationships (e.g., if A is a PART_OF B, and B is a PART_OF C, then A is implicitly PART_OF C).

Mongo Atlas Vector Search: No native reasoning capabilities. All "inferences" must be explicitly pre-calculated and stored as data, or handled in application logic.



Data Modeling Expressiveness for Interconnected Data:


Knowledge Graph: Inherently designed for highly interconnected data. It excels at representing complex networks where the connections are as important as the nodes themselves.

Mongo Atlas Vector Search: While flexible, it's fundamentally a document database. Representing dense, arbitrary, and deep networks of relationships can lead to heavily embedded documents, redundancy, or complex application-level data management.



Visualization and Exploration:


Knowledge Graph: Graph visualization tools allow intuitive exploration of relationships, making complex knowledge bases understandable.

Mongo Atlas Vector Search: While you can retrieve documents, visualizing the network of implied relationships from metadata requires custom application development.



When to Choose Which:

Choose Mongo Atlas Vector Search (or similar hybrid vector DB):


Your primary need is semantic search with powerful filtering across your document chunks.

Most of your queries involve retrieving relevant passages based on content and direct metadata.

"Relationships" are mostly one-hop (e.g., "give me documents by this author" or "in this section").

You want a unified, simpler operational stack for RAG.

The "knowledge" is largely contained within individual chunks or simple direct links, rather than in deep, transitive relationships between entities.


Choose a Knowledge Graph (e.g., Neo4j) (potentially in conjunction with a Vector DB):


Your core problem involves understanding and querying complex, indirect, multi-hop relationships between disparate entities (e.g., "Find all papers that cited a research group which collaborated with a company that developed this technology").

You need to reason over interconnected facts and infer new knowledge.

The relationships themselves carry significant meaning and are central to your queries.

You need to build a rich, interconnected map of your domain knowledge that goes beyond simple document attributes.

You want visual exploration of complex relationships.


Conclusion:

Mongo Atlas Vector Search is a fantastic and powerful evolution for RAG, bridging the gap between semantic search and structured filtering. For many, many use cases, it will be perfectly sufficient and a great choice.


However, it is not a direct replacement for a Knowledge Graph when the complexity lies in the depth and interconnectedness of relationships rather than just the content of individual documents. If your questions truly demand multi-hop traversals, inference, and understanding of a complex network of facts, a dedicated Knowledge Graph remains the superior tool. Often, the most robust RAG systems leverage both – a vector database for semantic chunk retrieval and a knowledge graph for structured knowledge and relational reasoning.


Tuesday, June 24, 2025

What is Lyria?


Lyria 2 delivers high-fidelity music and professional-grade audio, capturing subtle nuances across a range of genres and intricate compositions.


Lyria 2 is an advanced AI model, developed with input and insights from musicians and producers. Artists can use text prompts to shape the music, while controlling the key, BPM, and other characteristics.


High-fidelity music


Generates music with remarkable detail and richness, capturing nuance across different instruments and playing styles. Produces professional-grade 48kHz stereo audio, ready for seamless integration into any project.


Granular creative control


Allows musicians to control fine details within their compositions, so they can create pieces that match their intent and vision.


Diverse musical possibilities


Allows composition across a wide range of genres and styles. Classical, jazz, pop, electronic — musicians can steer compositions towards their tastes, and explore diverse musical ideas along the way.


references:

https://deepmind.google/models/lyria/



Good ADK first time setup

 


python -m venv .venv

source .venv/bin/activate

pip install google-adk



mkdir agentic-apps

mkdir renovation-agent

renovation-agent/

        __init__.py

        agent.py

        requirements.txt

        .env



The agent code is from https://github.com/AbiramiSukumaran/adk-renovation-single-agent/blob/main/agent.py

A storage bucket to be created https://cloud.google.com/storage/docs/creating-buckets#console


Single agent System Source Code Explanation

The agent.py file defines the structure and behavior of our kitchen renovation multi-agent system using the Agent Development Kit (ADK). Let's break down the key components:


Agent Definition

Root Agent (Orchestrator): proposal_agent

The root_agent acts as the orchestrator of this single-agent system. It receives the initial renovation request and determines which tools to invoke based on the request's needs.


The root_agent then collects the responses from the tools and combines them to provide a comprehensive response to the user. In this case we just have one tool "store_pdf".


7. Data Flow & Key Concepts

The user initiates a request through the ADK interface (either the terminal or the web UI).


The request is received by the root_agent.

The root_agent analyzes the request and routes it to the tool as and when required.

The tool "store_pdf" is designed to write the renovated text content to a PDF file, then upload it to Google Cloud Storage.

This then returns the response to the root_agent.

The root_agent combines the responses and provides a final output to the user.

LLMs (Large Language Models)


The agents rely heavily on LLMs to generate text, answer questions, and perform reasoning tasks. The LLMs are the "brains" behind the agents' ability to understand and respond to user requests. We are using Gemini 2.5 in this application.


Google Cloud Storage


Used to store the generated renovation proposal documents. You need to create a bucket and grant the necessary permissions for the agents to access it.


Cloud Run (Optional)


The OrderingAgent uses a Cloud Run function to interface with AlloyDB. Cloud Run provides a serverless environment to execute code in response to HTTP requests.


AlloyDB


If you're using the OrderingAgent, you'll need to set up an AlloyDB database to store order information.


.env file


The .env file stores sensitive information like API keys, database credentials, and bucket names. It's crucial to keep this file secure and not commit it to your repository. It also stores configuration settings for the agents and your Google Cloud project. The root_agent or supporting functions will typically read values from this file. Make sure all required variables are properly set in the .env file. This includes the Cloud Storage bucket name


Your agent's ability to understand user requests and generate responses is powered by a Large Language Model (LLM). Your agent needs to make secure calls to this external LLM service, which requires authentication credentials. Without valid authentication, the LLM service will deny the agent's requests, and the agent will be unable to function.


Get an API key from Google AI Studio.

In the next step where you set up the .env file, replace <<your API KEY>> with your actual API KEY value.



GOOGLE_GENAI_USE_VERTEXAI=FALSE

GOOGLE_API_KEY=<<your API KEY>>

GOOGLE_CLOUD_LOCATION = us-central1 <<or your region>>

GOOGLE_CLOUD_PROJECT = <<your project id>>

PROJECT_ID = <<your project id>>

GOOGLE_CLOUD_REGION=us-central1 <<or your region>>

STORAGE_BUCKET = next-demo-store <<or your storage bucket name>>



cd agentic-apps/renovation-agent

pip install -r requirements.txt

adk run .

adk web

user>> 


Hello. Generate Proposal Document for the kitchen remodel requirement in a proper format that applies to a renovation contract. Remember this text will eventually be stored as a pdf file so make sure to have the formatting appropriate. I have no other specification.

references:

https://codelabs.developers.google.com/your-first-agent-with-adk#10

What is Gremlin

Gremlin is a graph traversal language and machine developed by Apache TinkerPop. It's used to navigate and query relationships within graph databases, allowing users to explore complex connections and perform advanced operations. Essentially, it's a way to interact with and analyze data organized as a graph, where data points are nodes and their connections are edges


Here's a more detailed explanation:

1. Graph Traversal Language: Gremlin is a functional, data-flow language that allows users to express complex traversals (queries) on a property graph. It's designed to be flexible and compatible with various graph databases that support the Apache TinkerPop framework. 


Key Concepts:

Nodes (Vertices): Represent individual data points or entities within the graph. 

Edges: Represent relationships between nodes, indicating how they are connected. 

Traversals: Sequences of steps that navigate through the graph, following edges and filtering data based on specific criteria. 


3. How it works: Gremlin uses a set of instructions (steps) that tell the traversal machine how to move through the graph. These instructions can include steps to: 

Move between nodes: Follow specific types of edges.

Filter data: Select nodes or edges based on properties or other criteria.

Aggregate results: Calculate statistics or summaries from the traversal.


4. Example: A Gremlin query might look like this: g.V().has('name', 'John').out('knows').in('created').values('title'). This query does the following: 

Starts at a vertex (node) with the name 'John'.

Follows outgoing edges labeled 'knows'.

Follows incoming edges labeled 'created'.

Retrieves the 'title' property of the resulting vertices.


5. Benefits:

Flexibility:

Gremlin allows for diverse and complex graph traversals, making it suitable for various applications. 

Compatibility:

It works with different graph databases, promoting portability and reducing vendor lock-in. 

Expressiveness:

It enables users to write concise and efficient queries for exploring relationships in graph data. 

In essence, Gremlin is a powerful tool for working with graph data, enabling users to explore, analyze, and manipulate complex relationships within their data models.