LangChain-ReAct-Agent: a Qwen-based ReAct agent with Chroma RAG and a Streamlit trace view
基于 LangChain/LangGraph 的 ReAct Agent ,结合 RAG、工具调用与 Streamlit 界面,面向智能客服与报告生成场景。
At a glance
- What is it?
- lhh737/LangChain-ReAct-Agent is an MIT-licensed Python reference implementation of a ReAct loop over LangChain and LangGraph, wired to DashScope Qwen models, a Chroma vector store, and a Streamlit chat UI that shows the reasoning trace. The interesting part is not the agent, it is the middleware layer that swaps system prompts at runtime and the YAML-driven configuration split across four files.
- Who is it for?
- Adopt this if you want a readable, MIT-licensed skeleton for a Qwen-backed ReAct agent and you are willing to accept a hard DashScope dependency, since the model factory is built around ChatTongyi and DashScopeEmbedding and no other provider path is documented. Do not adopt it as a production customer-service system: there are no releases, no tests mentioned, no evaluation harness, and the prompt-switching rule lives in middleware code you will have to audit yourself.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 129 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem: a ReAct loop is easy to draw and annoying to assemble
The gap this repository fills is assembly, not invention. A ReAct agent is a short idea: the model emits a thought, picks an action, receives an observation, repeats. Building one that actually runs means picking a model provider, giving it a tool schema, giving it a retriever, deciding when to stop, and then finding a way to see what happened when the answer is wrong. The README describes a system that bundles all of those pieces around a single worked scenario: a robot vacuum cleaner support desk. The knowledge base in data/ is described as robot-vacuum material, and the suggested test questions are domain questions about vacuum functions and charging failures. That specificity is deliberate. A generic agent demo with a generic corpus tells you nothing about whether retrieval is working, because you cannot tell a good answer from a plausible one. Here you can.
The audience is therefore narrow and clear. It is a Python developer who already knows LangChain, wants to see a ReAct loop with retrieval and tool calls in one place, and is comfortable reading YAML and a handful of modules instead of a framework's documentation. It is not aimed at someone who wants a hosted support bot, and it is not aimed at someone who wants a library to import. There is no package to install from the repository; the README's install step is pip install -r requirements.txt followed by running app.py directly.
The ReAct loop and the three services hanging off it
The architecture diagram in the README shows one central box labelled ReAct Agent, containing a Thought to Action to Observation cycle, with three arrows leaving it: RAG, Tools, and Prompt. The Prompt arrow is labelled dynamic switching and template management, and the diagram places it inside a Middleware band alongside tool monitoring. So the loop is not a plain LangChain agent executor with a fixed system message. Something between the agent and the model is deciding which system prompt is in force.
That is the design decision worth paying attention to. The README's feature table says the middleware automatically switches between two system prompts, one for ordinary question answering and one for report generation, based on runtime context. The prompts themselves are files: prompts/main_prompt.txt, prompts/rag_summarize.txt, and prompts/report_prompt.txt, with the paths registered in config/prompts.yml. Keeping prompts as plain text files rather than Python string literals is the right call, because prompt edits then do not touch code and do not require a restart of anything other than the Streamlit process.
The tool layer is described as four capabilities: weather lookup, user location, external data retrieval, and report context filling. The README does not give the function signatures or the tool descriptions the model sees, which matters more than it sounds. A ReAct agent selects tools by reading their descriptions, so the quality of this system on your data depends on text that is not shown in the README. You will have to open agent/tools/agent_tools.py to judge it.
RAG: Chroma, DashScope embeddings, and MD5 file dedup
The retrieval side is conventional but has one detail worth noting. Documents are loaded from data/, split with RecursiveCharacterTextSplitter, embedded through DashScopeEmbedding, and persisted in Chroma. The README states that the loader handles mixed txt and pdf input, with PyPDF doing the PDF parsing. The dedup mechanism is MD5-based: files are hashed and already-ingested files are skipped. That is a coarse form of idempotency. It works when your corpus is a folder of stable documents and you re-run ingestion after adding a file. It does not help when a document is edited in place, because the hash changes and the file is treated as new, which means the old chunks stay in the collection unless you clear it. The README does not describe a delete or update path, so treat re-ingestion as an append operation and be prepared to drop the Chroma persistence directory when your source documents change.
Retrieval parameters are not hardcoded. config/chroma.yml holds the persistence path, the chunk size, the Top-K for retrieval, and the list of supported file types. config/rag.yml holds the chat model name and the embedding model name. Splitting these across two files rather than one is a small annoyance, but it does mean the retrieval tuning knobs are in one place and the model selection is in another, which is a defensible separation if you ever swap the embedding model independently of the chat model. The README does not state default values for chunk size or Top-K, so you cannot predict retrieval behaviour without opening the file.
Getting it running: five commands and one API key
The README's quick start is short and the steps are real. Clone the repository, then pip install -r requirements.txt. Set DASHSCOPE_API_KEY in the environment, either with export on Linux and macOS or set on Windows CMD, with .env.example as the reference. The key comes from Alibaba Cloud's Bailian console, which the README links twice. Python 3.10 or newer is required.
Ingestion is a one-liner the README gives verbatim: python -c "from rag.vector_store import VectorStoreService; VectorStoreService().load_document()". That single command tells you the ingestion entry point is a method on VectorStoreService and that it is not exposed through the Streamlit UI. Then streamlit run app.py, which the README says opens http://localhost:8501. Three verification prompts are provided: a knowledge question about vacuum functions, a troubleshooting question about charging failure, and a report generation request. The three map onto the three paths the architecture claims to support, which is a sensible smoke test set.
The dependency chain is the part to weigh before starting. LangChain 0.3, LangGraph 0.2, Streamlit 1.40, and DashScope are all pinned by badge version in the README. LangGraph in the 0.2 line and LangChain in the 0.3 line are both moving targets, and the README does not state exact pinned versions in requirements.txt. The last push recorded for the repository is 2026-05-10, and no releases have been published, so there is no tagged version to pin against. If you build on this, pin the versions yourself after a working install.
Where it will let you down
The most concrete limitation is provider lock-in. The model factory is described as producing ChatTongyi and DashScopeEmbedding. Both are Alibaba Cloud services. There is no documented path to an OpenAI-compatible endpoint, a local model, or a different embedding provider. If your organisation cannot send documents to DashScope, this repository is the wrong starting point, and swapping the provider means rewriting model/factory.py plus re-embedding the entire corpus, because embeddings from one model are not interchangeable with another.
The second limitation is that prompt switching is opaque. The README says the middleware switches prompts based on runtime context, but it does not say what that context is or how the decision is made. If the switch is keyword-based on the user's message, a question like "write me a report on why my vacuum keeps failing" could route into report mode when you wanted a troubleshooting answer. That is not a bug in the repository; it is a design surface you have to inspect and probably replace with something explicit, such as a UI toggle or a separate entry point.
The third is observability beyond the chat window. The Streamlit interface shows the reasoning trace for the current session, and the README mentions history retention and a logger handler in utils/logger_handler.py. What is not described is any structured trace export, any way to replay a past run, or any evaluation harness. For a demo this is fine. For anything where you need to know why last Tuesday's answer was wrong, you are reading log files.
The alternative: a plain LangChain retriever chain
The obvious comparison is not another agent framework. It is the much simpler thing this repository chose not to be: a retrieval-augmented chain with no agent loop at all. In a plain chain, the user question goes to the retriever, the retrieved chunks go into a prompt template, and the model answers. One call, one prompt, no tool selection, no reasoning trace.
The difference in approach is where the decision-making lives. In a ReAct agent, the model decides at runtime whether to search the knowledge base, call a weather tool, fetch user data, or do nothing, and it can chain those decisions across several steps. In a plain chain, you decide in code, and the model only writes the answer. The agent buys you flexibility on mixed-intent questions and costs you determinism, latency, and debuggability. Every additional reasoning step is another place for the model to pick the wrong tool or loop.
For the robot vacuum support scenario as described, most of the traffic looks like knowledge questions and troubleshooting, which a plain retriever chain handles with one round trip. The report generation flow is the case that genuinely needs orchestration, because it has to pull user data and external data before writing. A reasonable middle path is to keep this repository's RAG and configuration modules and call them from two separate entry points, one chain for questions and one agent for reports, rather than letting middleware guess which mode the user is in.
Maintenance cost and the MIT licence
The repository is MIT licensed, which permits commercial use, modification, and redistribution provided the copyright notice and permission notice are retained. That is the permissive end of the spectrum and imposes no copyleft obligation on your own code. It says nothing about the services the project depends on: your use of DashScope is governed by Alibaba Cloud's terms, not by this licence, and the same applies to any documents you feed into the vector store. This is not legal advice; if you are ingesting customer data, get the data-handling question answered separately from the licence question.
Maintenance cost has two components. The first is version drift in the agent stack. LangChain and LangGraph both change APIs between minor versions, and with no published releases there is no compatibility contract. Expect to spend time on upgrades when you bump either. The second is configuration surface: four YAML files, three prompt text files, and a middleware module that encodes routing logic. That is a modest amount to hold in your head, and it is the reason the project is readable. The cost is that the routing logic is the least documented part of the system and the most likely to need rewriting for your own use case.
There are no releases retrieved for this repository, so there is nothing to pin to and no changelog to read. If you fork it, tag your own working state before you start changing the middleware.
Editorial conclusion
Adopt this if you want a readable, MIT-licensed skeleton for a Qwen-backed ReAct agent and you are willing to accept a hard DashScope dependency, since the model factory is built around ChatTongyi and DashScopeEmbedding and no other provider path is documented. Do not adopt it as a production customer-service system: there are no releases, no tests mentioned, no evaluation harness, and the prompt-switching rule lives in middleware code you will have to audit yourself. Before committing, read agent/tools/middleware.py to see exactly what runtime context triggers the report prompt, and check config/chroma.yml for the chunk size and Top-K values, because those two settings determine whether retrieval returns anything useful on your own documents.
Community notes