Loading the notebook…
Loading the notebook…
Notebooks · RAG · 23
Plug the Super RAG subsystem into a regular shipit_agent.Agent using one constructor parameter — rag=. The agent gains three new tools (rag_search, rag_fetch_chunk, rag_list_sources) and the system prompt is augmented…
Its imports and arguments are checked against shipit-agent 3.0. The outputs were saved when it was written, for an earlier release.
from pathlib import Path
import sys
ROOT = (
Path.cwd().resolve().parent
if Path.cwd().name == "notebooks"
else Path.cwd().resolve()
)
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from shipit_agent import Agent
from shipit_agent.rag import RAG, HashingEmbedder
from shipit_agent.tools.base import ToolContextrag = RAG.default(embedder=HashingEmbedder(dimension=512))
rag.index_text(
"Shipit supports Python 3.10 and newer.",
document_id="readme",
source="readme.md",
)
rag.index_text(
"Shipit agents stream events in real time via agent.stream().",
document_id="streaming",
source="streaming.md",
)
rag.index_text(
"Shipit integrates with Jira, Linear, Slack, Gmail, Google Drive, Notion.",
document_id="integrations",
source="integrations.md",
)
print(f"{rag.count()} chunks indexed across {rag.list_sources()}")3 chunks indexed across ['integrations.md', 'readme.md', 'streaming.md']
In production swap this for Anthropic(), OpenAI(), Bedrock(), etc. — anything that returns an LLMResponse.
from examples.run_multi_tool_agent import build_llm_from_env
llm = build_llm_from_env("bedrock")Just pass rag= to the Agent constructor. The three RAG tools are auto-appended and the system prompt gains a short instruction block telling the LLM to use them and cite sources.
agent = Agent(llm=llm, rag=rag)
print("tools:", sorted(t.name for t in agent.tools))
print()
print("prompt suffix:")
print(agent.prompt.split("\n\n")[-1])tools: ['rag_fetch_chunk', 'rag_list_sources', 'rag_search'] prompt suffix: You have access to a RAG knowledge base through the tools `rag_search`, `rag_fetch_chunk`, and `rag_list_sources`. When the user asks about facts, documents, code, or past conversations, call `rag_search` first to ground your answer. In your final answer, cite sources using [N] markers that correspond to chunks you used. Never invent a citation.
The AgentResult.rag_sources field is populated automatically — every chunk the LLM retrieved during the run is recorded with a stable [1], [2], … citation index.
To make this notebook deterministic without a real LLM we manually drive the rag_search tool inside a begin_run/end_run window. In real use the LLM does this automatically.
rag.begin_run()
search_tool = next(t for t in agent.tools if t.name == "rag_search")
search_tool.run(ToolContext(prompt=""), query="python version", top_k=1)
search_tool.run(ToolContext(prompt=""), query="streaming events", top_k=1)
sources = rag.end_run()
for s in sources:
print(f"[{s.index}] {s.source} (chunk_id={s.chunk_id}, score={s.score:.2f})")
print(f" {s.text}")[1] readme.md (chunk_id=readme::0, score=0.02)
Shipit supports Python 3.10 and newer.
[2] streaming.md (chunk_id=streaming::0, score=0.02)
Shipit agents stream events in real time via agent.stream().When you run the agent for real, the runtime calls begin_run / end_run for you. The result.rag_sources field is the citation panel.
result = agent.run("What Python version does Shipit support?")
print("output:", result.output)
print("rag_sources:", len(result.rag_sources))
for s in result.rag_sources:
print(f" [{s.index}] {s.source} {s.text[:60]}…")BadRequestError: litellm.BadRequestError: BedrockException - {"message":"9 validation errors detected: Value '' at 'toolConfig.tools.1.member.toolSpec.name' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9_-]+; Value '' at 'toolConfig.tools.1.member.toolSpec.name' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.1.member.toolSpec.description' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.2.member.toolSpec.name' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9_-]+; Value '' at 'toolConfig.tools.2.member.toolSpec.name' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.2.member.toolSpec.description' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.3.member.toolSpec.name' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9_-]+; Value '' at 'toolConfig.tools.3.member.toolSpec.name' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.3.member.toolSpec.description' failed to satisfy constraint: Member must have length greater than or equal to 1"}agent.stream(...) yields events as they happen. RAG-equipped runs emit a final rag_sources event with the consolidated citation list.
for event in agent.stream("Tell me about streaming events"):
print(f"[{event.type}] {event.message}")
if event.type == "rag_sources":
for src in event.payload.get("sources", []):
print(f' citation [{src["index"]}] {src["source"]}')[run_started] Agent run started [step_started] LLM completion started
BadRequestError: litellm.BadRequestError: BedrockException - {"message":"9 validation errors detected: Value '' at 'toolConfig.tools.1.member.toolSpec.name' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9_-]+; Value '' at 'toolConfig.tools.1.member.toolSpec.name' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.1.member.toolSpec.description' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.2.member.toolSpec.name' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9_-]+; Value '' at 'toolConfig.tools.2.member.toolSpec.name' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.2.member.toolSpec.description' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.3.member.toolSpec.name' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9_-]+; Value '' at 'toolConfig.tools.3.member.toolSpec.name' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'toolConfig.tools.3.member.toolSpec.description' failed to satisfy constraint: Member must have length greater than or equal to 1"}A RAG instance is reusable. Source tracking uses thread-local state so independent runs don't bleed citations into each other.
researcher = Agent(llm=llm, prompt="You research the codebase.", rag=rag)
writer = Agent(llm=llm, prompt="You write user-facing docs.", rag=rag)
for name, agent in [("researcher", researcher), ("writer", writer)]:
print(f"\n=== {name} ===")
print(" tools:", sorted(t.name for t in agent.tools)[:6], "…")
result = agent.run("Summarise Shipit")
print(" rag_sources:", len(result.rag_sources))=== researcher === tools: ['rag_fetch_chunk', 'rag_list_sources', 'rag_search'] … rag_sources: 0 === writer === tools: ['rag_fetch_chunk', 'rag_list_sources', 'rag_search'] … rag_sources: 0
Agent.with_builtinsAll the regular built-in tools (web_search, code_execution, file workspace, …) coexist with the RAG tools. Just pass rag= to with_builtins.
full_agent = Agent.with_builtins(llm=llm, rag=rag)
names = [t.name for t in full_agent.tools]
print(f"total tools: {len(names)}")
print("rag tools present:", sorted(n for n in names if n.startswith("rag_")))total tools: 29 rag tools present: ['rag_fetch_chunk', 'rag_list_sources', 'rag_search']
Next: 24_rag_with_deep_agents.ipynb shows how the same rag= parameter flows through GoalAgent, ReflectiveAgent, AdaptiveAgent, Supervisor, and PersistentAgent.