Pesquisar

Artigo
· 4 hr atrás 9min de leitura

使用 InterSystems IRIS 的动态和嵌入式 SQL

大家好!

在本文中,我们将在 InterSystems IRIS 的背景下探讨动态 SQL(Dynamic SQL嵌入式 SQL(Embedded SQL ) 的概念,提供实际示例, 研究 它们的区别 ,以帮助您了解如何在应用程序中利用它们。

InterSystems SQL 提供全套标准关系功能,包括定义表模式、执行查询、定义和执行存储过程。您可以通过管理门户交互式地执行 InterSystems SQL,也可以使用 SQL shell 界面以编程方式执行 InterSystems SQL。嵌入式 SQL 使您可以在 ObjectScript 代码中嵌入 SQL 语句,而动态 SQL 使您可以在运行时从 ObjectScript 执行动态 SQL 语句。 静态 SQL 查询提供可预测的性能,而动态和嵌入式 SQL 则分别提供灵活性和集成性。

SQL

动态 SQL 是指在运行时构建和执行的 SQL 语句,而静态 SQL 是预先定义并直接嵌入到应用程序代码中的。当查询结构事先不知道或需要根据用户输入或应用程序逻辑进行动态调整时,动态 SQL 尤其有用。

在 InterSystems IRIS 中,动态 SQL 通过 %SQL.Statement 类实现,该类提供了动态准备和执行 SQL 语句的方法。

动态 SQL 的主要优势

  1. 灵活性:动态 SQL 允许以编程方式建立查询,因此非常适合具有复杂或不断变化要求的应用程序。
  2. 适应性强:您可以根据运行时条件(如用户输入或应用程序状态)修改查询。
  3. 临时查询:如果应用程序需要根据用户输入生成自定义查询,动态 SQL 允许在运行时构建这些查询。
  4. 复杂连接和条件:在连接或条件的数量会根据数据发生变化的情况下,动态 SQL 可以构建复杂的查询。


实际案例

1. 动态表创建:快速构建数据库模式

该示例演示了如何使用 InterSystems Dynamic SQL 在运行时动态创建表,从而实现灵活、自适应的数据库模式管理。

ClassMethod CreateDynamicTable(tableName As %String, columns As %String) As %Status
{
    // Construct sql text
    Set sql = "CREATE TABLE " _ tableName _ " (" _ columns _ ")"
    //Create an instance of %SQL.Statement
    Set statement = ##class(%SQL.Statement).%New()
    //Prepare the query
    Set status = statement.%Prepare(sql)
    If $$$ISERR(status) {
        Quit status
    }
    //Execute the query
    Set result = statement.%Execute()
    //Check for errors
    If result.%SQLCODE = 0 {
        Write "Table created successfully!", !
    } Else {
        Write "Error: ", result.%SQLCODE, " ", result.%SQLMSG, !
    }
    Quit $$$OK
}

调用方法

USER>do ##class(dc.DESql).CreateDynamicTable("Books","BookID NUMBER NOT NULL,Title VARCHAR(100),Author VARCHAR(300),PublicationYear  NUMBER NULL, AvailableFlag  BIT")

输出


2. 动态表搜索:使用用户定义的过滤器查询数据

本示例说明如何根据用户定义的条件执行动态表搜索,从而实现灵活、可调整的查询。

ClassMethod DynamicSearchPerson(name As %String = "", age As %Integer = "") As %Status
{
    // Create an instance of %SQL.Statement
    set stmt = ##class(%SQL.Statement).%New()

    // Base query
    set query = "SELECT ID, Name, Age, DOB FROM Sample.Person"
    // Add conditions based on input parameters
    if name '= "" {
        set query = query _ " WHERE Name %STARTSWITH ?"
    }
    if (age '= "") && (name '= "") {
        set query = query _ " AND Age = ?"
    }
    if (age '= "") && (name = "") {
        set query = query _ " WHERE Age = ?"
    }
    
    // Prepare the query
    set status = stmt.%Prepare(query)
    if $$$ISERR(status) {
        do $System.Status.DisplayError(status)
        quit status
    }
   
    // Execute the query with parameters
    if (age '= "") && (name '= "") {
        set rset = stmt.%Execute(name, age)
    }
    if (age '= "") && (name = "") {
        set rset = stmt.%Execute(age)
    }
    if (age = "") && (name '= "") {
        set rset = stmt.%Execute(name)
    }

    // Display results
    while rset.%Next() {
        write "ID: ", rset.ID, " Name: ", rset.Name, " Age: ", rset.Age,  !
    }

    quit $$$OK
}

调用方法

do ##class(dc.DESql).DynamicSearchPerson("Y",67)

 

    输出


        3. 动态透视表:转换数据以获得分析见解

        该示例展示了如何使用 InterSystems Dynamic SQL 动态生成数据透视表,将原始数据转换为结构化摘要。

        ClassMethod GeneratePivotTable(tableName As %String, rowDimension As %String, columnDimension As %String, valueColumn As %String) As %Status
        {
            // Simplified example; real pivot tables can be complex
            Set sql = "SELECT " _ rowDimension _ ", " _ columnDimension _ ", SUM(" _ valueColumn _ ") FROM " _ tableName _ " GROUP BY " _ rowDimension _ ", " _ columnDimension
            //Create an instance of %SQL.Statement
            Set statement = ##class(%SQL.Statement).%New()
            // Prepare the query
            Set status = statement.%Prepare(sql)
           
            If $$$ISERR(status) {
                Quit status
            }
            // Execute the query
            Set result = statement.%Execute()
            // Check for errors
            If result.%SQLCODE = 0 {
                While result.%Next() {
                    do result.%Display()
                }
            } Else {
                Write "Error: ", result.%SQLCODE, " ", result.%SQLMSG, !
            }
            Quit $$$OK
        }

        调用方法

        Do ##class(dc.DESql).GeneratePivotTable("Sales", "Region", "ProductCategory", "Revenue")

        输出

        4. 模式探索:使用动态 SQL 解锁数据库元数据

        本示例演示如何动态探索和检索数据库模式的元数据,从而深入了解表结构和列定义。

        ClassMethod ExploreTableSchema(tableName As %String) As %Status
        {
            // Create a new SQL statement object
            set stmt = ##class(%SQL.Statement).%New()
            
            // Construct the query dynamically
            set sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA||'.'||TABLE_NAME = ?"
            // Prepare the query
            set status = stmt.%Prepare(sql)
            if $$$ISERR(status) {
                do $System.Status.DisplayError(status)
                quit status
            }
           
            // Execute the query
            set result = stmt.%Execute(tableName)
            
            // Display schema information
            write !, "Schema for Table: ", tableName
            write !, "-------------------------"
            write !, "Column Name",?15, "Data Type", ?30, "Nullable ",?45,"Column#"
            write !, "-------------------------"
            while result.%Next() {
                
                write !, result.%Get("COLUMN_NAME"),?15, result.%Get("DATA_TYPE"), ?30,  result.%Get("IS_NULLABLE"), ?45,result.%Get("ORDINAL_POSITION") 
                
            }
            
            quit $$$OK
        }
        

        调用方法

        Do ##class(dc.DESql).ExploreTableSchema("Sample.Person")

        输出

        嵌入式 SQL

        嵌入式 SQL 是一种在编程语言(这里指 ObjectScript 或其他 InterSystems 兼容语言)中直接包含 SQL 语句的方法。在编译包含嵌入式 SQL 的例程时,不会编译嵌入式 SQL。当与 InterSystems IRIS 的对象访问功能结合使用时,嵌入式 SQL 的编译将非常强大。

        您可以在 InterSystems IRIS® 数据平台使用的 ObjectScript 代码中嵌入 SQL 语句。嵌入式 SQL 特别适用于执行查询、插入、更新和删除记录等数据库操作。

        嵌入式 SQL 有两种:

        • 简单的嵌入式 SQL 查询只能从单行中返回值。简单嵌入式 SQL 也可用于单行插入、更新和删除以及其他 SQL 操作。
        • 基于游标的嵌入式 SQL 查询可以遍历查询结果集,返回多行的值。基于游标的嵌入式 SQL 也可用于多行更新和删除 SQL 操作。

        嵌入式 SQL 的主要优势

        1. 无缝集成:嵌入式 SQL 允许您直接在 ObjectScript 代码中编写 SQL 语句,无需外部调用或复杂的接口。
        2. 性能:通过在 ObjectScript 中嵌入 SQL,您可以优化数据库交互并减少开销。
        3. 简单:嵌入式 SQL 可简化数据库工作流程,因为它无需单独的 SQL 脚本或外部工具。
        4. 错误处理:嵌入式 SQL 允许更好地处理错误,因为 SQL 代码是应用程序逻辑的一部分。

        实际案例

        1. 记录创建:使用嵌入式 SQL 插入数据

        本示例演示如何使用嵌入式 SQL 向表中插入新记录,确保无缝数据集成。

        ClassMethod AddBook(bookID As %Integer, title As %String, author As %String, year As %Integer, available As %Boolean) As %Status
        {
            // Embedded SQL to insert a new book
            &sql(
                INSERT INTO SQLUser.Books (BookID, Title, Author, PublicationYear, AvailableFlag)
                VALUES (:bookID, :title, :author, :year, :available)
            )
        
            // Check for errors
            if SQLCODE '= 0 {
                write "Error inserting book: ", %msg, !
                quit $$$ERROR($$$GeneralError, "Insert failed")
            }
        
            write "Book added successfully!", !
            quit $$$OK
        }
        

        调用方法

        Do ##class(dc.DESql).AddBook(1,"To Kill a Mockingbird","Harper Lee", 1960,1)

        输出

        2. Data Retrieval(数据检索):使用嵌入式 SQL 获取和显示记录

        此示例使用嵌入式 SQL 从数据库中获取图书列表,展示了如何高效地获取和显示数据。

        ClassMethod ListBooks()
        {
            // Embedded SQL to query books
            &sql(
                DECLARE BookCursor CURSOR FOR
                SELECT BookID, Title, Author, PublicationYear, AvailableFlag
                FROM SQLUser.Books
                WHERE AvailableFlag = 1
            )
        
            // Open the cursor
            &sql(OPEN BookCursor)
        
            // Fetch and display results
            for {
                &sql(FETCH BookCursor INTO :bookID, :title, :author, :year, :available)
                quit:(SQLCODE '= 0)
        
                write "Book ID: ", bookID, !
                write "Title: ", title, !
                write "Author: ", author, !
                write "Publication Year: ", year, !
                write "Available: ", available, !
                write "-----------------------------", !
            }
        
            // Close the cursor
            &sql(CLOSE BookCursor)
        }

        调用方

        Do ##class(dc.DESql).ListBooks()

        输出

        3. 事务管理:使用嵌入式 SQL 确保数据完整性

        本示例演示了如何使用嵌入式 SQL 管理数据库事务,确保资金转移过程中的数据完整性。

        ClassMethod TransferFunds(fromAccount As %Integer, toAccount As %Integer, amount As %Decimal) As %Status
        {
            // Start a transaction
            TSTART
            // Deduct amount from the source account
            &sql(UPDATE Accounts
                 SET Balance = Balance - :amount
                 WHERE AccountID = :fromAccount)
            
            if SQLCODE '= 0 {
                TROLLBACK
                quit $$$ERROR($$$GeneralError, "Failed to deduct amount from source account.")
            }
            
            // Add amount to the destination account
            &sql(UPDATE Accounts
                 SET Balance = Balance + :amount
                 WHERE AccountID = :toAccount)
            
            if SQLCODE '= 0 {
                TROLLBACK
                quit $$$ERROR($$$GeneralError, "Failed to add amount to destination account.")
            }
            
            // Commit the transaction
            TCOMMIT
            write !, "Funds transferred successfully."
            quit $$$OK
        }

        调用方法

        do ##class(MyApp.FundManager).TransferFunds(101, 102, 500.00)

        输出

        4. 验证用户名可用性

        此示例通过查询数据库确保用户名不存在,从而检查用户名是否可用。

        ClassMethod ValidateUserName(username As %String) As %Boolean
        {
            // Embedded SQL to check if the username exists
            &sql(SELECT COUNT(*) INTO :count
                 FROM SQLUser.Users
                 WHERE Name = :username)
            //Check for errors
            if SQLCODE = 0 {
                if count > 0 {
                    write !, "Username already exists."
                    quit 0
                } else {
                    write !, "Username is available."
                    quit 1
                }
            } else {
                write !, "Error validating username: ", %msg
                quit 0
            }
        }

        调用方法

        Do ##class(dc.DESql).ValidateUserName("Admin")

        输出

         

        动态 SQL 与嵌入式 SQL 的比较

        结论

        动态 SQL 和嵌入式 SQL 是 InterSystems IRIS 中的强大工具,可满足不同的使用情况。动态 SQL 为运行时查询构建提供了灵活性,而嵌入式 SQL 则为静态查询提供了性能优势。通过了解它们的优势并将其有效结合,您可以在 InterSystems IRIS 平台上构建强大而高效的应用程序。

        感谢阅读!

        Discussão (0)1
        Entre ou crie uma conta para continuar
        Anúncio
        · 9 hr atrás

        [Video] Inside Vector Search - Technical Innovations In InterSystems IRIS

        Hey Developers,

        Enjoy the new video on InterSystems Developers YouTube

        ⏯  Inside Vector Search - Technical Innovations In InterSystems IRIS @ READY 2025

        In this 20-minute technical session, we’ll skip the basics and dive into the InterSystems IRIS-specific innovations behind our Vector Search and Retrieval-Augmented Generation (RAG) capabilities. Instead of a general introduction to RAG, we’ll explore deeper technical elements—including our implementation of HNSW indexing, the EMBEDDING datatype, and advanced techniques like deferred indexing and smart chunking strategies. Join us for a behind-the-scenes look at how these innovations tackle common LLM challenges and deliver robust, under-the-hood performance — offering a unique, below-the-SQL-surface perspective on what powers InterSystems IRIS.

        🗣 Presenter: @Boya Song, Senior Systems Developer at InterSystems

        Curious about how this works? Watch the video and subscribe to learn more!👍

        Discussão (0)1
        Entre ou crie uma conta para continuar
        Artigo
        · 10 hr atrás 5min de leitura

        Unveiling the LangGraph

        How to Build Applications with LangGraph: A Step-by-Step Guide

        Tags: #LangGraph #LangChain #AI #Agents #Python #LLM #StateManagement #Workflows


        Hi everyone, I want to tell you a little about LangGraph, a tool that I'm studying and developing.

        Basically traditional AI applications often face challenges when dealing with complex workflows and dynamic states. LangGraph offers a robust solution, enabling the creation of stateful agents that can manage complex conversations, make context-based decisions, and execute sophisticated workflows.

        This article provides a step-by-step guide to building applications using LangGraph, a framework for creating multi-step agents with state graphs.


        Implementation Steps:

        1. Set Up Environment and Install Dependencies
        2. Define Application State
        3. Create Graph Nodes
        4. Configure State Graph
        5. Run the Agent

        1. Set Up Environment and Install Dependencies

        The first step is to set up the Python environment and install the necessary libraries:

        pip install langgraph langchain langchain-openai
        

        Configure your API credentials:

        import os
        from langchain_openai import ChatOpenAI
        
        # Configure your API Key
        os.environ["OPENAI_API_KEY"] = "your-api-key-here"
        
        # Initialize the model
        llm = ChatOpenAI(model="gpt-4", temperature=0)
        

        2. Define Application State

        LangGraph uses a TypedDict to define the state that will be shared between graph nodes:

        from typing import TypedDict, Annotated
        from operator import add
        
        class AgentState(TypedDict):
            """State shared between graph nodes"""
            messages: Annotated[list, add]
            user_input: str
            response: str
            next_step: str
        

        This state stores:

        • messages: History of exchanged messages
        • user_input: Current user input
        • response: Response generated by the agent
        • next_step: Next action to be executed

        Graph State


        3. Create Graph Nodes

        3.1 - Input Processing Node

        This node processes user input and prepares the context:

        def process_input(state: AgentState) -> AgentState:
            """Processes user input"""
            user_message = state["user_input"]
            
            # Add message to history
            state["messages"].append({
                "role": "user",
                "content": user_message
            })
            
            # Define next step
            state["next_step"] = "analyze"
            
            return state
        

        3.2 - Analysis and Decision Node

        This node uses the LLM to analyze input and decide the next action:

        from langchain.prompts import ChatPromptTemplate
        
        def analyze_request(state: AgentState) -> AgentState:
            """Analyzes the request and decides the next action"""
            
            prompt = ChatPromptTemplate.from_messages([
                ("system", "You are an intelligent assistant. Analyze the user's request and determine the best way to respond."),
                ("user", "{input}")
            ])
            
            chain = prompt | llm
            
            result = chain.invoke({
                "input": state["user_input"]
            })
            
            state["response"] = result.content
            state["next_step"] = "respond"
            
            return state
        

        3.3 - Response Node

        This node formats and returns the final response:

        def generate_response(state: AgentState) -> AgentState:
            """Generates the final response"""
            
            # Add response to history
            state["messages"].append({
                "role": "assistant",
                "content": state["response"]
            })
            
            state["next_step"] = "END"
            
            return state
        

        4. Configure State Graph

        4.1 - Create the Graph

        Now let's connect all nodes in a state graph:

        from langgraph.graph import StateGraph, END
        
        # Create the graph
        workflow = StateGraph(AgentState)
        
        # Add nodes
        workflow.add_node("process_input", process_input)
        workflow.add_node("analyze", analyze_request)
        workflow.add_node("respond", generate_response)
        
        # Define entry point
        workflow.set_entry_point("process_input")
        
        # Add transitions (edges)
        workflow.add_edge("process_input", "analyze")
        workflow.add_edge("analyze", "respond")
        workflow.add_edge("respond", END)
        
        # Compile the graph
        app = workflow.compile()
        

        4.2 - Visualize the Graph

        LangGraph allows you to visualize the graph structure:

        from IPython.display import Image, display
        
        try:
            display(Image(app.get_graph().draw_mermaid_png()))
        except Exception:
            print("Graph visualization requires additional dependencies")
        

        Graph Flow


        5. Run the Agent

        5.1 - Execute a Simple Query

        def run_agent(user_input: str):
            """Runs the agent with user input"""
            
            # Initial state
            initial_state = {
                "messages": [],
                "user_input": user_input,
                "response": "",
                "next_step": ""
            }
            
            # Execute the graph
            result = app.invoke(initial_state)
            
            return result["response"]
        
        # Test the agent
        response = run_agent("What is the capital of France?")
        print(f"Response: {response}")
        

        Expected output:

        Response: The capital of France is Paris.
        

        5.2 - Execute with Streaming

        For interactive applications, you can use streaming:

        async def run_agent_stream(user_input: str):
            """Runs the agent with streaming"""
            
            initial_state = {
                "messages": [],
                "user_input": user_input,
                "response": "",
                "next_step": ""
            }
            
            async for event in app.astream(initial_state):
                for node_name, node_state in event.items():
                    print(f"\n--- {node_name} ---")
                    if "response" in node_state and node_state["response"]:
                        print(f"Partial response: {node_state['response']}")
        

        Advanced Features

        Checkpoints and Persistence

        LangGraph supports checkpoints to save state:

        from langgraph.checkpoint.memory import MemorySaver
        
        # Add memory to the graph
        memory = MemorySaver()
        app_with_memory = workflow.compile(checkpointer=memory)
        
        # Execute with persistence
        config = {"configurable": {"thread_id": "user-123"}}
        result = app_with_memory.invoke(initial_state, config)
        

        Conditions and Dynamic Routing

        You can add conditional logic for routing:

        def router(state: AgentState) -> str:
            """Determines the next node based on state"""
            
            if "urgent" in state["user_input"].lower():
                return "priority_handler"
            else:
                return "normal_handler"
        
        # Add conditional routing
        workflow.add_conditional_edges(
            "analyze",
            router,
            {
                "priority_handler": "priority_node",
                "normal_handler": "normal_node"
            }
        )
        

        Use Cases

        LangGraph is ideal for:

        1. Complex Chatbots: Managing multi-turn conversations with context
        2. Autonomous Agents: Creating agents that make state-based decisions
        3. Processing Workflows: Orchestrating data processing pipelines
        4. Multi-Agent Systems: Coordinating multiple specialized agents

        See It in Action

        For more details and practical examples, visit:


        Conclusion

        LangGraph offers a powerful and flexible approach to building stateful AI applications. By combining state graphs with LLMs, you can create sophisticated systems that manage complex conversations, make contextual decisions, and execute dynamic workflows.

        LangGraph's modular structure allows you to scale from simple chatbots to complex multi-agent systems while keeping your code organized and maintainable.

         

        Thanks!


        Discussão (0)1
        Entre ou crie uma conta para continuar
        Artigo
        · 10 hr atrás 6min de leitura

        Desvendando o LangGraph

        Como Construir Aplicações com LangGraph: Um Guia Passo a Passo

        Tags: #LangGraph #LangChain #AI #Agents #Python #LLM #StateManagement #Workflows


        Olá pessoal, quero trazer para vocês aqui um pouco sobre o LangGraph, uma ferramenta que estou estudando e desenvolvendo.

        Basicamente aplicações tradicionais de IA frequentemente enfrentam desafios ao lidar com fluxos de trabalho complexos e estados dinâmicos. O LangGraph oferece uma solução robusta, permitindo criar agentes com estado que podem gerenciar conversas complexas, tomar decisões baseadas em contexto e executar workflows sofisticados.

        Este artigo fornece um guia passo a passo para construir aplicações utilizando LangGraph, um framework para criação de agentes multi-etapas com grafos de estado.


        Passos de Implementação:

        1. Configurar o Ambiente e Instalar Dependências
        2. Definir o Estado da Aplicação
        3. Criar os Nós do Grafo
        4. Configurar o Grafo de Estado
        5. Executar o Agente

        1. Configurar o Ambiente e Instalar Dependências

        O primeiro passo é configurar o ambiente Python e instalar as bibliotecas necessárias:

        pip install langgraph langchain langchain-openai
        

        Configure suas credenciais de API:

        import os
        from langchain_openai import ChatOpenAI
        
        # Configure sua API Key
        os.environ["OPENAI_API_KEY"] = "sua-api-key-aqui"
        
        # Inicialize o modelo
        llm = ChatOpenAI(model="gpt-4", temperature=0)
        

        2. Definir o Estado da Aplicação

        O LangGraph utiliza um TypedDict para definir o estado que será compartilhado entre os nós do grafo:

        from typing import TypedDict, Annotated
        from operator import add
        
        class AgentState(TypedDict):
            """Estado compartilhado entre os nós do grafo"""
            messages: Annotated[list, add]
            user_input: str
            response: str
            next_step: str
        

        Este estado armazena:

        • messages: Histórico de mensagens trocadas
        • user_input: Entrada atual do usuário
        • response: Resposta gerada pelo agente
        • next_step: Próxima ação a ser executada

        Estado do Grafo


        3. Criar os Nós do Grafo

        3.1 - Nó de Processamento de Entrada

        Este nó processa a entrada do usuário e prepara o contexto:

        def process_input(state: AgentState) -> AgentState:
            """Processa a entrada do usuário"""
            user_message = state["user_input"]
            
            # Adiciona a mensagem ao histórico
            state["messages"].append({
                "role": "user",
                "content": user_message
            })
            
            # Define próximo passo
            state["next_step"] = "analyze"
            
            return state
        

        3.2 - Nó de Análise e Decisão

        Este nó utiliza o LLM para analisar a entrada e decidir a próxima ação:

        from langchain.prompts import ChatPromptTemplate
        
        def analyze_request(state: AgentState) -> AgentState:
            """Analisa a requisição e decide a próxima ação"""
            
            prompt = ChatPromptTemplate.from_messages([
                ("system", "Você é um assistente inteligente. Analise a requisição do usuário e determine a melhor forma de responder."),
                ("user", "{input}")
            ])
            
            chain = prompt | llm
            
            result = chain.invoke({
                "input": state["user_input"]
            })
            
            state["response"] = result.content
            state["next_step"] = "respond"
            
            return state
        

        3.3 - Nó de Resposta

        Este nó formata e retorna a resposta final:

        def generate_response(state: AgentState) -> AgentState:
            """Gera a resposta final"""
            
            # Adiciona resposta ao histórico
            state["messages"].append({
                "role": "assistant",
                "content": state["response"]
            })
            
            state["next_step"] = "END"
            
            return state
        

        4. Configurar o Grafo de Estado

        4.1 - Criar o Grafo

        Agora vamos conectar todos os nós em um grafo de estado:

        from langgraph.graph import StateGraph, END
        
        # Criar o grafo
        workflow = StateGraph(AgentState)
        
        # Adicionar os nós
        workflow.add_node("process_input", process_input)
        workflow.add_node("analyze", analyze_request)
        workflow.add_node("respond", generate_response)
        
        # Definir o ponto de entrada
        workflow.set_entry_point("process_input")
        
        # Adicionar as transições (edges)
        workflow.add_edge("process_input", "analyze")
        workflow.add_edge("analyze", "respond")
        workflow.add_edge("respond", END)
        
        # Compilar o grafo
        app = workflow.compile()
        

        4.2 - Visualizar o Grafo

        O LangGraph permite visualizar a estrutura do grafo:

        from IPython.display import Image, display
        
        try:
            display(Image(app.get_graph().draw_mermaid_png()))
        except Exception:
            print("Visualização do grafo requer dependências adicionais")
        

        Fluxo do Grafo


        5. Executar o Agente

        5.1 - Executar uma Consulta Simples

        def run_agent(user_input: str):
            """Executa o agente com a entrada do usuário"""
            
            # Estado inicial
            initial_state = {
                "messages": [],
                "user_input": user_input,
                "response": "",
                "next_step": ""
            }
            
            # Executar o grafo
            result = app.invoke(initial_state)
            
            return result["response"]
        
        # Testar o agente
        response = run_agent("Qual é a capital da França?")
        print(f"Resposta: {response}")
        

        Saída esperada:

        Resposta: A capital da França é Paris.
        

        5.2 - Executar com Streaming

        Para aplicações interativas, você pode usar streaming:

        async def run_agent_stream(user_input: str):
            """Executa o agente com streaming"""
            
            initial_state = {
                "messages": [],
                "user_input": user_input,
                "response": "",
                "next_step": ""
            }
            
            async for event in app.astream(initial_state):
                for node_name, node_state in event.items():
                    print(f"\n--- {node_name} ---")
                    if "response" in node_state and node_state["response"]:
                        print(f"Resposta parcial: {node_state['response']}")
        

        Funcionalidades Avançadas

        Checkpoints e Persistência

        O LangGraph suporta checkpoints para salvar o estado:

        from langgraph.checkpoint.memory import MemorySaver
        
        # Adicionar memória ao grafo
        memory = MemorySaver()
        app_with_memory = workflow.compile(checkpointer=memory)
        
        # Executar com persistência
        config = {"configurable": {"thread_id": "user-123"}}
        result = app_with_memory.invoke(initial_state, config)
        

        Condições e Roteamento Dinâmico

        Você pode adicionar lógica condicional para roteamento:

        def router(state: AgentState) -> str:
            """Determina o próximo nó baseado no estado"""
            
            if "urgente" in state["user_input"].lower():
                return "priority_handler"
            else:
                return "normal_handler"
        
        # Adicionar roteamento condicional
        workflow.add_conditional_edges(
            "analyze",
            router,
            {
                "priority_handler": "priority_node",
                "normal_handler": "normal_node"
            }
        )
        

        Casos de Uso

        O LangGraph é ideal para:

        1. Chatbots Complexos: Gerenciar conversas multi-turno com contexto
        2. Agentes Autônomos: Criar agentes que tomam decisões baseadas em estado
        3. Workflows de Processamento: Orquestrar pipelines de processamento de dados
        4. Sistemas Multi-Agente: Coordenar múltiplos agentes especializados

        Veja em Ação

        Para mais detalhes e exemplos práticos, visite:


        Conclusão

        O LangGraph oferece uma abordagem poderosa e flexível para construir aplicações de IA com estado. Ao combinar grafos de estado com LLMs, você pode criar sistemas sofisticados que gerenciam conversas complexas, tomam decisões contextuais e executam workflows dinâmicos.

        A estrutura modular do LangGraph permite escalar desde simples chatbots até sistemas multi-agente complexos, mantendo o código organizado e fácil de manter.

        Discussão (0)1
        Entre ou crie uma conta para continuar
        Pergunta
        · 11 hr atrás

        Populating Persistent Class from JSON

        As I am iterating through the FHIR JSON Response from a Patient Search, I am running into an issue where the extracted values are not being popualted into the Response object that I have created. If I do a $$$LOGINFO on them they will show up in the Object log, however if I try the following for example I get an error.

        set target.MRN = identifier.value

        ERROR <Ens>ErrException: <INVALID OREF>Transform+15 ^osuwmc.Epic.FHIR.DTL.FHIRResponseToPatient.1 -- logged as '-'
        number - @'
        set target.MRN = identifier.value
        '

        Here is my Ens.DataTransform

        Class osuwmc.Epic.FHIR.DTL.FHIRResponseToPatient Extends Ens.DataTransform
        {
        
        ClassMethod Transform(source As HS.FHIRServer.Interop.Response, target As osuwmc.Epic.FHIR.DataStructures.PatientSearch.Response) As %Status
        {
          Set tSC=$$$OK
          set tQuickStream = ##Class(HS.SDA3.QuickStream).%OpenId(source.QuickStreamId)
          set tRawJSON = ##Class(%Library.DynamicObject).%FromJSON(tQuickStream)
          $$$TRACE(tRawJSON.%ToJSON())
          set tResource = tRawJSON.entry.%Get(0).resource
          if tResource.resourceType '= "Patient" {
            set tSC = $$$ERROR($$$GeneralError, "FHIRResponseToPatient: Resource type is not Patient")
            return tSC
          }
          else{
            $$$LOGINFO("Resource Type: "_tResource.resourceType)
            set mrnIter = tResource.identifier.%GetIterator()
            while mrnIter.%GetNext(,.identifier) {
              if identifier.system = "urn:oid:1.2.840.114350.1.13.172.2.7.5.737384.100" {
                  set target.MRN = identifier.value
              }
            }
            set NameIter = tResource.name.%GetIterator()
            while NameIter.%GetNext(,.humanName) {
              if humanName.use = "official" {
                set target.LastName = humanName.family
                set target.FirstName = humanName.given.%Get(0)
              }
            }
            set target.DOB = tResource.birthDate
            set target.Gender = tResource.gender
            set addrIter = tResource.address.%GetIterator()
            while addrIter.%GetNext(,.address) {
              if address.use = "home" {
             set target.Address = address.line.%Get(0)
                set target.City = address.city
                set target.State = address.state
                set target.PostalCode = address.postalCode
              }
            }
          }
          return tSC
        }
        
        }
        

        If I replace the set statements with $$$LOGINFO, the values will show up in the trace viewer.

        Discussão (0)1
        Entre ou crie uma conta para continuar