Skip to content

Repository files navigation

ScholarAgent — a grounded research assistant

ScholarAgent answers questions over a knowledge base by orchestrating a LangGraph tool-calling agent: Claude decides when to search, a retrieval tool pulls relevant passages (RAG), and the model answers only from what it retrieved, with inline citations. If the knowledge base doesn't contain the answer, it says so instead of hallucinating.

It demonstrates the agentic-engineering stack the way a production system would use it — agent orchestration, tool calling, retrieval-augmented generation, grounding guardrails, and (optional) LangSmith tracing.

How it works

flowchart LR
Q[Question] --> A[agent node: Claude]
A -->|tool_calls?| T[tools node: search_corpus]
T -->|retrieved passages| A
A -->|no more tool calls| ANS[Grounded, cited answer]
Loading
  • agent node — Claude, bound with the search_corpus tool, decides its next move.
  • tools node — runs the retrieval tool and feeds results back.
  • The loop repeats until Claude answers without another tool call. See src/scholaragent/graph.py.

Grounding guardrail: the system prompt requires the agent to search first, cite every claim as [doc_id], and refuse to answer when the corpus lacks the information. Retrieval is TF-IDF over the local corpus (data/corpus/), so it's fully offline and unit-testable.

Quickstart

make setup
make test# offline suite — no API key needed
cp .env.example .env # add your ANTHROPIC_API_KEY
make ask Q="What causes overfitting and how do you prevent it?"

Example answer (grounded + cited):

Overfitting happens when a model learns the noise in the training data rather than the underlying signal, showing low training error but high validation error [overfitting]. Common remedies include more data, reducing model capacity, regularization, and early stopping [overfitting][regularization].

Project structure

scholaragent/
├── data/corpus/ # the knowledge base (markdown docs)
├── src/scholaragent/
│ ├── retrieval.py # TF-IDF retriever (pure, offline)
│ ├── tools.py # search_corpus LangChain tool
│ ├── llm.py # ChatAnthropic factory
│ ├── graph.py # LangGraph tool-calling loop
│ ├── agent.py # system prompt + ask()
│ └── cli.py # command-line entry point
├── tests/ # retrieval + graph (fake-LLM) tests
├── docs/architecture.md
├── Makefile · pyproject.toml · requirements.txt

Configuration

Env varDefaultPurpose
ANTHROPIC_API_KEYRequired to run the agent
ANTHROPIC_MODELclaude-opus-4-8Model (claude-haiku-4-5 for cheaper demos)
SCHOLAR_TOP_K3Passages retrieved per search
LANGCHAIN_TRACING_V2Set true (+ LANGCHAIN_API_KEY) for LangSmith traces

Extending it

  • Swap the corpus: drop .md files into data/corpus/.
  • Add tools: write a @tool in tools.py and pass it to build_agent().
  • Upgrade retrieval: replace the TF-IDF Retriever with a vector store (e.g. FAISS or pgvector) behind the same search() interface.

License

MIT — see LICENSE.

About

A LangGraph research assistant — tool-calling agent + RAG with grounded citations

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages