Closed jithinagiboson closed 4 months ago
my package.json { "name": "ai-chart-generator", "version": "1.0.0", "description": "", "main": "index.js", "type": "module", "scripts": { "start": "nodemon index.js", "agent": "nodemon ./modules/database-ai/agent.js", "test": "nodemon ./modules/database-ai/test.js", "graph": "nodemon ./modules/lang-graph/index.js" }, "author": "", "license": "ISC", "dependencies": { "@langchain/community": "^0.2.17", "@langchain/core": "^0.2.12", "@langchain/langgraph": "^0.0.26", "@langchain/openai": "^0.2.0", "dotenv": "^16.4.5", "langchain": "^0.2.8", "langsmith": "^0.1.34", "mysql": "^2.18.1", "node-querybuilder": "^2.1.1", "typeorm": "^0.3.20", "xss": "^1.0.15" } }
const graph = new Graph();
... .... ... const runnable = graph.compile();
// new HumanMessage("elephents") // For Message graph, input should always be a message or list of messages. let state = { input: "list 1st 20 customers and genres " }; log(state); const res = await runnable.invoke(state);
i use a custom js object as state
@jithinagiboson could you please explain the step-by-step flow that you're trying to implement? it would also be helpful to see the full graph implementation in one code snippet that has graph state, nodes, edges and the compiled graph.
also, I believe you can just use a prebuilt ReAct agent to achieve the same behavior as langchain's SQL agent:
import { createReactAgent } from "@langchain/langgraph/prebuilt"
import { ChatAnthropic } from "@langchain/anthropic"
const tools = [] // your SQL tools defined here
const llm = new ChatAnthropic({ model: "claude-3-haiku-20240307" }) // or whichever model you're using
const agent = createReactAgent({ llm, tools })
const res = await agent.invoke(
{ messages: [["user", "list 1st 20 customers and genres"]] }
)
my requirements -use an opensource ai model for text to sql query current issues faced
using an sql agent doesnt give me much control over the outcome.And sql agent in js already have bug its only prompt is default to sqlite so i had to hard code it to mysql. what i did was using the same prompt used by sql agent inside langraph i used the llm responce to identify the too name to use and tried to route to that node
the below
graph.addNode("query",` async (state) => {
log("------------NODE QUERY------------");
log("state", state);
const parser = new JsonOutputParser();
const chain = prompt.pipe(modelJSON).pipe(parser);
let agentSteps = [];
let result = await chain.invoke({
dialect: DIALECT,
input: state.input,
agentSteps: agentSteps,
agent_scratchpad: "",
});
agentSteps = [{ Thought: result["Thought"] }];
return { input: state.input, result: result, intermediateSteps: agentSteps };
});
graph.addNode("list-tables-sql", async (state) => {
log("------------NODE list-tables-sql------------");
log("state", state);
const prompt = ChatPromptTemplate.fromTemplate(lama3_70b_prompt);
const parser = new JsonOutputParser();
const chain = prompt.pipe(modelJSON).pipe(parser);
//CALL TOOLS
let tableNameArray = db.allTables.map((a) => a.tableName); //get all table names
// log("tableNameArray",tableNameArray)
// process.exit()
// let default_result={result:{
// Question: state.input,
// Thought: 'I should look at the tables in the database to see what I can query.',
// Action: 'list-tables-sql',
// 'Action Input': '',
// Observation: getArray2Text(textArray) //'Album,Artist,Customer,Employee,Genre,Invoice,InvoiceLine,MediaType,Playlist,PlaylistTrack,Track'
// }}
let agentSteps = {
Action: state.result["Action"],
"Action Input": state.result["Action Input"],
Observation: getArray2Text(tableNameArray),
Thought: "",
};
state.intermediateSteps.push(agentSteps);
let concatAgentSteps =arrayJSON2Text(state.intermediateSteps);
let result = await chain.invoke({
dialect: DIALECT,
input: state.input,
agent_scratchpad: concatAgentSteps,
}); //llm call
state.intermediateSteps[state.intermediateSteps.length - 1].Thought =
result["Thought"]; //thought from llm
dialect:DIALECT,input:state.input,agent_steps:state.agent_steps&&state.agent_steps+'\n'+JSON2Text(agent_steps),agent_scratchpad:JSON2Text(agent_steps) }))
log("list-tables-sql RESULT", result);
return {
input: state.input,
result: result,
intermediateSteps: state.intermediateSteps,
};
});
graph.addEdge(START, "query");
graph.addEdge("query", "list-tables-sql"); // this line only work if i coment this it says query is a dead end
// graph.addEdge("query", "info-sql");
// graph.addEdge(START,"list-tables-sql");
graph.addConditionalEdges(
'query',
// Assess agent decision
router,
{
"list-tables-sql":"list-tables-sql"
}
);
// ROUTER function
const router=async (state)=>{
log("-------ROUTER---------")
let {result}=state
let action=result["Action"]
log(action)
// return action//next action
// return "list-tables-sql"
return "list-tables-sql"// just hard coded to test query to list table flow
}
this is the basic flow one node result has and action input which shloud be used for conditional routing to the next node but unfortunatly its not taken as an edge at all
i think the issue may be with import { Graph} from "@langchain/langgraph"; Graph doesnt seem to work with conditional edge the below code work with MessageGraph
import { START, END, MessageGraph, Graph,StateGraph, } from "@langchain/langgraph";
import { log } from "../helper/util.js";
import { HumanMessage } from "@langchain/core/messages";
const model=(state)=>{
log('--- AGENT-----')
return state
}
const action=(state)=>{
log('--- ACTION-----')
return state
}
const graph = new MessageGraph();
const workflow = new MessageGraph() //new Graph()
.addNode("agent", model)
.addNode("action",action);
const shouldContinue=(state)=>{
log("shouldContinue")
return "action"
}
workflow.addConditionalEdges("agent", shouldContinue);
workflow.addEdge(START, "agent");
workflow.addEdge("action", END);
let app=workflow.compile()
app.invoke({messages:[new HumanMessage("what about ny")]})
OUTPUT
[nodemon] starting node modules/lang-graph/route-test.js
--- AGENT-----
shouldContinue
--- ACTION-----
[nodemon]
i have solved my issue by using StateGrpah() instead of Graph()
ah, yes, it should be a StateGraph
, that's correct! glad it worked
langraph version 0.0.26
I have langgraph which is a replica of langchain sql agent but when i run the nodes with individual edges it worked but when i added conditionalEdge its not taken as a edge it says the first node is a dead end this below is the diagram of my a idea its actualy a by directional edge
// ROUTER function const router=async (state)=>{ log("-------ROUTER---------") let {result}=state let action=result["Action"] log(action) // return action//next action // return "list-tables-sql" return "list-tables-sql" } // query-sql,info-sql,list-tables-sql,query-checker // GRAPH
graph.addEdge("list-tables-sql", "info-sql"); graph.addEdge("info-sql", "query-checker"); graph.addEdge("query-checker", END);
graph.addEdge(START, "query"); graph.addEdge("query", "list-tables-sql"); // this line only work if i coment this it says query is a dead end // graph.addEdge("query", "info-sql"); // graph.addEdge(START,"list-tables-sql"); graph.addConditionalEdges( 'query', // Assess agent decision router, { "list-tables-sql":"list-tables-sql" } ); const runnable = graph.compile();