Skip to content

Latest commit

 

History

46 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Qwen Fullstack LangGraph Agent

This is a modified version of the Gemini fullstack LangGraph quickstart.

The frontend is intentionally left mostly unchanged. The backend has been rewritten to use:

  • Qwen through an OpenAI-compatible API
  • Tavily for fast web search
  • fetch_url for reading top search result pages
  • SQLite for structured long-term memory
  • Chroma for semantic vector memory
  • LangGraph for the agent workflow

Backend Flow

The graph still keeps the frontend-compatible node names:

generate_query -> web_research or finalize_answer

Internally, the backend now does this:

  1. generate_query

    • Uses Qwen to create up to three self-contained memory retrieval queries
    • Reads prior SQLite memory with search_memory
    • Reads semantic Chroma memory with search_vector_memory
    • Locally ranks and keeps at most three memory records
    • Skips fresh web search when memory is sufficient
  2. web_research

    • Calls Tavily through web_search
    • Fetches top result pages through fetch_url
    • Uses Qwen to summarize evidence with citations
  3. finalize_answer

    • Uses Qwen to write the final answer
    • If web search was needed, checks memory plus search context once before answering
    • Saves new memory only for search-backed answers, not for memory-only repeat answers

Memory Flow

Memory runs in four practical stages:

  1. Query planning

    • The current question plus conversation context are rewritten into one to three self-contained memory lookup queries.
    • This helps short follow-up questions retrieve the same long-term facts as the original full question.
  2. Retrieval

    • SQLite typed memory is searched through search_memory and previous answer summaries through search_memory_summaries.
    • Chroma semantic memory is searched through search_vector_memory.
    • Results from both stores are merged before ranking.
  3. Ranking and sufficiency

    • Local ranking keeps the most relevant memory records, controlled by MEMORY_RERANK_TOP_K.
    • The memory-first decision checks whether the ranked memory directly answers the current question.
    • If memory is sufficient, the graph skips fresh Tavily search. If not, it continues to web research.
  4. Write-back

    • Search-backed final answers are saved as answer memory in SQLite.
    • Atomic typed facts are extracted into agent_memory_items.
    • Typed facts are also written to Chroma for later semantic retrieval.
    • Memory-only repeat answers are not saved again, to avoid duplicating old facts.

Memory Debug API

The backend exposes read-only debug endpoints under the LangGraph API server:

GET /debug/memory
GET /debug/memory/items
GET /debug/memory/hits
GET /debug/memory/ranking
GET /debug/memory/sufficiency
GET /debug/memory/trace

Each endpoint accepts limit, for example:

curl "http://localhost:2024/debug/memory?limit=10"

Current persistence guarantees:

  • items reads typed facts from agent_memory_items.
  • hits reads recent retrieval hits from agent_memory_hits.
  • ranking is derived from hit order unless a dedicated ranking table or list function is added.
  • trace is derived from hit records unless a dedicated trace table or list function is added.
  • sufficiency returns persisted sufficiency decisions when a future table or list function exists; otherwise it returns an empty list.

Tools

The backend tools live in:

backend/src/agent/tools/

Current tools:

  • web_search: Tavily web search
  • fetch_url: fetch and extract readable text from web pages
  • search_memory: search SQLite memory
  • search_vector_memory: search Chroma semantic memory
  • save_memory: save final answer summaries to SQLite
  • save_vector_memory: save final answer summaries to Chroma
  • dedupe_sources: clean duplicate source URLs

Environment

Create backend/.env from backend/.env.example:

OPENAI_API_KEY=your_dashscope_api_key
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL=qwen-plus
EMBEDDING_MODEL=text-embedding-v4

SEARCH_PROVIDER=tavily
TAVILY_API_KEY=your_tavily_api_key
SEARCH_MAX_RESULTS=5
SEARCH_DEPTH=fast
FETCH_TOP_K=2

DATABASE_URL=sqlite:///./data/agent_memory.sqlite
VECTOR_DB_DIR=./data/chroma
VECTOR_COLLECTION=agent_memory
VECTOR_MEMORY_RESULTS=3
# VECTOR_MEMORY_MAX_DISTANCE=1.2
MEMORY_FIRST_ENABLED=true
MEMORY_FIRST_MIN_RECORDS=1
MEMORY_RERANK_TOP_K=3

OPENAI_API_KEY is named this way because the code uses the OpenAI SDK compatibility format. For Qwen, put your DashScope API key there.

EMBEDDING_MODEL is used only for vector memory. The default text-embedding-v4 stores answer summaries in Chroma so later questions can retrieve semantically related memories even when they do not repeat the exact same words.

VECTOR_MEMORY_MAX_DISTANCE is optional. Leave it unset unless you have measured Chroma distances for your collection and want to filter weak semantic matches.

MEMORY_FIRST_ENABLED=true lets the backend answer from retrieved memory before running Tavily. This makes follow-up or repeated questions much faster. Set it to false when you always want fresh web research.

MEMORY_FIRST_MIN_RECORDS is the minimum number of ranked memories required before the backend can skip web search.

MEMORY_RERANK_TOP_K controls how many ranked memory facts are passed to answer generation.

Test Dataset Runs

The memory evaluation dataset lives at:

backend/tests/memory_eval_cases.json

Run it with:

cd backend
pytest tests/test_memory_eval.py

The backend Makefile also supports passing a specific test file:

cd backend
make test TEST_FILE=tests/test_memory_eval.py

For an end-to-end backend check with real providers, run the CLI researcher after creating backend/.env:

cd backend
pip install .
python examples/cli_research.py

For repeat-memory testing, run the same prompt twice:

  1. The first run should use Tavily and then write answer memory, typed facts, and vector memory.
  2. The second run should show recent hits in /debug/memory/hits and may skip Tavily if the ranked memory is sufficient.

Use the debug endpoints to inspect the records created by each run.

Run Locally

Backend:

cd backend
pip install .
langgraph dev

Frontend:

cd frontend
npm install
npm run dev

Open the frontend at:

http://localhost:5173/app

The LangGraph API runs at:

http://localhost:2024

Notes

The frontend still has the original model selector labels. The backend ignores old gemini-* selector values and uses MODEL from the environment instead. This keeps the first backend refactor focused and avoids changing the UI in the same step.

About

基于langgraph的智能研究助手

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages