Chapter 12 · Capstone: evidence-grounded local QA
Combine retrieval, no-evidence routing, and answering. A fixed in-memory corpus and deterministic response template make the workflow verifiable offline. Replace the retriever or answer node independently later.
Mechanics and design choices
The flow is retrieve → route → answer/refuse. State explicitly carries evidence and answer, instead of trusting a model’s claim that it searched. Empty evidence causes refusal. Real RAG also needs source IDs, access controls, retrieval evaluation, and citation validation. This fixture lookup uses exact course keys, not semantic search or a production vector system.
Example
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
CORPUS = {"langgraph": "LangGraph orchestrates stateful workflows.",
"deepagents": "Deep Agents adds an agent harness on LangGraph."}
class State(TypedDict):
question: str
evidence: str
answer: str
def retrieve(state: State):
return {"evidence": CORPUS.get(state["question"].strip().lower(), "")}
def route(state: State):
return "answer" if state["evidence"] else "refuse"
def answer(state: State):
return {"answer": state["evidence"] + " [source: local-course-corpus]"}
def refuse(state: State):
return {"answer": "No evidence found. Please choose a known course."}
builder = StateGraph(State)
for name, function in [("retrieve", retrieve), ("answer", answer), ("refuse", refuse)]:
builder.add_node(name, function)
builder.add_edge(START, "retrieve")
builder.add_conditional_edges("retrieve", route, {"answer": "answer", "refuse": "refuse"})
builder.add_edge("answer", END)
builder.add_edge("refuse", END)
graph = builder.compile()
for question in ["langgraph", "unknown"]:
result = graph.invoke({"question": question, "evidence": "", "answer": ""})
assert bool(result["evidence"]) == (question == "langgraph")
print(result["answer"])Run and verify
Run known and unknown queries to obtain a sourced answer and a refusal. Inspect evidence and answer together rather than checking only that text exists. Continue with Agent Engineering in Production; this chapter performs no cloud deployment.
Pitfalls
Wrapping invoke in HTTP is not sufficient for production. Add validation, tenant isolation, timeouts, cancellation, redacted logs, persistence, and regression fixtures. Re-run empty-result and authorization tests when replacing retrieval.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. What happens without evidence?
2. Is this semantic search?
3. Should retrieval replacement trigger tests?
4. Is an HTTP wrapper sufficient for production?
Hands-on exercises
- Give each evidence record an ID and require matching citations.
- Replace retrieval while retaining the no-evidence refusal test.
- Add human review before exporting a local report.
Official references
Verified on: 2026-09-17.