<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">"use strict";(self.webpackChunkcore_docs=self.webpackChunkcore_docs||[]).push([[4934],{75204:(e,t,n)=&gt;{n.d(t,{Z:()=&gt;s});var a=n(2784),r=n(33e3),o=n(9929),i=n(65663);function s({children:e}){return a.createElement(r.Z,{groupId:"npm2yarn"},a.createElement(o.Z,{value:"npm",label:"npm"},a.createElement(i.Z,{language:"bash"},"npm i ",e)),a.createElement(o.Z,{value:"yarn",label:"yarn",default:!0},a.createElement(i.Z,{language:"bash"},"yarn add ",e)),a.createElement(o.Z,{value:"pnpm",label:"pnpm"},a.createElement(i.Z,{language:"bash"},"pnpm add ",e)))}},15872:(e,t,n)=&gt;{n.r(t),n.d(t,{assets:()=&gt;h,contentTitle:()=&gt;c,default:()=&gt;b,frontMatter:()=&gt;p,metadata:()=&gt;u,toc:()=&gt;m});n(2784);var a=n(30876),r=n(75139),o=n(75204);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):function(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&amp;&amp;(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))})),e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a&lt;o.length;a++)n=o[a],t.indexOf(n)&gt;=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a&lt;o.length;a++)n=o[a],t.indexOf(n)&gt;=0||Object.prototype.propertyIsEnumerable.call(e,n)&amp;&amp;(r[n]=e[n])}return r}const p={sidebar_position:0,title:"Build a Question Answering application over a Graph Database"},c=void 0,u={unversionedId:"tutorials/graph",id:"tutorials/graph",title:"Build a Question Answering application over a Graph Database",description:"In this guide we\u2019ll go over the basic ways to create a Q&amp;A chain over a",source:"@site/docs/tutorials/graph.md",sourceDirName:"tutorials",slug:"/tutorials/graph",permalink:"/v0.2/docs/tutorials/graph",draft:!1,tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,title:"Build a Question Answering application over a Graph Database"},sidebar:"docs",previous:{title:"Tutorials",permalink:"/v0.2/docs/tutorials/"},next:{title:"Tutorials",permalink:"/v0.2/docs/tutorials/"}},h={},m=[{value:"\u26a0\ufe0f Security note \u26a0\ufe0f",id:"security-note",level:2},{value:"Architecture",id:"architecture",level:2},{value:"Setup",id:"setup",level:2},{value:"Install dependencies",id:"install-dependencies",level:4},{value:"Set environment variables",id:"set-environment-variables",level:4},{value:"Graph schema",id:"graph-schema",level:2},{value:"Chain",id:"chain",level:2},{value:"Next steps",id:"next-steps",level:3}],g={toc:m},d="wrapper";function b(e){var{components:t}=e,p=l(e,["components"]);return(0,a.kt)(d,s(function(e){for(var t=1;t&lt;arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},a=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&amp;&amp;(a=a.concat(Object.getOwnPropertySymbols(n).filter((function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable})))),a.forEach((function(t){i(e,t,n[t])}))}return e}({},g,p),{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"In this guide we\u2019ll go over the basic ways to create a Q&amp;A chain over a\ngraph database. These systems will allow us to ask a question about the\ndata in a graph database and get back a natural language answer."),(0,a.kt)("h2",{id:"security-note"},"\u26a0\ufe0f Security note \u26a0\ufe0f"),(0,a.kt)("p",null,"Building Q&amp;A systems of graph databases requires executing\nmodel-generated graph queries. There are inherent risks in doing this.\nMake sure that your database connection permissions are always scoped as\nnarrowly as possible for your chain/agent\u2019s needs. This will mitigate\nthough not eliminate the risks of building a model-driven system. For\nmore on general security best practices, ",(0,a.kt)("a",{parentName:"p",href:"/docs/security"},"see here"),"."),(0,a.kt)("h2",{id:"architecture"},"Architecture"),(0,a.kt)("p",null,"At a high-level, the steps of most graph chains are:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Convert question to a graph database query"),": Model converts user\ninput to a graph database query (e.g.\xa0Cypher)."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Execute graph database query"),": Execute the graph database query."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Answer the question"),": Model responds to user input using the\nquery results.")),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"sql_usecase.png",src:n(12601).Z,width:"960",height:"540"})),(0,a.kt)("h2",{id:"setup"},"Setup"),(0,a.kt)("h4",{id:"install-dependencies"},"Install dependencies"),(0,a.kt)(r.default,{mdxType:"IntegrationInstallTooltip"}),(0,a.kt)(o.Z,{mdxType:"Npm2Yarn"},"langchain @langchain/community @langchain/openai neo4j-driver"),(0,a.kt)("h4",{id:"set-environment-variables"},"Set environment variables"),(0,a.kt)("p",null,"We\u2019ll use OpenAI in this example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-env"},"OPENAI_API_KEY=your-api-key\n\n# Optional, use LangSmith for best-in-class observability\nLANGSMITH_API_KEY=your-api-key\nLANGCHAIN_TRACING_V2=true\n\n# Reduce tracing latency if you are not in a serverless environment\n# LANGCHAIN_CALLBACKS_BACKGROUND=true\n")),(0,a.kt)("p",null,"Next, we need to define Neo4j credentials. Follow ",(0,a.kt)("a",{parentName:"p",href:"https://neo4j.com/docs/operations-manual/current/installation/"},"these installation\nsteps"),"\nto set up a Neo4j database."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-env"},'NEO4J_URI="bolt://localhost:7687"\nNEO4J_USERNAME="neo4j"\nNEO4J_PASSWORD="password"\n')),(0,a.kt)("p",null,"The below example will create a connection with a Neo4j database and\nwill populate it with example data about movies and their actors."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},'import "neo4j-driver";\nimport { Neo4jGraph } from "@langchain/community/graphs/neo4j_graph";\n\nconst url = Deno.env.get("NEO4J_URI");\nconst username = Deno.env.get("NEO4J_USER");\nconst password = Deno.env.get("NEO4J_PASSWORD");\nconst graph = await Neo4jGraph.initialize({ url, username, password });\n\n// Import movie information\nconst moviesQuery = `LOAD CSV WITH HEADERS FROM \n\'https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/movies/movies_small.csv\'\nAS row\nMERGE (m:Movie {id:row.movieId})\nSET m.released = date(row.released),\n    m.title = row.title,\n    m.imdbRating = toFloat(row.imdbRating)\nFOREACH (director in split(row.director, \'|\') | \n    MERGE (p:Person {name:trim(director)})\n    MERGE (p)-[:DIRECTED]-&gt;(m))\nFOREACH (actor in split(row.actors, \'|\') | \n    MERGE (p:Person {name:trim(actor)})\n    MERGE (p)-[:ACTED_IN]-&gt;(m))\nFOREACH (genre in split(row.genres, \'|\') | \n    MERGE (g:Genre {name:trim(genre)})\n    MERGE (m)-[:IN_GENRE]-&gt;(g))`;\n\nawait graph.query(moviesQuery);\n')),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-text"},"Schema refreshed successfully.\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-text"},"[]\n")),(0,a.kt)("h2",{id:"graph-schema"},"Graph schema"),(0,a.kt)("p",null,"In order for an LLM to be able to generate a Cypher statement, it needs\ninformation about the graph schema. When you instantiate a graph object,\nit retrieves the information about the graph schema. If you later make\nany changes to the graph, you can run the ",(0,a.kt)("inlineCode",{parentName:"p"},"refreshSchema")," method to\nrefresh the schema information."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},"await graph.refreshSchema();\nconsole.log(graph.getSchema());\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-text"},"Node properties are the following:\nMovie {imdbRating: FLOAT, id: STRING, released: DATE, title: STRING}, Person {name: STRING}, Genre {name: STRING}\nRelationship properties are the following:\n\nThe relationships are the following:\n(:Movie)-[:IN_GENRE]-&gt;(:Genre), (:Person)-[:DIRECTED]-&gt;(:Movie), (:Person)-[:ACTED_IN]-&gt;(:Movie)\n")),(0,a.kt)("p",null,"Great! We\u2019ve got a graph database that we can query. Now let\u2019s try\nhooking it up to an LLM."),(0,a.kt)("h2",{id:"chain"},"Chain"),(0,a.kt)("p",null,"Let\u2019s use a simple chain that takes a question, turns it into a Cypher\nquery, executes the query, and uses the result to answer the original\nquestion."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"graph_chain.webp",src:n(87591).Z,width:"572",height:"432"})),(0,a.kt)("p",null,"LangChain comes with a built-in chain for this workflow that is designed\nto work with Neo4j:\n",(0,a.kt)("a",{parentName:"p",href:"https://python.langchain.com/docs/use_cases/graph/graph_cypher_qa"},"GraphCypherQAChain")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-typescript"},'import { GraphCypherQAChain } from "langchain/chains/graph_qa/cypher";\nimport { ChatOpenAI } from "@langchain/openai";\n\nconst llm = new ChatOpenAI({ model: "gpt-3.5-turbo", temperature: 0 });\nconst chain = GraphCypherQAChain.fromLLM({\n  llm,\n  graph,\n});\nconst response = await chain.invoke({\n  query: "What was the cast of the Casino?",\n});\nconsole.log(response);\n')),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-text"},'{ result: "James Woods, Joe Pesci, Robert De Niro, Sharon Stone" }\n')),(0,a.kt)("h3",{id:"next-steps"},"Next steps"),(0,a.kt)("p",null,"For more complex query-generation, we may want to create few-shot\nprompts or add query-checking steps. For advanced techniques like this\nand more check out:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/docs/how_to/graph_prompting"},"Prompting strategies"),": Advanced\nprompt engineering techniques."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/docs/how_to/graph_mapping/"},"Mapping values"),": Techniques for\nmapping values from questions to database."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/docs/how_to/graph_semantic"},"Semantic layer"),": Techniques for\nworking implementing semantic layers."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"/docs/how_to/graph_constructing"},"Constructing graphs"),": Techniques\nfor constructing knowledge graphs.")))}b.isMDXComponent=!0},87591:(e,t,n)=&gt;{n.d(t,{Z:()=&gt;a});const a=n.p+"assets/images/graph_chain-6379941793e0fa985e51e4bda0329403.webp"},12601:(e,t,n)=&gt;{n.d(t,{Z:()=&gt;a});const a=n.p+"assets/images/graph_usecase-34d891523e6284bb6230b38c5f8392e5.png"}}]);</pre></body></html>