File size: 4,499 Bytes
63f13b5 0ea9e1b 63f13b5 cfa3fb2 63f13b5 1488b1e 63f13b5 0ea9e1b 63f13b5 ba74371 713c540 0c774c2 d7bbf02 f53d974 63f13b5 0ea9e1b cfa3fb2 63f13b5 ff3a79a 052837d cfa3fb2 c932e96 57fcac6 713c540 0c774c2 713c540 a72ec7c cfa3fb2 57fcac6 cfa3fb2 ff3a79a a72ec7c cfa3fb2 a72ec7c cfa3fb2 052837d a72ec7c 052837d a72ec7c cfa3fb2 a72ec7c ff3a79a a72ec7c ff3a79a cfa3fb2 a72ec7c 63f13b5 ff3a79a 63f13b5 6a63b68 63f13b5 a72ec7c cfa3fb2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | import os
import pandas as pd
from langchain_core.messages import HumanMessage, AIMessage
from langgraph.graph import StateGraph, END, MessagesState
from langchain_huggingface import HuggingFaceEndpoint
from tools import TOOLS
QA_PATH = "metadata.jsonl"
qa_pairs = pd.read_json(QA_PATH, lines=True)
qa_dict = {
row["Question"].strip(): row["Final answer"].strip()
for _, row in qa_pairs.iterrows()
}
def build_graph():
llm = HuggingFaceEndpoint(
endpoint_url="https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.3",
task="text-generation",
max_new_tokens=512,
temperature=0.1,
top_k=50,
top_p=0.95,
huggingfacehub_api_token=os.environ["HF_TOKEN"]
)
def retriever_node(state: MessagesState):
query = state["messages"][-1].content.strip()
if query in qa_dict:
print("✅ Exact match found in retriever.")
answer = qa_dict[query]
return {"messages": [AIMessage(content=answer)]}
print("🔍 No match. Passing to LLM.")
return
def assistant_node(state: MessagesState):
query = state["messages"][-1].content.strip()
system_prompt = (
"You are a helpful assistant. To answer the user's question, you can use tools. "
"To use a tool, respond with a single line: 'tool:tool_name:input'. "
"For example: 'tool:wiki_search:Apple Inc.' "
"If you have the final answer, provide it directly without any prefixes. "
"Never justify or explain your final answer."
)
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": query}
]
response = llm.invoke(messages).strip()
for tag in ("", "Answer:", "assistant:"):
if response.lower().startswith(tag.lower()):
response = response[len(tag):].strip()
return {"messages": [AIMessage(content=response)]}
def tool_node(state: MessagesState):
last_message = state["messages"][-1].content.strip()
try:
_, tool_name, tool_input = last_message.split(":", 2)
tool_name = tool_name.strip()
tool_input = tool_input.strip()
tool_fn = TOOLS.get(tool_name)
if not tool_fn:
print(f"❌ Unknown tool: {tool_name}")
return {"messages": [AIMessage(content="Unknown")]}
print(f"🔧 Using tool: {tool_name} with input: {tool_input}")
tool_result = tool_fn(tool_input)
return {"messages": [AIMessage(content=str(tool_result))]}
except Exception as e:
print(f"⚠️ Tool error: {e}")
return {"messages": [AIMessage(content="Unknown")]}
def route_after_retriever(state: MessagesState):
if isinstance(state["messages"][-1], AIMessage):
return END
return "assistant"
def route_after_assistant(state: MessagesState):
last_message = state["messages"][-1].content.strip().lower()
if last_message.startswith("tool:"):
return "tool"
return END
builder = StateGraph(MessagesState)
builder.add_node("retriever", retriever_node)
builder.add_node("assistant", assistant_node)
builder.add_node("tool", tool_node)
builder.set_entry_point("retriever")
builder.add_conditional_edges(
"retriever",
route_after_retriever,
{"assistant": "assistant", END: END}
)
builder.add_conditional_edges(
"assistant",
route_after_assistant,
{"tool": "tool", END: END}
)
builder.add_edge("tool", "assistant")
return builder.compile()
class BasicAgent:
def __init__(self):
print("✅ BasicAgent initialized with retriever + LLM + tools")
self.graph = build_graph()
def __call__(self, question: str) -> str:
print(f"📥 Question: {question[:100]}")
config = {"recursion_limit": 50}
try:
result = self.graph.invoke(
{"messages": [HumanMessage(content=question)]},
config=config
)
answer = result["messages"][-1].content.strip()
print(f"📤 Answer: {answer}")
return answer
except Exception as e:
print(f"Error during graph invocation: {e}")
return f"AGENT ERROR: {e}" |