Preface: Why RAG Agent is the Key Path for Current Implementation
Since 2024, the hallucination problem and knowledge timeliness bottleneck of pure large language models have become increasingly prominent, and enterprise-level applications are gradually shifting from "usable" to "trustworthy and usable". RAG (Retrieval-Augmented Generation) provides evidence support for models through external knowledge bases, while the Agent mechanism endows models with tool invocation and autonomous decision-making capabilities. The combination of the two essentially builds a closed-loop system that can "search, think, and act", which is not only a technological trend but also an inevitable choice for business implementation. This article will use the DeepSeek model as the foundation to deconstruct a runnable RAG Agent framework from scratch, covering data engineering, retrieval optimization, decision orchestration, and fault tolerance design, along with practical pitfalls encountered.
The RAG Agent we discuss is not a simple "PDF Q&A" but an intelligent agent with multi-step task decomposition, autonomous tool invocation, and self-verification of results. For example, when a user asks "compare the inventory difference between last quarter and this month and generate restocking suggestions", the system needs to automatically retrieve structured and unstructured data, invoke calculation tools, generate suggestions, and provide confidence levels. This process involves the precision of retrieval, the stability of tool invocation, and the interpretability of final output, each of which has unique engineering implementations with the support of the DeepSeek API.
1. Knowledge Base Construction: From Raw Documents to Retrievable Vector Space
Many tutorials stop at "loading PDFs and chunking for vectorization", but a production-grade knowledge base must address three issues: first, the robustness of document parsing (PDF tables, scanned documents, complex layouts); second, the semantic preservation of chunking strategies; third, the completeness of metadata. We adopt a multi-layer parsing pipeline: first use PyMuPDF to extract text and layout blocks, then chunk based on heading hierarchy or paragraph semantics, ensuring each chunk's context window does not exceed 500 tokens.
After chunking, vectors need to be generated. DeepSeek does not provide a dedicated embedding interface, but we can use compatible OpenAI format or the local BGE-M3 model. The key here is that the vector model must be paired with a reranker model; otherwise, noise in top-k retrieval will greatly affect the Agent's reasoning quality. We choose BGE-M3 to generate 1024-dimensional vectors and pair it with bge-reranker-base for secondary fine-ranking. In practice, on manually annotated
On the 200 annotated queries, the hit rate improved from 61% to 82%.# Document Chunking and Vectorization (Illustrative; full code in the project repository)
from deepseek_api import DeepSeekClient # Assuming a wrapper exists
from bge_embedding import BGEM3Embedding
client = DeepSeekClient(api_key="your-deepseek-api-key", base_url="https://api.deepseek.com")
embed_model = BGEM3Embedding(model_name="BAAI/bge-m3")
def slice_doc(text, max_len=500):
# Split by paragraphs and headings, preserving semantic integrity
blocks = split_by_heading(text)
return [block for block in blocks if len(block) < max_len]
for doc in raw_documents:
for chunk in slice_doc(doc):
vec = embed_model.encode(chunk)
metadata = {"source": doc.meta["path"], "page": chunk.page}
vector_db.insert(vec, metadata, text=chunk.text)Key reminder: In the vector database, do not only store vectors and text; be sure to store the parent document ID and location information of each chunk, because when the Agent makes decisions, we often need to reference original document fragments or jump links. Additionally, for structured tabular data, it is recommended to set up a separate SQLite or DuckDB database to avoid forced vectorization causing loss of numerical precision.
2. Retrieval Augmentation: Engineering Practices for Hybrid Retrieval and Re-ranking
In actual deployment, BM25 keyword retrieval and vector retrieval must be used together. Vectors excel at capturing semantics, but are not good at exact matching of numbers, models, prices, etc.; BM25 is the opposite. We implemented a lightweight hybrid retriever: first, use BM25 (based on rank_bm25) to get top-20, use vector retrieval to get top-20, then merge and deduplicate, feed into a reranker for fine-ranking, and finally take top-5 as context. This approach, with minimal additional cost, significantly improves the factual accuracy of the Agent.The reranking model cannot only do "relevance scoring"; it must also output explanatory reasons, such as "this fragment contains the target product's stock keeping unit and date, which highly matches the question." To this end, we switched to an LLM-based rerank: let DeepSeek-chat output a score from 1 to 5 and a reason for each candidate fragment, then weight by score. Although this method is slow, it can be integrated into the Agent's "self-reflection" step to improve the reliability of final decisions.
| Retrieval Method | Recall@5 | MRR | Average Latency (ms) |
|---|---|---|---|
| Vector Only | 61% | 0.43 | 35 |
| BM25 Only | 54% | 0.37 | 12 |
| Hybrid + Rerank | 82% | 0.71 | 180 |
III. Agent Decision Framework: From ReAct to Deep Planning
The core of this project is a ReAct-style Agent, but we added "long-term memory" and "tool usage records" to the classic thought-action-observation loop. DeepSeek-chat's function calling capability is strong; we defined a set of tools: knowledge retrieval, SQL query, Python computation, date retrieval, etc. The Agent's prompt requires it to explicitly state "current goal," "next step plan," and "why this tool is chosen," ensuring interpretability.To handle complex tasks, we implemented a lightweight "task decomposer": first split the user query into several subtasks (via LLM calls), then assign retrieval context and tools to each subtask. For example, "analyze the last threeMonthly sales trend and forecast for next month" is broken down into three steps: "Get sales data", "Run time series analysis", and "Generate report", each of which is traceable.
# Agent Core Loop (Pseudo-code)
from deepseek_api import DeepSeekClient
import json
client = DeepSeekClient(api_key="your-deepseek-api-key", base_url="https://api.deepseek.com")
def agent_loop(query, max_steps=5):
messages = [{"role": "system", "content": "You are a helpful agent..."}]
messages.append({"role": "user", "content": query})
for step in range(max_steps):
response = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
tools=tool_definitions,
tool_choice="auto"
)
msg = response.choices[0].message
if not msg.tool_calls:
return msg.content
messages.append(msg)
for tool_call in msg.tool_calls:
result = execute_tool(tool_call.function.name, json.loads(tool_call.function.arguments))
messages.append({"role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result)})
return "Reached maximum steps, please simplify the question"The above code demonstrates how to use DeepSeek's function calling to implement tool invocation. Note that we must keep the complete tool call history and results in messages, otherwise the model will lose context and make confused decisions. Additionally, when executing tools, all exceptions should be caught and returned to the model as normal results, allowing the model to decide whether to retry or switch strategies.4. Engineering Pitfalls and Solutions: Lessons from Real Projects
Pitfall 1: Context explosion. When too many retrieved snippets (more than 10) are included, DeepSeek-chat's context window gets filled and attention is diluted. Solution: Keep only the top-5 snippets, and compress each snippet by summarizing key information into points within 50 tokens before filling into the prompt. In our experiments, the summarized context improved answer groundedness from 74% to 89%.
Pitfall 2: Tool-returned JSON parsing failures. DeepSeek occasionally returns JSON with comments or extra whitespace, causing json.loads to fail. We wrote a fault-tolerant parser: first try direct parsing, if it fails, remove comments and try again; if still failing, ask the model to regenerate. Also, set a tool call timeout (e.g., 10 seconds) to avoid deadlocks.
Pitfall 3: Retrieved results are irrelevant but score high. This often happens because the embedding model performs poorly in specific domains (e.g., legal, code). Countermeasure: Fine-tune the embedding model for the domain, or use multi-path retrieval (e.g., keyword-based Elasticsearch and semantic-based Qdrant), then use an LLM to make a final selection from the combined results.
Pitfall 4: Agent gets stuck in a loop. When the model repeatedly calls the same tool without progress, we set up a "plan check" node: every two steps, trigger an LLM reflection to summarize current progress and decide whether a strategy change is needed. If two consecutive reflections agree, force stop and return the current partial results.
5. Advanced Autonomous Decision-Making: Introducing Reflection and Verification Mechanisms
Pure ReActPatterns tend to accumulate errors in complex tasks. We introduce two key mechanisms: first, "code execution verification," where when the Agent calls Python computation tools, we return not only the output but also the execution logs and the values of intermediate variables, allowing the model to check for logical errors itself; second, "post-answer review," where before generating the final answer, the DeepSeek model is required to output a "confidence score" and a "list of supporting evidence."Implementing "answer-then-review" is not complicated. In the system prompt, we require the model to invoke a tool named "verify" when generating the final answer. This tool calls the retrieval interface to check whether key entities in the answer (such as dates and numbers) are consistent with the knowledge base. If inconsistent, the model must modify the answer. This is similar to the double verification in AutoGen but more lightweight.nt is not just about code deployment; it requires complete monitoring. We record the full chain of each request: retrieved document IDs, reranking scores, the chain of thought at each step of the Agent, tool call inputs and outputs, and the final response. These logs are stored in Elasticsearch for analyzing failure cases and user intent.
We have set up alerts for three key metrics: retrieval hit rate (alert if below 60%, which may indicate knowledge base update issues), tool call failure rate (if above 10%, check API or code), and negative user feedback scores. At the same time, we designed a "human-in-the-loop" mechanism: when the Agent's confidence score falls below 0.5, it automatically transfers to human customer service, along with the reasoning history, to improve user experience.
For full link tracing, you can use OpenTelemetry, treating model calls and retrieval processes as spans. Our experience is to introduce observability early on; otherwise, troubleshooting later is like looking for a needle in a haystack.
Conclusion: From Volume to Substance
The implementation of RAG Agent does not depend on how powerful the model is, but on engineering details: data quality, retrieval strategies, fault tolerance design, and interpretability of decisions. Every aspect discussed in this article has been repeatedly refined in our actual projects. In the future, with advances in multimodality and long context, the boundaries of Agent capabilities will further expand, but the core principles remain unchanged: reliability first, evidence-based.
I hope this article helps you build truly usable intelligent agents in the DeepSeek ecosystem. Remember, in the era of AI applications, the ability to implement is the core competitiveness. Feel free to share the engineering challenges you encounter in the comments.